【实践原创】使用 FastAPI 实现 Coze 流式聊天 SSE 接口

使用 FastAPI 实现 Coze 流式聊天 SSE 接口

在开发 AI 助手或聊天应用时,我们通常希望服务端能够 实时向前端推送消息 ,让用户看到逐字打字效果。本文演示如何使用 FastAPI + Coze Python SDK(cozepy) 实现 流式聊天 SSE 接口 ,并提供 curl 测试方法。


功能特点

  1. 流式输出:前端可以实时接收聊天增量消息。
  2. SSE 格式:便于浏览器或 Go/Node 前端解析。
  3. 兼容不同版本 Coze SDK:处理可能缺失的异常类。
  4. 可直接使用 curl 测试:无需前端即可验证接口。

技术栈


完整示例代码

python 复制代码
import os
from typing import Optional, List, Dict, Any
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from cozepy import Coze, TokenAuth, Message, ChatEventType, COZE_CN_BASE_URL

# ===========================
# 兼容不同版本的cozepy异常类
# ===========================
try:
    from cozepy import CozeAPIError, CozeAuthError
except ImportError:
    class CozeAPIError(Exception): pass
    class CozeAuthError(Exception): pass

# ===========================
# 初始化FastAPI应用
# ===========================
app = FastAPI(title="Coze Stream Chat API")

# ===========================
# 全局配置与Coze客户端初始化
# ===========================
COZE_API_TOKEN = os.getenv("COZE_API_TOKEN", "你的默认Token")
COZE_API_BASE = COZE_CN_BASE_URL
BOT_VERSION = "1756277832"

coze_client: Optional[Coze] = None

def init_coze_client():
    """初始化Coze客户端"""
    global coze_client
    if coze_client:
        return coze_client
    try:
        coze_client = Coze(auth=TokenAuth(token=COZE_API_TOKEN), base_url=COZE_API_BASE)
        return coze_client
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Coze客户端初始化失败:{str(e)}")

init_coze_client()

# ===========================
# 定义请求体模型
# ===========================
class ChatRequest(BaseModel):
    user_id: str
    bot_id: str
    stream: bool = True
    additional_messages: List[Dict[str, Any]]
    conversation_id: Optional[str] = None
    bot_version: Optional[str] = BOT_VERSION

# ===========================
# 流式聊天接口
# ===========================
@app.post("/api/coze-chat")
async def coze_chat(request: ChatRequest):
    try:
        # 构建 Coze 消息
        import json
        messages = []
        for msg in request.additional_messages:
            if msg.get("role") == "user" and msg.get("content_type") == "text":
                content_list = json.loads(msg.get("content", "[]"))
                text = "".join([item.get("text", "") for item in content_list])
                messages.append(Message.build_user_question_text(text))

        # 调用流式接口
        stream = coze_client.chat.stream(
            bot_id=request.bot_id,
            user_id=request.user_id,
            conversation_id=request.conversation_id or None,
            publish_status="published_online",
            bot_version=request.bot_version,
            auto_save_history=False,
            additional_messages=messages
        )

        # SSE 流生成器
        async def generate_stream():
            try:
                for event in stream:
                    if not event:
                        continue
                    # 消息增量
                    if event.event == ChatEventType.CONVERSATION_MESSAGE_DELTA:
                        content = event.message.content.strip() if event.message.content else ""
                        if content:
                            yield f"data: {json.dumps({'type': 'delta', 'content': content})}\n\n"
                    # 聊天完成
                    elif event.event == ChatEventType.CONVERSATION_CHAT_COMPLETED:
                        usage = event.chat.usage.token_count if hasattr(event.chat, 'usage') else 0
                        conv_id = event.chat.conversation_id if hasattr(event.chat, 'conversation_id') else ""
                        yield f"data: {json.dumps({'type': 'completed', 'token_count': usage, 'conversation_id': conv_id})}\n\n"
                        yield "data: [DONE]\n\n"
            except Exception as e:
                yield f"data: {json.dumps({'type': 'error', 'message': str(e)})}\n\n"

        return StreamingResponse(
            generate_stream(),
            media_type="text/event-stream",
            headers={
                "Cache-Control": "no-cache",
                "Connection": "keep-alive",
                "Access-Control-Allow-Origin": "*"
            }
        )

    except CozeAuthError as e:
        raise HTTPException(status_code=401, detail=f"认证失败:{str(e)}")
    except CozeAPIError as e:
        raise HTTPException(status_code=502, detail=f"Coze API错误:{str(e)}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"服务器错误:{str(e)}")

# ===========================
# 启动服务
# ===========================
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

使用方法

  1. 安装依赖:
bash 复制代码
pip install fastapi uvicorn cozepy
  1. 设置环境变量(可选):
bash 复制代码
export COZE_API_TOKEN="你的CozeToken"
  1. 启动服务:
bash 复制代码
python main.py

服务将监听 http://0.0.0.0:8000


使用 curl 测试接口

你可以使用 curl 来实时查看 SSE 流:

bash 复制代码
# 测试Python服务
curl -X POST -H "Content-Type: application/json" -d '{
    "user_id": "123",
    "bot_id": "7579834670624407602",
    "stream": true,
    "additional_messages": [
        {
            "role": "user",
            "type": "question",
            "content_type": "text",
            "content": "[{\"type\":\"text\",\"text\":\"你好\"}]"
        }
    ]
}' http://localhost:8000/api/coze-chat

参数说明:

  • -N / --no-buffer:禁用输出缓存,实时显示流式数据。
  • -X POST:发送 POST 请求。
  • -d:传递 JSON 请求体。

执行后,你会看到类似以下输出(SSE 流):

复制代码
data: {"type": "delta", "content": "你"}
data: {"type": "delta", "content": "好"}
data: {"type": "delta", "content": ",Coze!"}
data: {"type": "completed", "token_count": 12, "conversation_id": "conv_123"}
data: [DONE]

前端示例(实时渲染打字机效果)

html 复制代码
<div id="chat"></div>
<script>
const chatDiv = document.getElementById("chat");
const evtSource = new EventSource("http://localhost:8000/api/coze-chat");

evtSource.onmessage = (e) => {
    if (e.data === "[DONE]") {
        console.log("聊天结束");
        return;
    }
    const data = JSON.parse(e.data);
    if(data.type === "delta"){
        chatDiv.innerHTML += data.content;
    }
    else if(data.type === "completed"){
        console.log("聊天完成, token_count:", data.token_count);
    }
};

evtSource.onerror = () => console.log("连接错误或关闭");
</script>

效果:消息逐字符显示,模拟 AI 打字机输出。


总结

  • 通过 FastAPI 可以快速实现 Coze 流式聊天接口。
  • SSE 格式让前端无需轮询即可接收消息增量。
  • 使用 curl 或前端 JS 均可实时验证流式输出。
  • 可扩展为 AI 聊天助手、客服机器人或协作工具。
相关推荐
海鸥-w20 分钟前
用python (fastapi)做项目第二天实现新闻列表和新闻详情接口
开发语言·python·fastapi
曲幽9 小时前
FastAPI 身份验证总踩坑?这份 FastAPI Users “避坑指南”请收好
python·fastapi·web·jwt·oauth2·user·authentication
海鸥-w21 小时前
用python (fastapi)做项目第一天创建项目结构,数据建表,ORM配置安装,写第一个接口
数据库·python·fastapi
li星野1 天前
从零搭建文件上传系统:FastAPI 后端 + Streamlit 前端
前端·状态模式·fastapi
至天2 天前
FastAPI 接入 FastAPI-Limiter 以及使用 Redis 进行限流指南
redis·python·fastapi·请求限流
li星野2 天前
FastAPI 中间件完全指南:从原理到实战,掌控请求响应的全局钩子
中间件·fastapi
Derrick__12 天前
基于 LangGraph + FastAPI 搭建一个带人工审核的行业分析多智能体系统
ai·agent·fastapi·vibe coding
ss2733 天前
【Python实战】基于FastAPI的绿植养护管理系统 - 完整项目
python·fastapi
li星野3 天前
FastAPI 响应类型完全指南:从 JSON 到流式响应、异常处理与输出模型
前端·json·fastapi
海鸥-w4 天前
python(fastapi) 实现更新,新增,删除接口
android·python·fastapi