ViannyCruz commited on
Commit
9e62597
·
verified ·
1 Parent(s): f167717

Delete seed_data.py

Browse files
Files changed (1) hide show
  1. seed_data.py +0 -335
seed_data.py DELETED
@@ -1,335 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- seed_data.py — Datos de prueba para el Sistema de Diagnóstico de Retinopatía Diabética
4
- Uso:
5
- python seed_data.py # Insertar datos (respeta existentes)
6
- python seed_data.py --reset # Borrar TODO y reinsertar desde cero
7
- python seed_data.py --clear # Solo borrar datos de prueba (no el admin)
8
- python seed_data.py --stats # Ver resumen de lo que hay en la BD
9
-
10
- Coloca este archivo junto a app.py y database.py antes de ejecutarlo.
11
- """
12
-
13
- import os
14
- import sys
15
- import random
16
- import sqlite3
17
- import hashlib
18
- from datetime import datetime, timedelta
19
-
20
- # ── Localizar la base de datos igual que lo hace la app ──────────────────────
21
- DB_PATH = os.environ.get("DB_PATH", "/data/medical_app.db")
22
- if not os.path.exists(os.path.dirname(DB_PATH)):
23
- DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "medical_app.db")
24
-
25
- print(f"Base de datos: {DB_PATH}")
26
-
27
- # ── Helpers ──────────────────────────────────────────────────────────────────
28
- def get_conn():
29
- conn = sqlite3.connect(DB_PATH)
30
- conn.row_factory = sqlite3.Row
31
- conn.execute("PRAGMA foreign_keys = ON")
32
- return conn
33
-
34
- def hash_pw(pw: str) -> str:
35
- return hashlib.sha256(pw.encode()).hexdigest()
36
-
37
- def rand_date(years_ago_min=1, years_ago_max=80) -> str:
38
- days = random.randint(years_ago_min * 365, years_ago_max * 365)
39
- return (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
40
-
41
- def rand_consultation_date(days_ago_max=180) -> str:
42
- days = random.randint(0, days_ago_max)
43
- hours = random.randint(7, 18)
44
- mins = random.randint(0, 59)
45
- dt = datetime.now() - timedelta(days=days, hours=hours, minutes=mins)
46
- return dt.strftime("%Y-%m-%d %H:%M:%S")
47
-
48
- # ── Datos de prueba ──────────────────────────────────────────────────────────
49
-
50
- USERS = [
51
- # (username, password, role)
52
- ("dr_ramirez", "doctor123", "Doctor"),
53
- ("dr_perez", "doctor123", "Doctor"),
54
- ("dr_martinez", "doctor123", "Doctor"),
55
- ("supervisor", "admin456", "Admin"),
56
- ]
57
-
58
- # Nombres dominicanos / caribeños realistas
59
- PATIENTS = [
60
- # (nombre, fecha_nacimiento, genero, tipo_diabetes)
61
- ("Juan Carlos Medina Castillo", "1958-03-14", "M", "Tipo 2"),
62
- ("María Elena Reyes Sánchez", "1965-07-22", "F", "Tipo 2"),
63
- ("Roberto Antonio Pérez Núñez", "1972-11-05", "M", "Tipo 1"),
64
- ("Carmen Altagracia Díaz López", "1949-01-30", "F", "Tipo 2"),
65
- ("Luis Fernando Vargas Torres", "1980-09-18", "M", "Tipo 2"),
66
- ("Ana Milagros Santos Herrera", "1955-04-12", "F", "Tipo 2"),
67
- ("Pedro Emilio Guzmán Rosario", "1963-12-28", "M", "Tipo 1"),
68
- ("Josefa Alicia Mora Taveras", "1970-06-03", "F", "Gestacional"),
69
- ("Francisco Javier Marte Féliz", "1945-08-17", "M", "Tipo 2"),
70
- ("Rosa María Almonte Encarnación", "1968-02-09", "F", "Tipo 2"),
71
- ("Miguel Ángel Cabrera Paulino", "1976-10-25", "M", "MODY"),
72
- ("Esperanza del Carmen Pichardo", "1952-05-31", "F", "Tipo 2"),
73
- ("Carlos Daniel Tejada Ureña", "1988-03-07", "M", "Tipo 1"),
74
- ("Yolanda Beatriz Novas Acosta", "1961-09-14", "F", "Tipo 2"),
75
- ("Ramón Ernesto Jiménez Clase", "1957-07-19", "M", "Tipo 2"),
76
- ("Gloria Inés Santana Bido", "1973-11-22", "F", "Tipo 2"),
77
- ("Héctor Manuel Ogando Matos", "1966-04-08", "M", "Tipo 2"),
78
- ("Milagros Concepción Báez Rijo", "1982-01-16", "F", "Tipo 1"),
79
- ("Víctor Hugo Severino Cepeda", "1948-08-04", "M", "Tipo 2"),
80
- ("Luz Marina Polanco Espinal", "1959-06-27", "F", "Tipo 2"),
81
- ("Andrés Felipe Castillo Grullón", "1990-12-11", "M", "Tipo 1"),
82
- ("Natividad Eugenia Pena Arias", "1944-03-23", "F", "Tipo 2"),
83
- ("Domingo Rafael Flores Medina", "1967-10-01", "M", "Otro"),
84
- ("Sandra Margarita Cruz Lizardo", "1978-05-18", "F", "Tipo 2"),
85
- ("Eugenio Antonio Lora Ferreira", "1953-09-30", "M", "Tipo 2"),
86
- ]
87
-
88
- # riskFactorIDs del sistema (se leen de la BD para no asumir IDs)
89
- # Mapeo nombre -> cuáles pacientes los tienen (por índice 0-based)
90
- PATIENT_RISK_FACTORS = {
91
- "Hipertensión": [0, 3, 4, 5, 8, 9, 13, 14, 16, 18, 19, 21, 24],
92
- "Diabetes Tipo 1": [2, 6, 12, 17, 20],
93
- "Diabetes Tipo 2": [0, 1, 3, 4, 5, 7, 8, 9, 11, 13, 14, 15, 16, 18, 19, 21, 22, 23, 24],
94
- "Obesidad": [0, 3, 8, 9, 14, 18, 21, 24],
95
- "Tabaquismo": [6, 8, 14, 18, 22],
96
- "Sedentarismo": [1, 3, 5, 9, 13, 19, 21],
97
- "Antecedentes Familiares":[0, 2, 4, 6, 10, 12, 15, 17, 20],
98
- "Edad Avanzada": [3, 8, 18, 21],
99
- "Colesterol Alto": [0, 4, 8, 13, 16, 18, 24],
100
- "Nefropatía": [3, 8, 18],
101
- }
102
-
103
- # ── Distribución de consultas ��────────────────────────────────────────────────
104
- # Cada tupla: (patient_idx, confidence, has_dr, notes_template)
105
- # has_dr=None => aleatorio según probabilidad del paciente
106
- CONSULTATION_TEMPLATES = [
107
- # Pacientes con DR positivo (casos más graves / mayores)
108
- (0, 92.3, True, "Lesiones hemorrágicas visibles en polo posterior. Se recomienda evaluación urgente con retinólogo."),
109
- (0, 87.1, True, "Seguimiento: persisten microaneurismas. Control en 3 meses."),
110
- (3, 95.8, True, "Retinopatía diabética no proliferativa severa. Derivación inmediata."),
111
- (3, 88.4, True, "Exudados duros periféricos. Edema macular presente."),
112
- (5, 79.2, True, "Microaneurismas múltiples en arcada temporal superior."),
113
- (8, 96.1, True, "Retinopatía proliferativa. Neovascularización de disco. Requiere fotocoagulación."),
114
- (8, 91.7, True, "Post-fotocoagulación. Reducción de neovascularización. Seguimiento mensual."),
115
- (13, 84.5, True, "Hemorragias en llama en cuadrante nasal inferior."),
116
- (14, 88.9, True, "Exudados algodonosos y microaneurismas. RDNP moderada."),
117
- (18, 93.2, True, "Retinopatía diabética avanzada. Tracción vitreorretiniana incipiente."),
118
- (21, 90.6, True, "Microaneurismas y hemorragias puntiformes bilaterales."),
119
- (24, 82.3, True, "RDNP leve. Primera detección. Inicio de seguimiento cada 6 meses."),
120
- # Pacientes sin DR (negativos)
121
- (1, 91.5, False, "Retina sin signos de retinopatía. Control anual programado."),
122
- (1, 94.2, False, "Sin cambios respecto a control anterior. Fondo de ojo normal."),
123
- (2, 88.7, False, "Retina en buen estado. Se refuerza importancia de control glucémico."),
124
- (4, 96.3, False, "Sin evidencia de retinopatía. Paciente con buen control metabólico."),
125
- (6, 85.1, False, "Fondo de ojo sin alteraciones. Seguimiento semestral indicado."),
126
- (7, 92.8, False, "Retina normal. Paciente en primer trimestre, control mensual."),
127
- (9, 89.4, False, "Sin signos de RD. Se mejora el control de HbA1c."),
128
- (10, 93.7, False, "Sin alteraciones retinianas. Paciente joven con buen pronóstico."),
129
- (11, 87.6, False, "Retina sin lesiones. Control semestral."),
130
- (12, 91.2, False, "Sin retinopatía. Paciente refiere visión borrosa ocasional, se descarta causa retiniana."),
131
- (15, 94.8, False, "Fondo de ojo normal. Se recomienda mantener HbA1c < 7%."),
132
- (16, 86.3, False, "Sin signos de RD. Control en 6 meses."),
133
- (17, 93.1, False, "Retina sin alteraciones. Control glucémico óptimo."),
134
- (19, 88.9, False, "Sin retinopatía. Se orienta sobre importancia del ejercicio físico."),
135
- (20, 95.4, False, "Fondo de ojo normal. Primer control, paciente de reciente diagnóstico."),
136
- (22, 82.7, False, "Sin evidencia de RD. Paciente con Otro tipo de DM, seguimiento especial."),
137
- (23, 90.1, False, "Retina sin lesiones. Excelente adherencia al tratamiento."),
138
- ]
139
-
140
- # ── Funciones principales ─────────────────────────────────────────────────────
141
-
142
- def clear_test_data(conn):
143
- """Elimina solo los datos de prueba (deja intacto el usuario admin)."""
144
- print("\n🗑 Limpiando datos de prueba...")
145
- # El cascade ON DELETE maneja Patients -> PatientsRiskFactors y Consultations
146
- conn.execute("DELETE FROM Users WHERE username != 'admin'")
147
- conn.commit()
148
- print(" ✓ Usuarios de prueba eliminados (pacientes y consultas en cascada)")
149
-
150
- def full_reset(conn):
151
- """Borra ABSOLUTAMENTE todo y deja solo el admin por defecto."""
152
- print("\n⚠️ Reset completo de la base de datos...")
153
- conn.execute("DELETE FROM Consultations")
154
- conn.execute("DELETE FROM PatientsRiskFactors")
155
- conn.execute("DELETE FROM Patients")
156
- conn.execute("DELETE FROM Users WHERE username != 'admin'")
157
- conn.commit()
158
- print(" ✓ Base de datos limpia (admin conservado)")
159
-
160
- def print_stats(conn):
161
- """Muestra un resumen del estado actual de la BD."""
162
- print("\n📊 Estado actual de la base de datos:")
163
- print("─" * 45)
164
-
165
- users = conn.execute("SELECT role, COUNT(*) as n FROM Users GROUP BY role").fetchall()
166
- print(" Usuarios:")
167
- for r in users:
168
- print(f" {r['role']:10s}: {r['n']}")
169
-
170
- n_patients = conn.execute("SELECT COUNT(*) FROM Patients").fetchone()[0]
171
- print(f" Pacientes : {n_patients}")
172
-
173
- n_consult = conn.execute("SELECT COUNT(*) FROM Consultations").fetchone()[0]
174
- n_pos = conn.execute("SELECT COUNT(*) FROM Consultations WHERE diabeticRetinopathy=1").fetchone()[0]
175
- n_neg = n_consult - n_pos
176
- print(f" Consultas : {n_consult} (✓ {n_neg} negativas / ✗ {n_pos} positivas)")
177
-
178
- n_rf = conn.execute("SELECT COUNT(*) FROM PatientsRiskFactors").fetchone()[0]
179
- print(f" Fact.riesgo : {n_rf} asignaciones")
180
- print("─" * 45)
181
-
182
- def seed(conn):
183
- print("\n🌱 Insertando datos de prueba...")
184
-
185
- # 1. Usuarios
186
- user_ids = {}
187
- existing_users = {r['username'] for r in conn.execute("SELECT username FROM Users").fetchall()}
188
- print("\n 👤 Usuarios:")
189
- for username, password, role in USERS:
190
- if username in existing_users:
191
- uid = conn.execute("SELECT userID FROM Users WHERE username=?", (username,)).fetchone()['userID']
192
- user_ids[username] = uid
193
- print(f" - {username} ({role}) → ya existe, omitido")
194
- else:
195
- cur = conn.execute(
196
- "INSERT INTO Users (username, password, role) VALUES (?,?,?)",
197
- (username, hash_pw(password), role)
198
- )
199
- user_ids[username] = cur.lastrowid
200
- print(f" + {username} ({role}) → creado [pass: {password}]")
201
- conn.commit()
202
-
203
- # Lista de doctores para repartir pacientes
204
- doctor_usernames = [u for u, _, r in USERS if r == "Doctor"]
205
- doctor_ids = [user_ids[u] for u in doctor_usernames]
206
-
207
- # 2. Pacientes
208
- patient_ids = []
209
- print("\n 🏥 Pacientes:")
210
- for i, (name, birth, gender, diab) in enumerate(PATIENTS):
211
- existing = conn.execute(
212
- "SELECT patientID FROM Patients WHERE name=?", (name,)
213
- ).fetchone()
214
- if existing:
215
- patient_ids.append(existing['patientID'])
216
- print(f" - {name} → ya existe, omitido")
217
- continue
218
-
219
- # Repartir entre doctores de forma cíclica
220
- doctor_id = doctor_ids[i % len(doctor_ids)]
221
- cur = conn.execute(
222
- "INSERT INTO Patients (createdByUserID, name, birthDate, gender, diabetesType) VALUES (?,?,?,?,?)",
223
- (doctor_id, name, birth, gender, diab)
224
- )
225
- patient_ids.append(cur.lastrowid)
226
- doctor_name = doctor_usernames[i % len(doctor_usernames)]
227
- print(f" + {name} ({diab}) → Dr. {doctor_name}")
228
- conn.commit()
229
-
230
- # 3. Factores de riesgo
231
- rf_map = {} # nombre -> riskFactorID
232
- for r in conn.execute("SELECT riskFactorID, name FROM RiskFactors").fetchall():
233
- rf_map[r['name']] = r['riskFactorID']
234
-
235
- print("\n ⚠️ Factores de riesgo:")
236
- rf_count = 0
237
- for rf_name, patient_indices in PATIENT_RISK_FACTORS.items():
238
- rf_id = rf_map.get(rf_name)
239
- if rf_id is None:
240
- print(f" ⚠ Factor '{rf_name}' no encontrado en BD, omitido")
241
- continue
242
- for idx in patient_indices:
243
- if idx >= len(patient_ids):
244
- continue
245
- pid = patient_ids[idx]
246
- try:
247
- conn.execute(
248
- "INSERT OR IGNORE INTO PatientsRiskFactors (patientID, riskFactorID) VALUES (?,?)",
249
- (pid, rf_id)
250
- )
251
- rf_count += 1
252
- except Exception:
253
- pass
254
- conn.commit()
255
- print(f" + {rf_count} asignaciones insertadas")
256
-
257
- # 4. Consultas
258
- print("\n 📋 Consultas:")
259
- consult_count = 0
260
- for patient_idx, confidence, has_dr, notes in CONSULTATION_TEMPLATES:
261
- if patient_idx >= len(patient_ids):
262
- continue
263
- pid = patient_ids[patient_idx]
264
-
265
- # El doctor que creó el paciente hace la consulta
266
- doctor_row = conn.execute(
267
- "SELECT createdByUserID FROM Patients WHERE patientID=?", (pid,)
268
- ).fetchone()
269
- if not doctor_row:
270
- continue
271
- doctor_id = doctor_row['createdByUserID']
272
-
273
- raw_output = confidence / 100.0
274
- consult_date = rand_consultation_date(days_ago_max=180)
275
-
276
- conn.execute(
277
- """INSERT INTO Consultations
278
- (patientID, createdByUserID, diabeticRetinopathy, notes,
279
- confidence, rawOutput, consultationDate)
280
- VALUES (?,?,?,?,?,?,?)""",
281
- (pid, doctor_id, 1 if has_dr else 0, notes,
282
- confidence, raw_output, consult_date)
283
- )
284
- consult_count += 1
285
-
286
- conn.commit()
287
- print(f" + {consult_count} consultas insertadas")
288
-
289
- print_stats(conn)
290
- print("\n✅ Seed completado.\n")
291
- print(" Credenciales de prueba:")
292
- print(" ┌─────────────────┬────────────┬─────────┐")
293
- print(" │ Usuario │ Contraseña │ Rol │")
294
- print(" ├─────────────────┼────────────┼─────────┤")
295
- print(" │ admin │ admin123 │ Admin │")
296
- print(" │ supervisor │ admin456 │ Admin │")
297
- print(" │ dr_ramirez │ doctor123 │ Doctor │")
298
- print(" │ dr_perez │ doctor123 │ Doctor │")
299
- print(" │ dr_martinez │ doctor123 │ Doctor │")
300
- print(" └─────────────────┴────────────┴─────────┘\n")
301
-
302
-
303
- # ── Entry point ───────────────────────────────────────────────────────────────
304
- if __name__ == "__main__":
305
- args = sys.argv[1:]
306
-
307
- if not os.path.exists(DB_PATH):
308
- print(f"❌ Base de datos no encontrada en: {DB_PATH}")
309
- print(" Asegúrate de ejecutar la app al menos una vez para inicializar la BD.")
310
- print(" O ajusta DB_PATH con: DB_PATH=/ruta/a/medical_app.db python seed_data.py")
311
- sys.exit(1)
312
-
313
- conn = get_conn()
314
-
315
- try:
316
- if "--stats" in args:
317
- print_stats(conn)
318
-
319
- elif "--clear" in args:
320
- clear_test_data(conn)
321
- print_stats(conn)
322
-
323
- elif "--reset" in args:
324
- confirm = input("⚠️ Esto borrará TODOS los datos (excepto admin). ¿Continuar? [s/N]: ")
325
- if confirm.lower() == 's':
326
- full_reset(conn)
327
- seed(conn)
328
- else:
329
- print("Cancelado.")
330
-
331
- else:
332
- seed(conn)
333
-
334
- finally:
335
- conn.close()