| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- from dotenv import load_dotenv
- load_dotenv()
- from hello_agents import SimpleAgent, HelloAgentsLLM
- from hello_agents.tools import NoteTool
- from prompt import OUTLINE_PROMPT
- import re
- import os
- def extract_note_id(output: str) -> str:
- """从 NoteTool 的输出文本中提取 note_id"""
- match = re.search(r"ID:\s*(note_[0-9_]+)", output)
- if not match:
- raise ValueError(f"无法从输出解析 note_id:\n{output}")
- return match.group(1)
- class OutlineAgent(SimpleAgent):
- """小说大纲生成Agent"""
- def __init__(self, name: str, llm: HelloAgentsLLM = HelloAgentsLLM(), **kwargs):
- self.workspace = kwargs.pop("workspace", "./outputs")
- super().__init__(name=name, llm=llm)
- self.outline_length = 3000
- self.note_tools = {}
- def _ensure_tool(self, novel_id: str, title: str = None):
- if not self.note_tools.get(novel_id):
- if not title:
- raise ValueError(f"Tool for novel_id {novel_id} not initialized and title not provided.")
- self.note_tools[novel_id] = NoteTool(workspace=os.path.join(self.workspace, f"{title}-{novel_id}", 'outline'))
- def run(self, user_input: str, **kwargs) -> str:
- """运行 Agent"""
- # 小说id用来区分小说,命名可能会重复
- novel_id = kwargs.pop("novel_id", None)
- assert novel_id, "请提供小说ID"
- title = kwargs.pop("title", None)
- assert title, "请提供小说标题"
- self._ensure_tool(novel_id, title)
- # 1. 构建上下文
- target_length = kwargs.pop("target_length", self.outline_length)
- context = OUTLINE_PROMPT.format(
- user_input=user_input,
- title=title or "无",
- tags=','.join([str(tag) for tag in kwargs.values() if tag]) or '无',
- target_length=target_length
- )
- # 2. 使用上下文调用 LLM
- messages = [{"role": "user", "content": context}]
- response = self.llm.invoke(messages)
- # 3. 保存大纲到笔记
- create_output = self.note_tools[novel_id].run({
- "action": "create",
- "title": f"{novel_id}-大纲",
- "content": response,
- "note_type": "outline",
- "tags": ["outline"]
- })
- # 获取笔记ID,建立与小说ID的关联
- note_id = extract_note_id(create_output)
- return response, note_id
- def get_outline(self, novel_id: str, note_id: str, title: str = None) -> str:
- """获取大纲"""
- if title:
- self._ensure_tool(novel_id, title)
- return self.note_tools[novel_id].run({
- "action": "read",
- "note_id": note_id
- })
-
- def del_outline(self, novel_id: str, note_id: str, title: str = None):
- """删除大纲"""
- if title:
- self._ensure_tool(novel_id, title)
- self.note_tools[novel_id].run({
- "action": "delete",
- "note_id": note_id
- })
- def update_outline(self, novel_id: str, note_id: str, title: str = None, **kwargs):
- """更新大纲"""
- if title:
- self._ensure_tool(novel_id, title)
- self.note_tools[novel_id].run({
- "action": "update",
- "note_id": note_id,
- **kwargs
- })
- def main():
- print("=" * 80)
- print("Novel OutlineAgent 示例")
- print("=" * 80 + "\n")
- llm = HelloAgentsLLM()
- novel_id = "demo_novel_001"
- title = "记忆之城"
- agent = OutlineAgent(
- name="小说大纲助手",
- llm=llm,
- workspace="./outputs",
- )
- user_idea = "一位能与城市记忆对话的年轻人,在拆迁浪潮中发现一段被刻意抹去的历史。"
- # 1. 生成大纲
- print(f"\n正在生成大纲...")
- response, note_id = agent.run(
- user_input=user_idea,
- novel_id=novel_id,
- title=title,
- 风格标签="都市奇幻",
- 情感基调="成长与和解",
- )
- print("生成的大纲(节选):")
- print(response[:200] + "...\n")
- print(f"大纲已保存到 NoteTool,note_id: {note_id}")
- # 2. 读取大纲
- print(f"\n正在读取大纲 (Note ID: {note_id})...")
- # 注意:get_outline 需要传入 novel_id 和 note_id
- stored_outline = agent.get_outline(novel_id, note_id)
- print("从 NoteTool 中读取的大纲(节选):")
- # 去掉可能存在的 frontmatter 后的内容预览(这里简单展示原始返回)
- print(stored_outline[:200] + "...")
- # 3. 更新大纲
- print(f"\n正在更新大纲...")
- # 简单模拟:在原有内容后追加一些信息
- # 注意:update_outline 会覆盖 content,所以需要先读取再追加,或者直接传入完整的新内容
- # 这里我们演示读取后追加
- new_content = stored_outline + "\n\n## 补充设定\n主角的能力在雨天会增强,且能听到建筑物的'呼吸声'。"
- agent.update_outline(novel_id, note_id, content=new_content, tags=["outline", "updated"])
- print("大纲已更新。")
- # 4. 再次读取验证更新
- print(f"\n正在验证更新后的内容...")
- updated_outline = agent.get_outline(novel_id, note_id)
- if "主角的能力在雨天会增强" in updated_outline:
- print("验证成功:更新内容已存在。")
- else:
- print("验证失败:未找到更新内容。")
- # 5. 删除大纲(演示,默认注释掉以免误删)
- # print(f"\n正在删除大纲...")
- # agent.del_outline(novel_id, note_id)
- # print("大纲已删除。")
- if __name__ == "__main__":
- main()
|