# 示例(curl / Python / JS / Flutter) 本文提供“最小可用”的端到端示例:创建对话 → 发送消息 → 轮询输出 →(可选)停止任务 → 文件上传/下载。 请先阅读 `auth.md` 并准备好 token。 ## 0. 统一变量 - `BASE_URL`:例如 `http://localhost:8091` - `TOKEN`:你的 Bearer Token(明文) --- ## 1) curl:完整对话流程 ### 1.1 创建对话 ```bash BASE_URL="http://localhost:8091" TOKEN="" curl -sS -X POST \ -H "Authorization: Bearer $TOKEN" \ "$BASE_URL/api/v1/conversations" ``` 假设返回: ```json { "success": true, "conversation_id": "conv_20260123_234245_036" } ``` ### 1.2 发送消息(创建任务) ```bash curl -sS -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "conversation_id": "conv_20260123_234245_036", "message": "请用中文简要介绍《明日方舟:终末地》", "run_mode": "fast", "max_iterations": 100 }' \ "$BASE_URL/api/v1/messages" ``` 假设返回: ```json { "success": true, "task_id": "60322db3-...", "status": "running", "conversation_id": "conv_...", "created_at": 1769182965.30 } ``` ### 1.3 轮询(建议脚本处理 next_offset) ```bash TASK_ID="60322db3-..." OFFSET=0 curl -sS -H "Authorization: Bearer $TOKEN" \ "$BASE_URL/api/v1/tasks/$TASK_ID?from=$OFFSET" ``` --- ## 2) Python:轮询并实时拼接文本 依赖:`pip install requests` ```python import time import requests BASE_URL = "http://localhost:8091" TOKEN = "" H = {"Authorization": f"Bearer {TOKEN}"} def post_json(path, payload): r = requests.post(BASE_URL + path, json=payload, headers={**H, "Content-Type":"application/json"}, timeout=30) r.raise_for_status() return r.json() def get_json(path, params=None): r = requests.get(BASE_URL + path, params=params or {}, headers=H, timeout=30) r.raise_for_status() return r.json() # 1) create conversation conv = requests.post(BASE_URL + "/api/v1/conversations", headers=H, timeout=30).json() assert conv["success"] conversation_id = conv["conversation_id"] # 2) send message task = post_json("/api/v1/messages", { "conversation_id": conversation_id, "message": "请用中文简要介绍《明日方舟:终末地》", "run_mode": "fast", "max_iterations": 100 }) task_id = task["task_id"] # 3) poll events offset = 0 text_buf = [] think_buf = [] while True: data = get_json(f"/api/v1/tasks/{task_id}", params={"from": offset}) if not data["success"]: raise RuntimeError(data.get("error")) info = data["data"] events = info["events"] offset = info["next_offset"] for ev in events: t = ev["type"] d = ev["data"] or {} if t == "text_chunk": text_buf.append(d.get("content","")) print(d.get("content",""), end="", flush=True) elif t == "text_end": print("\\n--- text_end ---\\n") elif t == "thinking_chunk": think_buf.append(d.get("content","")) elif t == "tool_start": print(f\"\\n[tool_start] {d.get('name')}\\n\") elif t == "update_action": # 工具状态更新 st = d.get("status") or "" msg = d.get("message") or "" if st or msg: print(f\"\\n[update_action] {st} {msg}\\n\") elif t == "error": print(f\"\\n[error] {d.get('message')}\\n\") if info["status"] != "running": break time.sleep(1.0) final_text = "".join(text_buf) final_thinking = "".join(think_buf) print("final status:", info["status"]) print("final text length:", len(final_text)) print("final thinking length:", len(final_thinking)) ``` --- ## 3) JavaScript(浏览器/Node)要点 浏览器端直接跨域请求时,请确保服务端允许 CORS(当前服务端已启用 CORS)。请求示例: ```js const BASE_URL = "http://localhost:8091"; const TOKEN = ""; async function api(path, options = {}) { const resp = await fetch(BASE_URL + path, { ...options, headers: { "Authorization": `Bearer ${TOKEN}`, ...(options.headers || {}) } }); const data = await resp.json(); if (!resp.ok || !data.success) throw new Error(data.error || resp.statusText); return data; } const conv = await api("/api/v1/conversations", { method: "POST" }); const msg = await api("/api/v1/messages", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ conversation_id: conv.conversation_id, message: "请用中文简要介绍《明日方舟:终末地》", run_mode: "fast", max_iterations: 100 }) }); let offset = 0; let text = ""; while (true) { const poll = await api(`/api/v1/tasks/${msg.task_id}?from=${offset}`); const info = poll.data; for (const ev of info.events) { if (ev.type === "text_chunk") text += ev.data.content || ""; if (ev.type === "tool_start") console.log("tool:", ev.data.name); } offset = info.next_offset; if (info.status !== "running") break; await new Promise(r => setTimeout(r, 1000)); } console.log("done:", text); ``` --- ## 4) Flutter(Dart)轮询示例(伪代码) 依赖:`http` 包或 `dio` 包均可,这里用 `http` 表达逻辑。 ```dart import 'dart:convert'; import 'dart:async'; import 'package:http/http.dart' as http; const baseUrl = "http://localhost:8091"; const token = ""; Map headersJson() => { "Authorization": "Bearer $token", "Content-Type": "application/json", }; Future createConversation() async { final resp = await http.post(Uri.parse("$baseUrl/api/v1/conversations"), headers: {"Authorization":"Bearer $token"}); final data = jsonDecode(resp.body); if (resp.statusCode != 200 || data["success"] != true) throw Exception(data["error"]); return data["conversation_id"]; } Future sendMessage(String convId, String message) async { final resp = await http.post(Uri.parse("$baseUrl/api/v1/messages"), headers: headersJson(), body: jsonEncode({ "conversation_id": convId, "message": message, "run_mode": "fast", "max_iterations": 100, })); final data = jsonDecode(resp.body); if (resp.statusCode != 202 || data["success"] != true) throw Exception(data["error"]); return data["task_id"]; } Stream pollText(String taskId) async* { int offset = 0; while (true) { final resp = await http.get(Uri.parse("$baseUrl/api/v1/tasks/$taskId?from=$offset"), headers: {"Authorization":"Bearer $token"}); final data = jsonDecode(resp.body); if (resp.statusCode != 200 || data["success"] != true) throw Exception(data["error"]); final info = data["data"]; final events = (info["events"] as List); for (final ev in events) { if (ev["type"] == "text_chunk") { yield (ev["data"]["content"] ?? ""); } } offset = info["next_offset"]; if (info["status"] != "running") break; await Future.delayed(Duration(milliseconds: 800)); } } ``` 提示: - Flutter UI 展示建议:把 `pollText()` 的输出 append 到一个 `StringBuffer`,并用 `setState()`/状态管理更新。 - 同时可以订阅 tool_* 事件在 UI 中显示“正在搜索/正在执行工具”等状态。