import json import uuid from pathlib import Path from typing import Optional from fastapi import APIRouter, File, Form, UploadFile from sse_starlette.sse import EventSourceResponse from app.agent.loop import run_agent_loop router = APIRouter() UPLOADS_DIR = Path(__file__).parent.parent.parent / "uploads" async def _save_upload(file: UploadFile) -> str: """保存上传的参考图,返回可访问的 URL 路径。""" ext = Path(file.filename).suffix or ".png" filename = f"{uuid.uuid4().hex}{ext}" filepath = UPLOADS_DIR / filename content = await file.read() filepath.write_bytes(content) return f"/uploads/{filename}" @router.post("/chat") async def chat( messages: str = Form(...), ref_image: Optional[UploadFile] = File(None), ): """ 主对话端点。 参数: - messages: JSON 字符串,对话历史 [{role, content}] - ref_image: 可选的参考图文件 """ parsed_messages = json.loads(messages) ref_image_url: Optional[str] = None if ref_image and ref_image.filename: ref_image_url = await _save_upload(ref_image) async def event_generator(): async for event in run_agent_loop(parsed_messages, ref_image_url): yield { "event": event["type"], "data": json.dumps(event["data"], ensure_ascii=False), } return EventSourceResponse(event_generator())