feat: Media Agent Blocco A+B + Calendar Agent fix
Blocco A — Jellyfin Playback Agent (AyrKWvboPldzZPsM): - Webhook PlaybackStart/Stop → behavioral_context + agent_messages - Fix: JSON.parse Jellyfin body, SSL Patroni, Postgres queryParams inline Blocco B1 — Media Library Sync (o3uM1xDLTAKw4D6E): - Weekly cron: Radarr+Sonarr → GPT-4.1 → memory_facts + Qdrant - Qdrant collection media_preferences creata (768-dim nomic-embed-text) Blocco B2 — Jellyfin Watch History Sync (K07e4PPANXDkmQsr): - Daily cron: Jellyfin history (90d) → GPT-4.1 → memory_facts - Jellyfin API token Pompeo creato via admin auth Calendar Agent fix (4ZIEGck9n4l5qaDt): - Cleanup: filter(i=>i.json.uid) per evitare undefined non quotato in SQL - Salva Evento: rimosso updated_at=NOW() (colonna non esistente) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
80
README.md
80
README.md
@@ -384,6 +384,62 @@ Imports bank CSV statements (Banca Sella format) into Actual Budget via Telegram
|
||||
|
||||
**Common pattern across Paperless + Actual workflows**: GitHub Copilot token is obtained fresh at each run (`GET https://api.github.com/copilot_internal/v2/token`), then used for `POST https://api.githubcopilot.com/chat/completions` with model `gpt-4.1`.
|
||||
|
||||
### 🎬 Pompeo — Jellyfin Playback Agent [Webhook] (`AyrKWvboPldzZPsM`) ✅ Active
|
||||
|
||||
Webhook-based — triggered in real time by the Jellyfin Webhook plugin on every `PlaybackStart` / `PlaybackStop` event.
|
||||
|
||||
- Webhook path: `jellyfin-playback` (via `https://orchestrator.mt-home.uk/webhook/jellyfin-playback`)
|
||||
- Normalizes the Jellyfin payload (body is a JSON-encoded string → `JSON.parse` required)
|
||||
- On **PlaybackStart**: INSERT into `behavioral_context` (`event_type=watching_media`, `do_not_disturb=true`, metadata in `notes` JSONB: `item`, `device`, `item_type`)
|
||||
- On **PlaybackStop**: UPDATE `behavioral_context` → set `end_at=now()`, `do_not_disturb=false`
|
||||
- Both events write to `agent_messages` (subject: `▶️ {title} ({device})` or `⏹️ …`)
|
||||
- **User filter**: only processes events for `UserId = 42369255a7c64917a28fc26d4c7f8265` (Martin)
|
||||
- **Jellyfin stop behavior**: `PlaybackStop` fires only on player close, NOT on pause
|
||||
|
||||
Known quirks fixed:
|
||||
- Jellyfin webhook plugin sends body as `$json.body` (JSON string) — must `JSON.parse()` before reading fields
|
||||
- Real Jellyfin field names: `Name` (not `ItemName`), `DeviceName` / `Client`, `UserId` (no dashes)
|
||||
|
||||
---
|
||||
|
||||
### 🎬 Pompeo — Media Library Sync [Schedule] (`o3uM1xDLTAKw4D6E`) ✅ Active
|
||||
|
||||
Weekly cron — every **Sunday at 03:00**.
|
||||
|
||||
- Fetches all movies from **Radarr** (`/radarr/api/v3/movie`) and all series from **Sonarr** (`/sonarr/api/v3/series`)
|
||||
- Merges into unified list: `{type, title, year, genres, status: available|missing|monitored|unmonitored, source, source_id}`
|
||||
- **GPT-4.1 analysis**: extracts `top_genres`, `preferred_types`, `library_stats`, `taste_summary`, `notable_patterns`
|
||||
- **Postgres upsert**: `memory_facts` (source=`media_library`, source_ref=`media_preferences_summary`, expires +7d)
|
||||
- **Per-item loop**: for each movie/series → Ollama `nomic-embed-text` (768-dim) → Qdrant upsert into `media_preferences` collection
|
||||
- Qdrant payload: `{title, year, type, genres, status, source, source_id, expires_at (+6 months)}`
|
||||
|
||||
Internal endpoints used:
|
||||
- `http://radarr.media.svc.cluster.local:7878/radarr/api/v3/movie?apikey=922d1405ab1147019d98a2997d941765`
|
||||
- `http://sonarr.media.svc.cluster.local:8989/sonarr/api/v3/series?apikey=22140655993a4ff6bf12314813ec6982`
|
||||
- `http://ollama.ai.svc.cluster.local:11434/api/embeddings` (model: `nomic-embed-text`)
|
||||
- `http://qdrant.persistence.svc.cluster.local:6333` (api-key: sealed secret `qdrant-api-secret`)
|
||||
|
||||
---
|
||||
|
||||
### 🎞️ Pompeo — Jellyfin Watch History Sync [Schedule] (`K07e4PPANXDkmQsr`) ✅ Active
|
||||
|
||||
Daily cron — every day at **04:00**.
|
||||
|
||||
- Fetches last 100 played/partially-played items for Martin from Jellyfin API
|
||||
- Endpoint: `/Users/42369255a7c64917a28fc26d4c7f8265/Items?Recursive=true&IncludeItemTypes=Movie,Episode&SortBy=DatePlayed&SortOrder=Descending&Limit=100`
|
||||
- Auth: `Authorization: MediaBrowser Token="d153606c1ca54574a20d2b40fcf1b02e"` (Pompeo API key)
|
||||
- Filters items with `PlayCount > 0` and `LastPlayedDate` within 90 days
|
||||
- **GPT-4.1 analysis**: extracts `recent_favorites`, `preferred_genres`, `watch_patterns`, `completion_rate`, `notes`
|
||||
- **Postgres upsert**: `memory_facts` (source=`jellyfin`, source_ref=`watch_history_summary`, expires +30d)
|
||||
- Skips silently if no played items found (IF node guards the LLM call)
|
||||
|
||||
Jellyfin credentials:
|
||||
- API Token (app: Pompeo): `d153606c1ca54574a20d2b40fcf1b02e` — created via `POST /Auth/Keys?app=Pompeo` with admin session
|
||||
- Martin UserId: `42369255a7c64917a28fc26d4c7f8265` (from Jellyfin SQLite DB / webhook payload)
|
||||
- Admin user `admin` with password `__Montecarlo00!` (local auth, SSO via Authentik is separate)
|
||||
|
||||
---
|
||||
|
||||
### 📅 Pompeo — Calendar Agent [Schedule] (`4ZIEGck9n4l5qaDt`) ✅ Active
|
||||
|
||||
Runs every morning at 06:30 (and on-demand via manual trigger).
|
||||
@@ -407,6 +463,15 @@ Calendars: Lavoro, Famiglia, Spazzatura, Pulizie, Formula 1, WEC, Inter, Complea
|
||||
| `ZIVFNgI3esCKuYXc` | Google Calendar account | Google Calendar OAuth2 (also used for Tasks API) |
|
||||
| `u0JCseXGnDG5hS9F` | Home Assistant API | HTTP Header Auth (long-lived HA token) |
|
||||
| `mRqzxhSboGscolqI` | Pompeo — PostgreSQL | Postgres (database: `pompeo`, user: `martin`) |
|
||||
| `u0JCseXGnDG5hS9F` | Home Assistant API | HTTP Header Auth (long-lived HA token) |
|
||||
|
||||
### Qdrant Collections
|
||||
|
||||
| Collection | Dimensions | Distance | Model | Used by |
|
||||
|---|---|---|---|---|
|
||||
| `media_preferences` | 768 | Cosine | `nomic-embed-text` (Ollama) | Media Library Sync (B1) |
|
||||
|
||||
Qdrant API key: sealed secret `qdrant-api-secret` in namespace `persistence` → `__Montecarlo00!`
|
||||
|
||||
---
|
||||
|
||||
@@ -437,8 +502,8 @@ Calendars: Lavoro, Famiglia, Spazzatura, Pulizie, Formula 1, WEC, Inter, Complea
|
||||
- Tabelle: `user_profile`, `memory_facts` (+ `source_ref` + dedup index), `finance_documents`, `behavioral_context`, `agent_messages`
|
||||
- Multi-tenancy: campo `user_id` su tutte le tabelle, seed `martin` + `shared`
|
||||
- Script DDL: `alpha/db/postgres.sql`
|
||||
- [ ] Verify embedding endpoint via Copilot (`text-embedding-3-small`) as bootstrap fallback
|
||||
- [ ] Plan migration to local Ollama embedding model once LLM server is online
|
||||
- [x] Verify embedding endpoint via Copilot (`text-embedding-3-small`) as bootstrap fallback
|
||||
- [x] ~~Plan migration to local Ollama embedding model once LLM server is online~~ ✅ Active — `nomic-embed-text` via `http://ollama.ai.svc.cluster.local:11434` (768-dim, multilingual)
|
||||
- [ ] Create `ha_sensor_config` table in Postgres and seed initial sensor patterns
|
||||
|
||||
---
|
||||
@@ -465,6 +530,17 @@ Calendars: Lavoro, Famiglia, Spazzatura, Pulizie, Formula 1, WEC, Inter, Complea
|
||||
- Telegram daily briefing at 06:30
|
||||
- **Phase 2**: add weekly Qdrant embedding for semantic retrieval
|
||||
|
||||
- [x] ~~**Jellyfin Playback Agent**~~ ✅ 2026-03-21 — `AyrKWvboPldzZPsM`
|
||||
- Webhook: PlaybackStart → `behavioral_context` INSERT (`do_not_disturb=true`), PlaybackStop → UPDATE (`end_at`, `do_not_disturb=false`)
|
||||
- `agent_messages` populated with `▶️`/`⏹️` + title + device
|
||||
- User filter: Martin only (UserId `42369255…`)
|
||||
|
||||
- [x] ~~**Media Library Sync (B1)**~~ ✅ 2026-03-21 — `o3uM1xDLTAKw4D6E`
|
||||
- Weekly (Sunday 03:00): Radarr + Sonarr → GPT-4.1 taste analysis → `memory_facts` + Qdrant `media_preferences` (768-dim, nomic-embed-text)
|
||||
|
||||
- [x] ~~**Jellyfin Watch History Sync (B2)**~~ ✅ 2026-03-21 — `K07e4PPANXDkmQsr`
|
||||
- Daily (04:00): Jellyfin play history (90d window) → GPT-4.1 pattern analysis → `memory_facts`
|
||||
|
||||
- [ ] **Finance Agent** (extend beyond Paperless)
|
||||
- Read Actual Budget export or API
|
||||
- Persist transactions, monthly summaries to `finance_documents`
|
||||
|
||||
Reference in New Issue
Block a user