File size: 5,064 Bytes
c3231de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da7bd93
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import os
import pytz
import gradio as gr
from datetime import datetime
from pinecone import Pinecone
from llama_index.llms.groq import Groq
from llama_index.core import VectorStoreIndex, Settings
from llama_index.vector_stores.pinecone import PineconeVectorStore
from llama_index.embeddings.huggingface import HuggingFaceEmbedding

# --- CONFIGURAZIONE ---
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")

if not GROQ_API_KEY or not PINECONE_API_KEY:
    raise ValueError("⚠️ ERRORE CRITICO: API Keys mancanti nei Secrets!")

# --- SETUP MODELLI ---
embed_model = HuggingFaceEmbedding(model_name="intfloat/multilingual-e5-large")
Settings.embed_model = embed_model

llm = Groq(model="llama-3.3-70b-versatile", api_key=GROQ_API_KEY)
Settings.llm = llm

# --- MOTORE RAG ---
def get_chat_engine():
    try:
        pc = Pinecone(api_key=PINECONE_API_KEY)
        index = VectorStoreIndex.from_vector_store(
            vector_store=PineconeVectorStore(
                pinecone_index=pc.Index("prometheus-demo"),
                namespace="accessibility-poc"
            )
        )

        system_prompt = (
            "Sei Prometheus, un assistente virtuale per l'Accessibilità e il Turismo Inclusivo. "
            "Il tuo compito è fornire informazioni utili come se fossi un operatore esperto allo sportello informazioni."
            "\n\n"
            "🚫 DIVIETI ASSOLUTI DI LINGUAGGIO (Blacklist): "
            "- MAI usare parole come: 'scheda tecnica', 'json', 'database', 'record', 'file', 'documento', 'valore', 'campo', 'null'. "
            "- EVITA frasi come: 'In base ai dati', 'Secondo la scheda', 'Il sistema dice che'. "
            "\n\n"
            "🧠 DIZIONARIO SEMANTICO (Interpretazione): "
            "- 'ingresso_senza_gradini: true' = 'L'ingresso è in piano / senza barriere'. "
            "- 'ingresso_senza_gradini: false' = 'Sono presenti gradini all'ingresso'. "
            "- 'bagni_accessibili: true' = 'È disponibile un bagno attrezzato'. "
            "\n\n"
            "✅ REGOLE DI RISPOSTA (Stile Conversazionale): "
            "1. **Conferme (True)**: Rispondi direttamente. Es: 'Sì, confermo che la struttura è dotata di ascensore.' "
            "2. **Negazioni (False)**: Sii gentile. Es: 'Purtroppo al momento non risulta presente un servizio di audioguida.' "
            "3. **Dati Mancanti (Null/Assente)**: Non citare la scheda. Di' semplicemente: 'Non ho informazioni aggiornate su questo specifico servizio.' oppure 'Al momento non mi risulta questa informazione, ti consiglio di verificare contattando la struttura.' "
            "4. **Note (Stringhe)**: Integra le note nel discorso. Es: 'Ti segnalo però che l'ascensore è attualmente in manutenzione.' "
            "5. **FEDELTÀ ASSOLUTA (Anti-Allucinazione)**: Attieniti ESCLUSIVAMENTE ai fatti forniti nel contesto. Non aggiungere MAI commenti personali, supposizioni o frasi di circostanza (come 'ho sentito dire')."
            "\n\n"
            "OBIETTIVO: Sii neutrale, preciso e disponibile. L'utente deve sentirsi aiutato da una persona competente."
        )

        return index.as_chat_engine(
            chat_mode="condense_plus_context",
            system_prompt=system_prompt,
            verbose=True
        )
    except Exception as e:
        print(f"Errore inizializzazione chat engine: {e}")
        return None

chat_engine = get_chat_engine()

# --- INTERFACCIA UTENTE ---
def respond(message, history):
    if chat_engine is None:
        return "⚠️ Servizio momentaneamente non disponibile."
    try:
        fuso_italia = pytz.timezone("Europe/Rome")
        adesso = datetime.now(fuso_italia)
        ora_data = adesso.strftime("%A %d %B %Y, ore %H:%M")
        messaggio_con_data = f"[Oggi è {ora_data}]\n{message}"
        return str(chat_engine.chat(messaggio_con_data))
    except Exception as e:
        print(f"❌ ERRORE in chat: {type(e).__name__}: {e}")
        return "Mi scuso, al momento non riesco a recuperare questa informazione."

disclaimer = """
<div style="
    margin-top: 24px;
    padding: 12px 20px;
    border-top: 1px solid #d1d5db;
    background-color: #f9fafb;
    border-radius: 8px;
    text-align: center;
    font-size: 13px;
    color: #6b7280;
    line-height: 1.6;
">
    <strong>Versione dimostrativa</strong> &mdash;
    Questa applicazione è a scopo esclusivamente illustrativo.
    Tutte le strutture, i dati e le informazioni presenti sono fittizi
    e non corrispondono a realtà esistenti.
</div>
"""

demo = gr.ChatInterface(
    fn=respond,
    title="ℹ️ Sportello Accessibilità - Prometheus",
    description="Chiedimi informazioni sui servizi per persone con disabilità di agriturismi nella provincia di Siena.<br>Applicazione dimostrativa con strutture fittizie.",
    examples=["Ci sono agriturismi accessibili a Siena?", "Parcheggi per disabili?"],
    cache_examples=False
)

with demo:
    gr.HTML(disclaimer)

if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=7860)