157 lines
5.7 KiB
TypeScript
157 lines
5.7 KiB
TypeScript
import type { DirectAgentToolCapability } from "@/lib/ai/runtime/direct-agent-execution";
|
|
|
|
export type CanvasAgentComposerMode = "agent" | "image" | "video" | "detail" | "clawd";
|
|
export type CanvasAgentEntryMode = "auto" | "preset";
|
|
|
|
export interface CanvasAgentRequestPolicy {
|
|
effectiveSelectedChatModel: string;
|
|
shouldForceToolOrchestration: boolean;
|
|
reason: string | null;
|
|
}
|
|
|
|
export interface CanvasAgentTargetPreference {
|
|
shouldPreferLatestResult: boolean;
|
|
shouldPreferWorkingMemoryTarget: boolean;
|
|
confidence: number;
|
|
reason: string | null;
|
|
}
|
|
|
|
const DEICTIC_TARGET_REGEX =
|
|
/(这张图|这只|这个|这款|这套|当前这张|当前这个|当前这只|这一张|这一只|这个产品|这个物体|这只猫|这只狗)/i;
|
|
|
|
const ACTIONABLE_IMAGE_EDIT_REGEX =
|
|
/(抠图|去背景|透明背景|去背|扣图|抠出|扣出|抠出来|扣出来|移除背景|去水印|水印|去logo|去\s*logo|移除logo|去除logo|换背景|改背景|背景换成|背景改成|白底|纯色背景|替换.*背景|变清晰|高清|锐化|降噪|提升质量|修复|清晰化|扩展|拓展|延伸|扩图|outpainting|拓宽|扩大|多视角|换视角|改视角|视角变体|新角度|换角度|改角度|去除|消除|擦掉|删除|移除|p掉|重绘|风格化|卡通化|动漫风|油画风|调色|调整颜色|亮度|对比度|饱和度|缩放|放大|缩小|调整尺寸|裁剪|resize|crop|修图|p图|改图|调图|编辑.*图|优化.*图|重做|再调整|继续改|继续调|处理)/i;
|
|
|
|
export function normalizeCanvasAgentRequestText(text: string) {
|
|
return String(text || "").toLowerCase().replace(/\s+/g, "").trim();
|
|
}
|
|
|
|
export function hasCanvasAgentDeicticTarget(text: string) {
|
|
return DEICTIC_TARGET_REGEX.test(String(text || ""));
|
|
}
|
|
|
|
export function hasCanvasAgentActionableImageEditIntent(text: string) {
|
|
return ACTIONABLE_IMAGE_EDIT_REGEX.test(String(text || ""));
|
|
}
|
|
|
|
export function inferCanvasAgentImageEditCapability(
|
|
text: string,
|
|
): DirectAgentToolCapability | null {
|
|
const normalizedText = normalizeCanvasAgentRequestText(text);
|
|
if (!normalizedText) return null;
|
|
if (/去水印|水印|去logo|移除logo|去除logo/.test(normalizedText)) {
|
|
return "remove_watermark";
|
|
}
|
|
if (/抠图|去背景|透明背景|去背|扣图|抠出|扣出|抠出来|扣出来|移除背景/.test(normalizedText)) {
|
|
return "remove_background";
|
|
}
|
|
if (/多视角|换视角|改视角|视角变体|新角度|换角度|改角度|侧面|侧视|背面|背后|俯视|俯拍|仰视|仰拍|低机位|高机位/.test(normalizedText)) {
|
|
return "angle_variant";
|
|
}
|
|
if (/扩展|拓展|延伸|扩图|outpainting|拓宽|扩大|比例|画幅|竖版|横版|竖图|横图|9:16|16:9|1:1/.test(normalizedText)) {
|
|
return "extend";
|
|
}
|
|
if (/调整尺寸|裁剪|resize|crop|缩放|放大|缩小/.test(normalizedText)) {
|
|
return "resize";
|
|
}
|
|
if (/局部|框选|选区|区域|涂抹|蒙版/.test(normalizedText)) {
|
|
return "local_edit";
|
|
}
|
|
if (/高清|清晰|锐化|降噪|提升质量|修复|清晰化/.test(normalizedText)) {
|
|
return "enhance";
|
|
}
|
|
if (hasCanvasAgentActionableImageEditIntent(text)) {
|
|
return "generic_edit";
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function resolveCanvasAgentRequestPolicy(params: {
|
|
composerMode?: string | null;
|
|
agentEntryMode?: string | null;
|
|
selectedChatModel?: string | null;
|
|
hasCanvasControlIntentFastPath?: boolean;
|
|
}): CanvasAgentRequestPolicy {
|
|
const composerMode = String(params.composerMode || "").trim();
|
|
const agentEntryMode = String(params.agentEntryMode || "").trim();
|
|
const selectedChatModel = String(params.selectedChatModel || "").trim() || "auto";
|
|
const isAgentAutoComposer = composerMode === "agent" && agentEntryMode !== "preset";
|
|
const shouldForceToolOrchestration =
|
|
isAgentAutoComposer || Boolean(params.hasCanvasControlIntentFastPath);
|
|
|
|
if (isAgentAutoComposer) {
|
|
return {
|
|
effectiveSelectedChatModel: "auto",
|
|
shouldForceToolOrchestration: true,
|
|
reason: "agent_auto_composer",
|
|
};
|
|
}
|
|
|
|
if (params.hasCanvasControlIntentFastPath) {
|
|
return {
|
|
effectiveSelectedChatModel: selectedChatModel,
|
|
shouldForceToolOrchestration: true,
|
|
reason: "canvas_control_fast_path",
|
|
};
|
|
}
|
|
|
|
return {
|
|
effectiveSelectedChatModel: selectedChatModel,
|
|
shouldForceToolOrchestration,
|
|
reason: null,
|
|
};
|
|
}
|
|
|
|
export function resolveCanvasAgentTargetPreference(params: {
|
|
text: string;
|
|
selectedImageCount: number;
|
|
latestResultImageCount: number;
|
|
workingMemoryTargetImageCount: number;
|
|
}): CanvasAgentTargetPreference {
|
|
const hasDeicticTarget = hasCanvasAgentDeicticTarget(params.text);
|
|
const hasEditIntent = hasCanvasAgentActionableImageEditIntent(params.text);
|
|
const selectedImageCount = Math.max(0, Math.round(params.selectedImageCount || 0));
|
|
const latestResultImageCount = Math.max(
|
|
0,
|
|
Math.round(params.latestResultImageCount || 0),
|
|
);
|
|
const workingMemoryTargetImageCount = Math.max(
|
|
0,
|
|
Math.round(params.workingMemoryTargetImageCount || 0),
|
|
);
|
|
|
|
if (!hasDeicticTarget || !hasEditIntent || selectedImageCount > 0) {
|
|
return {
|
|
shouldPreferLatestResult: false,
|
|
shouldPreferWorkingMemoryTarget: false,
|
|
confidence: 0,
|
|
reason: null,
|
|
};
|
|
}
|
|
|
|
if (latestResultImageCount > 0) {
|
|
return {
|
|
shouldPreferLatestResult: true,
|
|
shouldPreferWorkingMemoryTarget: false,
|
|
confidence: 90,
|
|
reason: "deictic_edit_prefers_latest_result",
|
|
};
|
|
}
|
|
|
|
if (workingMemoryTargetImageCount > 0) {
|
|
return {
|
|
shouldPreferLatestResult: false,
|
|
shouldPreferWorkingMemoryTarget: true,
|
|
confidence: 86,
|
|
reason: "deictic_edit_uses_working_memory_target",
|
|
};
|
|
}
|
|
|
|
return {
|
|
shouldPreferLatestResult: false,
|
|
shouldPreferWorkingMemoryTarget: false,
|
|
confidence: 0,
|
|
reason: null,
|
|
};
|
|
}
|