feat(llm): 增强解说文案生成和图片分析功能,优化JSON解析

在migration_adapter.py和generate_script_docu.py文件中,集成了增强的JSON解析器以提高解说文案生成的稳定性和兼容性。更新了生成解说文案的提示词管理系统,确保返回的JSON格式有效,并在图片分析中保持向后兼容性,提升了系统的灵活性和用户体验。
This commit is contained in:
linyq 2025-07-07 18:17:15 +08:00
parent 5ef9f4a10c
commit f70cfbab46
2 changed files with 78 additions and 43 deletions

View File

@ -5,6 +5,7 @@
""" """
import asyncio import asyncio
import json
from typing import List, Dict, Any, Optional, Union from typing import List, Dict, Any, Optional, Union
from pathlib import Path from pathlib import Path
import PIL.Image import PIL.Image
@ -94,47 +95,26 @@ class LegacyLLMAdapter:
def generate_narration(markdown_content: str, api_key: str, base_url: str, model: str) -> str: def generate_narration(markdown_content: str, api_key: str, base_url: str, model: str) -> str:
""" """
生成解说文案 - 兼容原有接口 生成解说文案 - 兼容原有接口
Args: Args:
markdown_content: Markdown格式的视频帧分析内容 markdown_content: Markdown格式的视频帧分析内容
api_key: API密钥 api_key: API密钥
base_url: API基础URL base_url: API基础URL
model: 模型名称 model: 模型名称
Returns: Returns:
生成的解说文案JSON字符串 生成的解说文案JSON字符串
""" """
try: try:
# 构建提示词 # 使用新的提示词管理系统
prompt = f""" prompt = PromptManager.get_prompt(
我是一名荒野建造解说的博主以下是一些同行的对标文案请你深度学习并总结这些文案的风格特点跟内容特点 category="documentary",
name="narration_generation",
parameters={
"video_frame_description": markdown_content
}
)
<video_frame_description>
{markdown_content}
</video_frame_description>
请根据以上视频帧描述生成引人入胜的解说文案
<output>
{{
"items": [
{{
"_id": 1,
"timestamp": "00:00:05,390-00:00:10,430",
"picture": "画面描述",
"narration": "解说文案",
}}
]
}}
</output>
<restriction>
1. 只输出 json 内容不要输出其他任何说明性的文字
2. 解说文案的语言使用 简体中文
3. 严禁虚构画面所有画面只能从 <video_frame_description> 中摘取
</restriction>
"""
# 使用统一服务生成文案 # 使用统一服务生成文案
result = _run_async_safely( result = _run_async_safely(
UnifiedLLMService.generate_text, UnifiedLLMService.generate_text,
@ -143,12 +123,41 @@ class LegacyLLMAdapter:
temperature=1.5, temperature=1.5,
response_format="json" response_format="json"
) )
return result # 使用增强的JSON解析器
from webui.tools.generate_short_summary import parse_and_fix_json
parsed_result = parse_and_fix_json(result)
if not parsed_result:
logger.error("无法解析LLM返回的JSON数据")
# 返回一个基本的JSON结构而不是错误字符串
return json.dumps({
"items": [
{
"_id": 1,
"timestamp": "00:00:00-00:00:10",
"picture": "解析失败请检查LLM输出",
"narration": "解说文案生成失败,请重试"
}
]
}, ensure_ascii=False)
# 确保返回的是JSON字符串
return json.dumps(parsed_result, ensure_ascii=False)
except Exception as e: except Exception as e:
logger.error(f"生成解说文案失败: {str(e)}") logger.error(f"生成解说文案失败: {str(e)}")
return f"生成解说文案失败: {str(e)}" # 返回一个基本的JSON结构而不是错误字符串
return json.dumps({
"items": [
{
"_id": 1,
"timestamp": "00:00:00-00:00:10",
"picture": "生成失败",
"narration": f"解说文案生成失败: {str(e)}"
}
]
}, ensure_ascii=False)
class VisionAnalyzerAdapter: class VisionAnalyzerAdapter:
@ -163,17 +172,17 @@ class VisionAnalyzerAdapter:
async def analyze_images(self, async def analyze_images(self,
images: List[Union[str, Path, PIL.Image.Image]], images: List[Union[str, Path, PIL.Image.Image]],
prompt: str, prompt: str,
batch_size: int = 10) -> List[str]: batch_size: int = 10) -> List[Dict[str, Any]]:
""" """
分析图片 - 兼容原有接口 分析图片 - 兼容原有接口
Args: Args:
images: 图片列表 images: 图片列表
prompt: 分析提示词 prompt: 分析提示词
batch_size: 批处理大小 batch_size: 批处理大小
Returns: Returns:
分析结果列表 分析结果列表格式与旧实现兼容
""" """
try: try:
# 使用统一服务分析图片 # 使用统一服务分析图片
@ -183,9 +192,26 @@ class VisionAnalyzerAdapter:
provider=self.provider, provider=self.provider,
batch_size=batch_size batch_size=batch_size
) )
return results # 转换为旧格式以保持向后兼容性
# 新实现返回 List[str],需要转换为 List[Dict]
compatible_results = []
for i, result in enumerate(results):
# 计算这个批次处理的图片数量
start_idx = i * batch_size
end_idx = min(start_idx + batch_size, len(images))
images_processed = end_idx - start_idx
compatible_results.append({
'batch_index': i,
'images_processed': images_processed,
'response': result,
'model_used': self.model
})
logger.info(f"图片分析完成,共处理 {len(images)} 张图片,生成 {len(compatible_results)} 个批次结果")
return compatible_results
except Exception as e: except Exception as e:
logger.error(f"图片分析失败: {str(e)}") logger.error(f"图片分析失败: {str(e)}")
raise raise

View File

@ -367,7 +367,16 @@ def generate_script_docu(params):
base_url=text_base_url, base_url=text_base_url,
model=text_model model=text_model
) )
narration_dict = json.loads(narration)['items']
# 使用增强的JSON解析器
from webui.tools.generate_short_summary import parse_and_fix_json
narration_data = parse_and_fix_json(narration)
if not narration_data or 'items' not in narration_data:
logger.error(f"解说文案JSON解析失败原始内容: {narration[:200]}...")
raise Exception("解说文案格式错误无法解析JSON或缺少items字段")
narration_dict = narration_data['items']
# 为 narration_dict 中每个 item 新增一个 OST: 2 的字段, 代表保留原声和配音 # 为 narration_dict 中每个 item 新增一个 OST: 2 的字段, 代表保留原声和配音
narration_dict = [{**item, "OST": 2} for item in narration_dict] narration_dict = [{**item, "OST": 2} for item in narration_dict]
logger.debug(f"解说文案创作完成:\n{"\n".join([item['narration'] for item in narration_dict])}") logger.debug(f"解说文案创作完成:\n{"\n".join([item['narration'] for item in narration_dict])}")