Aggregert ressursforbruk-dashboard som spør mot resource_usage_log (oppgave 15.7). Tre visninger: totaler per ressurstype, per samling, og daglig tidsserie. AI drill-down viser forbruk per jobbtype og modellnivå (fast/smart/deep). Backend: GET /admin/usage med days- og collection_id-filtre. Frontend: /admin/usage med filterbare tabeller og fargekodede kort. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.9 KiB
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
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)
{
"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)
{
"model": "medium", // "small" | "medium" | "large-v3"
"duration_seconds": 2520, // lengde på prosessert lyd
"language": "no",
"mode": "batch" // "live" | "batch"
}
TTS (tekst-til-tale)
{
"provider": "elevenlabs", // "elevenlabs" | "local"
"characters": 8200,
"voice_id": "norwegian_male_1"
}
CAS (lagring)
{
"hash": "sha256-abc123...",
"size_bytes": 84000000,
"mime": "audio/mp3",
"operation": "store" // "store" | "delete"
}
Bandwidth (servering)
{
"size_bytes": 84000000,
"path": "/media/podcast/ep47.mp3",
"client": "Apple Podcasts" // parsert fra User-Agent
}
LiveKit (sanntid)
{
"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).
Implementeringsstatus
Følgende ressurstyper logges til resource_usage_log:
| Ressurstype | Handler | Status |
|---|---|---|
ai |
summarize.rs, ai_edges.rs, agent.rs |
Implementert. Token-telling fra LiteLLM usage-feltet. Agent bruker claude CLI og logger 0 tokens (CLI gir ikke token-info). |
whisper |
transcribe.rs |
Implementert. Logger duration_seconds, model, language, mode. |
tts |
tts.rs |
Implementert. Logger provider, characters, voice_id. |
cas |
intentions.rs (upload_media) |
Implementert. Logger kun nye filer (ikke dedup). hash, size_bytes, mime, operation. |
livekit |
intentions.rs (join_communication) |
Implementert. Logger join-hendelser. Faktisk participant_minutes krever LiveKit webhook-integrasjon (fremtidig). |
bandwidth |
bandwidth.rs |
Implementert. Nattlig jobb (kl 03:00) parser Caddy JSON-access-logger. |
Sentralisert hjelpemodul
resource_usage.rs tilbyr log() og find_collection_for_node().
Alle handlers bruker denne for konsistent logging.
Admin-dashboard (oppgave 15.8)
/admin/usage viser aggregert forbruksoversikt:
- Totalkort per ressurstype med naturlige enheter (tokens, timer, GB, tegn, minutter)
- Per samling-tabell: filtrerbar på ressurstype og tidsperiode (7/30/90/365 dager)
- AI drill-down: per jobbtype og modellnivå (fast/smart/deep), tokens inn/ut
- Daglig tidsserie: aktivitet per dag og ressurstype
- Samlings- og ressurstype-filtre med live-oppdatering
Backend: maskinrommet/src/usage_overview.rs → GET /admin/usage?days=30&collection_id=<uuid>
Frontend: frontend/src/routes/admin/usage/+page.svelte
Caddy-oppsett
JSON access logging er konfigurert i Caddyfile for sidelinja.org
og synops.no. Logger skrives til /var/log/caddy/access-*.log
med 100 MiB rotasjon og 7 filer beholdt.