接入发布校准仓储接口

This commit is contained in:
Codex
2026-06-24 11:08:23 +08:00
parent f3d26e148a
commit 26b09da273
6 changed files with 608 additions and 0 deletions
+237
View File
@@ -1,5 +1,12 @@
import { nanoid } from "nanoid";
import type {
CalibrationEvent,
PerformanceSnapshot,
PublicationRecord,
RubricVersion,
ScoringRun,
} from "../calibration/types";
import type {
ConfirmedFactCard,
ImageInput,
@@ -102,6 +109,41 @@ interface QaReportRow {
report: string;
}
interface ScoringRunRow {
id: string;
job_id: string;
revision: number;
rubric_version_id: string;
dimension_scores: string;
composite_score: number;
rationale: string;
created_at: string;
}
interface PublicationRecordRow {
id: string;
job_id: string;
revision: number;
platform: PublishPlatform;
url: string;
published_at: string;
status: "draft" | "published" | "archived";
notes: string;
created_at: string;
updated_at: string;
}
interface PerformanceSnapshotRow {
id: string;
publication_id: string;
source: "manual" | `adapter:${string}`;
window_label: string;
metrics: string;
feedback_summary: string;
raw_reference: string | null;
snapshot_at: string;
}
function nowIso() {
return new Date().toISOString();
}
@@ -145,6 +187,21 @@ function toArticleJob(row: ArticleJobRow): ArticleJob {
};
}
function toScoringRun(row: ScoringRunRow): ScoringRun {
return {
...row,
dimension_scores: parseJson<Record<string, number>>(row.dimension_scores),
};
}
function toPerformanceSnapshot(row: PerformanceSnapshotRow): PerformanceSnapshot {
return {
...row,
raw_reference: row.raw_reference ?? undefined,
metrics: parseJson<PerformanceSnapshot["metrics"]>(row.metrics),
};
}
export function createBrandTemplate(
dbPath: string | undefined,
input: NewBrandTemplate,
@@ -380,3 +437,183 @@ export function getLatestQaReport(dbPath: string | undefined, jobId: string) {
return row ? parseJson<QaReport>(row.report) : null;
});
}
export function saveRubricVersion(
dbPath: string | undefined,
rubric: RubricVersion,
) {
return withDb(dbPath, (db) => {
db.prepare(
`insert into rubric_versions (
id, version, name, dimensions, formula, is_active, created_at
) values (?, ?, ?, ?, ?, ?, ?)
on conflict(id) do update set
version = excluded.version,
name = excluded.name,
dimensions = excluded.dimensions,
formula = excluded.formula,
is_active = excluded.is_active`,
).run(
rubric.id,
rubric.version,
rubric.name,
serialize(rubric.dimensions),
rubric.formula,
rubric.is_active ? 1 : 0,
rubric.created_at,
);
return rubric;
});
}
export function saveScoringRun(dbPath: string | undefined, run: ScoringRun) {
return withDb(dbPath, (db) => {
db.prepare(
`insert into scoring_runs (
id, job_id, revision, rubric_version_id, dimension_scores,
composite_score, rationale, created_at
) values (?, ?, ?, ?, ?, ?, ?, ?)`,
).run(
run.id,
run.job_id,
run.revision,
run.rubric_version_id,
serialize(run.dimension_scores),
run.composite_score,
run.rationale,
run.created_at,
);
return run;
});
}
export function getLatestScoringRun(
dbPath: string | undefined,
jobId: string,
revision: number,
) {
return withDb(dbPath, (db) => {
const row = db
.prepare(
`select * from scoring_runs
where job_id = ? and revision = ?
order by created_at desc
limit 1`,
)
.get(jobId, revision) as ScoringRunRow | undefined;
return row ? toScoringRun(row) : null;
});
}
export function createPublicationRecord(
dbPath: string | undefined,
input: Omit<PublicationRecord, "id" | "created_at" | "updated_at">,
) {
return withDb(dbPath, (db) => {
const timestamp = nowIso();
const record: PublicationRecord = {
id: `pub_${nanoid(10)}`,
...input,
created_at: timestamp,
updated_at: timestamp,
};
db.prepare(
`insert into publication_records (
id, job_id, revision, platform, url, published_at, status,
notes, created_at, updated_at
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
).run(
record.id,
record.job_id,
record.revision,
record.platform,
record.url,
record.published_at,
record.status,
record.notes,
record.created_at,
record.updated_at,
);
return record;
});
}
export function listPublicationRecords(dbPath: string | undefined, jobId: string) {
return withDb(dbPath, (db) =>
db
.prepare("select * from publication_records where job_id = ? order by published_at desc")
.all(jobId)
.map((row) => row as PublicationRecordRow),
);
}
export function getPublicationRecord(dbPath: string | undefined, id: string) {
return withDb(dbPath, (db) => {
const row = db
.prepare("select * from publication_records where id = ?")
.get(id) as PublicationRecordRow | undefined;
return row ?? null;
});
}
export function savePerformanceSnapshot(
dbPath: string | undefined,
snapshot: PerformanceSnapshot,
) {
return withDb(dbPath, (db) => {
db.prepare(
`insert into performance_snapshots (
id, publication_id, source, window_label, metrics,
feedback_summary, raw_reference, snapshot_at
) values (?, ?, ?, ?, ?, ?, ?, ?)`,
).run(
snapshot.id,
snapshot.publication_id,
snapshot.source,
snapshot.window_label,
serialize(snapshot.metrics),
snapshot.feedback_summary,
snapshot.raw_reference ?? null,
snapshot.snapshot_at,
);
return snapshot;
});
}
export function listPerformanceSnapshots(
dbPath: string | undefined,
publicationId: string,
) {
return withDb(dbPath, (db) =>
db
.prepare(
"select * from performance_snapshots where publication_id = ? order by snapshot_at desc",
)
.all(publicationId)
.map((row) => toPerformanceSnapshot(row as PerformanceSnapshotRow)),
);
}
export function saveCalibrationEvent(
dbPath: string | undefined,
event: CalibrationEvent,
) {
return withDb(dbPath, (db) => {
db.prepare(
`insert into calibration_events (
id, publication_id, scoring_run_id, performance_snapshot_id,
direction, observations, recommended_action, created_at
) values (?, ?, ?, ?, ?, ?, ?, ?)`,
).run(
event.id,
event.publication_id,
event.scoring_run_id,
event.performance_snapshot_id,
event.direction,
serialize(event.observations),
event.recommended_action,
event.created_at,
);
return event;
});
}