fix: 上传图片立即添加到画布
1. 图片上传成功后立即显示在画布中 2. 同时触发自动命名和设置缩略图 3. 移除发送时重复添加图片的逻辑 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
5e642165df
commit
e0366c43fd
@ -259,7 +259,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
// 标记是否已经为当前画布设置过标题(避免重复调用)
|
||||
const hasSetCanvasTitle = useRef(false);
|
||||
|
||||
// 处理发送
|
||||
// 处理发送(图片已在上传时添加到画布,这里只发送消息)
|
||||
const handleSend = useCallback(async () => {
|
||||
if (!input.trim() && attachments.length === 0) return;
|
||||
if (!selectedModelId) {
|
||||
@ -267,40 +267,17 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取第一张图片的 URL(用于自动命名和缩略图)
|
||||
const firstImageAttachment = attachments.find(a => a.contentType?.startsWith('image/'));
|
||||
|
||||
// 构建 parts 数组:文件在前,文本在后(与 multimodal-input 一致)
|
||||
const parts: any[] = [];
|
||||
|
||||
// 添加文件部分(作为 file 类型的 part)
|
||||
// 同时将用户上传的图片添加到画布
|
||||
attachments.forEach((a, index) => {
|
||||
attachments.forEach((a) => {
|
||||
parts.push({
|
||||
type: "file" as const,
|
||||
mediaType: a.contentType,
|
||||
name: a.name,
|
||||
url: a.url,
|
||||
});
|
||||
|
||||
// 将用户上传的图片添加到画布
|
||||
if (a.contentType?.startsWith('image/')) {
|
||||
const existingNodes = nodes.length;
|
||||
const x = 100 + ((existingNodes + index) % 4) * 320;
|
||||
const y = 100 + Math.floor((existingNodes + index) / 4) * 320;
|
||||
|
||||
addNode({
|
||||
type: 'image',
|
||||
position: { x, y },
|
||||
size: { width: 300, height: 300 },
|
||||
data: {
|
||||
src: a.url,
|
||||
status: 'completed',
|
||||
prompt: '用户上传',
|
||||
},
|
||||
connections: [],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 添加文本部分
|
||||
@ -315,60 +292,17 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
parts: parts,
|
||||
});
|
||||
|
||||
if (attachments.length > 0) {
|
||||
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, chatId]);
|
||||
}, [input, attachments, selectedModelId, sendMessage]);
|
||||
|
||||
// 处理文件选择
|
||||
// 处理文件选择 - 上传后立即添加到画布
|
||||
const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = e.target.files;
|
||||
if (!files) return;
|
||||
|
||||
let firstImageUrl: string | null = null;
|
||||
|
||||
for (const file of Array.from(files)) {
|
||||
if (!file.type.startsWith('image/')) {
|
||||
toast.error('请选择图片文件');
|
||||
@ -395,17 +329,86 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const imageUrl = data.url;
|
||||
|
||||
// 记录第一张图片的 URL(用于自动命名和缩略图)
|
||||
if (!firstImageUrl) {
|
||||
firstImageUrl = imageUrl;
|
||||
}
|
||||
|
||||
// 添加到附件列表
|
||||
setAttachments(prev => [...prev, {
|
||||
url: data.url,
|
||||
url: imageUrl,
|
||||
name: file.name,
|
||||
contentType: file.type,
|
||||
}]);
|
||||
|
||||
// 立即将图片添加到画布
|
||||
const existingNodes = nodes.length;
|
||||
const x = 100 + (existingNodes % 4) * 320;
|
||||
const y = 100 + Math.floor(existingNodes / 4) * 320;
|
||||
|
||||
addNode({
|
||||
type: 'image',
|
||||
position: { x, y },
|
||||
size: { width: 300, height: 300 },
|
||||
data: {
|
||||
src: imageUrl,
|
||||
status: 'completed',
|
||||
prompt: '用户上传',
|
||||
},
|
||||
connections: [],
|
||||
});
|
||||
|
||||
toast.success('图片已添加到画布');
|
||||
|
||||
} catch (error) {
|
||||
toast.error('图片上传失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是第一次上传图片,自动识别并设置画布标题和缩略图
|
||||
if (firstImageUrl && !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: firstImageUrl }),
|
||||
});
|
||||
|
||||
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: firstImageUrl,
|
||||
}),
|
||||
});
|
||||
|
||||
console.log('[CanvasChat] 画布已自动命名为:', title);
|
||||
toast.success(`画布已命名为: ${title}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[CanvasChat] 自动命名失败:', error);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
e.target.value = '';
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user