# 🔄 Sibilla — Diagramma di Flusso
> **Versione:** 0.2.0
> **Ultimo aggiornamento:** 18 Luglio 2026
---
## Pipeline di Ricerca Completa (Mermaid)
```mermaid
flowchart TD
A["👤 Utente invia query"] --> B["🌐 Web UI (POST /api/ask)
o
🔗 API (GET/POST /api/v1/query)"]
B --> C["🔮 Query Expansion
Gemini genera 3 varianti"]
C --> D{"🔍 Degoog
disponibile?"}
D -->|✅ Sì| E["Cerca con Degoog
prime 2 varianti"]
D -->|❌ No| F{"🔍 SearXNG
disponibile?"}
E --> G{"Risultati
trovati?"}
G -->|✅ Sì| H["Aggrega risultati
Dedup URL"]
G -->|❌ No| F
F -->|✅ Sì| I["Cerca con SearXNG
prime 2 varianti"]
F -->|❌ No| J["🔍 DuckDuckGo
fallback"]
I --> K{"Risultati
trovati?"}
K -->|✅ Sì| H
K -->|❌ No| J
J --> L{"Risultati
trovati?"}
L -->|✅ Sì| H
L -->|❌ No| M{"Tutti i backend
falliti?"}
M -->|✅ Sì| N["⚠️ Fallback Pure LLM
Gemini risponde senza fonti"]
M -->|❌ No| O["❌ Errore: 502
Restituisci errore"]
H --> P["📥 PageFetcher
Scarica full content
max 5 pagine, 300ms delay"]
P --> Q["📝 Build Prompt
Fonti numerate + data"]
Q --> R["🧠 Gemini Synthesis
SYNTHESIS_SYSTEM_PROMPT
temp=0.4, max_tokens=4096"]
R --> S["✅ JSON Response
answer + html_answer
+ speakable_text + sources"]
N --> T["✅ JSON Response
solo LLM, nessuna fonte"]
style A fill:#a78bfa,color:#fff
style S fill:#34d399,color:#000
style T fill:#fbbf24,color:#000
style O fill:#f87171,color:#fff
style R fill:#8b5cf6,color:#fff
```
---
## Flusso Richiesta Web (Frontend)
```mermaid
sequenceDiagram
actor U as 👤 Utente
participant B as Browser (app.js)
participant F as Flask /api/ask
participant P as Pipeline
participant G as Gemini
participant S as Search Engines
U->>B: Scrivi query e clicca "Interroga"
B->>B: Disabilita form, mostra spinner
B->>F: POST /api/ask {query}
F->>P: _run_search_pipeline(query, num_sources)
P->>G: rewrite_query(query, 3 varianti)
G-->>P: [originale, var1, var2, var3]
P->>S: Degoog.search(var1) + Degoog.search(var2)
S-->>P: SearchResponse {results[]}
P->>S: PageFetcher.fetch_results(top5)
S-->>P: SearchResult[] con full_content
P->>G: synthesize(system_prompt, user_prompt)
G-->>P: SynthesisResult {answer, tokens}
P-->>F: enriched[], response_data
F-->>B: JSON {answer, html_answer, speakable_text, sources[]}
B->>B: Render HTML answer, mostra fonti
B->>U: Mostra risultato
```
---
## Flusso API v1
```mermaid
sequenceDiagram
actor C as 🔗 Client (curl/Lambda)
participant F as Flask /api/v1/query
participant P as Pipeline
participant G as Gemini
participant S as Search Engines
C->>F: GET /api/v1/query?q=domanda
F->>F: Estrai query da query string
F->>P: _run_search_pipeline(query, num_sources=5)
P->>G: rewrite_query(query, 3 varianti)
G-->>P: [originale, var1, var2, var3]
alt Degoog OK
P->>S: Degoog.search(varianti)
S-->>P: Risultati
else SearXNG fallback
P->>S: SearXNG.search(varianti)
S-->>P: Risultati
else DuckDuckGo fallback
P->>S: DDG.search(query)
S-->>P: Risultati
else Pure LLM
P->>G: synthesize(FALLBACK_PROMPT, query)
G-->>P: Risposta senza fonti
end
P->>S: PageFetcher.fetch_results(top5)
S-->>P: Contenuti completi
P->>G: synthesize(SYNTHESIS_PROMPT, fonti)
G-->>P: SynthesisResult
P-->>F: enriched[], response_data
F-->>C: JSON {query, answer, speakable_text, sources[]}
```
---
## Flusso MCP Server
```mermaid
sequenceDiagram
actor A as 🤖 AI Agent (Claude/Gemini)
participant M as MCP Server (stdio)
participant D as DegoogClient
participant S as SearXNGClient
participant G as DuckDuckGoClient
participant F as PageFetcher
A->>M: JSON-RPC: initialize
M-->>A: {protocolVersion, capabilities, serverInfo}
A->>M: JSON-RPC: tools/list
M-->>A: {tools: [web_search, fetch_page]}
A->>M: JSON-RPC: tools/call {name: "web_search", arguments: {query: "..."}}
M->>D: search(query)
alt Degoog ha risultati
D-->>M: SearchResponse
else Degoog vuoto
M->>S: search(query)
alt SearXNG ha risultati
S-->>M: SearchResponse
else Entrambi vuoti
M->>G: search(query)
G-->>M: SearchResponse
end
end
M-->>A: {content: [{text: "Risultati formattati..."}]}
A->>M: JSON-RPC: tools/call {name: "fetch_page", arguments: {url: "..."}}
M->>F: fetch(url)
F-->>M: Testo estratto (max 8000 chars)
M-->>A: {content: [{text: "Contenuto pagina..."}]}
```
---
## Macchina a Stati: Pipeline di Ricerca
```mermaid
stateDiagram-v2
[*] --> ReceivingQuery: Utente invia query
ReceivingQuery --> QueryExpansion: Query valida
ReceivingQuery --> Error400: Query vuota
QueryExpansion --> DegoogSearch: Gemini espande query
DegoogSearch --> AggregatingResults: Risultati trovati
DegoogSearch --> SearXNGFallback: Nessun risultato
SearXNGFallback --> AggregatingResults: Risultati trovati
SearXNGFallback --> DDGFallback: Nessun risultato
DDGFallback --> AggregatingResults: Risultati trovati
DDGFallback --> PureLLMFallback: Nessun risultato
AggregatingResults --> FetchingContent: Dedup URL completato
FetchingContent --> BuildingPrompt: Full content scaricato
BuildingPrompt --> Synthesizing: Prompt assemblato
Synthesizing --> ReturningResponse: Sintesi completata
Synthesizing --> ReturningErrorResponse: Errore Gemini
PureLLMFallback --> SynthesizingFallback: Usa FALLBACK_PROMPT
SynthesizingFallback --> ReturningFallback: Risposta senza fonti
Error400 --> [*]
ReturningResponse --> [*]
ReturningErrorResponse --> [*]
ReturningFallback --> [*]
```
---
## Diagramma dei Componenti
```mermaid
graph TB
subgraph "Interfacce Utente"
WEB["🌐 Web UI
templates/index.html
static/app.js"]
API["🔗 REST API
/api/ask
/api/v1/query"]
MCP["🤖 MCP Server
stdio JSON-RPC"]
end
subgraph "Flask Application"
APP["app.py
Flask App Factory"]
PIPELINE["_run_search_pipeline()
Pipeline condivisa"]
end
subgraph "Servizi Core"
AI["ai.py
GeminiClient"]
SEARCH["search.py"]
MD["markdown.py
Render + Strip"]
PROMPTS["prompts.py
System Prompts"]
end
subgraph "Backend Esterni"
GEMINI["🧠 Google Gemini API
gemini-2.5-flash"]
DEGOOG["🔍 Degoog
self-hosted"]
SEARXNG["🔍 SearXNG
self-hosted"]
DDG["🔍 DuckDuckGo
HTML scraping"]
end
WEB --> APP
API --> APP
MCP --> SEARCH
APP --> PIPELINE
PIPELINE --> AI
PIPELINE --> SEARCH
PIPELINE --> PROMPTS
PIPELINE --> MD
AI --> GEMINI
SEARCH --> DEGOOG
SEARCH --> SEARXNG
SEARCH --> DDG
```
---
## Strategia di Query Expansion
```mermaid
flowchart LR
Q["Query originale:
'ultimo film sull Odissea'"] --> GE["Gemini rewrite_query()"]
GE --> V1["Variante 1:
film Odissea 2026 recensione"]
GE --> V2["Variante 2:
ultimo adattamento cinematografico Odissea"]
GE --> V3["Variante 3:
The Odyssey movie latest release"]
V1 --> D1["Degoog search"]
V2 --> D2["Degoog search"]
D1 --> AGG["Aggregazione
+ Deduplicazione"]
D2 --> AGG
```
---
## Legenda
| Simbolo | Significato |
|---------|------------|
| 🔍 | Motore di ricerca |
| 🧠 | LLM / AI |
| 📥 | Fetch / Download |
| 📝 | Costruzione prompt |
| ✅ | Successo |
| ❌ | Errore / Fallimento |
| ⚠️ | Degraded mode |
| 👤 | Interazione utente |
| 🔗 | API / Programmatico |
| 🤖 | Agente AI esterno |