From cb621ca5d0957117c036c32ba3952b3fc959417a Mon Sep 17 00:00:00 2001 From: "reza.g" Date: Sun, 25 Oct 2026 22:02:40 +0330 Subject: [PATCH] =?UTF-8?q?feat(monitoring):=20multi-model=20dashboard=20v?= =?UTF-8?q?2.1=20=E2=80=94=20tabs,=20per-model=20records,=20voice=20playba?= =?UTF-8?q?ck=20+=20MinIO=20dual-write?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the dashboard was Jev-centric; NLU/arbiter/fallback DeepSeek, STT providers and the audio-enhancer were barely visible, and stored texts/voices had no real access path. Bot (additive; reply path untouched): - nlu.result now records latency_ms + the DeepSeek usage tokens - matching.arbitration/fallback.result fill the model + latency_ms columns (payload unchanged; SQL coalesces column/payload so old rows still count) - storage.py: MinIO dual-write layer — every voice (raw + denoised) and user attachment is mirrored fire-and-forget into bucket bot-media; the blocking minio SDK runs via asyncio.to_thread (senior-engineer review) so the event loop is never stalled; empty MINIO_* env = layer off; bucket auto-created - requirements: minio>=7.2 Backend (admin-gated, read-only): - GET /bot-metrics/models — one record per model (jev, deepseek-nlu, deepseek-arbiter, deepseek-fallback, audio-enhancer + dynamic per-provider STT) with calls/ok-rate/p50/p95/tokens/last-seen + version-drift vs the pin - GET /bot-metrics/models/{id}/daily — per-model daily calls/fails/tokens/p50 - GET /bot-metrics/stages — every stage tagged with its Persian pipeline section (صوت/درک پیام/تطبیق/ابهام و انتخاب/پیش‌نویس) - /traces now carries input_kind + a 120-char text excerpt (consensus → input.text → first STT transcript) - media serving: POST /media-url mints a short-lived HMAC URL (audio/a tags cannot send Authorization); GET /media streams from MinIO bot-media with the read-only ./bot/data mount as fallback for pre-MinIO files; hard ref validation (voices|attachments only, no .., extension whitelist) - router exempted from the global Bearer dependency (files.py pattern) — every endpoint keeps its own require_role('admin') Frontend /bot-monitor (RTL, recharts): - four tabs: نمای کلی / مدل‌ها (records table + per-model expandable daily charts: calls/fails, tokens, p50) / بخش‌ها (sections grouped) / پیام‌ها - message drawer rebuilt: inline