Přeskočit obsah

app-hotline — Hotline AVAXIS (call & voice support monitoring)

Status: draft v0.3 (schema rewrite — screenplay model) Aktualizováno: 2026-05-30 Vendor: AVAXIS.CZ (publisher) Repo: git.avaxis.cz/avax-apps/app-hotline-app Slug: app-hotline (schema app_hotline, bucket app-hotline, port 8106) Související: ai-helper.md, app-ai-helper.md, voice-video-call.md, apps-gateway.md

0. Zásadní rozhodnutí

v0.3 — F3 schema rewrite (2026-05-30)

  • Application hotline-transcribe v app-ai-helper přebírá celou STT+strukturalizaci. Aplikace registrovaná druhým Claude na app-ai-helper s 2-step pipeline (speech.to_text.diarizedchat Aya 32B screenplay formatting). App-hotline backend volá 1× endpoint a dostane hotový screenplay + turns + AI topic/usefulness/summary.
  • Schema = screenplay model (ne turn-by-turn segments). Tabulky: hotline_call, hotline_turn, billing_entries, self_service_queries, audit_log. Per F3 commit 40a245d.
  • AI/human mirror columnshotline_call.ai_* (návrh od AI) vs hotline_call.human_* (operatorův přepis při approval). Vždy oba sloupce per pole (screenplay/topic/summary/usefulness) — pro audit trail původního AI návrhu i lidsky validovaného výstupu.
  • Customer consent gate — GDPR Article 6(1)(a) compliance. customer_consent BOOLEAN NOT NULL DEFAULT FALSE + dialog před recording. Bez consent recording nepoběží.
  • Customer phone hashing — SHA256(phone + company_salt). Plain phone NIKDY není uložené.

v0.2 (zachované)

  • Batch only. Žádný live streaming — WAV se uploaduje až po ukončení hovoru. Live transcription je P3 roadmap.
  • GDPR retention 30 dní audio (auto-delete cron), transkripty + screenplay zachovány déle (anonymizace per retention policy v audit_log).

1. Cíl

Hotline AVAXIS monitoruje hlasové hovory (telefon / VoIP / face-to-face s mic záznamem), automaticky je přepisuje, identifikuje účastníky a extrahuje dotazy + odpovědi. Z extrahovaných Q&A buduje RAG knowledge base, kterou uživatelé používají self-service místo dalšího volání. Souběžně generuje fakturační podklady (kdo volal, jak dlouho, jaká témata).

Use case scénář

  1. Klient (Jiří Novák) zavolá na hotline kvůli problému s migrací DB.
  2. Operátor (Petra) zvedne, hovor začne — Hotline app monitoruje mic (operátorův PC) + line-in (klientský audio stream přes VoIP bridge).
  3. Hovor trvá 12 min. Hotline:
  4. Live STT (Whisper Small, lokální worker)
  5. Speaker diarization (Petra vs. Jiří)
  6. Q&A turn detection: extrahuje páry (otázka klienta, odpověď operátora)
  7. Po hovoru:
  8. Audio uloženo do S3 (app-hotline/recordings/<call_id>.wav)
  9. Transcript do DB (app_hotline.transcripts)
  10. Q&A indexováno do RAG korpusu app-hotline-qa
  11. Billing entry: call_id, klient, operator, duration=12min, topics=[DB migrace]
  12. Příští klient (Marie) má stejný dotaz — místo volání otevře Tk klienta Hotline → Hledat, zadá migrace databáze. RAG vrátí odpověď Petry z minulého hovoru.
  13. Admin (Michal) v měsíčním reportu vidí: 47 hovorů, 9.3 hodin support time, top topic „DB migrace" (12 hovorů → vznikl RAG entry → vidí jak poklesl follow-up volume).

2. Architecture overview

                ┌──────────────────────────────────────────┐
                │  launcher2 (operátor / admin / klient)   │
                │  - login + IPC session token             │
                └──────────────────┬───────────────────────┘
                                   │ apps-gateway routing
        ┌──────────────────────────────────────────────────┐
        │  app-hotline kontejner (FastAPI + Celery worker)  │
        │  port 8106 → :: /apps/app-hotline/*               │
        │                                                   │
        │  ├─ Audio pipeline (v0.1 just capture+store)      │
        │  │   ├─ mic capture → local WAV (operátor disk)   │
        │  │   ├─ post-call upload → S3 mirror (volitelný)  │
        │  │   └─ job submit → ai-helper                    │
        │  │       `_AI.speech.transcribe_structured()`     │
        │  │       (až bude capability ready — v0.2)         │
        │  ├─ Transcript ingest (callback z ai-helper)      │
        │  │   └─ parse segments + Q/A pairs → DB           │
        │  ├─ RAG indexer (po approve)                       │
        │  │   └─ Q&A pairs → ai-helper `_AI.rag.index()`    │
        │  ├─ Billing report generator                       │
        │  └─ Q&A search UI (Tk panel)                       │
        └─────────────────┬────────────────────────────────┘
                          │ M2M (AVAX_AUTH_TOKEN)
                ┌─────────────────────────────────────┐
                │  app-ai-helper (existing service)   │
                │  - LM Studio worker pool             │
                │  - Whisper STT worker                │
                │  - RAG corpus `app-hotline-qa`       │
                │  - Embedding bge-m3 (1024d)         │
                └─────────────────────────────────────┘

3. Persony a role

Persona Co vidí v Tk klientu
Operátor (zaměstnanec AVAXIS support team) Live hovor tab (mic monitor), historie hovorů (filter podle data/klienta), Q&A draft editor
Klient (jakýkoli end-user s subscription) Q&A search („zeptat se hotliny bez hovoru"), historie vlastních dotazů
Billing manager (AVAXIS účetní) Billing report tab (export CSV/PDF), hodinový sazebník, fakturační statusy
Super_admin (Michal) Vše + admin tab (operátoři, sazby, RAG corpora správa, retention policy, GDPR ops)

UI: 12 tabs, dynamicky skryté podle role z JWT (system_role, company_id).

4. UI tabs (Tk customtkinter)

# Tab Persony Popis
1 🔴 Live hovor operator Mic capture aktivní + transcript live ▼. Klik „Konec" → uložit audio + spustit STT job.
2 📞 Historie hovorů operator, admin Tabulka: datum, klient, operátor, délka, status. Klik = detail (transcript, audio playback, Q&A draft).
3 ❓ Q&A hledat client, operator Search box + RAG retrieval. „Jak migrovat DB?" → vrátí top 3 hits z minulých hovorů.
4 📚 Q&A knowledge base operator, admin Browse all extracted Q&A pairs. Edit, schválit do public, smazat.
5 💰 Billing report billing, admin Filter podle období / klienta. Export CSV/PDF. Hodinová sazba.
6 📊 Statistiky admin Top topics, hovor volume, average duration, RAG hit rate (= kolik dotazů odpovědělo bez hovoru).
7 ⚙️ Nastavení operator Mic input device, sample rate, retention period, auto-RAG indexing on/off.
8 👥 Operátoři admin Správa speaker profiles (kdo je operátor, hodinová sazba per operátor).
9 🗄️ Retention admin GDPR: per-klient retention period, anonymizace, smazání.
10 🧠 RAG correctness admin Review Q&A pairs s nízkou confidence — odsouhlasit / přepsat / smazat.
11 🤖 AI workers admin Status workers (STT, embedding, chat) — link na app-ai-helper.
12 📋 Audit log admin Kdo přepisoval Q&A, kdy, co změnil.

5. Datový model (PostgreSQL app_hotline schema) — v0.3 screenplay model

Změny vs v0.2: - callshotline_call (široký, AI/human mirror columns, consent gate) - transcript_segmentshotline_turn (z screenplay turns, ne raw STT segments) - qa_pairsodstraněno — Q&A extraction nahrazené screenplay+topic+usefulness metadata na hotline_call (1 řádek per hovor, ne sekundární tabulka) - audit_log nově — kompliance pro 3y retention regulatory tracking

-- 5.1 hotline_call — primary entity, široká tabulka s AI/human mirror columns
CREATE TABLE app_hotline.hotline_call (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Časování
    call_started_at TIMESTAMPTZ NOT NULL,
    call_ended_at   TIMESTAMPTZ,
    call_duration_s INTEGER GENERATED ALWAYS AS
                      (EXTRACT(EPOCH FROM (call_ended_at - call_started_at))::int) STORED,

    -- Identifikace (operatorův user.id, zákazník hashed kvůli GDPR)
    operator_id          UUID NOT NULL,                  -- public.users(id) (cross-schema, ne FK)
    customer_user_id     UUID,                            -- pokud registered + souhlas, jinak NULL
    customer_phone_hash  VARCHAR(64),                     -- SHA256(phone + company_salt). NIKDY plain.
    customer_consent     BOOLEAN NOT NULL DEFAULT FALSE,  -- GDPR Article 6(1)(a) gate
    consent_recorded_at  TIMESTAMPTZ,

    -- Audio storage
    audio_s3_key      TEXT,
    audio_local_path  TEXT,
    audio_deleted_at  TIMESTAMPTZ,                        -- retention cron timestamp
    retention_until   TIMESTAMPTZ,                        -- default = call_started_at + 30 days

    -- AI Helper Application interaction (hotline-transcribe)
    ai_instance_id    UUID,                               -- ai_helper.application_instances.id
    transcribe_job_id TEXT,                               -- async job tracking

    -- Status state machine
    status TEXT NOT NULL DEFAULT 'recording'
      CHECK (status IN ('recording', 'stored', 'transcribing', 'pending_review',
                         'approved', 'rejected', 'archived', 'failed')),

    -- AI návrh (přímý výstup z hotline-transcribe Application)
    ai_screenplay           TEXT,    -- formátovaný screenplay text (Aya 32B step 2)
    ai_topic_primary        TEXT,    -- enum: billing|technical|account|complaint|inquiry|cancellation|other
    ai_topic_detail         TEXT,    -- max 80 chars upřesnění
    ai_usefulness           SMALLINT,  -- 1-5 (RAG push gate: ≤ 2 auto-skip)
    ai_usefulness_reasoning TEXT,    -- model's justification
    ai_summary              TEXT,    -- 3-5 vět summary

    -- Human přepis při approval (mirror sloupce, NULL pokud neupravoval)
    human_screenplay      TEXT,
    human_topic_primary   TEXT,
    human_topic_detail    TEXT,
    human_usefulness      SMALLINT,
    human_summary         TEXT,

    -- Approval workflow
    approved_by_user_id   UUID,
    approved_at           TIMESTAMPTZ,
    rejected_at           TIMESTAMPTZ,
    rejected_reason       TEXT,

    -- RAG push tracking (po approve)
    pushed_to_rag_at      TIMESTAMPTZ,
    rag_document_id       UUID,                            -- ai_helper.documents.id

    -- Billing
    billing_status TEXT NOT NULL DEFAULT 'pending'
      CHECK (billing_status IN ('pending', 'invoiced', 'paid', 'waived')),

    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    CHECK (ai_usefulness IS NULL OR (ai_usefulness BETWEEN 1 AND 5)),
    CHECK (human_usefulness IS NULL OR (human_usefulness BETWEEN 1 AND 5))
);

CREATE INDEX ix_hotline_call_started   ON app_hotline.hotline_call(call_started_at DESC);
CREATE INDEX ix_hotline_call_operator  ON app_hotline.hotline_call(operator_id, call_started_at DESC);
CREATE INDEX ix_hotline_call_status    ON app_hotline.hotline_call(status, call_started_at DESC);
CREATE INDEX ix_hotline_call_pending   ON app_hotline.hotline_call(status) WHERE status = 'pending_review';
CREATE INDEX ix_hotline_call_retention ON app_hotline.hotline_call(retention_until) WHERE audio_deleted_at IS NULL;
CREATE INDEX ix_hotline_call_customer  ON app_hotline.hotline_call(customer_phone_hash);

-- 5.2 hotline_turn — jednotlivé turny z hotline-transcribe screenplay
CREATE TABLE app_hotline.hotline_turn (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    call_id         UUID NOT NULL REFERENCES app_hotline.hotline_call(id) ON DELETE CASCADE,

    order_index     INTEGER NOT NULL,                     -- pořadí v hovoru (od 0)
    speaker_raw     TEXT NOT NULL,                        -- SPEAKER_00 / SPEAKER_01 (z pyannote)
    speaker_role    TEXT,                                  -- 'support' | 'customer' (z Aya step 2)
    speaker_user_id UUID,                                  -- public.users(id) pokud identifikováno

    start_ms        INTEGER NOT NULL,                     -- offset z call_started_at
    end_ms          INTEGER NOT NULL,

    text_raw        TEXT NOT NULL,                        -- raw Whisper output
    text_corrected  TEXT,                                  -- po Aya post-process (ASR fix)

    confidence      REAL,                                  -- 0-1 STT confidence
    was_edited      BOOLEAN NOT NULL DEFAULT FALSE,       -- operator přepsal v approval UI

    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX ix_hotline_turn_call ON app_hotline.hotline_turn(call_id, order_index);

-- 5.3 billing_entries — beze změny z v0.2 (jen FK target name)
CREATE TABLE app_hotline.billing_entries (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    call_id         UUID NOT NULL REFERENCES app_hotline.hotline_call(id),
    client_company  UUID,
    duration_min    NUMERIC(8,2) NOT NULL,
    rate_per_hour   NUMERIC(10,2) NOT NULL,
    amount          NUMERIC(10,2) NOT NULL,
    invoice_id      UUID,
    status          TEXT NOT NULL DEFAULT 'draft'
                      CHECK (status IN ('draft', 'sent', 'paid', 'cancelled')),
    period_start    DATE NOT NULL,
    period_end      DATE NOT NULL,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- 5.4 fakturační záznamy
-- 5.4 self_service_queries — Q&A search analytika
CREATE TABLE app_hotline.self_service_queries (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id           UUID NOT NULL,                       -- public.users(id)
    query_text        TEXT NOT NULL,
    rag_hits          JSONB,                                -- top N retrieval results
    user_satisfied    BOOLEAN,                              -- 👍/👎 feedback
    fallback_to_call  BOOLEAN NOT NULL DEFAULT FALSE,      -- klient přesto zavolal
    fallback_call_id  UUID REFERENCES app_hotline.hotline_call(id),  -- jaký hovor následoval
    created_at        TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX ix_self_queries_user ON app_hotline.self_service_queries(user_id, created_at DESC);

-- 5.5 audit_log — compliance tracking (3y retention)
CREATE TABLE app_hotline.audit_log (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    call_id     UUID REFERENCES app_hotline.hotline_call(id) ON DELETE SET NULL,
    user_id     UUID NOT NULL,
    action      TEXT NOT NULL
                  CHECK (action IN ('viewed', 'edited', 'approved', 'rejected',
                                     'deleted', 'exported')),
    field       TEXT,                                       -- který sloupec se měnil
    old_value   TEXT,
    new_value   TEXT,
    reason      TEXT,                                       -- např. "GDPR retention cron"
    ip_address  INET,
    user_agent  TEXT,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ON DELETE SET NULL: call CASCADE smaže hotline_call, audit_log řádek
-- zůstává (3y retention pro compliance audity).

CREATE INDEX ix_audit_call    ON app_hotline.audit_log(call_id, created_at DESC);
CREATE INDEX ix_audit_user    ON app_hotline.audit_log(user_id, created_at DESC);
CREATE INDEX ix_audit_action  ON app_hotline.audit_log(action, created_at DESC);

Status state machine (hotline_call.status)

recording           ← UI start (po consent dialog)
   │ Konec hovoru
stored              ← WAV uložený lokálně + S3 mirror (volitelné)
   │ submit hotline-transcribe
transcribing        ← async job v ai-helper Application
   │ ingest screenplay + turns
pending_review      ← operator může otevřít approval dialog
   │ approve   │ reject
   ▼           ▼
approved      rejected
   │             │
   │ push do RAG │
   ▼             ▼
(rag_document_id) ─────► archived (po retention cleanup)

failed       ← terminal po STT/upload/M2M error (fail-soft retry)

Per-app DB user GRANTs

Alembic vytvoří schema přes avaxis superuser, ale runtime kontejner běží jako avax_app_app_hotline (low-priv per-app user). Po prvním alembic upgrade head doplnit:

GRANT USAGE, CREATE ON SCHEMA app_hotline TO avax_app_app_hotline;
GRANT ALL ON ALL TABLES IN SCHEMA app_hotline TO avax_app_app_hotline;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_hotline
    GRANT ALL ON TABLES TO avax_app_app_hotline;

Per memory reference_alembic_deploy_gotchas + reference_per_app_db_grant_step.

6. Audio pipeline

6.1 Capture & storage (v0.1)

Reuse sounddevice patterny z voice-video-call.md: - Live mic input → ring buffer (memory) v Tk klientu - Stream do local WAV na disku operátora (audio_local_path) v C:\Avaxis\hotline\recordings\<call_id>.wav (default; override v Nastavení tab) - Po Konec hovoru klik: 1. Finalize WAV (close write, integrity check) 2. UPSERT calls row s status='stored', audio_local_path 3. Volitelný S3 mirror (Nastavení → „Zálohovat audio na S3") — async upload do app-hotline/recordings/<call_id>.wav přes APPDIST credentials. Pokud zapnutý, set audio_s3_key.

6.2 Transcribe → ai-helper capability

App-hotline nevolá STT přímo. Po status='stored' submitne job na app-ai-helper přes plánovanou capability:

from avaxis_sdk import AVAX
avax = AVAX.from_m2m(...)

job = avax._AI.speech.transcribe_structured_async(
    audio_source=audio_local_path or f"s3://app-hotline/recordings/{call_id}.wav",
    language="cs",
    speakers=2,           # known počet — operátor + klient
    extract_qa=True,      # vrátí i (otázka, odpověď) páry
    callback_url=f"https://api.avaxis.cz/apps/app-hotline/_internal/transcribe-done",
)
# job.id se uloží do calls.transcribe_job_id

speech.transcribe_structured() neexistuje v app-ai-helper v dnešní verzi (2026-05-28). Musí být doplněna — viz §13.1. App-hotline v0.1 ji jen volá optimisticky; pokud HTTP 501 (not implemented), status zůstává stored s badge „čeká na STT capability".

Návrh capability response (synchronní polling nebo callback):

{
  "job_id": "...",
  "status": "completed",
  "segments": [
    {"start_ms": 0,    "end_ms": 3200,  "speaker": "SPEAKER_00", "text": "Dobrý den…"},
    {"start_ms": 3300, "end_ms": 8100,  "speaker": "SPEAKER_01", "text": "Dobrý, mám problém…"}
  ],
  "qa_pairs": [
    {"question": "Jak migrovat databázi?", "answer": "…", "topic": "DB migrace", "confidence": 0.92}
  ],
  "model": "whisper-medium",
  "duration_ms": 12340
}

6.3 Speaker mapping

speech.transcribe_structured vrací anonymní SPEAKER_00/SPEAKER_01. App-hotline backend mapuje na konkrétní users: - Operátor: heuristika „kdo začíná hovor pozdravem" + cross-check s operator_id z calls row - Klient: druhý speaker (pokud jen 2 účastníci) - Pokud > 2 speakers: ručně přiřadit v Historie hovorů tab

Per-operator voice fingerprint (P3, ne v0.1): až ai-helper bude umět voice embedding, mapování operátora bude automatické bez heuristik.

6.4 RAG indexing

Pro každý approved Q&A pair:

doc = avax._AI.rag.index_document(
    corpus="app-hotline-qa",
    content=f"Otázka: {qa.question}\n\nOdpověď: {qa.answer}",
    metadata={
        "call_id": str(qa.call_id),
        "topic": qa.topic,
        "operator": qa.operator_name,
        "date": qa.created_at.isoformat(),
    },
)
qa.rag_doc_id = doc.id
qa.rag_indexed = True

Corpus app-hotline-qa musí existovat v app-ai-helper (admin tab "RAG corpora" → vytvořit s embedding_model=bge-m3, chunk_size=512).

7. RAG retrieval (Q&A search tab)

hits = avax._AI.rag.search(
    corpus="app-hotline-qa",
    query="jak migrovat databázi",
    top_k=5,
    threshold=0.7,
)
# hits = [{"text": "...", "score": 0.87, "metadata": {...}}, ...]

UI: ukázat top 3, klik = expand full Q&A + odkaz na původní hovor (přepis playable).

Self-service feedback loop: user klikne 👍 → self_service_queries.user_satisfied=true. Pokud 👎 nebo „fallback to call" — log → admin tab "Q&A correctness" review.

8. M2M auth + AI Helper integrace

App-hotline backend volá app-ai-helper přes M2M JWT z AVAX_AUTH_TOKEN (per vendor-onboarding §3 a apps-gateway §7):

# backend/app/services/ai_client.py
import os
from avaxis_sdk import AVAX

# M2M mode — JWT issuer = core-api /auth/token client_credentials grant
ai = AVAX.from_m2m(
    client_id=os.environ["AVAX_M2M_CLIENT_ID"],
    client_secret=os.environ["AVAX_M2M_CLIENT_SECRET"],
    api_url=os.environ["AVAX_API_URL"],
)

M2M client musí být vytvořen v UI Launcher2 (admin → M2M Clients → Vytvořit pro app-hotline). Po vytvoření Michal zapíše client_id + client_secret jako Gitea secrets AVAX_M2M_CLIENT_ID / AVAX_M2M_CLIENT_SECRET (per-repo, ne org level — secrety jsou unikátní per app).

Scopes potřebné pro app-hotline M2M client: - ai:chat (volitelné — pro post-processing Q&A párů, např. topic normalize) - ai:rag:read (search RAG corpus z self-service hledání) - ai:rag:write (index Q&A pairs po approve) - ai:speech:transcribe_structured (čeká na implementaci capability, viz §13.1)

9. Capabilities deklarace

V manifest.json:

{
  "slug": "app-hotline",
  "name": "Hotline AVAXIS",
  "version": "0.1.0",
  "description": "Voice/call monitoring + Q&A extraction + RAG knowledge base",
  "ai_consumer": {
    "capabilities": ["chat", "rag.search", "rag.index_document", "speech.stt"],
    "preferred_models": {
      "chat": "qwen2.5-14b",
      "embedding": "bge-m3",
      "stt": "whisper-small"
    }
  },
  "permissions": {
    "microphone": true,
    "filesystem": ["recordings/"],
    "s3_buckets": ["app-hotline"]
  }
}

Launcher2 manifest check při instalaci → zobrazí dialog „Tato app požaduje přístup k mikrofonu a hovoru AI workerům. Schválit?".

10. Migrations roadmap

Migrace Co
0001_init.py app_hotline schema create + 5 tabulek z §5
0002_indexes.py Performance indexy (top topics, billing periods)
0003_operator_profiles.py P2 voice fingerprint (pgvector 192d)
0004_audit_log.py Audit log (kdo přepisoval Q&A)

11. CI/CD

  • publish.yml (z skeleton): Wine cross-build → S3 app-hotline/channels/alpha.json
  • backend.yml (z skeleton): docker build → push to Gitea registry → SSH deploy na avaxdev → docker run avax-app-hotline -p 127.0.0.1:8106:8000
  • Alembic upgrade head jako post-deploy step (per reference-alembic-deploy-gotchas--sql workaround pokud online no-op)

12. Open questions (status k v0.2)

# Otázka Status
1 STT engine VYŘEŠENO — řeší app-ai-helper (nová capability speech.transcribe_structured), app-hotline jen volá
2 Diarization placement VYŘEŠENO — součást speech.transcribe_structured capability v app-ai-helper
3 GDPR retention VYŘEŠENO — 30 dní audio (auto-delete cron), transkripty napořád (s anonymizací jmen po retention)
4 Live vs batch STT VYŘEŠENO — batch only v0.1, live v P3 roadmap
5 Multi-channel audio (VoIP bridge) OTEVŘENÉ — v0.1 jen mic operátora; VoIP bridge (Asterisk?) P2+
6 Q&A approval flow VYŘEŠENOstrict approve gate: Q&A pairs jsou invisible (a NOT v RAG corpus) dokud operator/admin neaprove. Lepší kvalita, slower propagace.

12.1 Strict approval flow detail

ai-helper vrátí qa_pairs
INSERT INTO qa_pairs (..., is_approved=false, rag_indexed=false)
UI „Historie hovorů" → call detail → „Q&A pairs k schválení (N)"
  ▼ operator klik „✓ Schválit" pro každý pair
INSERT INTO RAG corpus (POST _AI.rag.index_document)
UPDATE qa_pairs SET is_approved=true, approved_by=user_id, approved_at=now(),
                    rag_doc_id=..., rag_indexed=true
  ▼ teď viditelné v Q&A search tabu pro klienty

Operator může i editovat text otázky/odpovědi PŘED approve (typo fix, přepsat osobní data, atd). Po approve text immutable (audit log zachycuje edits).

Bulk approve: tlačítko „Schválit všechny s confidence > 0.85" pro rychlou review session.

13. Roadmap

13.1 Co BLOKUJE app-hotline v0.1 deployment

Předpokládá novou capability v app-ai-helper:

POST /v1/call/speech.transcribe_structured_async
  audio_source: str            # file:// nebo s3://
  language: "cs" | "en" | ...
  speakers: int | "auto"
  extract_qa: bool             # vrátí i Q&A pairs (LLM post-process)
  callback_url: str | None
→ 202 Accepted + job_id

GET /v1/jobs/{job_id}
→ 200 OK status=completed|running|failed
   result.segments: [...]
   result.qa_pairs: [...]

App-hotline POC může běžet i bez této capability — UI bude fungovat, transcripty zůstanou prázdné. Druhý Claude na app-ai-helper repu musí capability implementovat (pravděpodobně přes Whisper worker + chained LLM call na Q&A extraction).

13.2 Phases

Phase Co Závisí na
P0 DB schema + REST API + Tk capture/storage + Historie hovorů UI
P1 speech.transcribe_structured napojení + Q&A approval UI app-ai-helper capability
P2 RAG indexing + Q&A search self-service UI P1 + corpus app-hotline-qa v app-ai-helper
P3 Billing report + statistiky + audit log P0
P4 GDPR retention cron (audio 30d delete) + anonymizace P0
P5 Multi-channel audio + VoIP bridge infra (Asterisk?)
P6 Live streaming STT + voice fingerprint operátorů app-ai-helper extended capabilities

Související