jaimalklyde commited on
Commit
1f8d682
·
verified ·
1 Parent(s): 607e067

Update src/module/add_data.py

Browse files
Files changed (1) hide show
  1. src/module/add_data.py +144 -0
src/module/add_data.py CHANGED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MODULE: DATA INJECTOR (FLUX CONTINU)
3
+ ====================================
4
+ Responsabilité : Injection contrôlée de nouveaux lots de données (quelques centaines de lignes).
5
+ Mode : Append (Ajout à la suite sans écraser).
6
+ """
7
+
8
+ import pandas as pd
9
+ import numpy as np
10
+ import datetime as dt
11
+ from faker import Faker
12
+ import streamlit as st
13
+
14
+ class DataInjector:
15
+ def __init__(self, client, sheet_name):
16
+ self.client = client
17
+ self.sheet_name = sheet_name
18
+ self.fake = Faker("fr_FR")
19
+ # Services de l'hôpital
20
+ self.svc_codes = ["URG", "MED", "PED", "REA", "INF", "ISO", "CAR", "NEU", "TRA"]
21
+
22
+ def _append_to_sheet(self, df, worksheet_name):
23
+ """Ajoute les données à la suite des lignes existantes dans Google Sheets"""
24
+ try:
25
+ sh = self.client.open(self.sheet_name)
26
+ worksheet = sh.worksheet(worksheet_name)
27
+
28
+ # Conversion en string pour l'API Google Sheets
29
+ df_export = df.copy()
30
+ for col in df_export.select_dtypes(include=['datetime64', 'object', 'datetimetz']).columns:
31
+ df_export[col] = df_export[col].astype(str)
32
+
33
+ # Extraction des valeurs brutes
34
+ values = df_export.values.tolist()
35
+
36
+ # Appel API
37
+ worksheet.append_rows(values)
38
+ return True
39
+ except Exception as e:
40
+ st.error(f"❌ Erreur lors de l'ajout dans '{worksheet_name}': {e}")
41
+ return False
42
+
43
+ def generate_batch(self, days=7):
44
+ """
45
+ Génère un lot de données pour X jours.
46
+ Volume estimé pour 7 jours : ~63 lignes Ressources + ~400 lignes Admissions + Stocks.
47
+ """
48
+ # On simule à partir d'aujourd'hui pour avoir des données "fraîches"
49
+ start_date = dt.date.today()
50
+ dates = pd.date_range(start_date, periods=days, freq="D")
51
+
52
+ # 1. SCÉNARIOS (Météo/Épidémie)
53
+ scen_rows = []
54
+ for d in dates:
55
+ # Petit hasard pour rendre ça vivant
56
+ r = np.random.random()
57
+ if r < 0.1: sc = "Grippe"
58
+ elif r < 0.05: sc = "Canicule"
59
+ else: sc = "Normal"
60
+ scen_rows.append({"date": d, "scenario": sc, "intensity": 1 if sc != "Normal" else 0})
61
+ df_scen = pd.DataFrame(scen_rows)
62
+
63
+ # 2. ADMISSIONS (Le flux patients)
64
+ adm_rows = []
65
+ for d in dates:
66
+ for svc in self.svc_codes:
67
+ # Variation aléatoire pour tester la sensibilité de l'IA
68
+ n_patients = np.random.poisson(lam=random.randint(3, 12))
69
+ adm_rows.append({
70
+ "date": d,
71
+ "service_code": svc,
72
+ "nb_admissions": n_patients
73
+ })
74
+ df_adm = pd.DataFrame(adm_rows)
75
+
76
+ # 3. RESSOURCES (L'état des lits)
77
+ res_rows = []
78
+ for d in dates:
79
+ for svc in self.svc_codes:
80
+ # Simulation d'une occupation variable
81
+ lits_tot = 150
82
+ occup = np.random.randint(80, 155) # Parfois ça déborde (>150)
83
+
84
+ # Injection d'anomalies pour tester le module DQ
85
+ is_anomaly = 1 if occup > lits_tot else 0
86
+ anomaly_type = "suroccupation" if is_anomaly else None
87
+
88
+ res_rows.append({
89
+ "date": d,
90
+ "service_code": svc,
91
+ "lits_total": lits_tot,
92
+ "lits_occupes": occup,
93
+ "personnel_disponible": np.random.randint(20, 35),
94
+ "personnel_requis": 30,
95
+ "taux_occupation": round(occup/lits_tot, 2),
96
+ "dq_is_anomaly": is_anomaly,
97
+ "dq_anomaly_type": anomaly_type
98
+ })
99
+ df_res = pd.DataFrame(res_rows)
100
+
101
+ return df_scen, df_adm, df_res
102
+
103
+ def run(self, days_to_add):
104
+ scen, adm, res = self.generate_batch(days=days_to_add)
105
+
106
+ total_rows = len(scen) + len(adm) + len(res)
107
+
108
+ with st.status(f"🚀 Injection de {total_rows} nouvelles lignes...", expanded=True) as status:
109
+ st.write("📝 Ajout au calendrier...")
110
+ self._append_to_sheet(scen, "scenarios_calendrier")
111
+
112
+ st.write(f"valeurs : {len(adm)} admissions...")
113
+ self._append_to_sheet(adm, "admissions_jour")
114
+
115
+ st.write(f"valeurs : {len(res)} relevés de ressources...")
116
+ self._append_to_sheet(res, "ressources_jour")
117
+
118
+ status.update(label="✅ Injection terminée !", state="complete")
119
+
120
+ return total_rows
121
+
122
+ # --- INTERFACE ---
123
+ def show_data_injector(client, sheet_name):
124
+ import random # Nécessaire ici si non importé en haut
125
+
126
+ st.markdown("## 💉 INJECTEUR DE FLUX (LIVE TEST)")
127
+ st.caption("Ajoute des données récentes pour tester la réaction de l'IA et du Dashboard.")
128
+
129
+ col1, col2 = st.columns([2, 1])
130
+
131
+ with col1:
132
+ days = st.slider("Jours à simuler", min_value=1, max_value=14, value=7,
133
+ help="7 jours génèrent environ 500 nouvelles lignes.")
134
+
135
+ with col2:
136
+ # Estimation du volume
137
+ st.metric("Volume estimé", f"~{days * 9 * 6} lignes", delta="Nouveaux cas")
138
+
139
+ if st.button("⚡ Injecter les données maintenant", type="primary"):
140
+ injector = DataInjector(client, sheet_name)
141
+ count = injector.run(days)
142
+
143
+ st.success(f"Opération réussie. **{count}** nouvelles lignes ont été ajoutées à la base.")
144
+ st.warning("👉 N'oubliez pas de relancer l'ETL (Feature Engineering) pour que l'IA voie ces nouvelles données.")