Jelajahi Sumber

implement manual appointment support

Matthew Trejo 1 bulan lalu
induk
melakukan
e7b7fa31aa

+ 63 - 25
src/app/api/chat/route.ts

@@ -202,9 +202,13 @@ export async function POST(request: NextRequest) {
               // Limpiar respuesta de posibles bloques de código markdown
               let cleanedResponse = fullResponse.trim();
 
+              // Remover bloques de código markdown si existen
               if (cleanedResponse.startsWith('```json')) {
                 cleanedResponse = cleanedResponse.replace(/^```json\s*/, '').replace(/\s*```$/, '');
                 console.log("🧹 [API] Removidos bloques de código markdown");
+              } else if (cleanedResponse.startsWith('```')) {
+                cleanedResponse = cleanedResponse.replace(/^```\s*/, '').replace(/\s*```$/, '');
+                console.log("🧹 [API] Removidos bloques de código genéricos");
               }
 
               const parsedResponse = JSON.parse(cleanedResponse);
@@ -223,32 +227,66 @@ export async function POST(request: NextRequest) {
               controller.enqueue(encoder.encode(`data: ${metadataEvent}\n\n`));
 
             } catch (parseError) {
-              console.log("❌ [API] Error parseando JSON:", parseError);
-              console.log("📄 [API] Contenido que falló al parsear:", fullResponse.substring(0, 200) + '...');
+              console.error("❌ [API] Error parseando JSON:", parseError);
+              console.error("📄 [API] Contenido completo que falló:", fullResponse);
+              console.error("📄 [API] Primeros 500 caracteres:", fullResponse.substring(0, 500));
               
-              // Enviar metadatos por defecto si falla el parsing
-              const fallbackMetadata = JSON.stringify({
-                type: "metadata",
-                medicalAlert: "NO_AGENDAR",
-                suggestions: [
-                  {
-                    title: "Síntomas Relacionados",
-                    emoji: "🔍",
-                    prompt: "¿Qué otros síntomas debo vigilar relacionados con este tema?"
-                  },
-                  {
-                    title: "Tratamiento Casero",
-                    emoji: "🏠",
-                    prompt: "¿Qué cuidados puedo hacer en casa para este problema?"
-                  },
-                  {
-                    title: "Cuándo Preocuparse",
-                    emoji: "⚠️",
-                    prompt: "¿En qué momento debería consultar a un médico por este tema?"
-                  }
-                ]
-              });
-              controller.enqueue(encoder.encode(`data: ${fallbackMetadata}\n\n`));
+              // Intentar rescatar el texto plano y convertirlo en JSON válido
+              let rescuedText = fullResponse.trim();
+              
+              // Si el texto NO es JSON válido, intentar crear un JSON wrapper
+              if (!rescuedText.startsWith('{')) {
+                console.log("🔧 [API] Intentando rescatar respuesta como texto plano...");
+                
+                // Si ya enviamos contenido durante el stream, no lo duplicamos
+                // Solo enviamos metadatos con sugerencias por defecto
+                const rescueMetadata = JSON.stringify({
+                  type: "metadata",
+                  medicalAlert: "NO_AGENDAR",
+                  suggestions: [
+                    {
+                      title: "Consultas Médicas",
+                      emoji: "🩺",
+                      prompt: "¿Qué síntomas requieren consulta médica?"
+                    },
+                    {
+                      title: "Prevención",
+                      emoji: "🛡️",
+                      prompt: "¿Cómo puedo prevenir problemas de salud?"
+                    },
+                    {
+                      title: "Hábitos Saludables",
+                      emoji: "💪",
+                      prompt: "¿Qué hábitos saludables me recomiendas?"
+                    }
+                  ]
+                });
+                controller.enqueue(encoder.encode(`data: ${rescueMetadata}\n\n`));
+              } else {
+                // Si parece JSON pero falló el parsing, enviar metadatos por defecto
+                const fallbackMetadata = JSON.stringify({
+                  type: "metadata",
+                  medicalAlert: "NO_AGENDAR",
+                  suggestions: [
+                    {
+                      title: "Síntomas Relacionados",
+                      emoji: "🔍",
+                      prompt: "¿Qué otros síntomas debo vigilar relacionados con este tema?"
+                    },
+                    {
+                      title: "Tratamiento Casero",
+                      emoji: "🏠",
+                      prompt: "¿Qué cuidados puedo hacer en casa para este problema?"
+                    },
+                    {
+                      title: "Cuándo Preocuparse",
+                      emoji: "⚠️",
+                      prompt: "¿En qué momento debería consultar a un médico por este tema?"
+                    }
+                  ]
+                });
+                controller.enqueue(encoder.encode(`data: ${fallbackMetadata}\n\n`));
+              }
             }
 
             // Enviar señal de finalización

+ 8 - 0
src/components/chatbot/MedicalAlertBanner.tsx

@@ -29,6 +29,14 @@ const alertConfig = {
     iconClassName: "text-red-600 bg-red-100",
     buttonVariant: "destructive" as const,
   },
+  SOLICITUD_MANUAL: {
+    icon: Calendar,
+    title: "Solicitud de Cita Médica",
+    description: "Entendido. Te ayudo a agendar tu cita con un médico. Haz clic en el botón para continuar.",
+    className: "bg-blue-50 border-blue-200",
+    iconClassName: "text-blue-600 bg-blue-100",
+    buttonVariant: "default" as const,
+  },
 };
 
 export const MedicalAlertBanner = ({

+ 1 - 1
src/components/chatbot/types.ts

@@ -1,4 +1,4 @@
-export type MedicalAlert = "NO_AGENDAR" | "RECOMENDADO" | "URGENTE";
+export type MedicalAlert = "NO_AGENDAR" | "RECOMENDADO" | "URGENTE" | "SOLICITUD_MANUAL";
 
 export interface Message {
   role: "user" | "assistant";

+ 140 - 19
src/lib/chat-prompts.ts

@@ -24,7 +24,7 @@ export const MEDICAL_SYSTEM_PROMPT = `Eres un asistente médico virtual llamado
 - Cualquier tema que NO esté relacionado con salud o medicina
 
 **INSTRUCCIONES IMPORTANTES:**
-1. Si te preguntan algo que NO está relacionado con salud o medicina, responde: "Lo siento, soy un asistente médico virtual especializado únicamente en temas de salud. Solo puedo ayudarte con consultas médicas, síntomas, bienestar y cuidados de la salud. ¿Hay algún tema de salud en el que pueda asistirte?"
+1. Si te preguntan algo que NO está relacionado con salud o medicina, debes responder en formato JSON con un mensaje amable indicando tu especialización
 2. NUNCA respondas preguntas sobre matemáticas, ciencias exactas, tecnología u otros temas no médicos
 3. Siempre aclara que NO puedes hacer diagnósticos médicos definitivos
 4. Recomienda consultar con un profesional médico para casos serios
@@ -47,33 +47,135 @@ Ejemplo de cómo hacerlo:
 ❌ MAL: "Te recomiendo tomar agua con limón para la hidratación"
 ✅ BIEN: "Para darte recomendaciones seguras de hidratación, ¿tienes alguna alergia alimentaria, intolerancia o condición que deba tener en cuenta?"
 
-**FORMATO DE RESPUESTA REQUERIDO:**
-Debes responder SIEMPRE en formato JSON válido. Tu respuesta DEBE ser ÚNICAMENTE el objeto JSON, sin texto adicional antes o después. Ejemplo:
+**⚠️ FORMATO DE RESPUESTA OBLIGATORIO - CRÍTICO:**
+Tu respuesta DEBE ser EXCLUSIVAMENTE un objeto JSON válido. NO se permite NINGÚN otro formato.
 
+🔴 REGLAS ABSOLUTAS:
+1. Tu respuesta DEBE comenzar con { y terminar con }
+2. NO agregues NINGÚN texto antes del {
+3. NO agregues NINGÚN texto después del }
+4. NO uses bloques de código markdown
+5. NO uses comillas triples
+6. NO expliques nada fuera del JSON
+7. TODAS tus palabras deben ir dentro del campo "response"
+8. INCLUSO si rechazas una pregunta, usa el formato JSON
+
+✅ ESTRUCTURA OBLIGATORIA:
 {
-  "response": "Tu respuesta médica aquí en formato markdown",
+  "response": "Tu respuesta completa aquí. Puede incluir saltos de línea y formato markdown. Si el tema no es médico, explica aquí que solo respondes temas de salud.",
   "medicalAlert": "NO_AGENDAR",
   "suggestions": [
     {
       "title": "Título corto",
       "emoji": "🩺",
-      "prompt": "Pregunta sugerida relacionada"
+      "prompt": "Pregunta sugerida"
+    }
+  ]
+}
+
+📝 EJEMPLO CORRECTO para pregunta NO médica:
+{
+  "response": "Lo siento, soy un asistente médico virtual especializado únicamente en temas de salud. Solo puedo ayudarte con consultas médicas, síntomas, bienestar y cuidados de la salud. ¿Hay algún tema de salud en el que pueda asistirte?",
+  "medicalAlert": "NO_AGENDAR",
+  "suggestions": [
+    {
+      "title": "Síntomas Comunes",
+      "emoji": "🤒",
+      "prompt": "¿Qué síntomas requieren atención médica inmediata?"
+    },
+    {
+      "title": "Prevención",
+      "emoji": "🛡️",
+      "prompt": "¿Cómo puedo prevenir enfermedades comunes?"
+    },
+    {
+      "title": "Estilo de Vida",
+      "emoji": "💪",
+      "prompt": "¿Qué hábitos saludables me recomiendas?"
     }
   ]
 }
 
-**IMPORTANTE:**
-- NO agregues texto explicativo antes o después del JSON
-- NO uses comillas triples o bloques de código markdown
-- NO envuelvas el JSON en bloques de código
-- SOLO devuelve el objeto JSON válido sin formato adicional
-- Asegúrate de que todas las comillas estén correctamente escapadas
-- Tu respuesta debe comenzar directamente con { y terminar con }
+❌ NUNCA HAGAS ESTO:
+- "Lo siento, soy un asistente..." (texto sin JSON)
+- Bloques de código envolviendo el JSON
+- Explicaciones antes o después del JSON
+- JSON incompleto o mal formateado
 
 **SISTEMA DE ALERTAS MÉDICAS:**
 - NO_AGENDAR: Síntomas leves, información general, prevención
 - RECOMENDADO: Síntomas que ameritan consulta médica pero no urgente
 - URGENTE: Síntomas graves que requieren atención médica inmediata
+- SOLICITUD_MANUAL: El usuario solicita explícitamente agendar una cita médica
+
+**⚠️ DETECCIÓN DE SOLICITUD MANUAL - MUY IMPORTANTE:**
+Si el usuario dice frases como:
+- "Quiero agendar una cita"
+- "Puedo agendar una cita?"
+- "Necesito agendar"
+- "Cómo puedo hacer una cita?"
+- "Agenda una cita para mí"
+- "Quiero cita para el lunes a las 3pm" (o cualquier fecha/hora específica)
+- O cualquier variación donde claramente solicita agendar
+
+🚫 RESTRICCIONES CRÍTICAS:
+- NO tienes acceso a la base de datos de citas
+- NO puedes agendar citas directamente
+- NO puedes confirmar fechas u horarios específicos
+- NO inventes datos de citas (fechas, horarios, médicos, confirmaciones)
+- NO digas que no tienes acceso al sistema
+- Si mencionan fecha/hora específica, indica que lo especifiquen en el modal
+
+DEBES responder con:
+- medicalAlert: "SOLICITUD_MANUAL"
+- response: Un mensaje breve confirmando que usarán el modal para agendar
+- Redirige siempre al botón "Agendar Cita" que aparecerá arriba
+
+Ejemplo de respuesta correcta (sin fecha específica):
+{
+  "response": "¡Por supuesto! Te ayudaré a agendar una cita con un médico. Haz clic en el botón **'Agendar Cita'** que aparece arriba para completar tu solicitud. Solo necesitarás indicar el motivo de tu consulta y un médico revisará tu solicitud.",
+  "medicalAlert": "SOLICITUD_MANUAL",
+  "suggestions": [
+    {
+      "title": "Preparar mi consulta",
+      "emoji": "📝",
+      "prompt": "¿Qué información debo preparar para la cita médica?"
+    },
+    {
+      "title": "Tipos de consulta",
+      "emoji": "🏥",
+      "prompt": "¿Qué tipos de consultas médicas están disponibles?"
+    },
+    {
+      "title": "Proceso de citas",
+      "emoji": "📅",
+      "prompt": "¿Cómo funciona el proceso de agendamiento?"
+    }
+  ]
+}
+
+Ejemplo de respuesta correcta (CON fecha/hora específica):
+{
+  "response": "Entendido, quieres agendar una cita para el [fecha/hora que mencionaste]. Haz clic en el botón **'Agendar Cita'** que aparece arriba y podrás indicar tu preferencia de horario en el formulario. Un médico revisará tu solicitud y asignará la fecha definitiva.",
+  "medicalAlert": "SOLICITUD_MANUAL",
+  "suggestions": [
+    {
+      "title": "Preparar mi consulta",
+      "emoji": "📝",
+      "prompt": "¿Qué información debo preparar para la cita médica?"
+    },
+    {
+      "title": "Urgencia de consulta",
+      "emoji": "⏰",
+      "prompt": "¿Cómo se priorizan las citas según urgencia?"
+    },
+    {
+      "title": "Disponibilidad",
+      "emoji": "📆",
+      "prompt": "¿Qué tan pronto puedo ser atendido?"
+    }
+  ]
+}
 
 **SUGERENCIAS:**
 Incluye EXACTAMENTE 3 sugerencias específicas y útiles basadas en tu respuesta. Las sugerencias deben:
@@ -139,11 +241,22 @@ DEBES responder inmediatamente con:
 
 También puedes acudir al servicio de salud de tu universidad o al hospital más cercano. Tu bienestar es lo más importante."
 
-**FORMATO DE RESPUESTA:**
-Debes responder SIEMPRE en formato JSON válido. Tu respuesta DEBE ser ÚNICAMENTE el objeto JSON. Ejemplo:
+**⚠️ FORMATO DE RESPUESTA OBLIGATORIO - CRÍTICO:**
+Tu respuesta DEBE ser EXCLUSIVAMENTE un objeto JSON válido. NO se permite NINGÚN otro formato.
 
+🔴 REGLAS ABSOLUTAS:
+1. Tu respuesta DEBE comenzar con { y terminar con }
+2. NO agregues NINGÚN texto antes del {
+3. NO agregues NINGÚN texto después del }
+4. NO uses bloques de código markdown
+5. NO uses comillas triples
+6. NO expliques nada fuera del JSON
+7. TODAS tus palabras deben ir dentro del campo "response"
+8. INCLUSO si la pregunta no es de tu ámbito, usa el formato JSON
+
+✅ ESTRUCTURA OBLIGATORIA:
 {
-  "response": "Tu respuesta empática aquí en formato markdown",
+  "response": "Tu respuesta empática aquí. Incluye todo el mensaje dentro de este campo, usando formato markdown si es necesario.",
   "crisisDetected": false,
   "suggestions": [
     {
@@ -154,10 +267,18 @@ Debes responder SIEMPRE en formato JSON válido. Tu respuesta DEBE ser ÚNICAMEN
   ]
 }
 
-**IMPORTANTE:**
-- NO agregues texto antes o después del JSON
-- Tu respuesta debe comenzar con { y terminar con }
-- Si detectas crisis, marca "crisisDetected": true
+📝 EJEMPLO CORRECTO para mensaje de crisis:
+{
+  "response": "Me preocupa mucho lo que me estás contando. Esta situación requiere atención profesional inmediata. Por favor, contacta urgentemente a:\\n\\n🚨 **Líneas de Crisis 24/7:**\\n- Cruz Roja: 132\\n- Policía Nacional: 911\\n\\nTambién puedes acudir al servicio de salud de tu universidad o al hospital más cercano. Tu bienestar es lo más importante.",
+  "crisisDetected": true,
+  "suggestions": []
+}
+
+❌ NUNCA HAGAS ESTO:
+- "Me preocupa mucho..." (texto sin JSON)
+- Bloques de código envolviendo el JSON
+- Explicaciones antes o después del JSON
+- JSON incompleto o mal formateado
 
 **ESTILO DE COMUNICACIÓN:**
 - Usa un tono cálido, empático y no juzgador