feat: init meijiaka-zj project from ai-meijiaka template

This commit is contained in:
小鱼开发
2026-04-20 16:39:57 +08:00
commit 74983ce5ec
291 changed files with 76164 additions and 0 deletions
+187
View File
@@ -0,0 +1,187 @@
"""
脚本生成 API
============
提供脚本生成、润色、模型健康检查等功能。
支持 SSE 流式响应。
"""
from __future__ import annotations
import logging
from fastapi import APIRouter, Request
from fastapi.responses import StreamingResponse
from app.schemas.common import ApiResponse, success_response
from app.schemas.script import (
GenerateScriptRequest,
ModelHealthResponse,
PolishRequest,
ScriptGenerationEvent,
ScriptShot,
TestModelRequest,
TestModelResponse,
)
from app.services.script_service import get_script_service
router = APIRouter()
logger = logging.getLogger(__name__)
@router.post("/generate", response_model=ApiResponse[list[ScriptShot]])
async def generate_script(request: GenerateScriptRequest):
"""
同步生成脚本
直接返回生成的分镜列表,适合快速预览。
"""
service = get_script_service()
shots = await service.generate_script(
topic=request.topic,
duration=request.duration,
script_type=request.script_type,
model=request.model,
)
return success_response(
data=shots,
message=f"成功生成 {len(shots)} 个分镜",
)
@router.post("/generate/stream")
async def generate_script_stream(request: Request, data: GenerateScriptRequest):
"""
流式生成脚本(SSE
返回 Server-Sent Events,包含进度更新和最终结果。
前端通过 EventSource 接收实时进度。
**SSE 事件类型:**
- `start`: 开始生成
- `analyzing`: 分析主题
- `planning`: 规划结构
- `generating`: AI 生成中
- `parsing`: 解析结果
- `complete`: 完成,包含 result 字段
- `error`: 错误
**示例事件流:**
```
data: {"type": "start", "progress": 0, "message": "开始生成脚本"}
data: {"type": "analyzing", "progress": 15, "message": "分析目标受众..."}
data: {"type": "complete", "progress": 100, "message": "成功生成 5 个分镜", "result": [...]}
```
"""
service = get_script_service()
async def event_generator():
"""SSE 事件生成器,带客户端断开检测"""
try:
async for event in service.generate_script_stream(
topic=data.topic,
duration=data.duration,
script_type=data.script_type,
model=data.model,
):
# 检查客户端是否已断开
if await request.is_disconnected():
logger.info("[SSE] 客户端已断开连接,停止生成")
break
# SSE 格式:data: {...}\n\n
try:
yield f"data: {event.model_dump_json()}\n\n"
except Exception as e:
logger.error(f"[SSE] 序列化事件失败: {e}")
continue
# 发送结束标记(如果客户端还连接着)
if not await request.is_disconnected():
yield "data: [DONE]\n\n"
except Exception as e:
logger.exception("[SSE] 事件生成器异常")
# 尝试发送错误信息给客户端
try:
error_event = ScriptGenerationEvent(
type="error",
progress=0,
message=f"服务器错误: {str(e)}",
)
yield f"data: {error_event.model_dump_json()}\n\n"
yield "data: [DONE]\n\n"
except:
pass
return StreamingResponse(
event_generator(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no", # 禁用 Nginx 缓冲
},
)
@router.post("/polish", response_model=ApiResponse[str])
async def polish_content(request: PolishRequest):
"""
AI 润色文案/画面描述
- `polishType=scene`: 润色画面描述(根据 shot_type 自动区分分镜/空镜)
- `polishType=voiceover`: 润色配音文案
参数:
- `shot_type`: "segment"(分镜)或 "empty_shot"(空镜),画面润色时必填
"""
service = get_script_service()
polished = await service.polish_content(
content=request.content,
polish_type=request.polish_type,
shot_type=request.shot_type or "segment",
)
type_name = "画面" if request.polish_type == "scene" else "文案"
return success_response(
data=polished,
message=f"{type_name}润色完成",
)
@router.get("/model-health", response_model=ApiResponse[ModelHealthResponse])
async def check_model_health():
"""
检查 AI 模型健康状态
返回所有配置的模型及其可用性状态。
"""
service = get_script_service()
health_data = await service.check_model_health()
return success_response(
data=ModelHealthResponse(**health_data),
message="模型健康检查完成",
)
@router.post("/test-model", response_model=ApiResponse[TestModelResponse])
async def test_model(request: TestModelRequest):
"""
测试指定模型连接
发送一个简单的测试请求,验证模型是否可用。
"""
service = get_script_service()
result = await service.test_model(request.model_id)
return success_response(
data=TestModelResponse(**result),
message="模型测试完成" if result["success"] else f"模型测试失败: {result.get('error')}",
)