Просмотр исходного кода

chore: 更新配置、修复脚本生成并添加验证脚本

- 构建并优化全流程测试脚本 :

- 创建了 test_agent_workflow.py ,用于在终端模拟完整的 Agent 运行流程。
- 配置脚本使用 Tavily 作为搜索引擎(替代不稳定的 DuckDuckGo),并启用了 TTS(语音合成)功能进行完整测试。
- 优化了日志输出,屏蔽了繁杂的调试信息,让终端输出更加清晰易读。
- 修复核心逻辑 Bug :

- 修复了 agent.py 中 ScriptGenerationService 初始化错误的问题(之前错误地传入了 LLM 而非 Agent 实例)。
- 修复了任务执行循环的 Bug,确保 Agent 能够真正执行研究任务,而不是跳过执行步骤。
- 解决 TTS API 超时与生成问题 :

- 在 audio_generator.py 中,将 TTS 请求的超时时间从 30 秒增加到 300 秒 ,解决了因 ECNU API 响应缓慢导致的 ReadTimeout 报错。
- 在 prompts.py 中,将播客对话轮数限制调整为 8-12 轮 。这不仅加快了生成速度,更重要的是避免了因生成内容过长导致 JSON 格式截断,从而修复了脚本解析失败的问题。
- 验证测试结果 :

- 成功运行了完整流程,Agent 对 "DeepSeek Technical Report" 进行了深入研究。
- 生成了研究报告 :包含背景、核心洞见、证据数据等结构化内容。
- 生成了播客脚本 :产出了 15 轮的双人对话脚本。
- 生成了音频文件 :成功调用 API 生成了所有对话片段,并合成了最终的播客音频文件。
JJSun 5 месяцев назад
Родитель
Сommit
61b2faf55a

+ 3 - 1
Co-creation-projects/JJason-DeepCastAgent/.gitignore

@@ -1,2 +1,4 @@
 .env
-docs/
+docs/
+notes/
+output/

+ 1 - 1
Co-creation-projects/JJason-DeepCastAgent/backend/env.example

@@ -1,6 +1,6 @@
 # 核心配置
 LOG_LEVEL=INFO
-SEARCH_API=duckduckgo
+SEARCH_API=tavily
 MAX_WEB_RESEARCH_LOOPS=3
 FETCH_FULL_PAGE=True
 

+ 117 - 0
Co-creation-projects/JJason-DeepCastAgent/backend/scripts/test_agent_workflow.py

@@ -0,0 +1,117 @@
+import os
+import sys
+from pathlib import Path
+
+# Add src to sys.path
+# backend/scripts/test_agent_workflow.py -> backend/src
+project_root = Path(__file__).resolve().parent.parent
+sys.path.append(str(project_root / "src"))
+
+from dotenv import load_dotenv
+
+# Load env from backend/.env
+env_path = project_root / ".env"
+if env_path.exists():
+    print(f"Loading environment from {env_path}")
+    load_dotenv(env_path)
+else:
+    print(f"Warning: .env file not found at {env_path}")
+
+from config import Configuration, SearchAPI
+from agent import DeepResearchAgent
+
+import logging
+
+def configure_logging():
+    # Set global level to INFO first
+    logging.basicConfig(level=logging.INFO, format='%(message)s')
+    
+    # Suppress verbose logs from specific loggers
+    loggers_to_silence = [
+        "services.tool_events", 
+        "services.planner",
+        "services.search",
+        "services.audio_generator",
+        "services.audio_synthesizer",
+        "services.script_generator",
+        "httpx",
+        "httpcore",
+        "urllib3",
+        "hello_agents"
+    ]
+    for logger_name in loggers_to_silence:
+        logging.getLogger(logger_name).setLevel(logging.WARNING)
+
+def main():
+    configure_logging()
+    print("Initializing DeepResearchAgent...")
+    # Initialize with default config (will load from env)
+    config = Configuration.from_env()
+    
+    # Override for testing speed
+    config.max_web_research_loops = 1
+    # Enable TTS for full workflow test
+    # config.tts_api_key = None 
+    # Use Tavily for search as DDG is flaky
+    config.search_api = SearchAPI.TAVILY
+    
+    print(f"Max Web Research Loops: {config.max_web_research_loops} (Overridden for testing)")
+
+    
+    # Print some config to verify
+    print("\nCurrent Configuration:")
+    print(f"LLM Provider: {config.llm_provider}")
+    print(f"Model: {config.resolved_model()}")
+    print(f"Search API: {config.search_api}")
+    print(f"TTS Enabled: {bool(config.tts_api_key)}")
+    print(f"FFmpeg Path: {config.ffmpeg_path}")
+    
+    agent = DeepResearchAgent(config=config)
+    
+    # Clean up previous audio outputs
+    output_dir = Path(config.audio_output_dir)
+    if output_dir.exists():
+        print(f"Cleaning up output directory: {output_dir}")
+        import shutil
+        shutil.rmtree(output_dir)
+    output_dir.mkdir(parents=True, exist_ok=True)
+    
+    topic = "DeepSeek Technical Report"
+    print(f"Starting research on topic: {topic}")
+    
+    try:
+        result = agent.run(topic)
+        
+        print("\n" + "="*50)
+        print("WORKFLOW COMPLETED SUCCESSFULLY")
+        print("="*50)
+        
+        print(f"Report Summary Length: {len(result.running_summary)}")
+        
+        print("\n" + "="*20 + " REPORT CONTENT " + "="*20)
+        print(result.running_summary)
+        print("="*56 + "\n")
+        
+        if result.podcast_script:
+            print(f"Podcast Script Generated: Yes ({len(result.podcast_script)} dialogue items)")
+        else:
+            print("Podcast Script Generated: No")
+            
+        # Check output files
+        output_dir = Path(config.audio_output_dir)
+        if output_dir.exists():
+            print(f"\nAudio Output Directory: {output_dir}")
+            files = list(output_dir.glob("*"))
+            print(f"Files generated ({len(files)}):")
+            for f in files:
+                print(f" - {f.name}")
+        else:
+            print(f"\nAudio Output Directory not found: {output_dir}")
+            
+    except Exception as e:
+        print(f"\nERROR: Workflow failed with error: {e}")
+        import traceback
+        traceback.print_exc()
+
+if __name__ == "__main__":
+    main()

+ 0 - 0
Co-creation-projects/JJason-DeepCastAgent/backend/tests/test_audio_generator.py → Co-creation-projects/JJason-DeepCastAgent/backend/scripts/test_audio_generator.py


+ 0 - 0
Co-creation-projects/JJason-DeepCastAgent/backend/tests/test_script_generator.py → Co-creation-projects/JJason-DeepCastAgent/backend/scripts/test_script_generator.py


+ 0 - 0
Co-creation-projects/JJason-DeepCastAgent/backend/tests/verify_ecnu_llm.py → Co-creation-projects/JJason-DeepCastAgent/backend/scripts/verify_ecnu_llm.py


+ 0 - 0
Co-creation-projects/JJason-DeepCastAgent/backend/tests/verify_ecnu_tts.py → Co-creation-projects/JJason-DeepCastAgent/backend/scripts/verify_ecnu_tts.py


+ 0 - 0
Co-creation-projects/JJason-DeepCastAgent/backend/tests/verify_ffmpeg.py → Co-creation-projects/JJason-DeepCastAgent/backend/scripts/verify_ffmpeg.py


+ 0 - 0
Co-creation-projects/JJason-DeepCastAgent/backend/tests/verify_search.py → Co-creation-projects/JJason-DeepCastAgent/backend/scripts/verify_search.py


+ 8 - 2
Co-creation-projects/JJason-DeepCastAgent/backend/src/agent.py

@@ -66,6 +66,10 @@ class DeepResearchAgent:
             name="报告撰写专家",
             system_prompt=report_writer_instructions.strip(),
         )
+        self.script_agent = self._create_tool_aware_agent(
+            name="脚本策划专家",
+            system_prompt=script_writer_instructions.strip(),
+        )
 
         self._summarizer_factory: Callable[[], ToolAwareSimpleAgent] = lambda: self._create_tool_aware_agent(  # noqa: E501
             name="任务总结专家",
@@ -75,8 +79,9 @@ class DeepResearchAgent:
         self.planner = PlanningService(self.todo_agent, self.config)
         self.summarizer = SummarizationService(self._summarizer_factory, self.config)
         self.reporting = ReportingService(self.report_agent, self.config)
-        self.script_generator = ScriptGenerationService(self.llm, self.config)
+        self.script_generator = ScriptGenerationService(self.script_agent, self.config)
         self.audio_generator = AudioGenerationService(self.config)
+
         self.podcast_synthesizer = PodcastSynthesisService(self.config)
         self._last_search_notices: list[str] = []
 
@@ -140,7 +145,8 @@ class DeepResearchAgent:
             state.todo_items = [self.planner.create_fallback_task(state)]
 
         for task in state.todo_items:
-            self._execute_task(state, task, emit_stream=False)
+            for _ in self._execute_task(state, task, emit_stream=False):
+                pass
 
         report = self.reporting.generate_report(state)
         self._drain_tool_events(state)

+ 1 - 1
Co-creation-projects/JJason-DeepCastAgent/backend/src/prompts.py

@@ -125,7 +125,7 @@ script_writer_instructions = """
 2. **主体**:深入浅出地讨论报告中的核心观点、数据和案例。Host 负责追问“为什么”、“怎么做”或“这对普通人有什么影响”,Guest 负责解答。
 3. **结尾**:Host 总结核心收获,Guest 给出简短的未来展望或金句。Host 结束语。
 4. **风格**:轻松、口语化,适当使用感叹词(如“哇”、“原来如此”、“确实”),但不要过度。
-5. **长度**:对话回合数控制在 10-20 轮之间,确保内容充实但不拖沓。
+5. **长度**:对话回合数控制在 8-12 轮之间,确保内容充实但不拖沓,且避免输出过长导致截断
 
 <FORMAT>
 请严格输出 JSON 格式的列表,不包含 Markdown 代码块标记(如 ```json ... ```),直接输出 JSON 数组:

+ 1 - 1
Co-creation-projects/JJason-DeepCastAgent/backend/src/services/audio_generator.py

@@ -108,7 +108,7 @@ class AudioGenerationService:
                 self._config.tts_base_url,
                 json=payload,
                 headers=headers,
-                timeout=30 # TTS generation might take some time
+                timeout=300
             )
             
             if response.status_code == 200:

+ 1 - 2
Co-creation-projects/JJason-DeepCastAgent/backend/src/services/script_generator.py

@@ -11,7 +11,6 @@ from hello_agents import ToolAwareSimpleAgent
 
 from models import SummaryState
 from config import Configuration
-from prompts import script_writer_instructions
 from utils import strip_thinking_tokens
 
 logger = logging.getLogger(__name__)
@@ -31,7 +30,7 @@ class ScriptGenerationService:
             logger.warning("No structured report available for script generation.")
             return []
 
-        prompt = f"{script_writer_instructions}\n\n<RESEARCH_REPORT>\n{state.structured_report}\n</RESEARCH_REPORT>"
+        prompt = f"<RESEARCH_REPORT>\n{state.structured_report}\n</RESEARCH_REPORT>"
 
         response = self._agent.run(prompt)
         self._agent.clear_history()