<!
DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-
scale=1.0" />
<title>AutonomaBot - Chat</title>
<link
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.
min.css" rel="stylesheet">
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/
all.min.css" rel="stylesheet">
<style>
body { background-color: #f5f5f5; }
.chat-container { display: flex; height: 90vh; }
.sidebar { width: 25%; background: #fff; border-right: 1px solid
#ccc; overflow-y: auto; padding: 1rem; }
.chat-box { width: 75%; display: flex; flex-direction: column; }
.messages { flex-grow: 1; padding: 1rem; overflow-y: auto;
background-color: #e9ecef; }
.input-box { padding: 1rem; background: #fff; border-top: 1px solid
#ccc; }
.message { margin-bottom: 1rem; }
.user { text-align: right; }
.bot { text-align: left; }
</style>
</head>
<body>
<nav class="navbar navbar-light bg-light px-4">
<span class="navbar-brand mb-0 h1">Bienvenido,
{{ usuario }}</span>
<a href="/logout" class="btn btn-danger">Cerrar sesión</a>
</nav>
<div class="chat-container">
<div class="sidebar">
<h5>Historial</h5>
<ul class="list-group" id="conversation-history"></ul>
</div>
<div class="chat-box">
<div class="messages" id="chatbox"></div>
<div class="input-box">
<form id="chat-form">
<div class="input-group">
<input type="text" id="textInput" class="form-control"
placeholder="Escribe tu mensaje..." autocomplete="off" />
<button class="btn btn-primary" type="submit"><i
class="fas fa-paper-plane"></i></button>
</div>
</form>
</div>
</div>
</div>
<script>
const form = document.getElementById('chat-form');
const input = document.getElementById('textInput');
const chatbox = document.getElementById('chatbox');
const historyList = document.getElementById('conversation-
history');
let history =
JSON.parse(localStorage.getItem("chat_history_{{ usuario }}") || "[]");
function appendMessage(sender, text) {
const msgDiv = document.createElement('div');
msgDiv.classList.add('message', sender);
msgDiv.innerText = (sender === 'user' ? 'Tú: ' : 'Bot: ') + text;
chatbox.appendChild(msgDiv);
chatbox.scrollTop = chatbox.scrollHeight;
function updateSidebar() {
historyList.innerHTML = "";
history.forEach((item, i) => {
const li = document.createElement("li");
li.className = "list-group-item text-truncate";
li.title = `${item.usuario || item.bot}`;
li.innerText = item.usuario ? `🧑 ${item.usuario}` : `🤖 $
{item.bot}`;
historyList.appendChild(li);
});
history.forEach(entry => {
if (entry.usuario) appendMessage('user', entry.usuario);
if (entry.bot) appendMessage('bot', entry.bot);
});
updateSidebar();
form.onsubmit = async (e) => {
e.preventDefault();
const msg = input.value.trim();
if (!msg) return;
appendMessage('user', msg);
history.push({ usuario: msg });
updateSidebar();
input.value = "";
const res = await fetch("/get", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({ msg })
});
const data = await res.json();
appendMessage('bot', data.respuesta);
history.push({ bot: data.respuesta });
updateSidebar();
localStorage.setItem("chat_history_{{ usuario }}",
JSON.stringify(history));
};
</script>
</body>
</html>
App.py
import os
import json
import time
import threading
import locale
import logging
import requests
import pyttsx3
import wikipedia
from datetime import datetime
from flask import Flask, render_template, request, jsonify, redirect,
session, url_for
from flask_session import Session
from langdetect import detect
from googletrans import Translator
from dotenv import load_dotenv
# Cargar variables del entorno
load_dotenv()
# Configurar idioma
try:
locale.setlocale(locale.LC_TIME, "es_ES.UTF-8")
except locale.Error:
locale.setlocale(locale.LC_TIME, "")
# Configuración de Flask
app = Flask(__name__)
app.secret_key = os.getenv("SECRET_KEY", "clave_super_secreta")
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Configurar logging
logging.basicConfig(level=logging.INFO)
# Configurar Wikipedia en español
wikipedia.set_lang("es")
# Inicializar pyttsx3
engine = pyttsx3.init()
def speak(text):
try:
engine.say(text)
engine.runAndWait()
except RuntimeError:
pass # Para evitar error de "run loop already started"
# Usuarios válidos
usuarios = {
"[email protected]": "1234",
"[email protected]": "abcd",
"[email protected]": "fs123",
"[email protected]": "mb123",
"[email protected]": "br123"
# Ruta de login
@app.route("/", methods=["GET", "POST"])
def login():
if request.method == "POST":
email = request.form["email"]
password = request.form["password"]
if email in usuarios and usuarios[email] == password:
session["usuario"] = email
session["historial"] = []
return redirect("/chat")
else:
return render_template("login.html", error="Correo o
contraseña incorrectos.")
return render_template("login.html")
# Ruta principal del chat
@app.route("/chat")
def chat_page():
if "usuario" not in session:
return redirect("/")
return render_template("chat.html", usuario=session["usuario"])
# Cerrar sesión y guardar historial
@app.route("/logout")
def logout():
guardar_historial()
session.clear()
return redirect("/")
# Ruta de conversación
@app.route("/get", methods=["POST"])
def chat():
msg = request.form.get("msg", "").strip()
if not msg:
return jsonify({"respuesta": "⚠️Mensaje vacío."})
session["historial"].append({"usuario": msg})
respuesta = ""
# Saludo
if msg.lower() in ["hola", "buenos días", "buenas tardes", "buenas
noches"]:
respuesta = "¡Hola! ¿En qué puedo ayudarte hoy? 😊"
# Mostrar hora
elif "hora" in msg.lower():
current_time = time.strftime("%H:%M del %A, %d de %B de %Y",
time.localtime())
respuesta = f"La hora actual es: {current_time}"
# Traducción
elif any(palabra in msg.lower() for palabra in ["cómo se dice",
"como se dice", "traducir", "traduce"]):
respuesta = traducir_texto(msg)
# Consultas informativas (Wikipedia o DuckDuckGo)
else:
respuesta = buscar_informacion(msg)
if not respuesta:
respuesta = "⚠️Lo siento, no encontré una respuesta clara."
session["historial"].append({"bot": respuesta})
session["last_bot_response"] = respuesta
threading.Thread(target=speak, args=(respuesta,)).start()
return jsonify({"respuesta": respuesta})
# Traducción de textos
def traducir_texto(msg):
traductor = Translator()
try:
palabras = msg.lower().split()
idioma = "en"
if "francés" in msg or "frances" in msg:
idioma = "fr"
elif "italiano" in msg:
idioma = "it"
elif "alemán" in msg or "aleman" in msg:
idioma = "de"
elif "portugués" in msg or "portugues" in msg:
idioma = "pt"
partes = msg.split("dice")
if len(partes) >= 2:
frase = partes[1].strip()
traduccion = traductor.translate(frase, dest=idioma)
return f'"{frase}" en {idioma.upper()} se dice:
"{traduccion.text}"'
else:
return "⚠️Especifica qué frase quieres traducir, por favor."
except Exception as e:
logging.error(f"Error al traducir: {e}")
return "❌ No pude traducir la frase."
# Buscar en Wikipedia o DuckDuckGo
def buscar_informacion(pregunta):
# Wikipedia
try:
summary = wikipedia.summary(pregunta, sentences=2)
if summary:
return summary
except:
pass
# DuckDuckGo Instant Answer API (NO oficial)
try:
url = f"https://api.duckduckgo.com/?
q={pregunta}&format=json&no_html=1&skip_disambig=1"
r = requests.get(url)
data = r.json()
if data.get("AbstractText"):
return data["AbstractText"]
except Exception as e:
logging.error(f"Error en búsqueda alternativa: {e}")
return ""
# Guardar historial de chat
def guardar_historial():
usuario = session.get("usuario")
historial = session.get("historial", [])
if not usuario or not historial:
return
nombre_archivo =
f"{usuario.replace('@','_').replace('.','_')}_{datetime.now().strftime('%
Y%m%d_%H%M%S')}.json"
os.makedirs("historiales", exist_ok=True)
ruta = os.path.join("historiales", nombre_archivo)
with open(ruta, "w", encoding="utf-8") as f:
json.dump(historial, f, indent=2, ensure_ascii=False)
# Hora por separado
@app.route("/time", methods=["GET"])
def get_time():
current_time = time.strftime("%H:%M del %A, %d de %B de %Y",
time.localtime())
return jsonify({"current_time": current_time})
if __name__ == "__main__":
app.run(debug=True)
login
!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Iniciar sesión - AutonomaBot</title>
<link
href="https://cdn.jsdelivr.net/npm/
[email protected]/dist/css/bootstrap.
min.css" rel="stylesheet">
<style>
body {
background-color: #f1f3f5;
.login-container {
max-width: 400px;
margin: 80px auto;
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 0 15px rgba(0,0,0,0.1);
.form-control {
border-radius: 8px;
.btn-primary {
border-radius: 8px;
.error-msg {
color: red;
font-size: 0.9rem;
margin-top: 10px;
</style>
</head>
<body>
<div class="login-container">
<h3 class="text-center mb-4">AutonomaBot</h3>
<form method="POST">
<div class="mb-3">
<label for="email" class="form-label">Correo
electrónico</label>
<input type="email" class="form-control" id="email"
name="email" placeholder="
[email protected]" required>
</div>
<div class="mb-3">
<label for="password"
class="form-label">Contraseña</label>
<input type="password" class="form-control" id="password"
name="password" placeholder="Ingrese su contraseña" required>
</div>
{% if error %}
<div class="error-msg">{{ error }}</div>
{% endif %}
<button type="submit" class="btn btn-primary w-100 mt-
3">Ingresar</button>
</form>
</div>
</body>
</html>