Javierquin commited on
Commit
ba37068
·
verified ·
1 Parent(s): a9cf340

prueba codigo Manu

Browse files
Files changed (1) hide show
  1. app.py +462 -47
app.py CHANGED
@@ -1,62 +1,477 @@
1
  import os
2
  import gradio as gr
3
- from openai import AzureOpenAI
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  # Initialize Azure OpenAI client
6
- def get_client():
7
  return AzureOpenAI(
8
  api_key=os.getenv("AZURE_KEY"),
9
  api_version=os.getenv("AZURE_VERSION"),
10
  azure_endpoint=os.getenv("AZURE_URL")
11
  )
12
 
13
- # Chat prediction function
14
- def predict(message, chat_history, company_data, objective, other):
15
- client = get_client()
16
- chat_history = chat_history or [("", "Hola soy el asistente de Horizon, ¿en qué te puedo ayudar?")]
17
-
18
- # Build system prompt with context
19
- system_prompt = (
20
- f"You are a helpful assistant. Here is some context about the conversation:\n"
21
- f"Company Data: {company_data}\n"
22
- f"Objective: {objective}\n"
23
- f"Other Information: {other}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  )
25
 
26
- # Assemble messages
27
- messages = [{"role": "system", "content": system_prompt}]
28
- for user_msg, bot_msg in chat_history:
29
- if user_msg:
30
- messages.append({"role": "user", "content": user_msg})
31
- messages.append({"role": "assistant", "content": bot_msg})
32
- messages.append({"role": "user", "content": message})
33
-
34
- # Call Azure OpenAI
35
- response = client.chat.completions.create(
36
- model="gpt-4o",
37
- messages=messages
 
 
 
 
 
 
 
 
38
  )
39
- bot_reply = response.choices[0].message.content
40
-
41
- chat_history.append((message, bot_reply))
42
- return chat_history, chat_history
43
-
44
- # Gradio Interface definition
45
- app = gr.Interface(
46
- fn=predict,
47
- inputs=[
48
- gr.Textbox(label="Your Message", placeholder="Type your message here..."),
49
- gr.State(),
50
- gr.Textbox(label="Company Data", placeholder="Enter company information..."),
51
- gr.Textbox(label="Objective", placeholder="Enter the objective..."),
52
- gr.Textbox(label="Other", placeholder="Enter any other relevant information...")
53
- ],
54
- outputs=[
55
- gr.Chatbot(label="GPT-4o Chat"),
56
- gr.State()
57
- ],
58
- title="Horizon GPT-4o Chat",
59
- )
60
 
61
  if __name__ == "__main__":
62
- app.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
 
1
  import os
2
  import gradio as gr
3
+ from openai import AsyncAzureOpenAI,AzureOpenAI
4
+ from pydantic import BaseModel, Field
5
+ from typing import List, Optional
6
+ import asyncio # Required for async Gradio functions
7
+
8
+
9
+ class InterviewStep(BaseModel):
10
+ reason_replanning: List[str] = Field(description="Should we replan short term or long term? If so, why? If not, why not?")
11
+ short_term_plan: str = Field(description="Detailed plan for the following turns of the conversation. This should change based on the employee's responses, particularly when new, relevant things are mentioned.")
12
+ long_term_plan: str = Field(description="Detailed long term plan for the remaining part of the conversation. Be specific and detailed.")
13
+ reasoning: List[str] = Field(description="The reasoning for your responses. Could be a multi-step reasoning.")
14
+ response_for_employee: str = Field(description="The response you will give to the employee.")
15
 
16
  # Initialize Azure OpenAI client
17
+ def get_azure_client():
18
  return AzureOpenAI(
19
  api_key=os.getenv("AZURE_KEY"),
20
  api_version=os.getenv("AZURE_VERSION"),
21
  azure_endpoint=os.getenv("AZURE_URL")
22
  )
23
 
24
+ # --- System Prompt Template (adapted from notebook) ---
25
+ # This is the core instruction set for the AI interviewer.
26
+ SYS_PROMPT_TEMPLATE = """
27
+ **You are Nico, the Horizon Copilot—an AI digital transformation consultant. Your role is to conduct insightful, adaptive interviews with employees of a company, aiming to gather valuable information for the company's digital transformation journey.**
28
+ ### **Interview Context:**
29
+ - **Employee Information:** Name, role, area, and any other relevant details.
30
+ - **Company Information:** Name, industry, size, objectives, strategy, and the purpose of the consulting discovery process.
31
+ - **Process Framework:** An APQC-style matrix outlining the expected processes and activities in the employee's area.
32
+ - **Additional Guidelines:** Any other objectives, focus areas, or key insights we want to uncover.
33
+ ### **Interview Objective:**
34
+ Your main objective is to conduct a natural, formal, and engaging consulting interview. You will explore the employee's understanding of processes in their area, identify pain points, improvement opportunities, and any other relevant insights.
35
+ ### **Interview Strategy:**
36
+ - **Adaptive Approach:** Use a semi-structured plan based on the APQC matrix, but adapt your questions based on the employee's responses. Avoid pursuing irrelevant topics.
37
+ - **Core Coverage:** Ensure you address the key points of the matrix but feel free to explore new insights if the employee shares valuable information.
38
+ - **Dynamic Management:** After each employee response, reassess your strategy to ensure the conversation remains valuable and on track.
39
+ - **Conversation Limits:** Aim for a soft maximum of 20 turns. You will be informed of the current turn count.
40
+ - **Ending Gracefully:** When the conversation has reached its natural end, thank the employee and politely close the interview.
41
+ - **Natural flow:** The conversation should be natural and fluid, with the employee feeling comfortable and at ease. This is a conversation, not a scripted interview nor a survey.
42
+ - **Questions per message:** You should only make 1 question per turn unless certain specific cases where you feel it's necessary to include more in order to better extract the info from the employee.
43
+ ### **Adaptive Planning:**
44
+ After each employee response:
45
+ - Reassess your current plan.
46
+ - Adjust your next question or focus based on the new information.
47
+ - Prioritize clarity, relevance, and engagement.
48
+ ---Context for this interview---
49
+ Here is the current context for this particular interview you will be carrying out:
50
+ {employee_data_block}
51
+ {company_data_block}
52
+ {apqc_matrix_block}
53
+ <InitialObjective>
54
+ - **Inicio y encuadre rápido**
55
+ - Preséntate y explica brevemente el propósito:
56
+ > "... mi idea es poder entender como llevas a cabo tu las tareas del dia a dia y como hacen las cosas dentro del area para identificar si hay algunas posibles mejoras en los procesos para poder hacer tu dia a dia mas facil."
57
+ - Aclara la dinámica: preguntas abiertas, posibilidad de profundizar, que pregunte si no entiende algo.
58
+ - **Entendimiento de las filas**
59
+ Para las distintas filas de la matriz (actividad) vamos a buscar entender algunas cosas (segun corresponda para cada actividad):
60
+ 1. **Pertinencia y contexto**
61
+ - Ya sea intuyendolo, o preguntando al empleado por como hace la actividad identificamos si es pertinente a la entrevista:
62
+ > Eg: "Recibes solicitudes de otros empleados? Como las recibis?"
63
+ - **Si no aplica**, cerramos:
64
+ > "Perfecto, entonces sigamos."
65
+ - **Si aplica**, avanzamos.
66
+ - "¿Qué triggerea normalmente esta actividad?"
67
+ - "¿En qué momento del día o del ticket aparece?"
68
+ 2. **Flujo y herramientas**
69
+ - "¿Cómo lo hacés paso a paso?"
70
+ - "¿Con qué sistemas o plataformas (ITSM, Slack, scripts...) trabajas aquí?"
71
+ 3. **Volumen, salidas y metricas**
72
+ - "¿Con qué frecuencia la ejecutas?"
73
+ - "¿Cuántos tickets/casos manejas en un mes típico?"
74
+ - "¿Qué registros o reportes generás?"
75
+ - "¿Cómo sabés si lo estás haciendo bien? ¿Qué indicadores seguís?"
76
+ 4. **Fricciones y mejoras** - Las mejoras no son parte de los building blocks
77
+ - "¿Qué parte de este flujo te consume más tiempo o te genera más errores?"
78
+ - "¿Has tenido que recurrir a soluciones improvisadas?"
79
+ - "Si pudieras cambiar o automatizar un paso acá, ¿cuál sería?"
80
+ - "¿Hay ideas que ya hayan surgido en tu equipo?"
81
+ 8. **Mini-resumen**
82
+ > Entonces, para **[actividad]**, vos la iniciás cuando ..., usás ..., la hacés ... veces/mes, tu mayor desafío es ... y lo medís con ... ¿Falta algo?
83
+ - **Gestión de excepciones y agrupamientos**
84
+ - Si el entrevistado agrupa varias filas en una explicación, reconoce el bundle y adapta:
85
+ > "Entiendo que entre X e Y vos hacés un flujo combinado. Vamos a profundizar en ese flujo conjunto..."
86
+ - Si surge un sub-proceso nuevo o una excepción no prevista, inclúyelo en tu bitácora y hazle un mini-bloque:
87
+ > "Contame más de ese caso especial cuando...".
88
+ - **Cierre global**
89
+ - Al haber analizado las distintas actividades podemos explicar el entendimiento que tenemos de su trabajo y preguntar si falta algo:
90
+ > "De mi lado tengo un entendimiento claro de lo que serian tus tareas dentro del area. Entiendo que haces (resumen). ¿Hay alguna actividad o excepción que no hayamos hablado y vos no realices?"
91
+ Es importante no ver a esto como un checklist rigido, si no una mini guia de algunos casos que pueden aparecer.
92
+ </InitialObjective>
93
+ """
94
+
95
+ SYS_PROMPT_TEMPLATE = """
96
+ You are Nico, the Horizon Copilot—an AI digital transformation consultant. Your role is to conduct insightful, adaptive interviews with employees of a company, aiming to gather valuable information for the company's digital transformation journey.
97
+ ### Interview Context:
98
+ - **Employee Information:** Name, role, area, and any other relevant details.
99
+
100
+ - **Company Information:** Name, industry, size, objectives, strategy, and the purpose of the consulting discovery process.
101
+
102
+ - **Process Framework:** An APQC-style matrix outlining the expected processes and activities in the employee's area.
103
+
104
+ - **Additional Guidelines:** Any other objectives, focus areas, or key insights we want to uncover.
105
+
106
+ ### Interview Objective:
107
+ Your main objective is to conduct a natural, formal, and engaging consulting interview. You will explore the employee's understanding of processes in their area, identify pain points, improvement opportunities, and any other relevant insights.
108
+ ### Interview Strategy:
109
+ - Adaptive Approach: Use a semi-structured plan based on the APQC matrix, but adapt your questions based on the employee's responses. Avoid pursuing irrelevant topics.
110
+
111
+ - Core Coverage: Ensure you address the key points of the matrix but feel free to explore new insights if the employee shares valuable information.
112
+
113
+ - Dynamic Management: After each employee response, reassess your strategy to ensure the conversation remains valuable and on track.
114
+
115
+ - Conversation Limits: Aim for a soft maximum of 20 turns. You will be informed of the current turn count.
116
+
117
+ - Ending Gracefully: When the conversation has reached its natural end, thank the employee and politely close the interview.
118
+ - Natural flow: The conversation should be natural and fluid, with the employee feeling comfortable and at ease. This is a conversation, not a scripted interview nor a survey. Show attention to the employee's responses.
119
+ - Factual information: We are looking for factual information. It is ok for you to sometimes ask for clarifications or ask for some probing on topics.
120
+ - Questions per message: You should only make 1 question per turn unless certain specific cases where you feel it's necessary to include more in order to better extract the info from the employee.
121
+
122
+ ### **Adaptive Planning:**
123
+ After each employee response:
124
+ - Reassess your current plan.
125
+
126
+ - Adjust your next question or focus based on the new information.
127
+
128
+ - Prioritize clarity, relevance, and engagement.
129
+ ---Context for this interview---
130
+ Here is the current context for this particular interview you will be carrying out:
131
+ {employee_data_block}
132
+ {company_data_block}
133
+ {apqc_matrix_block}
134
+ {initial_objective_block}
135
+ """
136
+
137
+ # --- Helper functions to format data for the system prompt ---
138
+ def format_employee_data(name, role, area):
139
+ return f"<EmployeeData>\nName: {name}\nRole: {role}\nArea: {area}\n</EmployeeData>"
140
+
141
+ def format_company_data(company_info):
142
+ return f"<CompanyData>\n{company_info}\n</CompanyData>"
143
+
144
+ def format_apqc_matrix(apqc_info):
145
+ return f"<APQCMatrixForArea>\n{apqc_info}\n</APQCMatrixForArea>"
146
+
147
+ def format_initial_objective(initial_objective):
148
+ return f"<InitialObjective>\n{initial_objective}\n</InitialObjective>"
149
+
150
+ # --- Gradio Callbacks ---
151
+ async def start_interview(emp_name, emp_role, emp_area, company_info, apqc_info, initial_objective):
152
+ """
153
+ Initializes the interview by sending the setup information to the AI
154
+ and getting the first question.
155
+ """
156
+ azure_client = get_azure_client()
157
+ messages_list_for_llm_history = []
158
+ turn_count = 0
159
+
160
+ employee_data_str = format_employee_data(emp_name, emp_role, emp_area)
161
+ company_data_str = format_company_data(company_info)
162
+ apqc_matrix_str = format_apqc_matrix(apqc_info)
163
+ initial_objective_str = format_initial_objective(initial_objective)
164
+
165
+ current_sys_prompt = SYS_PROMPT_TEMPLATE.format(
166
+ employee_data_block=employee_data_str,
167
+ company_data_block=company_data_str,
168
+ apqc_matrix_block=apqc_matrix_str,
169
+ initial_objective_block=initial_objective_str
170
+ )
171
+
172
+ # Messages for the first API call
173
+ messages_for_api_call = [{"role": "system", "content": current_sys_prompt}]
174
+
175
+ initial_user_directive = "Generate your plans and start the conversation"
176
+ messages_for_api_call.append({"role": "user", "content": initial_user_directive})
177
+
178
+ messages_list_for_llm_history.append({"role": "user", "content": initial_user_directive})
179
+
180
+ try:
181
+ response = azure_client.beta.chat.completions.parse(
182
+ model="gpt-4.1",
183
+ messages=messages_for_api_call,
184
+ response_format=InterviewStep,
185
+ temperature=0.3
186
+ )
187
+ interview_step: InterviewStep = response.choices[0].message.parsed
188
+
189
+ # Store AI's first structured response (including the question) in history
190
+ messages_list_for_llm_history.append({"role": "assistant", **interview_step.model_dump()})
191
+
192
+ # Initial chat history for display in Gradio: AI's first question
193
+ chat_history_display = [("", interview_step.response_for_employee)] # (User, AI)
194
+
195
+ return (
196
+ chat_history_display,
197
+ messages_list_for_llm_history,
198
+ turn_count + 1,
199
+ current_sys_prompt,
200
+ "\n".join(interview_step.reasoning),
201
+ "\n".join(interview_step.reason_replanning),
202
+ interview_step.short_term_plan or "N/A",
203
+ interview_step.long_term_plan or "N/A",
204
+ gr.update(visible=False), # For setup_column
205
+ gr.update(visible=True) # For chat_column
206
+ )
207
+ except Exception as e:
208
+ error_message = f"Error starting interview: {str(e)}"
209
+ print(error_message)
210
+ # Return an error message in the chat and reasoning display
211
+ return (
212
+ [("", error_message)],
213
+ [],
214
+ 0,
215
+ current_sys_prompt,
216
+ error_message,
217
+ "",
218
+ "",
219
+ "",
220
+ gr.update(visible=True), # Keep setup_column visible
221
+ gr.update(visible=True) # Keep chat_column visible
222
+ )
223
+
224
+
225
+ async def handle_employee_response(
226
+ employee_response_text: str,
227
+ chat_history_display_input: list,
228
+ messages_list_for_llm_history_input: list,
229
+ current_turn_count: int,
230
+ current_sys_prompt: str,
231
+ setup_column, # Add setup_column to outputs
232
+ chat_column # Add chat_column to outputs
233
+ ):
234
+ """
235
+ Handles the employee's response, sends it to the AI, and gets the next question/plan.
236
+ """
237
+ azure_client = get_azure_client()
238
+ if not employee_response_text.strip(): # Ignore empty submissions
239
+ # Return current state without changes, keep employee_response_text in box if it was just whitespace
240
+ return (
241
+ chat_history_display_input,
242
+ messages_list_for_llm_history_input,
243
+ current_turn_count,
244
+ gr.update(), gr.update(), gr.update(), gr.update(),
245
+ employee_response_text,
246
+ setup_column, # Keep setup_column visible
247
+ chat_column # Keep chat_column visible
248
+ )
249
+
250
+ # Make copies of state lists to avoid modifying them directly if an error occurs mid-way
251
+ chat_history_display = list(chat_history_display_input)
252
+ messages_list_for_llm_history = list(messages_list_for_llm_history_input)
253
+
254
+ # Construct messages for the API call from the history
255
+ messages_for_api_call = [{"role": "system", "content": current_sys_prompt}]
256
+
257
+ for message_item in messages_list_for_llm_history:
258
+ if message_item["role"] == "assistant":
259
+ # Format assistant's previous turn (plan + question)
260
+ formatted_assistant_msg = (
261
+ f'short_term_plan="{message_item.get("short_term_plan", "")}"\n'
262
+ f'long_term_plan="{message_item.get("long_term_plan", "")}"\n\n'
263
+ f'question_for_employee="{message_item.get("response_for_employee", "")}"'
264
+ )
265
+ messages_for_api_call.append({"role": "assistant", "content": formatted_assistant_msg})
266
+ else: # "user" role
267
+ messages_for_api_call.append({"role": "user", "content": message_item["content"]})
268
+
269
+ # Add current employee's response, formatted for the AI
270
+ current_user_message_formatted = f"Turn count: {current_turn_count}\nResponse from the employee:\n{employee_response_text}"
271
+ messages_for_api_call.append({"role": "user", "content": current_user_message_formatted})
272
+
273
+ # Add the raw employee response to the history list (for future reconstruction)
274
+ messages_list_for_llm_history.append({"role": "user", "content": employee_response_text})
275
+
276
+ try:
277
+ response = azure_client.beta.chat.completions.parse(
278
+ model="gpt-4.1", # Deployment name
279
+ messages=messages_for_api_call,
280
+ response_format=InterviewStep,
281
+ temperature=0.3
282
+ )
283
+ interview_step: InterviewStep = response.choices[0].message.parsed
284
+
285
+ # Add AI's new structured response to history
286
+ messages_list_for_llm_history.append({"role": "assistant", **interview_step.model_dump()})
287
+
288
+ # Update chat history for Gradio display
289
+ chat_history_display.append((employee_response_text, interview_step.response_for_employee))
290
+
291
+ return (
292
+ chat_history_display,
293
+ messages_list_for_llm_history,
294
+ current_turn_count + 1,
295
+ "\n".join(interview_step.reasoning),
296
+ "\n".join(interview_step.reason_replanning),
297
+ interview_step.short_term_plan or "N/A",
298
+ interview_step.long_term_plan or "N/A",
299
+ gr.update(visible=False), # Hide setup_column
300
+ gr.update(visible=True) # Ensure chat_column is visible (and will expand)
301
+ )
302
+ except Exception as e:
303
+ error_message = f"Error processing response: {str(e)}"
304
+ print(error_message)
305
+ chat_history_display.append((employee_response_text, error_message)) # Show error in chat
306
+ # Return state mostly as it was before this failed call, but show error.
307
+ # messages_list_for_llm_history_input does not include the latest AI response that failed.
308
+ # It does include the last user message.
309
+ return (
310
+ chat_history_display,
311
+ messages_list_for_llm_history, # This version includes the user's last message
312
+ current_turn_count, # Don't advance turn count
313
+ error_message, "", "", "",
314
+ employee_response_text, # Keep user input in the box
315
+ setup_column, # Keep setup_column visible
316
+ chat_column # Keep chat_column visible
317
+ )
318
+
319
+ # --- Default values for UI (from notebook's sys_prompt context) ---
320
+ DEFAULT_EMP_NAME = "Matias Silva"
321
+ DEFAULT_EMP_ROLE = "Internal Mesa de Ayuda"
322
+ DEFAULT_EMP_AREA = "Operations"
323
+ DEFAULT_COMPANY_INFO = "Montes del Plata es la principal planta de celulosa de Uruguay, con capacidad de producción de pulpa de eucalipto de alrededor de 1,4 millones de toneladas al año, además de generar internamente su energía a partir de biomasa, aportando cerca del 9 % del suministro eléctrico nacional. Gestiona unas 190 000 ha de bosques certificados FSC y PEFC, emplea alrededor de 630 personas directamente y moviliza más de 6 500 empleos directos e indirectos en su cadena de valor. Inaugurado en 2014, su complejo industrial integra un sistema logístico bimodal (terrestre y fluvial) y opera bajo los estándares de mejores técnicas disponibles de la UE (IPPC-BAT)."
324
+ DEFAULT_APQC_MATRIX = """
325
+ | Nivel 1: Macroproceso | Nivel 2: Subproceso | Nivel 3: Actividad Detallada | Nivel 4: Procedimiento / Workflow | Nivel 5: Instrucción de Trabajo ideal / Configuración Técnica |
326
+ |-------------------------------------------------|--------------------------------------------------------|---------------------------------------------------------|----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
327
+ | Soporte IT Interno (Mesa de Ayuda) | 1.1 Recepción y Registro de Solicitudes | 1.1.1 Recepción de solicitudes multicanal | Registrar automáticamente en herramienta ITSM | Configurar canales de entrada (portal, email, teléfono) |
328
+ | | | 1.1.2 Clasificación y categorización de tickets | Aplicar reglas de categorización según tipo de incidente | Motor de reglas en ITSM, aprendizaje automático supervisado |
329
+ | | | 1.1.3 Asignación y ruteo | Asignar automáticamente a grupo de soporte correspondiente | Configuración de colas por especialidad, turnos y SLAs |
330
+ | | 1.2 Gestión de Incidentes | 1.2.1 Diagnóstico inicial | Ejecutar troubleshooting básico y consulta de KB | Checklist de diagnóstico, acceso a base de conocimiento |
331
+ | | | 1.2.2 Resolución o escalamiento | Aplicar solución o derivar según criticidad | Guías de resolución rápida, matriz de escalamiento definida |
332
+ | | | 1.2.3 Cierre de ticket con documentación | Registrar causa raíz y solución aplicada | Plantilla de cierre, actualización automática de KB si aplica |
333
+ | | 1.3 Gestión de Solicitudes de Servicio | 1.3.1 Alta/Baja/Modificación de accesos y permisos | Ejecutar workflows aprobados y registrar cambios | Integración con sistemas de identidades y flujos de autorización |
334
+ | | | 1.3.2 Instalación o configuración de software | Validar requerimiento y aplicar política de instalación | Uso de herramientas de despliegue remoto (SCCM, Intune, etc.) |
335
+ | | 1.4 Gestión del Conocimiento | 1.4.1 Generación y mantenimiento de artículos KB | Documentar casos recurrentes | Formato estandarizado; revisión periódica asignada |
336
+ | | | 1.4.2 Uso activo de KB por agentes | Consultar y vincular KB al ticket | Integración nativa KB en plataforma ITSM |
337
+ | | 1.5 Monitoreo, Reportes y Mejora Continua | 1.5.1 Seguimiento de SLA y métricas operativas | Generar reportes mensuales de desempeño | Dashboards en Power BI, ServiceNow o Freshservice |
338
+ | | | 1.5.2 Revisión de feedback y encuestas | Analizar CSAT post-cierre | Encuestas automáticas y análisis mensual |
339
+ | | | 1.5.3 Identificación de automatizaciones | Detectar tickets repetitivos | Análisis de tendencias; propuestas de RPA o self-service |
340
+ """
341
+ DEFAULT_INITIAL_OBJECTIVE = """
342
+ ### Inicio y encuadre rápido
343
+ - Preséntate y explica brevemente el propósito:
344
+ > "... mi idea es poder entender como llevas a cabo tu las tareas del dia a dia y como hacen las cosas dentro del area para identificar si hay algunas posibles mejoras en los procesos para poder hacer tu dia a dia mas facil."
345
+
346
+ - Aclara la dinámica: preguntas abiertas, posibilidad de profundizar, que pregunte si no entiende algo.
347
+
348
+ - Comienza preguntando sobre sus tareas del dia a dia para abrir la conversacion. En base a esa respuesta, pasamos al entendimiento de la matriz acordemente.
349
+
350
+ ### Entendimiento de las filas
351
+ Para las distintas filas de la matriz (actividad) vamos a buscar entender algunas cosas (segun corresponda para cada actividad):
352
+
353
+ 1. **Pertinencia y contexto**
354
+
355
+ - Ya sea intuyendolo, o preguntando al empleado identificamos si es pertinente a la entrevista:
356
+ Eg: "Recibes solicitudes de otros empleados? Como las recibis?"
357
+ - **Si no aplica**, cerramos:
358
+ "Perfecto, entonces sigamos."
359
+ - **Si aplica**, avanzamos.
360
+ - "¿Qué triggerea normalmente esta actividad?"
361
+ - "¿En qué momento del día o del ticket aparece?"
362
+
363
+ 2. **Flujo y herramientas**
364
+ - "¿Cómo lo hacés paso a paso?"
365
+ - "¿Con qué sistemas o plataformas (ITSM, Slack, scripts...) trabajas aquí?"
366
+
367
+ 3. **Volumen, salidas y metricas**
368
+ - "¿Con qué frecuencia la ejecutas?"
369
+ - "¿Cuántos tickets/casos manejas en un mes típico?"
370
+ - "¿Qué registros o reportes generás?"
371
+ - "¿Cómo sabés si lo estás haciendo bien? ¿Qué indicadores seguís?"
372
+
373
+ 4. **Fricciones y mejoras** - Las mejoras no son parte de los building blocks
374
+ - "¿Qué parte de este flujo te consume más tiempo o te genera más errores?"
375
+ - "¿Has tenido que recurrir a soluciones improvisadas?"
376
+ - "Si pudieras cambiar o automatizar un paso acá, ¿cuál sería?"
377
+ - "¿Hay ideas que ya hayan surgido en tu equipo?"
378
+
379
+ 5. **Mini-resumen**
380
+ Una vez relevada una actividad, proceso o sub proceso podemos pedir confirmacion de algunos puntos.
381
+ Eg: "Entonces, para **[actividad]**, vos la iniciás cuando **...**, usás **...**, la hacés **... veces/mes**, tu mayor desafío es **...** y lo medís con **...**. ¿Falta algo?"
382
+
383
+ ### Gestión de excepciones y agrupamientos
384
+ - Si el entrevistado agrupa varias filas en una explicación, reconoce el bundle y adapta:
385
+ > "Entiendo que entre X e Y vos hacés un flujo combinado. Vamos a profundizar en ese flujo conjunto..."
386
+ - Si surge un sub-proceso nuevo o una excepción no prevista, inclúyelo en tu planificacoin y hazle un mini-bloque:
387
+ > "Contame más de ese caso especial cuando...".
388
+
389
+ ## Cierre global
390
+
391
+ - Al haber analizado las distintas actividades podemos explicar el entendimiento que tenemos de su trabajo y preguntar si falta algo:
392
+ > "De mi lado tengo un entendimiento claro de lo que serian tus tareas dentro del area. Entiendo que haces (resumen). ¿Hay alguna actividad o excepción que no hayamos hablado y vos no realices?"
393
+ Es importante no ver a esto como un checklist rigido, si no una mini guia de algunos casos que pueden aparecer.
394
+ """
395
+
396
+ # --- Gradio UI Layout ---
397
+ with gr.Blocks(theme=gr.themes.Soft(), title="AI Interviewer") as demo:
398
+ gr.Markdown("# AI Interviewer (Nico, the Horizon Copilot)")
399
+ gr.Markdown("This application simulates an AI interviewer (Nico) who will ask you questions based on the provided context. You play the role of the employee being interviewed.")
400
+
401
+ # --- Persistent State Variables for the Session ---
402
+ messages_list_state = gr.State([])
403
+ turn_count_state = gr.State(0)
404
+ system_prompt_state = gr.State("")
405
+
406
+ with gr.Row():
407
+ setup_column = gr.Column(scale=1, visible=True)
408
+ chat_column = gr.Column(scale=2, visible=True)
409
+
410
+ with setup_column:
411
+ gr.Markdown("## Interview Setup")
412
+ gr.Markdown("Provide the context for the interview. Nico will use this to tailor the conversation.")
413
+ emp_name_input = gr.Textbox(label="Employee Name", value=DEFAULT_EMP_NAME)
414
+ emp_role_input = gr.Textbox(label="Employee Role", value=DEFAULT_EMP_ROLE)
415
+ emp_area_input = gr.Textbox(label="Employee Area/Department", value=DEFAULT_EMP_AREA)
416
+ company_info_input = gr.Textbox(label="Company Information", lines=7, value=DEFAULT_COMPANY_INFO,elem_id="company-info")
417
+ apqc_matrix_input = gr.Textbox(label="Process Framework (e.g., APQC Matrix for Employee's Area)", lines=10, value=DEFAULT_APQC_MATRIX, elem_id="apqc-matrix")
418
+ initial_objective_input = gr.Textbox(label="Initial Objective", lines=7, value=DEFAULT_INITIAL_OBJECTIVE, elem_id="initial-objective")
419
+ start_button = gr.Button("Start Interview with Nico", variant="primary")
420
+
421
+ with chat_column:
422
+ gr.Markdown("## Interview Chat with Nico")
423
+ with gr.Row():
424
+ with gr.Column(scale=2):
425
+ chatbot_display = gr.Chatbot(label="Nico (AI Interviewer)", height=550, bubble_full_width=False, avatar_images=(None, "https://cdn-icons-png.flaticon.com/512/1698/1698535.png"))
426
+ employee_response_box = gr.Textbox(label="Your Response (as Employee)", placeholder="Type your response here and press Enter to submit...", show_label=True)
427
+
428
+ with gr.Column(scale=1):
429
+ gr.Markdown("### AI's Internal Thoughts")
430
+ reasoning_display = gr.Textbox(label="Nico's Reasoning for the question:", lines=10, interactive=False)
431
+ reason_replanning_display = gr.Textbox(label="Nico's Reason for Replanning (if any):", lines=5, interactive=False)
432
+ short_term_plan_display = gr.Textbox(label="Nico's Short-Term Plan:", lines=5, interactive=False)
433
+ long_term_plan_display = gr.Textbox(label="Nico's Long-Term Plan:", lines=7, interactive=False)
434
+
435
+ # --- Event Handlers Wiring ---
436
+ start_button.click(
437
+ fn=start_interview,
438
+ inputs=[emp_name_input, emp_role_input, emp_area_input, company_info_input, apqc_matrix_input, initial_objective_input],
439
+ outputs=[
440
+ chatbot_display,
441
+ messages_list_state,
442
+ turn_count_state,
443
+ system_prompt_state,
444
+ reasoning_display,
445
+ reason_replanning_display,
446
+ short_term_plan_display,
447
+ long_term_plan_display,
448
+ setup_column, # Controls visibility of the setup column
449
+ chat_column # Controls visibility of the main chat/reasoning column
450
+ ],
451
+ api_name="start_interview"
452
  )
453
 
454
+ employee_response_box.submit(
455
+ fn=handle_employee_response,
456
+ inputs=[
457
+ employee_response_box,
458
+ chatbot_display,
459
+ messages_list_state,
460
+ turn_count_state,
461
+ system_prompt_state
462
+ ],
463
+ outputs=[
464
+ chatbot_display,
465
+ messages_list_state,
466
+ turn_count_state,
467
+ reasoning_display,
468
+ reason_replanning_display,
469
+ short_term_plan_display,
470
+ long_term_plan_display,
471
+ employee_response_box
472
+ ],
473
+ api_name="employee_response"
474
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
 
476
  if __name__ == "__main__":
477
+ demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))