# Feature: Lydmeldinger & Diktering **Filsti:** `docs/features/lydmeldinger.md` ## 1. Konsept En mobil-first talefeature med tre moduser som dekker spekteret fra kjappe chatmeldinger til langt feltopptak. Grunnprinsippet er det samme: **du snakker inn i telefonen, og systemet gjør noe nyttig med det**. Forskjellen er hva som er output. | Modus | Typisk lengde | Output | Master-format | Lagring | |---|---|---|---|---| | **Voice-to-text** | <30 sek | Rå transkripsjon i meldingsfeltet | Tekst | Ingen (lyden kastes) | | **Lydmelding** | <10 min | Lydfil + transkripsjon for søk | Lyd | `media_file` + node i grafen | | **Diktering** | 1–30 min | AI-ryddet tekst (strukturert notat) | Tekst | Node i grafen | Voice-to-text er en del av chat-featuren (se `docs/features/chat.md`, seksjon 8). Denne specen dekker de to tyngre modusene. ## 2. Lydmelding-modus ### 2.1 Brukerflyt 1. Bruker åpner lydmelding-modus (via FAB-knapp, hurtigtast eller fra en channel). 2. Trykker record. Nettleseren fanger lyd via `MediaRecorder` API (WebM/Opus). 3. Kan valgfritt velge kontekst: et Tema, en Aktør, eller "Usortert". 4. Ved stopp lastes lydfilen opp til SvelteKit (streaming for store filer). 5. Filen lagres som `media_file` i workspace-mappen (`/srv/sidelinja/media/{workspace_slug}/voice/`). 6. En `whisper_transcribe`-jobb opprettes i jobbkøen for å gjøre opptaket søkbart. 7. Transkripsjonen lagres som metadata på noden — lydfilen forblir master. ### 2.2 Datamodell Lydmeldingen er en node i Kunnskapsgrafen (`node_type = 'melding'`, `message_type = 'voice_memo'`): ``` nodes (workspace_id, node_type = 'melding') → messages (channel_id, message_type = 'voice_memo', body = transkripsjon, metadata = { duration, transcription_status }) → message_attachments → media_files (lydfilen) ``` Lydmeldinger kan: - Sendes i en channel (som vedlegg til en melding) - Leve fristående i en personlig "Innboks"-channel - Knyttes til Temaer/Aktører via `graph_edges` (manuelt eller AI-foreslått) ### 2.3 Triagering Redaksjonen trenger en flate for å gå gjennom nye lydmeldinger: - Lytt, tagg med Temaer/Aktører - Marker for bruk i episode (kobles til Kanban/Kjøreplan) - Forkast / arkiver - Denne flaten er en filtrert visning av "Innboks"-channelen, ikke et eget system ### 2.4 Bruk i podcast Lydmeldinger markert for bruk kan trekkes inn i Podcastfabrikkens pipeline. Lydfilen er allerede i media-mappen — den kan klippes inn i en episode direkte. ## 3. Dikteringsmodus ### 3.1 Brukerflyt 1. Bruker åpner dikteringsmodus (mobil-first, men fungerer på desktop). 2. Snakker fritt — kan være flere minutter. Visuell indikator viser at opptak pågår. 3. Ved stopp opprettes to jobber i jobbkøen (sekvensielt): - `whisper_transcribe` — rå transkripsjon (`medium` + `initial_prompt` for kvalitet) - `dictation_cleanup` — AI rydder i teksten 4. Brukeren ser resultatet: rå transkripsjon og AI-ryddet versjon side om side. 5. Kan redigere den ryddede versjonen før lagring. 6. Lagres som et notat (node i grafen). Lydfilen slettes etter vellykket transkripsjon. ### 3.2 AI-opprydding (`dictation_cleanup`) AI Gateway (`sidelinja/rutine`) prosesserer transkripsjonen med instruksjon om å: - Fjerne fyllord, gjentakelser og ufullstendige setninger - Strukturere i avsnitt med overskrifter der det gir mening - Bevare talerens mening og tone — ikke omskrive til "AI-språk" - Foreslå `#Tema`- og `@Aktør`-tags basert på innholdet ### 3.3 Datamodell Dikterte notater er meldinger i en channel: ``` nodes (workspace_id, node_type = 'melding') → messages (channel_id, message_type = 'text', body = ryddet tekst, metadata = { raw_transcript, source: 'dictation' }) ``` Metadata bevarer rå-transkripsjonen slik at brukeren alltid kan se hva som faktisk ble sagt. ### 3.4 Målkanal Brukeren velger hvor notatet havner: - **Personlig notat-channel** — default, kun synlig for brukeren selv - **Tema-channel** — delt med redaksjonen som et innspill - **Direkte til en annen bruker** — som en asynkron "talemelding i tekstform" ## 4. Felles infrastruktur ### 4.1 Opptak (klient) Begge moduser bruker samme opptakskomponent i SvelteKit: - `MediaRecorder` API med WebM/Opus - Visuell feedback (lydnivå-indikator, varighet) - Modus-velger: Lydmelding / Diktering - Kontekst-velger: Tema, Aktør, eller Usortert ### 4.2 Opplasting SvelteKit håndterer filopplasting strømmende. For korte klipp (<2 min) kan opplasting starte umiddelbart etter stopp. For lengre opptak bør det vises en fremdriftsindikator. ### 4.3 Whisper Begge moduser bruker live transkripsjonspipelinen (se `docs/features/live_transkripsjon.md`) i batch-modus via jobbkøen. Modellvalg: - Lydmelding: `small` (rask, transkripsjonen er sekundær — lyden er master) - Diktering: `medium` + `initial_prompt` (kvalitet prioritert — teksten er master) ### 4.4 Personlig "Innboks"-channel Ved workspace-opprettelse opprettes en privat channel per bruker for usorterte lydmeldinger og notater. Config: ```json { "threads": false, "mentions": false, "attachments": true, "research_clips": false, "ttl_days": null } ``` ## 5. Dataklassifisering (ref. ARCHITECTURE.md 2.2) | Data | Kategori | Detaljer | |---|---|---| | Lydfiler (voice memos) | Kritisk (backup) | Unikt råmateriale — lyden *er* innholdet, kan brukes direkte i podcasten | | Diktert tekst (ryddet) | Kritisk (PG) | Brukerens innhold | | Rå transkripsjon | Avledet | Kan regenereres fra lydfil | | Lydfil fra diktering | Flyktig (TTL) | Lyden er kun et *transportformat* for teksten — slettes etter at brukeren har godkjent den ryddede teksten. Spart diskplass, og unngår å lagre halvformulerte tanker som lyd. | ## 6. Jobbtyper | Jobbtype | Modellalias | Beskrivelse | |---|---|---| | `whisper_transcribe` | — | Eksisterende jobbtype, gjenbrukes | | `dictation_cleanup` | `sidelinja/rutine` | AI-opprydding av transkripsjon | ## 7. Instruks for Claude Code * Opptakskomponenten skal være en gjenbrukbar Svelte-komponent med modus-prop (`voice_memo` / `dictation`). * Lydfiler lagres i `media/{workspace_slug}/voice/` — aldri i databasen. * Diktering: slett lydfilen først *etter* at brukeren har godkjent den ryddede teksten. * `voice_memo` er en ny `message_type` — utvid enum i migrasjonen. * Personlig innboks-channel opprettes automatisk ved workspace-medlemskap (som del av `workspace_members`-inserten). * Alt er workspace-scopet.