From 7eb52d97b11c9aeab5aca228411506845710ab71 Mon Sep 17 00:00:00 2001 From: Jake Date: Sat, 25 Apr 2026 00:12:20 +0100 Subject: [PATCH] feat(phase9): frontend types + persistence wiring for llmTags TranscriptEntry gains llmTags: string[]; TranscriptRow gains the storage-shape llmTags: string. ContentTags type added. mapTranscriptRow hydrates llmTags from the comma-joined column. saveTranscriptMeta forwards llmTags through to update_transcript_meta_cmd, mirroring the existing manualTags handling. buildFrontmatter unions auto + manual + llm tags so exported markdown surfaces every source in one tags: list. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/stores/page.svelte.ts | 9 +++++++++ src/lib/types/app.ts | 12 ++++++++++++ src/lib/utils/frontmatter.ts | 7 ++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/lib/stores/page.svelte.ts b/src/lib/stores/page.svelte.ts index eed0e31..08bb3d0 100644 --- a/src/lib/stores/page.svelte.ts +++ b/src/lib/stores/page.svelte.ts @@ -144,6 +144,8 @@ function mapTranscriptRow(row: TranscriptDto): TranscriptEntry { const text = row.text ?? ""; const rawTags = row.manualTags ?? ""; const manualTags = rawTags ? rawTags.split(",").filter(Boolean) : []; + const rawLlmTags = row.llmTags ?? ""; + const llmTags = rawLlmTags ? rawLlmTags.split(",").filter(Boolean) : []; const rawSegments = row.segmentsJson ?? ""; let segments: Segment[] = []; if (rawSegments) { @@ -173,6 +175,7 @@ function mapTranscriptRow(row: TranscriptDto): TranscriptEntry { template: row.template ?? "", language: row.language ?? "", segments, + llmTags, }; } @@ -196,6 +199,7 @@ function normaliseTranscriptEntry(entry: TranscriptWriteEntry): TranscriptEntry template: entry.template ?? "", language: entry.language ?? "", segments: Array.isArray(entry.segments) ? entry.segments : [], + llmTags: Array.isArray(entry.llmTags) ? entry.llmTags : [], }; } @@ -292,6 +296,11 @@ export async function saveTranscriptMeta(id: string, patch: TranscriptMetaPatch) template: patch.template, language: patch.language, segmentsJson: patch.segments === undefined ? undefined : JSON.stringify(patch.segments), + llmTags: patch.llmTags == null + ? undefined + : (Array.isArray(patch.llmTags) + ? patch.llmTags.join(",") + : String(patch.llmTags)), }; const row = await invoke("update_transcript_meta_cmd", { id: String(id), diff --git a/src/lib/types/app.ts b/src/lib/types/app.ts index 655a1be..8fb2720 100644 --- a/src/lib/types/app.ts +++ b/src/lib/types/app.ts @@ -180,6 +180,8 @@ export interface TranscriptDto { template: string; language: string; segmentsJson: string; + /** Phase 9. Comma-joined LLM-generated tags ("topic:foo", "intent:..."). */ + llmTags: string; } export interface TranscriptEntry { @@ -200,6 +202,13 @@ export interface TranscriptEntry { template: string; language: string; segments: Segment[]; + /** Phase 9. AI-generated content tags ("topic:foo", "intent:..."). */ + llmTags: string[]; +} + +export interface ContentTags { + topic: string; + intent: string; } export interface TranscriptWriteEntry extends Partial { @@ -220,6 +229,9 @@ export interface TranscriptMetaPatch { template?: string; language?: string; segments?: Segment[]; + /** Phase 9. Pass an array to set, an empty array to clear, or omit + * the field to leave llm_tags unchanged. */ + llmTags?: string[] | string; } /** diff --git a/src/lib/utils/frontmatter.ts b/src/lib/utils/frontmatter.ts index d094c9b..f8e62ab 100644 --- a/src/lib/utils/frontmatter.ts +++ b/src/lib/utils/frontmatter.ts @@ -90,7 +90,12 @@ export function buildFrontmatter(item: TranscriptEntry | null) { if (!item) return {}; const auto = deriveAutoTags(item); const manual = Array.isArray(item.manualTags) ? item.manualTags : []; - const tags = Array.from(new Set([...auto, ...manual.map(normaliseTag)])).filter(Boolean); + const llm = Array.isArray(item.llmTags) ? item.llmTags : []; + const tags = Array.from(new Set([ + ...auto, + ...manual.map(normaliseTag), + ...llm.map(normaliseTag), + ])).filter(Boolean); const wordCount = item.text ? item.text.trim().split(/\s+/).filter(Boolean).length : 0; return { id: item.id,