Spaces:
Running
Running
Déploiement automatique depuis GitLab CI
Browse files- .streamlit/config.toml +1 -2
- Dockerfile +1 -6
- MistralChat.py +45 -75
- requirements_docker.txt +1 -1
- start.sh +6 -24
.streamlit/config.toml
CHANGED
|
@@ -8,8 +8,7 @@ font = "sans serif"
|
|
| 8 |
|
| 9 |
[server]
|
| 10 |
maxUploadSize = 10
|
| 11 |
-
enableXsrfProtection =
|
| 12 |
-
enableCORS = false
|
| 13 |
|
| 14 |
[browser]
|
| 15 |
gatherUsageStats = false
|
|
|
|
| 8 |
|
| 9 |
[server]
|
| 10 |
maxUploadSize = 10
|
| 11 |
+
enableXsrfProtection = true
|
|
|
|
| 12 |
|
| 13 |
[browser]
|
| 14 |
gatherUsageStats = false
|
Dockerfile
CHANGED
|
@@ -34,7 +34,6 @@ LABEL description="Chatbot NBA hybride RAG + SQL (Streamlit + LangGraph + Mistra
|
|
| 34 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 35 |
postgresql-17 \
|
| 36 |
postgresql-client-17 \
|
| 37 |
-
nginx \
|
| 38 |
libglib2.0-0 \
|
| 39 |
libsm6 \
|
| 40 |
libxext6 \
|
|
@@ -78,9 +77,6 @@ COPY --chown=user:user SQL_db/schema_relationnel_sql.sql ./sql/01_schema.sql
|
|
| 78 |
COPY --chown=user:user start.sh /home/user/start.sh
|
| 79 |
RUN chmod +x /home/user/start.sh
|
| 80 |
|
| 81 |
-
# --- Configuration nginx ---------------------------------------------------
|
| 82 |
-
COPY nginx.conf /home/user/nginx.conf
|
| 83 |
-
|
| 84 |
# --- Variables d'environnement par défaut ----------------------------------
|
| 85 |
# PG_HOST/PG_PORT pointent vers PostgreSQL local dans le même conteneur
|
| 86 |
ENV HOME=/home/user \
|
|
@@ -89,8 +85,7 @@ ENV HOME=/home/user \
|
|
| 89 |
PG_PORT=5432 \
|
| 90 |
PG_DB=oc_mlops_projet_3 \
|
| 91 |
PG_ADMIN=admin \
|
| 92 |
-
PGDATA=/home/user/pgdata
|
| 93 |
-
PYTHONUNBUFFERED=1
|
| 94 |
|
| 95 |
# --- Port exposé (7860 requis par HF Spaces) -------------------------------
|
| 96 |
EXPOSE 7860
|
|
|
|
| 34 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 35 |
postgresql-17 \
|
| 36 |
postgresql-client-17 \
|
|
|
|
| 37 |
libglib2.0-0 \
|
| 38 |
libsm6 \
|
| 39 |
libxext6 \
|
|
|
|
| 77 |
COPY --chown=user:user start.sh /home/user/start.sh
|
| 78 |
RUN chmod +x /home/user/start.sh
|
| 79 |
|
|
|
|
|
|
|
|
|
|
| 80 |
# --- Variables d'environnement par défaut ----------------------------------
|
| 81 |
# PG_HOST/PG_PORT pointent vers PostgreSQL local dans le même conteneur
|
| 82 |
ENV HOME=/home/user \
|
|
|
|
| 85 |
PG_PORT=5432 \
|
| 86 |
PG_DB=oc_mlops_projet_3 \
|
| 87 |
PG_ADMIN=admin \
|
| 88 |
+
PGDATA=/home/user/pgdata
|
|
|
|
| 89 |
|
| 90 |
# --- Port exposé (7860 requis par HF Spaces) -------------------------------
|
| 91 |
EXPOSE 7860
|
MistralChat.py
CHANGED
|
@@ -2,9 +2,7 @@
|
|
| 2 |
import streamlit as st
|
| 3 |
import logfire
|
| 4 |
|
| 5 |
-
|
| 6 |
-
print("[MistralChat] Démarrage — chargement des imports...")
|
| 7 |
-
print("=" * 60)
|
| 8 |
|
| 9 |
try:
|
| 10 |
from utils.config import (
|
|
@@ -15,10 +13,8 @@ try:
|
|
| 15 |
from utils.vector_store import VectorStoreManager
|
| 16 |
from utils.langgraph_app import build_graph, AppState # Graphe partagé RAG + SQL
|
| 17 |
from load_excel_to_db import main as load_excel_main
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
print(f"[MistralChat] ❌ ERREUR import : {type(e).__name__}: {e}")
|
| 21 |
-
st.error(f"Erreur d'importation ({type(e).__name__}): {e}. Vérifiez la structure de vos dossiers et les fichiers dans 'utils'.")
|
| 22 |
st.stop()
|
| 23 |
|
| 24 |
|
|
@@ -87,24 +83,8 @@ def get_vector_store_manager():
|
|
| 87 |
return None, messages
|
| 88 |
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
sql_messages = []
|
| 93 |
-
vector_store_manager = None
|
| 94 |
-
vs_messages = []
|
| 95 |
-
graph = None
|
| 96 |
-
|
| 97 |
-
try:
|
| 98 |
-
sql_messages = init_sql_db()
|
| 99 |
-
except Exception as _e:
|
| 100 |
-
st.error(f"❌ Erreur initialisation SQL : {_e}")
|
| 101 |
-
logfire.error("[MistralChat] Erreur init_sql_db", erreur=str(_e))
|
| 102 |
-
|
| 103 |
-
try:
|
| 104 |
-
vector_store_manager, vs_messages = get_vector_store_manager()
|
| 105 |
-
except Exception as _e:
|
| 106 |
-
st.error(f"❌ Erreur chargement VectorStore : {_e}")
|
| 107 |
-
logfire.error("[MistralChat] Erreur get_vector_store_manager", erreur=str(_e))
|
| 108 |
|
| 109 |
|
| 110 |
# --- Compilation du graphe LangGraph hybride (RAG + SQL) ---
|
|
@@ -117,13 +97,7 @@ def get_langgraph(_vector_store_manager):
|
|
| 117 |
return graph
|
| 118 |
|
| 119 |
|
| 120 |
-
|
| 121 |
-
graph = get_langgraph(vector_store_manager)
|
| 122 |
-
except Exception as _e:
|
| 123 |
-
st.error(f"❌ Erreur construction graphe LangGraph : {_e}")
|
| 124 |
-
logfire.error("[MistralChat] Erreur get_langgraph", erreur=str(_e))
|
| 125 |
-
|
| 126 |
-
|
| 127 |
# ==============================
|
| 128 |
# CSS Global — Design professionnel & responsive
|
| 129 |
# ==============================
|
|
@@ -490,46 +464,42 @@ if user_input:
|
|
| 490 |
with st.chat_message("user"):
|
| 491 |
st.markdown(prompt)
|
| 492 |
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
"content": response_content, # contenu brut sans badge pour le contexte LLM
|
| 533 |
-
"route": response_route,
|
| 534 |
-
"display": response_display, # version affichée avec badge
|
| 535 |
-
})
|
|
|
|
| 2 |
import streamlit as st
|
| 3 |
import logfire
|
| 4 |
|
| 5 |
+
|
|
|
|
|
|
|
| 6 |
|
| 7 |
try:
|
| 8 |
from utils.config import (
|
|
|
|
| 13 |
from utils.vector_store import VectorStoreManager
|
| 14 |
from utils.langgraph_app import build_graph, AppState # Graphe partagé RAG + SQL
|
| 15 |
from load_excel_to_db import main as load_excel_main
|
| 16 |
+
except ImportError as e:
|
| 17 |
+
st.error(f"Erreur d'importation: {e}. Vérifiez la structure de vos dossiers et les fichiers dans 'utils'.")
|
|
|
|
|
|
|
| 18 |
st.stop()
|
| 19 |
|
| 20 |
|
|
|
|
| 83 |
return None, messages
|
| 84 |
|
| 85 |
|
| 86 |
+
sql_messages = init_sql_db()
|
| 87 |
+
vector_store_manager, vs_messages = get_vector_store_manager()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
|
| 90 |
# --- Compilation du graphe LangGraph hybride (RAG + SQL) ---
|
|
|
|
| 97 |
return graph
|
| 98 |
|
| 99 |
|
| 100 |
+
graph = get_langgraph(vector_store_manager)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
# ==============================
|
| 102 |
# CSS Global — Design professionnel & responsive
|
| 103 |
# ==============================
|
|
|
|
| 464 |
with st.chat_message("user"):
|
| 465 |
st.markdown(prompt)
|
| 466 |
|
| 467 |
+
# 2. Invoquer le graphe LangGraph (routage automatique RAG ou SQL)
|
| 468 |
+
with st.chat_message("assistant"):
|
| 469 |
+
message_placeholder = st.empty()
|
| 470 |
+
message_placeholder.markdown("""
|
| 471 |
+
<div class="thinking-bar">
|
| 472 |
+
<div class="dot-flashing"></div>
|
| 473 |
+
Analyse en cours…
|
| 474 |
+
</div>
|
| 475 |
+
""", unsafe_allow_html=True)
|
| 476 |
+
try:
|
| 477 |
+
logfire.info(f"[Graph] Invocation pour : '{prompt}'")
|
| 478 |
+
# Exclure le message de bienvenue (index 0) et la question en cours (dernier)
|
| 479 |
+
chat_history = st.session_state.messages[1:-1]
|
| 480 |
+
result = graph.invoke({
|
| 481 |
+
"user_question": prompt,
|
| 482 |
+
"chat_history": chat_history,
|
| 483 |
+
})
|
| 484 |
+
response_content = result.get("final_answer", "Je n'ai pas pu générer de réponse.")
|
| 485 |
+
response_route = result.get("route", "unknown")
|
| 486 |
+
# Préfixe visuel de la route
|
| 487 |
+
route_badge = {"rag": "🔎 `[RAG]`", "sql": "🔢 `[SQL]`"}.get(response_route, "🤖 `[?]`")
|
| 488 |
+
response_display = f"{route_badge} {response_content}"
|
| 489 |
+
logfire.info(f"[Graph] Réponse finale obtenue (route={response_route}).")
|
| 490 |
+
except Exception as e:
|
| 491 |
+
response_content = "Je suis désolé, une erreur technique m'empêche de répondre. Veuillez réessayer."
|
| 492 |
+
response_display = response_content
|
| 493 |
+
response_route = "unknown"
|
| 494 |
+
st.error(f"Erreur lors de l'appel au graphe : {e}")
|
| 495 |
+
logfire.exception("Erreur lors de graph.invoke")
|
| 496 |
+
|
| 497 |
+
message_placeholder.markdown(response_display)
|
| 498 |
+
|
| 499 |
+
# 3. Ajouter la réponse à l'historique (avec route pour filtrage contextuel)
|
| 500 |
+
st.session_state.messages.append({
|
| 501 |
+
"role": "assistant",
|
| 502 |
+
"content": response_content, # contenu brut sans badge pour le contexte LLM
|
| 503 |
+
"route": response_route,
|
| 504 |
+
"display": response_display, # version affichée avec badge
|
| 505 |
+
})
|
|
|
|
|
|
|
|
|
|
|
|
requirements_docker.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
mistralai==1.12.4
|
| 2 |
-
streamlit>=1.44.1
|
| 3 |
langchain>=1.2.10
|
| 4 |
langchain-community>=0.4.1
|
| 5 |
langchain-core>=1.2.17
|
|
|
|
| 1 |
mistralai==1.12.4
|
| 2 |
+
streamlit>=1.44.1
|
| 3 |
langchain>=1.2.10
|
| 4 |
langchain-community>=0.4.1
|
| 5 |
langchain-core>=1.2.17
|
start.sh
CHANGED
|
@@ -87,30 +87,12 @@ echo "🚀 [PG] Démarrage de PostgreSQL (port $PG_PORT) ..."
|
|
| 87 |
pg_ctl -D "$PGDATA" -l "$PG_LOG" start -w -t 60 || { echo "❌ [PG] Échec du démarrage. Log :"; cat "$PG_LOG"; exit 1; }
|
| 88 |
echo "✅ [PG] PostgreSQL démarré."
|
| 89 |
# ---------------------------------------------------------------------------
|
| 90 |
-
# Étape 3 — Démarrage de Streamlit en
|
| 91 |
# ---------------------------------------------------------------------------
|
| 92 |
-
echo "🚀 [Streamlit] Démarrage sur le port
|
| 93 |
cd "$APP_DIR"
|
| 94 |
-
streamlit run MistralChat.py \
|
| 95 |
-
--server.port=
|
| 96 |
-
--server.address=
|
| 97 |
--server.headless=true \
|
| 98 |
-
--
|
| 99 |
-
--server.enableCORS=false \
|
| 100 |
-
--browser.gatherUsageStats=false &
|
| 101 |
-
|
| 102 |
-
# Attendre que Streamlit soit prêt avant de démarrer nginx
|
| 103 |
-
echo "⏳ [Streamlit] Attente du démarrage (port 7861) ..."
|
| 104 |
-
for i in $(seq 1 30); do
|
| 105 |
-
if curl -sf http://127.0.0.1:7861/_stcore/health > /dev/null 2>&1; then
|
| 106 |
-
echo "✅ [Streamlit] Prêt."
|
| 107 |
-
break
|
| 108 |
-
fi
|
| 109 |
-
sleep 2
|
| 110 |
-
done
|
| 111 |
-
|
| 112 |
-
# ---------------------------------------------------------------------------
|
| 113 |
-
# Étape 4 — Démarrage de nginx en premier plan (port 7860, public HF Spaces)
|
| 114 |
-
# ---------------------------------------------------------------------------
|
| 115 |
-
echo "🚀 [nginx] Démarrage sur le port 7860 (public) ..."
|
| 116 |
-
exec nginx -c /home/user/nginx.conf
|
|
|
|
| 87 |
pg_ctl -D "$PGDATA" -l "$PG_LOG" start -w -t 60 || { echo "❌ [PG] Échec du démarrage. Log :"; cat "$PG_LOG"; exit 1; }
|
| 88 |
echo "✅ [PG] PostgreSQL démarré."
|
| 89 |
# ---------------------------------------------------------------------------
|
| 90 |
+
# Étape 3 — Démarrage de Streamlit en premier plan (port 7860, HF Spaces)
|
| 91 |
# ---------------------------------------------------------------------------
|
| 92 |
+
echo "🚀 [Streamlit] Démarrage sur le port 7860 ..."
|
| 93 |
cd "$APP_DIR"
|
| 94 |
+
exec streamlit run MistralChat.py \
|
| 95 |
+
--server.port=7860 \
|
| 96 |
+
--server.address=0.0.0.0 \
|
| 97 |
--server.headless=true \
|
| 98 |
+
--browser.gatherUsageStats=false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|