Spaces:
Sleeping
Sleeping
Add application file
Browse files
app.py
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from google.adk.agents import Agent
|
3 |
+
from google.adk.sessions import InMemorySessionService
|
4 |
+
from google.adk.runners import Runner
|
5 |
+
from google.adk.agents import LlmAgent
|
6 |
+
from google.genai import types
|
7 |
+
from typing import Dict, Any
|
8 |
+
from google.adk.models.lite_llm import LiteLlm
|
9 |
+
import uuid
|
10 |
+
import asyncio
|
11 |
+
from google import genai
|
12 |
+
import os
|
13 |
+
|
14 |
+
#download_files_from_drive_tool = FunctionTool(func=download_files_from_drive)
|
15 |
+
# --- Definición de Mod
|
16 |
+
|
17 |
+
# Definir función para el Agente Revisor
|
18 |
+
|
19 |
+
# Envolver funciones como herramientas de ADK
|
20 |
+
# Es importante que el nombre de la herramienta sea el mismo que el nombre de la función para el ADK
|
21 |
+
instruction = """Sos un auditor clínico experto. Que debes validar la pertinencia clínica de una orden médica. Identifica el estudio solicitado, el diagnóstico y la justificación clínica. Posteriormente analiza si el estudio solicitado está clínicamente justificado.
|
22 |
+
|
23 |
+
**IMPORTANTE**: Inpendientemente recuerda que la Guía Práctica Clínica dice: `Se recomienda que ante un paciente con Dolor lumbar sin respuesta al tratamiento después de 4-6 semanas de evolución considerar la utilidad de estudios de imagen. El tratamiento con paracetamol es insuficiente para justificar estudios de imagen.`
|
24 |
+
|
25 |
+
|
26 |
+
Formato de respuesta en bullets:
|
27 |
+
|
28 |
+
**Evaluación de pertinencia clínica**: [observaciones]
|
29 |
+
|
30 |
+
**Resultado**: [✅ Aprobado | ❌ Rechazado]
|
31 |
+
|
32 |
+
**Notas para el médico solicitante (Solo en el caso de rechazo)**: - [información]
|
33 |
+
|
34 |
+
Fuente: (Ministerio de Salud Pública. Dolor lumbar: Guía Práctica Clínica (GPC). Primera Edición. Quito: Dirección Nacional de Normatización; 2015)
|
35 |
+
|
36 |
+
IMPORTANTE_ Siempre debes citar la fuente."""
|
37 |
+
def consultar_guia_medica(consulta: str) -> str:
|
38 |
+
client = genai.Client(api_key=os.getenv("GOOGLE_API_KEY"))
|
39 |
+
|
40 |
+
try:
|
41 |
+
response = client.models.generate_content(
|
42 |
+
model="gemini-2.0-flash",
|
43 |
+
contents=f"""Responde la siguiente consulta en base a la guia de Dolor Lumbar y cita la fuente de la recomendación:
|
44 |
+
|
45 |
+
{consulta}
|
46 |
+
"""
|
47 |
+
)
|
48 |
+
print("RESPONSE", response)
|
49 |
+
return response.candidates[0].content.parts[0].text
|
50 |
+
except Exception as e:
|
51 |
+
print(e)
|
52 |
+
|
53 |
+
|
54 |
+
APP_NAME = "predoc_app"
|
55 |
+
|
56 |
+
|
57 |
+
|
58 |
+
root_agent = LlmAgent(
|
59 |
+
model=LiteLlm(model="openai/gpt-4.1"),
|
60 |
+
generate_content_config=types.GenerateContentConfig(
|
61 |
+
temperature=0.0,
|
62 |
+
),
|
63 |
+
name="Agente_especialista",
|
64 |
+
instruction=instruction,
|
65 |
+
description="Agente especialista en dolor lumbar",
|
66 |
+
#tools=[consultar_guia_medica]
|
67 |
+
)
|
68 |
+
|
69 |
+
session_service = InMemorySessionService()
|
70 |
+
|
71 |
+
# Esta función se conecta a ChatInterface
|
72 |
+
def respond(message, history):
|
73 |
+
# Detectar si es inicio de conversación (history vacío o con 0 mensajes)
|
74 |
+
print("HISTORY",history)
|
75 |
+
if history is None or len(history) == 0:
|
76 |
+
user_id = str(uuid.uuid4())
|
77 |
+
session_id = str(uuid.uuid4())
|
78 |
+
print(f"🔄 Nueva sesión: {session_id}")
|
79 |
+
|
80 |
+
async def create_session():
|
81 |
+
await session_service.create_session(
|
82 |
+
app_name=APP_NAME,
|
83 |
+
user_id=user_id,
|
84 |
+
session_id=session_id
|
85 |
+
)
|
86 |
+
asyncio.run(create_session())
|
87 |
+
# Guardar en algún lado user_id y session_id para usar en las próximas llamadas
|
88 |
+
# Por simplicidad acá lo guardamos en variables globales
|
89 |
+
global CURRENT_USER_ID, CURRENT_SESSION_ID
|
90 |
+
CURRENT_USER_ID = user_id
|
91 |
+
CURRENT_SESSION_ID = session_id
|
92 |
+
else:
|
93 |
+
# Usar IDs existentes
|
94 |
+
user_id = CURRENT_USER_ID
|
95 |
+
session_id = CURRENT_SESSION_ID
|
96 |
+
|
97 |
+
runner = Runner(agent=root_agent, app_name=APP_NAME, session_service=session_service)
|
98 |
+
|
99 |
+
def call_agent_text(query):
|
100 |
+
content = types.Content(role='user', parts=[types.Part(text=query)])
|
101 |
+
events = runner.run(user_id=user_id, session_id=session_id, new_message=content)
|
102 |
+
for event in events:
|
103 |
+
if event.is_final_response():
|
104 |
+
return event.content.parts[0].text
|
105 |
+
return "No se obtuvo respuesta."
|
106 |
+
|
107 |
+
def call_agent_image(query):
|
108 |
+
images = []
|
109 |
+
for q in query:
|
110 |
+
with open(q, 'rb') as f:
|
111 |
+
image_bytes = f.read()
|
112 |
+
images.append(types.Part.from_bytes(data=image_bytes, mime_type='image/jpeg'))
|
113 |
+
|
114 |
+
content = types.Content(role='user', parts=images)
|
115 |
+
events = runner.run(user_id=user_id, session_id=session_id, new_message=content)
|
116 |
+
for event in events:
|
117 |
+
if event.is_final_response():
|
118 |
+
return event.content.parts[0].text
|
119 |
+
return "No se obtuvo respuesta."
|
120 |
+
|
121 |
+
def call_agent_both(image, text):
|
122 |
+
with open(image[0], 'rb') as f:
|
123 |
+
image_bytes = f.read()
|
124 |
+
content = types.Content(
|
125 |
+
role='user',
|
126 |
+
parts=[
|
127 |
+
types.Part.from_bytes(data=image_bytes, mime_type='image/jpeg'),
|
128 |
+
types.Part(text=text)
|
129 |
+
]
|
130 |
+
)
|
131 |
+
events = runner.run(user_id=user_id, session_id=session_id, new_message=content)
|
132 |
+
for event in events:
|
133 |
+
if event.is_final_response():
|
134 |
+
return event.content.parts[0].text
|
135 |
+
return "No se obtuvo respuesta."
|
136 |
+
|
137 |
+
# Dispatcher
|
138 |
+
if message['text'] != '' and len(message['files']) > 0:
|
139 |
+
return call_agent_both(message['files'], message['text'])
|
140 |
+
elif message['text'] == '' and len(message['files']) > 0:
|
141 |
+
return call_agent_image(message['files'])
|
142 |
+
elif message['text'] != '' and len(message['files']) == 0:
|
143 |
+
return call_agent_text(message['text'])
|
144 |
+
else:
|
145 |
+
return "Escribe algo para que pueda contestarte."
|
146 |
+
|
147 |
+
# Inicializamos demo sin el argumento state
|
148 |
+
demo = gr.ChatInterface(fn=respond, title="Agente Revisor", multimodal=True)
|
149 |
+
|
150 |
+
demo.launch(debug=True)
|