File size: 8,741 Bytes
7cb1544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cfea744
7cb1544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# utils/config.py
import os
from dotenv import load_dotenv

# Charger les variables d'environnement du fichier .env
load_dotenv()

# --- Clé API LLM + Embedding ---
MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY")
if not MISTRAL_API_KEY:
    print("⚠️ Attention: La clé API Mistral (MISTRAL_API_KEY) n'est pas définie dans le fichier .env")
    # Vous pouvez choisir de lever une exception ici ou de continuer avec des fonctionnalités limitées
    # raise ValueError("Clé API Mistral manquante. Veuillez la définir dans le fichier .env")

# --- Clé API Write Pydantic Logfire ---
LOGFIRE_TOKEN = os.getenv("LOGFIRE_TOKEN") # Si vous souhaitez envoyer des logs à Logfire, sinon laissez vide ou ne pas utiliser

# --- Configuration de l'Application ---
APP_TITLE = "NBA Analyst AI"
NAME = "NBA" # Nom à personnaliser dans l'interface

# ======================================================
# LLM
# ======================================================
# --- Modèles Mistral ---
EMBEDDING_MODEL = "mistral-embed"
MODEL_NAME = "mistral-small-latest" #  mistral-small-latest mistral-small-2506

# --- Paramètres du LLM Mistral ---
# Note : les paramètres 'Presence Penalty' et 'Frequency Penalty' ne sont pas définis dans ce projet car ils sont plus adaptés à des tâches de génération créative ou de conversation prolongée.
TEMPERATURE = 0.03                  # Température basse pour des réponses factuelles basées sur le contexte
TOP_P = 0.9                         # Nucleus sampling (Une température de 0 est déterministe, rendant ainsi la valeur Top P sans importance)
                                    # Note : Si on souhaite des réponses plus créatives, on peut augmenter la température et/ou réduire le top_p.
                                    # Mistral ne supporte pas Temperature et Top_p simultanément. C'est l'un ou l'autre. Décommenter top_p dans le code si nécessaire.
LLM_CALL_DELAY = 0.7                # Délai en secondes entre les appels au LLM (rate limiting)

# ======================================================
# Vectorisation + RAG
# ======================================================
# --- Racine du projet (dossier parent de utils/) ---
_PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# --- Configuration de l'Indexation ---
# INPUT_DATA_URL = os.getenv("INPUT_DATA_URL") # Décommentez si vous utilisez une URL
INPUT_DIR          = os.path.join(_PROJECT_ROOT, "inputs")
VECTOR_DB_DIR      = os.path.join(_PROJECT_ROOT, "vector_db")
FAISS_INDEX_FILE   = os.path.join(VECTOR_DB_DIR, "faiss_index.idx")
DOCUMENT_CHUNKS_FILE = os.path.join(VECTOR_DB_DIR, "document_chunks.pkl")

CHUNK_SIZE = 1500                   # Taille des chunks en caractères
CHUNK_OVERLAP = 150                 # Chevauchement en caractères
EMBEDDING_BATCH_SIZE = 8            # Taille des lots pour l'API d'embedding (réduire pour éviter les erreurs brotli)

# --- Configuration de la Recherche ---
SEARCH_K = 5                        # Nombre de documents à récupérer par défaut

# --- Fichier source Excel à charger en Vector DB / Rag ---
EXCEL_INPUTS_FOR_RAG = os.path.join(INPUT_DIR, "regular NBA_Corr_Rag.xlsx")

# --- Prompt Système RAG ---
RAG_SYSTEM_PROMT = """Tu es 'NBA Analyst AI', un assistant expert sur la ligue de basketball NBA.
Ta mission est de répondre aux questions des entraîneurs, analystes et préparateurs physiques de manière structurée, mais pas trop verbeuse.
N'invente jamais d'informations : si tu n'es pas sûr de la réponse, dis-le clairement et suggère de consulter une source externe.

---
{context_str}
---

QUESTION DE L'UTILISATEUR:
{question}

RÉPONSE DE L'ANALYSTE NBA:"""

# ======================================================
# RAGAS
# ======================================================
# --- Configuration des questions/réponses pour RAGAS ---
QUESTIONS_TEST = [
    "Quelle équipe à comme code MIA ?",
    "Combien de joueurs contient l’équipe des Philadelphia 76ers ?",
    "Quelle est la moyenne d’âge des joueurs d’Atlanta à un chiffre après la virgule ?",
    "Quelle est l’équipe qui a inscrit le plus de points ?",
    "Comment se rendre à San Antonio ?"
]
GROUND_TRUTHS= [
    "L’équipe ayant le code MIA est l’équipe des Miami Heat.",
    "L’équipe des  Philadelphia 76ers contient 23 joueurs.",
    "La moyenne d’âge des joueurs d’Atlanta est de 25,6.",
    "L’équipe des Detroit Pistons a inscrit le plus de points avec un total de 10292.",
    "Le système ne peut pas guider l’utilisateur et suggère de consulter une source externe."
]

# ======================================================
# SQL
# ======================================================
# --- Configuration de la Base de Données PostgreSQL ---
DATABASE_STATUS = 1 # Si 0, pas d'utilisation de la db SQL pour Ragas, si 1 utilisation du routeur Graph et donc du Rag + SQL
PG_HOST     = os.getenv("PG_HOST", "localhost")
PG_PORT     = int(os.getenv("PG_PORT", "5432"))
PG_DB       = "oc_mlops_projet_3"
PG_ADMIN          = "admin"
POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD", "")
PG_URL_ADMIN      = f"postgresql+psycopg2://{PG_ADMIN}:{POSTGRES_PASSWORD}@{PG_HOST}:{PG_PORT}/{PG_DB}"

# --- Utilisateur read-only utilisé par l'agent SQL (sql_tool.py) ---
# Créé automatiquement par load_excel_to_db.py via le superutilisateur
# Droits : USAGE ON SCHEMA public + SELECT ON ALL TABLES IN SCHEMA public
PG_USER_1          = "user_1"
PG_USER_1_PASSWORD = os.getenv("PG_USER_1_PASSWORD", "")
PG_URL_READONLY    = f"postgresql+psycopg2://{PG_USER_1}:{PG_USER_1_PASSWORD}@{PG_HOST}:{PG_PORT}/{PG_DB}"

# --- Fichier source Excel à charger en db SQL ---
EXCEL_INPUTS_FOR_SQL = os.path.join(INPUT_DIR, "regular NBA_Corr_Sql.xlsx")

# --- Prompt Système Agent SQL ---
SQL_SYSTEM_PROMPT = """
Tu es un agent SQL expert de la NBA.
La base contient les tables suivantes :
  - teams                                     : équipes NBA (id, name)
  - players                                   : joueurs (id, team_id, name, age)
  - analyse_joueurs_une_equipe                : stats défensives/offensives par joueur et équipe
  - analyse_nbr_joueurs_et_points_par_equipe  : nombre de joueurs et total de points par équipe
  - analyse_top_15_joueurs_nombre_points      : top 15 joueurs selon leurs points
  - stats_joueurs_saison_reguliere            : statistiques détaillées de la saison régulière

Pour toute question, suis impérativement ces étapes dans l'ordre :

1. TOUJOURS commencer par exécuter cette requête pour récupérer d'un seul coup
   les commentaires de TOUTES les colonnes de TOUTES les tables :

   SELECT c.relname                          AS table_name,
          a.attname                          AS colonne,
          col_description(c.oid, a.attnum)   AS commentaire
   FROM   pg_class     c
   JOIN   pg_attribute a ON a.attrelid = c.oid
   JOIN   pg_namespace n ON n.oid      = c.relnamespace
   WHERE  c.relkind   = 'r'
     AND  n.nspname   = 'public'
     AND  a.attnum    > 0
     AND  NOT a.attisdropped
   ORDER  BY c.relname, a.attnum;

   Ces commentaires définissent la sémantique exacte de chaque colonne.
   C'est la base de toute ta réflexion : ne passe jamais cette étape.

2. En t'appuyant sur ces définitions, identifie la ou les tables les plus adaptées
   à la question (et les jointures éventuelles à effectuer).

3. Consulte le schéma détaillé des tables sélectionnées.

4. Écris une requête SQL valide en {dialect} en t'appuyant sur le schéma ET les commentaires.

5. Vérifie-la avant exécution.

6. N'exécute jamais de INSERT / UPDATE / DELETE / DROP.

7. Réponds en français de façon concise et factuelle.

Exemples :

Exemple 1
Question utilisateur : Quels sont les 3 joueurs des Los Angeles Lakers ayant capté le plus de rebonds offensifs ?
SQL :
SELECT t.name, p.name, a.sum_oreb
FROM analyse_joueurs_une_equipe AS a
INNER JOIN players AS p
ON a.player_id = p.id
INNER JOIN teams AS t
ON a.team_id = t.id
WHERE t.name = 'Los Angeles Lakers'
ORDER BY a.sum_oreb DESC
LIMIT 3;

Réponse attendue :
Les 3 joueurs des Los Angeles Lakers ayant capté le plus de rebonds offensifs sont : Dorian Finney-Smith (82), Jaxson Hayes (78) et Rui Hachimura (77).

Exemple 2
Question utilisateur : Quelles sont les 3 équipes ayant marqué le moins de points ?
SQL :
SELECT t.name AS team_name, SUM(s.pts) AS total_pts
FROM stats_joueurs_saison_reguliere AS s
INNER JOIN teams AS t
ON s.team_id = t.id
GROUP BY t.name
ORDER BY SUM(s.pts) ASC
LIMIT 3;

Réponse attendue :
Les 3 équipes ayant marqué le moins de points sont : les Washington Wizards (7986), les Brooklyn Nets (7999) et les Charlotte Hornets (8278).
"""