File size: 4,500 Bytes
de3503b
3ae1f10
de97f37
24059db
3ae1f10
 
de3503b
24059db
 
3ae1f10
de3503b
24059db
 
 
de3503b
 
 
24059db
de3503b
 
24059db
de3503b
 
 
 
24059db
f297a4a
3ae1f10
 
567fe9c
3ae1f10
 
24059db
3ae1f10
 
 
24059db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
de97f37
 
 
 
3ae1f10
 
 
f297a4a
 
 
 
 
24059db
3ae1f10
f297a4a
 
 
 
24059db
3ae1f10
 
 
 
24059db
de97f37
f297a4a
3ae1f10
 
de97f37
24059db
3ae1f10
 
 
 
f297a4a
24059db
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
117
118
119
120
121
122
123
124
125
126
127
from fastapi import FastAPI
from pydantic import BaseModel
import chromadb
from chromadb.config import Settings
from sentence_transformers import SentenceTransformer
import os
import google.generativeai as genai
import pandas as pd
import numpy as np

# === 1. Configurer le cache dans /tmp/ (accessible en écriture) ===
os.environ['HF_HOME'] = '/tmp/huggingface'
os.environ['TRANSFORMERS_CACHE'] = '/tmp/huggingface'
os.makedirs('/tmp/huggingface', exist_ok=True)

# === 2. Charger le modèle avec gestion des erreurs ===
try:
    model = SentenceTransformer('all-MiniLM-L6-v2', cache_folder='/tmp/huggingface')
except Exception as e:
    print(f"Erreur de chargement (nom court): {e}")
    model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2', cache_folder='/tmp/huggingface')

# === 3. Configurer ChromaDB dans /tmp/ ===
client = chromadb.PersistentClient(path="/tmp/chroma_db")

# === 4. Configurer Gemini ===
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
genai.configure(api_key=GEMINI_API_KEY)
model_gemini = genai.GenerativeModel("gemini-2.0-flash-lite")

app = FastAPI()

# === Classe Query pour FastAPI ===
class Query(BaseModel):
    query: str

# === Fonction d'initialisation de la collection ===
def init_collection():
    # Essaie de récupérer la collection, sinon la crée et l'initialise
    try:
        collection = client.get_collection("Festivals")
        print("Collection 'Festivals' chargée")
    except Exception:
        print("Collection 'Festivals' non trouvée, création et remplissage...")
        collection = client.create_collection(name="Festivals", metadata={"hnsw:space": "ip"})
        
        # Ici tu dois récupérer tes données (ex: depuis Airtable)
        # Exemple fictif avec dataframe statique, remplace par ta vraie fonction fetch_data()
        df = pd.DataFrame([
            {
                "Festival Name": "Hellfest",
                "City": "Clisson",
                "Country": "France",
                "Dates": "15-18 Juin",
                "Genre": "Metal/Rock",
                "Ticket Price (EUR)": 200,
                "Accommodation option": "Camping",
                "Atmosphere": "Festive"
            },
            {
                "Festival Name": "Sziget",
                "City": "Budapest",
                "Country": "Hongrie",
                "Dates": "10-15 Août",
                "Genre": "Divers",
                "Ticket Price (EUR)": 150,
                "Accommodation option": "Tentes",
                "Atmosphere": "Jeune et dynamique"
            }
        ])

        embeddings, metadatas, ids = [], [], []
        for idx, row in df.iterrows():
            row_text = "\n".join([f"{col}: {val}" for col, val in row.items() if pd.notna(val)])
            embedding = model.encode(row_text)
            embedding /= np.linalg.norm(embedding)
            embeddings.append(embedding.tolist())
            metadatas.append({k: str(v) for k, v in row.items() if pd.notna(v)})
            ids.append(f"fest_{idx}")

        collection.add(embeddings=embeddings, metadatas=metadatas, ids=ids)
        print(f"Collection 'Festivals' initialisée avec {len(ids)} entrées")

    return collection


# === Initialisation au démarrage ===
collection = init_collection()


@app.get("/")
async def root():
    return {"message": "🎵 GrooveNomad Festivals API est en ligne !"}

@app.post("/api/ask")
async def ask_festival(data: Query):
    query_embedding = model.encode(data.query).tolist()
    results = collection.query(
        query_embeddings=[query_embedding],
        n_results=3,
        include=["metadatas", "distances"]
    )

    def get_val(meta, key):
        val = meta.get(key)
        if not val or str(val).lower() in ["", "nan", "none"]:
            return "Non spécifié"
        return val

    context = "\n".join([
        f"{get_val(m, 'Festival Name')} à {get_val(m, 'City')} ({get_val(m, 'Country')}) le {get_val(m, 'Dates')} 🎶 {get_val(m, 'Genre')}{get_val(m, 'Ticket Price (EUR)')}€"
        for m in results["metadatas"][0]
    ])

    prompt = f"""Tu es un expert des festivals. Voici la requête :
\"{data.query}\"
Voici les options :
{context}
Génère une réponse naturelle, enthousiaste, concise, avec des emojis."""

    try:
        response = model_gemini.generate_content(prompt)
        return {"response": response.text}
    except Exception as e:
        print(f"Erreur lors de la génération : {e}")
        return {"error": str(e)}