feat(canvas): auto-name generated images via auto-title model
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-21 04:55:31 +08:00
parent c43f6a95fc
commit d137e0ba26

View File

@ -2676,13 +2676,14 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
const x = 100 + (existingNodes % 3) * (dimensions.width + spacing);
const y = 100 + Math.floor(existingNodes / 3) * (dimensions.height + spacing);
addNode({
const nodeId = addNode({
type: 'image',
position: { x, y },
size: { width: dimensions.width, height: dimensions.height },
data: {
src: url,
status: 'completed',
title: '图片',
prompt: generationPrompt || '对话生成',
metadata: {
originalWidth: dimensions.originalWidth,
@ -2693,6 +2694,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
},
connections: [],
});
void autoNameGeneratedImageNode(nodeId, url);
addedImageCount += 1;
}
}
@ -2736,7 +2738,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
}
}
});
}, [messages, addNode, nodes]);
}, [messages, addNode, nodes, autoNameGeneratedImageNode]);
// 为历史节点补全可编辑的原始提示词(旧数据里可能只有“对话生成”占位文案)
useEffect(() => {
@ -2789,6 +2791,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
// 标记是否已经为当前画布设置过标题(避免重复调用)
const hasSetCanvasTitle = useRef(false);
const imageAutoTitleCacheRef = useRef<Map<string, string>>(new Map());
// 🆕 Agent模式上下文(画布图片布局)
const buildAutoContext = useCallback(() => {
@ -4437,6 +4440,60 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
}
}, [chatId]);
const autoNameGeneratedImageNode = useCallback(
async (nodeId: string, imageUrl: string) => {
if (!nodeId || !imageUrl) return;
const normalizeAutoTitle = (rawTitle: string) => {
const compact = String(rawTitle || "").replace(/\s+/g, "").trim();
if (!compact || compact === "新画布" || compact === "未命名画布" || compact.includes("画布")) {
return "图片";
}
return compact.slice(0, 12);
};
const applyNodeTitle = (title: string) => {
const storeState = useCanvasStore.getState();
const currentNode = storeState.getNode(nodeId);
if (!currentNode) return;
const currentData = ((currentNode.data as any) || {}) as Record<string, any>;
storeState.updateNode(nodeId, {
data: {
...currentData,
title,
metadata: {
...(currentData.metadata || {}),
autoTitle: title,
},
},
});
};
const cachedTitle = imageAutoTitleCacheRef.current.get(imageUrl);
if (cachedTitle) {
applyNodeTitle(cachedTitle);
return;
}
try {
const response = await fetch('/api/canvas/auto-title', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ imageUrl }),
});
const data = await response.json().catch(() => ({}));
const title = normalizeAutoTitle(String(data?.title || ""));
imageAutoTitleCacheRef.current.set(imageUrl, title);
applyNodeTitle(title);
} catch (error) {
console.warn('[CanvasChat] 自动命名图片失败:', error);
applyNodeTitle("图片");
}
},
[],
);
const uploadImageFileAndAddToCanvas = useCallback(async (
file: File,
nodeIndex: number