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, loans_engine, ml_dashboard, notifications, ontology_graph, repayments
except ImportError:
# Fallback si l'import direct échoue (structure de dossier simple)
import kyc_form
import map_dashboard
import loans_engine
import ml_dashboard
import notifications
import ontology_graph
import repayments
# ==============================================================================
# 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"
]
# ==============================================================================
# 2. INJECTION CSS GOTHAM SURVEILLANCE - STYLE GLOBAL
# ==============================================================================
st.markdown("""
""", unsafe_allow_html=True)
# ==============================================================================
# 3. 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()
# ==============================================================================
# 4. 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}-2026-{next_id:04d}" #2026 a changé pour 2027 plus tard
# ==============================================================================
# 5. FONCTION DE RĂINITIALISATION COMPLĂTE
# ==============================================================================
def reset_application():
"""
Réinitialise complÚtement l'application :
- Vide le session_state
- Vide tous les caches
- Force un rechargement complet
"""
# 1. Sauvegarder les clés essentielles (si nécessaire)
# Par exemple, si vous voulez garder certaines variables
# keys_to_keep = []
# 2. Vider complĂštement le session_state
for key in list(st.session_state.keys()):
del st.session_state[key]
# 3. Vider tous les caches de Streamlit
st.cache_data.clear()
st.cache_resource.clear()
# 4. Force un rechargement complet
st.rerun()
# ==============================================================================
# 6. 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()
st.sidebar.markdown("### System")
menu = st.sidebar.radio("Module",
["Dashboard", "Ontology Model", "Tracking Metrics","Actor Onboarding", "Init Loan", "Repayments"]
)
st.sidebar.divider()
# --- BOUTON DE RĂINITIALISATION ---
st.sidebar.markdown("### Rerunning")
col1, col2 = st.sidebar.columns([3, 1])
with col1:
st.markdown("Réinitialiser l'application", unsafe_allow_html=True)
with col2:
# Utilisation d'une clé unique et d'une classe CSS personnalisée
if st.button("reset", key="reset_app_btn", help="Réinitialiser l'application à son état initial"):
reset_application()
# Version alternative avec un bouton plus visible :
# st.sidebar.markdown("---")
# if st.sidebar.button("đ RESET APPLICATION", key="reset_full", help="RĂ©initialiser complĂštement l'application"):
# reset_application()
# --- A. TABLEAU DE BORD ---
if menu == "Dashboard":
# --- AJOUTS VORTEX-FLUX (ML & NOTIFICATIONS) ---
# 1.Appel direct du Dashboard ML (Le "Nouveau" Tableau de Bord)
ml_dashboard.show_ml_features(client, SHEET_NAME)
st.divider()
# 2. Module de Notification (Bouton de vérification)
notifications.verifier_et_notifier_echeances(client, SHEET_NAME)
# --- B. CODE DU MODULE ONTOLOGY ---
elif menu == "Ontology Model":
ontology_graph.show_ontology_graph(client, SHEET_NAME)
# --- C. CODE DU MODULE CARTE TACTIQUE ---
elif menu == "Tracking Metrics":
# Appel du nouveau module
map_dashboard.show_map_dashboard(client, SHEET_NAME)
# --- D. CODE DU MODULE KYC ---
elif menu == "Actor Onboarding":
# APPEL DU MODULE EXTERNE
kyc_form.show_kyc_form(client, SHEET_NAME, generate_ontology_id)
# --- E. CODE DU MODULE LOANS ---
elif menu == "Init Loan":
loans_engine.show_loans_engine(client, SHEET_NAME)
# --- F. CODE DU MODULE Repayment ---
elif menu == "Repayments":
repayments.show_repayments_module(client, SHEET_NAME)
else:
st.error("đ Impossible de se connecter Ă Google Sheets. VĂ©rifiez vos credentials.")