feat: 画布聊天面板功能增强
1. 加载历史对话消息(从 API 获取) 2. 选中画布图片时自动添加到对话附件 3. 修复类型错误 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6464135cf6
commit
8f90aaba08
@ -104,6 +104,46 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
|||||||
// Canvas store
|
// Canvas store
|
||||||
const addNode = useCanvasStore((state) => state.addNode);
|
const addNode = useCanvasStore((state) => state.addNode);
|
||||||
const nodes = useCanvasStore((state) => state.nodes);
|
const nodes = useCanvasStore((state) => state.nodes);
|
||||||
|
const selectedNodeIds = useCanvasStore((state) => state.selectedNodeIds);
|
||||||
|
|
||||||
|
// 获取纯 UUID(去掉 canvas- 前缀)用于 API 调用
|
||||||
|
const rawChatId = chatId.startsWith('canvas-')
|
||||||
|
? chatId.replace('canvas-', '')
|
||||||
|
: chatId;
|
||||||
|
|
||||||
|
// 从 API 加载历史消息
|
||||||
|
const { data: historyData, isLoading: isLoadingHistory } = useSWR<{
|
||||||
|
messages: ChatMessage[];
|
||||||
|
}>(rawChatId ? `/api/messages?chatId=${rawChatId}` : null, fetcher);
|
||||||
|
|
||||||
|
// 获取选中的图片节点
|
||||||
|
const selectedImageNodes = nodes.filter(
|
||||||
|
n => selectedNodeIds.includes(n.id) && n.type === 'image' && (n.data as any)?.src
|
||||||
|
);
|
||||||
|
|
||||||
|
// 当选中画布中的图片时,自动添加到附件
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedImageNodes.length > 0) {
|
||||||
|
const newAttachments: Attachment[] = selectedImageNodes.map(node => {
|
||||||
|
const data = node.data as any;
|
||||||
|
return {
|
||||||
|
url: data.src,
|
||||||
|
name: data.prompt || '画布图片',
|
||||||
|
contentType: 'image/jpeg',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 只添加还没在附件中的图片
|
||||||
|
setAttachments(prev => {
|
||||||
|
const existingUrls = new Set(prev.map(a => a.url));
|
||||||
|
const toAdd = newAttachments.filter(a => !existingUrls.has(a.url));
|
||||||
|
if (toAdd.length > 0) {
|
||||||
|
return [...prev, ...toAdd];
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [selectedImageNodes.length, selectedNodeIds]);
|
||||||
|
|
||||||
// 获取模型列表
|
// 获取模型列表
|
||||||
const { data: modelsData } = useSWR<{
|
const { data: modelsData } = useSWR<{
|
||||||
@ -145,6 +185,11 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
|||||||
imageParamsRef.current = imageParams;
|
imageParamsRef.current = imageParams;
|
||||||
}, [imageParams]);
|
}, [imageParams]);
|
||||||
|
|
||||||
|
// 合并 initialMessages 和历史消息
|
||||||
|
const mergedInitialMessages = historyData?.messages?.length
|
||||||
|
? historyData.messages
|
||||||
|
: initialMessages;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
messages,
|
messages,
|
||||||
setMessages,
|
setMessages,
|
||||||
@ -153,7 +198,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
|||||||
stop,
|
stop,
|
||||||
} = useChat<ChatMessage>({
|
} = useChat<ChatMessage>({
|
||||||
id: chatId,
|
id: chatId,
|
||||||
messages: initialMessages,
|
messages: mergedInitialMessages,
|
||||||
experimental_throttle: 100,
|
experimental_throttle: 100,
|
||||||
generateId: generateUUID,
|
generateId: generateUUID,
|
||||||
transport: new DefaultChatTransport({
|
transport: new DefaultChatTransport({
|
||||||
@ -217,6 +262,16 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
|||||||
toast.error(error.message || "生成失败");
|
toast.error(error.message || "生成失败");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 当历史消息加载完成后,更新消息列表
|
||||||
|
const hasLoadedHistory = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (historyData?.messages?.length && !hasLoadedHistory.current) {
|
||||||
|
hasLoadedHistory.current = true;
|
||||||
|
setMessages(historyData.messages);
|
||||||
|
console.log('[CanvasChat] 已加载历史消息:', historyData.messages.length);
|
||||||
|
}
|
||||||
|
}, [historyData, setMessages]);
|
||||||
|
|
||||||
// 监听消息变化,提取图片并添加到画布
|
// 监听消息变化,提取图片并添加到画布
|
||||||
const processedMessageIds = useRef<Set<string>>(new Set());
|
const processedMessageIds = useRef<Set<string>>(new Set());
|
||||||
@ -574,9 +629,9 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* 附件预览 */}
|
{/* 附件预览 */}
|
||||||
{message.attachments && message.attachments.length > 0 && (
|
{(message as any).attachments && (message as any).attachments.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-2 mb-2">
|
<div className="flex flex-wrap gap-2 mb-2">
|
||||||
{message.attachments.map((att: any, i: number) => (
|
{(message as any).attachments.map((att: any, i: number) => (
|
||||||
<img
|
<img
|
||||||
key={i}
|
key={i}
|
||||||
src={att.url}
|
src={att.url}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user