| |
| |
|
|
| import os |
| import re |
| import random |
| from collections import Counter |
|
|
| |
| |
| |
| TOPICO = "entrenamiento en el gimnasio" |
| PALABRAS_CLAVE = { |
| |
| "gimnasio","entrenar","rutina","pesas","mancuernas","series","repeticiones", |
| "calentamiento","piernas","pecho","espalda","hombros","biceps","triceps", |
| "cardio","fuerza","hipertrofia","descanso","nutricion","proteina","creatina", |
| "tecnica","maquina","sentadilla","press","remar","dominadas","plan","progreso" |
| } |
| ARCHIVO_VOCAB = "vocab.txt" |
| TAMANIO_VOCAB = 1000 |
|
|
| |
| MENSAJE_FUERA_DE_TEMA = ( |
| "lo siento. solo puedo hablar sobre " + TOPICO + ". " |
| "por favor hacé una pregunta relacionada." |
| ) |
|
|
| |
| |
| |
| def normalizar(texto: str) -> str: |
| texto = texto.lower() |
| texto = re.sub(r"[^\wáéíóúñü ]", " ", texto, flags=re.UNICODE) |
| texto = re.sub(r"\s+", " ", texto).strip() |
| return texto |
|
|
| def cargar_o_crear_vocab(ruta: str, objetivo: int) -> list: |
| """ |
| - Si existe vocab.txt: lo carga y valida tamaño. |
| - Si no existe: crea una lista de palabras base + tokens de relleno hasta llegar a 1000 |
| y la guarda en el archivo para que la puedas editar. |
| """ |
| if os.path.exists(ruta): |
| with open(ruta, "r", encoding="utf-8") as f: |
| palabras = [normalizar(l) for l in f if l.strip()] |
| |
| seen = set() |
| vocab = [] |
| for p in palabras: |
| if p not in seen: |
| seen.add(p) |
| vocab.append(p) |
| |
| if len(vocab) > objetivo: |
| vocab = vocab[:objetivo] |
| elif len(vocab) < objetivo: |
| faltan = objetivo - len(vocab) |
| |
| inicio = len(vocab) + 1 |
| for i in range(inicio, inicio + faltan): |
| vocab.append(f"token{i:03d}") |
| return vocab |
| else: |
| base = set(""" |
| yo tu vos usted ustedes nosotros hola chau gracias por favor si no tal vez |
| puedo podes podesme decir contar explicar como cuando donde cual porque para |
| hoy ayer manana semana mes anio ahora antes despues poco mucho bien mal mas |
| menos igual tema topico relacionado ejemplo paso guia idea ayuda duda |
| pregunta respuesta claro listo simple rapido seguro lento suave duro facil dificil |
| cuerpo espalda pecho hombro pierna brazo biceps triceps abdomen gluteo |
| calentar descanso energia fuerza peso repetir serie rutina plan objetivo |
| progreso tecnica forma postura respiracion dolor cuidado prevenir riesgo |
| maquina banco barra mancuerna polea cuerda banda remo press sentadilla |
| dominada elevacion curl extension cardio cinta bici remadora |
| tiempo minuto segundo intervalo dia |
| nutricion comida proteina carbohidrato grasa agua creatina suplemento |
| tomar comer cocinar batido leche avena huevo arroz pollo carne banana |
| antes durante despues entrenar |
| """.split()) |
| |
| base.update({ |
| "hola","bienvenido","estoy","listo","para","ayudar","sobre","entrenamiento", |
| "en","el","gimnasio","es","importante","usar","buena","tecnica","y","progresar", |
| "de","a","poco","si","sos","principiante","empeza","con","poco","peso","y", |
| "aumenta","cuando","la","forma","sea","solida","queres","rutina","para","hoy", |
| "tenes","alguna","meta","fuerza","o","hipertrofia","recorda","descansar", |
| "entre","series","y","dormir","bien" |
| }) |
| base = [normalizar(w) for w in base if w.strip()] |
| |
| vocab = [] |
| seen = set() |
| for w in base: |
| if w not in seen: |
| seen.add(w) |
| vocab.append(w) |
| i = 1 |
| while len(vocab) < objetivo: |
| token = f"token{i:03d}" |
| if token not in seen: |
| seen.add(token) |
| vocab.append(token) |
| i += 1 |
| |
| with open(ruta, "w", encoding="utf-8") as f: |
| f.write("\n".join(vocab)) |
| return vocab |
|
|
| def es_en_tema(texto_usuario: str, palabras_clave: set) -> bool: |
| tu = set(normalizar(texto_usuario).split()) |
| |
| if tu & palabras_clave: |
| return True |
| for w in normalizar(TOPICO).split(): |
| if w in tu: |
| return True |
| return False |
|
|
| def limitar_a_vocab(texto: str, vocab_set: set) -> str: |
| """ |
| Asegura que la salida solo use palabras del vocabulario. |
| Palabras fuera del vocabulario se sustituyen por 'token001'. |
| """ |
| palabras = normalizar(texto).split() |
| out = [] |
| sustituto = "token001" if "token001" in vocab_set else next(iter(vocab_set)) |
| for p in palabras: |
| out.append(p if p in vocab_set else sustituto) |
| return " ".join(out) |
|
|
| |
| |
| |
| def detectar_intencion(texto_usuario: str) -> str: |
| t = normalizar(texto_usuario) |
| if any(x in t for x in ["hola","buenas","que tal","buen dia","buenas tardes","buenas noches"]): |
| return "saludo" |
| if any(x in t for x in ["rutina","plan","programa","entreno","entrenar","hoy que hago"]): |
| return "rutina" |
| if any(x in t for x in ["pecho","espalda","pierna","hombro","biceps","triceps","abdomen","core"]): |
| return "musculo" |
| if any(x in t for x in ["tecnica","forma","postura","como hago","como se hace"]): |
| return "tecnica" |
| if any(x in t for x in ["nutricion","comer","proteina","creatina","batido","dieta","comida"]): |
| return "nutricion" |
| if any(x in t for x in ["descanso","series","repeticiones","cuanto","cuantas","minutos","intervalo"]): |
| return "parametros" |
| if any(x in t for x in ["chau","adios","gracias","nos vemos","hasta luego"]): |
| return "despedida" |
| return "desconocida" |
|
|
| def generar_respuesta_en_tema(intencion: str) -> str: |
| |
| if intencion == "saludo": |
| return ( |
| "hola. estoy listo para ayudar sobre entrenamiento en el gimnasio. " |
| "queres una rutina para hoy o una guia por objetivo." |
| ) |
| if intencion == "rutina": |
| return ( |
| "rutina base: cuerpo completo. hacé tres series por ejercicio y ocho a doce repeticiones. " |
| "ejemplo: sentadilla, press pecho, remo, elevacion hombro, curl biceps, extension triceps, plancha. " |
| "descanso uno a dos minutos entre series." |
| ) |
| if intencion == "musculo": |
| return ( |
| "para ese musculo, usa uno a tres ejercicios con tecnica solida. " |
| "progresá poco a poco y evita dolor raro. " |
| "si la forma falla, baja el peso y repetí." |
| ) |
| if intencion == "tecnica": |
| return ( |
| "usa postura neutral, abdomen activo y movimiento controlado. " |
| "sin rebote y con rango que puedas sostener sin dolor. " |
| "respira: baja tomando aire y sube soltando." |
| ) |
| if intencion == "nutricion": |
| return ( |
| "nutricion simple: prioriza proteina en cada comida, hidrata con agua y dormi bien. " |
| "si usas creatina: cinco gramos al dia con comida. " |
| "no es magia, es constancia." |
| ) |
| if intencion == "parametros": |
| return ( |
| "series: dos a cuatro por ejercicio. repeticiones: seis a doce para hipertrofia. " |
| "descanso: uno a tres minutos segun esfuerzo. " |
| "progreso: subí poco el peso cuando la tecnica sea solida." |
| ) |
| if intencion == "despedida": |
| return "gracias por charlar. buen entrenamiento y buen descanso." |
| |
| return ( |
| "puedo hablar sobre rutina, tecnica, nutricion, series y progresion en el gimnasio. " |
| "decime que queres y armamos algo simple." |
| ) |
|
|
| |
| |
| |
| def main(): |
| vocab = cargar_o_crear_vocab(ARCHIVO_VOCAB, TAMANIO_VOCAB) |
| vocab_set = set(vocab) |
|
|
| print("chatbot:", limitar_a_vocab( |
| f"hola. soy un asistente sobre {TOPICO}. usa mensajes simples. escribi 'salir' para terminar.", |
| vocab_set |
| )) |
|
|
| while True: |
| try: |
| user = input("vos: ") |
| except (EOFError, KeyboardInterrupt): |
| print("\nchatbot: chau.") |
| break |
|
|
| if not user: |
| continue |
|
|
| if normalizar(user) == "salir": |
| print("chatbot:", limitar_a_vocab("chau. hasta luego.", vocab_set)) |
| break |
|
|
| |
| if not es_en_tema(user, PALABRAS_CLAVE): |
| print("chatbot:", limitar_a_vocab(MENSAJE_FUERA_DE_TEMA, vocab_set)) |
| continue |
|
|
| |
| intent = detectar_intencion(user) |
| respuesta = generar_respuesta_en_tema(intent) |
| respuesta_limited = limitar_a_vocab(respuesta, vocab_set) |
|
|
| |
| if not respuesta_limited.strip(): |
| respuesta_limited = limitar_a_vocab( |
| "lo siento. no tengo una respuesta. podes repetir con otras palabras.", |
| vocab_set |
| ) |
|
|
| print("chatbot:", respuesta_limited) |
|
|
| if __name__ == "__main__": |
| main() |
| import gradio as gr |
|
|
| iface = gr.Interface(fn=chat, inputs="text", outputs="text") |
| iface.launch() |
|
|