This folder provides an interactive web UI + backend server (FastAPI) that looks and feels like a ChatGPT chat window, tailored for tabular data preparation with DeepPrep.
It supports:
- Upload multiple input tables (CSV / PKL / Parquet)
- Provide a target table schema description (guided input: high-level task + column schema)
- Run a multi-turn agent and visualize generated operator chains as an operator tree
- Extract the final solution chain, execute it to produce the target table, show a preview, and allow download
- UI is served from chatapp/static/index.html by FastAPI.
- Backend server is chatapp/server.py.
- Agent runner is chatapp/agent_runner.py:
- Starts a background thread
- Calls
MultiTurnAgentturn-by-turn - Maintains an operator tree (trie-like) via chatapp/operator_tree.py
- Pushes events to the UI over WebSocket
/ws/{trial_id}
- In-memory state is managed by chatapp/state.py.
Important: the ChatApp server also exposes a minimal set of ApiClient-compatible endpoints (/trials, /simulate, /evaluate, etc.).
This allows MultiTurnAgent (which internally uses ApiClient) to talk to this same process.
- Endpoint:
POST /ui/upload(multipart form) - Supported file types:
.csv.pkl/.pickle(must contain a DataFrame, or a dict containing a DataFrame).parquet
- Uploaded files are stored under chatapp/uploads/.
- Tables are loaded into pandas and normalized to names:
table_1,table_2, ...
- Endpoint:
POST /ui/target_description - UI collects two fields:
- High-level task description (free text)
- Schema JSON (structured, see below)
Recommended schemaJson format:
{
"Task Description": "...",
"Column Schema": {
"colA": {"description": "...", "requirements": ["distinct", "non-null"]},
"colB": {"description": "...", "requirements": []}
}
}You may also provide a simpler mapping:
{
"colA": {"description": "...", "requirements": ["distinct"]},
"colB": "some text description"
}The server will normalize it into a DataPool-compatible schema payload.
- Endpoint:
POST /ui/run- Starts a background thread to run
MultiTurnAgent - Maintains an operator tree and pushes incremental updates
- Starts a background thread to run
Operator tree construction rule (string-level matching):
- Root is a fixed
ROOTnode. - For each newly generated operator chain, we match from root by normalized operator string equality.
- On first mismatch, we create a new branch and append all remaining operators on that branch.
- When a
<solution>...</solution>appears, we add it into the same tree and send a highlight path event to the UI.
- Result is produced by executing the final solution chain locally (pandas execution via
Executor). - Preview endpoint:
GET /ui/trials/{trial_id}/result - Download endpoint:
GET /ui/trials/{trial_id}/download(CSV)
Run from the repository root (the folder that contains chatapp/ and src/).
Minimum dependencies:
fastapiuvicornpandashttpxpython-multipart
ChatApp uses the global config mechanism in _config/current_config.yaml.
Example (use GPT-5 config):
python -c "from src.tools.helper import Config; Config.set_current_config('multiturn_opchain_gpt5'); cfg=Config.load_current_config(); print(cfg.get('framework'), cfg.get('execute_mode'), cfg.get('llm_name'))"The config YAML file is _config/_CONFIG_multiturn_opchain_gpt5.yaml.
export DS_AGENT_API_BASE_URL=http://127.0.0.1:8000
uvicorn chatapp.server:app --host 0.0.0.0 --port 8000Health check:
curl -s http://127.0.0.1:8000/healthThis project switches LLMs via config YAML under _config.
Option 1: switch via Python (writes _config/current_config.yaml):
python -c "from src.tools.helper import Config; Config.set_current_config('multiturn_opchain_claude'); print(Config.load_current_config().get('llm_name'))"Option 2: switch via UI API:
GET /ui/configslists available options.POST /ui/configswitches the active config.
Example:
curl -s -X POST http://127.0.0.1:8000/ui/config \
-H 'Content-Type: application/json' \
-d '{"configName":"multiturn_opchain_gpt5"}'If your new model can be called through an OpenAI-compatible chat-completions API (including local vLLM OpenAI server, many gateways, etc.), you do NOT need to touch src/.
Steps:
-
Create a new config YAML under _config.
Example file name:
_config/_CONFIG_multiturn_opchain_myllm.yaml
Minimal fields example:
agent_max_err_cnt: 5 execute_mode: rule framework: multiturn_ops key_file: keys_myllm.txt llm_name: my-model-name openai_base_url: http://127.0.0.1:8001/v1 max_explore_op: 50 max_explore_turn: 5 name: multiturn_ops_myllm
Notes:
openai_base_urlis used to setOPENAI_BASE_URLinternally.- If you are using an Azure-style endpoint, set
api_version(see existing configs for examples).
-
Create the key file under a new folder at repo root:
./_keys/keys_myllm.txt
Put one API key per line. The runtime will rotate keys line-by-line. If your endpoint does not require a key, you can put
EMPTYas the only line. -
(For Chat UI dropdown) Register this config in chatapp/configs.py:
Add a new entry into
LLM_CONFIGS, e.g.:LLM_CONFIGS["My-LLM"] = "multiturn_opchain_myllm"
Why:
/ui/configonly accepts config names listed inLLM_CONFIGS. -
Restart the server.
After that, you can select it in the UI (or call POST /ui/config).
If the new LLM does not provide an OpenAI-compatible API, then the calling logic would need a new adapter in src.tools.helper / inference layer.
This repo’s ChatApp is intentionally designed to avoid modifying src/. In this case, the practical option is:
- Deploy a small gateway that exposes your model as OpenAI-compatible, then follow the steps in B.
GET /UI pageGET /healthGET /ui/configslist available LLM configsPOST /ui/configswitch active LLM configPOST /ui/uploadupload tablesPOST /ui/target_descriptionsubmit high-level + schema JSONPOST /ui/runstart agentGET /ui/trials/{trial_id}/resultpoll for result previewGET /ui/trials/{trial_id}/downloaddownload result CSVWS /ws/{trial_id}stream events (chat,tree,status,highlight,result)
These exist so MultiTurnAgent can run without a separate Action Sandbox:
POST /trialsPOST /trials/create_with_task_idGET /trialsGET /trials/{trial_id}GET /trials/{trial_id}/tablesDELETE /trials/{trial_id}POST /trials/{trial_id}/copyDELETE /trials/{trial_id}/clearPOST /trials/{trial_id}/executePOST /trials/{trial_id}/stepPOST /trials/{trial_id}/simulatePOST /trials/{trial_id}/simulate_evaluatePOST /trials/{trial_id}/evaluatePOST /operators/validatePOST /trials/reward(best-effort similarity reward)
- Run from repo root.
- Ensure Python deps are installed.
python -c "from src.tools.helper import Config; Config.set_current_config('multiturn_opchain_gpt5'); cfg=Config.load_current_config(); print(cfg.get('framework'), cfg.get('execute_mode'), cfg.get('llm_name'))"export DS_AGENT_API_BASE_URL=http://127.0.0.1:8000
uvicorn chatapp.server:app --host 0.0.0.0 --port 8000This tests:
- Config switching
- Start a temporary uvicorn (random port) and verify
/health - ApiClient-compatible endpoints (create/copy/execute/step/simulate/evaluate/reward/validate/delete)
- UI endpoints (
/ui/upload,/ui/target_description,/ui/run,/ui/trials/{id}/result)
Run:
bash chatapp/run_all_smoke_tests.shOr specify config:
CHATAPP_CONFIG_NAME=multiturn_opchain_gpt5 bash chatapp/run_all_smoke_tests.shNote: /ui/run starts the agent in a background thread. If no valid LLM key/endpoint is configured, the agent may fail in the background, but the smoke tests will still validate that the server endpoints are reachable and behave correctly.