UTF-8 encoding to fix error with saving documents on Windows

This commit is contained in:
jaycode 2026-03-18 10:46:20 +07:00
parent f362a160c3
commit 3fc9609387
1 changed files with 29 additions and 13 deletions

View File

@ -1,11 +1,27 @@
from typing import Optional from typing import Optional
import datetime import datetime
import sys
import typer import typer
from pathlib import Path from pathlib import Path
from functools import wraps from functools import wraps
from rich.console import Console from rich.console import Console
from dotenv import load_dotenv from dotenv import load_dotenv
def configure_stdio_encoding() -> None:
"""Force UTF-8 for terminal output on Windows-friendly Python streams."""
for stream_name in ("stdout", "stderr"):
stream = getattr(sys, stream_name, None)
if stream is None or not hasattr(stream, "reconfigure"):
continue
try:
stream.reconfigure(encoding="utf-8", errors="replace")
except ValueError:
# Some redirected streams do not allow reconfiguration.
pass
configure_stdio_encoding()
# Load environment variables from .env file # Load environment variables from .env file
load_dotenv() load_dotenv()
from rich.panel import Panel from rich.panel import Panel
@ -623,19 +639,19 @@ def save_report_to_disk(final_state, ticker: str, save_path: Path):
analyst_parts = [] analyst_parts = []
if final_state.get("market_report"): if final_state.get("market_report"):
analysts_dir.mkdir(exist_ok=True) analysts_dir.mkdir(exist_ok=True)
(analysts_dir / "market.md").write_text(final_state["market_report"]) (analysts_dir / "market.md").write_text(final_state["market_report"], encoding="utf-8")
analyst_parts.append(("Market Analyst", final_state["market_report"])) analyst_parts.append(("Market Analyst", final_state["market_report"]))
if final_state.get("sentiment_report"): if final_state.get("sentiment_report"):
analysts_dir.mkdir(exist_ok=True) analysts_dir.mkdir(exist_ok=True)
(analysts_dir / "sentiment.md").write_text(final_state["sentiment_report"]) (analysts_dir / "sentiment.md").write_text(final_state["sentiment_report"], encoding="utf-8")
analyst_parts.append(("Social Analyst", final_state["sentiment_report"])) analyst_parts.append(("Social Analyst", final_state["sentiment_report"]))
if final_state.get("news_report"): if final_state.get("news_report"):
analysts_dir.mkdir(exist_ok=True) analysts_dir.mkdir(exist_ok=True)
(analysts_dir / "news.md").write_text(final_state["news_report"]) (analysts_dir / "news.md").write_text(final_state["news_report"], encoding="utf-8")
analyst_parts.append(("News Analyst", final_state["news_report"])) analyst_parts.append(("News Analyst", final_state["news_report"]))
if final_state.get("fundamentals_report"): if final_state.get("fundamentals_report"):
analysts_dir.mkdir(exist_ok=True) analysts_dir.mkdir(exist_ok=True)
(analysts_dir / "fundamentals.md").write_text(final_state["fundamentals_report"]) (analysts_dir / "fundamentals.md").write_text(final_state["fundamentals_report"], encoding="utf-8")
analyst_parts.append(("Fundamentals Analyst", final_state["fundamentals_report"])) analyst_parts.append(("Fundamentals Analyst", final_state["fundamentals_report"]))
if analyst_parts: if analyst_parts:
content = "\n\n".join(f"### {name}\n{text}" for name, text in analyst_parts) content = "\n\n".join(f"### {name}\n{text}" for name, text in analyst_parts)
@ -648,15 +664,15 @@ def save_report_to_disk(final_state, ticker: str, save_path: Path):
research_parts = [] research_parts = []
if debate.get("bull_history"): if debate.get("bull_history"):
research_dir.mkdir(exist_ok=True) research_dir.mkdir(exist_ok=True)
(research_dir / "bull.md").write_text(debate["bull_history"]) (research_dir / "bull.md").write_text(debate["bull_history"], encoding="utf-8")
research_parts.append(("Bull Researcher", debate["bull_history"])) research_parts.append(("Bull Researcher", debate["bull_history"]))
if debate.get("bear_history"): if debate.get("bear_history"):
research_dir.mkdir(exist_ok=True) research_dir.mkdir(exist_ok=True)
(research_dir / "bear.md").write_text(debate["bear_history"]) (research_dir / "bear.md").write_text(debate["bear_history"], encoding="utf-8")
research_parts.append(("Bear Researcher", debate["bear_history"])) research_parts.append(("Bear Researcher", debate["bear_history"]))
if debate.get("judge_decision"): if debate.get("judge_decision"):
research_dir.mkdir(exist_ok=True) research_dir.mkdir(exist_ok=True)
(research_dir / "manager.md").write_text(debate["judge_decision"]) (research_dir / "manager.md").write_text(debate["judge_decision"], encoding="utf-8")
research_parts.append(("Research Manager", debate["judge_decision"])) research_parts.append(("Research Manager", debate["judge_decision"]))
if research_parts: if research_parts:
content = "\n\n".join(f"### {name}\n{text}" for name, text in research_parts) content = "\n\n".join(f"### {name}\n{text}" for name, text in research_parts)
@ -666,7 +682,7 @@ def save_report_to_disk(final_state, ticker: str, save_path: Path):
if final_state.get("trader_investment_plan"): if final_state.get("trader_investment_plan"):
trading_dir = save_path / "3_trading" trading_dir = save_path / "3_trading"
trading_dir.mkdir(exist_ok=True) trading_dir.mkdir(exist_ok=True)
(trading_dir / "trader.md").write_text(final_state["trader_investment_plan"]) (trading_dir / "trader.md").write_text(final_state["trader_investment_plan"], encoding="utf-8")
sections.append(f"## III. Trading Team Plan\n\n### Trader\n{final_state['trader_investment_plan']}") sections.append(f"## III. Trading Team Plan\n\n### Trader\n{final_state['trader_investment_plan']}")
# 4. Risk Management # 4. Risk Management
@ -676,15 +692,15 @@ def save_report_to_disk(final_state, ticker: str, save_path: Path):
risk_parts = [] risk_parts = []
if risk.get("aggressive_history"): if risk.get("aggressive_history"):
risk_dir.mkdir(exist_ok=True) risk_dir.mkdir(exist_ok=True)
(risk_dir / "aggressive.md").write_text(risk["aggressive_history"]) (risk_dir / "aggressive.md").write_text(risk["aggressive_history"], encoding="utf-8")
risk_parts.append(("Aggressive Analyst", risk["aggressive_history"])) risk_parts.append(("Aggressive Analyst", risk["aggressive_history"]))
if risk.get("conservative_history"): if risk.get("conservative_history"):
risk_dir.mkdir(exist_ok=True) risk_dir.mkdir(exist_ok=True)
(risk_dir / "conservative.md").write_text(risk["conservative_history"]) (risk_dir / "conservative.md").write_text(risk["conservative_history"], encoding="utf-8")
risk_parts.append(("Conservative Analyst", risk["conservative_history"])) risk_parts.append(("Conservative Analyst", risk["conservative_history"]))
if risk.get("neutral_history"): if risk.get("neutral_history"):
risk_dir.mkdir(exist_ok=True) risk_dir.mkdir(exist_ok=True)
(risk_dir / "neutral.md").write_text(risk["neutral_history"]) (risk_dir / "neutral.md").write_text(risk["neutral_history"], encoding="utf-8")
risk_parts.append(("Neutral Analyst", risk["neutral_history"])) risk_parts.append(("Neutral Analyst", risk["neutral_history"]))
if risk_parts: if risk_parts:
content = "\n\n".join(f"### {name}\n{text}" for name, text in risk_parts) content = "\n\n".join(f"### {name}\n{text}" for name, text in risk_parts)
@ -694,12 +710,12 @@ def save_report_to_disk(final_state, ticker: str, save_path: Path):
if risk.get("judge_decision"): if risk.get("judge_decision"):
portfolio_dir = save_path / "5_portfolio" portfolio_dir = save_path / "5_portfolio"
portfolio_dir.mkdir(exist_ok=True) portfolio_dir.mkdir(exist_ok=True)
(portfolio_dir / "decision.md").write_text(risk["judge_decision"]) (portfolio_dir / "decision.md").write_text(risk["judge_decision"], encoding="utf-8")
sections.append(f"## V. Portfolio Manager Decision\n\n### Portfolio Manager\n{risk['judge_decision']}") sections.append(f"## V. Portfolio Manager Decision\n\n### Portfolio Manager\n{risk['judge_decision']}")
# Write consolidated report # Write consolidated report
header = f"# Trading Analysis Report: {ticker}\n\nGenerated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n" header = f"# Trading Analysis Report: {ticker}\n\nGenerated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
(save_path / "complete_report.md").write_text(header + "\n\n".join(sections)) (save_path / "complete_report.md").write_text(header + "\n\n".join(sections), encoding="utf-8")
return save_path / "complete_report.md" return save_path / "complete_report.md"