TradingAgents/frontend/components/analysis/AnalystReport.tsx

141 lines
5.1 KiB
TypeScript

/**
* Analyst reports display component
*/
"use client";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type { Reports } from "@/lib/types";
import { useLanguage } from "@/contexts/LanguageContext";
interface AnalystReportProps {
reports: Reports;
}
export function AnalystReport({ reports }: AnalystReportProps) {
const { t } = useLanguage();
const hasAnalystReports =
reports.market_report ||
reports.sentiment_report ||
reports.news_report ||
reports.fundamentals_report;
const hasResearchReports =
reports.investment_debate_state?.bull_history ||
reports.investment_debate_state?.bear_history ||
reports.investment_debate_state?.judge_decision;
const hasRiskReports =
reports.risk_debate_state?.risky_history ||
reports.risk_debate_state?.safe_history ||
reports.risk_debate_state?.neutral_history;
if (!hasAnalystReports && !hasResearchReports && !hasRiskReports) {
return null;
}
return (
<Card className="shadow-lg hover-lift animate-scale-up">
<CardHeader>
<CardTitle>{t.results.title}</CardTitle>
<CardDescription>{t.home.professionalAgentsDesc}</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="analysts" className="w-full">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="analysts">{t.tabs.analysts}</TabsTrigger>
<TabsTrigger value="research">{t.tabs.researchers}</TabsTrigger>
<TabsTrigger value="trader">{t.tabs.trader}</TabsTrigger>
<TabsTrigger value="risk">{t.tabs.risk}</TabsTrigger>
</TabsList>
<TabsContent value="analysts" className="space-y-4">
{reports.market_report && (
<ReportSection title={t.agents.market_analyst} content={reports.market_report} />
)}
{reports.sentiment_report && (
<ReportSection title={t.agents.social_analyst} content={reports.sentiment_report} />
)}
{reports.news_report && (
<ReportSection title={t.agents.news_analyst} content={reports.news_report} />
)}
{reports.fundamentals_report && (
<ReportSection title={t.agents.fundamentals_analyst} content={reports.fundamentals_report} />
)}
</TabsContent>
<TabsContent value="research" className="space-y-4">
{reports.investment_debate_state?.bull_history && (
<ReportSection
title={t.agents.bull_researcher}
content={reports.investment_debate_state.bull_history}
/>
)}
{reports.investment_debate_state?.bear_history && (
<ReportSection
title={t.agents.bear_researcher}
content={reports.investment_debate_state.bear_history}
/>
)}
{reports.investment_debate_state?.judge_decision && (
<ReportSection
title={t.agents.research_manager}
content={reports.investment_debate_state.judge_decision}
/>
)}
</TabsContent>
<TabsContent value="trader" className="space-y-4">
{reports.trader_investment_plan && (
<ReportSection title={t.agents.trader} content={reports.trader_investment_plan} />
)}
</TabsContent>
<TabsContent value="risk" className="space-y-4">
{reports.risk_debate_state?.risky_history && (
<ReportSection
title={t.agents.aggressive_debator}
content={reports.risk_debate_state.risky_history}
/>
)}
{reports.risk_debate_state?.safe_history && (
<ReportSection
title={t.agents.conservative_debator}
content={reports.risk_debate_state.safe_history}
/>
)}
{reports.risk_debate_state?.neutral_history && (
<ReportSection
title={t.agents.neutral_debator}
content={reports.risk_debate_state.neutral_history}
/>
)}
{reports.risk_debate_state?.judge_decision && (
<ReportSection
title={t.agents.risk_manager}
content={reports.risk_debate_state.judge_decision}
/>
)}
</TabsContent>
</Tabs>
</CardContent>
</Card>
);
}
function ReportSection({ title, content }: { title: string; content: string }) {
return (
<div className="border rounded-lg p-4 bg-gradient-to-br from-blue-50/50 to-purple-50/50 dark:from-blue-900/10 dark:to-purple-900/10 hover:shadow-md transition-shadow">
<h3 className="font-semibold text-lg mb-2">{title}</h3>
<div className="prose prose-sm dark:prose-invert max-w-none">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{content}
</ReactMarkdown>
</div>
</div>
);
}