Science4Insights commited on
Commit
c899bba
·
verified ·
1 Parent(s): 9477c5c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +18 -74
app.py CHANGED
@@ -4,8 +4,11 @@ import numpy as np
4
  import tempfile
5
  import os
6
  from typing import Dict
 
7
  from tqdm.auto import tqdm
8
-
 
 
9
 
10
  VARIABLES = {
11
  "Lugar de nacimiento": ["España", "Magreb", "Latinoamérica", "Otro país de Europa", "Otro lugar del mundo"],
@@ -76,36 +79,26 @@ def crear_grafico_frecuencias(df_resultados):
76
  """
77
  Crea gráficos de frecuencias para las respuestas de la encuesta
78
  """
79
- # Identificar las columnas de respuestas (empiezan con 'P')
80
  columnas_respuestas = [col for col in df_resultados.columns if col.startswith('P')]
81
 
82
  if not columnas_respuestas:
83
  return None
84
 
85
- # Crear una figura con subplots
86
  n_preguntas = len(columnas_respuestas)
87
- n_rows = (n_preguntas + 1) // 2 # Dos gráficos por fila
88
  fig = make_subplots(rows=n_rows, cols=2,
89
  subplot_titles=columnas_respuestas,
90
  vertical_spacing=0.1,
91
  horizontal_spacing=0.1)
92
 
93
- # Para cada pregunta
94
  for i, pregunta in enumerate(columnas_respuestas):
95
- # Calcular frecuencias
96
  freq = df_resultados[pregunta].value_counts()
97
-
98
- # Calcular porcentajes
99
  porcentajes = (freq / len(df_resultados) * 100).round(1)
100
-
101
- # Crear texto para las barras (frecuencia y porcentaje)
102
  text = [f"{v} ({p}%)" for v, p in zip(freq.values, porcentajes.values)]
103
 
104
- # Determinar posición en el subplot
105
  row = (i // 2) + 1
106
  col = (i % 2) + 1
107
 
108
- # Añadir barra
109
  fig.add_trace(
110
  go.Bar(
111
  x=freq.index,
@@ -118,11 +111,9 @@ def crear_grafico_frecuencias(df_resultados):
118
  col=col
119
  )
120
 
121
- # Actualizar layout del subplot
122
  fig.update_xaxes(title_text="Respuestas", row=row, col=col)
123
  fig.update_yaxes(title_text="Frecuencia", row=row, col=col)
124
 
125
- # Actualizar layout general
126
  fig.update_layout(
127
  title_text="Resultados de la Encuesta",
128
  showlegend=False,
@@ -150,20 +141,19 @@ def llamar_api_gpt(descripcion, encuesta, api_key):
150
 
151
  try:
152
  response = client.chat.completions.create(
153
- model="gpt-4o",
154
  messages=[
155
  {
156
  "role": "system",
157
- "content": [{"type": "text", "text": system_content}]
158
  },
159
  {
160
  "role": "user",
161
- "content": [{"type": "text", "text": encuesta}]
162
  }
163
  ],
164
- response_format={"type": "text"},
165
  temperature=0,
166
- max_completion_tokens=200,
167
  top_p=1,
168
  frequency_penalty=0,
169
  presence_penalty=0
@@ -171,34 +161,29 @@ def llamar_api_gpt(descripcion, encuesta, api_key):
171
  return response.choices[0].message.content, None
172
  except Exception as e:
173
  return None, str(e)
 
174
  def generar_entrevistado(config: Dict[str, Dict[str, float]], n: int) -> pd.DataFrame:
175
  """
176
- Genera un DataFrame con 'n' panelistas. Para cada variable de VARIABLES:
177
- - Si está en 'config', usa su distribución personalizada
178
- - Si no está, usa distribución uniforme
179
  """
180
  data = []
181
  for i in range(n):
182
  entrevistado = {"id_panelista": f"ID_{i+1:04d}"}
183
 
184
- # Asignar valor a cada variable
185
  for var, opciones in VARIABLES.items():
186
  if var in config:
187
- dist = list(config[var].values()) # p.ej. [0.3, 0.5, 0.2]
188
  suma = sum(dist)
189
  if suma > 0:
190
- dist = [x / suma for x in dist] # Normaliza
191
  else:
192
- # Si suman 0, forzamos uniforme
193
  dist = [1/len(opciones)] * len(opciones)
194
  valor = np.random.choice(opciones, p=dist)
195
  else:
196
- # Si no está en config => distribución uniforme
197
  valor = np.random.choice(opciones)
198
 
199
  entrevistado[var] = valor
200
 
201
- # Crear una descripción completa de la persona
202
  desc = (
203
  f"Se trata de una persona que ha nacido en {entrevistado['Lugar de nacimiento']}, de sexo {entrevistado['Sexo']} que pertenece a la Generación {entrevistado['Generación']}, "
204
  f"que reside en {entrevistado['Comunidad Autónoma']} (España), en un municipio de hábitat {entrevistado['Hábitat']}. "
@@ -214,6 +199,7 @@ def generar_entrevistado(config: Dict[str, Dict[str, float]], n: int) -> pd.Data
214
 
215
  df = pd.DataFrame(data)
216
  return df
 
217
  def lanzar_encuesta(df, texto_encuesta, api_key, progress=gr.Progress()):
218
  if not api_key:
219
  return None, None, "Error: Es necesario introducir una API Key de OpenAI", None
@@ -224,23 +210,18 @@ def lanzar_encuesta(df, texto_encuesta, api_key, progress=gr.Progress()):
224
  if not texto_encuesta:
225
  return None, None, "Error: Debes introducir el texto de la encuesta", None
226
 
227
- # Lista para almacenar resultados
228
  resultados = []
229
  errores = []
230
 
231
- # Información inicial
232
  total_panelistas = len(df)
233
  progress(0, desc=f"Iniciando encuesta para {total_panelistas} panelistas...")
234
 
235
- # Variables de perfil que queremos mantener (todas excepto 'Descripción')
236
  variables_perfil = [col for col in df.columns if col != 'Descripción']
237
 
238
- # Para cada panelista
239
  for i, (_, row) in enumerate(df.iterrows()):
240
  progress((i/total_panelistas),
241
  desc=f"Procesando panelista {i+1} de {total_panelistas}")
242
 
243
- # Llamar a la API
244
  respuestas, error = llamar_api_gpt(
245
  row['Descripción'],
246
  texto_encuesta,
@@ -252,10 +233,8 @@ def lanzar_encuesta(df, texto_encuesta, api_key, progress=gr.Progress()):
252
  continue
253
 
254
  try:
255
- # Procesar respuestas
256
  resp_dict = procesar_respuesta_api(respuestas)
257
 
258
- # Añadir todas las variables de perfil del panelista
259
  for var in variables_perfil:
260
  resp_dict[var] = row[var]
261
 
@@ -263,7 +242,6 @@ def lanzar_encuesta(df, texto_encuesta, api_key, progress=gr.Progress()):
263
  except Exception as e:
264
  errores.append(f"Error procesando respuesta de {row['id_panelista']}: {str(e)}")
265
 
266
- # Crear mensaje de resumen
267
  total_exitosos = len(resultados)
268
  total_errores = len(errores)
269
 
@@ -282,15 +260,11 @@ def lanzar_encuesta(df, texto_encuesta, api_key, progress=gr.Progress()):
282
  mensaje_resumen += f"<li>{error}</li>"
283
  mensaje_resumen += "</ul>"
284
 
285
- # Si no hay ningún resultado exitoso
286
  if not resultados:
287
  return None, None, mensaje_resumen, None
288
 
289
- # Crear DataFrame de resultados
290
  df_resultados = pd.DataFrame(resultados)
291
 
292
- # Reordenar las columnas para mejor visualización
293
- # Primero el ID, luego las variables de perfil, finalmente las respuestas
294
  columnas_respuestas = [col for col in df_resultados.columns
295
  if col not in variables_perfil]
296
  orden_columnas = ['id_panelista'] + \
@@ -299,35 +273,30 @@ def lanzar_encuesta(df, texto_encuesta, api_key, progress=gr.Progress()):
299
 
300
  df_resultados = df_resultados[orden_columnas]
301
 
302
- # Crear gráficos de frecuencias
303
  fig = crear_grafico_frecuencias(df_resultados)
304
 
305
- # Guardar a Excel
306
  with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
307
  df_resultados.to_excel(tmp.name, index=False)
308
  file_path = tmp.name
309
 
310
  progress(1.0, desc="¡Proceso completado!")
311
  return df_resultados, file_path, mensaje_resumen, fig
 
312
  def crear_interfaz():
313
  with gr.Blocks(title="Generador de Panelistas Sintéticos") as app:
314
  gr.Markdown("## 🧴 Generador de Consumidores de Cremas Antiarrugas")
315
 
316
- # API Key de OpenAI
317
  api_key = gr.Textbox(
318
  label="OpenAI API Key",
319
  placeholder="Introduce tu API Key de OpenAI...",
320
  type="password"
321
  )
322
 
323
- # Tamaño de la muestra
324
  n_muestra = gr.Number(label="Tamaño de la muestra", value=100, precision=0)
325
 
326
- # Variables para el estado y progreso
327
  estado = gr.Textbox(label="Estado del proceso", value="Esperando acción...")
328
  progreso = gr.Progress()
329
 
330
- # Listas donde acumulamos todos los checkboxes y sliders
331
  all_checkboxes = []
332
  all_sliders = []
333
  vars_options = []
@@ -337,14 +306,12 @@ def crear_interfaz():
337
  with gr.Group():
338
  gr.Markdown(f"### {var}")
339
 
340
- # Checkbox: si se quiere personalizar la distribución de esta variable
341
  var_checkbox = gr.Checkbox(
342
  label=f"Personalizar {var}",
343
  value=False
344
  )
345
  all_checkboxes.append(var_checkbox)
346
 
347
- # Sliders para cada opción de la variable
348
  for op in opciones:
349
  s = gr.Slider(
350
  minimum=0,
@@ -355,14 +322,11 @@ def crear_interfaz():
355
  )
356
  all_sliders.append(s)
357
 
358
- # Guardar la info para reconstruir 'config' después
359
  vars_options.append((var, opciones))
360
 
361
- # Salidas iniciales
362
  output_table = gr.Dataframe(label="Panelistas Generados")
363
  download_file = gr.File(label="Descargar Excel", file_count="single")
364
 
365
- # Nueva sección para la encuesta
366
  with gr.Accordion("Realizar Encuesta", open=False):
367
  encuesta_texto = gr.Textbox(
368
  label="Pegue aquí el texto de la encuesta",
@@ -372,41 +336,27 @@ def crear_interfaz():
372
  info_encuesta = gr.HTML(label="Información de la encuesta")
373
  btn_encuesta = gr.Button("Lanzar Encuesta")
374
 
375
- # Sección de resultados de la encuesta
376
  with gr.Tab("Resultados"):
377
  resultados_encuesta = gr.Dataframe(label="Resultados Detallados")
378
  download_resultados = gr.File(label="Descargar Resultados Excel")
379
 
380
- # Nueva pestaña para los gráficos
381
  with gr.Tab("Gráficos"):
382
  graficos_resultados = gr.Plot(label="Gráficos de Frecuencias")
383
 
384
- # Botón generar muestra
385
  btn_generar = gr.Button("Generar Muestra", variant="primary")
386
- return app # <-- ¡Faltaba este return!
387
 
388
  def generar(n, *values):
389
- """
390
- Recibe:
391
- - n (número)
392
- - un bloque de checkboxes (uno por variable)
393
- - un bloque de sliders (uno por opción de cada variable)
394
- """
395
  n_muestra_int = int(n)
396
  num_vars = len(vars_options)
397
 
398
- # Los primeros 'num_vars' valores son bool de checkboxes
399
  checks = values[:num_vars]
400
- # El resto son floats de sliders
401
  sliders = values[num_vars:]
402
 
403
  config_procesada = {}
404
  idx_slider = 0
405
 
406
- # Recorremos cada variable
407
  for i, (var, opciones) in enumerate(vars_options):
408
  if checks[i]:
409
- # Personalizar
410
  dist = {}
411
  for op in opciones:
412
  valor_slider = sliders[idx_slider]
@@ -414,20 +364,16 @@ def crear_interfaz():
414
  dist[op] = valor_slider / 100.0
415
  config_procesada[var] = dist
416
  else:
417
- # No se personaliza => avanzamos el índice de sliders sin usarlos
418
  idx_slider += len(opciones)
419
 
420
- # Generar DF
421
  df = generar_entrevistado(config_procesada, n_muestra_int)
422
 
423
- # Guardar a Excel en un archivo temporal
424
  with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
425
  df.to_excel(tmp.name, index=False)
426
  file_path = tmp.name
427
 
428
  return df, file_path, "Muestra generada correctamente"
429
 
430
- # Conectar los botones
431
  btn_generar.click(
432
  fn=generar,
433
  inputs=[n_muestra] + all_checkboxes + all_sliders,
@@ -439,9 +385,7 @@ def crear_interfaz():
439
  inputs=[output_table, encuesta_texto, api_key],
440
  outputs=[resultados_encuesta, download_resultados, info_encuesta, graficos_resultados]
441
  )
 
 
442
 
443
-
444
- # Configuración para Hugging Face
445
- if __name__ == "__main__":
446
- app = crear_interfaz()
447
- app.launch()
 
4
  import tempfile
5
  import os
6
  from typing import Dict
7
+ from openai import OpenAI
8
  from tqdm.auto import tqdm
9
+ import plotly.express as px
10
+ import plotly.graph_objects as go
11
+ from plotly.subplots import make_subplots
12
 
13
  VARIABLES = {
14
  "Lugar de nacimiento": ["España", "Magreb", "Latinoamérica", "Otro país de Europa", "Otro lugar del mundo"],
 
79
  """
80
  Crea gráficos de frecuencias para las respuestas de la encuesta
81
  """
 
82
  columnas_respuestas = [col for col in df_resultados.columns if col.startswith('P')]
83
 
84
  if not columnas_respuestas:
85
  return None
86
 
 
87
  n_preguntas = len(columnas_respuestas)
88
+ n_rows = (n_preguntas + 1) // 2
89
  fig = make_subplots(rows=n_rows, cols=2,
90
  subplot_titles=columnas_respuestas,
91
  vertical_spacing=0.1,
92
  horizontal_spacing=0.1)
93
 
 
94
  for i, pregunta in enumerate(columnas_respuestas):
 
95
  freq = df_resultados[pregunta].value_counts()
 
 
96
  porcentajes = (freq / len(df_resultados) * 100).round(1)
 
 
97
  text = [f"{v} ({p}%)" for v, p in zip(freq.values, porcentajes.values)]
98
 
 
99
  row = (i // 2) + 1
100
  col = (i % 2) + 1
101
 
 
102
  fig.add_trace(
103
  go.Bar(
104
  x=freq.index,
 
111
  col=col
112
  )
113
 
 
114
  fig.update_xaxes(title_text="Respuestas", row=row, col=col)
115
  fig.update_yaxes(title_text="Frecuencia", row=row, col=col)
116
 
 
117
  fig.update_layout(
118
  title_text="Resultados de la Encuesta",
119
  showlegend=False,
 
141
 
142
  try:
143
  response = client.chat.completions.create(
144
+ model="gpt-4",
145
  messages=[
146
  {
147
  "role": "system",
148
+ "content": system_content
149
  },
150
  {
151
  "role": "user",
152
+ "content": encuesta
153
  }
154
  ],
 
155
  temperature=0,
156
+ max_tokens=200,
157
  top_p=1,
158
  frequency_penalty=0,
159
  presence_penalty=0
 
161
  return response.choices[0].message.content, None
162
  except Exception as e:
163
  return None, str(e)
164
+
165
  def generar_entrevistado(config: Dict[str, Dict[str, float]], n: int) -> pd.DataFrame:
166
  """
167
+ Genera un DataFrame con 'n' panelistas
 
 
168
  """
169
  data = []
170
  for i in range(n):
171
  entrevistado = {"id_panelista": f"ID_{i+1:04d}"}
172
 
 
173
  for var, opciones in VARIABLES.items():
174
  if var in config:
175
+ dist = list(config[var].values())
176
  suma = sum(dist)
177
  if suma > 0:
178
+ dist = [x / suma for x in dist]
179
  else:
 
180
  dist = [1/len(opciones)] * len(opciones)
181
  valor = np.random.choice(opciones, p=dist)
182
  else:
 
183
  valor = np.random.choice(opciones)
184
 
185
  entrevistado[var] = valor
186
 
 
187
  desc = (
188
  f"Se trata de una persona que ha nacido en {entrevistado['Lugar de nacimiento']}, de sexo {entrevistado['Sexo']} que pertenece a la Generación {entrevistado['Generación']}, "
189
  f"que reside en {entrevistado['Comunidad Autónoma']} (España), en un municipio de hábitat {entrevistado['Hábitat']}. "
 
199
 
200
  df = pd.DataFrame(data)
201
  return df
202
+
203
  def lanzar_encuesta(df, texto_encuesta, api_key, progress=gr.Progress()):
204
  if not api_key:
205
  return None, None, "Error: Es necesario introducir una API Key de OpenAI", None
 
210
  if not texto_encuesta:
211
  return None, None, "Error: Debes introducir el texto de la encuesta", None
212
 
 
213
  resultados = []
214
  errores = []
215
 
 
216
  total_panelistas = len(df)
217
  progress(0, desc=f"Iniciando encuesta para {total_panelistas} panelistas...")
218
 
 
219
  variables_perfil = [col for col in df.columns if col != 'Descripción']
220
 
 
221
  for i, (_, row) in enumerate(df.iterrows()):
222
  progress((i/total_panelistas),
223
  desc=f"Procesando panelista {i+1} de {total_panelistas}")
224
 
 
225
  respuestas, error = llamar_api_gpt(
226
  row['Descripción'],
227
  texto_encuesta,
 
233
  continue
234
 
235
  try:
 
236
  resp_dict = procesar_respuesta_api(respuestas)
237
 
 
238
  for var in variables_perfil:
239
  resp_dict[var] = row[var]
240
 
 
242
  except Exception as e:
243
  errores.append(f"Error procesando respuesta de {row['id_panelista']}: {str(e)}")
244
 
 
245
  total_exitosos = len(resultados)
246
  total_errores = len(errores)
247
 
 
260
  mensaje_resumen += f"<li>{error}</li>"
261
  mensaje_resumen += "</ul>"
262
 
 
263
  if not resultados:
264
  return None, None, mensaje_resumen, None
265
 
 
266
  df_resultados = pd.DataFrame(resultados)
267
 
 
 
268
  columnas_respuestas = [col for col in df_resultados.columns
269
  if col not in variables_perfil]
270
  orden_columnas = ['id_panelista'] + \
 
273
 
274
  df_resultados = df_resultados[orden_columnas]
275
 
 
276
  fig = crear_grafico_frecuencias(df_resultados)
277
 
 
278
  with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
279
  df_resultados.to_excel(tmp.name, index=False)
280
  file_path = tmp.name
281
 
282
  progress(1.0, desc="¡Proceso completado!")
283
  return df_resultados, file_path, mensaje_resumen, fig
284
+
285
  def crear_interfaz():
286
  with gr.Blocks(title="Generador de Panelistas Sintéticos") as app:
287
  gr.Markdown("## 🧴 Generador de Consumidores de Cremas Antiarrugas")
288
 
 
289
  api_key = gr.Textbox(
290
  label="OpenAI API Key",
291
  placeholder="Introduce tu API Key de OpenAI...",
292
  type="password"
293
  )
294
 
 
295
  n_muestra = gr.Number(label="Tamaño de la muestra", value=100, precision=0)
296
 
 
297
  estado = gr.Textbox(label="Estado del proceso", value="Esperando acción...")
298
  progreso = gr.Progress()
299
 
 
300
  all_checkboxes = []
301
  all_sliders = []
302
  vars_options = []
 
306
  with gr.Group():
307
  gr.Markdown(f"### {var}")
308
 
 
309
  var_checkbox = gr.Checkbox(
310
  label=f"Personalizar {var}",
311
  value=False
312
  )
313
  all_checkboxes.append(var_checkbox)
314
 
 
315
  for op in opciones:
316
  s = gr.Slider(
317
  minimum=0,
 
322
  )
323
  all_sliders.append(s)
324
 
 
325
  vars_options.append((var, opciones))
326
 
 
327
  output_table = gr.Dataframe(label="Panelistas Generados")
328
  download_file = gr.File(label="Descargar Excel", file_count="single")
329
 
 
330
  with gr.Accordion("Realizar Encuesta", open=False):
331
  encuesta_texto = gr.Textbox(
332
  label="Pegue aquí el texto de la encuesta",
 
336
  info_encuesta = gr.HTML(label="Información de la encuesta")
337
  btn_encuesta = gr.Button("Lanzar Encuesta")
338
 
 
339
  with gr.Tab("Resultados"):
340
  resultados_encuesta = gr.Dataframe(label="Resultados Detallados")
341
  download_resultados = gr.File(label="Descargar Resultados Excel")
342
 
 
343
  with gr.Tab("Gráficos"):
344
  graficos_resultados = gr.Plot(label="Gráficos de Frecuencias")
345
 
 
346
  btn_generar = gr.Button("Generar Muestra", variant="primary")
 
347
 
348
  def generar(n, *values):
 
 
 
 
 
 
349
  n_muestra_int = int(n)
350
  num_vars = len(vars_options)
351
 
 
352
  checks = values[:num_vars]
 
353
  sliders = values[num_vars:]
354
 
355
  config_procesada = {}
356
  idx_slider = 0
357
 
 
358
  for i, (var, opciones) in enumerate(vars_options):
359
  if checks[i]:
 
360
  dist = {}
361
  for op in opciones:
362
  valor_slider = sliders[idx_slider]
 
364
  dist[op] = valor_slider / 100.0
365
  config_procesada[var] = dist
366
  else:
 
367
  idx_slider += len(opciones)
368
 
 
369
  df = generar_entrevistado(config_procesada, n_muestra_int)
370
 
 
371
  with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
372
  df.to_excel(tmp.name, index=False)
373
  file_path = tmp.name
374
 
375
  return df, file_path, "Muestra generada correctamente"
376
 
 
377
  btn_generar.click(
378
  fn=generar,
379
  inputs=[n_muestra] + all_checkboxes + all_sliders,
 
385
  inputs=[output_table, encuesta_texto, api_key],
386
  outputs=[resultados_encuesta, download_resultados, info_encuesta, graficos_resultados]
387
  )
388
+
389
+ return app
390
 
391
+ app = crear_interfaz()