File size: 13,088 Bytes
257a6c5
7deea0b
e2594a1
 
 
 
257a6c5
f41fa1f
22c150d
f41fa1f
 
 
 
 
 
e2594a1
 
f41fa1f
e2594a1
 
 
 
 
 
 
f41fa1f
e2594a1
 
 
 
f41fa1f
e2594a1
 
f41fa1f
e2594a1
f41fa1f
 
e2594a1
f41fa1f
 
 
 
e2594a1
 
 
 
 
 
 
 
 
 
f41fa1f
e2594a1
 
 
 
f41fa1f
e2594a1
 
f41fa1f
e2594a1
f41fa1f
e2594a1
 
f41fa1f
e2594a1
 
 
 
f41fa1f
e2594a1
 
 
f41fa1f
e2594a1
 
f41fa1f
e2594a1
f41fa1f
 
e2594a1
f41fa1f
 
e2594a1
f41fa1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e2594a1
 
f41fa1f
 
e2594a1
f41fa1f
 
 
 
 
 
 
 
 
e2594a1
f41fa1f
e2594a1
f41fa1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e2594a1
 
 
f41fa1f
e2594a1
f41fa1f
 
 
 
 
 
 
 
 
 
 
e2594a1
 
 
 
 
7deea0b
f41fa1f
 
e2594a1
f41fa1f
e2594a1
 
 
f41fa1f
 
 
 
 
 
 
 
e2594a1
 
f41fa1f
 
 
 
 
 
 
 
e2594a1
f41fa1f
e2594a1
 
 
 
 
 
f41fa1f
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
import gradio as gr
import os
import re
import json
import requests
from pypdf import PdfReader

# ✅ Configurar API Key de OpenRouter desde variables de entorno
OPENROUTER_API_KEY = os.getenv("sk-OsMMq65tXdfOIlTUYtocSL7NCsmA7CerN77OkEv29dODg1EA")
if not OPENROUTER_API_KEY:
    raise ValueError("❌ OPENROUTER_API_KEY no está configurada. Ve a Settings > Variables de entorno en tu Space.")

OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions"
# ✅ Modelo gratuito y potente: DeepSeek R1
MODEL = "deepseek/deepseek-r1-0528-qwen3-8b:free"

def extract_text_from_pdf(pdf_file):
    """Extrae texto de un archivo PDF"""
    try:
        reader = PdfReader(pdf_file)
        text = ""
        for page in reader.pages:
            extracted = page.extract_text()
            if extracted:
                text += extracted + "\n"
        return text[:5000]  # Limitar para no exceder tokens
    except Exception as e:
        return f"Error al leer PDF: {str(e)}"

def generate_smart_objective(objective, age, duration):
    """Genera un objetivo SMART completo y detallado"""
    age_group = 'preescolar' if age < 36 else 'escolar' if age < 144 else 'adolescente/adulto'
    time_frame = 'corto plazo' if duration < 30 else 'mediano plazo' if duration < 60 else 'largo plazo'
    return f"El paciente {age_group} logrará {objective} con un 80% de precisión durante {duration} minutos, utilizando apoyo visual/auditivo según necesidad, medible a través de registro de respuestas correctas en {time_frame}."

def call_openrouter_api(prompt):
    """Llama a la API de OpenRouter"""
    headers = {
        "Authorization": f"Bearer {OPENROUTER_API_KEY}",
        "Content-Type": "application/json",
        "HTTP-Referer": "https://tufonoayuda-pixel.github.io/ActFonoGenerator/",  # Tu URL
        "X-Title": "Generador IA de Actividades Fonoaudiológicas"
    }
    
    data = {
        "model": MODEL,
        "messages": [{"role": "user", "content": prompt}],
        "temperature": 0.3,
        "max_tokens": 4096
    }
    
    try:
        response = requests.post(OPENROUTER_API_URL, headers=headers, json=data, timeout=60)
        response.raise_for_status()
        result = response.json()
        return result["choices"][0]["message"]["content"]
    except Exception as e:
        raise Exception(f"Error al llamar a OpenRouter: {str(e)}")

def generate_activity(user_desc, objective, duration, session_type, is_pediatric, context, pdf_files):
    """Genera una actividad terapéutica COMPLETA y DETALLADA con IA real de OpenRouter"""
    if not all([user_desc, objective, duration]):
        return ("⚠️ Error", "Por favor completa todos los campos obligatorios.", "", "", "", "", "", "")

    try:
        # Extraer edad
        age = int(re.search(r'\d+', user_desc).group()) if re.search(r'\d+', user_desc) else 60
        is_child = age < 144 or is_pediatric
        dur = int(duration)

        # Procesar PDFs
        pdf_text = ""
        if pdf_files:
            for pdf_file in pdf_files:
                pdf_text += f"\n--- Contenido de {pdf_file.name} ---\n"
                pdf_text += extract_text_from_pdf(pdf_file)

        # ✅ Construir prompt detallado para OpenRouter
        prompt = f"""
        Eres un fonoaudiólogo experto con 20 años de experiencia clínica. Tu tarea es generar una ACTIVIDAD TERAPÉUTICA COMPLETA, DETALLADA Y LISTA PARA IMPLEMENTAR, basada en evidencia científica y buenas prácticas clínicas.

        PACIENTE: {user_desc}
        OBJETIVO TERAPÉUTICO: {objective}
        DURACIÓN DE LA SESIÓN: {duration} minutos
        TIPO DE SESIÓN: {session_type}
        ¿SESIÓN PEDIÁTRICA?: {'Sí, usar lenguaje lúdico y adaptado' if is_child else 'No, lenguaje profesional y técnico'}
        CONTEXTO ADICIONAL: {context or 'Ninguno'}
        {f'REFERENCIAS CIENTÍFICAS (usa esta información para fundamentar): {pdf_text}' if pdf_text else ''}

        INSTRUCCIONES ESPECÍFICAS PARA LA ACTIVIDAD:

        1. TÍTULO: Crea un título atractivo, profesional y descriptivo que refleje el contenido de la actividad.

        2. OBJETIVO SMART: Formula un objetivo terapéutico específico, medible, alcanzable, relevante y con tiempo definido. Debe ser una oración completa y detallada.

        3. DESCRIPCIÓN GENERAL: Escribe un párrafo completo (mínimo 5-7 oraciones) que describa la actividad, su propósito, población objetivo, y cómo se relaciona con el objetivo terapéutico.

        4. MATERIALES NECESARIOS: Lista todos los materiales requeridos con descripciones específicas y detalladas. No uses viñetas sueltas, escribe oraciones completas.

        5. PROCEDIMIENTO PASO A PASO: Describe detalladamente las tres fases de la actividad (calentamiento, desarrollo, cierre). Para cada fase:
           - Nombre de la fase
           - Duración estimada
           - Instrucciones verbales exactas que debe dar el terapeuta
           - Actividades específicas que realizará el paciente
           - Posibles variaciones o adaptaciones durante la actividad
           - Señales de progreso o dificultad a observar

        6. EVALUACIÓN: Define:
           - Criterios de logro específicos y medibles
           - Métodos de evaluación cuantitativos y cualitativos
           - Cómo se registrará el progreso
           - Cómo se dará retroalimentación al paciente/familia

        7. ADAPTACIONES: Sugiere adaptaciones específicas para:
           - Diferentes niveles de habilidad
           - Contextos (clínico, domiciliario, educativo)
           - Características individuales del paciente
           - Disponibilidad de recursos

        8. FUNDAMENTACIÓN TEÓRICA: Explica brevemente (2-3 párrafos completos) en qué teorías, modelos o enfoques se basa la actividad. Cita autores o referencias cuando sea posible.

        FORMATO DE RESPUESTA OBLIGATORIO (JSON con estas claves):

        {{
            "title": "string (título completo y descriptivo)",
            "smart_objective": "string (oración completa y detallada)",
            "description": "string (párrafo completo de 5-7 oraciones mínimo)",
            "materials": "string (párrafo detallado describiendo todos los materiales)",
            "procedure": [
                {{
                    "name": "string (nombre de la fase)",
                    "time": number (duración en minutos),
                    "instructions": "string (instrucciones verbales exactas del terapeuta)",
                    "activities": "string (descripción detallada de las actividades del paciente)",
                    "variations": "string (posibles variaciones o adaptaciones)",
                    "progress_indicators": "string (señales de progreso o dificultad a observar)"
                }}
            ],
            "evaluation": {{
                "criteria": "string (criterios de logro específicos y medibles)",
                "methods": "string (métodos de evaluación cuantitativos y cualitativos)",
                "recording": "string (cómo se registrará el progreso)",
                "feedback": "string (cómo se dará retroalimentación al paciente/familia)"
            }},
            "adaptations": "string (párrafo completo describiendo todas las adaptaciones necesarias)",
            "theoretical_foundation": "string (2-3 párrafos completos con fundamentación teórica)"
        }}

        IMPORTANTE: TODAS las respuestas deben ser TEXTOS COMPLETOS, NO viñetas sueltas ni palabras aisladas. Usa lenguaje profesional, claro y detallado. La actividad debe ser práctica, realista y lista para implementar en una sesión clínica real.
        """

        # ✅ Llamar a OpenRouter API
        content = call_openrouter_api(prompt)

        # Limpiar y parsear JSON
        if content.startswith("```json"):
            content = content[7:]
        if content.endswith("```"):
            content = content[:-3]
        
        data = json.loads(content)

        # ✅ Retornar resultados completos
        return (
            data.get("title", f"Actividad Terapéutica para {objective}"),
            data.get("smart_objective", generate_smart_objective(objective, age, dur)),
            data.get("description", "Descripción detallada generada por IA no disponible."),
            data.get("materials", "Lista de materiales no disponible."),
            "\n\n".join([
                f"FASE: {p.get('name', 'Fase no especificada')} ({p.get('time', 0)} minutos)\n"
                f"INSTRUCCIONES DEL TERAPEUTA: {p.get('instructions', 'No especificadas')}\n"
                f"ACTIVIDADES DEL PACIENTE: {p.get('activities', 'No especificadas')}\n"
                f"VARIACIONES: {p.get('variations', 'No especificadas')}\n"
                f"INDICADORES DE PROGRESO: {p.get('progress_indicators', 'No especificados')}"
                for p in data.get("procedure", [])
            ]),
            f"CRITERIOS DE LOGRO: {data.get('evaluation', {}).get('criteria', 'No especificados')}\n\n"
            f"MÉTODOS DE EVALUACIÓN: {data.get('evaluation', {}).get('methods', 'No especificados')}\n\n"
            f"REGISTRO DE PROGRESO: {data.get('evaluation', {}).get('recording', 'No especificado')}\n\n"
            f"RETROALIMENTACIÓN: {data.get('evaluation', {}).get('feedback', 'No especificada')}",
            data.get("adaptations", "Adaptaciones no disponibles."),
            data.get("theoretical_foundation", "Fundamentación teórica no disponible.")
        )

    except Exception as e:
        # ✅ Mostrar error real
        return (
            "❌ Error al generar con IA",
            f"Error: {str(e)}",
            "La IA no pudo generar una respuesta completa. Esto puede deberse a:\n"
            "• El prompt es demasiado largo o complejo\n"
            "• Problemas temporales con la API de OpenRouter\n"
            "• Tu API Key no es válida o ha excedido límites\n\n"
            "Sugerencias:\n"
            "• Intenta con una descripción más concisa\n"
            "• Reduce la cantidad de PDFs o contexto adicional\n"
            "• Intenta nuevamente en unos minutos",
            "",
            "",
            "",
            "",
            ""
        )

# ✅ Interfaz de Gradio
with gr.Blocks(title="🧠 Generador IA de Actividades Fonoaudiológicas") as demo:
    gr.Markdown("# 🧠 Generador IA de Actividades Fonoaudiológicas")
    gr.Markdown("### ✨ Potenciado con DeepSeek R1 en OpenRouter • Creado por Flgo. Cristóbal San Martín [@tufonoayuda](https://instagram.com/tufonoayuda)")
    
    with gr.Row():
        with gr.Column():
            user_desc = gr.Textbox(label="👤 Descripción del usuario (edad en meses y contexto)", placeholder="Ej: Niño de 48 meses con dislalia funcional, buen nivel cognitivo pero con dificultades en la articulación de fonemas líquidos", lines=3)
            objective = gr.Textbox(label="🎯 Objetivo específico", placeholder="Ej: Mejorar la articulación del fonema /r/ en posición inicial de palabras bisílabas en contexto estructurado con 80% de precisión", lines=2)
            duration = gr.Number(label="⏱️ Duración (minutos)", value=30, minimum=15, maximum=120)
            session_type = gr.Dropdown(["individual", "grupal", "hogar"], label="👥 Tipo de sesión", value="individual")
            is_pediatric = gr.Checkbox(label="🧸 Sesión Pediátrica (lenguaje lúdico)")
            context = gr.Textbox(label="📚 Contexto Adicional (Opcional - Sé lo más específico posible)", placeholder="Ej: El niño responde bien a refuerzos visuales, tiene interés por los dinosaurios, la familia puede reforzar en casa 10 minutos diarios, se ha intentado terapia miofuncional sin éxito...", lines=4)
            pdf_files = gr.File(label="📖 Subir PDFs de Referencia (Opcional)", file_types=[".pdf"], file_count="multiple")
            btn = gr.Button("✨ Generar Actividad con IA", variant="primary")
        
        with gr.Column():
            title = gr.Textbox(label="Título de la Actividad", lines=2)
            smart_obj = gr.Textbox(label="📋 Objetivo SMART", lines=3)
            description = gr.Textbox(label="📝 Descripción General", lines=6)
            materials = gr.Textbox(label="🎯 Materiales Necesarios", lines=4)
            procedure = gr.Textbox(label="⚡ Procedimiento Paso a Paso (Instrucciones completas)", lines=10)
            evaluation = gr.Textbox(label="📊 Evaluación (Criterios, métodos, registro y retroalimentación)", lines=6)
            adaptations = gr.Textbox(label="🔧 Adaptaciones (Párrafo completo)", lines=4)
            theory = gr.Textbox(label="📚 Fundamentación Teórica (2-3 párrafos completos)", lines=6)
    
    # Conectar botón
    btn.click(
        fn=generate_activity,
        inputs=[user_desc, objective, duration, session_type, is_pediatric, context, pdf_files],
        outputs=[title, smart_obj, description, materials, procedure, evaluation, adaptations, theory]
    )

# Lanzar app
if __name__ == "__main__":
    demo.launch()