refactor(script): remove sync endpoint, add thread-pool & timeout
- Remove unused POST /script/generate sync endpoint and frontend generate() - Move JSON parsing/validation to asyncio.to_thread() to avoid event-loop blocking - Add 60s asyncio.timeout() around entire script generation pipeline - Migrate volcengine_provider to unified AsyncArk client
This commit is contained in:
@@ -141,89 +141,100 @@ class ScriptService:
|
||||
model_router = await get_model_router()
|
||||
|
||||
try:
|
||||
# 加载 Prompt
|
||||
system_prompt = load_system_prompt(category, subcategory)
|
||||
if not system_prompt:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message=f"未找到提示词: category={category}, subcategory={subcategory}",
|
||||
)
|
||||
return
|
||||
|
||||
user_prompt = load_script_user_prompt(
|
||||
topic=f"{category}/{subcategory}",
|
||||
duration=duration,
|
||||
)
|
||||
|
||||
yield ScriptGenerationEvent(
|
||||
type="start",
|
||||
message="准备生成...",
|
||||
)
|
||||
|
||||
full_content = ""
|
||||
has_shown_generating = False
|
||||
|
||||
async for chunk in model_router.generate_stream_with_progress(
|
||||
prompt=user_prompt,
|
||||
system_prompt=system_prompt,
|
||||
model_id=model,
|
||||
task_type="script",
|
||||
temperature=0.7,
|
||||
response_format="json_object",
|
||||
):
|
||||
if chunk["type"] == "chunk":
|
||||
chunk_content = chunk.get("content", "")
|
||||
if not chunk_content:
|
||||
continue
|
||||
full_content += chunk_content
|
||||
|
||||
if not has_shown_generating:
|
||||
yield ScriptGenerationEvent(
|
||||
type="generating",
|
||||
message="正在创作脚本...",
|
||||
)
|
||||
has_shown_generating = True
|
||||
|
||||
if not full_content or not full_content.strip():
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message="AI 返回内容为空,请检查模型配置或重试",
|
||||
)
|
||||
return
|
||||
|
||||
success, parsed_data, error_msg = safe_parse_ai_json_response(full_content)
|
||||
|
||||
if not success:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message=f"脚本解析失败: {error_msg or '无法解析 AI 返回的内容'}",
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
shots_data = validate_and_normalize_shots(parsed_data)
|
||||
|
||||
if not shots_data:
|
||||
async with asyncio.timeout(60):
|
||||
# 加载 Prompt
|
||||
system_prompt = load_system_prompt(category, subcategory)
|
||||
if not system_prompt:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message="AI 返回的分镜数据为空或格式不正确",
|
||||
message=f"未找到提示词: category={category}, subcategory={subcategory}",
|
||||
)
|
||||
return
|
||||
|
||||
shots = [ScriptShot(**shot) for shot in shots_data]
|
||||
|
||||
yield ScriptGenerationEvent(
|
||||
type="complete",
|
||||
message="脚本生成成功",
|
||||
result=shots,
|
||||
user_prompt = load_script_user_prompt(
|
||||
topic=f"{category}/{subcategory}",
|
||||
duration=duration,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message=f"分镜数据处理失败: {str(e)}",
|
||||
type="start",
|
||||
message="准备生成...",
|
||||
)
|
||||
|
||||
full_content = ""
|
||||
has_shown_generating = False
|
||||
|
||||
async for chunk in model_router.generate_stream_with_progress(
|
||||
prompt=user_prompt,
|
||||
system_prompt=system_prompt,
|
||||
model_id=model,
|
||||
task_type="script",
|
||||
temperature=0.7,
|
||||
response_format="json_object",
|
||||
):
|
||||
if chunk["type"] == "chunk":
|
||||
chunk_content = chunk.get("content", "")
|
||||
if not chunk_content:
|
||||
continue
|
||||
full_content += chunk_content
|
||||
|
||||
if not has_shown_generating:
|
||||
yield ScriptGenerationEvent(
|
||||
type="generating",
|
||||
message="正在创作脚本...",
|
||||
)
|
||||
has_shown_generating = True
|
||||
|
||||
if not full_content or not full_content.strip():
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message="AI 返回内容为空,请检查模型配置或重试",
|
||||
)
|
||||
return
|
||||
|
||||
success, parsed_data, error_msg = await asyncio.to_thread(
|
||||
safe_parse_ai_json_response, full_content
|
||||
)
|
||||
|
||||
if not success:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message=f"脚本解析失败: {error_msg or '无法解析 AI 返回的内容'}",
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
shots_data = await asyncio.to_thread(
|
||||
validate_and_normalize_shots, parsed_data
|
||||
)
|
||||
|
||||
if not shots_data:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message="AI 返回的分镜数据为空或格式不正确",
|
||||
)
|
||||
return
|
||||
|
||||
shots = [ScriptShot(**shot) for shot in shots_data]
|
||||
|
||||
yield ScriptGenerationEvent(
|
||||
type="complete",
|
||||
message="脚本生成成功",
|
||||
result=shots,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message=f"分镜数据处理失败: {str(e)}",
|
||||
)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
message="脚本生成超时,请重试",
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
yield ScriptGenerationEvent(
|
||||
type="error",
|
||||
|
||||
Reference in New Issue
Block a user