Spaces:
Runtime error
Runtime error
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() |