forked from 77media/video-flow
chatbox--完善流程推送 生成视频
This commit is contained in:
parent
65c21e1c40
commit
2a7a9f4701
@ -11,7 +11,7 @@ export function LoadMoreButton({ onClick, loading = false }: LoadMoreButtonProps
|
|||||||
<button
|
<button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-full flex items-center justify-center gap-2 py-2 text-sm text-gray-400 hover:text-gray-300 hover:bg-gray-800/30 transition-colors disabled:opacity-50"
|
className="w-full flex items-center justify-center gap-2 text-sm text-gray-400 hover:text-gray-300 hover:bg-gray-800/30 transition-colors disabled:opacity-50"
|
||||||
data-alt="load-more-button"
|
data-alt="load-more-button"
|
||||||
>
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
|
|||||||
@ -106,7 +106,16 @@ export function MessageRenderer({ msg }: MessageRendererProps) {
|
|||||||
case "video":
|
case "video":
|
||||||
return (
|
return (
|
||||||
<div key={idx} className="overflow-hidden rounded-xl">
|
<div key={idx} className="overflow-hidden rounded-xl">
|
||||||
<video controls src={b.url} poster={b.poster} className="w-full max-h-80 bg-black" />
|
<video
|
||||||
|
controls
|
||||||
|
src={b.url}
|
||||||
|
poster={b.poster}
|
||||||
|
className="w-full max-h-80 bg-black"
|
||||||
|
controlsList="nodownload noremoteplayback"
|
||||||
|
disablePictureInPicture
|
||||||
|
disableRemotePlayback
|
||||||
|
onContextMenu={e => e.preventDefault()}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case "audio":
|
case "audio":
|
||||||
|
|||||||
@ -86,8 +86,8 @@ export default function SmartChatBox({ isSmartChatBoxOpen, setIsSmartChatBoxOpen
|
|||||||
<span>Chat</span>
|
<span>Chat</span>
|
||||||
{/* System push toggle */}
|
{/* System push toggle */}
|
||||||
<Switch
|
<Switch
|
||||||
checkedChildren="系统推送开"
|
checkedChildren="系统推送:开"
|
||||||
unCheckedChildren="系统推送关"
|
unCheckedChildren="系统推送:关"
|
||||||
checked={systemPush}
|
checked={systemPush}
|
||||||
onChange={toggleSystemPush}
|
onChange={toggleSystemPush}
|
||||||
className="ml-2"
|
className="ml-2"
|
||||||
|
|||||||
@ -13,7 +13,8 @@ import {
|
|||||||
ScriptSummary,
|
ScriptSummary,
|
||||||
CharacterGeneration,
|
CharacterGeneration,
|
||||||
SketchGeneration,
|
SketchGeneration,
|
||||||
ShotSketchGeneration
|
ShotSketchGeneration,
|
||||||
|
ShotVideoGeneration
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import { post } from "@/api/request";
|
import { post } from "@/api/request";
|
||||||
|
|
||||||
@ -28,7 +29,6 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
content: '我想拍一个关于一个小女孩和她的机器人朋友的故事,故事发生在未来世界。'
|
content: '我想拍一个关于一个小女孩和她的机器人朋友的故事,故事发生在未来世界。'
|
||||||
}]),
|
}]),
|
||||||
created_at: '2024-03-20T10:00:00Z',
|
created_at: '2024-03-20T10:00:00Z',
|
||||||
message_type: undefined,
|
|
||||||
function_name: undefined,
|
function_name: undefined,
|
||||||
custom_data: undefined,
|
custom_data: undefined,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -40,7 +40,6 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '我会帮您创建一个温馨感人的科幻短片,讲述人工智能与人类情感的故事。',
|
content: '我会帮您创建一个温馨感人的科幻短片,讲述人工智能与人类情感的故事。',
|
||||||
created_at: '2024-03-20T10:00:10Z',
|
created_at: '2024-03-20T10:00:10Z',
|
||||||
message_type: 'project_init',
|
|
||||||
function_name: 'create_project',
|
function_name: 'create_project',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
project_data: {
|
project_data: {
|
||||||
@ -56,7 +55,6 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '故事概要:在2045年的未来城市,10岁的小女孩艾米丽收到了一个特别的生日礼物——一个具有高度情感智能的机器人伙伴"小星"。随着时间推移,他们建立了深厚的友谊。当小星因能源耗尽即将永久关闭时,艾米丽想尽办法寻找解决方案,最终通过她的坚持和创意,成功为小星找到了新的能源,让这段跨越人机界限的友谊得以延续。',
|
content: '故事概要:在2045年的未来城市,10岁的小女孩艾米丽收到了一个特别的生日礼物——一个具有高度情感智能的机器人伙伴"小星"。随着时间推移,他们建立了深厚的友谊。当小星因能源耗尽即将永久关闭时,艾米丽想尽办法寻找解决方案,最终通过她的坚持和创意,成功为小星找到了新的能源,让这段跨越人机界限的友谊得以延续。',
|
||||||
created_at: '2024-03-20T10:01:00Z',
|
created_at: '2024-03-20T10:01:00Z',
|
||||||
message_type: 'script_summary',
|
|
||||||
function_name: 'generate_script_summary',
|
function_name: 'generate_script_summary',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
summary: '一个关于友谊和希望的温暖故事'
|
summary: '一个关于友谊和希望的温暖故事'
|
||||||
@ -70,12 +68,11 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '主角艾米丽的形象已生成',
|
content: '主角艾米丽的形象已生成',
|
||||||
created_at: '2024-03-20T10:02:00Z',
|
created_at: '2024-03-20T10:02:00Z',
|
||||||
message_type: 'character_generation',
|
|
||||||
function_name: 'generate_character',
|
function_name: 'generate_character',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
character_name: '艾米丽',
|
character_name: '艾米丽',
|
||||||
image_path: 'https://picsum.photos/seed/emily/300/400',
|
image_path: 'https://picsum.photos/seed/emily/300/400',
|
||||||
count: 1,
|
completed_count: 1,
|
||||||
total_count: 2
|
total_count: 2
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -87,12 +84,11 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '机器人小星的形象已生成',
|
content: '机器人小星的形象已生成',
|
||||||
created_at: '2024-03-20T10:03:00Z',
|
created_at: '2024-03-20T10:03:00Z',
|
||||||
message_type: 'character_generation',
|
|
||||||
function_name: 'generate_character',
|
function_name: 'generate_character',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
character_name: '小星',
|
character_name: '小星',
|
||||||
image_path: 'https://picsum.photos/seed/robot/300/400',
|
image_path: 'https://picsum.photos/seed/robot/300/400',
|
||||||
count: 2,
|
completed_count: 2,
|
||||||
total_count: 2
|
total_count: 2
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -104,12 +100,11 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '未来城市场景设计完成',
|
content: '未来城市场景设计完成',
|
||||||
created_at: '2024-03-20T10:04:00Z',
|
created_at: '2024-03-20T10:04:00Z',
|
||||||
message_type: 'sketch_generation',
|
|
||||||
function_name: 'generate_sketch',
|
function_name: 'generate_sketch',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
sketch_name: '未来城市街景',
|
sketch_name: '未来城市街景',
|
||||||
image_path: 'https://picsum.photos/seed/city/600/400',
|
image_path: 'https://picsum.photos/seed/city/600/400',
|
||||||
count: 1,
|
completed_count: 1,
|
||||||
total_count: 3
|
total_count: 3
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -121,12 +116,11 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '艾米丽的未来风格卧室设计完成',
|
content: '艾米丽的未来风格卧室设计完成',
|
||||||
created_at: '2024-03-20T10:05:00Z',
|
created_at: '2024-03-20T10:05:00Z',
|
||||||
message_type: 'sketch_generation',
|
|
||||||
function_name: 'generate_sketch',
|
function_name: 'generate_sketch',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
sketch_name: '艾米丽的卧室',
|
sketch_name: '艾米丽的卧室',
|
||||||
image_path: 'https://picsum.photos/seed/room/600/400',
|
image_path: 'https://picsum.photos/seed/room/600/400',
|
||||||
count: 2,
|
completed_count: 2,
|
||||||
total_count: 3
|
total_count: 3
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -138,12 +132,11 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '高科技实验室场景设计完成',
|
content: '高科技实验室场景设计完成',
|
||||||
created_at: '2024-03-20T10:06:00Z',
|
created_at: '2024-03-20T10:06:00Z',
|
||||||
message_type: 'sketch_generation',
|
|
||||||
function_name: 'generate_sketch',
|
function_name: 'generate_sketch',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
sketch_name: '未来实验室',
|
sketch_name: '未来实验室',
|
||||||
image_path: 'https://picsum.photos/seed/lab/600/400',
|
image_path: 'https://picsum.photos/seed/lab/600/400',
|
||||||
count: 3,
|
completed_count: 3,
|
||||||
total_count: 3
|
total_count: 3
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -155,14 +148,13 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '第一个分镜:艾米丽收到礼物时的场景',
|
content: '第一个分镜:艾米丽收到礼物时的场景',
|
||||||
created_at: '2024-03-20T10:07:00Z',
|
created_at: '2024-03-20T10:07:00Z',
|
||||||
message_type: 'shot_sketch_generation',
|
|
||||||
function_name: 'generate_shot_sketch',
|
function_name: 'generate_shot_sketch',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
shot_type: '中景',
|
shot_type: '中景',
|
||||||
atmosphere: '温馨、期待',
|
atmosphere: '温馨、期待',
|
||||||
key_action: '艾米丽惊喜地打开礼物盒,小星缓缓启动',
|
key_action: '艾米丽惊喜地打开礼物盒,小星缓缓启动',
|
||||||
url: 'https://picsum.photos/seed/shot1/600/400',
|
url: 'https://picsum.photos/seed/shot1/600/400',
|
||||||
count: 1,
|
completed_count: 1,
|
||||||
total_count: 3
|
total_count: 3
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -174,14 +166,13 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '第二个分镜:小星能源耗尽的场景',
|
content: '第二个分镜:小星能源耗尽的场景',
|
||||||
created_at: '2024-03-20T10:08:00Z',
|
created_at: '2024-03-20T10:08:00Z',
|
||||||
message_type: 'shot_sketch_generation',
|
|
||||||
function_name: 'generate_shot_sketch',
|
function_name: 'generate_shot_sketch',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
shot_type: '特写',
|
shot_type: '特写',
|
||||||
atmosphere: '紧张、担忧',
|
atmosphere: '紧张、担忧',
|
||||||
key_action: '小星的能源指示灯闪烁微弱,艾米丽神情焦急',
|
key_action: '小星的能源指示灯闪烁微弱,艾米丽神情焦急',
|
||||||
url: 'https://picsum.photos/seed/shot2/600/400',
|
url: 'https://picsum.photos/seed/shot2/600/400',
|
||||||
count: 2,
|
completed_count: 2,
|
||||||
total_count: 3
|
total_count: 3
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -193,19 +184,34 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
role: 'system',
|
role: 'system',
|
||||||
content: '第三个分镜:找到新能源解决方案的场景',
|
content: '第三个分镜:找到新能源解决方案的场景',
|
||||||
created_at: '2024-03-20T10:09:00Z',
|
created_at: '2024-03-20T10:09:00Z',
|
||||||
message_type: 'shot_sketch_generation',
|
|
||||||
function_name: 'generate_shot_sketch',
|
function_name: 'generate_shot_sketch',
|
||||||
custom_data: {
|
custom_data: {
|
||||||
shot_type: '全景',
|
shot_type: '全景',
|
||||||
atmosphere: '欢欣、胜利',
|
atmosphere: '欢欣、胜利',
|
||||||
key_action: '实验室中艾米丽成功激活新能源,小星重新焕发活力',
|
key_action: '实验室中艾米丽成功激活新能源,小星重新焕发活力',
|
||||||
url: 'https://picsum.photos/seed/shot3/600/400',
|
url: 'https://picsum.photos/seed/shot3/600/400',
|
||||||
count: 3,
|
completed_count: 3,
|
||||||
total_count: 3
|
total_count: 3
|
||||||
},
|
},
|
||||||
status: 'success',
|
status: 'success',
|
||||||
intent_type: 'procedure'
|
intent_type: 'procedure'
|
||||||
},
|
},
|
||||||
|
// 分镜视频生成
|
||||||
|
{
|
||||||
|
id: 11.1,
|
||||||
|
role: 'system',
|
||||||
|
content: '分镜视频生成完成',
|
||||||
|
created_at: '2024-03-20T10:10:00Z',
|
||||||
|
function_name: 'generate_video',
|
||||||
|
custom_data: {
|
||||||
|
core_atmosphere: '欢欣、胜利',
|
||||||
|
urls: ['https://cdn.qikongjian.com/faces/1755798635_facefusion_output_1755798635.mp4'],
|
||||||
|
completed_count: 1,
|
||||||
|
total_count: 1
|
||||||
|
},
|
||||||
|
status: 'success',
|
||||||
|
intent_type: 'procedure'
|
||||||
|
},
|
||||||
// 用户反馈
|
// 用户反馈
|
||||||
{
|
{
|
||||||
id: 12,
|
id: 12,
|
||||||
@ -215,7 +221,6 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
content: '这个故事设计太棒了!特别喜欢艾米丽和小星的互动场景。'
|
content: '这个故事设计太棒了!特别喜欢艾米丽和小星的互动场景。'
|
||||||
}]),
|
}]),
|
||||||
created_at: '2024-03-20T10:10:00Z',
|
created_at: '2024-03-20T10:10:00Z',
|
||||||
message_type: undefined,
|
|
||||||
function_name: undefined,
|
function_name: undefined,
|
||||||
custom_data: undefined,
|
custom_data: undefined,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -230,7 +235,6 @@ const MOCK_MESSAGES: RealApiMessage[] = [
|
|||||||
content: '谢谢您的肯定!我们可以继续优化任何场景或角色设计,您觉得有什么地方需要调整吗?'
|
content: '谢谢您的肯定!我们可以继续优化任何场景或角色设计,您觉得有什么地方需要调整吗?'
|
||||||
}]),
|
}]),
|
||||||
created_at: '2024-03-20T10:10:10Z',
|
created_at: '2024-03-20T10:10:10Z',
|
||||||
message_type: undefined,
|
|
||||||
function_name: undefined,
|
function_name: undefined,
|
||||||
custom_data: undefined,
|
custom_data: undefined,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
@ -250,15 +254,19 @@ function isScriptSummary(data: any): data is ScriptSummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isCharacterGeneration(data: any): data is CharacterGeneration {
|
function isCharacterGeneration(data: any): data is CharacterGeneration {
|
||||||
return data && 'character_name' in data && 'image_path' in data && 'count' in data && 'total_count' in data;
|
return data && 'character_name' in data && 'image_path' in data && 'completed_count' in data && 'total_count' in data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSketchGeneration(data: any): data is SketchGeneration {
|
function isSketchGeneration(data: any): data is SketchGeneration {
|
||||||
return data && 'sketch_name' in data && 'image_path' in data && 'count' in data && 'total_count' in data;
|
return data && 'sketch_name' in data && 'image_path' in data && 'completed_count' in data && 'total_count' in data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isShotSketchGeneration(data: any): data is ShotSketchGeneration {
|
function isShotSketchGeneration(data: any): data is ShotSketchGeneration {
|
||||||
return data && 'shot_type' in data && 'atmosphere' in data && 'key_action' in data && 'url' in data && 'count' in data && 'total_count' in data;
|
return data && 'shot_type' in data && 'atmosphere' in data && 'key_action' in data && 'url' in data && 'completed_count' in data && 'total_count' in data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isShotVideoGeneration(data: any): data is ShotVideoGeneration {
|
||||||
|
return data && 'core_atmosphere' in data && 'urls' in data && 'completed_count' in data && 'total_count' in data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,7 +275,7 @@ function isShotSketchGeneration(data: any): data is ShotSketchGeneration {
|
|||||||
function transformSystemMessage(
|
function transformSystemMessage(
|
||||||
functionName: FunctionName,
|
functionName: FunctionName,
|
||||||
content: string,
|
content: string,
|
||||||
customData: ProjectInit | ScriptSummary | CharacterGeneration | SketchGeneration | ShotSketchGeneration
|
customData: ProjectInit | ScriptSummary | CharacterGeneration | SketchGeneration | ShotSketchGeneration | ShotVideoGeneration
|
||||||
): MessageBlock[] {
|
): MessageBlock[] {
|
||||||
let blocks: MessageBlock[] = [];
|
let blocks: MessageBlock[] = [];
|
||||||
|
|
||||||
@ -303,9 +311,9 @@ function transformSystemMessage(
|
|||||||
text: '图片中演员形象仅供参考,后续可根据视频生成后进行调整。'
|
text: '图片中演员形象仅供参考,后续可根据视频生成后进行调整。'
|
||||||
}, {
|
}, {
|
||||||
type: 'progress',
|
type: 'progress',
|
||||||
value: customData.count,
|
value: customData.completed_count,
|
||||||
total: customData.total_count,
|
total: customData.total_count,
|
||||||
label: `已生成 ${customData.count} 个演员,剧本中共有 ${customData.total_count} 个`
|
label: `已生成 ${customData.completed_count} 个演员,剧本中共有 ${customData.total_count} 个`
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -323,9 +331,9 @@ function transformSystemMessage(
|
|||||||
text: '图片中场景仅供参考,后续可根据视频生成后进行调整。'
|
text: '图片中场景仅供参考,后续可根据视频生成后进行调整。'
|
||||||
}, {
|
}, {
|
||||||
type: 'progress',
|
type: 'progress',
|
||||||
value: customData.count,
|
value: customData.completed_count,
|
||||||
total: customData.total_count,
|
total: customData.total_count,
|
||||||
label: `已生成 ${customData.count} 个场景,剧本中共有 ${customData.total_count} 个`
|
label: `已生成 ${customData.completed_count} 个场景,剧本中共有 ${customData.total_count} 个`
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -343,9 +351,29 @@ function transformSystemMessage(
|
|||||||
text: '图片中故事板静帧仅供参考,后续可根据视频生成后进行调整。'
|
text: '图片中故事板静帧仅供参考,后续可根据视频生成后进行调整。'
|
||||||
}, {
|
}, {
|
||||||
type: 'progress',
|
type: 'progress',
|
||||||
value: customData.count,
|
value: customData.completed_count,
|
||||||
total: customData.total_count,
|
total: customData.total_count,
|
||||||
label: `已生成 ${customData.count} 个故事板静帧,剧本中共有 ${customData.total_count} 个`
|
label: `已生成 ${customData.completed_count} 个故事板静帧,剧本中共有 ${customData.total_count} 个`
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'generate_video':
|
||||||
|
if (isShotVideoGeneration(customData)) {
|
||||||
|
blocks = [{
|
||||||
|
type: 'text',
|
||||||
|
text: `🎬 分镜视频生成 \n核心氛围:${customData.core_atmosphere}`
|
||||||
|
}, {
|
||||||
|
type: 'video',
|
||||||
|
url: customData.urls[0] || ''
|
||||||
|
}, {
|
||||||
|
type: 'text',
|
||||||
|
text: '后续可在剪辑线上进行编辑。'
|
||||||
|
}, {
|
||||||
|
type: 'progress',
|
||||||
|
value: customData.completed_count,
|
||||||
|
total: customData.total_count,
|
||||||
|
label: `已生成 ${customData.completed_count} 个分镜视频,剧本中共有 ${customData.total_count} 个`
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -77,8 +77,7 @@ export interface MessagesResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContentType = "text" | "image" | "video" | "audio";
|
type ContentType = "text" | "image" | "video" | "audio";
|
||||||
export type MessageType = "project_init" | "script_summary" | "character_generation" | "sketch_generation" | "shot_sketch_generation";
|
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";
|
|
||||||
|
|
||||||
// 项目创建
|
// 项目创建
|
||||||
export interface ProjectInit {
|
export interface ProjectInit {
|
||||||
@ -94,14 +93,14 @@ export interface ScriptSummary {
|
|||||||
export interface CharacterGeneration {
|
export interface CharacterGeneration {
|
||||||
character_name: string; // 角色名称
|
character_name: string; // 角色名称
|
||||||
image_path: string; // 角色图片
|
image_path: string; // 角色图片
|
||||||
count: number; // 生成数量
|
completed_count: number; // 生成数量
|
||||||
total_count: number; // 总数量
|
total_count: number; // 总数量
|
||||||
}
|
}
|
||||||
// 场景草图生成
|
// 场景草图生成
|
||||||
export interface SketchGeneration {
|
export interface SketchGeneration {
|
||||||
sketch_name: string; // 场景草图名称
|
sketch_name: string; // 场景草图名称
|
||||||
image_path: string; // 场景草图图片
|
image_path: string; // 场景草图图片
|
||||||
count: number; // 生成数量
|
completed_count: number; // 生成数量
|
||||||
total_count: number; // 总数量
|
total_count: number; // 总数量
|
||||||
}
|
}
|
||||||
// 分镜草图生成
|
// 分镜草图生成
|
||||||
@ -110,7 +109,14 @@ export interface ShotSketchGeneration {
|
|||||||
atmosphere: string; // 氛围描述
|
atmosphere: string; // 氛围描述
|
||||||
key_action: string; // 关键动作描述
|
key_action: string; // 关键动作描述
|
||||||
url: string; // 分镜草图图片
|
url: string; // 分镜草图图片
|
||||||
count: number; // 生成数量
|
completed_count: number; // 生成数量
|
||||||
|
total_count: number; // 总数量
|
||||||
|
}
|
||||||
|
// 分镜视频生成
|
||||||
|
export interface ShotVideoGeneration {
|
||||||
|
core_atmosphere: string; // 核心氛围
|
||||||
|
urls: string[]; // 分镜视频
|
||||||
|
completed_count: number; // 生成数量
|
||||||
total_count: number; // 总数量
|
total_count: number; // 总数量
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,9 +130,8 @@ export interface RealApiMessage {
|
|||||||
id: number;
|
id: number;
|
||||||
role: Role;
|
role: Role;
|
||||||
content: string;
|
content: string;
|
||||||
message_type?: MessageType;
|
|
||||||
function_name?: FunctionName;
|
function_name?: FunctionName;
|
||||||
custom_data?: ProjectInit | ScriptSummary | CharacterGeneration | SketchGeneration | ShotSketchGeneration;
|
custom_data?: ProjectInit | ScriptSummary | CharacterGeneration | SketchGeneration | ShotSketchGeneration | ShotVideoGeneration;
|
||||||
status: MessageStatus;
|
status: MessageStatus;
|
||||||
intent_type: IntentType;
|
intent_type: IntentType;
|
||||||
}
|
}
|
||||||
@ -23,14 +23,28 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
|
|
||||||
// 系统推送状态
|
// 系统推送状态
|
||||||
const [systemPush, setSystemPush] = useState(true);
|
const [systemPush, setSystemPush] = useState(true);
|
||||||
|
const systemPushDisabledTimeRef = useRef<number | null>(null);
|
||||||
|
|
||||||
// 状态引用
|
// 状态引用
|
||||||
const configRef = useRef(config);
|
const configRef = useRef(config);
|
||||||
const isInitialLoadRef = useRef(true);
|
const isInitialLoadRef = useRef(true);
|
||||||
const timeoutIdRef = useRef<NodeJS.Timeout | null>(null);
|
const timeoutIdRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const isPollingRef = useRef(false);
|
||||||
const isViewingHistoryRef = useRef(false);
|
const isViewingHistoryRef = useRef(false);
|
||||||
const prevTotalCountRef = useRef(totalCount);
|
const prevTotalCountRef = useRef(totalCount);
|
||||||
const isPollingRef = useRef(false);
|
|
||||||
|
// 过滤消息
|
||||||
|
const filterMessages = useCallback((messages: ChatMessage[]) => {
|
||||||
|
if (systemPush || !systemPushDisabledTimeRef.current) {
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 系统推送关闭时,只显示关闭前的系统消息和所有非系统消息
|
||||||
|
return messages.filter(msg =>
|
||||||
|
msg.role !== 'system' ||
|
||||||
|
msg.createdAt <= systemPushDisabledTimeRef.current!
|
||||||
|
);
|
||||||
|
}, [systemPush]);
|
||||||
|
|
||||||
// 合并和去重消息
|
// 合并和去重消息
|
||||||
const mergeMessages = useCallback((oldMessages: ChatMessage[], newMessages: ChatMessage[]) => {
|
const mergeMessages = useCallback((oldMessages: ChatMessage[], newMessages: ChatMessage[]) => {
|
||||||
@ -42,9 +56,12 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 转回数组并按 id 排序
|
// 转回数组并按 id 排序
|
||||||
return Array.from(messageMap.values())
|
const merged = Array.from(messageMap.values())
|
||||||
.sort((a, b) => Number(a.id) - Number(b.id));
|
.sort((a, b) => Number(a.id) - Number(b.id));
|
||||||
}, []);
|
|
||||||
|
// 过滤系统消息
|
||||||
|
return filterMessages(merged);
|
||||||
|
}, [filterMessages]);
|
||||||
|
|
||||||
// 更新 config 引用
|
// 更新 config 引用
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -68,9 +85,11 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetchMessages(configRef.current, 0, PAGE_SIZE);
|
const response = await fetchMessages(configRef.current, 0, PAGE_SIZE);
|
||||||
setLatestMessages(response.messages);
|
const filteredMessages = filterMessages(response.messages);
|
||||||
|
|
||||||
|
setLatestMessages(response.messages); // 保存完整的消息列表
|
||||||
if (!isViewingHistoryRef.current) {
|
if (!isViewingHistoryRef.current) {
|
||||||
setDisplayMessages(response.messages);
|
setDisplayMessages(filteredMessages); // 显示过滤后的消息
|
||||||
}
|
}
|
||||||
setTotalCount(response.totalCount);
|
setTotalCount(response.totalCount);
|
||||||
setHasMore(response.hasMore);
|
setHasMore(response.hasMore);
|
||||||
@ -83,7 +102,7 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, [filterMessages]);
|
||||||
|
|
||||||
// 加载更多历史消息
|
// 加载更多历史消息
|
||||||
const loadMoreMessages = useCallback(async () => {
|
const loadMoreMessages = useCallback(async () => {
|
||||||
@ -111,9 +130,9 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
// 返回最新消息
|
// 返回最新消息
|
||||||
const backToLatest = useCallback(async () => {
|
const backToLatest = useCallback(async () => {
|
||||||
isViewingHistoryRef.current = false;
|
isViewingHistoryRef.current = false;
|
||||||
setDisplayMessages(latestMessages);
|
setDisplayMessages(filterMessages(latestMessages));
|
||||||
onMessagesUpdate?.(true);
|
onMessagesUpdate?.(true);
|
||||||
}, [latestMessages, onMessagesUpdate]);
|
}, [latestMessages, filterMessages, onMessagesUpdate]);
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
const handleSendMessage = useCallback(async (blocks: MessageBlock[]) => {
|
const handleSendMessage = useCallback(async (blocks: MessageBlock[]) => {
|
||||||
@ -177,8 +196,19 @@ export function useMessages({ config, onMessagesUpdate }: UseMessagesProps): [Me
|
|||||||
|
|
||||||
// 系统推送开关
|
// 系统推送开关
|
||||||
const toggleSystemPush = useCallback(() => {
|
const toggleSystemPush = useCallback(() => {
|
||||||
setSystemPush(prev => !prev);
|
setSystemPush(prev => {
|
||||||
}, []);
|
if (prev) {
|
||||||
|
// 关闭系统推送时,记录当前时间
|
||||||
|
systemPushDisabledTimeRef.current = Date.now();
|
||||||
|
} else {
|
||||||
|
// 开启系统推送时,清除时间记录并更新显示
|
||||||
|
systemPushDisabledTimeRef.current = null;
|
||||||
|
// 立即更新显示的消息
|
||||||
|
setDisplayMessages(filterMessages(latestMessages));
|
||||||
|
}
|
||||||
|
return !prev;
|
||||||
|
});
|
||||||
|
}, [latestMessages, filterMessages]);
|
||||||
|
|
||||||
// 轮询获取最新消息
|
// 轮询获取最新消息
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user