fix: gate detail references by selected brand
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-04-27 23:19:18 +08:00
parent 83c274e8d4
commit 8b9d9d42e0

View File

@ -366,10 +366,12 @@ function isBrandNameMatched(
const normalizedBrandName = normalizeComparableName(candidateBrandName);
if (!normalizedBrandName) return false;
if (normalizedBrandName === normalizedRequestedBrand) return true;
// 只允许“候选品牌包含当前品牌”的弱匹配,避免短品牌名反向包含导致串品牌。
return (
normalizedBrandName === normalizedRequestedBrand ||
normalizedBrandName.includes(normalizedRequestedBrand) ||
normalizedRequestedBrand.includes(normalizedBrandName)
normalizedRequestedBrand.length >= 2 &&
normalizedBrandName.includes(normalizedRequestedBrand)
);
}
@ -452,11 +454,6 @@ export async function GET(request: NextRequest) {
resourceType: "task-detail",
[queryType]: normalizedKeyword,
});
if (requestedBrandName) {
upstreamParams.set("brandName", requestedBrandName);
upstreamParams.set("brand", requestedBrandName);
upstreamParams.set("productBrand", requestedBrandName);
}
const upstreamUrl = `${normalizeBaseUrl(
config.baseUrl
)}/standard-model-white-background?${upstreamParams.toString()}`;
@ -475,6 +472,27 @@ export async function GET(request: NextRequest) {
const errorMessage =
String(upstreamResult.error?.message || "").trim() ||
`参考图搜索失败(${upstreamResponse.status})`;
if (
requestedBrandName &&
(errorCode === "TASK_DETAIL_NOT_FOUND" || errorCode === "FULL_SET_NOT_FOUND")
) {
return jsonNoStore(
{
success: false,
error: {
code: "BRAND_REFERENCE_NOT_FOUND",
message: `当前品牌「${requestedBrandName}」下没有可用的${
parsed.target === "main"
? "主图参考图"
: parsed.target === "detail"
? "详情参考图"
: "SKU参考图"
}`,
},
},
{ status: 404 }
);
}
return jsonNoStore(
{
success: false,
@ -488,14 +506,44 @@ export async function GET(request: NextRequest) {
}
const upstreamBrandName = getExternalBrandName(upstreamResult.data);
const fallbackBrandName =
upstreamBrandName ||
(verifiedGoodsBrandName &&
isBrandNameMatched(verifiedGoodsBrandName, requestedBrandName)
? verifiedGoodsBrandName
: null);
const rawCandidates = upstreamResult.data.candidates || [];
const candidateBrandSamples = Array.from(
new Set(
rawCandidates
.map((candidate) => getExternalBrandName(candidate))
.filter((brandName): brandName is string => Boolean(brandName))
)
).slice(0, 8);
if (requestedBrandName) {
console.info("[Agent Workflow Reference Search] Brand gate:", {
keyword: normalizedKeyword,
queryType,
target: parsed.target,
requestedBrandName,
verifiedGoodsBrandName,
upstreamBrandName,
candidateCount: rawCandidates.length,
candidateBrandSamples,
});
}
const hasVerifiedRequestedBrand =
Boolean(verifiedGoodsBrandName) &&
isBrandNameMatched(verifiedGoodsBrandName, requestedBrandName);
const hasUpstreamRequestedBrand =
Boolean(upstreamBrandName) &&
isBrandNameMatched(upstreamBrandName, requestedBrandName);
let fallbackBrandName: string | null = null;
if (requestedBrandName) {
if (hasVerifiedRequestedBrand) {
fallbackBrandName = verifiedGoodsBrandName || null;
} else if (hasUpstreamRequestedBrand) {
fallbackBrandName = upstreamBrandName || null;
}
} else {
fallbackBrandName = upstreamBrandName;
}
const sortedCandidates = sortCandidatesByUploadedAtDesc(
(upstreamResult.data.candidates || []).map((item, index) =>
rawCandidates.map((item, index) =>
normalizeCandidate(item, index, fallbackBrandName)
)
);
@ -550,7 +598,6 @@ export async function GET(request: NextRequest) {
brandName:
selectedCandidate.brandName ||
fallbackBrandName ||
requestedBrandName ||
null,
categoryName: selectedCandidate.categoryName || String(upstreamResult.data.categoryName || "").trim() || null,
shopName: selectedCandidate.shopName || String(upstreamResult.data.shopName || "").trim() || null,