给消息key

This commit is contained in:
北枳 2025-08-31 04:22:22 +08:00
parent 85f68a5462
commit 9204a3e177
5 changed files with 19 additions and 6 deletions

View File

@ -1,6 +1,6 @@
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { ChatMessage } from "./types"; import { ChatMessage, MessageBlock } from "./types";
import { bubbleVariants, hhmm } from "./utils"; import { bubbleVariants, hhmm } from "./utils";
import { ProgressBar } from "./ProgressBar"; import { ProgressBar } from "./ProgressBar";
import { Loader2, AlertCircle, CheckCircle2 } from "lucide-react"; import { Loader2, AlertCircle, CheckCircle2 } from "lucide-react";
@ -8,9 +8,10 @@ import { Image } from 'antd';
interface MessageRendererProps { interface MessageRendererProps {
msg: ChatMessage; msg: ChatMessage;
sendMessage: (blocks: MessageBlock[]) => Promise<void>;
} }
export function MessageRenderer({ msg }: MessageRendererProps) { export function MessageRenderer({ msg, sendMessage }: MessageRendererProps) {
// Decide bubble style // Decide bubble style
const isUser = msg.role === "user"; const isUser = msg.role === "user";
const isSystem = msg.role === "system"; const isSystem = msg.role === "system";
@ -75,6 +76,7 @@ export function MessageRenderer({ msg }: MessageRendererProps) {
animate="visible" animate="visible"
transition={{ duration: 0.25 }} transition={{ duration: 0.25 }}
data-alt="message-bubble" data-alt="message-bubble"
key={msg.id}
> >
<div className={`max-w-[75%] rounded-2xl shadow-md p-3 ${bubbleClass}`}> <div className={`max-w-[75%] rounded-2xl shadow-md p-3 ${bubbleClass}`}>
{/* Header */} {/* Header */}
@ -126,6 +128,11 @@ export function MessageRenderer({ msg }: MessageRendererProps) {
return <ProgressBar key={idx} value={b.value} total={b.total} label={b.label} />; return <ProgressBar key={idx} value={b.value} total={b.total} label={b.label} />;
case "link": case "link":
return <a key={idx} href={b.url} className="underline hover:underline text-[rgb(111 208 211)]">{b.text}</a>; return <a key={idx} href={b.url} className="underline hover:underline text-[rgb(111 208 211)]">{b.text}</a>;
case "applyButton":
return <button key={idx} className="bg-[#6fd0d3] text-white px-2 py-1 rounded-md" onClick={() => {
// 帮用户发送一条消息消息内容是confirm apply
sendMessage([{ type: "text", text: "confirm apply" }]);
}}>{b.text}</button>;
default: default:
return null; return null;
} }

View File

@ -161,7 +161,7 @@ export default function SmartChatBox({
<React.Fragment key={group.date}> <React.Fragment key={group.date}>
<DateDivider timestamp={group.date} /> <DateDivider timestamp={group.date} />
{group.messages.map((message) => ( {group.messages.map((message) => (
<MessageRenderer key={message.id} msg={message} /> <MessageRenderer key={message.id} msg={message} sendMessage={sendMessage} />
))} ))}
</React.Fragment> </React.Fragment>
))} ))}

View File

@ -239,6 +239,11 @@ function transformMessage(apiMessage: RealApiMessage): ChatMessage {
message.blocks.push({ type: "link", text: c.content, url: c.url || '' }); message.blocks.push({ type: "link", text: c.content, url: c.url || '' });
} }
}); });
// todo: 需要确认是否需要添加applyButton
// if (role === 'assistant' && function_name === 'modify_video_with_runway') {
// message.blocks.push({ type: "applyButton", text: "Apply" });
// }
} catch (error) { } catch (error) {
// 如果 JSON 解析失败,将整个 content 作为文本内容 // 如果 JSON 解析失败,将整个 content 作为文本内容
message.blocks.push({ type: "text", text: content }); message.blocks.push({ type: "text", text: content });

View File

@ -8,7 +8,8 @@ export type MessageBlock =
| { type: "video"; url: string; poster?: string } | { type: "video"; url: string; poster?: string }
| { type: "audio"; url: string } | { type: "audio"; url: string }
| { type: "progress"; value: number; total?: number; label?: string } | { type: "progress"; value: number; total?: number; label?: string }
| { type: "link"; text: string; url: string }; | { type: "link"; text: string; url: string }
| { type: "applyButton"; text: string; }
export interface ChatMessage { export interface ChatMessage {
id: string; id: string;
@ -80,7 +81,7 @@ export interface MessagesResponse {
} }
type ContentType = "text" | "image" | "video" | "audio"; type ContentType = "text" | "image" | "video" | "audio";
export type FunctionName = "create_project" | "generate_script_summary" | "generate_character" | "generate_sketch" | "generate_shot_sketch" | "generate_video"; export type FunctionName = "create_project" | "generate_script_summary" | "generate_character" | "generate_sketch" | "generate_shot_sketch" | "generate_video" | "modify_video_with_runway";
// 项目创建 // 项目创建
export interface ProjectInit { export interface ProjectInit {

View File

@ -115,7 +115,7 @@ export function useWorkflowData() {
const generateEditPlan = useCallback(async (isInit?: boolean) => { const generateEditPlan = useCallback(async (isInit?: boolean) => {
isInit && await getGenerateEditPlan({ project_id: episodeId }); isInit && await getGenerateEditPlan({ project_id: episodeId });
window.open(`https://smartcut.huiying.video/ai-editor/${episodeId}?token=${token}&user_id=${useid}`, '_target'); window.open(`https://smartcut.movieflow.ai/editor/${episodeId}?token=${token}&user_id=${useid}`, '_target');
}, [episodeId]); }, [episodeId]);
useEffect(() => { useEffect(() => {