# Ressursforbruk — Måling og synliggjøring ## Konsept Alle ressurskrevende operasjoner logges med naturlige enheter. Forbruket akkumuleres på tre akser: noden som ble behandlet, brukeren som utløste det, og samlingen det skjedde i. Formålet er synliggjøring og innsikt, ikke fakturering. ## Ressurstyper | Ressurstype | Enhet | Hva måles | |---|---|---| | `ai` | tokens inn / tokens ut | LLM-kall via AI Gateway | | `whisper` | sekunder prosessert lyd | Transkripsjons-pipeline | | `tts` | tegn | Tekst-til-tale-generering | | `cas` | bytes | Lagring i CAS (store/delete) | | `bandwidth` | bytes ut | Servering av mediefiler og publisert innhold | | `livekit` | deltaker-minutter | WebRTC-sesjoner (møter, opptak) | | `graph` | noder / edges | Opprettelse av noder og edges i grafen | ## Logg-skjema ```sql CREATE TABLE resource_usage_log ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), target_node_id UUID NOT NULL REFERENCES nodes(id), triggered_by UUID REFERENCES nodes(id), -- null for system-jobber collection_id UUID REFERENCES nodes(id), resource_type TEXT NOT NULL, -- 'ai', 'whisper', 'tts', 'cas', 'bandwidth', 'livekit' detail JSONB NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX idx_resource_usage_target ON resource_usage_log(target_node_id); CREATE INDEX idx_resource_usage_triggered ON resource_usage_log(triggered_by); CREATE INDEX idx_resource_usage_collection ON resource_usage_log(collection_id); CREATE INDEX idx_resource_usage_type_time ON resource_usage_log(resource_type, created_at); ``` ## Detail-struktur per type ### AI (LLM-kall) ```jsonc { "model_level": "fast", // "fast" | "smart" | "deep" "model_id": "gemini-2.0-flash", "tokens_in": 1240, "tokens_out": 380, "job_type": "auto_tag" // hva jobben var } ``` Modellnivåer: | Nivå | Semantikk | Typiske modeller | |---|---|---| | `fast` | Billig, lav latens | Gemini Flash, Haiku | | `smart` | Balansert | Sonnet, Gemini Pro | | `deep` | Grundig, dyr | Opus, GPT-4 | ### Whisper (transkripsjon) ```jsonc { "model": "medium", // "small" | "medium" | "large-v3" "duration_seconds": 2520, // lengde på prosessert lyd "language": "no", "mode": "batch" // "live" | "batch" } ``` ### TTS (tekst-til-tale) ```jsonc { "provider": "elevenlabs", // "elevenlabs" | "local" "characters": 8200, "voice_id": "norwegian_male_1" } ``` ### CAS (lagring) ```jsonc { "hash": "sha256-abc123...", "size_bytes": 84000000, "mime": "audio/mp3", "operation": "store" // "store" | "delete" } ``` ### Bandwidth (servering) ```jsonc { "size_bytes": 84000000, "path": "/media/podcast/ep47.mp3", "client": "Apple Podcasts" // parsert fra User-Agent } ``` ### LiveKit (sanntid) ```jsonc { "room_id": "meeting-abc123", "participant_minutes": 180, "tracks": 4 // antall aktive lyd/video-spor } ``` ### Graph (noder og edges) Trenger ikke logges i `resource_usage_log` — kan telles direkte fra `nodes` og `edges`-tabellene med `COUNT` + `GROUP BY created_by` eller `GROUP BY collection`. Billig spørring, ingen ekstra lagring. Vises i bruker- og samlingsvisning som kontekst: ``` Vegard: 423 noder opprettet 1 204 edges Sidelinja: 2 891 noder 8 340 edges ``` ## Aggregering Tre naturlige visninger, alle er GROUP BY-spørringer mot samme tabell: ### Per node Synlig i node-detaljer for eieren. Gir innsikt i hva en spesifikk node har kostet i ressurser. ``` Episode 47: AI (smart) 12k tokens inn, 3k ut — 4 jobber Whisper 42 min prosessert (medium) TTS 8 200 tegn CAS 84 MB lagret Båndbredde 2.3 GB servert LiveKit 180 deltaker-minutter 12 noder, 34 edges ``` ### Per bruker Synlig for brukeren selv i sin profil/innstillinger. Sum av alle noder brukeren har utløst arbeid på. ``` Vegard denne måneden: AI fast: 42k / smart: 18k / deep: 3k tokens Whisper 3.2 timer prosessert TTS 24k tegn 423 noder opprettet, 1 204 edges ``` ### Per samling Synlig for samlingens eiere/admins. Sum av alt forbruk i samlingen. Nyttig for å forstå hvilke samlinger som bruker mest ressurser. ``` Sidelinja (mars 2026): AI 148k tokens totalt Whisper 12.4 timer prosessert CAS 2.1 GB lagret Båndbredde 48 GB servert 2 891 noder, 8 340 edges ``` ## Triggered-by-regler | Scenario | triggered_by | |---|---| | Bruker klikker "oppsummer" | Brukeren | | Bruker sender melding som trigger auto-tag | Brukeren | | Nattlig samlings-digest | null (system) | | Podcast-nedlasting av ekstern lytter | null (system) | Når `triggered_by` er null, tilhører forbruket kun samlingen — det belaster ingen spesifikk bruker. ## Logging-ansvar Maskinrommet logger all ressursbruk. Hver handler (AI, Whisper, TTS, CAS, LiveKit) skriver til `resource_usage_log` som siste steg etter vellykket operasjon. Feilede jobber logges ikke — ingen ressurs ble forbrukt. Båndbredde-logging skjer via Caddy-logg-parsing i nattlig batch-jobb (samme mønster som `docs/features/podcast_statistikk.md`).