接入文章优化案例自动保存
This commit is contained in:
@@ -4,7 +4,7 @@ import type {
|
||||
OptimizedArticle,
|
||||
} from "../domain/types";
|
||||
import { optimizedArticleSchema } from "../domain/validation";
|
||||
import { generateValidatedJson } from "../llm/client";
|
||||
import { generateValidatedJson, type GenerateInput } from "../llm/client";
|
||||
import {
|
||||
ARTICLE_OPTIMIZER_SYSTEM_PROMPT,
|
||||
buildArticleOptimizerPrompt,
|
||||
@@ -13,11 +13,13 @@ import {
|
||||
export interface OptimizeArticleInput {
|
||||
input: ArticleInput;
|
||||
factCard: OptimizationFactCard;
|
||||
onAuditSummary?: GenerateInput["onAuditSummary"];
|
||||
}
|
||||
|
||||
export async function optimizeArticle({
|
||||
input,
|
||||
factCard,
|
||||
onAuditSummary,
|
||||
}: OptimizeArticleInput): Promise<OptimizedArticle> {
|
||||
const llmArticle = await generateValidatedJson({
|
||||
schema: optimizedArticleSchema,
|
||||
@@ -25,6 +27,7 @@ export async function optimizeArticle({
|
||||
prompt: buildArticleOptimizerPrompt(input, factCard),
|
||||
temperature: 0.2,
|
||||
task: "article_optimizer",
|
||||
onAuditSummary,
|
||||
});
|
||||
|
||||
return optimizedArticleSchema.parse({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ArticleInput, CandidateFactCard } from "../domain/types";
|
||||
import { candidateFactCardSchema } from "../domain/validation";
|
||||
import { generateValidatedJson } from "../llm/client";
|
||||
import { generateValidatedJson, type GenerateInput } from "../llm/client";
|
||||
import {
|
||||
FACT_EXTRACTOR_SYSTEM_PROMPT,
|
||||
buildFactExtractorPrompt,
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
|
||||
export async function extractCandidateFactCard(
|
||||
input: ArticleInput,
|
||||
options: { onAuditSummary?: GenerateInput["onAuditSummary"] } = {},
|
||||
): Promise<CandidateFactCard> {
|
||||
return generateValidatedJson({
|
||||
schema: candidateFactCardSchema,
|
||||
@@ -15,5 +16,6 @@ export async function extractCandidateFactCard(
|
||||
prompt: buildFactExtractorPrompt(input),
|
||||
temperature: 0.1,
|
||||
task: "fact_extractor",
|
||||
onAuditSummary: options.onAuditSummary,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { ArticleInput, OptimizationFactCard } from "../domain/types";
|
||||
import type { GenerateInput } from "../llm/client";
|
||||
|
||||
import { optimizeArticle } from "./article-optimizer";
|
||||
import { inspectQualityWithLlm } from "./quality-inspector";
|
||||
@@ -8,6 +9,7 @@ export interface RunOptimizationWorkflowInput {
|
||||
input: ArticleInput;
|
||||
factCard: OptimizationFactCard;
|
||||
onProgress?: (event: WorkflowProgressEvent) => void | Promise<void>;
|
||||
onAuditSummary?: GenerateInput["onAuditSummary"];
|
||||
}
|
||||
|
||||
export interface WorkflowTimingStep {
|
||||
@@ -68,13 +70,14 @@ export async function runOptimizationWorkflow({
|
||||
input,
|
||||
factCard,
|
||||
onProgress,
|
||||
onAuditSummary,
|
||||
}: RunOptimizationWorkflowInput) {
|
||||
const startedAt = Date.now();
|
||||
const timingSteps: WorkflowTimingStep[] = [];
|
||||
let article = await timedStep(
|
||||
"生成优化稿",
|
||||
timingSteps,
|
||||
() => optimizeArticle({ input, factCard }),
|
||||
() => optimizeArticle({ input, factCard, onAuditSummary }),
|
||||
onProgress,
|
||||
);
|
||||
let qaReport = await timedStep(
|
||||
@@ -86,6 +89,7 @@ export async function runOptimizationWorkflow({
|
||||
factCard,
|
||||
platform: input.platform,
|
||||
sourceImages: input.images,
|
||||
onAuditSummary,
|
||||
}),
|
||||
onProgress,
|
||||
);
|
||||
@@ -97,7 +101,7 @@ export async function runOptimizationWorkflow({
|
||||
article = await timedStep(
|
||||
`定向修复第 ${nextRound} 轮`,
|
||||
timingSteps,
|
||||
() => rewriteFailedSections({ article, factCard, failedChecks }),
|
||||
() => rewriteFailedSections({ article, factCard, failedChecks, onAuditSummary }),
|
||||
onProgress,
|
||||
);
|
||||
rewriteRounds = nextRound;
|
||||
@@ -110,6 +114,7 @@ export async function runOptimizationWorkflow({
|
||||
factCard,
|
||||
platform: input.platform,
|
||||
sourceImages: input.images,
|
||||
onAuditSummary,
|
||||
}),
|
||||
onProgress,
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ import type {
|
||||
QualityRuleId,
|
||||
} from "../domain/types";
|
||||
import { qaCheckSchema, qaReportSchema } from "../domain/validation";
|
||||
import { generateValidatedJson } from "../llm/client";
|
||||
import { generateValidatedJson, type GenerateInput } from "../llm/client";
|
||||
import {
|
||||
QUALITY_INSPECTOR_SYSTEM_PROMPT,
|
||||
buildQualityInspectorPrompt,
|
||||
@@ -43,6 +43,7 @@ export interface InspectQualityInput {
|
||||
factCard: OptimizationFactCard;
|
||||
platform: PublishPlatform;
|
||||
sourceImages: ImageInput[];
|
||||
onAuditSummary?: GenerateInput["onAuditSummary"];
|
||||
}
|
||||
|
||||
export function inspectQuality(input: InspectQualityInput): QaReport {
|
||||
@@ -71,6 +72,7 @@ export async function inspectQualityWithLlm(
|
||||
}),
|
||||
temperature: 0.1,
|
||||
task: "quality_inspector",
|
||||
onAuditSummary: input.onAuditSummary,
|
||||
});
|
||||
|
||||
const patchedChecks = deterministicReport.checks.map((deterministicCheck) => {
|
||||
|
||||
@@ -14,7 +14,11 @@ export type OptimizationStreamStage =
|
||||
| "final";
|
||||
|
||||
export type OptimizationStreamEvent =
|
||||
| { type: "job_created"; job: { id: string } }
|
||||
| {
|
||||
type: "job_created";
|
||||
job: { id: string };
|
||||
case?: { id: string; case_type: "article" };
|
||||
}
|
||||
| {
|
||||
type: "fact_card_ready";
|
||||
job_id: string;
|
||||
@@ -34,6 +38,8 @@ export type OptimizationStreamEvent =
|
||||
| {
|
||||
type: "final_ready";
|
||||
job_id: string;
|
||||
case?: { id: string; case_type: "article" };
|
||||
result_version?: { id: string; version: number };
|
||||
optimized_article: OptimizedArticle;
|
||||
qa_report: QaReport;
|
||||
export_paths: Record<string, string>;
|
||||
@@ -41,6 +47,8 @@ export type OptimizationStreamEvent =
|
||||
| {
|
||||
type: "failed";
|
||||
job_id?: string;
|
||||
case?: { id: string; case_type: "article" };
|
||||
result_version?: { id: string; version: number };
|
||||
stage: OptimizationStreamStage;
|
||||
error: string;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import type { ArticleInput, OptimizationFactCard } from "../domain/types";
|
||||
import type { ProcessSummaryStep } from "../cases/types";
|
||||
import { createProcessStep } from "../cases/summaries";
|
||||
import type { GenerateInput } from "../llm/client";
|
||||
|
||||
import { optimizeArticle } from "./article-optimizer";
|
||||
import { inspectQualityWithLlm } from "./quality-inspector";
|
||||
@@ -10,6 +13,7 @@ export interface RunStreamingOptimizationWorkflowInput {
|
||||
input: ArticleInput;
|
||||
factCard: OptimizationFactCard;
|
||||
onEvent: (event: OptimizationStreamEvent) => void | Promise<void>;
|
||||
onAuditSummary?: GenerateInput["onAuditSummary"];
|
||||
}
|
||||
|
||||
export async function runStreamingOptimizationWorkflow({
|
||||
@@ -17,13 +21,26 @@ export async function runStreamingOptimizationWorkflow({
|
||||
input,
|
||||
factCard,
|
||||
onEvent,
|
||||
onAuditSummary,
|
||||
}: RunStreamingOptimizationWorkflowInput) {
|
||||
const processSummary: ProcessSummaryStep[] = [];
|
||||
|
||||
await onEvent({
|
||||
type: "draft_started",
|
||||
job_id: jobId,
|
||||
message: "正在生成优化草稿",
|
||||
});
|
||||
let article = await optimizeArticle({ input, factCard });
|
||||
let stageStartedAt = Date.now();
|
||||
let article = await optimizeArticle({ input, factCard, onAuditSummary });
|
||||
processSummary.push(
|
||||
createProcessStep({
|
||||
stage: "draft",
|
||||
startedAt: stageStartedAt,
|
||||
endedAt: Date.now(),
|
||||
status: "success",
|
||||
producedResultVersion: false,
|
||||
}),
|
||||
);
|
||||
await onEvent({ type: "draft_ready", job_id: jobId, article });
|
||||
|
||||
await onEvent({
|
||||
@@ -31,12 +48,23 @@ export async function runStreamingOptimizationWorkflow({
|
||||
job_id: jobId,
|
||||
message: "正在检查质量",
|
||||
});
|
||||
stageStartedAt = Date.now();
|
||||
let qaReport = await inspectQualityWithLlm({
|
||||
article,
|
||||
factCard,
|
||||
platform: input.platform,
|
||||
sourceImages: input.images,
|
||||
onAuditSummary,
|
||||
});
|
||||
processSummary.push(
|
||||
createProcessStep({
|
||||
stage: "qa",
|
||||
startedAt: stageStartedAt,
|
||||
endedAt: Date.now(),
|
||||
status: "success",
|
||||
producedResultVersion: false,
|
||||
}),
|
||||
);
|
||||
await onEvent({ type: "qa_ready", job_id: jobId, qa_report: qaReport });
|
||||
|
||||
let rewriteRounds = 0;
|
||||
@@ -48,8 +76,24 @@ export async function runStreamingOptimizationWorkflow({
|
||||
job_id: jobId,
|
||||
round: nextRound,
|
||||
});
|
||||
article = await rewriteFailedSections({ article, factCard, failedChecks });
|
||||
stageStartedAt = Date.now();
|
||||
article = await rewriteFailedSections({
|
||||
article,
|
||||
factCard,
|
||||
failedChecks,
|
||||
onAuditSummary,
|
||||
});
|
||||
rewriteRounds = nextRound;
|
||||
processSummary.push(
|
||||
createProcessStep({
|
||||
stage: "rewrite",
|
||||
startedAt: stageStartedAt,
|
||||
endedAt: Date.now(),
|
||||
status: "success",
|
||||
rewriteRound: nextRound,
|
||||
producedResultVersion: false,
|
||||
}),
|
||||
);
|
||||
await onEvent({
|
||||
type: "rewrite_ready",
|
||||
job_id: jobId,
|
||||
@@ -62,12 +106,24 @@ export async function runStreamingOptimizationWorkflow({
|
||||
job_id: jobId,
|
||||
message: `正在复检第 ${nextRound} 轮修复`,
|
||||
});
|
||||
stageStartedAt = Date.now();
|
||||
qaReport = await inspectQualityWithLlm({
|
||||
article,
|
||||
factCard,
|
||||
platform: input.platform,
|
||||
sourceImages: input.images,
|
||||
onAuditSummary,
|
||||
});
|
||||
processSummary.push(
|
||||
createProcessStep({
|
||||
stage: "qa",
|
||||
startedAt: stageStartedAt,
|
||||
endedAt: Date.now(),
|
||||
status: "success",
|
||||
rewriteRound: nextRound,
|
||||
producedResultVersion: false,
|
||||
}),
|
||||
);
|
||||
await onEvent({ type: "qa_ready", job_id: jobId, qa_report: qaReport });
|
||||
}
|
||||
|
||||
@@ -77,5 +133,6 @@ export async function runStreamingOptimizationWorkflow({
|
||||
rewriteRounds,
|
||||
stoppedAfterMaxRewrites:
|
||||
qaReport.overall_status === "fail" && rewriteRounds >= 2,
|
||||
processSummary,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OptimizationFactCard, OptimizedArticle, QaCheck } from "../domain/types";
|
||||
import { optimizedArticleSchema } from "../domain/validation";
|
||||
import { generateValidatedJson } from "../llm/client";
|
||||
import { generateValidatedJson, type GenerateInput } from "../llm/client";
|
||||
import {
|
||||
TARGETED_REWRITER_SYSTEM_PROMPT,
|
||||
buildTargetedRewritePrompt,
|
||||
@@ -10,12 +10,14 @@ export interface RewriteFailedSectionsInput {
|
||||
article: OptimizedArticle;
|
||||
factCard: OptimizationFactCard;
|
||||
failedChecks: QaCheck[];
|
||||
onAuditSummary?: GenerateInput["onAuditSummary"];
|
||||
}
|
||||
|
||||
export async function rewriteFailedSections({
|
||||
article,
|
||||
factCard,
|
||||
failedChecks,
|
||||
onAuditSummary,
|
||||
}: RewriteFailedSectionsInput): Promise<OptimizedArticle> {
|
||||
const llmArticle = await generateValidatedJson({
|
||||
schema: optimizedArticleSchema,
|
||||
@@ -23,6 +25,7 @@ export async function rewriteFailedSections({
|
||||
prompt: buildTargetedRewritePrompt({ article, factCard, failedChecks }),
|
||||
temperature: 0.15,
|
||||
task: "targeted_rewriter",
|
||||
onAuditSummary,
|
||||
});
|
||||
|
||||
return optimizedArticleSchema.parse({
|
||||
|
||||
Reference in New Issue
Block a user