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

  1. 新增函数 call_hermes_stream(user_input, timeout=120) → generator yielding text chunks

    • 使用 subprocess.Popen 启动 hermes chat -m <input>
    • 用 stdout.readline() 逐行读取输出
    • 每读到一行就 yield 出去
    • 超时或结束时清理进程
  2. 新增 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//stream
  • test_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