fix: 兼容优化稿LLM可选字段

This commit is contained in:
Codex
2026-06-24 10:10:05 +08:00
parent 9918cd982b
commit 3709c64a17
2 changed files with 57 additions and 5 deletions
@@ -200,4 +200,35 @@ describe("domain validation", () => {
"body: Fixed sentence flow.",
]);
});
it("normalizes near-valid optimized article LLM optional fields", () => {
const parsed = optimizedArticleSchema.parse({
title: { text: "示例科技 GEO 内容优化方案" },
summary: ["围绕事实卡重写官网文章摘要"],
body_markdown: {
markdown: "## 服务能力\n示例科技有限公司提供GEO内容优化服务。",
},
image_suggestions: [
"当前版本不生成图片建议",
{ source: "image_1" },
{ suggestion: "使用产品后台截图" },
{ source: "image_2", suggestion: "保留原文截图说明" },
],
changed_sections: [
{ section: "title", change: "改成中文官网标题" },
],
requires_user_confirmation: [
{ claim: "客户案例", reason: "原文没有给出客户名称" },
],
});
expect(parsed.title).toBe("示例科技 GEO 内容优化方案");
expect(parsed.summary).toBe("围绕事实卡重写官网文章摘要");
expect(parsed.body_markdown).toContain("## 服务能力");
expect(parsed.image_suggestions).toEqual([
{ source: "image_2", suggestion: "保留原文截图说明" },
]);
expect(parsed.changed_sections).toEqual(["title: 改成中文官网标题"]);
expect(parsed.requires_user_confirmation).toEqual(["客户案例"]);
});
});
+26 -5
View File
@@ -232,6 +232,27 @@ export const imageSuggestionSchema = z.object({
suggestion: z.string().trim().min(1),
});
function normalizeImageSuggestions(value: unknown): unknown {
if (!Array.isArray(value)) return [];
return value.flatMap((item) => {
if (!isPlainRecord(item)) return [];
const source = normalizedStringOrNull(
item.source ?? item.image ?? item.name ?? item.title,
);
const suggestion = normalizedStringOrNull(
item.suggestion ?? item.description ?? item.reason ?? item.fix ?? item.text,
);
if (!source || !suggestion) return [];
return [{ source, suggestion }];
});
}
const imageSuggestionsSchema = z.preprocess(
normalizeImageSuggestions,
z.array(imageSuggestionSchema).default([]),
);
function normalizeChangedSection(value: unknown) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return value;
@@ -279,12 +300,12 @@ const changedSectionSchema = z.preprocess(
export const optimizedArticleSchema = z.object({
job_id: z.string().trim().min(1).optional(),
revision: z.number().int().positive().optional(),
title: z.string().trim().min(1),
summary: z.string().trim().min(1),
body_markdown: z.string().trim().min(1),
image_suggestions: z.array(imageSuggestionSchema).default([]),
title: requiredLlmStringSchema,
summary: requiredLlmStringSchema,
body_markdown: requiredLlmStringSchema,
image_suggestions: imageSuggestionsSchema,
changed_sections: z.array(changedSectionSchema).default([]),
requires_user_confirmation: z.array(z.string().trim().min(1)).default([]),
requires_user_confirmation: stringListSchema,
}) satisfies z.ZodType<OptimizedArticle>;
export const qaCheckSchema = z.object({