s4_sse_stream.md
1.74 KB
PLAN: S4 — SSE 流式回复
Goal
新增 SSE endpoint 实现 AI 回复的逐字流式传输。
Current State
- S3: call_hermes() 使用 subprocess.run(阻塞,一次性返回全部输出)
- app.py: 已有 POST /api/conversations//messages(一次性回复)
What to Build
新增函数
call_hermes_stream(user_input, timeout=120)→ generator yielding text chunks- 使用 subprocess.Popen 启动
hermes chat -m <input> - 用 stdout.readline() 逐行读取输出
- 每读到一行就 yield 出去
- 超时或结束时清理进程
- 使用 subprocess.Popen 启动
新增 SSE endpoint:
GET /api/conversations/<int:conv_id>/stream?message=<text>- 使用 Flask Response + text/event-stream content type
- 先保存用户消息到 DB
- 构建历史上下文
- 调用 call_hermes_stream() 生成流式输出
- 每个 chunk 通过 SSE 发送:
data: <chunk>\n\n - 流结束后发送
data: [DONE]\n\n - 在生成器中累积全文,流结束后保存 AI 回复到 DB
- 需要设置 threading 让 DB 写入不阻塞主线程
Files
app.py: 新增 call_hermes_stream() + GET /api/conversations//streamtest_s4_sse.py: 集成测试
Data Flow
Browser (EventSource) → GET /stream?message=hello
→ Flask saves user msg to DB
→ call_hermes_stream(history + message)
→ Popen(["hermes", "chat", "-m", input])
→ for line in stdout: yield chunk → SSE to client
→ after loop: save full AI reply to DB
Risks
- Flask's default WSGI server (Werkzeug) is single-threaded; SSE streaming blocks one worker
- Need to ensure DB writes don't conflict with streaming
- Popen process cleanup on client disconnect
Verification
- Syntax check
- Unit test: mock Popen to verify SSE format
- Smoke test: all 8 pass