diff --git a/web/src/app/_components/research-block.tsx b/web/src/app/_components/research-block.tsx index 795f781..9ca576e 100644 --- a/web/src/app/_components/research-block.tsx +++ b/web/src/app/_components/research-block.tsx @@ -1,13 +1,13 @@ // Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT -import { X } from "lucide-react"; -import { useEffect, useState } from "react"; +import { Check, Copy, Headphones, X } from "lucide-react"; +import { useCallback, useEffect, useState } from "react"; import { Button } from "~/components/ui/button"; import { Card } from "~/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; -import { openResearch, useStore } from "~/core/store"; +import { listenToPodcast, openResearch, useStore } from "~/core/store"; import { cn } from "~/lib/utils"; import { ResearchActivitiesBlock } from "./research-activities-block"; @@ -29,16 +29,66 @@ export function ResearchBlock({ const hasReport = useStore((state) => researchId ? state.researchReportIds.has(researchId) : false, ); + const reportStreaming = useStore((state) => + reportId ? (state.messages.get(reportId)?.isStreaming ?? false) : false, + ); useEffect(() => { if (hasReport) { setActiveTab("report"); } }, [hasReport]); + const handleGeneratePodcast = useCallback(async () => { + if (!researchId) { + return; + } + await listenToPodcast(researchId); + }, [researchId]); + + const [copied, setCopied] = useState(false); + const handleCopy = useCallback(() => { + if (!reportId) { + return; + } + const report = useStore.getState().messages.get(reportId); + if (!report) { + return; + } + void navigator.clipboard.writeText(report.content); + setCopied(true); + setTimeout(() => { + setCopied(false); + }, 1000); + }, [reportId]); + return (
-
+
+ {hasReport && !reportStreaming && ( + <> + + + + + + + + )} - - )} -
{message?.content} {message?.isStreaming && }