// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates // SPDX-License-Identifier: MIT import { motion } from "framer-motion"; import { FastForward, Play } from "lucide-react"; import { useTranslations } from "next-intl"; import { useCallback, useRef, useState } from "react"; import { RainbowText } from "~/components/deer-flow/rainbow-text"; import { Button } from "~/components/ui/button"; import { Card, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; import { fastForwardReplay } from "~/core/api"; import { useReplayMetadata } from "~/core/api/hooks"; import type { Option, Resource } from "~/core/messages"; import { useReplay } from "~/core/replay"; import { sendMessage, useMessageIds, useStore } from "~/core/store"; import { env } from "~/env"; import { cn } from "~/lib/utils"; import { ConversationStarter } from "./conversation-starter"; import { InputBox } from "./input-box"; import { MessageListView } from "./message-list-view"; import { Welcome } from "./welcome"; export function MessagesBlock({ className }: { className?: string }) { const t = useTranslations("chat.messages"); const messageIds = useMessageIds(); const messageCount = messageIds.length; const responding = useStore((state) => state.responding); const { isReplay } = useReplay(); const { title: replayTitle, hasError: replayHasError } = useReplayMetadata(); const [replayStarted, setReplayStarted] = useState(false); const abortControllerRef = useRef(null); const [feedback, setFeedback] = useState<{ option: Option } | null>(null); const handleSend = useCallback( async ( message: string, options?: { interruptFeedback?: string; resources?: Array; }, ) => { const abortController = new AbortController(); abortControllerRef.current = abortController; try { await sendMessage( message, { interruptFeedback: options?.interruptFeedback ?? feedback?.option.value, resources: options?.resources, }, { abortSignal: abortController.signal, }, ); } catch {} }, [feedback], ); const handleCancel = useCallback(() => { abortControllerRef.current?.abort(); abortControllerRef.current = null; }, []); const handleFeedback = useCallback( (feedback: { option: Option }) => { setFeedback(feedback); }, [setFeedback], ); const handleRemoveFeedback = useCallback(() => { setFeedback(null); }, [setFeedback]); const handleStartReplay = useCallback(() => { setReplayStarted(true); void sendMessage(); }, [setReplayStarted]); const [fastForwarding, setFastForwarding] = useState(false); const handleFastForwardReplay = useCallback(() => { setFastForwarding(!fastForwarding); fastForwardReplay(!fastForwarding); }, [fastForwarding]); return (
{!isReplay ? (
{!responding && messageCount === 0 && ( )}
) : ( <>
{responding && ( )} {responding ? t("replaying") : `${replayTitle}`} {responding ? t("replayDescription") : replayStarted ? t("replayHasStopped") : t("replayModeDescription")}
{!replayHasError && (
{responding && ( )} {!replayStarted && ( )}
)}
{!replayStarted && env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY && (
{t("demoNotice")}{" "} {t("clickHere")} {" "} {t("cloneLocally")}
)}
)}
); }