didi-lot2-backend/backend/services/orchestration-layer/agent-v3/INDEX.md
2026-07-10 03:39:53 -07:00

58 KiB
Raw Permalink Blame History

Agent V3 - Index

Serviciul principal al platformei DIDI. Analizeaza continut (text, URL, imagine, audio, video) pentru detectarea dezinformarii. Produce scoruri 0-100 pe 4 componente si un verdict agregat.

Port: 24803 Framework: Express 5 + TypeScript Container: didi-agent-v3


Infrastructura data-layer

Data layer rulează local pe mașina de deployment, ca containere Docker pe didi-network. Nu există cluster extern — serviciile se adresează prin numele de container Docker, nu prin IP de mașină. Config real din env-ul didi-agent-v3:

Serviciu Container (target) Config Credentials
PostgreSQL 17 didi-postgres:5432 DB DIDI, schema bos_analysis user bos_interface / interface
Redis 7 didi-cache:6379 DB 0 parolă redis123
RabbitMQ 3.12 staging-dataLayer-rabbitmq:5672 vhost / user admin / rabbitmq123

Clienți ioredis centralizați via src/shared/redis/connection.tscreateRedisConnection(label). Zero new Redis({...}) inline. Auto-reconnect + reconnectOnError.

RabbitMQ client via src/queue/connection.ts + src/shared/queue/constants.ts. Vhost / (encodeURIComponent() la construirea URI-ului AMQP).

Bootstrap auto-populate: la startup, didi-framework detectează dacă didi:framework:manifest lipsește în Redis și auto-rulează POST /api/sync-redis. Zero intervenție manuală pe fresh deploy.


Integrare cu platforma AI (Lot 1)

Backend-ul (Lot 2) apelează serviciile platformei AI (Lot 1) prin HTTP — nu implementează niciunul intern. Fiecare are un URL configurabil din env, cu fail-open: orice eroare (timeout, 5xx, network, feature flag off) → analiza continuă fără serviciul respectiv (fallback la calea locală sau skip). Cum funcționează intern brain/RAG, atom cache, extractorii, forensic, buster etc. e documentat în platforma AI (Lot 1); aici descriem doar contractul de integrare.

Serviciu Lot 1 Env (default) Folosit pentru Fail-open
didi_brain DIDI_BRAIN_URL (http://10.11.10.12:8090) Verification cache + analysis atom cache pentru claims/techniques/ai-tampered → LLM direct
extractors EXTRACTORS_URL (http://<HOST_IP>:54400) Extragere conținut/metadata → skip
video analysis (buster) VIDEO_ANALYSIS_URL (http://<HOST_IP>:54600) Analiză video → procesare locală
forensic FORENSIC_API_URL (http://forensic-features-api:8080) Forensic features imagine → skip
whisper (audio) M17_WHISPER_URL (http://10.11.10.17:54300) Transcriere audio → Groq → OpenAI
web search M17_WEB_API_URL (http://10.11.10.13:51100) Căutare web claims/source fallback când brain MISS
LLM router LLM_ROUTER_URL (http://10.11.10.17:14011) Inferență LLM primară (Qwen local) → OpenRouter
vision VISION_LLM_URL (http://10.11.10.17:14011) OCR + AI detection imagine → Gemini / GPT-4o
domain check DOMAIN_CHECK_API_URL (http://<domain-check-host>:11000) WHOIS/DNS/SSL/blacklist domeniu → skip

IP-urile GPU 10.11.10.17:14011 (LLM/vision) și 10.11.10.17:54300 (whisper) sunt default, configurabile din env.

Client brain (cod backend, src/shared/brain/client.ts): gatherFromBrain() (verification cache lookup + evidence pentru claims), writeVerificationCacheAsync(), lookupAnalysisAtom() / writeAnalysisAtomAsync() / patchAnalysisAtomGold() (analysis atom cache pentru techniques/ai-tampered), plus helpers de hashing. Detaliul acestei integrări backend e la secțiunea „Funcționalități suplimentare".


Tier-aware execution (premium vs free)

Agent-v3 ruleaza chain-uri diferite de modele LLM in functie de planul de abonament al utilizatorului.

Cum se determina tier-ul

  1. Fiecare request face checkCredits() la didiFramework, care returneaza planType (1-6) in raspuns
  2. getSearchTier(planType) din src/shared/credits.ts mapeaza:
    • plan_type 1-3 → tier 'free'
    • plan_type 4-6 → tier 'premium'
  3. tier (variabila searchTier in cod) e propagat prin toate straturile:
    • Sync routes: pipeline-routes.ts, ai-tampered-routes.tsPipelineInput.searchTier
    • Async via queue: component-worker.ts deriva din taskMessage.planType
    • ComponentRunner.runAll()AnalysisInput.searchTier
    • Fiecare executor primeste tier ca parametru la execute()
    • verdict-explanation.ts: primeste tier la generate()
    • vision.ts / callVision(): primeste tier
    • transcription.ts / transcribe(): primeste tier in options
    • M17 search (claims/source-assessment): trimite X-Search-Tier: premium header

Ce se schimba per tier

Component/Stage Free primary Premium primary
Techniques screening Qwen 3.5 397B local Gemini 3 Flash Preview (OR)
Techniques deep Qwen 3.5 397B local Claude Sonnet 4.6 (OR)
AI-Tampered screening Qwen 3.5 397B local Gemini 3 Flash Preview (OR)
AI-Tampered deep Qwen 3.5 397B local Claude Sonnet 4.6 (OR)
Claims extraction Qwen 3.5 397B local Gemini 3 Flash Preview (OR)
Claims verification Qwen 3.5 397B local Claude Sonnet 4.6 (OR)
Source extraction Qwen 3.5 397B local Gemini 3 Flash Preview (OR)
Source evaluation Qwen 3.5 397B local Claude Sonnet 4.6 (OR)
Verdict reviewer Qwen 3.5 397B local Gemini 3 Flash Preview (OR)
Vision (OCR + AI detect) Qwen Vision local Gemini 3 Flash Preview (OR)
Transcription (audio) M17-Whisper local Groq-Whisper
Web search (claims/source) M17 SearXNG M17 + Brave + Tavily (via X-Search-Tier header)

Fallback chain pentru premium termina pe Qwen local (safety net, 0 cost) — zero erori de rutare daca cloud crapa.

Cum se incarca stage assignments tier-based

Executoarele citesc cheia Redis didi:config:{component}:v1:stage_assignments cu structura tier-nested:

{
  "techniques_screening": {
    "free":    { "models": [{ order:1, model_key: "qwen35:Qwen3.5-397B-A17B", ...}, ...] },
    "premium": { "models": [{ order:1, model_key: "openrouter:google/gemini-3-flash-preview", ...}, ...] }
  },
  "techniques_deep": { "free": {...}, "premium": {...} }
}

Helper resolveStageAssignment(assignments, stageCode, tier) returneaza chain-ul corect, cu fallback automat la 'free' daca 'premium' lipseste. Asta protejeaza utilizatorii premium daca configul nu e complet.


Componente de analiza

Serviciul ruleaza 4 componente independente + un calculator de verdict:

Componenta Ce face Scor produs
Techniques Detecteaza tehnici de manipulare (propaganda, apel emotional, etc.) manipulation_score 0-100
AI-Tampered Detecteaza continut generat/modificat de AI ai_probability 0-100
Claims Extrage afirmatii si le verifica prin cautare web credibility_score 0-100
Domain Analizeaza domeniul sursa (varsta, SSL, blacklist, reputatie) trust_score 0-100
Verdict Agrega scorurile componentelor intr-un scor final de risc risk_score 0-100

Fiecare componenta (in afara de Domain) foloseste un pipeline in 2 etape:

  • Screening: analiza rapida cu un model LLM rapid
  • Deep Analysis: analiza detaliata pe fiecare dimensiune/categorie detectata

Fiecare etapa are 3 nivele de fallback (primary -> fallback_1 -> fallback_2 -> fallback_3).


Structura fisierelor

src/
  index.ts                              -- Server Express, middleware, montare rute
  api/                                  -- Rute organizate pe subdirectoare (fiecare *-routes.ts la root e shim de re-export)
    routes.ts / techniques.ts           -- Endpoint-uri Techniques (+ /health general)
    ai-tampered/                        -- Endpoint-uri AI-Tampered
    claims/                             -- Endpoint-uri Claims (analyze, config, results)
    source-assessment/                  -- Endpoint-uri Source Assessment (config, models, stage-assignments, analyze)
    domain.ts                           -- Endpoint-uri Domain (legacy)
    media.ts                            -- Endpoint-uri Media/Fisiere (upload/download MinIO)
    pipeline/                           -- Pipeline complet + Istoric + Extensie + dry-run.ts + cancel.ts (cancel/resume) + async.ts
    moderation/                         -- HIL Moderation (queue.ts, flag-stats.ts, _gold-promotion.ts, _middleware.ts)
  components/
    component-runner.ts                 -- Orchestrator direct (invocare executori fara HTTP intern)
    techniques/
      executor.ts                       -- Executor Techniques: screening -> deep analysis -> scoring (params din Redis)
    ai-tampered/
      executor.ts                       -- Executor AI-Tampered: disclosure check -> screening -> deep -> scoring (params din Redis)
    claims/
      executor.ts                       -- Executor Claims: extractie afirmatii -> verificare web -> scoring (params din Redis)
    source-assessment/
      executor.ts                       -- Executor Source Assessment: extractie sursa -> M17 search -> evaluare (params din Redis)
    moderation/
      triage.ts                         -- Decide daca o sesiune intra in coada review (config Redis, feature-flag `triage_enabled`)
      queue-manager.ts                  -- Operatii PG pe `bos_analysis.moderation_queue` (enqueue/list/get/claim/resolve/stats)
    pipeline/
      executor.ts                       -- Orchestrator pipeline: ruleaza toate componentele + verdict
      verdict-calculator.ts             -- Calcul verdict cu input profiles per tip input (params din Redis)
      verdict-explanation.ts            -- Generare explicatie bilingva (RO+EN) via LLM
      virality-calculator.ts            -- Calcul scor viralitate (factori: emotie, urgenta, reach)
      types.ts                          -- Tipuri interne pipeline
  shared/
    media/
      transcription.ts                  -- Transcriere audio: M17-Whisper -> Groq -> OpenAI (fallback chain)
      vision.ts                         -- Analiza imagine: Qwen Local -> Gemini Flash -> GPT-4o (fallback chain)
      video-processor.ts               -- Pipeline video: download -> extrage cadre -> transcriere + viziune
      media-service.ts                  -- Interfata unificata media (download, format, cleanup)
    persistence/
      persist-service.ts                -- Coordonare Redis (cache) + PostgreSQL (permanent)
      pg-adapter.ts                     -- Adaptor PostgreSQL: save/load/history/delete pe schema bos_analysis
      pg-pool.ts                        -- Pool conexiuni PostgreSQL (singleton)
    redis/
      connection.ts                     -- Factory centralizat ioredis (ACL ready, retry, reconnectOnError)
      keys.ts                           -- Registru central chei Redis
      session-store.ts                  -- Stocare sesiuni in Redis ca JSON (TTL 7 zile)
    brain/
      client.ts                         -- Client didi-brain: gather cu verification lookup + write cache + analysis atom lookup/write/patch (gold/silver/bronze tiers, fire-and-forget writes)
    queue/
      constants.ts                      -- Topologie cozi: exchange, routing keys, prioritati
    types/
      component-results.ts              -- Definitii tipuri pentru toate cele 5 rezultate componente
      analysis-session.ts               -- Tipul AnalysisSession (wrapper root al unei analize)
      api-responses.ts                  -- Tipuri raspunsuri API (success/error envelope)
    test-utils/
      fixtures.ts                       -- Date de test (sesiuni, rezultate componente)
      mock-pg.ts                        -- Mock PostgreSQL pool pentru teste
      mock-redis.ts                     -- Mock Redis pentru teste
    helpers/
      empty-media-response.ts           -- Raspuns standardizat cand media nu are continut text
    auth/
      jwt-verify.ts                     -- Verificare criptografica JWT RS256 via Keycloak JWKS (Modul 7)
      guards.ts                         -- Route guards (resolveUserId, authRequired, requireRole, ROLES_ADMIN)
    observability/
      metrics.ts                        -- Metrici Prometheus business + OTel tracing + /metrics server workeri (Modul 8)
      queue-depth-poller.ts             -- Poller RabbitMQ Management API → gauge didi_queue_depth / didi_active_workers
    credits.ts                          -- Verificare si deducere credite utilizator (via didiFramework)
  config/
    analysisLimits.ts                   -- Limite text: min 20, max 50000 caractere + validare UTF-8
  queue/
    dispatcher.ts                       -- Dispatch mesaje catre RabbitMQ (async)
    connection.ts                       -- Manager conexiune RabbitMQ
    aggregator.ts                       -- Agregator verdict (consuma rezultate componente)
    types.ts                            -- Tipuri mesaje coada (dispatch, result, etc.)
    workers/
      component-worker.ts              -- Worker generic (consuma din coada, ruleaza componenta)
      techniques-worker.ts             -- Worker Techniques (config)
      ai-tampered-worker.ts            -- Worker AI-Tampered (config)
      claims-worker.ts                 -- Worker Claims (config)
  worker-entrypoints/
    techniques.ts                       -- Entry point Docker: worker techniques (2 replici)
    ai-tampered.ts                      -- Entry point Docker: worker ai-tampered (2 replici)
    claims.ts                           -- Entry point Docker: worker claims (3 replici)
    domain.ts                           -- Entry point Docker: worker domain (2 replici)
    aggregator.ts                       -- Entry point Docker: verdict aggregator (2 replici)
  scripts/
    export-schemas.ts                   -- Export scheme Zod ca JSON Schema
    init-priority-queues.ts             -- Initializare cozi RabbitMQ cu prioritati

Nota: queue/constants.ts (topologie cozi: exchange, routing keys, prioritati) se afla la shared/queue/constants.ts.


API - Toate endpoint-urile

General (/api/v3)

Metoda Path Ce face Logica in fisier
GET /health Health check (raspunde cu service name, version, timestamp) api/routes.ts

Nota: /health este montat pe routerul /api/v3, deci path-ul complet este /api/v3/health.

Techniques (/api/v3/techniques)

Metoda Path Ce face Logica in fisier
GET /definitions Ierarhie completa tehnici din Redis (dimensiuni -> subdimensiuni -> tehnici) api/routes.ts
GET /config Configurare completa din Redis api/routes.ts
GET /models Lista modele LLM disponibile api/routes.ts
GET /stage-assignments Configurare etape (screening/deep) api/routes.ts
PUT /stage-assignments Actualizeaza configurare etape api/routes.ts
POST /test-model Testeaza conexiunea la un model LLM api/routes.ts
POST /test-openrouter Testeaza OpenRouter cu provider routing api/routes.ts
POST /analyze Analiza text sincrona api/routes.ts -> components/techniques/executor.ts
POST /analyze-media Analiza media sincrona (imagine/audio/video) api/routes.ts -> shared/media/* -> components/techniques/executor.ts
POST /analyze-async Analiza asincrona via RabbitMQ api/routes.ts -> queue/dispatcher.ts
GET /results/:sessionId Rezultate intermediare din Redis api/routes.ts

AI-Tampered (/api/v3/ai-tampered)

Metoda Path Ce face Logica in fisier
GET /health Health check api/ai-tampered-routes.ts
GET /config Configurare completa din Redis api/ai-tampered-routes.ts
GET /models Lista modele LLM api/ai-tampered-routes.ts
GET /categories Categorii + ierarhie indicatori AI api/ai-tampered-routes.ts
GET /stage-assignments Configurare etape api/ai-tampered-routes.ts
PUT /stage-assignments Actualizeaza configurare etape api/ai-tampered-routes.ts
POST /quick Analiza rapida fara LLM (doar euristici) api/ai-tampered-routes.ts -> components/ai-tampered/executor.ts
POST /analyze Analiza text completa cu LLM api/ai-tampered-routes.ts -> components/ai-tampered/executor.ts
POST /analyze-image Analiza imagine pentru AI (doar viziune) api/ai-tampered-routes.ts -> shared/media/vision.ts
POST /analyze-media Analiza media sincrona api/ai-tampered-routes.ts -> shared/media/* -> components/ai-tampered/executor.ts
POST /analyze-async Analiza asincrona via RabbitMQ api/ai-tampered-routes.ts -> queue/dispatcher.ts
GET /results/:sessionId Rezultate intermediare din Redis api/ai-tampered-routes.ts
POST /test-model Testeaza model LLM api/ai-tampered-routes.ts

Claims (/api/v3/claims)

Metoda Path Ce face Logica in fisier
GET /health Health check api/claims-routes.ts
GET /config Configurare + tipuri/statusuri din framework api/claims-routes.ts
GET /types Tipuri de afirmatii (VF, EF, RE, etc.) api/claims-routes.ts
GET /statuses Statusuri verificare (VT, LT, UV, etc.) api/claims-routes.ts
GET /models Lista modele LLM api/claims-routes.ts
GET /stage-assignments Configurare etape api/claims-routes.ts
PUT /stage-assignments Actualizeaza configurare etape api/claims-routes.ts
POST /analyze Analiza text: extractie + verificare afirmatii api/claims-routes.ts -> components/claims/executor.ts
POST /analyze-media Analiza media sincrona api/claims-routes.ts -> shared/media/* -> components/claims/executor.ts
POST /analyze-async Analiza asincrona via RabbitMQ api/claims-routes.ts -> queue/dispatcher.ts
GET /results/:sessionId Rezultate intermediare din Redis api/claims-routes.ts
POST /test-model Testeaza model LLM api/claims-routes.ts

Pipeline complet (/api/v3/pipeline)

Metoda Path Ce face Logica in fisier
POST /analyze Analiza completa sincrona (toate componentele) api/pipeline-routes.ts -> components/pipeline/executor.ts
POST /analyze-url Analiza URL inteligenta (detecteaza YouTube, imagine, articol) api/pipeline-routes.ts -> shared/media/video-processor.ts
POST /analyze-media Analiza media sincrona (shortcut) api/pipeline-routes.ts -> components/pipeline/executor.ts
POST /analyze-async Analiza completa asincrona via RabbitMQ api/pipeline-routes.ts -> queue/dispatcher.ts
GET /:sessionId/status Status sesiune (polling) api/pipeline-routes.ts -> shared/redis/session-store.ts
GET /:sessionId/component/:name Rezultat o singura componenta api/pipeline-routes.ts -> shared/redis/session-store.ts
GET /:sessionId/result Rezultat complet sesiune api/pipeline-routes.ts -> shared/persistence/persist-service.ts
GET /:sessionId/queue-status Status coada async (progres %) api/pipeline-routes.ts -> queue/dispatcher.ts
GET /queue-health Sanatate RabbitMQ api/pipeline-routes.ts -> queue/connection.ts
GET /verdict-config Configurare verdict (categorii, ponderi, override-uri din Redis) api/pipeline-routes.ts
POST /dry-run Rezolvă planul complet de execuție fără dispatch (ce componente rulează/skip + de ce, chain-uri model/tier, profil verdict). Read-only: fără session id, fără credite, fără mesaje. Modul 1. api/pipeline/dry-run.ts
POST /:sessionId/cancel Anulează o sesiune în execuție (flag Redis; workerii short-circuit, aggregator finalizează canceled). Idempotent, owner/admin. api/pipeline/cancel.ts
POST /:sessionId/resume Resume din checkpoint — re-dispatch DOAR componentele necompletate (dispatcher.resumeDispatch). Owner/admin. api/pipeline/cancel.ts

Istoric (/api/v3/pipeline)

Metoda Path Ce face Logica in fisier
GET /history Istoric utilizator paginat api/pipeline-routes.ts -> shared/persistence/pg-adapter.ts
GET /history/:id O intrare din istoric api/pipeline-routes.ts -> shared/persistence/persist-service.ts
DELETE /history/:id Sterge intrare din istoric api/pipeline-routes.ts -> shared/persistence/persist-service.ts
GET /history/admin Istoric admin (toti utilizatorii, filtre) api/pipeline-routes.ts -> shared/persistence/pg-adapter.ts
GET /history/admin/:id O intrare admin api/pipeline-routes.ts -> shared/persistence/persist-service.ts
DELETE /history/admin/:id Sterge intrare admin api/pipeline-routes.ts -> shared/persistence/persist-service.ts

Extensie browser (/api/v3/pipeline/extension)

Metoda Path Ce face Logica in fisier
POST /analyze Analiza via API key (nu JWT) api/pipeline-routes.ts -> components/pipeline/executor.ts
POST /keys Creeaza API key pentru extensie api/pipeline-routes.ts (proxy -> didiFramework)
GET /keys Lista API keys api/pipeline-routes.ts (proxy -> didiFramework)
DELETE /keys/:id Sterge API key api/pipeline-routes.ts (proxy -> didiFramework)

Media/Fisiere (/api/v3/media)

Metoda Path Ce face Logica in fisier
POST /upload-url Obtine URL presemnat pentru upload in MinIO api/routes.ts
POST /upload Upload direct fisier (multipart, max 50MB) api/routes.ts
POST /download-url Obtine URL presemnat pentru download din MinIO api/routes.ts
GET /file/:bucket/{*objectKey} Proxy servire fisiere din MinIO (suporta range requests, Express 5 wildcard) api/routes.ts

Source Assessment (/api/v3/source-assessment)

Metoda Path Ce face Logica in fisier
GET /health Health check api/source-assessment-routes.ts
GET /config Configurare (scoring_config + framework sources) api/source-assessment-routes.ts
GET /models Modele LLM disponibile api/source-assessment-routes.ts
GET /stage-assignments Configurare etape api/source-assessment-routes.ts
PUT /stage-assignments Actualizeaza etape api/source-assessment-routes.ts
POST /test-model Test conectivitate model api/source-assessment-routes.ts
POST /analyze Analiza sursa (text + optional URL) api/source-assessment-routes.ts -> components/source-assessment/executor.ts
POST /analyze-media Analiza sursa din media api/source-assessment-routes.ts

Domain (/api/v3/domain) — LEGACY, inlocuit de Source Assessment

Metoda Path Ce face Logica in fisier
POST /analyze Analiza domeniu sincrona (apeleaza Domain Check API extern) api/routes.ts
POST /analyze-async Analiza domeniu asincrona api/routes.ts -> queue/dispatcher.ts

HIL Moderation (/api/v3/moderation)

Metoda Path Roluri permise Ce face Logica in fisier
GET /queue admin, moderator, senior_moderator Listeaza coada review (filtre: status CSV, priority CSV, assigned_to=me|user) api/moderation-routes.ts -> components/moderation/queue-manager.ts
GET /queue/:queueId admin, moderator, senior_moderator Intrare coada + sesiunea analiza JOIN-ed api/moderation-routes.ts -> components/moderation/queue-manager.ts
POST /queue/:queueId/claim moderator, senior_moderator Claim atomic (UPDATE conditionat pe pending) — assigneaza la user-ul JWT api/moderation-routes.ts -> components/moderation/queue-manager.ts
PUT /queue/:queueId/resolve moderator, senior_moderator Resolve cu actiune approved | corrected | rejected + corrections JSONB diff api/moderation-routes.ts -> components/moderation/queue-manager.ts -> shared/brain/client.ts (PATCH atom gold)
POST /flag orice user autenticat Flag user (extensie browser) — enqueue review api/moderation-routes.ts -> components/moderation/queue-manager.ts
GET /stats admin, moderator, senior_moderator Counts pe tier/component + hit_rate_24h api/moderation-routes.ts -> components/moderation/queue-manager.ts

Auth (Faza D done 2026-05-02): requireRole() și requireAuth() din moderation-routes.ts aplică role check strict când STAGING_MODE=false (production). În staging (STAGING_MODE=true, default actual): GET-urile de read trec fără JWT (legacy), /flag cere body user_id sau JWT. Vezi IMPLEMENTATION_PLAN_HIL_BRAIN.md Faza D pentru permission matrix completa.

Constants in moderation-routes.ts:

  • ROLES_READ = ['admin', 'moderator', 'senior_moderator'] — citire queue/stats
  • ROLES_WRITE = ['moderator', 'senior_moderator'] — claim/resolve (admin nu modifică queue, doar vede)
  • STAGING = process.env.STAGING_MODE === 'true' — controller pentru soft auth fallback

Autentificare JWT (Modul 7)

Fișier: src/shared/auth/jwt-verify.ts (+ guards în src/shared/auth/guards.ts).

Verificare criptografică a token-urilor JWT — nu doar la gateway, ci și în backend, deci un acces direct pe :24803 (bypass Kong) sau prin nginx-ul admin-dashboard este la fel de protejat.

  • RS256 via Keycloak JWKS: fiecare Bearer JWT e verificat împotriva JWKS-ului realm-ului emitent (didi-clients / didi-admins, allow-list JWT_ALLOWED_REALMS). JWKS descărcat remote și cache-uit per realm (createRemoteJWKSet din jose).
  • Respinge cu 401 (error_code: JWT_INVALID): token forjat (semnătură invalidă pe cheile noastre), expirat/nbf (validare exp/nbf), sau emis de un realm foreign (issuer în afara allow-list). Un token cu issuer didi-* spoofat tot pică pe semnătură.
  • Fără header Authorization → request rămâne anonim (route guards decid). Bearer non-JWT (API key opac) trece netransformat.
  • jwtIdentityMiddleware() populează req.jwtUserId / req.jwtEmail / req.jwtRoles din payload-ul verificat (realm_access.roles).
  • Env: KEYCLOAK_URL (default http://didi-keycloak:8080/auth), JWT_ALLOWED_REALMS, JWT_VERIFY_ENABLED (false → decode-only, doar dev, cu warning zgomotos).

Observabilitate (Modul 8)

Fișiere: src/shared/observability/metrics.ts + src/shared/observability/queue-depth-poller.ts.

Metrici Prometheus (client prom-client), inclusiv metrici business DiDi:

  • didi_analyses_completed_total / didi_analyses_failed_total (labels: component, tier, media_type, verdict/reason)
  • didi_pipeline_duration_seconds (histogram, per component+tier)
  • didi_llm_calls_total + didi_llm_tokens_total (provider, model, component)
  • didi_brain_cache_hits_total / ..._misses_total (verification + atom)
  • didi_queue_depth + didi_active_workers (gauge, per component+plan) — alimentate de queue-depth-poller.ts care interoghează RabbitMQ Management API la 30s (fail-open)
  • didi_dlq_messages_total, didi_http_requests_total, didi_http_request_duration_seconds + default Node/process metrics

Server /metrics: expus de agent-v3 (Express) și de fiecare container worker via startWorkerMetricsServer() (workerii n-au app Express, deci server HTTP minimal dedicat pentru scrape).

OpenTelemetry tracing: initObservability() pornește OTel NodeSDK cu auto-instrumentations (Express, http, redis, amqplib, pg) când OTEL_EXPORTER_OTLP_ENDPOINT e setat (default http://didi-otel-collector:4317); altfel disabled.

Spec OpenAPI

Fișier: openapi.yaml la root-ul serviciului (OpenAPI 3.0.3, Modulele 1-3). Descrie toate endpoint-urile (async 202 + poll, pipeline cu dependențe explicite, dry-run/cancel/resume, istoric, moderare HIL). Security: bearerAuth (JWT Keycloak RS256 verificat în backend, nu doar la gateway).

Fluxul de date

Analiza text (sincrona)

Request POST /api/v3/pipeline/analyze { text }
  |
  v
Validare text (20-50000 caractere) + Verificare credite
  |
  v
PipelineExecutor.execute()
  |
  v
ComponentRunner.runAll() -- ruleaza in paralel:
  |-- TechniquesV3Executor: screening -> deep analysis -> manipulation_score
  |-- AITamperedExecutor:   disclosure check -> screening -> deep -> ai_probability
  |-- ClaimsExecutor:       extractie afirmatii -> brain /v1/gather (cache check + evidence) -> fresh HIT skip LLM / miss: LLM verificare + fire-and-forget cache write -> credibility_score
  |-- analyzeDomain():      analiza locala (daca exista URL) -> trust_score
  |
  v
VerdictCalculator.calculate() -- functie pura, fara I/O
  |-- Selecteaza INPUT PROFILE per input_type (din Redis didi:config:pipeline:v1:input_profiles)
  |     Profiluri: text_no_url, text_with_url, image, audio, video, url
  |     Fiecare profil defineste: ponderi, override-uri active, reguli INCONCLUSIVE
  |-- Extrage scoruri componente (0-100)
  |-- Aplica ponderi din profil (ex: image: ai=50%, tech=20%, claims=15%, source=15%)
  |     Fallback la ponderi globale daca profilul nu exista
  |-- Aplica multiplicator topic INAINTE de override (nu amplifica bonusurile)
  |-- Aplica override-uri din profil (doar cele activate per input type):
  |     - synergy_bonus: 2+ componente cu risc >= threshold (+bonus/componenta, max cap)
  |     - false_claims: afirmatii false (+bonus/claim, max cap)
  |     - unverified_verifiable: claims verificabile neverificate (bonus fix)
  |     - severe_techniques: tehnici severe (bonus fix)
  |     - undisclosed_ai: AI nedeclarat (bonus fix)
  |     - untrusted_source: sursa neincrezuta/suspecta (bonus fix, din source_assessment)
  |     - blacklisted_source: sursa pe lista neagra (bonus fix, din source_assessment)
  |     - source_red_flags: red flags sursa (+bonus/flag, max cap)
  |     - override cap total per profil (default 50)
  |-- Rotunjire inainte de mapare la categorii
  |-- Mapare la risk_category, risk_level, severity (din Redis)
  |-- Calcul confidence (bonusuri/penalitati din profil)
  |-- INCONCLUSIVE check din profil (componenta primara crapat, min_components, required_any)
  |-- Virality: delegat la virality-calculator.ts (scor + factori + nivel)
  |
  v
PersistService.persist() -- salveaza in Redis + PostgreSQL
  |
  v
Response: AnalysisSession cu toate componentele

Analiza media (audio/video)

Request POST /api/v3/techniques/analyze-media { media_url, media_type }
  |
  v
Verificare credite
  |
  v
Procesare media:
  |-- Audio: transcribe() via M17-Whisper -> Groq -> OpenAI
  |-- Video: download (yt-dlp) -> extrage cadre (ffmpeg) -> transcriere + viziune
  |-- Imagine: callVision() OCR -> text extras
  |
  v
Text extras -> TechniquesV3Executor (la fel ca text)
  |
  v
PersistService.persist()
  |
  v
Response: AnalysisSession cu metadata extractie (durata, provider, cadre analizate)

Analiza asincrona

Request POST /api/v3/pipeline/analyze-async { text/media_url, plan_type }
  |
  v
Validare + Creditare
  |
  v
Dispatcher.dispatch() -> publica in RabbitMQ
  |
  v
Response 202: { session_id, poll_url, result_url }

--- In fundal (workeri Docker separati) ---

ComponentWorker consuma din coada -> ruleaza componenta -> publica rezultat in analysis.results
  |
  v
Aggregator consuma din analysis.results -> asteapta toate componentele -> VerdictCalculator
  |
  v
PersistService.persist() -> sesiune finala in Redis + PostgreSQL

--- Clientul polleaza ---

GET /api/v3/pipeline/{sessionId}/queue-status -> progres + componente finalizate
GET /api/v3/pipeline/{sessionId}/result -> sesiune completa cand status=completed

Servicii externe apelate

Serviciu Scop Unde in cod
Redis local (didi-cache:6379, DB 0, parolă redis123) Config framework + cache sesiuni (TTL 7 zile), acces prin createRedisConnection() shared/redis/*
PostgreSQL 17 local (didi-postgres:5432, DB DIDI, user bos_interface) Stocare permanenta (schema bos_analysis) shared/persistence/*
RabbitMQ local (staging-dataLayer-rabbitmq:5672, vhost /, user admin) Cozi async pentru workeri queue/*
MinIO (9000) Stocare fisiere media api/routes.ts (media endpoints)
OpenRouter API Modele LLM (Gemini, GPT-4o, Claude, etc.) components/*/executor.ts
OpenAI API LLM fallback + Whisper transcriere components/*/executor.ts, shared/media/transcription.ts
Groq API LLM fallback + Whisper transcriere components/*/executor.ts, shared/media/transcription.ts
M17-Whisper (M17_WHISPER_URL, default http://10.11.10.17:54300, configurabil din env) Transcriere audio primara shared/media/transcription.ts
M17 Web API (10.11.10.13:51100) Fallback cautare web — folosit cand brain dezactivat sau MISS fara evidence components/claims/executor.ts, components/source-assessment/executor.ts
didi-brain (Lot 1, DIDI_BRAIN_URL default http://10.11.10.12:8090) Verification cache claims (/v1/gather, /v1/verification_cache) + analysis atom cache techniques/ai-tampered (/v1/analysis_atom*) — vezi „Integrare cu platforma AI (Lot 1)" shared/brain/client.ts, components/*/executor.ts
Vision LLM (Lot 1, VISION_LLM_URL default http://10.11.10.17:14011) Analiza imagine (OCR + AI detection) shared/media/vision.ts
Domain Check API (:11000) Analiza domeniu (WHOIS, DNS, SSL, blacklist) api/routes.ts (domain/analyze)
didiFramework (didi-framework:3005) Verificare/deducere credite + API keys extensie + sync framework → Redis local shared/credits.ts, api/pipeline-routes.ts

Baza de date PostgreSQL

Schema: bos_analysis

Tabel Ce stocheaza Cheie
analysis_session Sesiunea root: user, input, status, timing, risk_score session_id (UUID)
analysis_techniques Rezultat componenta Techniques (JSONB: techniques_detected, coupling_context) session_id FK
analysis_ai_tampered Rezultat componenta AI-Tampered (JSONB: indicators_detected, image_analysis) session_id FK
analysis_claims Rezultat componenta Claims (JSONB: claims_verified, claims_by_status) session_id FK
analysis_domain Rezultat componenta Domain (trust_score, red_flags TEXT[], warnings) session_id FK
analysis_verdict Verdict final (risk_score, JSONB: applied_weights, context_summary) session_id FK
moderation_queue Coada review HIL (FK → analysis_session.session_id UUID): tier, priority, status, assigned_to, corrections JSONB queue_id (UUID)

Tabelul analysis_session are 6 coloane suplimentare pentru HIL: review_status, human_corrected, human_corrections (JSONB), verified_by, verified_at, review_notes (adaugate via migration 011_add_moderation.sql rulata de didiFramework).

In schema bos_parammgmt, didiFramework owneste 3 tabele de config citite de agent-v3 prin Redis: moderation_config (single row), sensitive_topic, moderation_role.

Salvarea este tranzactionala (all-or-nothing). Ce produce componenta = ce se salveaza (zero transformari).


Chei Redis importante

Framework (FrameworkKeys) — permanente, scrise de didiFramework sync-redis

Cheie Scop
didi:framework:manifest Index categorii config
didi:framework:techniques Ierarhie tehnici: dimensiuni -> subdimensiuni -> tehnici -> indicatori
didi:framework:sources Parametri credibilitate sursa
didi:framework:claims Parametri claims (tipuri, statusuri, confidence)
didi:framework:verdicts Categorii verdict, risk mappings, severity assessments
didi:framework:weights Ponderi componente, scenarii, multiplicatori
didi:framework:providers Config provideri LLM (optional)
didi:framework:dimensions_compact Lista compacta dimensiuni pentru prompts screening

Config componente (ConfigKeys) — permanente, scrise de didiFramework sync-redis

Toate stage_assignments sunt tier-nested (structura {stage_code: {free: {...}, premium: {...}}}) dupa migration 006 (tier column). Chain-urile de modele sunt diferite per tier — vezi sectiunea "Tier-aware execution" de mai sus.

Cheie Scop
didi:config:pipeline:v1:component_config Config executor pipeline + video track weights
didi:config:pipeline:v1:session_config Config sesiune pipeline
didi:config:pipeline:v1:verdict_config Override-uri, synergy, confidence (globale, fallback)
didi:config:pipeline:v1:input_profiles Profiluri verdict per input type (6 profile cu ponderi, override-uri, INCONCLUSIVE rules)
didi:config:techniques:v3:available_models Modele LLM Techniques (union free + premium)
didi:config:techniques:v3:stage_assignments Tier-nested asignari etape Techniques
didi:config:techniques:v3:scoring_config Parametri scoring: count_scaler, severe_threshold, intensity bonus, bonuses
didi:config:techniques:v3:dimensions_compact Lista compacta dimensiuni Techniques
didi:config:claims:v1:available_models Modele LLM Claims (union free + premium)
didi:config:claims:v1:stage_assignments Tier-nested asignari etape Claims
didi:config:claims:v1:scoring_config Parametri scoring: status_weights, unverified behavior, claim_type_weights
didi:config:ai-tampered:v1:available_models Modele LLM AI-Tampered (union free + premium)
didi:config:ai-tampered:v1:stage_assignments Tier-nested asignari etape AI-Tampered
didi:config:ai-tampered:v1:scoring_config Parametri scoring: blend_weights, disclosure_impact, thresholds, undisclosed_threshold
didi:config:ai-tampered:v1:vision_models Legacy flat vision config (fallback — nou e didi:config:vision:v1:stage_assignments)
didi:config:source-assessment:v1:available_models Modele LLM Source Assessment (union free + premium)
didi:config:source-assessment:v1:stage_assignments Tier-nested asignari etape Source Assessment
didi:config:source-assessment:v1:scoring_config Parametri scoring: axis_weights, verdict_thresholds
didi:config:source-assessment:v1:prompts:extraction Prompt extractie metadata sursa
didi:config:source-assessment:v1:prompts:evaluation Prompt evaluare sursa cu categorii framework
didi:config:verdict:v1:stage_assignments Tier-nested asignari Verdict reviewer (stage: verdict_review)
didi:config:verdict:v1:available_models Legacy fallback pentru verdict-explanation.ts
didi:config:vision:v1:stage_assignments Tier-nested asignari Vision (stage: image_analysis — OCR + AI detection + video frames)
didi:config:vision:v1:prompts:extraction Prompt viziune: extractie text din imagine
didi:config:vision:v1:prompts:video_frames Prompt viziune: analiza cadre video
didi:config:vision:v1:prompts:ai_detection Prompt viziune: detectie AI in imagine
didi:config:moderation:v1:settings Setari moderation + brain client (thresholds: confidence_low, risk_grey_min/max, feature flags: triage_enabled, brain_enabled, brain_url, brain_lookup_timeout_ms, brain_per_component) — citit cu cache 60s
didi:config:moderation:v1:sensitive_topics Lista topice sensibile pentru triage (auto-enqueue daca match)
didi:config:moderation:v1:roles Map roluri moderation (folosit la role check soft)

Toate cheile config au corespondent in PG (bos_parammgmt.component_config + component_prompt + component_stage_assignment + moderation_config + sensitive_topic + moderation_role). Sync-redis le citeste din PG si le scrie in Redis. Admin dashboard editeaza PG, apoi sync to Redis.

Sesiuni pipeline (SessionKeys) — TTL 7 zile

Pattern Scop
didi:pipeline:{sessionId}:status Status executie pipeline (JSON: PipelineStatus)
didi:pipeline:{sessionId}:{component} Rezultat componenta (JSON: TechniquesResult etc.)
didi:pipeline:{sessionId}:verdict Verdict final (JSON: VerdictResult)

Istoric (HistoryKeys) — TTL 7 zile

Pattern Scop
didi:pipeline:history:entry:{sessionId} Date intrare istoric (JSON: input + metadata)
didi:pipeline:history:user:{userId} Sorted set istoric utilizator (score=timestamp, member=sessionId)

Coada (QueueKeys) — TTL scurt (30s-5min)

Pattern Scop
didi:queue:session:{sessionId} Stare fan-in agregare (JSON: partial AnalysisSession)
didi:queue:lock:{sessionId}:{component} Lock executie componenta (previne duplicare worker)
didi:queue:aggregator:{sessionId} Lock agregator (previne calcul verdict concurent)

Rezultate intermediare (AgentKeys) — TTL 7 zile

Pattern Scop
agent:result:{sessionId}:{component}:{stage} Rezultat intermediar etapa (screening, deep_analysis)
agent:result:{sessionId}:ai-tampered:visual Rezultat analiza vizuala AI
agent:result:{sessionId}:ai-tampered:final Rezultat final AI tampered (media merged)
agent:result:{sessionId}:ai-tampered:media Rezultat intermediar AI tampered media

Media cache (MediaCacheKeys) — TTL 1 ora

Scrise de media-preprocess worker. Citite de component workers.

Pattern Scop
agent:media:{sessionId}:transcript Transcript audio (Whisper)
agent:media:{sessionId}:vision:misinformation Output Vision frames — analiza manipulare
agent:media:{sessionId}:vision:ai_detection Output Vision frames — detectie AI
agent:media:{sessionId}:merged_text Transcript + vision misinformation (pentru techniques + claims)
agent:media:{sessionId}:lock Lock procesare media (previne duplicare)
agent:media:{sessionId}:ready Semnal finalizare pre-procesare ("1")

Extensie (ExtensionKeys) — permanente

Pattern Scop
didi:extension:key:{apiKey} Cache API key extensie browser

Docker Compose - Servicii

Serviciu Replici Rol
agent-v3 1 Server API principal (port 24803)
worker-media-preprocess 2 Pre-procesare media: 1× download, 1× ffmpeg, 1× transcriptie, 2× Vision. Cache in Redis. Dispatche-aza component workers.
worker-techniques 2 Consuma din coada techniques. Citeste media din Redis cache.
worker-ai-tampered 2 Consuma din coada ai-tampered. Citeste media din Redis cache. 2-track video scoring (text 40% + visual 60%).
worker-claims 3 Consuma din coada claims (mai lent, mai multe replici). Citeste merged_text din Redis cache (transcript + text vizual).
worker-domain 2 Consuma din coada domain
verdict-aggregator 2 Colecteaza rezultate si calculeaza verdict

Dependinte sistem in container: ffmpeg, yt-dlp, python3 (pentru video download si procesare).

Fluxul async media (video/audio/image)

POST /api/v3/pipeline/analyze-async { media_type: "video" }
  |
  v
Dispatcher → analysis.media_preprocess.{plan} (1 task)
  |
  v
MediaPreprocessWorker:
  1. Download video (1×)
  2. ffmpeg: extract frames uniform (1×) + extract audio (1×)
  3. Whisper: transcriere audio (1×)
  4. Vision misinformation: analiza frames (1×)
  5. Vision ai_detection: analiza frames (1×)
  6. Salveaza in Redis (TTL 1h):
     - agent:media:{sid}:transcript
     - agent:media:{sid}:vision:misinformation
     - agent:media:{sid}:vision:ai_detection
     - agent:media:{sid}:merged_text
     - agent:media:{sid}:ready
  7. Dispatche-aza: techniques + ai_tampered + claims (+ domain daca URL)
  |
  v
Component Workers (citesc din Redis cache, zero download/ffmpeg):
  - techniques: primeste merged_text (transcript + vizual)
  - ai_tampered: primeste transcript (Track 1 text) + vision:ai_detection (Track 2 visual)
  - claims: primeste merged_text (transcript + text vizibil de pe ecran)
  - domain: primeste doar URL (skip pe media fara URL)
  |
  v
Verdict Aggregator → verdict (neschimbat)

Fallback: daca media preprocess esueaza, component workers proceseaza media local (safety net).

Fluxul async text/URL (neschimbat)

Dispatcher → direct la component workers (fara media preprocess).


Timeout-uri pe rute

Ruta Timeout Motiv
/api/v3/pipeline/* 660s (11 min) Download video + transcriere + analiza completa
/api/v3/techniques/analyze-media 300s (5 min) Transcriere media + analiza
/api/v3/ai-tampered/analyze-media 300s (5 min) Procesare media + analiza
/api/v3/claims/analyze-media 300s (5 min) Transcriere + extractie + verificare
Toate celelalte 180s (3 min) Analiza text standard (server.timeout)
keepAliveTimeout 665s Usor mai mare decat max per-route timeout
headersTimeout 670s Usor mai mare decat keepAliveTimeout

Tipuri de raspuns

AnalysisSession (raspuns standard pentru toate analizele)

{
  session_id, user_id, user_email,
  input_type (text/url/image/audio/video),
  input_text, input_url, input_media_url,
  input_hash,                               // SHA256
  status (pending/running/completed/failed),
  components_run[], components_skipped[],
  risk_score, risk_category, risk_level,
  confidence, confidence_level,
  started_at, completed_at, total_duration_ms,
  scenario_applied, topic_applied,
  source_app, api_version: "v3",
  created_at,

  techniques: {
    manipulation_score, total_severity, dimensions_affected[], techniques_count,
    techniques_detected[], coupling_context,
    llm_screening, llm_deep,
    screening_duration_ms, deep_analysis_duration_ms, total_duration_ms,
    fallbacks_screening, fallbacks_deep
  },
  ai_tampered: {
    ai_probability, verdict, risk_score, categories_affected[], indicators_count,
    disclosure_detected, disclosure_explicit, disclosure_text,
    indicators_detected[], coupling_context,
    llm_screening, llm_deep,
    screening_duration_ms, deep_analysis_duration_ms, total_duration_ms,
    fallbacks_screening, fallbacks_deep,
    content_type, image_analysis
  },
  claims: {
    total_claims, verified_true, verified_false, unverified, opinions,
    credibility_score, interpretation,
    claims_by_status, claims_by_type, claims_verified[],
    llm_extraction, llm_verification,
    extraction_duration_ms, verification_duration_ms, total_duration_ms,
    web_searches_made
  },
  domain: { domain, trust_score, verdict, risk_level, red_flags[], warnings[], duration_ms, ... },
  verdict: {
    risk_score, risk_category, risk_category_color,
    risk_level, risk_level_color,
    severity, recommended_action,
    confidence, confidence_level,
    score_manipulation, score_claims, score_ai, score_source, score_context,
    applied_weights, override_applied, override_type, override_reason, override_adjustment,
    context_summary, components_used[], weights_source, duration_ms,
    explanation_ro, explanation_en,
    virality_score, virality_level, virality_factors[]
  }
}

Raspuns async (202 Accepted)

{
  success: true, async: true,
  data: { session_id, status: "processing", queued_components[], plan_type, poll_url, result_url }
}

Raspuns media gol (cand nu s-a extras text din media)

{
  success: true,
  data: {
    session_id, status: "completed",
    input_type, input_media_url, media_type,
    skipped: true, skip_reason: "no_text_content" | "transcription_failed" | "vision_failed" | "extraction_failed",
    message: "...",
    techniques: null, ai_tampered: null, claims: null, domain: null, verdict: null,
    components_run: [], components_skipped: ["techniques", "ai_tampered", "claims"],
    risk_score: null, risk_category: null,
    metadata: { extraction_duration_ms, provider_tried }
  }
}

Schimbari de logica (2026-03-20)

Verdict INCONCLUSIVE determinist pe media fara claims

Fisier: components/pipeline/verdict-calculator.ts

Daca claims nu a produs rezultat (null) pe input video/audio/image → forteaza risk_category = INCONCLUSIVE. Inainte, LLM reviewer-ul decidea (inconsistent: +14 pe un video, +45 pe altul identic). Acum e determinist in cod.

LLM reviewer-ul (verdict-explanation.ts) nu mai penalizeaza pentru componente lipsa — instructiune explicita in prompt.

Claims primeste text vizual din video frames

Fisier: queue/workers/component-worker.ts

Claims primeste merged_text (transcript audio + text vizibil de pe ecran) in loc de doar transcript. Permite verificarea afirmatiilor scrise pe ecran (titluri, statistici, URL-uri).

Prompt-ul claims extraction (Redis didi:config:claims:v1:prompts:extraction) instruieste LLM-ul sa distinga intre text citat de pe ecran (extrage ca claim) si observatii Vision AI (ignora).

AI Tampered video: ponderi 40% text + 60% vizual

Fisier: queue/workers/component-worker.ts

Ponderile 2-track video scoring inversate: text 40% + vizual 60% (era text 60% + vizual 40%). Deepfake-uri cu voce reala dar fete AI primeau scor mic (34%) — vizualul trebuie sa domine pe video.

Prag minim text track: 200 chars. Sub 200 chars, text track e skip-uit si vizualul primeste 100% weight.

Prompt AI detection Vision — 3 tiere forensic

Redis: didi:config:vision:v1:prompts:ai_detection

Tier 1: artefacte grosolane (warping, extra fingers) → AI_CONFIDENCE 75-95 Tier 2: indicii subtile deepfake modern (face-background mismatch, skin uniformity, hair boundary, eye reflections) → AI_CONFIDENCE 45-75 Tier 3: evaluare context (face closeup TV = minim 30, nu 0) → AI_CONFIDENCE 30-40

AI_CONFIDENCE: 0 interzis pe face closeup video.

Techniques: intensity bonus diminishing returns

Fisier: components/techniques/executor.ts

Formula veche (liniara): (avgIntensity - 1) * 0.05 → intensity 8 = 0.35 (35pp bonus) Formula noua (sqrt + cap): min(0.15, sqrt(avgIntensity - 1) * 0.05) → intensity 8 = 0.13 (13pp bonus)

Previne scor 100% pe editoriale/jurnalism de investigatie cu ton puternic dar fara manipulare reala.

Limite durata media

Fisiere: api/pipeline-routes.ts (API check), shared/media/video-processor.ts (ffprobe check)

  • Video: max 180s (3 minute)
  • Audio: max 420s (7 minute)

Doua guard-uri: API (instant, daca frontend trimite media_duration_sec) + ffprobe (dupa download, safety net).

Optimizari claims

Fisiere: components/claims/executor.ts, components/component-runner.ts

  • Claims global timeout: 300s → 600s
  • Claims Qwen timeout: 60s → 120s (Redis config)
  • Claims cap: 10 → 7 (skip low priority)
  • Chunks paralele: 3 → 5
  • Transcript trunchiat la 4000 chars pentru claims pe media

Video frame sampling uniform

Fisier: shared/media/video-processor.ts

Inainte: fps=1/5 secvential → frames doar din primele 50s. Video 5 min = 83% ignorat. Acum: interval dinamic = durata / maxFrames → acoperire uniforma 100%. Minim 3 frames pe orice video.


Funcționalități suplimentare (în afara celor 9 module de caiet)

Secțiunile de mai jos sunt cod backend real, dar reprezintă funcționalitate în plus față de cele 9 module ale caietului de sarcini. Tot aici se încadrează și Tier-aware execution (premium vs free), Virality (virality-calculator.ts) și HIL Moderation (secțiunea următoare). Logica internă a brain-ului (RAG, tiering atom pe brain-side) aparține platformei AI (Lot 1); aici e descrisă doar integrarea client-side din agent-v3.

Brain v2 Atom Cache (integrare client-side)

Brain v2 introduce un cache de rezultate de analiza per componenta (analysis atoms), in plus fata de verification cache-ul existent pentru claims. Salveaza output-ul deep analysis pentru techniques si ai_tampered indexat pe (content_hash, component, tier, prompt_hash, framework_version). Hit fresh + tier potrivit (gold/silver) → skip LLM complet.

Tier-uri atom

Tier Cum se obtine Cum se foloseste
gold Promovat manual via PATCH din HIL Moderation (action: approved sau corrected) Hit fresh gold → folosit cu prioritate maxima
silver Auto-scris de agent-v3 dupa fiecare analiza reusita pe tier premium Hit fresh silver → folosit (overridable de gold)
bronze Tier intermediar pe brain side (rezervat) Ignorat de agent-v3 (skip LLM doar pe gold OR silver)

Brain refuza scrieri pentru tier free — atoms scrise doar din premium analyses (calitate consistenta).

Client extensie (src/shared/brain/client.ts)

Pe langa helperele existente (gatherFromBrain, writeVerificationCacheAsync, evidenceOverlap), clientul expune:

  • lookupAnalysisAtom({ content_hash, component, tier, prompt_hash, framework_version }){ atom_id, data: AnalysisAtomData, cache_tier: AtomCacheTier, staleness: AtomStaleness } | null
  • writeAnalysisAtomAsync(payload) — fire-and-forget POST /v1/analysis_atom, doar pentru tier = premium
  • patchAnalysisAtomGold(atomId, corrections) — promoveaza atom la gold cu corectiile umane (apelat din moderation-routes.ts pe resolve)
  • helpers: computeContentHash(text), computePromptHash(prompt), computeFrameworkVersion(...)
  • types: AnalysisAtomData, AtomCacheTier ('gold' | 'silver' | 'bronze'), AtomStaleness ('fresh' | 'stale_framework' | 'stale_prompt' | 'miss')

Config & feature flags (Redis: didi:config:moderation:v1:settings, cache 60s)

Cheie Rol
brain_enabled Master switch — false → toate apelurile atom skip-uite, fallback direct LLM
brain_url Override per environment (default DIDI_BRAIN_URL env)
brain_lookup_timeout_ms Timeout per lookup (default tipic 800ms)
brain_per_component Granular: {techniques: bool, ai_tampered: bool, claims: bool}

Fail-open in toate cazurile: orice eroare brain (timeout, 5xx, network, feature flag off) → continua cu LLM. Atom cache nu poate bloca o analiza.

Integrare in executoare

Atat components/techniques/executor.ts cat si components/ai-tampered/executor.ts:

execute(input):
  // START — atom lookup
  if (brain_enabled && brain_per_component[component]) {
    atom = await lookupAnalysisAtom({ content_hash, component, tier, prompt_hash, framework_version })
    if (atom && atom.staleness === 'fresh' && (atom.cache_tier === 'gold' || atom.cache_tier === 'silver')) {
      return atomToComponentResult(atom.data)   // skip LLM complet
    }
  }

  // ... screening + deep analysis (LLM normal flow) ...

  // END — atom write (happy path AND early-exit branches)
  writeAnalysisAtomAsync({ ... })   // fire-and-forget, doar tier=premium
  return result

Atom write e plasat pe ambele ramuri (happy path si early-exit pe disclosure detected / no techniques) — orice rezultat reprezentativ se cache-uieste.

Promovare la gold via HIL

In moderation-routes.ts handler-ul PUT /queue/:queueId/resolve:

  • action = 'approved' → patch atomii existenti per componenta (techniques, ai_tampered, claims) la gold (semnal: omul confirma rezultatul automat)
  • action = 'corrected' → patch atomii la gold cu corrections aplicate (omul a editat output-ul automat — varianta corectata devine fontul de adevar)
  • action = 'rejected' → nu touch-uie atoms (rezultatul a fost gresit, dar nu avem corectie validata)

PATCH-ul foloseste (content_hash, component, tier, prompt_hash, framework_version) pentru a localiza atomii potriviti pe brain side.

Endpoint-uri brain v2 folosite

Metoda Path Folosit de
POST /v1/analysis_atom/lookup lookupAnalysisAtom() la START in techniques + ai-tampered
POST /v1/analysis_atom writeAnalysisAtomAsync() la END in techniques + ai-tampered (premium only)
PATCH /v1/analysis_atom/{id} patchAnalysisAtomGold() din HIL resolve
GET /v1/analysis_atom/stats Endpoint diagnostic (folosit la nevoie)
POST /v1/gather Existent — claims (verification cache lookup + evidence)
POST /v1/verification_cache Existent — claims write

HIL Moderation

Human-in-the-loop pentru sesiuni cu confidence scazut, scor in zona gri, sau topice sensibile. Triage-ul ruleaza dupa persistenta (NU blocheaza analiza) si decide daca sesiunea intra in coada de review uman. Moderatorii claim & resolve via REST API; rezolutiile pozitive (approved/corrected) promoveaza atomii la gold in brain.

Triage (src/components/moderation/triage.ts)

Citeste config din Redis (didi:config:moderation:v1:settings, cache 60s):

Threshold Rol
confidence_low Sub aceasta valoare → enqueue review (model nesigur)
risk_grey_min/max Banda gri risk_score (ex. 40-60) → enqueue review (rezultat ambiguu)
sensitive_topics Match in continut → enqueue review automat

Feature-flag protected: triage_enabled = false → triage no-op total.

Queue manager (src/components/moderation/queue-manager.ts)

Operatii directe pe bos_analysis.moderation_queue via shared/persistence/pg-pool.ts:

Functie Ce face
enqueueForReview(session, reason, priority) Idempotent — skip daca exista deja entry pending pentru acest session_id
listQueue(filters) Listare cu filtre status CSV, priority CSV, assigned_to
getQueueEntry(queueId) Entry + JOIN pe analysis_session (sesiunea full)
claimQueueEntry(queueId, userId) UPDATE atomic conditionat pe status = 'pending'
resolveQueueEntry(queueId, action, corrections, notes) UPDATE status + scrie human_corrected / human_corrections / verified_by / verified_at pe analysis_session
getQueueStats() Counts pe tier/component + hit_rate_24h

Integrare in pipeline

Triage hook apelat dupa persistService.persist(session) in:

  • src/components/pipeline/executor.ts (sync path)
  • src/queue/aggregator.ts (async path)

Wrapping try/catch — orice eroare in triage e log-uita, NU se propaga. Analiza nu se blocheaza niciodata din cauza moderation.

Role check soft

Middleware-ul JWT (src/index.ts) extrage req.jwtRoles din realm_access.roles. Endpoint-urile /api/v3/moderation/*:

  • Staging fara JWT roles (Keycloak nu trimite role): permit (pentru testing)
  • Productie cu JWT: require rol moderator (sau echivalent din didi:config:moderation:v1:roles)

Politica e soft (permit pe absent) ca sa nu blocheze flows-uri de testare interne.

userFlagged flow

POST /api/v3/moderation/flag permite oricarui user autenticat (sau extensiei browser) sa raporteze o sesiune. Cand sesiunea e creata cu user_flagged = true (request body field), flag-ul e plumbed prin:

  • PipelineInput.userFlagged (components/pipeline/types.ts)
  • SessionState.userFlagged (queue/types.ts)
  • api/pipeline-routes.ts extrage din body si forward-eaza

Triage citeste flag-ul si forteaza enqueue indiferent de threshold-uri (semnal uman = priority).