vvillarreal-cfee commited on
Commit
e0c9b20
·
1 Parent(s): d183fa0

Refactor Streamlit app UI and enhance AI precompletion functionality; add .gitignore and Pipfile

Browse files
Files changed (3) hide show
  1. .gitignore +1 -0
  2. Pipfile +15 -0
  3. src/streamlit_app.py +105 -15
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ Pipfile.lock
Pipfile ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [[source]]
2
+ url = "https://pypi.org/simple"
3
+ verify_ssl = true
4
+ name = "pypi"
5
+
6
+ [packages]
7
+ altair = "*"
8
+ pandas = "*"
9
+ streamlit = "*"
10
+ google-genai = "*"
11
+
12
+ [dev-packages]
13
+
14
+ [requires]
15
+ python_version = "3.12"
src/streamlit_app.py CHANGED
@@ -4,7 +4,7 @@ import os
4
 
5
  # --- Interfaz de Usuario con Streamlit ---
6
  st.set_page_config(
7
- page_title="Generador de Post-Mortem (Gemini AI)",
8
  layout="wide"
9
  )
10
 
@@ -12,16 +12,97 @@ st.set_page_config(
12
  if 'gemini_api_key' not in st.session_state:
13
  st.session_state['gemini_api_key'] = ''
14
 
15
- st.title("📄 Generador de Informes Post-Mortem con Gemini AI")
16
- st.markdown("Ingresa los detalles de la incidencia y la IA generará un informe técnico estructurado.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  # --- Sidebar para la configuración de la API Key ---
19
  with st.sidebar:
20
- st.header("⚙️ Configuración")
21
 
22
  # Campo de entrada para la API Key
23
  st.session_state['gemini_api_key'] = st.text_input(
24
- "Ingresa tu API Key de Gemini",
25
  type="password",
26
  value=st.session_state['gemini_api_key']
27
  )
@@ -31,6 +112,9 @@ with st.sidebar:
31
  else:
32
  st.warning("🚨 Por favor, ingresa tu API Key de Gemini.")
33
 
 
 
 
34
 
35
  # --- Función para generar el Post-Mortem ---
36
  def generar_post_mortem(api_key, tipo_alerta, sistema, fecha_hora, impacto, acciones):
@@ -83,37 +167,43 @@ def generar_post_mortem(api_key, tipo_alerta, sistema, fecha_hora, impacto, acci
83
  # --- Formulario de entrada de datos principal ---
84
  with st.form("post_mortem_form"):
85
  st.subheader("Detalles de la Incidencia")
86
-
87
  col1, col2 = st.columns(2)
88
  with col1:
89
  tipo_alerta = st.text_input(
90
  "Tipo de Alerta / Título del Problema",
91
- placeholder="Ej: High CPU usage en DB Server; Caída del servicio de Login"
 
 
92
  )
93
  sistema_afectado = st.text_input(
94
  "Sistema Afectado",
95
- placeholder="Ej: Servidor de Base de Datos; Microservicio de Autenticación"
 
 
96
  )
97
-
98
  with col2:
99
  fecha_hora = st.text_input(
100
  "Fecha y Hora",
101
- placeholder="Ej: 26/Sep/2025 21:45 PM UTC-3"
 
 
102
  )
103
-
104
  st.subheader("Descripción y Consecuencias")
105
  impacto_detalle = st.text_area(
106
  "Impacto del Negocio y Observaciones",
 
107
  placeholder="Ej: Latencia elevada afectó al 20% de los usuarios.",
108
- height=150
 
109
  )
110
-
111
  acciones_tomadas = st.text_area(
112
  "Acciones Tomadas (Mitigación Inmediata)",
 
113
  placeholder="Ej: Se escaló a Dev Team. Se reinició el servicio crítico.",
114
- height=150
 
115
  )
116
-
117
  # Botón de envío
118
  submitted = st.form_submit_button("🚀 Generar Informe Post-Mortem")
119
 
 
4
 
5
  # --- Interfaz de Usuario con Streamlit ---
6
  st.set_page_config(
7
+ page_title="Generador IA de Informes Post-Mortem",
8
  layout="wide"
9
  )
10
 
 
12
  if 'gemini_api_key' not in st.session_state:
13
  st.session_state['gemini_api_key'] = ''
14
 
15
+
16
+ st.title("📄 Generador IA de Informes Post-Mortem")
17
+
18
+ with st.expander("ℹ️ Dejar que la IA precomplete los campos", expanded=False):
19
+ # --- Cuadro de texto libre para pegar el texto raw de la alerta/incidente ---
20
+ if 'raw_text' not in st.session_state:
21
+ st.session_state['raw_text'] = ''
22
+ if 'precomplete_triggered' not in st.session_state:
23
+ st.session_state['precomplete_triggered'] = False
24
+
25
+ raw_text = st.text_area(
26
+ "Texto de la alerta/incidente (puede pegar aquí el mensaje completo)",
27
+ value=st.session_state['raw_text'],
28
+ height=120,
29
+ key="raw_text_area"
30
+ )
31
+
32
+ # Botón para precompletar los campos con IA
33
+ precomplete = st.button("Precompletar campos con IA", icon="🧠")
34
+
35
+ # --- Lógica para precompletar campos ---
36
+ def precompletar_campos_con_ia(api_key, raw_text):
37
+ """
38
+ Llama a Gemini para analizar el texto raw y extraer los campos estructurados.
39
+ """
40
+ MODEL_NAME = "gemini-2.5-flash"
41
+ try:
42
+ client = genai.Client(api_key=api_key)
43
+ except Exception as e:
44
+ return {"error": f"Error al inicializar el cliente de Gemini: {e}"}
45
+
46
+ system_instruction = (
47
+ "Eres un asistente experto en IT. Analiza el siguiente texto de alerta/incidente y extrae los siguientes campos en formato JSON:\n"
48
+ "- tipo_alerta: Título o tipo principal del problema\n"
49
+ "- sistema_afectado: Sistema, servicio o componente afectado\n"
50
+ "- fecha_hora: Fecha y hora de inicio del incidente\n"
51
+ "- impacto_detalle: Impacto del negocio y observaciones\n"
52
+ "- acciones_tomadas: Acciones inmediatas tomadas\n"
53
+ "Responde solo con el JSON, sin explicaciones ni texto adicional."
54
+ )
55
+ prompt_content = f"""
56
+ Extrae los campos solicitados del siguiente texto de alerta/incidente:\n\n{raw_text}
57
+ """
58
+ try:
59
+ response = client.models.generate_content(
60
+ model=MODEL_NAME,
61
+ contents=prompt_content,
62
+ config=genai.types.GenerateContentConfig(
63
+ system_instruction=system_instruction
64
+ )
65
+ )
66
+ import json
67
+ # Buscar el primer bloque JSON en la respuesta
68
+ import re
69
+ match = re.search(r'\{[\s\S]*\}', response.text)
70
+ if match:
71
+ campos = json.loads(match.group(0))
72
+ return campos
73
+ else:
74
+ return {"error": "No se pudo extraer el JSON de la respuesta de la IA."}
75
+ except Exception as e:
76
+ return {"error": f"Error al analizar el texto con Gemini: {e}"}
77
+
78
+ # Si el usuario presiona el botón de precompletar
79
+ if precomplete:
80
+ st.session_state['raw_text'] = raw_text
81
+ st.session_state['precomplete_triggered'] = True
82
+ api_key = st.session_state.get('gemini_api_key')
83
+ if not api_key:
84
+ st.error("❌ Por favor, ingresa tu API Key de Gemini en el panel lateral (sidebar) antes de continuar.")
85
+ elif not raw_text.strip():
86
+ st.error("❌ Por favor, pega el texto de la alerta o incidente para analizar.")
87
+ else:
88
+ with st.spinner("🔎 Analizando texto y extrayendo campos con Gemini..."):
89
+ resultado = precompletar_campos_con_ia(api_key, raw_text)
90
+ if 'error' in resultado:
91
+ st.error(resultado['error'])
92
+ else:
93
+ # Guardar los campos extraídos en session_state para precompletar el formulario
94
+ for campo in ['tipo_alerta', 'sistema_afectado', 'fecha_hora', 'impacto_detalle', 'acciones_tomadas']:
95
+ st.session_state[campo] = resultado.get(campo, '')
96
+ st.success("Campos precompletados. Revisa y edita antes de generar el informe.")
97
+
98
 
99
  # --- Sidebar para la configuración de la API Key ---
100
  with st.sidebar:
101
+ st.header("⚙️ Instrucciones")
102
 
103
  # Campo de entrada para la API Key
104
  st.session_state['gemini_api_key'] = st.text_input(
105
+ "1. 🔑 Ingresa tu API Key de Gemini",
106
  type="password",
107
  value=st.session_state['gemini_api_key']
108
  )
 
112
  else:
113
  st.warning("🚨 Por favor, ingresa tu API Key de Gemini.")
114
 
115
+ st.write("2. 📄 Completa el formulario con los detalles de la incidencia (o pega el texto RAW y deja que la IA extraiga los campos)")
116
+ st.write("3. 🚀 Presiona el botón y la IA generará un informe técnico estructurado post-mortem de tu incidente.")
117
+
118
 
119
  # --- Función para generar el Post-Mortem ---
120
  def generar_post_mortem(api_key, tipo_alerta, sistema, fecha_hora, impacto, acciones):
 
167
  # --- Formulario de entrada de datos principal ---
168
  with st.form("post_mortem_form"):
169
  st.subheader("Detalles de la Incidencia")
170
+ # Usar session_state para precompletar si corresponde
171
  col1, col2 = st.columns(2)
172
  with col1:
173
  tipo_alerta = st.text_input(
174
  "Tipo de Alerta / Título del Problema",
175
+ value=st.session_state.get('tipo_alerta', ''),
176
+ placeholder="Ej: High CPU usage en DB Server; Caída del servicio de Login",
177
+ key="tipo_alerta_input"
178
  )
179
  sistema_afectado = st.text_input(
180
  "Sistema Afectado",
181
+ value=st.session_state.get('sistema_afectado', ''),
182
+ placeholder="Ej: Servidor de Base de Datos; Microservicio de Autenticación",
183
+ key="sistema_afectado_input"
184
  )
 
185
  with col2:
186
  fecha_hora = st.text_input(
187
  "Fecha y Hora",
188
+ value=st.session_state.get('fecha_hora', ''),
189
+ placeholder="Ej: 26/Sep/2025 21:45 PM UTC-3",
190
+ key="fecha_hora_input"
191
  )
 
192
  st.subheader("Descripción y Consecuencias")
193
  impacto_detalle = st.text_area(
194
  "Impacto del Negocio y Observaciones",
195
+ value=st.session_state.get('impacto_detalle', ''),
196
  placeholder="Ej: Latencia elevada afectó al 20% de los usuarios.",
197
+ height=150,
198
+ key="impacto_detalle_input"
199
  )
 
200
  acciones_tomadas = st.text_area(
201
  "Acciones Tomadas (Mitigación Inmediata)",
202
+ value=st.session_state.get('acciones_tomadas', ''),
203
  placeholder="Ej: Se escaló a Dev Team. Se reinició el servicio crítico.",
204
+ height=150,
205
+ key="acciones_tomadas_input"
206
  )
 
207
  # Botón de envío
208
  submitted = st.form_submit_button("🚀 Generar Informe Post-Mortem")
209