This commit is contained in:
MarkLo 2025-12-07 04:12:25 +08:00
parent 915ee9915c
commit 9ce8fcdcb3
2 changed files with 443 additions and 0 deletions

View File

@ -8,6 +8,7 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { AgentFlowDiagram } from "@/components/AgentFlowDiagram";
export default function HomePage() {
return (
@ -197,6 +198,15 @@ export default function HomePage() {
</div>
</div>
{/* Agent Flow Diagram Section */}
<div className="mb-16">
<h2 className="text-3xl font-bold text-center mb-4">🔄 </h2>
<p className="text-center text-gray-600 dark:text-gray-400 mb-8 max-w-3xl mx-auto">
</p>
<AgentFlowDiagram />
</div>
{/* LLM Support Section */}
<div className="mb-16">
<h2 className="text-3xl font-bold text-center mb-4">🌍 </h2>

View File

@ -0,0 +1,433 @@
/**
* Agent Flow Diagram Component
* Visualizes the complete data flow through all 12 agents
*/
"use client";
import { Card } from "@/components/ui/card";
import {
ArrowDown,
Database,
MessageSquare,
Newspaper,
DollarSign,
TrendingUp,
TrendingDown,
Shield,
ShieldAlert,
ShieldCheck,
Users,
Target,
BarChart3
} from "lucide-react";
export function AgentFlowDiagram() {
return (
<div className="w-full max-w-7xl mx-auto space-y-6">
{/* Data Sources Layer */}
<div>
<h3 className="text-center text-sm font-semibold text-gray-500 dark:text-gray-400 mb-4">
📥
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<DataSourceCard
icon={<Database className="w-5 h-5" />}
name="yfinance"
description="股價數據"
color="blue"
/>
<DataSourceCard
icon={<MessageSquare className="w-5 h-5" />}
name="Reddit API"
description="社群情緒"
color="orange"
/>
<DataSourceCard
icon={<Newspaper className="w-5 h-5" />}
name="RSS Feed"
description="新聞資訊"
color="green"
/>
<DataSourceCard
icon={<DollarSign className="w-5 h-5" />}
name="Alpha Vantage"
description="財務數據"
color="purple"
/>
</div>
</div>
{/* Arrow */}
<FlowArrow label="資料擷取與清理" color="blue" />
{/* Analysts Layer - 4 agents */}
<div>
<h3 className="text-center text-sm font-semibold text-gray-500 dark:text-gray-400 mb-4">
🤖 (4)
</h3>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<AgentCard
name="市場分析師"
icon={<BarChart3 className="w-5 h-5" />}
gradient="from-blue-500 to-cyan-500"
description="技術面分析"
tasks={["RSI 指標", "MACD 動能", "價格走勢"]}
/>
<AgentCard
name="社群媒體分析師"
icon={<MessageSquare className="w-5 h-5" />}
gradient="from-orange-500 to-red-500"
description="情緒面分析"
tasks={["NLP 情緒", "討論熱度", "投資者信心"]}
/>
<AgentCard
name="新聞分析師"
icon={<Newspaper className="w-5 h-5" />}
gradient="from-green-500 to-emerald-500"
description="新聞面分析"
tasks={["新聞摘要", "事件評估", "影響預測"]}
/>
<AgentCard
name="基本面分析師"
icon={<DollarSign className="w-5 h-5" />}
gradient="from-purple-500 to-pink-500"
description="基本面分析"
tasks={["財報分析", "估值指標", "盈利評估"]}
/>
</div>
</div>
{/* Arrow */}
<FlowArrow label="分析報告整合" color="purple" />
{/* Researchers Layer - 2 agents */}
<div>
<h3 className="text-center text-sm font-semibold text-gray-500 dark:text-gray-400 mb-4">
🔍 (2)
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 max-w-4xl mx-auto">
<AgentCard
name="多頭研究員"
icon={<TrendingUp className="w-5 h-5" />}
gradient="from-green-500 to-emerald-500"
description="看多觀點研究"
tasks={["正面因素分析", "成長機會評估", "買入理由整理"]}
/>
<AgentCard
name="空頭研究員"
icon={<TrendingDown className="w-5 h-5" />}
gradient="from-red-500 to-rose-500"
description="看空觀點研究"
tasks={["負面因素分析", "風險評估", "賣出理由整理"]}
/>
</div>
</div>
{/* Arrow */}
<FlowArrow label="研究整合與辯論準備" color="green" />
{/* Research Manager */}
<div className="max-w-md mx-auto">
<ManagerCard
name="研究經理"
icon={<Users className="w-6 h-6" />}
gradient="from-indigo-500 to-purple-500"
description="整合多空研究觀點"
tasks={["平衡雙方論點", "綜合投資建議", "制定初步策略"]}
/>
</div>
{/* Arrow */}
<FlowArrow label="進入風險辯論階段" color="orange" />
{/* Risk Debators Layer - 3 agents */}
<div>
<h3 className="text-center text-sm font-semibold text-gray-500 dark:text-gray-400 mb-4">
(3)
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<AgentCard
name="激進辯論者"
icon={<ShieldAlert className="w-5 h-5" />}
gradient="from-red-500 to-orange-500"
description="高風險高報酬"
tasks={["積極投資策略", "最大化收益", "承擔計算風險"]}
/>
<AgentCard
name="中立辯論者"
icon={<Shield className="w-5 h-5" />}
gradient="from-blue-500 to-indigo-500"
description="平衡風險報酬"
tasks={["穩健投資策略", "風險平衡", "理性決策"]}
/>
<AgentCard
name="保守辯論者"
icon={<ShieldCheck className="w-5 h-5" />}
gradient="from-green-500 to-teal-500"
description="低風險低波動"
tasks={["保守投資策略", "資本保護", "降低風險"]}
/>
</div>
</div>
{/* Arrow */}
<FlowArrow label="風險評估與管理" color="red" />
{/* Risk Manager */}
<div className="max-w-md mx-auto">
<ManagerCard
name="風險經理"
icon={<Shield className="w-6 h-6" />}
gradient="from-red-500 to-pink-500"
description="整合風險辯論結果"
tasks={["風險等級評定", "止損止盈設定", "最終風險控制"]}
/>
</div>
{/* Arrow */}
<FlowArrow label="制定最終交易決策" color="green" />
{/* Trader */}
<div className="max-w-md mx-auto">
<TraderCard
name="交易員"
icon={<Target className="w-7 h-7" />}
gradient="from-blue-600 via-purple-600 to-pink-600"
description="執行最終交易決策"
outputs={["交易訊號 (BUY/SELL/HOLD)", "目標價位", "交易數量", "風險參數"]}
/>
</div>
{/* Final Arrow */}
<FlowArrow label="生成完整投資報告" color="blue" />
{/* Output Layer */}
<div>
<h3 className="text-center text-sm font-semibold text-gray-500 dark:text-gray-400 mb-4">
📊 12
</h3>
<Card className="bg-gradient-to-r from-blue-500/10 via-purple-500/10 to-pink-500/10 dark:from-blue-600/20 dark:via-purple-600/20 dark:to-pink-600/20 border-2 border-dashed border-blue-300 dark:border-blue-700 p-6">
<div className="text-center mb-4">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 text-white shadow-lg mb-3">
<BarChart3 className="w-8 h-8" />
</div>
<h4 className="font-bold text-lg mb-2 gradient-text-primary"></h4>
<p className="text-sm text-gray-600 dark:text-gray-400">
12
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
<ReportSection
title="分析師報告 (4份)"
items={["技術面分析", "社群情緒分析", "新聞面分析", "基本面分析"]}
color="blue"
/>
<ReportSection
title="研究報告 (3份)"
items={["多頭研究報告", "空頭研究報告", "研究經理整合"]}
color="green"
/>
<ReportSection
title="風險與交易 (5份)"
items={["激進策略評估", "中立策略評估", "保守策略評估", "風險經理整合", "最終交易決策"]}
color="red"
/>
</div>
</Card>
</div>
</div>
);
}
function DataSourceCard({
icon,
name,
description,
color,
}: {
icon: React.ReactNode;
name: string;
description: string;
color: "blue" | "orange" | "green" | "purple";
}) {
const colorClasses = {
blue: "from-blue-500 to-cyan-500 border-blue-300 dark:border-blue-700",
orange: "from-orange-500 to-red-500 border-orange-300 dark:border-orange-700",
green: "from-green-500 to-emerald-500 border-green-300 dark:border-green-700",
purple: "from-purple-500 to-pink-500 border-purple-300 dark:border-purple-700",
};
return (
<Card className={`p-3 text-center hover-lift animate-slide-up border-2 ${colorClasses[color]}`}>
<div className={`inline-flex items-center justify-center w-10 h-10 rounded-full bg-gradient-to-br ${colorClasses[color].split(' ')[0]} ${colorClasses[color].split(' ')[1]} text-white mb-2 shadow-lg`}>
{icon}
</div>
<h4 className="font-semibold text-xs mb-0.5">{name}</h4>
<p className="text-xs text-gray-600 dark:text-gray-400">{description}</p>
</Card>
);
}
function AgentCard({
name,
icon,
gradient,
description,
tasks,
}: {
name: string;
icon: React.ReactNode;
gradient: string;
description: string;
tasks: string[];
}) {
return (
<Card className="p-4 hover-lift animate-scale-up relative overflow-hidden group">
<div className={`absolute inset-0 bg-gradient-to-br ${gradient} opacity-0 group-hover:opacity-10 transition-opacity duration-300`} />
<div className="relative z-10">
<div className="text-center mb-3">
<div className={`inline-flex items-center justify-center w-10 h-10 rounded-full bg-gradient-to-br ${gradient} text-white mb-2 shadow-lg`}>
{icon}
</div>
<h4 className="font-bold text-sm mb-0.5">{name}</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">{description}</p>
</div>
<div className="space-y-0.5">
{tasks.map((task, index) => (
<div key={index} className="flex items-start text-xs text-gray-600 dark:text-gray-400">
<span className="mr-1"></span>
<span>{task}</span>
</div>
))}
</div>
</div>
</Card>
);
}
function ManagerCard({
name,
icon,
gradient,
description,
tasks,
}: {
name: string;
icon: React.ReactNode;
gradient: string;
description: string;
tasks: string[];
}) {
return (
<Card className={`p-5 hover-lift relative overflow-hidden border-2 bg-gradient-to-br ${gradient} bg-opacity-5`}>
<div className="text-center mb-3">
<div className={`inline-flex items-center justify-center w-12 h-12 rounded-full bg-gradient-to-br ${gradient} text-white mb-2 shadow-xl`}>
{icon}
</div>
<h4 className="font-bold text-base mb-1">{name}</h4>
<p className="text-sm text-gray-600 dark:text-gray-400">{description}</p>
</div>
<div className="space-y-1">
{tasks.map((task, index) => (
<div key={index} className="flex items-start text-sm text-gray-700 dark:text-gray-300">
<span className="mr-2"></span>
<span>{task}</span>
</div>
))}
</div>
</Card>
);
}
function TraderCard({
name,
icon,
gradient,
description,
outputs,
}: {
name: string;
icon: React.ReactNode;
gradient: string;
description: string;
outputs: string[];
}) {
return (
<Card className={`p-6 hover-lift relative overflow-hidden border-4 border-double bg-gradient-to-br ${gradient}`}>
<div className="absolute inset-0 bg-white dark:bg-gray-900 opacity-95" />
<div className="relative z-10">
<div className="text-center mb-4">
<div className={`inline-flex items-center justify-center w-14 h-14 rounded-full bg-gradient-to-br ${gradient} text-white mb-3 shadow-2xl animate-pulse-slow`}>
{icon}
</div>
<h4 className="font-bold text-lg mb-1 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">{name}</h4>
<p className="text-sm text-gray-600 dark:text-gray-400 font-medium">{description}</p>
</div>
<div className="space-y-2 bg-gray-50 dark:bg-gray-800/50 p-3 rounded-lg">
<div className="text-xs font-semibold text-gray-700 dark:text-gray-300 mb-2">:</div>
{outputs.map((output, index) => (
<div key={index} className="flex items-start text-sm font-medium text-gray-700 dark:text-gray-300">
<span className="mr-2 text-green-600 dark:text-green-400"></span>
<span>{output}</span>
</div>
))}
</div>
</div>
</Card>
);
}
function FlowArrow({ label, color }: { label: string; color: string }) {
const colorClasses = {
blue: "text-blue-500 dark:text-blue-400",
purple: "text-purple-500 dark:text-purple-400",
green: "text-green-500 dark:text-green-400",
orange: "text-orange-500 dark:text-orange-400",
red: "text-red-500 dark:text-red-400",
};
return (
<div className="flex justify-center">
<div className="flex flex-col items-center">
<div className="text-xs text-gray-500 dark:text-gray-400 mb-1 font-medium">{label}</div>
<ArrowDown className={`w-7 h-7 ${colorClasses[color as keyof typeof colorClasses]} animate-bounce`} />
</div>
</div>
);
}
function ReportSection({
title,
items,
color,
}: {
title: string;
items: string[];
color: "blue" | "green" | "red";
}) {
const colorClasses = {
blue: "bg-blue-50 dark:bg-blue-950/30 border-blue-200 dark:border-blue-800",
green: "bg-green-50 dark:bg-green-950/30 border-green-200 dark:border-green-800",
red: "bg-red-50 dark:bg-red-950/30 border-red-200 dark:border-red-800",
};
return (
<div className={`p-3 rounded-lg border ${colorClasses[color]}`}>
<h5 className="font-semibold text-xs mb-2 text-gray-800 dark:text-gray-200">{title}</h5>
<div className="space-y-1">
{items.map((item, index) => (
<div key={index} className="text-xs text-gray-600 dark:text-gray-400 flex items-start">
<span className="mr-1"></span>
<span>{item}</span>
</div>
))}
</div>
</div>
);
}