feat: import external reports

This commit is contained in:
Tomortec 2025-07-01 23:53:46 +08:00
parent 3f5ee3f5b2
commit dc93d025fb
9 changed files with 56 additions and 14 deletions

View File

@ -459,20 +459,28 @@ def get_user_selections():
)
selected_research_depth = select_research_depth()
# Step 5: OpenAI backend
# Step 5: External Reports
console.print(
create_question_box(
get_lang("step5_title"), get_lang("step5_prompt")
)
)
selected_llm_provider, backend_url = select_llm_provider()
# Step 6: Thinking agents
external_reports = get_external_reports()
# Step 6: OpenAI backend
console.print(
create_question_box(
get_lang("step6_title"), get_lang("step6_prompt")
)
)
selected_llm_provider, backend_url = select_llm_provider()
# Step 7: Thinking agents
console.print(
create_question_box(
get_lang("step7_title"), get_lang("step7_prompt")
)
)
selected_shallow_thinker = select_shallow_thinking_agent(selected_llm_provider)
selected_deep_thinker = select_deep_thinking_agent(selected_llm_provider)
@ -483,6 +491,7 @@ def get_user_selections():
"research_depth": selected_research_depth,
"llm_provider": selected_llm_provider.lower(),
"backend_url": backend_url,
"external_reports": external_reports,
"shallow_thinker": selected_shallow_thinker,
"deep_thinker": selected_deep_thinker,
}
@ -511,6 +520,15 @@ def get_analysis_date():
"[red]Error: Invalid date format. Please use YYYY-MM-DD[/red]"
)
def get_external_reports():
"""Get external reports from user input."""
need_external = typer.confirm(
get_lang("step5_prompt"), default=False
)
if need_external:
reports = typer.edit(require_save=False)
return reports.replace("\n", "").split("<END>") if reports else []
return []
def display_complete_report(final_state):
"""Display the complete analysis report with team-based panels."""
@ -761,6 +779,10 @@ def run_analysis():
"System",
f"Selected analysts: {', '.join(analyst.value for analyst in selections['analysts'])}",
)
message_buffer.add_message(
"User",
f"External reports: {'<END>\n'.join(selections['external_reports']) if selections['external_reports'] else 'None'}",
)
update_display(layout)
# Reset agent statuses
@ -786,7 +808,7 @@ def run_analysis():
# Initialize state and get graph args
init_agent_state = graph.propagator.create_initial_state(
selections["ticker"], selections["analysis_date"]
selections["ticker"], selections["analysis_date"], selections["external_reports"]
)
args = graph.propagator.get_graph_args()

View File

@ -10,6 +10,7 @@ def create_research_manager(llm, memory):
sentiment_report = state["sentiment_report"]
news_report = state["news_report"]
fundamentals_report = state["fundamentals_report"]
external_reports = state.get("external_reports", [])
investment_debate_state = state["investment_debate_state"]
@ -23,7 +24,9 @@ def create_research_manager(llm, memory):
prompt = get_prompts("managers", "research_manager") \
.replace("{max_tokens}", str(DEFAULT_CONFIG["max_tokens"])) \
.replace("{past_memory_str}", past_memory_str) \
.replace("{history}", history)
.replace("{history}", history) \
.replace("{external_reports}", "\n".join(external_reports))
response = llm.invoke(prompt)
new_investment_debate_state = {

View File

@ -14,6 +14,7 @@ def create_risk_manager(llm, memory):
news_report = state["news_report"]
fundamentals_report = state["news_report"]
sentiment_report = state["sentiment_report"]
external_reports = state.get("external_reports", [])
trader_plan = state["investment_plan"]
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
@ -27,7 +28,9 @@ def create_risk_manager(llm, memory):
.replace("{max_tokens}", str(DEFAULT_CONFIG["max_tokens"])) \
.replace("{trader_plan}", trader_plan) \
.replace("{past_memory_str}", past_memory_str) \
.replace("{history}", history)
.replace("{history}", history) \
.replace("{external_reports}", "\n".join(external_reports))
response = llm.invoke(prompt)
new_risk_debate_state = {

View File

@ -11,6 +11,7 @@ def create_trader(llm, memory):
sentiment_report = state["sentiment_report"]
news_report = state["news_report"]
fundamentals_report = state["fundamentals_report"]
external_reports = state.get("external_reports", [])
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
past_memories = memory.get_memories(curr_situation, n_matches=2)
@ -23,7 +24,8 @@ def create_trader(llm, memory):
"role": "user",
"content": get_prompts("trader", "user_message") \
.replace("{company_name}", company_name) \
.replace("{investment_plan}", investment_plan)
.replace("{investment_plan}", investment_plan) \
.replace("{external_reports}", "\n".join(external_reports))
}
messages = [

View File

@ -54,6 +54,7 @@ class AgentState(MessagesState):
sender: Annotated[str, "Agent that sent this message"]
# research step
external_reports: Annotated[list[str], "Reports from the External Expert Researcher"]
market_report: Annotated[str, "Report from the Market Analyst"]
sentiment_report: Annotated[str, "Report from the Social Media Analyst"]
news_report: Annotated[

View File

@ -16,7 +16,7 @@ class Propagator:
self.max_recur_limit = max_recur_limit
def create_initial_state(
self, company_name: str, trade_date: str
self, company_name: str, trade_date: str, external_reports: list[str] = []
) -> Dict[str, Any]:
"""Create the initial state for the agent graph."""
return {
@ -39,6 +39,7 @@ class Propagator:
"fundamentals_report": "",
"sentiment_report": "",
"news_report": "",
"external_reports": external_reports,
}
def get_graph_args(self) -> Dict[str, Any]:

View File

@ -51,10 +51,12 @@ LANG = {
"step3_prompt": "Select your LLM analyst agents for the analysis",
"step4_title": "Step 4: Research Depth",
"step4_prompt": "Select your research depth level",
"step5_title": "Step 5: Thinking Agents",
"step5_prompt": "Select your thinking agents for analysis",
"step5_title": "Step 5: External Reports",
"step5_prompt": "Do you need to import external reports?",
"step6_title": "Step 6: Thinking Agents",
"step6_prompt": "Select your thinking agents for analysis",
"step7_title": "Step 7: Thinking Agents",
"step7_prompt": "Select your thinking agents for analysis",
"default_ticker": "SPY",
"ticker_validate": "Please enter a valid ticker symbol.",
"date_validate": "Please enter a valid date in YYYY-MM-DD format.",

View File

@ -51,10 +51,12 @@ LANG = {
"step3_prompt": "请选择用于分析的LLM分析师代理",
"step4_title": "步骤4研究深度",
"step4_prompt": "请选择研究深度等级",
"step5_title": "步骤5思考代理",
"step5_prompt": "请选择用于分析的思考代理",
"step5_title": "步骤5外部报告",
"step5_prompt": "需要导入外部报告吗?",
"step6_title": "步骤6思考代理",
"step6_prompt": "请选择用于分析的思考代理",
"step7_title": "步骤7思考代理",
"step7_prompt": "请选择用于分析的思考代理",
"default_ticker": "SPY",
"ticker_validate": "请输入有效的资产代码。",
"date_validate": "请输入有效的日期格式为YYYY-MM-DD。",

View File

@ -86,6 +86,9 @@ PROMPTS = {
考虑你过去在类似情况下的错误利用这些见解来完善你的决策并确保你正在学习和改进以对话的方式呈现你的分析就像自然地说话一样无需特殊的格式
必须认真考虑外部分析师报告:
{external_reports}
你在过去的错误和反思:
\"{past_memory_str}\"
@ -107,6 +110,9 @@ PROMPTS = {
- 基于辩论与反思的详细理由
- 务必不超过{max_tokens}tokens
必须认真考虑外部分析师报告:
{external_reports}
分析师辩论历史
{history}"""
#endregion
@ -199,7 +205,7 @@ Here is the current conversation history: {history} Here is the last response fr
},
"trader": {
#region Trader
"user_message": "以下是针对 {company_name} 的投资建议方案,由多个分析师协作提供,涵盖了技术趋势、宏观指标与社交舆情。请将此方案作为下一步交易决策的参考依据:\n\n建议方案:{investment_plan}\n\n请基于此作出合理而有策略的判断。",
"user_message": "以下是针对 {company_name} 的投资建议方案,由多个分析师协作提供,涵盖了技术趋势、宏观指标与社交舆情。请将此方案作为下一步交易决策的参考依据:\n\n建议方案:{investment_plan}\n\n外部专家分析:{external_reports}\n\n请基于此作出合理而有策略的判断。",
"system_message": "你是一名交易代理,负责根据市场数据做出买入、卖出或持有的明确投资决策。分析结束后,请以 “最终投资建议BUY/HOLD/SELL” 结尾,明确表达立场。请结合历史经验做出更优判断。以下为你在类似情况中总结的教训:{past_memory_str}"
#endregion
},