import streamlit as st import pandas as pd import gspread from google.oauth2.service_account import Credentials import os import json import sys # Ajout du chemin pour trouver les modules sys.path.append(os.path.join(os.path.dirname(__file__), 'modules')) # IMPORT DU NOUVEAU MODULE try: from modules import kyc_form, map_dashboard # <-- Ajout ici except ImportError: # Fallback si l'import direct échoue (structure de dossier simple) import kyc_form import map_dashboard # <-- Ajout ici # ============================================================================== # 1. CONFIGURATION DU "DIRECT DRIVER" & DESIGN # ============================================================================== st.set_page_config( page_title="Vortex-Flux | Ontology", page_icon="🔺", layout="wide", initial_sidebar_state="expanded" ) # Nom exact de votre fichier Google Sheets (Doit être partagé avec l'email du bot) SHEET_NAME = "Vortex-Flux" # Scopes requis pour l'accès Google Drive/Sheets SCOPES = [ "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive" ] # Injection CSS : Design Gotham (Palantir) & Space Grotesk st.markdown(""" """, unsafe_allow_html=True) # ============================================================================== # 2. MOTEUR DE CONNEXION (GSPREAD PUR) # ============================================================================== @st.cache_resource def get_gspread_client(): """Authentification robuste via gspread sans passer par st.connection""" raw_json = os.environ.get("GSHEETS_JSON") if not raw_json: st.error("🛑 SECRET MANQUANT : 'GSHEETS_JSON' est introuvable.") return None try: # Création du fichier temporaire sécurisé creds_dict = json.loads(raw_json) with open("temp_creds.json", "w") as f: json.dump(creds_dict, f) # Authentification Google credentials = Credentials.from_service_account_file("temp_creds.json", scopes=SCOPES) client = gspread.authorize(credentials) return client except Exception as e: st.error(f"⚠️ Erreur d'authentification GSpread : {e}") return None def get_data_from_sheet(worksheet_name): """Récupère les données d'un onglet sous forme de DataFrame""" client = get_gspread_client() if not client: return pd.DataFrame() try: # Ouverture du classeur par son nom sh = client.open(SHEET_NAME) # Sélection de l'onglet worksheet = sh.worksheet(worksheet_name) # Lecture des données data = worksheet.get_all_records() return pd.DataFrame(data) except gspread.WorksheetNotFound: # Si l'onglet n'existe pas encore, on renvoie vide sans planter return pd.DataFrame() except gspread.SpreadsheetNotFound: st.error(f"⚠️ Fichier Google Sheet '{SHEET_NAME}' introuvable. Vérifiez le nom et le partage.") return pd.DataFrame() except Exception as e: st.error(f"Erreur de lecture : {e}") return pd.DataFrame() # ============================================================================== # 3. LOGIQUE ONTOLOGIQUE (IDs) # ============================================================================== def generate_ontology_id(prefix, sheet_tab): df = get_data_from_sheet(sheet_tab) # Calcul ID : Nombre de lignes + 1 next_id = len(df) + 1 return f"{prefix}-2025-{next_id:04d}" #2025 a changé pour 2026 plus tard # ============================================================================== # 4. INTERFACE UTILISATEUR # ============================================================================== client = get_gspread_client() if client: # --- BARRE LATÉRALE --- st.sidebar.title("🔺🔻 VORTEX-FLUX") st.sidebar.caption("Jumeau Numérique & Ontologie") st.sidebar.divider() menu = st.sidebar.radio("NAVIGATION", ["TABLEAU DE BORD", "CARTE TACTIQUE","KYC CLIENTS"] ) # --- A. TABLEAU DE BORD --- if menu == "TABLEAU DE BORD": st.header("OBJECT EXPLORER") st.success(f"✅ Liaison Directe établie avec '{SHEET_NAME}'") col1, col2, col3 = st.columns(3) col1.metric("CAPITAL DEHORS", "1.2M XOF", "▲ 5%") col2.metric("FLUX ATTENDU (J+7)", "450k XOF", "▼ 2%") col3.metric("SCORE LIQUIDITÉ", "8.5/10") st.divider() st.subheader("VUE ONTOLOGIQUE : CLIENTS") df_clients = get_data_from_sheet("Clients_KYC") if not df_clients.empty: st.dataframe(df_clients, use_container_width=True) else: st.info("ℹ️ L'onglet 'Clients_KYC' est vide ou n'existe pas encore.") # --- B. CODE DU MODULE CARTE TACTIQUE --- elif menu == "CARTE TACTIQUE": # Appel du nouveau module map_dashboard.show_map_dashboard(client, SHEET_NAME) # --- C. CODE DU MODULE KYC --- elif menu == "KYC CLIENTS": # APPEL DU MODULE EXTERNE # C'est ici que la magie opère : on passe le client et la fonction ID au module kyc_form.show_kyc_form(client, SHEET_NAME, generate_ontology_id)