feat: use llm for targeted rewrite
This commit is contained in:
@@ -16,6 +16,7 @@ vi.mock("../../llm/client", async () => {
|
||||
|
||||
import { extractCandidateFactCard } from "../fact-extractor";
|
||||
import { optimizeArticle } from "../article-optimizer";
|
||||
import { rewriteFailedSections } from "../targeted-rewriter";
|
||||
|
||||
describe("LLM workflow integration", () => {
|
||||
const confirmedFactCard = {
|
||||
@@ -127,4 +128,70 @@ describe("LLM workflow integration", () => {
|
||||
"Unsupported requested claim: 99 patents",
|
||||
);
|
||||
});
|
||||
|
||||
it("uses LLM output for targeted rewrite when valid", async () => {
|
||||
llmMocks.generateValidatedJson.mockResolvedValueOnce({
|
||||
title: "Rewritten By LLM",
|
||||
summary: "Original summary",
|
||||
body_markdown:
|
||||
"## Body\nExample Technology Co., Ltd. focuses on GEO optimization.",
|
||||
image_suggestions: [],
|
||||
changed_sections: ["title"],
|
||||
requires_user_confirmation: [],
|
||||
});
|
||||
|
||||
const rewritten = await rewriteFailedSections({
|
||||
article: {
|
||||
title: "Bad title!!!",
|
||||
summary: "Original summary",
|
||||
body_markdown: "## Body\nOriginal body",
|
||||
image_suggestions: [],
|
||||
changed_sections: [],
|
||||
requires_user_confirmation: [],
|
||||
},
|
||||
factCard: confirmedFactCard,
|
||||
failedChecks: [
|
||||
{
|
||||
rule_id: "title_quality",
|
||||
status: "fail",
|
||||
evidence: "Bad title!!!",
|
||||
reason: "Title has punctuation stuffing.",
|
||||
suggested_fix: "Rewrite title.",
|
||||
target_agent: "title",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(rewritten.title).toBe("Rewritten By LLM");
|
||||
expect(llmMocks.generateValidatedJson).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("falls back to deterministic targeted rewrite when LLM returns null", async () => {
|
||||
llmMocks.generateValidatedJson.mockResolvedValueOnce(null);
|
||||
|
||||
const rewritten = await rewriteFailedSections({
|
||||
article: {
|
||||
title: "Bad title!!!",
|
||||
summary: "Original summary",
|
||||
body_markdown: "## Body\nOriginal body",
|
||||
image_suggestions: [],
|
||||
changed_sections: [],
|
||||
requires_user_confirmation: [],
|
||||
},
|
||||
factCard: confirmedFactCard,
|
||||
failedChecks: [
|
||||
{
|
||||
rule_id: "title_quality",
|
||||
status: "fail",
|
||||
evidence: "Bad title!!!",
|
||||
reason: "Title has punctuation stuffing.",
|
||||
suggested_fix: "Rewrite title.",
|
||||
target_agent: "title",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(rewritten.title).toContain("GEO optimization Guide");
|
||||
expect(rewritten.summary).toBe("Original summary");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -183,7 +183,7 @@ describe("workflow nodes", () => {
|
||||
expect(report.overall_status).toBe("fail");
|
||||
});
|
||||
|
||||
it("rewrites only the failing target area", () => {
|
||||
it("rewrites only the failing target area", async () => {
|
||||
const article = {
|
||||
title: "Bad title!!!",
|
||||
summary: "Original summary",
|
||||
@@ -193,7 +193,7 @@ describe("workflow nodes", () => {
|
||||
requires_user_confirmation: [],
|
||||
};
|
||||
|
||||
const rewritten = rewriteFailedSections({
|
||||
const rewritten = await rewriteFailedSections({
|
||||
article,
|
||||
factCard: confirmedFactCard,
|
||||
failedChecks: [
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function runOptimizationWorkflow({
|
||||
|
||||
while (qaReport.overall_status === "fail" && rewriteRounds < 2) {
|
||||
const failedChecks = qaReport.checks.filter((check) => check.status === "fail");
|
||||
article = rewriteFailedSections({ article, factCard, failedChecks });
|
||||
article = await rewriteFailedSections({ article, factCard, failedChecks });
|
||||
rewriteRounds += 1;
|
||||
qaReport = inspectQuality({
|
||||
article,
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import type { ConfirmedFactCard, OptimizedArticle, QaCheck } from "../domain/types";
|
||||
import { optimizedArticleSchema } from "../domain/validation";
|
||||
import { generateValidatedJson } from "../llm/client";
|
||||
import {
|
||||
TARGETED_REWRITER_SYSTEM_PROMPT,
|
||||
buildTargetedRewritePrompt,
|
||||
} from "../llm/prompts";
|
||||
|
||||
export interface RewriteFailedSectionsInput {
|
||||
article: OptimizedArticle;
|
||||
@@ -6,7 +12,22 @@ export interface RewriteFailedSectionsInput {
|
||||
failedChecks: QaCheck[];
|
||||
}
|
||||
|
||||
export function rewriteFailedSections({
|
||||
export async function rewriteFailedSections({
|
||||
article,
|
||||
factCard,
|
||||
failedChecks,
|
||||
}: RewriteFailedSectionsInput): Promise<OptimizedArticle> {
|
||||
const llmArticle = await generateValidatedJson({
|
||||
schema: optimizedArticleSchema,
|
||||
system: TARGETED_REWRITER_SYSTEM_PROMPT,
|
||||
prompt: buildTargetedRewritePrompt({ article, factCard, failedChecks }),
|
||||
temperature: 0.15,
|
||||
});
|
||||
|
||||
return llmArticle ?? rewriteFailedSectionsFallback({ article, factCard, failedChecks });
|
||||
}
|
||||
|
||||
function rewriteFailedSectionsFallback({
|
||||
article,
|
||||
factCard,
|
||||
failedChecks,
|
||||
|
||||
Reference in New Issue
Block a user