229 lines
6.1 KiB
Python
229 lines
6.1 KiB
Python
"""
|
||
Prompt 简单加载器
|
||
=================
|
||
从文件加载 Prompt,支持热更新。
|
||
"""
|
||
|
||
from pathlib import Path
|
||
from string import Template
|
||
|
||
_PROMPTS_DIR = Path(__file__).parent
|
||
|
||
|
||
def load_prompt(path: str) -> str:
|
||
"""
|
||
加载 Prompt 文件
|
||
|
||
Args:
|
||
path: 相对路径,如 "script/system", "polish/scene"
|
||
|
||
Returns:
|
||
Prompt 内容,文件不存在返回空字符串
|
||
"""
|
||
file_path = _PROMPTS_DIR / f"{path}.txt"
|
||
if file_path.exists():
|
||
return file_path.read_text(encoding="utf-8")
|
||
return ""
|
||
|
||
|
||
def render_template(template: str, **kwargs) -> str:
|
||
"""
|
||
安全渲染模板变量
|
||
|
||
Args:
|
||
template: 模板字符串
|
||
**kwargs: 变量值
|
||
|
||
Returns:
|
||
渲染后的字符串
|
||
"""
|
||
try:
|
||
# 转义 $ 符号防止用户输入干扰
|
||
safe_kwargs = {k: str(v).replace("$", "$$") for k, v in kwargs.items()}
|
||
return Template(template).substitute(**safe_kwargs)
|
||
except KeyError as e:
|
||
raise ValueError(f"模板缺少变量: {e}")
|
||
|
||
|
||
# 便捷函数
|
||
def load_script_system() -> str:
|
||
"""加载脚本生成 System Prompt"""
|
||
return load_prompt("script/system")
|
||
|
||
|
||
def load_script_user(topic: str, duration: int, script_type: str) -> str:
|
||
"""加载并渲染脚本生成 User Prompt"""
|
||
template = load_prompt("script/user")
|
||
return render_template(template, topic=topic, duration=duration, type=script_type)
|
||
|
||
|
||
def load_polish_scene() -> str:
|
||
"""加载画面润色 Prompt"""
|
||
return load_prompt("polish/scene")
|
||
|
||
|
||
def load_polish_voiceover() -> str:
|
||
"""加载文案润色 Prompt"""
|
||
return load_prompt("polish/voiceover")
|
||
|
||
|
||
# 预定义的脚本类型和风格
|
||
SCRIPT_TYPES = [
|
||
{"id": "干货型", "name": "干货型", "description": "知识分享、技巧传授"},
|
||
{"id": "故事型", "name": "故事型", "description": "案例故事、用户体验"},
|
||
{"id": "对比型", "name": "对比型", "description": "产品对比、优劣分析"},
|
||
{"id": "避坑型", "name": "避坑型", "description": "防骗指南、常见误区"},
|
||
{"id": "测评型", "name": "测评型", "description": "产品测评、真实体验"},
|
||
]
|
||
|
||
VIDEO_STYLES = [
|
||
{"id": "口播", "name": "口播", "description": "真人出镜讲解"},
|
||
{"id": "图文", "name": "图文", "description": "图片+文字+配音"},
|
||
{"id": "混剪", "name": "混剪", "description": "素材混剪+配音"},
|
||
{"id": "剧情", "name": "剧情", "description": "情景剧演绎"},
|
||
{"id": "Vlog", "name": "Vlog", "description": "记录式视频"},
|
||
]
|
||
|
||
|
||
class ScriptPromptBuilder:
|
||
"""
|
||
脚本 Prompt 构建器
|
||
|
||
用于构建家装行业短视频脚本的 System Prompt。
|
||
"""
|
||
|
||
def build(
|
||
self,
|
||
duration: int = 30,
|
||
script_type: str = "干货型",
|
||
video_style: str = "口播",
|
||
industry: str = "家装",
|
||
tone: str | None = None,
|
||
custom_requirements: str | None = None,
|
||
) -> str:
|
||
"""
|
||
构建系统 Prompt
|
||
|
||
Args:
|
||
duration: 视频时长(秒)
|
||
script_type: 脚本类型(干货型、故事型等)
|
||
video_style: 视频风格(口播、剧情等)
|
||
industry: 行业(家装)
|
||
tone: 语气风格
|
||
custom_requirements: 自定义要求
|
||
|
||
Returns:
|
||
完整的 System Prompt
|
||
"""
|
||
# 基础 System Prompt
|
||
base_prompt = load_script_system()
|
||
|
||
# 构建上下文信息
|
||
context_parts = [
|
||
f"行业:{industry}",
|
||
f"时长:{duration}秒",
|
||
f"类型:{script_type}",
|
||
f"风格:{video_style}",
|
||
]
|
||
|
||
if tone:
|
||
context_parts.append(f"语气:{tone}")
|
||
|
||
context = "\n".join(context_parts)
|
||
|
||
# 构建完整 Prompt
|
||
full_prompt = f"""{base_prompt}
|
||
|
||
【创作要求】
|
||
{context}
|
||
"""
|
||
|
||
if custom_requirements:
|
||
full_prompt += f"""
|
||
【特殊要求】
|
||
{custom_requirements}
|
||
"""
|
||
|
||
# 添加输出格式要求
|
||
full_prompt += """
|
||
【输出格式】
|
||
请严格按照以下 JSON 数组格式返回,每个元素代表一个镜头:
|
||
[
|
||
{
|
||
"id": 1,
|
||
"type": "segment",
|
||
"scene": "画面描述",
|
||
"voiceover": "配音文案",
|
||
"duration": "5s"
|
||
}
|
||
]
|
||
|
||
type 可以是:
|
||
- "segment": 分镜(有画面+配音)
|
||
- "empty_shot": 空镜(纯画面,voiceover 可为空)
|
||
|
||
注意:
|
||
1. 只返回 JSON 数组,不要有其他文字
|
||
2. 确保 JSON 格式正确
|
||
3. 总时长必须严格控制在要求范围内
|
||
"""
|
||
|
||
return full_prompt
|
||
|
||
|
||
class PolishPromptBuilder:
|
||
"""
|
||
润色 Prompt 构建器
|
||
|
||
用于构建润色文案或画面描述的 Prompt。
|
||
"""
|
||
|
||
POLISH_TYPES = {
|
||
"scene": "画面描述",
|
||
"voiceover": "配音文案",
|
||
"text": "文案内容",
|
||
}
|
||
|
||
def build(self, polish_type: str = "voiceover") -> str:
|
||
"""
|
||
构建润色 Prompt
|
||
|
||
Args:
|
||
polish_type: 润色类型(scene/voiceover/text)
|
||
|
||
Returns:
|
||
System Prompt
|
||
"""
|
||
type_name = self.POLISH_TYPES.get(polish_type, "文案")
|
||
|
||
if polish_type == "scene":
|
||
return self._build_scene_prompt()
|
||
else:
|
||
return self._build_voiceover_prompt()
|
||
|
||
def _build_scene_prompt(self) -> str:
|
||
"""构建画面描述润色 Prompt"""
|
||
return """你是一位专业的视频画面描述优化师。你的任务是优化画面描述,使其更加生动、具体、有画面感。
|
||
|
||
优化要求:
|
||
1. 增加细节描写(光线、色彩、构图)
|
||
2. 使用专业的影视语言
|
||
3. 描述要具体可执行
|
||
4. 保持简洁,不要过度渲染
|
||
5. 适合 AI 视频生成模型理解
|
||
|
||
请直接返回优化后的画面描述,不要添加解释。"""
|
||
|
||
def _build_voiceover_prompt(self) -> str:
|
||
"""构建配音文案润色 Prompt"""
|
||
return """你是一位专业的短视频文案编辑。你的任务是优化口播文案,使其更加流畅、有吸引力。
|
||
|
||
优化要求:
|
||
1. 语言口语化,适合朗读
|
||
2. 增加节奏感和停顿
|
||
3. 保留核心信息点
|
||
4. 适当使用修辞手法
|
||
5. 控制字数,不要过长
|
||
|
||
请直接返回优化后的文案,不要添加解释。"""
|