| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- import streamlit as st
- import os
- import glob
- import shutil
- from workflow_Agent import app # Ton graphe compilé
- from langchain_core.messages import HumanMessage
- import pandas as pd
- # --- CONFIGURATION ET NETTOYAGE AU DÉMARRAGE ---
- st.set_page_config(page_title="Dataltist AI Assistant", layout="wide")
- st.title("📊 Dataltist BI Chat")
- from langfuse.langchain import CallbackHandler
-
- # Initialize Langfuse CallbackHandler for Langchain (tracing)
- langfuse_handler = CallbackHandler()
- # Initialisation du dossier de travail
- if "app_initialized" not in st.session_state:
- if os.path.exists("outputs"):
- shutil.rmtree("outputs")
- os.makedirs("outputs", exist_ok=True)
- if not os.path.exists("data"):
- os.makedirs("data", exist_ok=True)
- st.session_state.app_initialized = True
- st.session_state.query_count = 0
- st.session_state.messages = []
- # --- 1. SIDEBAR : GESTION DES DONNÉES ---
- file_path = None
- with st.sidebar:
- st.header("📁 Données")
- uploaded_file = st.file_uploader("Charge ton fichier (CSV/Excel)", type=["csv", "xlsx"])
-
- if uploaded_file:
- # 1. Définition et sauvegarde du fichier
- file_path = os.path.join("data", uploaded_file.name)
- with open(file_path, "wb") as f:
- f.write(uploaded_file.getbuffer())
- st.success(f"Fichier '{uploaded_file.name}' prêt !")
- df = pd.read_csv(file_path) if file_path.endswith(".csv") else pd.read_excel(file_path)
- columns_list = df.columns.tolist()
- # 2. Initialisation ou Mise à jour du Session State
- # On utilise le nom exact de ta classe : AgentState
- if "AgentState" not in st.session_state:
- st.session_state.AgentState = {
- "messages": [], # Liste vide pour l'historique
- "current_df_path": file_path, # Le chemin vers le fichier uploadé
- "Data_colomns" : columns_list,
- "generated_charts": [] # Liste vide pour les futurs PNG
- }
- else:
- # Si l'utilisateur change de fichier, on met à jour le chemin
- st.session_state.AgentState["current_df_path"] = file_path
-
- st.write("---")
- if st.button("🗑️ Effacer la discussion & fichiers", use_container_width=True):
- st.session_state.messages = []
- st.session_state.query_count = 0
- if os.path.exists("outputs"):
- shutil.rmtree("outputs")
- os.makedirs("outputs", exist_ok=True)
- st.rerun()
- # --- 2. AFFICHAGE DE L'HISTORIQUE ---
- for message in st.session_state.messages:
- with st.chat_message(message["role"]):
- st.markdown(message["content"])
- # Réaffichage des graphiques archivés pour ce message
- if "charts" in message and message["charts"]:
- cols = st.columns(min(len(message["charts"]), 2))
- for idx, path in enumerate(message["charts"]):
- if os.path.exists(path):
- cols[idx % 2].image(path, use_container_width=True)
- # --- 3. INTERACTION AVEC LES AGENTS ---
- if prompt := st.chat_input("Pose ta question sur tes données..."):
- if not file_path:
- st.error("Veuillez d'abord charger un fichier dans la barre latérale.")
- st.stop()
- # Archivage : Création du dossier spécifique pour cette requête
- current_query_id = st.session_state.query_count
- query_folder = os.path.join("outputs", f"query_{current_query_id}")
- os.makedirs(query_folder, exist_ok=True)
- # Affichage message utilisateur
- st.session_state.messages.append({"role": "user", "content": prompt})
- with st.chat_message("user"):
- st.markdown(prompt)
- # Appel des agents
- with st.chat_message("assistant"):
- with st.status("Analyse Dataltist en cours...", expanded=True) as status:
-
- inputs = {
- "messages": [HumanMessage(content=prompt)],
- "current_df_path": file_path
- }
-
- # Exécution du graphe
- final_state = app.invoke(
- inputs,
- config={"callbacks": [langfuse_handler], "run_name": f"Query_{st.session_state.query_count}"}
- )
-
- # Récupération de la réponse finale (Reporter)
- response_text = final_state["messages"][-1].content
- st.markdown(response_text)
-
- # --- GESTION DES FICHIERS GÉNÉRÉS ---
- new_files_paths = []
- # On scanne la racine de 'outputs/' pour trouver ce que l'Exécuteur a créé
- raw_files = [f for f in glob.glob("outputs/*") if os.path.isfile(f)]
-
- if raw_files:
- st.write("---")
- st.subheader("📊 Résultats de l'analyse")
-
- # On déplace les fichiers vers le dossier de la query pour l'historique
- for f in raw_files:
- dest_path = os.path.join(query_folder, os.path.basename(f))
- shutil.move(f, dest_path)
- new_files_paths.append(dest_path)
- # Affichage des images et fichiers Excel
- images = [p for p in new_files_paths if p.lower().endswith(('.png', '.jpg'))]
- docs = [p for p in new_files_paths if p.lower().endswith(('.xlsx', '.csv'))]
- if images:
- cols = st.columns(min(len(images), 2))
- for idx, img_path in enumerate(images):
- cols[idx % 2].image(img_path, use_container_width=True, caption=f"Visuel {idx+1}")
-
- if docs:
- for doc_path in docs:
- with open(doc_path, "rb") as f:
- st.download_button(
- label=f"📥 Télécharger {os.path.basename(doc_path)}",
- data=f,
- file_name=os.path.basename(doc_path),
- mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
- )
-
- status.update(label="Analyse terminée !", state="complete")
- # Mise à jour de la session et du compteur
- st.session_state.messages.append({
- "role": "assistant",
- "content": response_text,
- "charts": new_files_paths
- })
- st.session_state.query_count += 1
|