83 lines
2.1 KiB
Python
83 lines
2.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
AI Free Chat - Flask 主应用
|
|
提供聊天页面和 SSE 流式接口
|
|
"""
|
|
import os
|
|
import json
|
|
from flask import Flask, render_template, request, Response, stream_with_context
|
|
from dotenv import load_dotenv
|
|
|
|
from services.doubao import DoubaoService
|
|
from services.deepseek import DeepSeekService
|
|
|
|
# 加载环境变量
|
|
load_dotenv()
|
|
|
|
app = Flask(__name__)
|
|
|
|
# 初始化服务
|
|
services = {
|
|
"doubao": DoubaoService(),
|
|
"deepseek": DeepSeekService(),
|
|
}
|
|
|
|
|
|
@app.route("/")
|
|
def index():
|
|
"""渲染聊天页面"""
|
|
return render_template("index.html")
|
|
|
|
|
|
@app.route("/api/chat", methods=["POST"])
|
|
def chat():
|
|
"""
|
|
SSE 流式聊天接口
|
|
请求体: { provider: 'doubao'|'deepseek', messages: [{role, content}] }
|
|
响应: text/event-stream
|
|
"""
|
|
data = request.get_json(silent=True) or {}
|
|
provider = data.get("provider", "deepseek")
|
|
messages = data.get("messages", [])
|
|
|
|
if provider not in services:
|
|
return Response(
|
|
f"data: {json.dumps({'error': '未知的 provider'})}\n\n",
|
|
mimetype="text/event-stream",
|
|
)
|
|
|
|
if not messages:
|
|
return Response(
|
|
f"data: {json.dumps({'error': 'messages 不能为空'})}\n\n",
|
|
mimetype="text/event-stream",
|
|
)
|
|
|
|
service = services[provider]
|
|
|
|
def generate():
|
|
"""生成 SSE 事件流"""
|
|
try:
|
|
for chunk in service.stream_chat(messages):
|
|
payload = json.dumps({"content": chunk}, ensure_ascii=False)
|
|
yield f"data: {payload}\n\n"
|
|
yield "data: [DONE]\n\n"
|
|
except Exception as e: # noqa: BLE001
|
|
err = json.dumps({"error": str(e)}, ensure_ascii=False)
|
|
yield f"data: {err}\n\n"
|
|
|
|
headers = {
|
|
"Cache-Control": "no-cache",
|
|
"X-Accel-Buffering": "no",
|
|
"Connection": "keep-alive",
|
|
}
|
|
return Response(
|
|
stream_with_context(generate()),
|
|
mimetype="text/event-stream",
|
|
headers=headers,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
port = int(os.getenv("PORT", "5000"))
|
|
app.run(host="0.0.0.0", port=port, debug=True, threaded=True)
|