Pdro-ruiz commited on
Commit
b61df7c
·
verified ·
1 Parent(s): 85c91a2

S2S upload

Browse files
Notebooks/00_synthetic_data.ipynb CHANGED
@@ -17,7 +17,7 @@
17
  },
18
  {
19
  "cell_type": "code",
20
- "execution_count": 1,
21
  "metadata": {},
22
  "outputs": [],
23
  "source": [
@@ -37,7 +37,7 @@
37
  },
38
  {
39
  "cell_type": "code",
40
- "execution_count": 2,
41
  "metadata": {},
42
  "outputs": [
43
  {
@@ -68,112 +68,170 @@
68
  "cell_type": "markdown",
69
  "metadata": {},
70
  "source": [
71
- "## 3. Generación de Datos Sintéticos para Wikidoc\n",
72
- "\n",
73
- "En esta sección se generan datos sintéticos a partir de la base de datos **Wikidoc**.\n",
74
- "Se tomarán filas aleatorias y se modificará ligeramente el texto en las columnas:\n",
75
- "- **instruction**\n",
76
- "- **input**\n",
77
- "- **output**\n",
78
- " \n",
79
- "Se añadirá una frase modificadora para simular variaciones."
80
  ]
81
  },
82
  {
83
  "cell_type": "code",
84
  "execution_count": 4,
85
  "metadata": {},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  "outputs": [
87
  {
88
- "data": {
89
- "text/html": [
90
- "<div>\n",
91
- "<style scoped>\n",
92
- " .dataframe tbody tr th:only-of-type {\n",
93
- " vertical-align: middle;\n",
94
- " }\n",
95
- "\n",
96
- " .dataframe tbody tr th {\n",
97
- " vertical-align: top;\n",
98
- " }\n",
99
- "\n",
100
- " .dataframe thead th {\n",
101
- " text-align: right;\n",
102
- " }\n",
103
- "</style>\n",
104
- "<table border=\"1\" class=\"dataframe\">\n",
105
- " <thead>\n",
106
- " <tr style=\"text-align: right;\">\n",
107
- " <th></th>\n",
108
- " <th>instruction_sintetica</th>\n",
109
- " <th>input_sintetico</th>\n",
110
- " <th>output_sintetico</th>\n",
111
- " </tr>\n",
112
- " </thead>\n",
113
- " <tbody>\n",
114
- " <tr>\n",
115
- " <th>0</th>\n",
116
- " <td>Answer this question truthfully [augmented]</td>\n",
117
- " <td>Could you explain what Meckel's diverticulum i...</td>\n",
118
- " <td>There is insufficient evidence to recommend ro...</td>\n",
119
- " </tr>\n",
120
- " <tr>\n",
121
- " <th>1</th>\n",
122
- " <td>Answer this question truthfully (versión sinté...</td>\n",
123
- " <td>Could you provide information on AIDS dementia...</td>\n",
124
- " <td>AIDS (acquired immune deficiency syndrome) is ...</td>\n",
125
- " </tr>\n",
126
- " <tr>\n",
127
- " <th>2</th>\n",
128
- " <td>Answer this question truthfully (versión sinté...</td>\n",
129
- " <td>What information is available regarding esopha...</td>\n",
130
- " <td>Esophageal cancer is not very common in the Un...</td>\n",
131
- " </tr>\n",
132
- " <tr>\n",
133
- " <th>3</th>\n",
134
- " <td>Answer this question truthfully [datos aumenta...</td>\n",
135
- " <td>Can you provide an overview of delirium tremen...</td>\n",
136
- " <td>Screening tools include the Alcohol Use Disord...</td>\n",
137
- " </tr>\n",
138
- " <tr>\n",
139
- " <th>4</th>\n",
140
- " <td>Answer this question truthfully (modificado si...</td>\n",
141
- " <td>What information is available about Nocturia? ...</td>\n",
142
- " <td>http://www.nlm.nih.gov/medlineplus/ency/articl...</td>\n",
143
- " </tr>\n",
144
- " </tbody>\n",
145
- "</table>\n",
146
- "</div>"
147
- ],
148
- "text/plain": [
149
- " instruction_sintetica \\\n",
150
- "0 Answer this question truthfully [augmented] \n",
151
- "1 Answer this question truthfully (versión sinté... \n",
152
- "2 Answer this question truthfully (versión sinté... \n",
153
- "3 Answer this question truthfully [datos aumenta... \n",
154
- "4 Answer this question truthfully (modificado si... \n",
155
- "\n",
156
- " input_sintetico \\\n",
157
- "0 Could you explain what Meckel's diverticulum i... \n",
158
- "1 Could you provide information on AIDS dementia... \n",
159
- "2 What information is available regarding esopha... \n",
160
- "3 Can you provide an overview of delirium tremen... \n",
161
- "4 What information is available about Nocturia? ... \n",
162
- "\n",
163
- " output_sintetico \n",
164
- "0 There is insufficient evidence to recommend ro... \n",
165
- "1 AIDS (acquired immune deficiency syndrome) is ... \n",
166
- "2 Esophageal cancer is not very common in the Un... \n",
167
- "3 Screening tools include the Alcohol Use Disord... \n",
168
- "4 http://www.nlm.nih.gov/medlineplus/ency/articl... "
169
- ]
170
- },
171
- "execution_count": 4,
172
- "metadata": {},
173
- "output_type": "execute_result"
174
  }
175
  ],
176
  "source": [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  "def generar_datos_sinteticos_wikidoc(df, n=10):\n",
178
  " \"\"\"\n",
179
  " Genera datos sintéticos para el dataset Wikidoc.\n",
@@ -209,12 +267,80 @@
209
  " \"output_sintetico\": salidas_sinteticas\n",
210
  " })\n",
211
  " \n",
212
- " return df_sintetico\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  "\n",
214
- "# Generamos 10 filas sintéticas para Wikidoc\n",
215
- "wikidoc_sintetico = generar_datos_sinteticos_wikidoc(wikidoc, n=10)\n",
216
- "wikidoc_sintetico.head()\n",
217
- "\n"
 
 
 
 
 
 
218
  ]
219
  },
220
  {
@@ -223,187 +349,242 @@
223
  "source": [
224
  "## 4. Generación de Datos Sintéticos para MedQA\n",
225
  " \n",
226
- "En esta sección se generan datos sintéticos a partir de la base de datos **MedQA**.\n",
227
- "Se modificarán las columnas:\n",
228
- "- **question**\n",
229
- "- **answer**\n",
230
- " \n",
231
- "Se añadirá una frase modificadora para simular variaciones en la consulta y en la respuesta."
232
  ]
233
  },
234
  {
235
  "cell_type": "code",
236
- "execution_count": 5,
237
  "metadata": {},
238
  "outputs": [
239
  {
240
- "data": {
241
- "text/html": [
242
- "<div>\n",
243
- "<style scoped>\n",
244
- " .dataframe tbody tr th:only-of-type {\n",
245
- " vertical-align: middle;\n",
246
- " }\n",
247
- "\n",
248
- " .dataframe tbody tr th {\n",
249
- " vertical-align: top;\n",
250
- " }\n",
251
- "\n",
252
- " .dataframe thead th {\n",
253
- " text-align: right;\n",
254
- " }\n",
255
- "</style>\n",
256
- "<table border=\"1\" class=\"dataframe\">\n",
257
- " <thead>\n",
258
- " <tr style=\"text-align: right;\">\n",
259
- " <th></th>\n",
260
- " <th>question_sintetica</th>\n",
261
- " <th>answer_sintetica</th>\n",
262
- " </tr>\n",
263
- " </thead>\n",
264
- " <tbody>\n",
265
- " <tr>\n",
266
- " <th>0</th>\n",
267
- " <td>A 55-year-old man with a history of myocardial...</td>\n",
268
- " <td>Post-traumatic stress disorder [synthetic data]</td>\n",
269
- " </tr>\n",
270
- " <tr>\n",
271
- " <th>1</th>\n",
272
- " <td>A 50-year-old man is brought to the emergency ...</td>\n",
273
- " <td>Muffled heart sounds [versión aumentada]</td>\n",
274
- " </tr>\n",
275
- " <tr>\n",
276
- " <th>2</th>\n",
277
- " <td>A 30-year-old woman presents with generalized ...</td>\n",
278
- " <td>Ribavirin (datos generados)</td>\n",
279
- " </tr>\n",
280
- " <tr>\n",
281
- " <th>3</th>\n",
282
- " <td>A 58-year-old man with type 2 diabetes mellitu...</td>\n",
283
- " <td>Ludwig angina\\n\" [synthetic data]</td>\n",
284
- " </tr>\n",
285
- " <tr>\n",
286
- " <th>4</th>\n",
287
- " <td>A 55-year-old woman comes to the physician bec...</td>\n",
288
- " <td>Pulmonary embolism (datos generados)</td>\n",
289
- " </tr>\n",
290
- " </tbody>\n",
291
- "</table>\n",
292
- "</div>"
293
- ],
294
- "text/plain": [
295
- " question_sintetica \\\n",
296
- "0 A 55-year-old man with a history of myocardial... \n",
297
- "1 A 50-year-old man is brought to the emergency ... \n",
298
- "2 A 30-year-old woman presents with generalized ... \n",
299
- "3 A 58-year-old man with type 2 diabetes mellitu... \n",
300
- "4 A 55-year-old woman comes to the physician bec... \n",
301
- "\n",
302
- " answer_sintetica \n",
303
- "0 Post-traumatic stress disorder [synthetic data] \n",
304
- "1 Muffled heart sounds [versión aumentada] \n",
305
- "2 Ribavirin (datos generados) \n",
306
- "3 Ludwig angina\\n\" [synthetic data] \n",
307
- "4 Pulmonary embolism (datos generados) "
308
- ]
309
- },
310
- "execution_count": 5,
311
- "metadata": {},
312
- "output_type": "execute_result"
313
  }
314
  ],
315
  "source": [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  "def generar_datos_sinteticos_medqa(df, n=10):\n",
317
  " \"\"\"\n",
318
  " Genera datos sintéticos para el dataset MedQA.\n",
319
  " Toma 'n' muestras y modifica ligeramente el texto en las columnas question y answer.\n",
 
320
  " \n",
321
- " Retorna un DataFrame con las columnas modificadas.\n",
322
  " \"\"\"\n",
323
  " sampled = df.sample(n, replace=True)\n",
324
  " modificaciones = [\n",
325
- " \"(consulta sintética)\",\n",
326
- " \"[versión aumentada]\",\n",
327
- " \"(datos generados)\",\n",
328
- " \"[synthetic data]\"\n",
329
  " ]\n",
330
  " \n",
331
- " questions_sinteticas = []\n",
332
- " answers_sinteticas = []\n",
 
 
333
  " \n",
334
  " for _, row in sampled.iterrows():\n",
335
  " mod = random.choice(modificaciones)\n",
336
- " question = str(row[\"question\"]) + \" \" + mod\n",
337
- " answer = str(row[\"answer\"]) + \" \" + mod\n",
338
- " questions_sinteticas.append(question)\n",
339
- " answers_sinteticas.append(answer)\n",
 
 
 
 
 
 
 
 
 
340
  " \n",
341
- " df_sintetico_medqa = pd.DataFrame({\n",
342
- " \"question_sintetica\": questions_sinteticas,\n",
343
- " \"answer_sintetica\": answers_sinteticas\n",
 
 
344
  " })\n",
345
  " \n",
346
- " return df_sintetico_medqa\n",
 
 
 
 
347
  "\n",
348
- "# Generamos 10 filas sintéticas para MedQA\n",
349
- "medqa_sintetico = generar_datos_sinteticos_medqa(medqa, n=10)\n",
350
- "medqa_sintetico.head()"
 
 
 
 
 
 
 
 
351
  ]
352
  },
353
  {
354
  "cell_type": "code",
355
- "execution_count": 7,
356
  "metadata": {},
357
  "outputs": [
 
 
 
 
 
 
 
358
  {
359
  "name": "stdout",
360
  "output_type": "stream",
361
  "text": [
362
- "wikidoc_sintetico: (10000, 3)\n",
363
- "medqa_sintetico: (10178, 6)\n"
 
 
 
 
 
 
 
 
 
 
 
364
  ]
365
  }
366
  ],
367
  "source": [
368
- "print(\"wikidoc_sintetico:\", wikidoc.shape)\n",
369
- "print(\"medqa_sintetico:\", medqa.shape)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  ]
371
  },
372
  {
373
  "cell_type": "markdown",
374
  "metadata": {},
375
  "source": [
376
- "## 5. Conclusión\n",
377
- "\n",
378
- "Se han generado datos sintéticos de forma separada para las bases de datos **Wikidoc** y **MedQA**.\n",
379
- "Estos datos pueden usarse para realizar pruebas, evaluar la robustez de tus modelos y ampliar el conjunto de entrenamiento."
380
  ]
381
  },
382
  {
383
  "cell_type": "code",
384
- "execution_count": 8,
385
  "metadata": {},
386
  "outputs": [
387
  {
388
  "name": "stdout",
389
  "output_type": "stream",
390
  "text": [
391
- "Número de datos sintéticos generados para Wikidoc: 10\n",
392
- "Número de datos sintéticos generados para MedQA: 10\n"
393
  ]
394
  }
395
  ],
396
  "source": [
397
- "print(\"Número de datos sintéticos generados para Wikidoc:\", wikidoc_sintetico.shape[0])\n",
398
- "print(\"Número de datos sintéticos generados para MedQA:\", medqa_sintetico.shape[0])\n"
 
 
 
 
 
 
 
399
  ]
400
- },
401
- {
402
- "cell_type": "code",
403
- "execution_count": null,
404
- "metadata": {},
405
- "outputs": [],
406
- "source": []
407
  }
408
  ],
409
  "metadata": {
 
17
  },
18
  {
19
  "cell_type": "code",
20
+ "execution_count": 2,
21
  "metadata": {},
22
  "outputs": [],
23
  "source": [
 
37
  },
38
  {
39
  "cell_type": "code",
40
+ "execution_count": 3,
41
  "metadata": {},
42
  "outputs": [
43
  {
 
68
  "cell_type": "markdown",
69
  "metadata": {},
70
  "source": [
71
+ "Normalización de Texto: Limpia el texto en columnas como instruction, input, output, question, y answer. Por ejemplo, convierte a minúsculas, elimina espacios extras, y elimina caracteres especiales innecesarios:"
 
 
 
 
 
 
 
 
72
  ]
73
  },
74
  {
75
  "cell_type": "code",
76
  "execution_count": 4,
77
  "metadata": {},
78
+ "outputs": [],
79
+ "source": [
80
+ "import re\n",
81
+ "\n",
82
+ "def clean_text(text):\n",
83
+ " if pd.isna(text):\n",
84
+ " return \"\"\n",
85
+ " text = str(text).lower().strip()\n",
86
+ " text = re.sub(r'\\s+', ' ', text)\n",
87
+ " text = re.sub(r'[^\\w\\s]', '', text)\n",
88
+ " return text\n",
89
+ "\n",
90
+ "wikidoc['instruction'] = wikidoc['instruction'].apply(clean_text)\n",
91
+ "wikidoc['input'] = wikidoc['input'].apply(clean_text)\n",
92
+ "wikidoc['output'] = wikidoc['output'].apply(clean_text)"
93
+ ]
94
+ },
95
+ {
96
+ "cell_type": "markdown",
97
+ "metadata": {},
98
+ "source": [
99
+ "Eliminación de Duplicados: Si encuentras duplicados, elimínalos para evitar sesgos en el modelo:"
100
+ ]
101
+ },
102
+ {
103
+ "cell_type": "code",
104
+ "execution_count": 5,
105
+ "metadata": {},
106
+ "outputs": [],
107
+ "source": [
108
+ "wikidoc.drop_duplicates(inplace=True)"
109
+ ]
110
+ },
111
+ {
112
+ "cell_type": "markdown",
113
+ "metadata": {},
114
+ "source": [
115
+ "2. Mejores Prácticas para Preprocesar los Datos\n",
116
+ "a) Tokenización y Extracción de Entidades\n",
117
+ "Dado que trabajas con datos médicos y PLN, considera tokenizar el texto y extraer entidades relevantes (por ejemplo, nombres de enfermedades, síntomas, tratamientos) usando bibliotecas como spaCy o NLTK, o modelos preentrenados como BERT adaptados al dominio médico."
118
+ ]
119
+ },
120
+ {
121
+ "cell_type": "code",
122
+ "execution_count": 6,
123
+ "metadata": {},
124
  "outputs": [
125
  {
126
+ "name": "stderr",
127
+ "output_type": "stream",
128
+ "text": [
129
+ "c:\\Users\\pedro\\miniconda\\envs\\carecompanion\\lib\\site-packages\\spacy\\language.py:2141: FutureWarning: Possible set union at position 6328\n",
130
+ " deserializers[\"tokenizer\"] = lambda p: self.tokenizer.from_disk( # type: ignore[union-attr]\n"
131
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
133
  ],
134
  "source": [
135
+ "import spacy\n",
136
+ "\n",
137
+ "nlp = spacy.load(\"en_core_sci_md\") # Modelo para texto científico/médico\n",
138
+ "def extract_entities(text):\n",
139
+ " if pd.isna(text):\n",
140
+ " return []\n",
141
+ " doc = nlp(text)\n",
142
+ " return [ent.text for ent in doc.ents]\n",
143
+ "\n",
144
+ "wikidoc['entities_instruction'] = wikidoc['instruction'].apply(extract_entities)"
145
+ ]
146
+ },
147
+ {
148
+ "cell_type": "markdown",
149
+ "metadata": {},
150
+ "source": [
151
+ "b) Segmentación y Balanceo\n",
152
+ "Si los datos tienen sesgos (por ejemplo, más preguntas sobre ciertas enfermedades), asegúrate de balancearlos o de generar datos sintéticos para cubrir áreas subrepresentadas.\n",
153
+ "Usa técnicas como submuestreo, sobremuestreo, o generación sintética (ver siguiente sección) para equilibrar las clases o categorías.\n",
154
+ "c) Formato Estándar\n",
155
+ "Asegúrate de que las columnas tengan un formato consistente. Por ejemplo, si input o output pueden contener URLs o referencias, normalízalas o clasifícalas en categorías (por ejemplo, \"enlace externo\", \"texto descriptivo\")."
156
+ ]
157
+ },
158
+ {
159
+ "cell_type": "code",
160
+ "execution_count": 7,
161
+ "metadata": {},
162
+ "outputs": [],
163
+ "source": [
164
+ "def categorize_output(output):\n",
165
+ " if pd.isna(output):\n",
166
+ " return \"No output\"\n",
167
+ " if \"http\" in str(output).lower():\n",
168
+ " return \"URL\"\n",
169
+ " return \"Text\"\n",
170
+ "\n",
171
+ "wikidoc['output_type'] = wikidoc['output'].apply(categorize_output)"
172
+ ]
173
+ },
174
+ {
175
+ "cell_type": "markdown",
176
+ "metadata": {},
177
+ "source": [
178
+ "3. Generar Más Datos Sintéticos\n",
179
+ "Tu notebook ya incluye una base sólida para generar datos sintéticos con técnicas de data augmentation. Aquí tienes algunas recomendaciones para expandir y mejorar este proceso:\n",
180
+ "\n",
181
+ "a) Ampliar la Variedad de Modificaciones\n",
182
+ "En lugar de solo añadir frases modificadoras (como “[synthetic data]”, “(datos generados)”), considera técnicas más avanzadas:\n",
183
+ "Paráfrasis: Usa modelos de lenguaje como T5, BART, o Mistral para reescribir preguntas y respuestas manteniendo el significado. Por ejemplo:\n"
184
+ ]
185
+ },
186
+ {
187
+ "cell_type": "code",
188
+ "execution_count": 8,
189
+ "metadata": {},
190
+ "outputs": [
191
+ {
192
+ "name": "stderr",
193
+ "output_type": "stream",
194
+ "text": [
195
+ "c:\\Users\\pedro\\miniconda\\envs\\carecompanion\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
196
+ " from .autonotebook import tqdm as notebook_tqdm\n",
197
+ "c:\\Users\\pedro\\miniconda\\envs\\carecompanion\\lib\\site-packages\\torchvision\\datapoints\\__init__.py:12: UserWarning: The torchvision.datapoints and torchvision.transforms.v2 namespaces are still Beta. While we do not expect major breaking changes, some APIs may still change according to user feedback. Please submit any feedback you may have in this issue: https://github.com/pytorch/vision/issues/6753, and you can also check out https://github.com/pytorch/vision/issues/7319 to learn more about the APIs that we suspect might involve future changes. You can silence this warning by calling torchvision.disable_beta_transforms_warning().\n",
198
+ " warnings.warn(_BETA_TRANSFORMS_WARNING)\n",
199
+ "c:\\Users\\pedro\\miniconda\\envs\\carecompanion\\lib\\site-packages\\torchvision\\transforms\\v2\\__init__.py:54: UserWarning: The torchvision.datapoints and torchvision.transforms.v2 namespaces are still Beta. While we do not expect major breaking changes, some APIs may still change according to user feedback. Please submit any feedback you may have in this issue: https://github.com/pytorch/vision/issues/6753, and you can also check out https://github.com/pytorch/vision/issues/7319 to learn more about the APIs that we suspect might involve future changes. You can silence this warning by calling torchvision.disable_beta_transforms_warning().\n",
200
+ " warnings.warn(_BETA_TRANSFORMS_WARNING)\n",
201
+ "Device set to use cuda:0\n",
202
+ "You seem to be using the pipelines sequentially on GPU. In order to maximize efficiency please use a dataset\n"
203
+ ]
204
+ }
205
+ ],
206
+ "source": [
207
+ "from transformers import pipeline\n",
208
+ "\n",
209
+ "paraphraser = pipeline(\"text2text-generation\", model=\"t5-base\")\n",
210
+ "def paraphrase_text(text):\n",
211
+ " if pd.isna(text):\n",
212
+ " return \"\"\n",
213
+ " return paraphraser(f\"paraphrase: {text}\", max_length=50)[0]['generated_text']\n",
214
+ "\n",
215
+ "wikidoc['instruction_paraphrased'] = wikidoc['instruction'].apply(paraphrase_text)"
216
+ ]
217
+ },
218
+ {
219
+ "cell_type": "markdown",
220
+ "metadata": {},
221
+ "source": [
222
+ "Sustitución de Sinónimos: Reemplaza palabras clave con sinónimos médicos relevantes (por ejemplo, \"dolor intenso\" por \"dolor severo\") usando bibliotecas como nltk o wordnet.\n",
223
+ "Añadir Ruido Controlado: Introduce variaciones leves, como cambiar la duración o la intensidad en ejemplos (por ejemplo, \"dolor intenso durante 3 horas\" podría convertirse en \"dolor severo durante 4 horas\").\n",
224
+ "b) Aumentar el Volumen\n",
225
+ "En tu notebook generas 10 filas sintéticas por dataset, pero puedes escalar esto según tus necesidades. Por ejemplo, genera el 10-20% del tamaño original de cada dataset para entrenar modelos más robustos"
226
+ ]
227
+ },
228
+ {
229
+ "cell_type": "code",
230
+ "execution_count": 9,
231
+ "metadata": {},
232
+ "outputs": [],
233
+ "source": [
234
+ "# Definir la función\n",
235
  "def generar_datos_sinteticos_wikidoc(df, n=10):\n",
236
  " \"\"\"\n",
237
  " Genera datos sintéticos para el dataset Wikidoc.\n",
 
267
  " \"output_sintetico\": salidas_sinteticas\n",
268
  " })\n",
269
  " \n",
270
+ " return df_sintetico"
271
+ ]
272
+ },
273
+ {
274
+ "cell_type": "code",
275
+ "execution_count": 10,
276
+ "metadata": {},
277
+ "outputs": [
278
+ {
279
+ "name": "stdout",
280
+ "output_type": "stream",
281
+ "text": [
282
+ "Dimensiones de wikidoc_sintetico: (2000, 3)\n",
283
+ " instruction_sintetica \\\n",
284
+ "0 answer this question truthfully [datos aumenta... \n",
285
+ "1 answer this question truthfully (versión sinté... \n",
286
+ "2 answer this question truthfully [augmented] \n",
287
+ "3 answer this question truthfully (versión sinté... \n",
288
+ "4 answer this question truthfully [datos aumenta... \n",
289
+ "\n",
290
+ " input_sintetico \\\n",
291
+ "0 in cases of aortic dissection what does the ch... \n",
292
+ "1 what is the surgery for papillary muscle ruptu... \n",
293
+ "2 can you explain the connection between dysphag... \n",
294
+ "3 what information is available concerning the o... \n",
295
+ "4 what are the quality grades for left ventricul... \n",
296
+ "\n",
297
+ " output_sintetico \n",
298
+ "0 findings on chest xray suggestive of aortic di... \n",
299
+ "1 patients with rupture of the chordae tendineae... \n",
300
+ "2 modified barium swallow study conducted by a s... \n",
301
+ "3 before taking amiodarone tell your doctor and ... \n",
302
+ "4 following are the explanations for the differe... \n"
303
+ ]
304
+ }
305
+ ],
306
+ "source": [
307
+ "# Generar datos sintéticos (20% del tamaño original)\n",
308
+ "n_synthetic = int(0.2 * len(wikidoc)) # Genera el 20% de datos sintéticos\n",
309
+ "wikidoc_sintetico = generar_datos_sinteticos_wikidoc(wikidoc, n=n_synthetic)\n",
310
+ "\n",
311
+ "# Verificar resultados\n",
312
+ "print(\"Dimensiones de wikidoc_sintetico:\", wikidoc_sintetico.shape)\n",
313
+ "print(wikidoc_sintetico.head())"
314
+ ]
315
+ },
316
+ {
317
+ "cell_type": "markdown",
318
+ "metadata": {},
319
+ "source": [
320
+ "Combina los datos sintéticos con los originales en un nuevo archivo CSV:"
321
+ ]
322
+ },
323
+ {
324
+ "cell_type": "code",
325
+ "execution_count": 11,
326
+ "metadata": {},
327
+ "outputs": [],
328
+ "source": [
329
+ "import os\n",
330
+ "\n",
331
+ "# Create the directory if it doesn't exist\n",
332
+ "os.makedirs('../data/synthetic', exist_ok=True)\n",
333
  "\n",
334
+ "# Save the combined dataframe to CSV\n",
335
+ "wikidoc_combined = pd.concat([wikidoc, wikidoc_sintetico], ignore_index=True)\n",
336
+ "wikidoc_combined.to_csv(\"../data/synthetic/wikidoc.csv\", index=False)"
337
+ ]
338
+ },
339
+ {
340
+ "cell_type": "markdown",
341
+ "metadata": {},
342
+ "source": [
343
+ "---"
344
  ]
345
  },
346
  {
 
349
  "source": [
350
  "## 4. Generación de Datos Sintéticos para MedQA\n",
351
  " \n",
352
+ "1. Cargar y Preprocesar los Datos de MedQA\n",
353
+ "Primero, cargaremos el dataset de MedQA y realizaremos un preprocesamiento básico para limpiar el texto y eliminar duplicados."
 
 
 
 
354
  ]
355
  },
356
  {
357
  "cell_type": "code",
358
+ "execution_count": 18,
359
  "metadata": {},
360
  "outputs": [
361
  {
362
+ "name": "stdout",
363
+ "output_type": "stream",
364
+ "text": [
365
+ "MedQA original: (10178, 6)\n",
366
+ "MedQA tras eliminar duplicados: (10178, 6)\n"
367
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  }
369
  ],
370
  "source": [
371
+ "# Configuración inicial\n",
372
+ "pd.set_option('display.max_columns', None)\n",
373
+ "\n",
374
+ "# Ruta a los datos\n",
375
+ "raw_path = Path(\"../data/raw\")\n",
376
+ "medqa_file = raw_path / \"medqa.csv\"\n",
377
+ "medqa = pd.read_csv(medqa_file)\n",
378
+ "\n",
379
+ "print(\"MedQA original:\", medqa.shape)\n",
380
+ "\n",
381
+ "# Función para limpiar texto\n",
382
+ "def clean_text(text):\n",
383
+ " if pd.isna(text):\n",
384
+ " return \"\"\n",
385
+ " text = str(text).lower().strip()\n",
386
+ " text = re.sub(r'\\s+', ' ', text)\n",
387
+ " text = re.sub(r'[^\\w\\s]', '', text)\n",
388
+ " return text\n",
389
+ "\n",
390
+ "# Limpieza de columnas relevantes\n",
391
+ "medqa['question'] = medqa['question'].apply(clean_text)\n",
392
+ "medqa['answer'] = medqa['answer'].apply(clean_text)\n",
393
+ "\n",
394
+ "# Eliminar duplicados\n",
395
+ "medqa.drop_duplicates(subset=['question', 'answer'], inplace=True)\n",
396
+ "print(\"MedQA tras eliminar duplicados:\", medqa.shape)"
397
+ ]
398
+ },
399
+ {
400
+ "cell_type": "markdown",
401
+ "metadata": {},
402
+ "source": [
403
+ "2. Generar Datos Sintéticos para MedQA\n",
404
+ "Dado que MedQA tiene una estructura basada en preguntas de opción múltiple (question, answer, options, answer_idx, etc.), el proceso de generación debe mantener esta coherencia. Usaremos una función similar a la de Wikidoc, pero adaptada para generar variaciones en las preguntas y respuestas, respetando las opciones."
405
+ ]
406
+ },
407
+ {
408
+ "cell_type": "code",
409
+ "execution_count": 19,
410
+ "metadata": {},
411
+ "outputs": [
412
+ {
413
+ "name": "stdout",
414
+ "output_type": "stream",
415
+ "text": [
416
+ "Dimensiones de medqa_sintetico: (2035, 4)\n",
417
+ " question_sintetica \\\n",
418
+ "0 a 34yearold woman comes to the physician becau... \n",
419
+ "1 a young researcher is responsible for graphing... \n",
420
+ "2 a 43yearold woman presents to her primary care... \n",
421
+ "3 a 57yearold man presents to the emergency depa... \n",
422
+ "4 a 29yearold woman at 38 weeks gestation comes ... \n",
423
+ "\n",
424
+ " answer_sintetico \\\n",
425
+ "0 de quervain tenosynovitis (modificado sintétic... \n",
426
+ "1 a ventilation b blood flow c base of the lung ... \n",
427
+ "2 inhibition of hepatic gluconeogenesis (modific... \n",
428
+ "3 ca199 (versión sintética) \n",
429
+ "4 exposure to excessive androgenic steroids duri... \n",
430
+ "\n",
431
+ " options_sintetico answer_idx_sintetico \n",
432
+ "0 {'A': 'De Quervain tenosynovitis', 'B': 'Swan ... A \n",
433
+ "1 {'A': 'A: Ventilation B: Blood flow C: Base of... A \n",
434
+ "2 {'A': 'Activation of peroxisome proliferator-a... D \n",
435
+ "3 {'A': 'Alpha-fetoprotein', 'B': 'CA-19-9', 'C'... B \n",
436
+ "4 {'A': 'Defective androgen receptors', 'B': 'De... D \n"
437
+ ]
438
+ }
439
+ ],
440
+ "source": [
441
+ "# Función para generar datos sintéticos para MedQA\n",
442
  "def generar_datos_sinteticos_medqa(df, n=10):\n",
443
  " \"\"\"\n",
444
  " Genera datos sintéticos para el dataset MedQA.\n",
445
  " Toma 'n' muestras y modifica ligeramente el texto en las columnas question y answer.\n",
446
+ " Mantiene la estructura de options y answer_idx.\n",
447
  " \n",
448
+ " Retorna un DataFrame con las columnas sintéticas.\n",
449
  " \"\"\"\n",
450
  " sampled = df.sample(n, replace=True)\n",
451
  " modificaciones = [\n",
452
+ " \"(modificado sintéticamente)\",\n",
453
+ " \"[datos aumentados]\",\n",
454
+ " \"(versión sintética)\",\n",
455
+ " \"[synthetic]\"\n",
456
  " ]\n",
457
  " \n",
458
+ " preguntas_sinteticas = []\n",
459
+ " respuestas_sinteticas = []\n",
460
+ " opciones_sinteticas = []\n",
461
+ " answer_idx_sinteticos = []\n",
462
  " \n",
463
  " for _, row in sampled.iterrows():\n",
464
  " mod = random.choice(modificaciones)\n",
465
+ " # Modificar la pregunta\n",
466
+ " pregunta = str(row[\"question\"]) + \" \" + mod\n",
467
+ " # Modificar la respuesta\n",
468
+ " respuesta = str(row[\"answer\"]) + \" \" + mod\n",
469
+ " # Mantener las opciones originales\n",
470
+ " opciones = row[\"options\"]\n",
471
+ " # Mantener el índice de la respuesta correcta\n",
472
+ " answer_idx = row[\"answer_idx\"]\n",
473
+ " \n",
474
+ " preguntas_sinteticas.append(pregunta)\n",
475
+ " respuestas_sinteticas.append(respuesta)\n",
476
+ " opciones_sinteticas.append(opciones)\n",
477
+ " answer_idx_sinteticos.append(answer_idx)\n",
478
  " \n",
479
+ " df_sintetico = pd.DataFrame({\n",
480
+ " \"question_sintetica\": preguntas_sinteticas,\n",
481
+ " \"answer_sintetico\": respuestas_sinteticas,\n",
482
+ " \"options_sintetico\": opciones_sinteticas,\n",
483
+ " \"answer_idx_sintetico\": answer_idx_sinteticos\n",
484
  " })\n",
485
  " \n",
486
+ " return df_sintetico\n",
487
+ "\n",
488
+ "# Generar datos sintéticos (20% del tamaño original)\n",
489
+ "n_synthetic = int(0.2 * len(medqa)) # Genera el 20% de datos sintéticos\n",
490
+ "medqa_sintetico = generar_datos_sinteticos_medqa(medqa, n=n_synthetic)\n",
491
  "\n",
492
+ "# Verificar resultados\n",
493
+ "print(\"Dimensiones de medqa_sintetico:\", medqa_sintetico.shape)\n",
494
+ "print(medqa_sintetico.head())"
495
+ ]
496
+ },
497
+ {
498
+ "cell_type": "markdown",
499
+ "metadata": {},
500
+ "source": [
501
+ "3. Ampliar la Generación con Técnicas Avanzadas\n",
502
+ "Para mejorar la calidad de los datos sintéticos, podemos integrar técnicas avanzadas como paráfrasis. Aquí usaremos un modelo de lenguaje como T5 para reescribir las preguntas manteniendo su significado."
503
  ]
504
  },
505
  {
506
  "cell_type": "code",
507
+ "execution_count": 20,
508
  "metadata": {},
509
  "outputs": [
510
+ {
511
+ "name": "stderr",
512
+ "output_type": "stream",
513
+ "text": [
514
+ "Device set to use cuda:0\n"
515
+ ]
516
+ },
517
  {
518
  "name": "stdout",
519
  "output_type": "stream",
520
  "text": [
521
+ " question_sintetica \\\n",
522
+ "0 a 34yearold woman comes to the physician becau... \n",
523
+ "1 a young researcher is responsible for graphing... \n",
524
+ "2 a 43yearold woman presents to her primary care... \n",
525
+ "3 a 57yearold man presents to the emergency depa... \n",
526
+ "4 a 29yearold woman at 38 weeks gestation comes ... \n",
527
+ "\n",
528
+ " question_sintetica_paraphrased \n",
529
+ "0 a 34yearold woman comes to the physician becau... \n",
530
+ "1 a researcher is responsible for graphing labor... \n",
531
+ "2 :: a patient presents to her primary care prov... \n",
532
+ "3 a 57yearold man presents to the emergency depa... \n",
533
+ "4 a 29year old woman at 38 weeks gestation comes... \n"
534
  ]
535
  }
536
  ],
537
  "source": [
538
+ "from transformers import pipeline\n",
539
+ "\n",
540
+ "# Cargar el modelo de paráfrasis\n",
541
+ "paraphraser = pipeline(\"text2text-generation\", model=\"t5-base\")\n",
542
+ "\n",
543
+ "def paraphrase_text(text):\n",
544
+ " if pd.isna(text):\n",
545
+ " return \"\"\n",
546
+ " result = paraphraser(f\"paraphrase: {text}\", max_length=100)[0]['generated_text']\n",
547
+ " return result\n",
548
+ "\n",
549
+ "# Aplicar paráfrasis a las preguntas sintéticas\n",
550
+ "medqa_sintetico['question_sintetica_paraphrased'] = medqa_sintetico['question_sintetica'].apply(paraphrase_text)\n",
551
+ "\n",
552
+ "# Verificar resultados\n",
553
+ "print(medqa_sintetico[['question_sintetica', 'question_sintetica_paraphrased']].head())"
554
  ]
555
  },
556
  {
557
  "cell_type": "markdown",
558
  "metadata": {},
559
  "source": [
560
+ "4. Combinar y Guardar los Datos\n",
561
+ "Finalmente, combinamos los datos sintéticos con los originales y los guardamos en un archivo CSV."
 
 
562
  ]
563
  },
564
  {
565
  "cell_type": "code",
566
+ "execution_count": 21,
567
  "metadata": {},
568
  "outputs": [
569
  {
570
  "name": "stdout",
571
  "output_type": "stream",
572
  "text": [
573
+ "Datos combinados guardados en '../data/synthetic/medqa.csv'\n"
 
574
  ]
575
  }
576
  ],
577
  "source": [
578
+ "# Combinar datos originales y sintéticos\n",
579
+ "medqa_combined = pd.concat([medqa, medqa_sintetico], ignore_index=True)\n",
580
+ "\n",
581
+ "# Crear directorio si no existe\n",
582
+ "os.makedirs('../data/synthetic', exist_ok=True)\n",
583
+ "\n",
584
+ "# Guardar el dataset combinado\n",
585
+ "medqa_combined.to_csv(\"../data/synthetic/medqa.csv\", index=False)\n",
586
+ "print(\"Datos combinados guardados en '../data/synthetic/medqa.csv'\")"
587
  ]
 
 
 
 
 
 
 
588
  }
589
  ],
590
  "metadata": {
README.md CHANGED
@@ -1,12 +1,84 @@
1
- ---
2
- title: CareCompanion
3
- emoji: 💻
4
- colorFrom: green
5
- colorTo: yellow
6
- sdk: gradio
7
- sdk_version: 5.20.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # README – Asistente de Atención Médica y Asesoramiento (En Fase de Desarrollo)
2
+
3
+ ¡Bienvenido/a al repositorio del **Asistente de Atención Médica**! Este proyecto se encuentra **en fase de desarrollo**, por lo que algunas funcionalidades podrían cambiar o evolucionar con el tiempo.
4
+
5
+ ## Índice
6
+ - [README – Asistente de Atención Médica y Asesoramiento (En Fase de Desarrollo)](#readme--asistente-de-atención-médica-y-asesoramiento-en-fase-de-desarrollo)
7
+ - [Índice](#índice)
8
+ - [Descripción General](#descripción-general)
9
+ - [Herramientas Principales](#herramientas-principales)
10
+ - [1. Atención Primaria (Triaje)](#1-atención-primaria-triaje)
11
+ - [2. Asesoramiento](#2-asesoramiento)
12
+ - [Flujo de Datos](#flujo-de-datos)
13
+ - [Especificaciones Técnicas](#especificaciones-técnicas)
14
+ - [Entrada y Preprocesamiento](#entrada-y-preprocesamiento)
15
+ - [Algoritmos y Modelos](#algoritmos-y-modelos)
16
+ - [Integración entre Herramientas](#integración-entre-herramientas)
17
+ - [Generación de Datos Sintéticos](#generación-de-datos-sintéticos)
18
+ - [Estado del Proyecto](#estado-del-proyecto)
19
+
20
+
21
+ ## Descripción General
22
+ Este repositorio alberga un **asistente** dividido en dos herramientas principales orientadas a:
23
+ - **Detección y triaje** de posibles casos urgentes (Atención Primaria).
24
+ - **Asesoramiento** con información y recomendaciones generales basadas en conocimientos médicos.
25
+ - En desarrollo...
26
+
27
+ Por ahora el objetivo es ofrecer una **primera línea de respuesta** a dudas médicas y orientar a los usuarios para que reciban la atención adecuada.
28
+
29
+ > **Nota Importante:** Ninguna de estas herramientas sustituye la consulta con un profesional médico. Siempre aconsejamos acudir a un especialista.
30
+
31
+ ## Herramientas Principales
32
+
33
+ ### 1. Atención Primaria (Triaje)
34
+ - **Objetivo:** Evaluar síntomas y antecedentes para determinar la urgencia de la situación.
35
+ - **Puntos clave:**
36
+ - Recopilar datos básicos como intensidad, duración de los síntomas y factores de riesgo.
37
+ - Aplicar escalas de prioridad o criterios clínicos predefinidos.
38
+ - Generar alertas inmediatas (p. ej.: “busque atención de emergencia” o “concierto de cita no urgente”).
39
+
40
+ ### 2. Asesoramiento
41
+ - **Objetivo:** Brindar información y orientación general sobre enfermedades, tratamientos y autocuidado.
42
+ - **Puntos clave:**
43
+ - Responder preguntas abiertas y ofrecer referencias a guías o estudios médicos.
44
+ - Incluir siempre disclaimers para recordar que no se trata de un diagnóstico formal.
45
+ - En caso de detectar signos de alerta, recomendar el uso de la herramienta de Atención Primaria.
46
+
47
+ ## Flujo de Datos
48
+ 1. **Entrada de Datos**
49
+ - *Asesoramiento:* Texto libre, preguntas abiertas.
50
+ - *Triaje:* Formularios estructurados con campos específicos (síntomas, duración, antecedentes, etc.).
51
+ 2. **Procesamiento Inicial**
52
+ - Uso de **NLP** para extraer entidades médicas y evaluar gravedad.
53
+ - El Asesoramiento puede derivar al Triaje si detecta palabras clave o patrones urgentes.
54
+ 3. **Evaluación Específica**
55
+ - *Asesoramiento:* Se aporta respuesta detallada de la base de conocimientos médicos.
56
+ - *Triaje:* Se calcula una **puntuación de urgencia** y se emiten recomendaciones concretas.
57
+ 4. **Respuesta y Retroalimentación**
58
+ - El usuario recibe un informe con la recomendación adecuada (p. ej.: atención inmediata, cita programada, autocuidado).
59
+ - El sistema puede reasignar al usuario de Asesoramiento a Triaje o viceversa según sea necesario.
60
+
61
+ ## Especificaciones Técnicas
62
+
63
+ ### Entrada y Preprocesamiento
64
+ - **Asesoramiento:** Texto libre, limpieza de datos, tokenización y detección de entidades.
65
+ - **Triaje:** Datos estructurados (formularios), normalización y validación de campos.
66
+
67
+ ### Algoritmos y Modelos
68
+ - **NLP:** Modelos entrenados específicamente en vocabulario médico.
69
+ - **Clasificación de Urgencia:** Algoritmos de scoring que asignan un nivel de prioridad basado en criterios clínicos establecidos.
70
+
71
+ ### Integración entre Herramientas
72
+ - **API Interna:** Permite que Asesoramiento escale al Triaje cuando se detectan señales de alarma.
73
+ - **Modularidad:** Cada herramienta se puede mantener y actualizar de manera independiente.
74
+
75
+ ### Generación de Datos Sintéticos
76
+ - **Data Augmentation:** Creación de casos simulados o generación de frases de consulta con modelos de lenguaje para cubrir más escenarios.
77
+ - **Simulación Clínica:** Escenarios ficticios inspirados en casos reales para afinar la precisión de los modelos.
78
+
79
+
80
+ ## Estado del Proyecto
81
+ Actualmente, el proyecto se encuentra en **fase de desarrollo**. Esto implica que:
82
+ - Es posible que las funcionalidades no estén completamente implementadas.
83
+ - Se están realizando pruebas con datos sintéticos y de ejemplo.
84
+ - Podrían producirse cambios significativos en la estructura y el diseño del repositorio.
app.py CHANGED
@@ -1,32 +1,66 @@
1
- # Importar bibliotecas necesarias
2
- from transformers import pipeline
3
  import gradio as gr
 
 
 
 
 
 
 
4
 
5
- # Cargar el modelo (usamos Mistral como base inicial)
 
6
  health_nlp = pipeline("text-generation", model="mistralai/Mixtral-8x7B-Instruct-v0.1")
7
 
8
- # Función de triaje básico
9
- def triage_symptoms(symptoms):
10
- # Prompt claro para el modelo
11
- prompt = (
12
- f"Evalúa los siguientes síntomas: {symptoms}. "
13
- "Sugiere pasos a seguir (por ejemplo, descansar, visitar un médico) "
14
- "y añade un disclaimer legal indicando que esto no sustituye una consulta médica."
15
- )
16
- # Generar respuesta
17
- response = health_nlp(prompt, max_length=150, num_return_sequences=1)[0]["generated_text"]
18
- # Asegurar el disclaimer
19
- disclaimer = "\n\n*Nota: Este es un asistente de IA y no sustituye el consejo de un profesional médico. Consulta a un doctor para un diagnóstico preciso.*"
20
- return response + disclaimer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- # Crear la interfaz con Gradio
23
- interface = gr.Interface(
24
- fn=triage_symptoms,
25
- inputs=gr.Textbox(label="Describe tus síntomas", placeholder="Ejemplo: Tengo tos y fiebre desde ayer"),
26
- outputs=gr.Textbox(label="Sugerencias"),
27
- title="CareCompanion - Asistente de Triaje Básico",
28
- description="Ingresa tus síntomas y obtén sugerencias básicas. No reemplaza una consulta médica."
29
- )
 
 
 
30
 
31
- # Lanzar la aplicación
32
- interface.launch()
 
 
 
1
  import gradio as gr
2
+ import spacy
3
+ from faster_whisper import WhisperModel
4
+ from gtts import gTTS
5
+ from transformers import pipeline
6
+ import os
7
+ from tools.asesoramiento_tool import asesorar_consulta
8
+ from tools.triaje_tool import triaje_primer_tool
9
 
10
+ nlp = spacy.load("en_core_sci_md")
11
+ whisper_model = WhisperModel("tiny", device="cpu", compute_type="int8")
12
  health_nlp = pipeline("text-generation", model="mistralai/Mixtral-8x7B-Instruct-v0.1")
13
 
14
+ def speech_to_text(audio_path):
15
+ segments, _ = whisper_model.transcribe(audio_path, language="es")
16
+ return " ".join([segment.text for segment in segments])
17
+
18
+ def text_to_speech(text):
19
+ tts = gTTS(text, lang="es")
20
+ audio_file = "response.mp3"
21
+ tts.save(audio_file)
22
+ return audio_file
23
+
24
+ def process_input(audio, mode="asesoramiento"):
25
+ if audio is None:
26
+ return None, "Por favor, graba algo."
27
+
28
+ query = speech_to_text(audio)
29
+
30
+ if mode == "asesoramiento":
31
+ resultado = asesorar_consulta(query)
32
+ respuesta = resultado["respuesta"]
33
+ elif mode == "triaje":
34
+ doc = nlp(query.lower())
35
+ symptoms = [ent.text for ent in doc.ents if ent.label_ in ["SYMPTOM", "DISEASE"]]
36
+ data = {
37
+ "sintomas": " ".join(symptoms) if symptoms else query,
38
+ "intensidad": "moderada",
39
+ "duracion": "6",
40
+ "antecedentes": ""
41
+ }
42
+ resultado = triaje_primer_tool(data)
43
+ respuesta = f"Puntaje: {resultado['score']}. {resultado['recomendacion']}"
44
+ elif mode == "mistral":
45
+ prompt = f"Evalúa: {query}. Sugiere pasos a seguir."
46
+ respuesta = health_nlp(prompt, max_length=150)[0]["generated_text"]
47
+ respuesta += "\n\n*Nota: Este es un asistente de IA y no sustituye el consejo de un profesional médico.*"
48
+ else:
49
+ respuesta = "Modo no reconocido."
50
+
51
+ audio_response = text_to_speech(respuesta)
52
+ return audio_response, f"Pregunta: {query}\nRespuesta: {respuesta}"
53
 
54
+ with gr.Blocks(title="Agente Médico Speech-to-Speech") as demo:
55
+ gr.Markdown("# Agente Médico\nHabla y elige un modo: Asesoramiento, Triaje o Mistral.")
56
+ with gr.Row():
57
+ audio_input = gr.Audio(source="microphone", type="filepath", label="Habla aquí")
58
+ mode_select = gr.Radio(["asesoramiento", "triaje", "mistral"], label="Modo", value="asesoramiento")
59
+ with gr.Row():
60
+ audio_output = gr.Audio(label="Respuesta en audio")
61
+ text_output = gr.Textbox(label="Transcripción y Respuesta")
62
+ btn = gr.Button("Procesar")
63
+
64
+ btn.click(fn=process_input, inputs=[audio_input, mode_select], outputs=[audio_output, text_output])
65
 
66
+ demo.launch()
 
requirements.txt CHANGED
@@ -1,3 +1,5 @@
1
- transformers
2
- torch
3
- gradio
 
 
 
1
+ gradio
2
+ spacy
3
+ faster-whisper
4
+ gtts
5
+ transformers
script/00_syntetic_wikilock.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import random
3
+ from pathlib import Path
4
+ import re
5
+ from transformers import pipeline
6
+
7
+ # Configuración básica
8
+ raw_path = Path("../data/raw")
9
+ processed_path = Path("../data/processed")
10
+ synthetic_path = Path("../data/synthetic")
11
+
12
+ # Cargar datos
13
+ wikidoc_file = raw_path / "medical_meadow_wikidoc.csv"
14
+ wikidoc = pd.read_csv(wikidoc_file, encoding='utf-8')
15
+
16
+ # Limpieza de datos
17
+ def clean_text(text):
18
+ if pd.isna(text):
19
+ return ""
20
+ text = str(text).lower().strip()
21
+ text = re.sub(r'\s+', ' ', text)
22
+ text = re.sub(r'[^\w\s]', '', text)
23
+ return text
24
+
25
+ wikidoc['instruction'] = wikidoc['instruction'].apply(clean_text)
26
+ wikidoc['input'] = wikidoc['input'].apply(clean_text)
27
+ wikidoc['output'] = wikidoc['output'].apply(clean_text)
28
+
29
+ # Generación de datos sintéticos
30
+ def generate_synthetic_wikidoc(df, n=100):
31
+ sampled = df.sample(n, replace=True)
32
+ modificaciones = ["(modificado sintéticamente)", "[datos aumentados]", "(versión sintética)", "[augmented]"]
33
+
34
+ instructions, inputs, outputs = [], [], []
35
+ for _, row in sampled.iterrows():
36
+ mod = random.choice(modificaciones)
37
+ instruction = str(row["instruction"]) + " " + mod
38
+ input_text = (str(row["input"]) + " " + mod) if pd.notnull(row["input"]) else mod
39
+ output_text = str(row["output"]) + " " + mod
40
+ instructions.append(instruction)
41
+ inputs.append(input_text)
42
+ outputs.append(output_text)
43
+
44
+ df_synthetic = pd.DataFrame({
45
+ "instruction_sintetica": instructions,
46
+ "input_sintetico": inputs,
47
+ "output_sintetico": outputs
48
+ })
49
+ return df_synthetic
50
+
51
+ # Generar y guardar datos sintéticos
52
+ wikidoc_synthetic = generate_synthetic_wikidoc(wikidoc, n=100)
53
+ wikidoc_synthetic.to_csv(synthetic_path / "wikidoc_synthetic.csv", index=False)
54
+
55
+ # Combinar datos originales y sintéticos
56
+ wikidoc_combined = pd.concat([wikidoc, wikidoc_synthetic], ignore_index=True)
57
+ wikidoc_combined.to_csv(processed_path / "wikidoc_combined.csv", index=False)
58
+
59
+ print("Datos procesados y sintéticos generados exitosamente.")
script/01_syntetic_medqa.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import random
3
+ from pathlib import Path
4
+ import re
5
+ from transformers import pipeline
6
+
7
+ # Configuración básica
8
+ raw_path = Path("../data/raw")
9
+ processed_path = Path("../data/processed")
10
+ synthetic_path = Path("../data/synthetic")
11
+
12
+ # Cargar datos
13
+ medqa_file = raw_path / "medqa.csv"
14
+ medqa = pd.read_csv(medqa_file, encoding='utf-8')
15
+
16
+ # Limpieza de datos
17
+ def clean_text(text):
18
+ if pd.isna(text):
19
+ return ""
20
+ text = str(text).lower().strip()
21
+ text = re.sub(r'\s+', ' ', text) # Elimina espacios extras
22
+ text = re.sub(r'[^\w\s]', '', text) # Elimina caracteres especiales (opcional, ajusta según necesidad)
23
+ return text
24
+
25
+ # Aplicar limpieza a las columnas relevantes
26
+ medqa['question'] = medqa['question'].apply(clean_text)
27
+ medqa['answer'] = medqa['answer'].apply(clean_text)
28
+ # Si las opciones están en formato de lista o texto, también puedes limpiarlas
29
+ if 'options' in medqa.columns:
30
+ medqa['options'] = medqa['options'].apply(lambda x: clean_text(str(x)) if pd.notnull(x) else "")
31
+
32
+ # Verificación inicial (opcional, para debugging)
33
+ print("Dimensiones de MedQA:", medqa.shape)
34
+ print("Valores nulos en MedQA:\n", medqa.isnull().sum())
35
+ print("Duplicados en MedQA:", medqa.duplicated().sum())
36
+
37
+ # Manejo de nulos (por ejemplo, rellenar con valores predeterminados)
38
+ medqa.fillna({"options": "No options provided"}, inplace=True)
39
+
40
+ # Generación de datos sintéticos para MedQA
41
+ def generate_synthetic_medqa(df, n=100):
42
+ """
43
+ Genera datos sintéticos para el dataset MedQA.
44
+ Toma 'n' muestras y modifica ligeramente el texto en las columnas question y answer.
45
+ """
46
+ sampled = df.sample(n, replace=True)
47
+ modificaciones = [
48
+ "(consulta sintética)",
49
+ "[versión aumentada]",
50
+ "(datos generados)",
51
+ "[synthetic data]"
52
+ ]
53
+
54
+ questions, answers = [], []
55
+
56
+ for _, row in sampled.iterrows():
57
+ mod = random.choice(modificaciones)
58
+ question = str(row["question"]) + " " + mod
59
+ answer = str(row["answer"]) + " " + mod
60
+ questions.append(question)
61
+ answers.append(answer)
62
+
63
+ # Si quieres incluir opciones sintéticas, puedes generarlas de manera similar
64
+ if 'options' in df.columns:
65
+ options_sinteticas = [str(row["options"]) + " " + mod for _, row in sampled.iterrows()]
66
+ df_synthetic = pd.DataFrame({
67
+ "question_sintetica": questions,
68
+ "answer_sintetica": answers,
69
+ "options_sinteticas": options_sinteticas
70
+ })
71
+ else:
72
+ df_synthetic = pd.DataFrame({
73
+ "question_sintetica": questions,
74
+ "answer_sintetica": answers
75
+ })
76
+
77
+ return df_synthetic
78
+
79
+ # Generar y guardar datos sintéticos
80
+ medqa_synthetic = generate_synthetic_medqa(medqa, n=100)
81
+ medqa_synthetic.to_csv(synthetic_path / "medqa_synthetic.csv", index=False)
82
+
83
+ # Combinar datos originales y sintéticos
84
+ medqa_combined = pd.concat([medqa, medqa_synthetic], ignore_index=True)
85
+ medqa_combined.to_csv(processed_path / "medqa_combined.csv", index=False)
86
+
87
+ print("Datos procesados y sintéticos generados exitosamente para MedQA.")
tools/asesoramiento_tool.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ def evaluar_triaje(sintomas, intensidad, duracion, antecedentes):
4
+ score = 0
5
+ sintomas_criticos = ["dolor intenso", "falta de aire", "desmayo", "pérdida de conciencia"]
6
+ for sintoma in sintomas_criticos:
7
+ if sintoma in sintomas.lower():
8
+ score += 5
9
+ sintomas_moderados = ["fiebre alta", "dolor en el pecho", "mareos", "náusea"]
10
+ for sintoma in sintomas_moderados:
11
+ if sintoma in sintomas.lower():
12
+ score += 3
13
+ intensidad = intensidad.lower()
14
+ if intensidad in ["intensa", "alta"]:
15
+ score += 3
16
+ elif intensidad == "moderada":
17
+ score += 2
18
+ elif intensidad in ["leve", "baja"]:
19
+ score += 1
20
+ try:
21
+ duracion = float(duracion)
22
+ if duracion >= 24:
23
+ score += 3
24
+ elif duracion >= 6:
25
+ score += 2
26
+ else:
27
+ score += 1
28
+ except ValueError:
29
+ print("Error: La duración debe ser un valor numérico.")
30
+ antecedentes_relevantes = ["cardiopatía", "hipertensión", "diabetes"]
31
+ for item in antecedentes_relevantes:
32
+ if item in antecedentes.lower():
33
+ score += 2
34
+ return score
35
+
36
+ def recomendar_atencion(score):
37
+ if score >= 12:
38
+ return "Se recomienda atención de emergencia. Llame a los servicios de urgencia."
39
+ elif score >= 7:
40
+ return "Se sugiere acudir a consulta médica lo antes posible."
41
+ else:
42
+ return "Puede programar una consulta médica de rutina."
43
+
44
+ def triaje_primer_tool(data):
45
+ score = evaluar_triaje(
46
+ data.get("sintomas", ""),
47
+ data.get("intensidad", ""),
48
+ data.get("duracion", "0"),
49
+ data.get("antecedentes", "")
50
+ )
51
+ recomendacion = recomendar_atencion(score)
52
+ return {
53
+ "score": score,
54
+ "recomendacion": recomendacion
55
+ }
56
+
57
+ if __name__ == "__main__":
58
+ ejemplo_data = {
59
+ "sintomas": "El paciente presenta dolor intenso en el pecho y falta de aire.",
60
+ "intensidad": "intensa",
61
+ "duracion": "8",
62
+ "antecedentes": "El paciente tiene antecedentes de hipertensión."
63
+ }
64
+ resultado = triaje_primer_tool(ejemplo_data)
65
+ print("Puntaje de riesgo:", resultado["score"])
66
+ print("Recomendación:", resultado["recomendacion"])