import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { AppIcon } from "./PixelIcons"; import { Card, Tag, Loading } from "./ui"; import { api } from "../lib/api"; type Props = { symbol: string; scope: "stock" | "company" | "fund"; title?: string; auto?: boolean; aiFocus: { symbol: string; subPage: string; label: string; cardTitle?: string }; }; function verdictTone(v?: string): "up" | "down" | "gold" { if (v === "偏正面") return "up"; if (v === "謹慎") return "down"; return "gold"; } export default function AiSummaryCard({ symbol, scope, title = "AI 今日總結", auto = true, aiFocus }: Props) { const qc = useQueryClient(); const q = useQuery({ queryKey: ["ai-summary", symbol, scope], queryFn: () => api.aiSummary(symbol, scope, auto), enabled: !!symbol && auto, staleTime: 12 * 3600_000, retry: 1, }); const syncMut = useMutation({ mutationFn: () => api.syncAiSummary(symbol, scope), onSuccess: (data) => { qc.setQueryData(["ai-summary", symbol, scope], data); }, }); const summary = q.data?.summary; const loading = q.isLoading || syncMut.isPending; return ( } ai aiFocus={{ ...aiFocus, cardTitle: title }} onRefresh={() => syncMut.mutate()} refreshing={loading} refreshLabel="重新分析" >
{q.data?.cached ? `今日已分析 · ${q.data?.summary?.day || ""} · 讀資料庫(省 token)` : q.data?.mcpUsed ? "MCP + 本機資料已送 AI 總結" : "整合本機財報/公司研究;可串 MCP 補充"}
{loading && !summary ? ( ) : summary ? ( <>
{summary.verdict ? {summary.verdict} : null} {summary.provider ? via {summary.provider} : null}
AI 總結

{summary.summaryZh}

{summary.bullets?.length ? (
    {summary.bullets.map((b, i) => (
  • {b}
  • ))}
) : null}
{summary.risks?.length ? (

風險/待確認

    {summary.risks.map((r, i) => (
  • {r}
  • ))}
) : null} {summary.sources?.length ? (

來源:{summary.sources.join(" · ")}

) : null} {q.data?.skipReason ?

{q.data.skipReason}

: null} {q.data?.aiError ?

AI 略過:{q.data.aiError}(已用規則備援)

: null} ) : (

尚無今日總結。

)}
); }