diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 8d62c874b..f974dc3e4 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -256,14 +256,20 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]); + // 标记是否已经为当前画布设置过标题(避免重复调用) + const hasSetCanvasTitle = useRef(false); + // 处理发送 - const handleSend = useCallback(() => { + const handleSend = useCallback(async () => { if (!input.trim() && attachments.length === 0) return; if (!selectedModelId) { toast.error("请选择一个模型"); return; } + // 获取第一张图片的 URL(用于自动命名和缩略图) + const firstImageAttachment = attachments.find(a => a.contentType?.startsWith('image/')); + // 构建 parts 数组:文件在前,文本在后(与 multimodal-input 一致) const parts: any[] = []; @@ -313,9 +319,50 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF toast.success(`已将 ${attachments.length} 张图片添加到画布`); } + // 如果是第一次上传图片,自动识别并设置画布标题和缩略图 + if (firstImageAttachment && !hasSetCanvasTitle.current) { + hasSetCanvasTitle.current = true; + + // 异步调用 AI 识别图片主体并更新画布 + (async () => { + try { + // 调用 auto-title API 识别图片主体 + const response = await fetch('/api/canvas/auto-title', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ imageUrl: firstImageAttachment.url }), + }); + + if (response.ok) { + const data = await response.json(); + const title = data.title || '未命名画布'; + + // 提取纯 UUID(去掉 canvas- 前缀) + const rawId = chatId.startsWith('canvas-') + ? chatId.replace('canvas-', '') + : chatId; + + // 更新画布标题和缩略图 + await fetch(`/api/canvas/${rawId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + title: title, + thumbnail: firstImageAttachment.url, + }), + }); + + console.log('[CanvasChat] 画布已自动命名为:', title); + } + } catch (error) { + console.error('[CanvasChat] 自动命名失败:', error); + } + })(); + } + setInput(""); setAttachments([]); - }, [input, attachments, selectedModelId, sendMessage, addNode, nodes.length]); + }, [input, attachments, selectedModelId, sendMessage, addNode, nodes.length, chatId]); // 处理文件选择 const handleFileSelect = async (e: React.ChangeEvent) => {