feat: output all analysis into one single .md file
as described in the title
This commit is contained in:
parent
0853aa7a06
commit
873fe41f1d
68
cli/main.py
68
cli/main.py
|
|
@ -523,12 +523,16 @@ def get_analysis_date():
|
|||
)
|
||||
|
||||
|
||||
def display_complete_report(final_state):
|
||||
"""Display the complete analysis report with team-based panels."""
|
||||
def display_complete_report(final_state, report_dir, selections):
|
||||
"""Display the complete analysis report with team-based panels and save to markdown file."""
|
||||
console.print("\n[bold green]Complete Analysis Report[/bold green]\n")
|
||||
|
||||
# Create full markdown report content
|
||||
md_content = ["# Complete Analysis Report"]
|
||||
|
||||
# I. Analyst Team Reports
|
||||
analyst_reports = []
|
||||
md_content.append("## I. Analyst Team Reports")
|
||||
|
||||
# Market Analyst Report
|
||||
if final_state.get("market_report"):
|
||||
|
|
@ -540,6 +544,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Market Analyst")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
final_state["market_report"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
# Social Analyst Report
|
||||
if final_state.get("sentiment_report"):
|
||||
|
|
@ -551,6 +559,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Social Analyst")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
final_state["sentiment_report"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
# News Analyst Report
|
||||
if final_state.get("news_report"):
|
||||
|
|
@ -562,6 +574,9 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### News Analyst")
|
||||
md_content.append(adjust_markdown_headers(final_state["news_report"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
# Fundamentals Analyst Report
|
||||
if final_state.get("fundamentals_report"):
|
||||
|
|
@ -573,6 +588,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Fundamentals Analyst")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
final_state["fundamentals_report"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
if analyst_reports:
|
||||
console.print(
|
||||
|
|
@ -588,6 +607,7 @@ def display_complete_report(final_state):
|
|||
if final_state.get("investment_debate_state"):
|
||||
research_reports = []
|
||||
debate_state = final_state["investment_debate_state"]
|
||||
md_content.append("## II. Research Team Decision")
|
||||
|
||||
# Bull Researcher Analysis
|
||||
if debate_state.get("bull_history"):
|
||||
|
|
@ -599,6 +619,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Bull Researcher")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
debate_state["bull_history"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
# Bear Researcher Analysis
|
||||
if debate_state.get("bear_history"):
|
||||
|
|
@ -610,6 +634,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Bear Researcher")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
debate_state["bear_history"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
# Research Manager Decision
|
||||
if debate_state.get("judge_decision"):
|
||||
|
|
@ -621,6 +649,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Research Manager Decision")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
debate_state["judge_decision"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
if research_reports:
|
||||
console.print(
|
||||
|
|
@ -634,6 +666,12 @@ def display_complete_report(final_state):
|
|||
|
||||
# III. Trading Team Reports
|
||||
if final_state.get("trader_investment_plan"):
|
||||
md_content.append("## III. Trading Team Plan")
|
||||
md_content.append("### Trader")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
final_state["trader_investment_plan"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
console.print(
|
||||
Panel(
|
||||
Panel(
|
||||
|
|
@ -652,6 +690,7 @@ def display_complete_report(final_state):
|
|||
if final_state.get("risk_debate_state"):
|
||||
risk_reports = []
|
||||
risk_state = final_state["risk_debate_state"]
|
||||
md_content.append("## IV. Risk Management Team Decision")
|
||||
|
||||
# Aggressive (Risky) Analyst Analysis
|
||||
if risk_state.get("risky_history"):
|
||||
|
|
@ -663,6 +702,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Aggressive (Risky) Analyst")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
risk_state["risky_history"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
# Conservative (Safe) Analyst Analysis
|
||||
if risk_state.get("safe_history"):
|
||||
|
|
@ -674,6 +717,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Conservative (Safe) Analyst")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
risk_state["safe_history"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
# Neutral Analyst Analysis
|
||||
if risk_state.get("neutral_history"):
|
||||
|
|
@ -685,6 +732,10 @@ def display_complete_report(final_state):
|
|||
padding=(1, 2),
|
||||
)
|
||||
)
|
||||
md_content.append("### Neutral Analyst")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
risk_state["neutral_history"]))
|
||||
md_content.append("") # Empty line for spacing
|
||||
|
||||
if risk_reports:
|
||||
console.print(
|
||||
|
|
@ -698,6 +749,11 @@ def display_complete_report(final_state):
|
|||
|
||||
# V. Portfolio Manager Decision
|
||||
if risk_state.get("judge_decision"):
|
||||
md_content.append("## V. Portfolio Manager Decision")
|
||||
md_content.append("### Portfolio Manager")
|
||||
md_content.append(adjust_markdown_headers(
|
||||
risk_state["judge_decision"]))
|
||||
|
||||
console.print(
|
||||
Panel(
|
||||
Panel(
|
||||
|
|
@ -712,6 +768,12 @@ def display_complete_report(final_state):
|
|||
)
|
||||
)
|
||||
|
||||
# Write the full markdown report to file
|
||||
complete_report_filename = f"complete_report_by_{selections.get('shallow_thinker')}__{selections.get('deep_thinker')}.md"
|
||||
complete_report_path = report_dir / complete_report_filename
|
||||
with open(complete_report_path, "w") as f:
|
||||
f.write("\n".join(md_content))
|
||||
|
||||
|
||||
def update_research_team_status(status):
|
||||
"""Update status for all research team members and trader."""
|
||||
|
|
@ -1102,7 +1164,7 @@ def run_analysis():
|
|||
message_buffer.update_report_section(section, final_state[section])
|
||||
|
||||
# Display the complete final report
|
||||
display_complete_report(final_state)
|
||||
display_complete_report(final_state, report_dir, selections)
|
||||
|
||||
update_display(layout)
|
||||
|
||||
|
|
|
|||
22
cli/utils.py
22
cli/utils.py
|
|
@ -1,6 +1,6 @@
|
|||
import questionary
|
||||
from typing import List, Optional, Tuple, Dict
|
||||
|
||||
import re
|
||||
from cli.models import AnalystType
|
||||
|
||||
ANALYST_ORDER = [
|
||||
|
|
@ -274,3 +274,23 @@ def select_llm_provider() -> tuple[str, str]:
|
|||
print(f"You selected: {display_name}\tURL: {url}")
|
||||
|
||||
return display_name, url
|
||||
|
||||
|
||||
def adjust_markdown_headers(markdown_text: str) -> str:
|
||||
def replace_header(match):
|
||||
hashes = match.group(1)
|
||||
header_text = match.group(2)
|
||||
header_level = len(hashes)
|
||||
|
||||
if header_level <= 3:
|
||||
new_hashes = "####" # Force at least h4
|
||||
else:
|
||||
new_hashes = "#" * (header_level + 1) # Increase one #
|
||||
|
||||
return f"{new_hashes} {header_text}"
|
||||
|
||||
# Regex to match markdown headers from level 1 to 6
|
||||
adjusted_text = re.sub(
|
||||
r"^(#{1,6})\s+(.*)", replace_header, markdown_text, flags=re.MULTILINE
|
||||
)
|
||||
return adjusted_text
|
||||
Loading…
Reference in New Issue