improve target image resolution for follow-up edits
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-03-10 09:43:13 +08:00
parent 641827031f
commit f1dd0e9da9

View File

@ -7,9 +7,9 @@ import type {
} from "@/lib/ai/context-memory/types";
const ORIGINAL_IMAGE_REGEX =
/(原图|上传图|参考图|最初那张|第一张图|素材图|源图|原始图片|原始那张)/i;
/(原图|上传图|参考图|最初那张|第一张图|素材图|源图|原始图片|原始那张|我发的那张|上传的那张|原来的图)/i;
const LATEST_RESULT_REGEX =
/(上一张|上一轮|刚生成|最新生成|这个结果|该结果|按这个结果|继续在这张|基于这张结果|延续上一次结果|上一版|刚才那张结果)/i;
/(上一张|上一轮|刚生成|最新生成|这个结果|该结果|按这个结果|继续在这张|基于这张结果|延续上一次结果|上一版|刚才那张结果|生成的图|生成图|结果图|出图结果|刚出的图|上一张生成图|上一轮结果图|现在这张生成图)/i;
const SELECTION_REGEX = /(选中的|当前这张|我选的|这几张|这些图|选中图)/i;
const ACTIONABLE_EDIT_REGEX =
/(改|调整|优化|换|替换|去掉|抠|重绘|增强|修|处理|按照|按|保留|统一|色差|背景|清晰|风格|亮一点|暗一点|白底|透明底)/i;
@ -154,6 +154,23 @@ function buildResolvedTargetAssets(params: {
};
}
function toWorkingMemoryRefs(urls: string[]): ResolvedImageRef[] {
return urls.map((url) => ({
url,
normalizedUrl: url,
source: "working_memory" as const,
role: "working_memory" as const,
}));
}
function buildNormalizedUrlSet(refs: ResolvedImageRef[]): Set<string> {
return new Set(
refs
.map((ref) => String(ref.normalizedUrl || ref.url || "").trim())
.filter(Boolean),
);
}
export function resolveTargetAssets(
params: ResolveTargetAssetsParams,
): ResolvedTargetAssets {
@ -167,10 +184,47 @@ export function resolveTargetAssets(
const candidateRefs = mediaInput.imageRefs;
const workingState = params.workingState;
const focusPolicy = params.contextPayload?.focusPolicy || "auto";
const workingStateGeneratedUrls = normalizeStringArray(workingState?.lastGeneratedImageUrls);
const workingStateUploadedUrls = normalizeStringArray(workingState?.lastUploadedImageUrls);
const generatedRefs =
workingStateGeneratedUrls.length > 0 ? toWorkingMemoryRefs(workingStateGeneratedUrls) : assistantRefs;
const originalRefs =
workingStateUploadedUrls.length > 0 ? toWorkingMemoryRefs(workingStateUploadedUrls) : userRefs;
const selectedLooksLikeOriginal = (() => {
if (selectedRefs.length === 0 || originalRefs.length === 0) return false;
const originalKeys = buildNormalizedUrlSet(originalRefs);
return selectedRefs.every((ref) =>
originalKeys.has(String(ref.normalizedUrl || ref.url || "").trim()),
);
})();
if (focusPolicy === "original" && userRefs.length > 0) {
if (ORIGINAL_IMAGE_REGEX.test(text) && originalRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: userRefs,
targetRefs: originalRefs,
candidateRefs,
resolutionMode: "text_reference",
confidence: 95,
needsClarification: false,
reason: "用户文本明确指向原图/上传图",
fromHistory: true,
});
}
if (LATEST_RESULT_REGEX.test(text) && generatedRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: generatedRefs,
candidateRefs,
resolutionMode: "latest_result",
confidence: 95,
needsClarification: false,
reason: "用户文本明确指向上一轮结果/生成图",
fromHistory: true,
});
}
if (focusPolicy === "original" && originalRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: originalRefs,
candidateRefs,
resolutionMode: "text_reference",
confidence: 96,
@ -180,9 +234,9 @@ export function resolveTargetAssets(
});
}
if (focusPolicy === "latest_result" && assistantRefs.length > 0) {
if (focusPolicy === "latest_result" && generatedRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: assistantRefs,
targetRefs: generatedRefs,
candidateRefs,
resolutionMode: "latest_result",
confidence: 96,
@ -192,42 +246,6 @@ export function resolveTargetAssets(
});
}
if (focusPolicy === "selected" && selectedRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: selectedRefs,
candidateRefs,
resolutionMode: "explicit_selection",
confidence: 97,
needsClarification: false,
reason: "前端已明确选中目标图片",
fromHistory: true,
});
}
if (ORIGINAL_IMAGE_REGEX.test(text) && userRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: userRefs,
candidateRefs,
resolutionMode: "text_reference",
confidence: 94,
needsClarification: false,
reason: "用户文本明确指向原图/上传图",
fromHistory: true,
});
}
if (LATEST_RESULT_REGEX.test(text) && assistantRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: assistantRefs,
candidateRefs,
resolutionMode: "latest_result",
confidence: 94,
needsClarification: false,
reason: "用户文本明确指向上一轮结果",
fromHistory: true,
});
}
const ordinalRefs = pickByOrdinal(text, canvasRefs);
if (ordinalRefs.length > 0) {
return buildResolvedTargetAssets({
@ -266,6 +284,37 @@ export function resolveTargetAssets(
});
}
if (
ACTIONABLE_EDIT_REGEX.test(text) &&
currentRefs.length === 0 &&
generatedRefs.length > 0 &&
selectedLooksLikeOriginal &&
!SELECTION_REGEX.test(text) &&
!ORIGINAL_IMAGE_REGEX.test(text)
) {
return buildResolvedTargetAssets({
targetRefs: generatedRefs,
candidateRefs,
resolutionMode: "latest_result",
confidence: 89,
needsClarification: false,
reason: "连续对话默认续接上一轮生成结果,避免误回退到原始选中图",
fromHistory: true,
});
}
if (focusPolicy === "selected" && selectedRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: selectedRefs,
candidateRefs,
resolutionMode: "explicit_selection",
confidence: 97,
needsClarification: false,
reason: "前端已明确选中目标图片",
fromHistory: true,
});
}
if ((SELECTION_REGEX.test(text) || focusPolicy === "selected") && selectedRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: selectedRefs,
@ -290,16 +339,9 @@ export function resolveTargetAssets(
});
}
const workingStateResolvedUrls = normalizeStringArray(
workingState?.lastResolvedTargetImageUrls,
);
const workingStateResolvedUrls = normalizeStringArray(workingState?.lastResolvedTargetImageUrls);
if (workingStateResolvedUrls.length > 0) {
const refs = workingStateResolvedUrls.map((url) => ({
url,
normalizedUrl: url,
source: "working_memory" as const,
role: "working_memory" as const,
}));
const refs = toWorkingMemoryRefs(workingStateResolvedUrls);
return buildResolvedTargetAssets({
targetRefs: refs,
candidateRefs,
@ -311,14 +353,8 @@ export function resolveTargetAssets(
});
}
const workingStateGeneratedUrls = normalizeStringArray(workingState?.lastGeneratedImageUrls);
if (workingStateGeneratedUrls.length > 0) {
const refs = workingStateGeneratedUrls.map((url) => ({
url,
normalizedUrl: url,
source: "working_memory" as const,
role: "working_memory" as const,
}));
const refs = toWorkingMemoryRefs(workingStateGeneratedUrls);
return buildResolvedTargetAssets({
targetRefs: refs,
candidateRefs,
@ -330,9 +366,9 @@ export function resolveTargetAssets(
});
}
if (assistantRefs.length > 0) {
if (generatedRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: assistantRefs,
targetRefs: generatedRefs,
candidateRefs,
resolutionMode: "latest_result",
confidence: 74,
@ -342,9 +378,9 @@ export function resolveTargetAssets(
});
}
if (userRefs.length > 0) {
if (originalRefs.length > 0) {
return buildResolvedTargetAssets({
targetRefs: userRefs,
targetRefs: originalRefs,
candidateRefs,
resolutionMode: "working_memory",
confidence: 68,