|
|
@@ -21,102 +21,85 @@ MODEL_NAME = "google/gemini-2.5-pro"
|
|
|
|
|
|
|
|
|
# ========== System Prompt ==========
|
|
|
+
|
|
|
GENERATE_INSPIRATIONS_PROMPT = """
|
|
|
# 任务
|
|
|
-基于给定的人设体系和锚点要素,分析和生成可能的灵感点。
|
|
|
+你是一个内容创作者,现在要从一个锚点要素出发,模拟灵感产生的完整思维路径。
|
|
|
|
|
|
## 输入说明
|
|
|
+- **<人设体系></人设体系>**: 完整的人设系统,包含所有可用的节点
|
|
|
+- **<锚点要素></锚点要素>**: 作为起点的人设要素
|
|
|
+- **<要素定义></要素定义>**: 该要素的完整定义
|
|
|
+- **<要素上下文></要素上下文>**: 该要素的上下文信息
|
|
|
|
|
|
-- **<人设体系></人设体系>**: 完整的人设系统,用于理解整体风格和定位
|
|
|
-- **<锚点要素></锚点要素>**: 作为锚点的人设要素(一级或二级分类)
|
|
|
-- **<要素定义></要素定义>**: 该要素在人设中的完整定义(如果有)
|
|
|
-- **<要素上下文></要素上下文>**: 该要素的上下文信息(所属视角、一级分类等)
|
|
|
-
|
|
|
-## 分析方法
|
|
|
+## 思维路径规则
|
|
|
|
|
|
-### 核心原则:基于人设特征和要素定位发散灵感
|
|
|
+每个灵感的产生都需要完整的思维路径:**[锚点] → [维度] → [节点/联想]**
|
|
|
|
|
|
-1. 先理解整个人设体系的风格、调性和定位
|
|
|
-2. 深入理解锚点要素在人设中的含义和作用
|
|
|
-3. 基于人设特征,推理可能触发该要素的灵感来源
|
|
|
+1. **[锚点]**: 必须从给定的锚点要素出发
|
|
|
+2. **[维度]**: 从锚点特征自然产生的思维方向(动态的,根据锚点特点决定)
|
|
|
+ - 例如:跨节点组合、具体场景联想、情感延伸、时间维度、夸张变形等
|
|
|
+3. **[节点/联想]**:
|
|
|
+ - **[节点]**: 人设体系中的其他节点
|
|
|
+ - **[联想]**: 自由联想的具体内容
|
|
|
+ - 可以有多个,用 + 连接
|
|
|
|
|
|
-### 分析步骤
|
|
|
+## 示例
|
|
|
|
|
|
-1. **理解人设体系**
|
|
|
- - 分析人设的整体风格和内容定位
|
|
|
- - 理解灵感点、目的点、关键点的组织方式
|
|
|
- - 把握人设的表达特色和价值取向
|
|
|
+假设锚点是"宠物迷惑行为":
|
|
|
|
|
|
-2. **理解锚点要素**
|
|
|
- - 结合要素定义,理解该要素的核心含义
|
|
|
- - 分析该要素在人设体系中的层级位置
|
|
|
- - 理解该要素代表的内容类型或表达方式
|
|
|
-
|
|
|
-3. **发散灵感思考**
|
|
|
- - 基于人设整体风格,思考什么样的灵感会触发该要素
|
|
|
- - 考虑不同的场景、话题、情感、事件等
|
|
|
- - 确保生成的灵感符合人设的调性和定位
|
|
|
- - 灵感应该多样化,但都要能映射到该要素
|
|
|
+```
|
|
|
+路径: [锚点]宠物迷惑行为 → [维度]跨节点组合 → [节点]职场疲惫
|
|
|
+灵感点: 猫咪上班后的呆滞眼神
|
|
|
|
|
|
-4. **生成灵感点列表**
|
|
|
- - 每个灵感点应该简洁明确(一句话)
|
|
|
- - 灵感点之间应有一定的多样性
|
|
|
- - 灵感点应该能够触发该人设要素
|
|
|
- - 纯粹基于人设和要素特征推理
|
|
|
+路径: [锚点]宠物迷惑行为 → [维度]具体场景联想 → [联想]盯着空气
|
|
|
+灵感点: 猫咪对着空气打拳
|
|
|
|
|
|
----
|
|
|
+路径: [锚点]宠物迷惑行为 → [维度]跨节点组合 → [节点]职场疲惫 + [节点]谐音梗
|
|
|
+灵感点: 猫咪"喵"班摸鱼
|
|
|
+```
|
|
|
|
|
|
## 输出格式(严格JSON)
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
- "人设理解": {
|
|
|
- "整体风格": "简要描述人设的整体风格和定位(1-2句话)",
|
|
|
- "内容调性": "该人设的内容调性和表达特点"
|
|
|
- },
|
|
|
- "要素分析": {
|
|
|
- "核心特征": "结合人设和要素定义,描述该要素的核心特征(1-2句话)",
|
|
|
- "适用场景": "该要素在这个人设中适用的内容场景"
|
|
|
- },
|
|
|
"灵感点列表": [
|
|
|
{
|
|
|
- "灵感点": "具体的灵感点描述",
|
|
|
- "说明": "为什么这个灵感可能触发该要素(结合人设特征说明)"
|
|
|
+ "路径": "[锚点]xxx → [维度]xxx → [节点/联想]xxx",
|
|
|
+ "灵感点": "具体的灵感点描述"
|
|
|
},
|
|
|
{
|
|
|
- "灵感点": "具体的灵感点描述",
|
|
|
- "说明": "为什么这个灵感可能触发该要素(结合人设特征说明)"
|
|
|
+ "路径": "[锚点]xxx → [维度]xxx → [联想]xxx",
|
|
|
+ "灵感点": "具体的灵感点描述"
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-**输出要求**:
|
|
|
-1. 必须严格按照上述JSON格式输出
|
|
|
-2. 所有字段都必须填写
|
|
|
-3. **人设理解**:体现对整个人设体系的把握
|
|
|
-4. **要素分析**:结合人设和要素定义进行分析
|
|
|
-5. **灵感点列表**:生成 5-10 个灵感点
|
|
|
-6. 每个灵感点包含:
|
|
|
- - **灵感点**:简洁的灵感描述(一句话)
|
|
|
- - **说明**:解释为什么这个灵感可能触发该要素,要结合人设特征(1-2句话)
|
|
|
-7. 灵感点应该多样化,覆盖不同角度和场景
|
|
|
-8. 纯粹基于人设和要素特征进行推理,不依赖外部参考
|
|
|
+**要求**:
|
|
|
+1. 生成 8-15 个灵感点
|
|
|
+2. 路径必须严格按照 `[锚点] → [维度] → [节点/联想]` 格式
|
|
|
+3. 维度要多样化,探索不同的思考方向
|
|
|
+4. 每个灵感点简洁明确(一句话)
|
|
|
+5. 灵感点要具体、可执行、符合人设风格
|
|
|
+6. 必须严格按照 JSON 格式输出
|
|
|
""".strip()
|
|
|
|
|
|
|
|
|
-def create_generate_agent(model_name: str) -> Agent:
|
|
|
- """创建灵感生成的 Agent
|
|
|
+def create_agent(model_name: str, prompt: str, name: str) -> Agent:
|
|
|
+ """创建 Agent
|
|
|
|
|
|
Args:
|
|
|
model_name: 模型名称
|
|
|
+ prompt: System prompt
|
|
|
+ name: Agent 名称
|
|
|
|
|
|
Returns:
|
|
|
Agent 实例
|
|
|
"""
|
|
|
agent = Agent(
|
|
|
- name="Inspiration Generator Expert",
|
|
|
- instructions=GENERATE_INSPIRATIONS_PROMPT,
|
|
|
+ name=name,
|
|
|
+ instructions=prompt,
|
|
|
model=get_model(model_name),
|
|
|
tools=[],
|
|
|
)
|
|
|
@@ -124,11 +107,12 @@ def create_generate_agent(model_name: str) -> Agent:
|
|
|
return agent
|
|
|
|
|
|
|
|
|
-def parse_generate_response(response_content: str) -> dict:
|
|
|
- """解析生成响应
|
|
|
+def parse_json_response(response_content: str, default_value: dict = None) -> dict:
|
|
|
+ """解析 JSON 响应
|
|
|
|
|
|
Args:
|
|
|
response_content: Agent 返回的响应内容
|
|
|
+ default_value: 解析失败时的默认返回值
|
|
|
|
|
|
Returns:
|
|
|
解析后的字典
|
|
|
@@ -149,17 +133,7 @@ def parse_generate_response(response_content: str) -> dict:
|
|
|
return json.loads(json_text)
|
|
|
except Exception as e:
|
|
|
print(f"解析响应失败: {e}")
|
|
|
- return {
|
|
|
- "人设理解": {
|
|
|
- "整体风格": "解析失败",
|
|
|
- "内容调性": "解析失败"
|
|
|
- },
|
|
|
- "要素分析": {
|
|
|
- "核心特征": "解析失败",
|
|
|
- "适用场景": "解析失败"
|
|
|
- },
|
|
|
- "灵感点列表": []
|
|
|
- }
|
|
|
+ return default_value if default_value else {}
|
|
|
|
|
|
|
|
|
def format_persona_system(persona_data: dict) -> str:
|
|
|
@@ -261,13 +235,62 @@ def find_step1_file(persona_dir: str, inspiration: str, model_name: str) -> str:
|
|
|
return str(step1_files[0])
|
|
|
|
|
|
|
|
|
+async def generate_inspirations_with_paths(
|
|
|
+ persona_system_text: str,
|
|
|
+ matched_element: str,
|
|
|
+ element_definition: str,
|
|
|
+ element_context: str
|
|
|
+) -> list:
|
|
|
+ """生成带思维路径的灵感点列表
|
|
|
+
|
|
|
+ Args:
|
|
|
+ persona_system_text: 完整人设系统文本
|
|
|
+ matched_element: 匹配要素
|
|
|
+ element_definition: 要素定义
|
|
|
+ element_context: 要素上下文
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ 灵感点列表 [{"路径": "...", "灵感点": "..."}, ...]
|
|
|
+ """
|
|
|
+ task_description = f"""## 本次任务
|
|
|
+
|
|
|
+<人设体系>
|
|
|
+{persona_system_text}
|
|
|
+</人设体系>
|
|
|
+
|
|
|
+<锚点要素>
|
|
|
+{matched_element}
|
|
|
+</锚点要素>
|
|
|
+
|
|
|
+<要素定义>
|
|
|
+{element_definition if element_definition else '无'}
|
|
|
+</要素定义>
|
|
|
+
|
|
|
+<要素上下文>
|
|
|
+{element_context}
|
|
|
+</要素上下文>
|
|
|
+
|
|
|
+请从锚点要素出发,模拟灵感产生的完整思维路径,生成多个灵感点,严格按照 JSON 格式输出。"""
|
|
|
+
|
|
|
+ messages = [{
|
|
|
+ "role": "user",
|
|
|
+ "content": [{"type": "input_text", "text": task_description}]
|
|
|
+ }]
|
|
|
+
|
|
|
+ agent = create_agent(MODEL_NAME, GENERATE_INSPIRATIONS_PROMPT, "Inspiration Path Generator")
|
|
|
+ result = await Runner.run(agent, input=messages)
|
|
|
+
|
|
|
+ parsed = parse_json_response(result.final_output, {"灵感点列表": []})
|
|
|
+ return parsed.get("灵感点列表", [])
|
|
|
+
|
|
|
+
|
|
|
async def process_step3_generate_inspirations(
|
|
|
step1_top1: dict,
|
|
|
persona_data: dict,
|
|
|
current_time: str = None,
|
|
|
log_url: str = None
|
|
|
) -> dict:
|
|
|
- """执行灵感生成分析(核心业务逻辑)
|
|
|
+ """执行灵感生成分析(核心业务逻辑 - 单层路径生成)
|
|
|
|
|
|
Args:
|
|
|
step1_top1: step1 的 top1 匹配结果
|
|
|
@@ -291,60 +314,30 @@ async def process_step3_generate_inspirations(
|
|
|
# 查找要素定义
|
|
|
element_definition = find_element_definition(persona_data, matched_element)
|
|
|
|
|
|
- print(f"\n开始灵感生成分析")
|
|
|
+ print(f"\n{'=' * 80}")
|
|
|
+ print(f"Step3: 基于锚点生成灵感路径")
|
|
|
+ print(f"{'=' * 80}")
|
|
|
print(f"锚点要素: {matched_element}")
|
|
|
print(f"要素定义: {element_definition if element_definition else '(未找到定义)'}")
|
|
|
print(f"模型: {MODEL_NAME}\n")
|
|
|
|
|
|
- # 构建任务描述(包含完整人设系统、锚点要素、要素定义、要素上下文)
|
|
|
- task_description = f"""## 本次分析任务
|
|
|
-
|
|
|
-<人设体系>
|
|
|
-{persona_system_text}
|
|
|
-</人设体系>
|
|
|
-
|
|
|
-<锚点要素>
|
|
|
-{matched_element}
|
|
|
-</锚点要素>
|
|
|
-
|
|
|
-<要素定义>
|
|
|
-{element_definition if element_definition else '无'}
|
|
|
-</要素定义>
|
|
|
-
|
|
|
-<要素上下文>
|
|
|
-{element_context}
|
|
|
-</要素上下文>
|
|
|
-
|
|
|
-请基于上述完整的人设体系和锚点要素,深入理解人设的整体风格和该要素的定位,推理并生成可能的灵感点列表,严格按照系统提示中的 JSON 格式输出结果。"""
|
|
|
+ # 生成灵感点(单层,包含完整思维路径)
|
|
|
+ with custom_span(name="生成带路径的灵感点", data={"锚点要素": matched_element}):
|
|
|
+ inspirations = await generate_inspirations_with_paths(
|
|
|
+ persona_system_text, matched_element, element_definition, element_context
|
|
|
+ )
|
|
|
|
|
|
- # 构造消息
|
|
|
- messages = [{
|
|
|
- "role": "user",
|
|
|
- "content": [
|
|
|
- {
|
|
|
- "type": "input_text",
|
|
|
- "text": task_description
|
|
|
- }
|
|
|
- ]
|
|
|
- }]
|
|
|
-
|
|
|
- # 使用 custom_span 追踪生成过程
|
|
|
- with custom_span(
|
|
|
- name=f"Step3: 灵感生成 - {matched_element}",
|
|
|
- data={
|
|
|
- "锚点要素": matched_element,
|
|
|
- "模型": MODEL_NAME,
|
|
|
- "步骤": "基于要素生成灵感点"
|
|
|
- }
|
|
|
- ):
|
|
|
- # 创建 Agent
|
|
|
- agent = create_generate_agent(MODEL_NAME)
|
|
|
-
|
|
|
- # 运行 Agent
|
|
|
- result = await Runner.run(agent, input=messages)
|
|
|
+ print(f"\n{'=' * 80}")
|
|
|
+ print(f"完成!共生成 {len(inspirations)} 个灵感点")
|
|
|
+ print(f"{'=' * 80}\n")
|
|
|
|
|
|
- # 解析响应
|
|
|
- parsed_result = parse_generate_response(result.final_output)
|
|
|
+ # 预览前3个
|
|
|
+ if inspirations:
|
|
|
+ print("预览前3个灵感点:")
|
|
|
+ for i, item in enumerate(inspirations[:3], 1):
|
|
|
+ print(f" {i}. 路径: {item.get('路径', '')}")
|
|
|
+ print(f" 灵感: {item.get('灵感点', '')}")
|
|
|
+ print()
|
|
|
|
|
|
# 构建输出
|
|
|
return {
|
|
|
@@ -360,7 +353,7 @@ async def process_step3_generate_inspirations(
|
|
|
"要素上下文": element_context
|
|
|
},
|
|
|
"step1_结果": step1_top1,
|
|
|
- "生成结果": parsed_result
|
|
|
+ "灵感点列表": inspirations
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -461,17 +454,14 @@ async def main(current_time: str, log_url: str, force: bool = False):
|
|
|
with open(output_file, 'w', encoding='utf-8') as f:
|
|
|
json.dump(output, f, ensure_ascii=False, indent=2)
|
|
|
|
|
|
- # 输出生成的灵感点预览
|
|
|
- generated = output.get("生成结果", {})
|
|
|
- inspirations = generated.get("灵感点列表", [])
|
|
|
-
|
|
|
+ # 输出统计信息
|
|
|
+ stats = output.get("统计", {})
|
|
|
print(f"\n{'=' * 80}")
|
|
|
- print(f"生成了 {len(inspirations)} 个灵感点:")
|
|
|
+ print(f"统计信息:")
|
|
|
+ print(f" 外层维度数: {stats.get('外层维度数', 0)}")
|
|
|
+ print(f" 内层维度数: {stats.get('内层维度数', 0)}")
|
|
|
+ print(f" 灵感点总数: {stats.get('灵感点总数', 0)}")
|
|
|
print(f"{'=' * 80}")
|
|
|
- for i, item in enumerate(inspirations[:5], 1):
|
|
|
- print(f"{i}. {item.get('灵感点', '')}")
|
|
|
- if len(inspirations) > 5:
|
|
|
- print(f"... 还有 {len(inspirations) - 5} 个")
|
|
|
|
|
|
print(f"\n完成!结果已保存到: {output_file}")
|
|
|
if log_url:
|