接入发布校准仓储接口
This commit is contained in:
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user