Menu iconMenu icon
OpenAI API Biblia Volumen 2

Capítulo 4: Construyendo un Chatbot Simple con Memoria

4.2 Creación de Interfaces de Usuario Interactivas

Las interfaces de usuario son el puente entre la inteligencia de tu chatbot y sus usuarios. Una UI bien diseñada puede transformar un sistema de IA capaz en una herramienta atractiva y accesible que los usuarios disfrutan usar. Crear una interfaz efectiva para el chatbot requiere una cuidadosa consideración de los principios de experiencia de usuario, elementos de diseño visual y patrones de interacción.

Esta sección explora el arte y la ciencia de construir interfaces de chatbot intuitivas. Examinaremos tanto la implementación técnica como las consideraciones de diseño que hacen que un chatbot sea verdaderamente fácil de usar. Aprenderás a crear interfaces que no solo se vean profesionales sino que también proporcionen retroalimentación significativa, manejen errores con elegancia y guíen a los usuarios a través de conversaciones naturales.

Ya sea que estés construyendo un bot de servicio al cliente, un asistente virtual o una herramienta de aprendizaje impulsada por IA, los principios y técnicas cubiertos aquí te ayudarán a crear interfaces que mejoren en lugar de obstaculizar la experiencia del usuario. Veremos enfoques de implementación usando tanto Streamlit como Flask, dándote la flexibilidad de elegir las herramientas que mejor se adapten a las necesidades de tu proyecto.

4.2.1 Por qué la UI es Importante en un Chatbot

El éxito de un chatbot depende en gran medida de su interfaz de usuario y experiencia de usuario general. No importa cuán sofisticado sea tu modelo de IA, los usuarios tendrán dificultades para interactuar efectivamente con él si la interfaz es difícil de usar o poco intuitiva. Por eso es crucial crear interfaces bien diseñadas y fáciles de usar. Nos centraremos en construir UIs intuitivas, responsivas y fáciles de usar que no solo se vean profesionales sino que también creen un flujo natural de conversación entre el usuario y la IA.

Nuestro enfoque enfatiza tres aspectos fundamentales del diseño de interfaces que son críticos para crear un chatbot efectivo:

Experiencia de Usuario (UX)

Crear interfaces que sean fáciles de navegar y entender, con jerarquías visuales claras y patrones de interacción intuitivos. Una UX bien diseñada considera varios aspectos clave:

  1. Arquitectura de Información: Organizar el contenido en una estructura lógica y fácil de seguir que coincida con los modelos mentales de los usuarios.
  2. Diseño Visual: Usar esquemas de color, tipografía y espaciado consistentes para crear jerarquías visuales claras que guíen la atención de los usuarios.
  3. Diseño de Interacción: Implementar controles y patrones de navegación intuitivos que se sientan familiares y predecibles para los usuarios.
  4. Mecanismos de Retroalimentación: Proporcionar señales visuales y textuales claras que ayuden a los usuarios a entender:
    • Cuándo su mensaje está siendo procesado
    • Cuándo el chatbot está "pensando"
    • Si ocurre un error
    • Si su entrada fue recibida exitosamente
  5. Gestión de Carga Cognitiva: Minimizar el esfuerzo mental requerido para usar la interfaz mediante:
    • División de tareas complejas en pasos más pequeños
    • Uso de patrones de diseño familiares
    • Proporcionar instrucciones claras cuando sea necesario
    • Mantener un comportamiento consistente en toda la interfaz

Este enfoque reflexivo del diseño UX reduce la fricción, aumenta el compromiso del usuario y hace que el chatbot se sienta natural y sin esfuerzo de usar.

Capacidad de Respuesta

Asegurar que la interfaz proporcione retroalimentación inmediata y mantenga un rendimiento fluido en diferentes dispositivos y tamaños de pantalla. Esto involucra varios aspectos clave:

  1. Optimización del Rendimiento:
    • Implementar estados de carga eficientes que muestren a los usuarios que sus acciones están siendo procesadas
    • Optimizar tiempos de respuesta mediante técnicas como debouncing de solicitudes y caché
    • Usar carga progresiva para el historial de chat para manejar conversaciones grandes
  2. Compatibilidad con Dispositivos:
    • Usar principios de diseño responsivo para asegurar que el chatbot funcione sin problemas en todos los dispositivos
    • Implementar diseños fluidos que se ajusten a diferentes tamaños de pantalla
    • Asegurar elementos de interfaz amigables al tacto para usuarios móviles
    • Probar y optimizar para varios navegadores y plataformas
  3. Elementos UI Adaptativos:
    • Crear burbujas de chat flexibles que cambien de tamaño según el contenido
    • Implementar menús y controles plegables para pantallas más pequeñas
    • Usar unidades relativas (em, rem, vh, vw) en lugar de píxeles fijos
    • Asegurar un correcto ajuste de texto y legibilidad en todos los tamaños

La interfaz debe adaptarse dinámicamente a diferentes tamaños de pantalla mientras mantiene la funcionalidad y el atractivo visual, proporcionando una experiencia consistente ya sea que se acceda desde un smartphone, tablet o computadora de escritorio.

Accesibilidad

Hacer que el chatbot sea utilizable para personas con diferentes capacidades y conocimientos técnicos es crucial para garantizar un acceso inclusivo. Esto implica varias consideraciones clave:

  • Compatibilidad con Lectores de Pantalla
    • Implementación de etiquetas y roles ARIA apropiados para describir elementos de la interfaz
    • Asegurar una estructura de encabezados y navegación significativa
    • Proporcionar alternativas textuales para todo el contenido no textual
  • Navegación por Teclado
    • Soporte del control completo por teclado de todas las funciones
    • Implementación de indicadores visibles de enfoque
    • Creación de un orden lógico de tabulación a través de la interfaz
  • Diseño Visual
    • Mantener ratios de contraste de color suficientes (mínimo 4.5:1)
    • Evitar el uso del color como único medio para transmitir información
    • Permitir el redimensionamiento del texto sin pérdida de funcionalidad
  • Consideraciones Técnicas
    • Seguir los estándares de las Pautas de Accesibilidad para el Contenido Web (WCAG) 2.1 Nivel AA
    • Pruebas regulares con herramientas de accesibilidad y lectores de pantalla
    • Proporcionar alternativas para interacciones complejas

Al implementar estas características de accesibilidad, aseguras que tu chatbot pueda ser utilizado efectivamente por personas con diversas discapacidades, incluyendo impedimentos visuales, auditivos, motores y cognitivos. Esto no solo cumple con los requisitos legales sino que también demuestra un compromiso con los principios de diseño universal.

Para crear una interfaz de chatbot efectiva y fácil de usar, exploraremos estos componentes esenciales en detalle:

  1. Construcción de una Interfaz de Chat Intuitiva
    • Implementación de principios de diseño limpios y modernos que prioricen la legibilidad y el compromiso del usuario
    • Consideración cuidadosa del espaciado para crear espacio visual entre elementos
    • Uso estratégico de la tipografía para establecer una jerarquía clara de información
    • Elementos visuales consistentes que guíen a los usuarios a través del flujo de conversación
  2. Gestión del Historial de Conversación
    • Implementación de sistemas eficientes de almacenamiento y recuperación de registros de chat
    • Integración de funcionalidad de marcas temporales para mejor seguimiento de conversaciones
    • Creación de estilos visuales distintivos para mensajes de usuario y bot
    • Desarrollo de mecánicas de desplazamiento suave para conversaciones más largas
  3. Optimización de la Presentación de Respuestas
    • Selección cuidadosa de fuentes y tamaños de texto para máxima legibilidad
    • Implementación de patrones de espaciado consistentes entre elementos de mensaje
    • Consideraciones especiales de formato para diferentes tipos de contenido (bloques de código, listas, etc.)
    • Integración de indicadores visuales para estado y tipo de mensaje
  4. Implementación de Sistemas Robustos de Retroalimentación
    • Creación de animaciones de carga sutiles pero visibles durante la generación de respuestas
    • Desarrollo de mensajes de error claros que guíen a los usuarios hacia soluciones
    • Implementación de mecanismos de recuperación para escenarios comunes de error
    • Integración de indicadores de estado para mantener a los usuarios informados del estado del sistema

Obtendrás ejemplos completos tanto en Streamlit como en Flask, permitiéndote elegir el framework que mejor se adapte a tu estilo de desarrollo y requisitos del proyecto. Cada ejemplo incluye explicaciones detalladas y mejores prácticas para la implementación.

4.2.2 Interfaz de Chat Interactiva con Streamlit

Este ejemplo demuestra cómo crear un chatbot interactivo usando Streamlit y OpenAI, sobre el cual construiremos más adelante. Usando Streamlit, crearemos una interfaz de chat amigable que mantiene el historial de conversación. Este caso de uso presenta conceptos clave y mejores prácticas para construir un chatbot robusto e interactivo.

Paso 1: Instalar Dependencias

pip install streamlit openai python-dotenv
  • streamlit: Una librería de Python para crear aplicaciones web interactivas.
  • openai: La librería de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una librería para cargar variables de entorno desde un archivo .env.

Paso 2: Crear la Aplicación Streamlit (chatbot.py)

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.

    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.

    Returns:
        str: The assistant's reply, or an error message.

    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

def initialize_session_state():
    """
    Initializes session state variables.  This function should be called
    at the beginning of the main() function.  It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

# --- Main App ---
def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")

    initialize_session_state()  # Initialize session state

    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history) # corrected to clear_chat_history

    # Display chat history, রাখা changed to display_messages
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")

    # User input, রাখা outside the conditional block
    user_input = st.chat_input("Ask me anything...", key="user_input")

    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})

        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model) #added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response

        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})

        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()

if __name__ == "__main__":
    main()

Desglose del Código

Analicemos el código paso a paso.

Importaciones:

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

Importa las bibliotecas necesarias:

  • streamlit: Para crear la interfaz web.
  • openai: Para interactuar con la API de OpenAI.
  • os: Para acceder a las variables de entorno.
  • dotenv: Para cargar variables de entorno desde un archivo .env.
  • time: Para manejar posibles errores de API mediante esperas.
  • typing: Para anotaciones de tipo que mejoran la legibilidad del código.

Variables de Entorno:

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

Carga la clave API de OpenAI desde un archivo .env y la configura para la biblioteca OpenAI.

Constantes:

DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant.  Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
  • DEFAULT_MODEL: El modelo predeterminado de OpenAI utilizado para el chatbot.
  • SYSTEM_PROMPT: El mensaje inicial enviado a la API de OpenAI para establecer el comportamiento del asistente.
  • SESSION_MESSAGES_KEY: Clave para usar en el historial principal de conversación en el estado de la sesión.
  • DISPLAY_MESSAGES_KEY: Clave para usar en el historial de conversación que se muestra en la interfaz de usuario.

Funciones Auxiliares:

  • get_openai_response():
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.
    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.
    Returns:
        str: The assistant's reply, or an error message.
    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

Envía la entrada del usuario a la API de OpenAI y obtiene la respuesta. Esta función también incluye manejo de errores usando un bloque try...except para capturar posibles excepciones openai.error.OpenAIError y una Exception general para otros errores. Se agrega un tiempo límite para evitar que la aplicación se quede colgada indefinidamente.

  • initialize_session_state():
def initialize_session_state():
    """
    Initializes session state variables. This function should be called
    at the beginning of the main() function. It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

Inicializa las variables del estado de la sesión:

  • SESSION_MESSAGES_KEY: Almacena el historial completo de la conversación.
  • DISPLAY_MESSAGES_KEY: Almacena el historial de la conversación que se muestra al usuario.
  • model: El modelo LLM
  • clear_chat_history():
def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

Borra el historial del chat cuando el usuario hace clic en el botón "Borrar Chat".

Aplicación Principal:

def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")
    initialize_session_state()
    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history)
    # Display chat history
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")
    # User input
    user_input = st.chat_input("Ask me anything...", key="user_input")
    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})
        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model)  # added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()
if __name__ == "__main__":
    main()
  • st.set_page_config(page_title="AI Chatbot", page_icon="🤖"): Configura el título y el ícono de la página en la pestaña del navegador.
  • st.title("🤖 GPT-4o Assistant"): Establece el título de la aplicación Streamlit.
  • initialize_session_state(): Inicializa la sesión
  • st.sidebar.header("Settings"): Crea una sección de barra lateral titulada "Settings".
  • model = st.sidebar.selectbox(...): Crea un menú desplegable en la barra lateral para seleccionar el modelo de OpenAI.
  • clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history): Agrega un botón a la barra lateral para borrar el historial del chat.
  • El historial del chat se muestra usando st.chat_message, con diferentes estilos para los mensajes del usuario y del asistente.
  • user_input = st.chat_input("Ask me anything...", key="user_input"): Crea un campo de entrada de texto para que el usuario escriba su consulta. El argumento key es importante para que Streamlit gestione el estado del campo de entrada.
  • La aplicación obtiene la entrada del usuario, la envía a la API de OpenAI usando la función get_openai_response, y muestra la respuesta.
  • El historial de la conversación se almacena en st.session_state.messages como una lista de diccionarios. Cada diccionario tiene un "role" (ya sea "user" o "assistant") y "content".
  • st.rerun() se utiliza para actualizar la pantalla después de que el asistente responde.
  • Ejecutar la aplicación:Para ejecutar la aplicación, guarda el código en un archivo llamado chatbot.py y ejecuta el siguiente comando en tu terminal:
streamlit run chatbot.py

4.2.3 Interfaz de Chat Personalizada con Flask + HTML/CSS

Este ejemplo implementa un chatbot usando Flask y el modelo GPT-4o de OpenAI, con énfasis en permitir que los desarrolladores personalicen la interfaz del chat usando su propio HTML y CSS. Este enfoque proporciona mayor flexibilidad en el diseño y la disposición en comparación con el uso de componentes de interfaz preconfigurados. Este código proporciona un chatbot robusto y personalizable, explicando conceptos clave y mejores prácticas para desarrolladores de nivel intermedio.

Paso 1: Instalar Dependencias

pip install flask openai python-dotenv
  • flask: Un framework web para construir la aplicación del chatbot.
  • openai: La biblioteca de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una biblioteca para cargar variables de entorno desde un archivo .env.

Paso 2: Plantilla Actualizada de Flask (templates/chat.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GPT-4o Chat Assistant</title>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
  <style>
    /* --- General Styles --- */
    body {
      font-family: 'Inter', sans-serif;  /* Modern font */
      background-color: #f3f4f6;  /* Tailwind's gray-100 */
      padding: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      color: #1f2937;  /* Tailwind's gray-800 */
    }
    .container {
      max-width: 800px;  /* Increased max-width */
      width: 100%;
      background-color: #fff; /* White background */
      padding: 30px;
      border-radius: 0.75rem;  /* Tailwind's rounded-lg */
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);  /* Tailwind's shadow-md */
    }
    h2 {
      font-size: 1.875rem; /* Tailwind's text-2xl */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 2rem;  /* Tailwind's mb-8 */
      color: #1e293b; /* Tailwind's gray-900 */
      text-align: center;
    }
    /* --- Message Styles --- */
    .message {
      margin-bottom: 1.5rem;  /* Tailwind's mb-6 */
      display: flex;
      flex-direction: column;
    }
    .message p {
      padding: 1rem;  /* Tailwind's p-4 */
      border-radius: 1rem;  /* Tailwind's rounded-lg */
      max-width: 80%; /* Limit message width */
    }
    .user p {
      background-color: #e0f2fe;  /* Tailwind's bg-blue-100 */
      color: #1d4ed8;  /* Tailwind's text-blue-700 */
      margin-left: auto; /* Push user message to the right */
    }
    .assistant p {
      background-color: #f0fdf4;  /* Tailwind's bg-green-100 */
      color: #15803d;  /* Tailwind's text-green-700 */
    }
    .message strong {
      font-size: 0.875rem; /* Tailwind's text-sm */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
    }
    .user strong {
        color: #1e40af; /* Tailwind's text-blue-800 */
    }
    .assistant strong {
        color: #16a34a; /* Tailwind's text-green-800 */
    }

    /* --- Form Styles --- */
    form {
      margin-top: 2rem;  /* Tailwind's mt-8 */
      display: flex;
      flex-direction: column;
      gap: 0.5rem; /* Tailwind's gap-2 */
    }
    textarea {
      width: 100%;
      padding: 0.75rem;  /* Tailwind's p-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      border: 1px solid #d1d5db;  /* Tailwind's border-gray-300 */
      resize: none;
      font-size: 1rem;  /* Tailwind's text-base */
      line-height: 1.5rem;  /* Tailwind's leading-relaxed */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
      box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow, more subtle */
    }
    textarea:focus {
      outline: none;
      border-color: #3b82f6;  /* Tailwind's border-blue-500 */
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);  /* Tailwind's ring-blue-500 with opacity */
    }
    input[type="submit"] {
      padding: 0.75rem 1.5rem;  /* Tailwind's px-6 py-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      background-color: #3b82f6;  /* Tailwind's bg-blue-500 */
      color: #fff;  /* White text */
      font-size: 1rem;  /* Tailwind's text-base */
      font-weight: 600;  /* Tailwind's font-semibold */
      cursor: pointer;
      transition: background-color 0.3s ease;  /* Smooth transition */
      border: none;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);  /* Tailwind's shadow-sm */
    }
    input[type="submit"]:hover {
      background-color: #2563eb;  /* Tailwind's bg-blue-700 on hover */
    }
    input[type="submit"]:focus {
      outline: none;
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);  /* Tailwind's ring-blue-500 with more opacity*/
    }

    /* --- Responsive Adjustments --- */
    @media (max-width: 768px) {  /* Medium screens and below (md breakpoint in Tailwind is 768px) */
      .container {
        padding: 20px;
      }
      textarea {
        height: 100px;  /* Make textarea taller on smaller screens */
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>🧠 GPT-4o Chat Assistant</h2>
    {% for msg in history %}
      <div class="message {{ msg.role }}">
        <p><strong>{{ msg.role.capitalize() }}:</strong> {{ msg.content }}</p>
      </div>
    {% endfor %}
    <form method="post">
      <textarea name="user_input" placeholder="Type your message..."></textarea><br>
      <input type="submit" value="Send Message">
    </form>
  </div>
</body>
</html>

Plantilla HTML:

  • Diseño Moderno: La plantilla presenta un enfoque de diseño contemporáneo inspirado en Tailwind CSS. Esto incluye:
    • Fuente limpia (Inter)
    • Espaciado y márgenes amplios
    • Esquinas redondeadas
    • Sombras sutiles
    • Paleta de colores consistente
  • Diseño Responsivo: Se agregó una media query para ajustar el diseño en pantallas más pequeñas (tabletas y teléfonos).
  • Formulario Mejorado: El formulario está estilizado con un estado de enfoque, mejores márgenes y un efecto suave al pasar el cursor.
  • HTML Semántico: Utiliza lang="en" en la etiqueta &lt;html&gt; para mejor accesibilidad.
  • Comentarios: Se agregaron comentarios para explicar el CSS, relacionándolo con Tailwind CSS cuando corresponde, para facilitar la comprensión.

Paso 3: Backend Flask Actualizado (app.py)

from flask import Flask, request, render_template, session, redirect, url_for
import openai
import os
from dotenv import load_dotenv
import time
from typing import List, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)
app.secret_key = os.urandom(24)  # Required for session management

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "conversation"  # Consistent key for session

# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors.
    Args:
        messages: A list of message dictionaries.
        model: The OpenAI model to use.
    Returns:
        The assistant's reply, or an error message.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        # Log the error for debugging
        print(f"OpenAI API error: {e}")
        return f"Sorry, there was an error communicating with the AI: {e}"
    except Exception as e:
        print(f"Unexpected error: {e}")
        return "Sorry, an unexpected error occurred."

def initialize_session_state():
    """Initializes session state."""
    if SESSION_MESSAGES_KEY not in session:
        session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if "model" not in session:
        session["model"] = DEFAULT_MODEL

def clear_conversation():
    """Clears the conversation history from the session."""
    session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    session.modified = True  # Ensure session is saved
    return redirect(url_for("chat"))  # Redirect to the chat route

# --- Routes ---
@app.route("/", methods=["GET", "POST"])
def chat():
    initialize_session_state()
    conversation = session[SESSION_MESSAGES_KEY]
    model = session["model"]

    if request.method == "POST":
        user_input = request.form["user_input"]
        conversation.append({"role": "user", "content": user_input})

        reply = get_openai_response(conversation, model)
        conversation.append({"role": "assistant", "content": reply})

        session[SESSION_MESSAGES_KEY] = conversation
        session.modified = True  # Important:  You need to mark the session as modified
        return render_template("chat.html", history=conversation[1:])  # Skip system message

    return render_template("chat.html", history=conversation[1:])  # Skip system message

@app.route("/clear", methods=["POST"])  # New route to handle clearing the chat
def clear_chat():
    return clear_conversation()

if __name__ == "__main__":
    app.run(debug=True)

Analicemos este código de aplicación Flask para un chatbot:

1. Importaciones y Configuración

  • Componentes esenciales de Flask e integración con OpenAI
  • Carga de variables de entorno con python-dotenv
  • Generación de clave secreta para gestión de sesiones

2. Configuración Principal

  • Modelo predeterminado establecido como "gpt-4o"
  • Prompt del sistema que define la personalidad y comportamiento de la IA
  • Gestión de sesiones para persistencia de conversaciones

3. Funciones Auxiliares

  • get_openai_response(): Gestiona la comunicación con la API de OpenAI, incluyendo manejo de errores
  • initialize_session_state(): Configura el estado inicial de la conversación y ajustes del modelo
  • clear_conversation(): Reinicia el historial del chat al estado inicial

4. Rutas

  • Ruta principal ("/"):
    • Maneja solicitudes GET y POST
    • Gestiona el flujo de conversación y el historial de mensajes
    • Renderiza la plantilla del chat con el historial de conversación
  • Ruta de limpieza ("/clear"):
    • Proporciona funcionalidad para reiniciar la conversación

El ejemplo implementa un chatbot robusto que mantiene el historial de conversación mediante sesiones de Flask, maneja eficientemente la comunicación con la API de OpenAI e incluye un manejo integral de errores para garantizar la fiabilidad.

4.2.4 Mejoras Opcionales

Aquí hay algunas funciones avanzadas que puedes implementar para mejorar la funcionalidad y experiencia de usuario de tu chatbot:

Alternador de modo oscuro usando CSS

  • Implementar un selector de tema que cambie el esquema de colores
    • Crear un botón de alternación con animaciones suaves de transición
    • Definir paletas de colores separadas para modos claro y oscuro
  • Usar variables CSS para una gestión fácil del tema
    • Definir variables CSS a nivel raíz para colores, sombras y fondos
    • Implementar una única fuente de verdad para los estilos relacionados con el tema
  • Almacenar preferencias del usuario en almacenamiento local
    • Guardar preferencia de tema usando la API localStorage del navegador
    • Aplicar automáticamente la preferencia guardada al recargar la página
    • Respetar la configuración de modo oscuro del sistema usando la media query prefers-color-scheme

Iconos de avatar para usuario y asistente

  • Añadir distinción visual entre participantes
    • Usar diferentes colores y formas para identificar claramente los mensajes de usuarios versus el asistente IA
    • Incluir señales visuales sutiles como orientación de mensajes (alineación izquierda/derecha)
  • Usar imágenes personalizadas o fotos de perfil predeterminadas
    • Permitir a los usuarios subir sus propias fotos de perfil
    • Proporcionar un conjunto predeterminado de avatares profesionales para usuarios que no suban imágenes personalizadas
    • Generar avatares únicos del asistente IA que reflejen su personalidad
  • Implementar transiciones suaves entre mensajes
    • Añadir animaciones de aparición gradual cuando aparecen nuevos mensajes
    • Incluir indicadores de escritura mientras la IA genera respuestas
    • Usar animaciones sutiles de escala al pasar el cursor sobre los mensajes

Entrada de voz a texto usando APIs del navegador

  • Integrar la API Web Speech para reconocimiento de voz
    • Usar la interfaz SpeechRecognition para capturar entrada de audio
    • Implementar manejo de errores para casos cuando el navegador no soporta reconocimiento de voz
    • Añadir manejo de permisos de micrófono y retroalimentación al usuario
  • Añadir retroalimentación de transcripción en tiempo real
    • Mostrar resultados provisionales mientras el usuario habla
    • Implementar indicadores visuales para el estado de escucha activa
    • Añadir puntuaciones de confianza para precisión de transcripción
  • Manejar soporte para múltiples idiomas
    • Configurar reconocimiento para diferentes idiomas usando etiquetas de idioma BCP 47
    • Permitir a los usuarios cambiar entre idiomas dinámicamente
    • Implementar detección de dialectos y manejo de acentos regionales

Respuestas de voz usando la salida TTS de OpenAI y JavaScript

  • Convertir respuestas del chatbot a voz natural
    • Usar la API Text-to-Speech de OpenAI para generar audio de alta calidad
    • Soportar múltiples idiomas y acentos para usuarios internacionales
    • Manejar preprocesamiento de texto para mejor pronunciación
  • Implementar controles de reproducción
    • Añadir control de reproducir/pausar, velocidad y volumen
    • Incluir barra de progreso para respuestas largas
    • Habilitar atajos de teclado para control rápido
  • Añadir opciones para diferentes voces y velocidades de habla
    • Ofrecer selección de personalidades de voz (casual, profesional, etc.)
    • Permitir velocidad de habla personalizable (0.5x a 2x)
    • Implementar controles de tono de voz y énfasis

En este capítulo, hemos explorado cómo transformar un chatbot básico en una interfaz sofisticada y amigable que ofrece una experiencia verdaderamente interactiva. Esta mejora se puede lograr a través de dos enfoques distintos:

Streamlit: Este framework moderno sobresale en el desarrollo rápido y ofrece numerosas ventajas para construir chatbots:

  • Componentes de interfaz de chat preconfigurados
    • Burbujas de mensajes, campos de entrada y diseños de chat listos para usar
    • Componentes integrados para carga y manejo de archivos
  • Gestión de estado simplificada
    • Manejo automático del estado de sesión y caché
    • Implementación sencilla del historial de conversación
  • Capacidades de prototipado rápido
    • Recarga en vivo para desarrollo veloz
    • API intuitiva para iteración rápida
  • Requisitos mínimos de configuración
    • Posibilidad de aplicaciones en un solo archivo
    • No requiere configuración compleja

Flask: Este micro-framework versátil proporciona a los desarrolladores control total mediante:

  • Control completo sobre la estructura HTML
    • Plantillas personalizadas para control preciso del diseño
    • Libertad para implementar cualquier patrón de diseño
  • Opciones de estilo CSS personalizadas
    • Control total sobre estilos y animaciones
    • Integración con cualquier framework CSS
  • Capacidades avanzadas de enrutamiento
    • Patrones de URL complejos y parámetros
    • Implementación de API RESTful
  • Gestión granular de sesiones
    • Manejo y almacenamiento personalizado de sesiones
    • Control preciso sobre datos de usuario

Hemos implementado varias características clave que transforman este chatbot básico en una aplicación de nivel profesional:

  • Gestión robusta de memoria de conversación
    • Implementa almacenamiento seguro de historial de chat
    • Mantiene el contexto a través de múltiples interacciones
    • Maneja la limpieza y gestión del estado de conversación
  • Visualización intuitiva del historial de chat
    • Clara organización y encadenamiento de mensajes
    • Separación visual distintiva entre respuestas de usuario e IA
    • Indicadores de marca de tiempo y estado de mensajes
  • Animaciones y transiciones fluidas de respuesta
    • Estados de carga durante llamadas a la API
    • Efectos de aparición gradual para nuevos mensajes
    • Desplazamiento suave a los mensajes más recientes
  • Elementos profesionales de diseño UI/UX
    • Esquema de colores y tipografía consistentes
    • Diseño responsivo para todas las pantallas
    • Elementos de interfaz que cumplen con la accesibilidad

Estas mejoras trabajan en conjunto para crear un chatbot que no solo funciona eficientemente sino que también proporciona una experiencia profesional y atractiva que se siente natural y receptiva para los usuarios. Cada característica ha sido implementada cuidadosamente para asegurar un rendimiento óptimo mientras mantiene una experiencia de usuario fluida durante todo el flujo de conversación.

4.2 Creación de Interfaces de Usuario Interactivas

Las interfaces de usuario son el puente entre la inteligencia de tu chatbot y sus usuarios. Una UI bien diseñada puede transformar un sistema de IA capaz en una herramienta atractiva y accesible que los usuarios disfrutan usar. Crear una interfaz efectiva para el chatbot requiere una cuidadosa consideración de los principios de experiencia de usuario, elementos de diseño visual y patrones de interacción.

Esta sección explora el arte y la ciencia de construir interfaces de chatbot intuitivas. Examinaremos tanto la implementación técnica como las consideraciones de diseño que hacen que un chatbot sea verdaderamente fácil de usar. Aprenderás a crear interfaces que no solo se vean profesionales sino que también proporcionen retroalimentación significativa, manejen errores con elegancia y guíen a los usuarios a través de conversaciones naturales.

Ya sea que estés construyendo un bot de servicio al cliente, un asistente virtual o una herramienta de aprendizaje impulsada por IA, los principios y técnicas cubiertos aquí te ayudarán a crear interfaces que mejoren en lugar de obstaculizar la experiencia del usuario. Veremos enfoques de implementación usando tanto Streamlit como Flask, dándote la flexibilidad de elegir las herramientas que mejor se adapten a las necesidades de tu proyecto.

4.2.1 Por qué la UI es Importante en un Chatbot

El éxito de un chatbot depende en gran medida de su interfaz de usuario y experiencia de usuario general. No importa cuán sofisticado sea tu modelo de IA, los usuarios tendrán dificultades para interactuar efectivamente con él si la interfaz es difícil de usar o poco intuitiva. Por eso es crucial crear interfaces bien diseñadas y fáciles de usar. Nos centraremos en construir UIs intuitivas, responsivas y fáciles de usar que no solo se vean profesionales sino que también creen un flujo natural de conversación entre el usuario y la IA.

Nuestro enfoque enfatiza tres aspectos fundamentales del diseño de interfaces que son críticos para crear un chatbot efectivo:

Experiencia de Usuario (UX)

Crear interfaces que sean fáciles de navegar y entender, con jerarquías visuales claras y patrones de interacción intuitivos. Una UX bien diseñada considera varios aspectos clave:

  1. Arquitectura de Información: Organizar el contenido en una estructura lógica y fácil de seguir que coincida con los modelos mentales de los usuarios.
  2. Diseño Visual: Usar esquemas de color, tipografía y espaciado consistentes para crear jerarquías visuales claras que guíen la atención de los usuarios.
  3. Diseño de Interacción: Implementar controles y patrones de navegación intuitivos que se sientan familiares y predecibles para los usuarios.
  4. Mecanismos de Retroalimentación: Proporcionar señales visuales y textuales claras que ayuden a los usuarios a entender:
    • Cuándo su mensaje está siendo procesado
    • Cuándo el chatbot está "pensando"
    • Si ocurre un error
    • Si su entrada fue recibida exitosamente
  5. Gestión de Carga Cognitiva: Minimizar el esfuerzo mental requerido para usar la interfaz mediante:
    • División de tareas complejas en pasos más pequeños
    • Uso de patrones de diseño familiares
    • Proporcionar instrucciones claras cuando sea necesario
    • Mantener un comportamiento consistente en toda la interfaz

Este enfoque reflexivo del diseño UX reduce la fricción, aumenta el compromiso del usuario y hace que el chatbot se sienta natural y sin esfuerzo de usar.

Capacidad de Respuesta

Asegurar que la interfaz proporcione retroalimentación inmediata y mantenga un rendimiento fluido en diferentes dispositivos y tamaños de pantalla. Esto involucra varios aspectos clave:

  1. Optimización del Rendimiento:
    • Implementar estados de carga eficientes que muestren a los usuarios que sus acciones están siendo procesadas
    • Optimizar tiempos de respuesta mediante técnicas como debouncing de solicitudes y caché
    • Usar carga progresiva para el historial de chat para manejar conversaciones grandes
  2. Compatibilidad con Dispositivos:
    • Usar principios de diseño responsivo para asegurar que el chatbot funcione sin problemas en todos los dispositivos
    • Implementar diseños fluidos que se ajusten a diferentes tamaños de pantalla
    • Asegurar elementos de interfaz amigables al tacto para usuarios móviles
    • Probar y optimizar para varios navegadores y plataformas
  3. Elementos UI Adaptativos:
    • Crear burbujas de chat flexibles que cambien de tamaño según el contenido
    • Implementar menús y controles plegables para pantallas más pequeñas
    • Usar unidades relativas (em, rem, vh, vw) en lugar de píxeles fijos
    • Asegurar un correcto ajuste de texto y legibilidad en todos los tamaños

La interfaz debe adaptarse dinámicamente a diferentes tamaños de pantalla mientras mantiene la funcionalidad y el atractivo visual, proporcionando una experiencia consistente ya sea que se acceda desde un smartphone, tablet o computadora de escritorio.

Accesibilidad

Hacer que el chatbot sea utilizable para personas con diferentes capacidades y conocimientos técnicos es crucial para garantizar un acceso inclusivo. Esto implica varias consideraciones clave:

  • Compatibilidad con Lectores de Pantalla
    • Implementación de etiquetas y roles ARIA apropiados para describir elementos de la interfaz
    • Asegurar una estructura de encabezados y navegación significativa
    • Proporcionar alternativas textuales para todo el contenido no textual
  • Navegación por Teclado
    • Soporte del control completo por teclado de todas las funciones
    • Implementación de indicadores visibles de enfoque
    • Creación de un orden lógico de tabulación a través de la interfaz
  • Diseño Visual
    • Mantener ratios de contraste de color suficientes (mínimo 4.5:1)
    • Evitar el uso del color como único medio para transmitir información
    • Permitir el redimensionamiento del texto sin pérdida de funcionalidad
  • Consideraciones Técnicas
    • Seguir los estándares de las Pautas de Accesibilidad para el Contenido Web (WCAG) 2.1 Nivel AA
    • Pruebas regulares con herramientas de accesibilidad y lectores de pantalla
    • Proporcionar alternativas para interacciones complejas

Al implementar estas características de accesibilidad, aseguras que tu chatbot pueda ser utilizado efectivamente por personas con diversas discapacidades, incluyendo impedimentos visuales, auditivos, motores y cognitivos. Esto no solo cumple con los requisitos legales sino que también demuestra un compromiso con los principios de diseño universal.

Para crear una interfaz de chatbot efectiva y fácil de usar, exploraremos estos componentes esenciales en detalle:

  1. Construcción de una Interfaz de Chat Intuitiva
    • Implementación de principios de diseño limpios y modernos que prioricen la legibilidad y el compromiso del usuario
    • Consideración cuidadosa del espaciado para crear espacio visual entre elementos
    • Uso estratégico de la tipografía para establecer una jerarquía clara de información
    • Elementos visuales consistentes que guíen a los usuarios a través del flujo de conversación
  2. Gestión del Historial de Conversación
    • Implementación de sistemas eficientes de almacenamiento y recuperación de registros de chat
    • Integración de funcionalidad de marcas temporales para mejor seguimiento de conversaciones
    • Creación de estilos visuales distintivos para mensajes de usuario y bot
    • Desarrollo de mecánicas de desplazamiento suave para conversaciones más largas
  3. Optimización de la Presentación de Respuestas
    • Selección cuidadosa de fuentes y tamaños de texto para máxima legibilidad
    • Implementación de patrones de espaciado consistentes entre elementos de mensaje
    • Consideraciones especiales de formato para diferentes tipos de contenido (bloques de código, listas, etc.)
    • Integración de indicadores visuales para estado y tipo de mensaje
  4. Implementación de Sistemas Robustos de Retroalimentación
    • Creación de animaciones de carga sutiles pero visibles durante la generación de respuestas
    • Desarrollo de mensajes de error claros que guíen a los usuarios hacia soluciones
    • Implementación de mecanismos de recuperación para escenarios comunes de error
    • Integración de indicadores de estado para mantener a los usuarios informados del estado del sistema

Obtendrás ejemplos completos tanto en Streamlit como en Flask, permitiéndote elegir el framework que mejor se adapte a tu estilo de desarrollo y requisitos del proyecto. Cada ejemplo incluye explicaciones detalladas y mejores prácticas para la implementación.

4.2.2 Interfaz de Chat Interactiva con Streamlit

Este ejemplo demuestra cómo crear un chatbot interactivo usando Streamlit y OpenAI, sobre el cual construiremos más adelante. Usando Streamlit, crearemos una interfaz de chat amigable que mantiene el historial de conversación. Este caso de uso presenta conceptos clave y mejores prácticas para construir un chatbot robusto e interactivo.

Paso 1: Instalar Dependencias

pip install streamlit openai python-dotenv
  • streamlit: Una librería de Python para crear aplicaciones web interactivas.
  • openai: La librería de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una librería para cargar variables de entorno desde un archivo .env.

Paso 2: Crear la Aplicación Streamlit (chatbot.py)

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.

    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.

    Returns:
        str: The assistant's reply, or an error message.

    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

def initialize_session_state():
    """
    Initializes session state variables.  This function should be called
    at the beginning of the main() function.  It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

# --- Main App ---
def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")

    initialize_session_state()  # Initialize session state

    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history) # corrected to clear_chat_history

    # Display chat history, রাখা changed to display_messages
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")

    # User input, রাখা outside the conditional block
    user_input = st.chat_input("Ask me anything...", key="user_input")

    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})

        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model) #added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response

        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})

        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()

if __name__ == "__main__":
    main()

Desglose del Código

Analicemos el código paso a paso.

Importaciones:

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

Importa las bibliotecas necesarias:

  • streamlit: Para crear la interfaz web.
  • openai: Para interactuar con la API de OpenAI.
  • os: Para acceder a las variables de entorno.
  • dotenv: Para cargar variables de entorno desde un archivo .env.
  • time: Para manejar posibles errores de API mediante esperas.
  • typing: Para anotaciones de tipo que mejoran la legibilidad del código.

Variables de Entorno:

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

Carga la clave API de OpenAI desde un archivo .env y la configura para la biblioteca OpenAI.

Constantes:

DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant.  Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
  • DEFAULT_MODEL: El modelo predeterminado de OpenAI utilizado para el chatbot.
  • SYSTEM_PROMPT: El mensaje inicial enviado a la API de OpenAI para establecer el comportamiento del asistente.
  • SESSION_MESSAGES_KEY: Clave para usar en el historial principal de conversación en el estado de la sesión.
  • DISPLAY_MESSAGES_KEY: Clave para usar en el historial de conversación que se muestra en la interfaz de usuario.

Funciones Auxiliares:

  • get_openai_response():
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.
    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.
    Returns:
        str: The assistant's reply, or an error message.
    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

Envía la entrada del usuario a la API de OpenAI y obtiene la respuesta. Esta función también incluye manejo de errores usando un bloque try...except para capturar posibles excepciones openai.error.OpenAIError y una Exception general para otros errores. Se agrega un tiempo límite para evitar que la aplicación se quede colgada indefinidamente.

  • initialize_session_state():
def initialize_session_state():
    """
    Initializes session state variables. This function should be called
    at the beginning of the main() function. It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

Inicializa las variables del estado de la sesión:

  • SESSION_MESSAGES_KEY: Almacena el historial completo de la conversación.
  • DISPLAY_MESSAGES_KEY: Almacena el historial de la conversación que se muestra al usuario.
  • model: El modelo LLM
  • clear_chat_history():
def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

Borra el historial del chat cuando el usuario hace clic en el botón "Borrar Chat".

Aplicación Principal:

def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")
    initialize_session_state()
    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history)
    # Display chat history
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")
    # User input
    user_input = st.chat_input("Ask me anything...", key="user_input")
    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})
        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model)  # added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()
if __name__ == "__main__":
    main()
  • st.set_page_config(page_title="AI Chatbot", page_icon="🤖"): Configura el título y el ícono de la página en la pestaña del navegador.
  • st.title("🤖 GPT-4o Assistant"): Establece el título de la aplicación Streamlit.
  • initialize_session_state(): Inicializa la sesión
  • st.sidebar.header("Settings"): Crea una sección de barra lateral titulada "Settings".
  • model = st.sidebar.selectbox(...): Crea un menú desplegable en la barra lateral para seleccionar el modelo de OpenAI.
  • clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history): Agrega un botón a la barra lateral para borrar el historial del chat.
  • El historial del chat se muestra usando st.chat_message, con diferentes estilos para los mensajes del usuario y del asistente.
  • user_input = st.chat_input("Ask me anything...", key="user_input"): Crea un campo de entrada de texto para que el usuario escriba su consulta. El argumento key es importante para que Streamlit gestione el estado del campo de entrada.
  • La aplicación obtiene la entrada del usuario, la envía a la API de OpenAI usando la función get_openai_response, y muestra la respuesta.
  • El historial de la conversación se almacena en st.session_state.messages como una lista de diccionarios. Cada diccionario tiene un "role" (ya sea "user" o "assistant") y "content".
  • st.rerun() se utiliza para actualizar la pantalla después de que el asistente responde.
  • Ejecutar la aplicación:Para ejecutar la aplicación, guarda el código en un archivo llamado chatbot.py y ejecuta el siguiente comando en tu terminal:
streamlit run chatbot.py

4.2.3 Interfaz de Chat Personalizada con Flask + HTML/CSS

Este ejemplo implementa un chatbot usando Flask y el modelo GPT-4o de OpenAI, con énfasis en permitir que los desarrolladores personalicen la interfaz del chat usando su propio HTML y CSS. Este enfoque proporciona mayor flexibilidad en el diseño y la disposición en comparación con el uso de componentes de interfaz preconfigurados. Este código proporciona un chatbot robusto y personalizable, explicando conceptos clave y mejores prácticas para desarrolladores de nivel intermedio.

Paso 1: Instalar Dependencias

pip install flask openai python-dotenv
  • flask: Un framework web para construir la aplicación del chatbot.
  • openai: La biblioteca de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una biblioteca para cargar variables de entorno desde un archivo .env.

Paso 2: Plantilla Actualizada de Flask (templates/chat.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GPT-4o Chat Assistant</title>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
  <style>
    /* --- General Styles --- */
    body {
      font-family: 'Inter', sans-serif;  /* Modern font */
      background-color: #f3f4f6;  /* Tailwind's gray-100 */
      padding: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      color: #1f2937;  /* Tailwind's gray-800 */
    }
    .container {
      max-width: 800px;  /* Increased max-width */
      width: 100%;
      background-color: #fff; /* White background */
      padding: 30px;
      border-radius: 0.75rem;  /* Tailwind's rounded-lg */
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);  /* Tailwind's shadow-md */
    }
    h2 {
      font-size: 1.875rem; /* Tailwind's text-2xl */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 2rem;  /* Tailwind's mb-8 */
      color: #1e293b; /* Tailwind's gray-900 */
      text-align: center;
    }
    /* --- Message Styles --- */
    .message {
      margin-bottom: 1.5rem;  /* Tailwind's mb-6 */
      display: flex;
      flex-direction: column;
    }
    .message p {
      padding: 1rem;  /* Tailwind's p-4 */
      border-radius: 1rem;  /* Tailwind's rounded-lg */
      max-width: 80%; /* Limit message width */
    }
    .user p {
      background-color: #e0f2fe;  /* Tailwind's bg-blue-100 */
      color: #1d4ed8;  /* Tailwind's text-blue-700 */
      margin-left: auto; /* Push user message to the right */
    }
    .assistant p {
      background-color: #f0fdf4;  /* Tailwind's bg-green-100 */
      color: #15803d;  /* Tailwind's text-green-700 */
    }
    .message strong {
      font-size: 0.875rem; /* Tailwind's text-sm */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
    }
    .user strong {
        color: #1e40af; /* Tailwind's text-blue-800 */
    }
    .assistant strong {
        color: #16a34a; /* Tailwind's text-green-800 */
    }

    /* --- Form Styles --- */
    form {
      margin-top: 2rem;  /* Tailwind's mt-8 */
      display: flex;
      flex-direction: column;
      gap: 0.5rem; /* Tailwind's gap-2 */
    }
    textarea {
      width: 100%;
      padding: 0.75rem;  /* Tailwind's p-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      border: 1px solid #d1d5db;  /* Tailwind's border-gray-300 */
      resize: none;
      font-size: 1rem;  /* Tailwind's text-base */
      line-height: 1.5rem;  /* Tailwind's leading-relaxed */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
      box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow, more subtle */
    }
    textarea:focus {
      outline: none;
      border-color: #3b82f6;  /* Tailwind's border-blue-500 */
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);  /* Tailwind's ring-blue-500 with opacity */
    }
    input[type="submit"] {
      padding: 0.75rem 1.5rem;  /* Tailwind's px-6 py-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      background-color: #3b82f6;  /* Tailwind's bg-blue-500 */
      color: #fff;  /* White text */
      font-size: 1rem;  /* Tailwind's text-base */
      font-weight: 600;  /* Tailwind's font-semibold */
      cursor: pointer;
      transition: background-color 0.3s ease;  /* Smooth transition */
      border: none;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);  /* Tailwind's shadow-sm */
    }
    input[type="submit"]:hover {
      background-color: #2563eb;  /* Tailwind's bg-blue-700 on hover */
    }
    input[type="submit"]:focus {
      outline: none;
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);  /* Tailwind's ring-blue-500 with more opacity*/
    }

    /* --- Responsive Adjustments --- */
    @media (max-width: 768px) {  /* Medium screens and below (md breakpoint in Tailwind is 768px) */
      .container {
        padding: 20px;
      }
      textarea {
        height: 100px;  /* Make textarea taller on smaller screens */
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>🧠 GPT-4o Chat Assistant</h2>
    {% for msg in history %}
      <div class="message {{ msg.role }}">
        <p><strong>{{ msg.role.capitalize() }}:</strong> {{ msg.content }}</p>
      </div>
    {% endfor %}
    <form method="post">
      <textarea name="user_input" placeholder="Type your message..."></textarea><br>
      <input type="submit" value="Send Message">
    </form>
  </div>
</body>
</html>

Plantilla HTML:

  • Diseño Moderno: La plantilla presenta un enfoque de diseño contemporáneo inspirado en Tailwind CSS. Esto incluye:
    • Fuente limpia (Inter)
    • Espaciado y márgenes amplios
    • Esquinas redondeadas
    • Sombras sutiles
    • Paleta de colores consistente
  • Diseño Responsivo: Se agregó una media query para ajustar el diseño en pantallas más pequeñas (tabletas y teléfonos).
  • Formulario Mejorado: El formulario está estilizado con un estado de enfoque, mejores márgenes y un efecto suave al pasar el cursor.
  • HTML Semántico: Utiliza lang="en" en la etiqueta &lt;html&gt; para mejor accesibilidad.
  • Comentarios: Se agregaron comentarios para explicar el CSS, relacionándolo con Tailwind CSS cuando corresponde, para facilitar la comprensión.

Paso 3: Backend Flask Actualizado (app.py)

from flask import Flask, request, render_template, session, redirect, url_for
import openai
import os
from dotenv import load_dotenv
import time
from typing import List, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)
app.secret_key = os.urandom(24)  # Required for session management

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "conversation"  # Consistent key for session

# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors.
    Args:
        messages: A list of message dictionaries.
        model: The OpenAI model to use.
    Returns:
        The assistant's reply, or an error message.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        # Log the error for debugging
        print(f"OpenAI API error: {e}")
        return f"Sorry, there was an error communicating with the AI: {e}"
    except Exception as e:
        print(f"Unexpected error: {e}")
        return "Sorry, an unexpected error occurred."

def initialize_session_state():
    """Initializes session state."""
    if SESSION_MESSAGES_KEY not in session:
        session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if "model" not in session:
        session["model"] = DEFAULT_MODEL

def clear_conversation():
    """Clears the conversation history from the session."""
    session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    session.modified = True  # Ensure session is saved
    return redirect(url_for("chat"))  # Redirect to the chat route

# --- Routes ---
@app.route("/", methods=["GET", "POST"])
def chat():
    initialize_session_state()
    conversation = session[SESSION_MESSAGES_KEY]
    model = session["model"]

    if request.method == "POST":
        user_input = request.form["user_input"]
        conversation.append({"role": "user", "content": user_input})

        reply = get_openai_response(conversation, model)
        conversation.append({"role": "assistant", "content": reply})

        session[SESSION_MESSAGES_KEY] = conversation
        session.modified = True  # Important:  You need to mark the session as modified
        return render_template("chat.html", history=conversation[1:])  # Skip system message

    return render_template("chat.html", history=conversation[1:])  # Skip system message

@app.route("/clear", methods=["POST"])  # New route to handle clearing the chat
def clear_chat():
    return clear_conversation()

if __name__ == "__main__":
    app.run(debug=True)

Analicemos este código de aplicación Flask para un chatbot:

1. Importaciones y Configuración

  • Componentes esenciales de Flask e integración con OpenAI
  • Carga de variables de entorno con python-dotenv
  • Generación de clave secreta para gestión de sesiones

2. Configuración Principal

  • Modelo predeterminado establecido como "gpt-4o"
  • Prompt del sistema que define la personalidad y comportamiento de la IA
  • Gestión de sesiones para persistencia de conversaciones

3. Funciones Auxiliares

  • get_openai_response(): Gestiona la comunicación con la API de OpenAI, incluyendo manejo de errores
  • initialize_session_state(): Configura el estado inicial de la conversación y ajustes del modelo
  • clear_conversation(): Reinicia el historial del chat al estado inicial

4. Rutas

  • Ruta principal ("/"):
    • Maneja solicitudes GET y POST
    • Gestiona el flujo de conversación y el historial de mensajes
    • Renderiza la plantilla del chat con el historial de conversación
  • Ruta de limpieza ("/clear"):
    • Proporciona funcionalidad para reiniciar la conversación

El ejemplo implementa un chatbot robusto que mantiene el historial de conversación mediante sesiones de Flask, maneja eficientemente la comunicación con la API de OpenAI e incluye un manejo integral de errores para garantizar la fiabilidad.

4.2.4 Mejoras Opcionales

Aquí hay algunas funciones avanzadas que puedes implementar para mejorar la funcionalidad y experiencia de usuario de tu chatbot:

Alternador de modo oscuro usando CSS

  • Implementar un selector de tema que cambie el esquema de colores
    • Crear un botón de alternación con animaciones suaves de transición
    • Definir paletas de colores separadas para modos claro y oscuro
  • Usar variables CSS para una gestión fácil del tema
    • Definir variables CSS a nivel raíz para colores, sombras y fondos
    • Implementar una única fuente de verdad para los estilos relacionados con el tema
  • Almacenar preferencias del usuario en almacenamiento local
    • Guardar preferencia de tema usando la API localStorage del navegador
    • Aplicar automáticamente la preferencia guardada al recargar la página
    • Respetar la configuración de modo oscuro del sistema usando la media query prefers-color-scheme

Iconos de avatar para usuario y asistente

  • Añadir distinción visual entre participantes
    • Usar diferentes colores y formas para identificar claramente los mensajes de usuarios versus el asistente IA
    • Incluir señales visuales sutiles como orientación de mensajes (alineación izquierda/derecha)
  • Usar imágenes personalizadas o fotos de perfil predeterminadas
    • Permitir a los usuarios subir sus propias fotos de perfil
    • Proporcionar un conjunto predeterminado de avatares profesionales para usuarios que no suban imágenes personalizadas
    • Generar avatares únicos del asistente IA que reflejen su personalidad
  • Implementar transiciones suaves entre mensajes
    • Añadir animaciones de aparición gradual cuando aparecen nuevos mensajes
    • Incluir indicadores de escritura mientras la IA genera respuestas
    • Usar animaciones sutiles de escala al pasar el cursor sobre los mensajes

Entrada de voz a texto usando APIs del navegador

  • Integrar la API Web Speech para reconocimiento de voz
    • Usar la interfaz SpeechRecognition para capturar entrada de audio
    • Implementar manejo de errores para casos cuando el navegador no soporta reconocimiento de voz
    • Añadir manejo de permisos de micrófono y retroalimentación al usuario
  • Añadir retroalimentación de transcripción en tiempo real
    • Mostrar resultados provisionales mientras el usuario habla
    • Implementar indicadores visuales para el estado de escucha activa
    • Añadir puntuaciones de confianza para precisión de transcripción
  • Manejar soporte para múltiples idiomas
    • Configurar reconocimiento para diferentes idiomas usando etiquetas de idioma BCP 47
    • Permitir a los usuarios cambiar entre idiomas dinámicamente
    • Implementar detección de dialectos y manejo de acentos regionales

Respuestas de voz usando la salida TTS de OpenAI y JavaScript

  • Convertir respuestas del chatbot a voz natural
    • Usar la API Text-to-Speech de OpenAI para generar audio de alta calidad
    • Soportar múltiples idiomas y acentos para usuarios internacionales
    • Manejar preprocesamiento de texto para mejor pronunciación
  • Implementar controles de reproducción
    • Añadir control de reproducir/pausar, velocidad y volumen
    • Incluir barra de progreso para respuestas largas
    • Habilitar atajos de teclado para control rápido
  • Añadir opciones para diferentes voces y velocidades de habla
    • Ofrecer selección de personalidades de voz (casual, profesional, etc.)
    • Permitir velocidad de habla personalizable (0.5x a 2x)
    • Implementar controles de tono de voz y énfasis

En este capítulo, hemos explorado cómo transformar un chatbot básico en una interfaz sofisticada y amigable que ofrece una experiencia verdaderamente interactiva. Esta mejora se puede lograr a través de dos enfoques distintos:

Streamlit: Este framework moderno sobresale en el desarrollo rápido y ofrece numerosas ventajas para construir chatbots:

  • Componentes de interfaz de chat preconfigurados
    • Burbujas de mensajes, campos de entrada y diseños de chat listos para usar
    • Componentes integrados para carga y manejo de archivos
  • Gestión de estado simplificada
    • Manejo automático del estado de sesión y caché
    • Implementación sencilla del historial de conversación
  • Capacidades de prototipado rápido
    • Recarga en vivo para desarrollo veloz
    • API intuitiva para iteración rápida
  • Requisitos mínimos de configuración
    • Posibilidad de aplicaciones en un solo archivo
    • No requiere configuración compleja

Flask: Este micro-framework versátil proporciona a los desarrolladores control total mediante:

  • Control completo sobre la estructura HTML
    • Plantillas personalizadas para control preciso del diseño
    • Libertad para implementar cualquier patrón de diseño
  • Opciones de estilo CSS personalizadas
    • Control total sobre estilos y animaciones
    • Integración con cualquier framework CSS
  • Capacidades avanzadas de enrutamiento
    • Patrones de URL complejos y parámetros
    • Implementación de API RESTful
  • Gestión granular de sesiones
    • Manejo y almacenamiento personalizado de sesiones
    • Control preciso sobre datos de usuario

Hemos implementado varias características clave que transforman este chatbot básico en una aplicación de nivel profesional:

  • Gestión robusta de memoria de conversación
    • Implementa almacenamiento seguro de historial de chat
    • Mantiene el contexto a través de múltiples interacciones
    • Maneja la limpieza y gestión del estado de conversación
  • Visualización intuitiva del historial de chat
    • Clara organización y encadenamiento de mensajes
    • Separación visual distintiva entre respuestas de usuario e IA
    • Indicadores de marca de tiempo y estado de mensajes
  • Animaciones y transiciones fluidas de respuesta
    • Estados de carga durante llamadas a la API
    • Efectos de aparición gradual para nuevos mensajes
    • Desplazamiento suave a los mensajes más recientes
  • Elementos profesionales de diseño UI/UX
    • Esquema de colores y tipografía consistentes
    • Diseño responsivo para todas las pantallas
    • Elementos de interfaz que cumplen con la accesibilidad

Estas mejoras trabajan en conjunto para crear un chatbot que no solo funciona eficientemente sino que también proporciona una experiencia profesional y atractiva que se siente natural y receptiva para los usuarios. Cada característica ha sido implementada cuidadosamente para asegurar un rendimiento óptimo mientras mantiene una experiencia de usuario fluida durante todo el flujo de conversación.

4.2 Creación de Interfaces de Usuario Interactivas

Las interfaces de usuario son el puente entre la inteligencia de tu chatbot y sus usuarios. Una UI bien diseñada puede transformar un sistema de IA capaz en una herramienta atractiva y accesible que los usuarios disfrutan usar. Crear una interfaz efectiva para el chatbot requiere una cuidadosa consideración de los principios de experiencia de usuario, elementos de diseño visual y patrones de interacción.

Esta sección explora el arte y la ciencia de construir interfaces de chatbot intuitivas. Examinaremos tanto la implementación técnica como las consideraciones de diseño que hacen que un chatbot sea verdaderamente fácil de usar. Aprenderás a crear interfaces que no solo se vean profesionales sino que también proporcionen retroalimentación significativa, manejen errores con elegancia y guíen a los usuarios a través de conversaciones naturales.

Ya sea que estés construyendo un bot de servicio al cliente, un asistente virtual o una herramienta de aprendizaje impulsada por IA, los principios y técnicas cubiertos aquí te ayudarán a crear interfaces que mejoren en lugar de obstaculizar la experiencia del usuario. Veremos enfoques de implementación usando tanto Streamlit como Flask, dándote la flexibilidad de elegir las herramientas que mejor se adapten a las necesidades de tu proyecto.

4.2.1 Por qué la UI es Importante en un Chatbot

El éxito de un chatbot depende en gran medida de su interfaz de usuario y experiencia de usuario general. No importa cuán sofisticado sea tu modelo de IA, los usuarios tendrán dificultades para interactuar efectivamente con él si la interfaz es difícil de usar o poco intuitiva. Por eso es crucial crear interfaces bien diseñadas y fáciles de usar. Nos centraremos en construir UIs intuitivas, responsivas y fáciles de usar que no solo se vean profesionales sino que también creen un flujo natural de conversación entre el usuario y la IA.

Nuestro enfoque enfatiza tres aspectos fundamentales del diseño de interfaces que son críticos para crear un chatbot efectivo:

Experiencia de Usuario (UX)

Crear interfaces que sean fáciles de navegar y entender, con jerarquías visuales claras y patrones de interacción intuitivos. Una UX bien diseñada considera varios aspectos clave:

  1. Arquitectura de Información: Organizar el contenido en una estructura lógica y fácil de seguir que coincida con los modelos mentales de los usuarios.
  2. Diseño Visual: Usar esquemas de color, tipografía y espaciado consistentes para crear jerarquías visuales claras que guíen la atención de los usuarios.
  3. Diseño de Interacción: Implementar controles y patrones de navegación intuitivos que se sientan familiares y predecibles para los usuarios.
  4. Mecanismos de Retroalimentación: Proporcionar señales visuales y textuales claras que ayuden a los usuarios a entender:
    • Cuándo su mensaje está siendo procesado
    • Cuándo el chatbot está "pensando"
    • Si ocurre un error
    • Si su entrada fue recibida exitosamente
  5. Gestión de Carga Cognitiva: Minimizar el esfuerzo mental requerido para usar la interfaz mediante:
    • División de tareas complejas en pasos más pequeños
    • Uso de patrones de diseño familiares
    • Proporcionar instrucciones claras cuando sea necesario
    • Mantener un comportamiento consistente en toda la interfaz

Este enfoque reflexivo del diseño UX reduce la fricción, aumenta el compromiso del usuario y hace que el chatbot se sienta natural y sin esfuerzo de usar.

Capacidad de Respuesta

Asegurar que la interfaz proporcione retroalimentación inmediata y mantenga un rendimiento fluido en diferentes dispositivos y tamaños de pantalla. Esto involucra varios aspectos clave:

  1. Optimización del Rendimiento:
    • Implementar estados de carga eficientes que muestren a los usuarios que sus acciones están siendo procesadas
    • Optimizar tiempos de respuesta mediante técnicas como debouncing de solicitudes y caché
    • Usar carga progresiva para el historial de chat para manejar conversaciones grandes
  2. Compatibilidad con Dispositivos:
    • Usar principios de diseño responsivo para asegurar que el chatbot funcione sin problemas en todos los dispositivos
    • Implementar diseños fluidos que se ajusten a diferentes tamaños de pantalla
    • Asegurar elementos de interfaz amigables al tacto para usuarios móviles
    • Probar y optimizar para varios navegadores y plataformas
  3. Elementos UI Adaptativos:
    • Crear burbujas de chat flexibles que cambien de tamaño según el contenido
    • Implementar menús y controles plegables para pantallas más pequeñas
    • Usar unidades relativas (em, rem, vh, vw) en lugar de píxeles fijos
    • Asegurar un correcto ajuste de texto y legibilidad en todos los tamaños

La interfaz debe adaptarse dinámicamente a diferentes tamaños de pantalla mientras mantiene la funcionalidad y el atractivo visual, proporcionando una experiencia consistente ya sea que se acceda desde un smartphone, tablet o computadora de escritorio.

Accesibilidad

Hacer que el chatbot sea utilizable para personas con diferentes capacidades y conocimientos técnicos es crucial para garantizar un acceso inclusivo. Esto implica varias consideraciones clave:

  • Compatibilidad con Lectores de Pantalla
    • Implementación de etiquetas y roles ARIA apropiados para describir elementos de la interfaz
    • Asegurar una estructura de encabezados y navegación significativa
    • Proporcionar alternativas textuales para todo el contenido no textual
  • Navegación por Teclado
    • Soporte del control completo por teclado de todas las funciones
    • Implementación de indicadores visibles de enfoque
    • Creación de un orden lógico de tabulación a través de la interfaz
  • Diseño Visual
    • Mantener ratios de contraste de color suficientes (mínimo 4.5:1)
    • Evitar el uso del color como único medio para transmitir información
    • Permitir el redimensionamiento del texto sin pérdida de funcionalidad
  • Consideraciones Técnicas
    • Seguir los estándares de las Pautas de Accesibilidad para el Contenido Web (WCAG) 2.1 Nivel AA
    • Pruebas regulares con herramientas de accesibilidad y lectores de pantalla
    • Proporcionar alternativas para interacciones complejas

Al implementar estas características de accesibilidad, aseguras que tu chatbot pueda ser utilizado efectivamente por personas con diversas discapacidades, incluyendo impedimentos visuales, auditivos, motores y cognitivos. Esto no solo cumple con los requisitos legales sino que también demuestra un compromiso con los principios de diseño universal.

Para crear una interfaz de chatbot efectiva y fácil de usar, exploraremos estos componentes esenciales en detalle:

  1. Construcción de una Interfaz de Chat Intuitiva
    • Implementación de principios de diseño limpios y modernos que prioricen la legibilidad y el compromiso del usuario
    • Consideración cuidadosa del espaciado para crear espacio visual entre elementos
    • Uso estratégico de la tipografía para establecer una jerarquía clara de información
    • Elementos visuales consistentes que guíen a los usuarios a través del flujo de conversación
  2. Gestión del Historial de Conversación
    • Implementación de sistemas eficientes de almacenamiento y recuperación de registros de chat
    • Integración de funcionalidad de marcas temporales para mejor seguimiento de conversaciones
    • Creación de estilos visuales distintivos para mensajes de usuario y bot
    • Desarrollo de mecánicas de desplazamiento suave para conversaciones más largas
  3. Optimización de la Presentación de Respuestas
    • Selección cuidadosa de fuentes y tamaños de texto para máxima legibilidad
    • Implementación de patrones de espaciado consistentes entre elementos de mensaje
    • Consideraciones especiales de formato para diferentes tipos de contenido (bloques de código, listas, etc.)
    • Integración de indicadores visuales para estado y tipo de mensaje
  4. Implementación de Sistemas Robustos de Retroalimentación
    • Creación de animaciones de carga sutiles pero visibles durante la generación de respuestas
    • Desarrollo de mensajes de error claros que guíen a los usuarios hacia soluciones
    • Implementación de mecanismos de recuperación para escenarios comunes de error
    • Integración de indicadores de estado para mantener a los usuarios informados del estado del sistema

Obtendrás ejemplos completos tanto en Streamlit como en Flask, permitiéndote elegir el framework que mejor se adapte a tu estilo de desarrollo y requisitos del proyecto. Cada ejemplo incluye explicaciones detalladas y mejores prácticas para la implementación.

4.2.2 Interfaz de Chat Interactiva con Streamlit

Este ejemplo demuestra cómo crear un chatbot interactivo usando Streamlit y OpenAI, sobre el cual construiremos más adelante. Usando Streamlit, crearemos una interfaz de chat amigable que mantiene el historial de conversación. Este caso de uso presenta conceptos clave y mejores prácticas para construir un chatbot robusto e interactivo.

Paso 1: Instalar Dependencias

pip install streamlit openai python-dotenv
  • streamlit: Una librería de Python para crear aplicaciones web interactivas.
  • openai: La librería de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una librería para cargar variables de entorno desde un archivo .env.

Paso 2: Crear la Aplicación Streamlit (chatbot.py)

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.

    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.

    Returns:
        str: The assistant's reply, or an error message.

    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

def initialize_session_state():
    """
    Initializes session state variables.  This function should be called
    at the beginning of the main() function.  It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

# --- Main App ---
def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")

    initialize_session_state()  # Initialize session state

    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history) # corrected to clear_chat_history

    # Display chat history, রাখা changed to display_messages
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")

    # User input, রাখা outside the conditional block
    user_input = st.chat_input("Ask me anything...", key="user_input")

    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})

        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model) #added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response

        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})

        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()

if __name__ == "__main__":
    main()

Desglose del Código

Analicemos el código paso a paso.

Importaciones:

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

Importa las bibliotecas necesarias:

  • streamlit: Para crear la interfaz web.
  • openai: Para interactuar con la API de OpenAI.
  • os: Para acceder a las variables de entorno.
  • dotenv: Para cargar variables de entorno desde un archivo .env.
  • time: Para manejar posibles errores de API mediante esperas.
  • typing: Para anotaciones de tipo que mejoran la legibilidad del código.

Variables de Entorno:

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

Carga la clave API de OpenAI desde un archivo .env y la configura para la biblioteca OpenAI.

Constantes:

DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant.  Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
  • DEFAULT_MODEL: El modelo predeterminado de OpenAI utilizado para el chatbot.
  • SYSTEM_PROMPT: El mensaje inicial enviado a la API de OpenAI para establecer el comportamiento del asistente.
  • SESSION_MESSAGES_KEY: Clave para usar en el historial principal de conversación en el estado de la sesión.
  • DISPLAY_MESSAGES_KEY: Clave para usar en el historial de conversación que se muestra en la interfaz de usuario.

Funciones Auxiliares:

  • get_openai_response():
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.
    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.
    Returns:
        str: The assistant's reply, or an error message.
    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

Envía la entrada del usuario a la API de OpenAI y obtiene la respuesta. Esta función también incluye manejo de errores usando un bloque try...except para capturar posibles excepciones openai.error.OpenAIError y una Exception general para otros errores. Se agrega un tiempo límite para evitar que la aplicación se quede colgada indefinidamente.

  • initialize_session_state():
def initialize_session_state():
    """
    Initializes session state variables. This function should be called
    at the beginning of the main() function. It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

Inicializa las variables del estado de la sesión:

  • SESSION_MESSAGES_KEY: Almacena el historial completo de la conversación.
  • DISPLAY_MESSAGES_KEY: Almacena el historial de la conversación que se muestra al usuario.
  • model: El modelo LLM
  • clear_chat_history():
def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

Borra el historial del chat cuando el usuario hace clic en el botón "Borrar Chat".

Aplicación Principal:

def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")
    initialize_session_state()
    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history)
    # Display chat history
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")
    # User input
    user_input = st.chat_input("Ask me anything...", key="user_input")
    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})
        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model)  # added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()
if __name__ == "__main__":
    main()
  • st.set_page_config(page_title="AI Chatbot", page_icon="🤖"): Configura el título y el ícono de la página en la pestaña del navegador.
  • st.title("🤖 GPT-4o Assistant"): Establece el título de la aplicación Streamlit.
  • initialize_session_state(): Inicializa la sesión
  • st.sidebar.header("Settings"): Crea una sección de barra lateral titulada "Settings".
  • model = st.sidebar.selectbox(...): Crea un menú desplegable en la barra lateral para seleccionar el modelo de OpenAI.
  • clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history): Agrega un botón a la barra lateral para borrar el historial del chat.
  • El historial del chat se muestra usando st.chat_message, con diferentes estilos para los mensajes del usuario y del asistente.
  • user_input = st.chat_input("Ask me anything...", key="user_input"): Crea un campo de entrada de texto para que el usuario escriba su consulta. El argumento key es importante para que Streamlit gestione el estado del campo de entrada.
  • La aplicación obtiene la entrada del usuario, la envía a la API de OpenAI usando la función get_openai_response, y muestra la respuesta.
  • El historial de la conversación se almacena en st.session_state.messages como una lista de diccionarios. Cada diccionario tiene un "role" (ya sea "user" o "assistant") y "content".
  • st.rerun() se utiliza para actualizar la pantalla después de que el asistente responde.
  • Ejecutar la aplicación:Para ejecutar la aplicación, guarda el código en un archivo llamado chatbot.py y ejecuta el siguiente comando en tu terminal:
streamlit run chatbot.py

4.2.3 Interfaz de Chat Personalizada con Flask + HTML/CSS

Este ejemplo implementa un chatbot usando Flask y el modelo GPT-4o de OpenAI, con énfasis en permitir que los desarrolladores personalicen la interfaz del chat usando su propio HTML y CSS. Este enfoque proporciona mayor flexibilidad en el diseño y la disposición en comparación con el uso de componentes de interfaz preconfigurados. Este código proporciona un chatbot robusto y personalizable, explicando conceptos clave y mejores prácticas para desarrolladores de nivel intermedio.

Paso 1: Instalar Dependencias

pip install flask openai python-dotenv
  • flask: Un framework web para construir la aplicación del chatbot.
  • openai: La biblioteca de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una biblioteca para cargar variables de entorno desde un archivo .env.

Paso 2: Plantilla Actualizada de Flask (templates/chat.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GPT-4o Chat Assistant</title>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
  <style>
    /* --- General Styles --- */
    body {
      font-family: 'Inter', sans-serif;  /* Modern font */
      background-color: #f3f4f6;  /* Tailwind's gray-100 */
      padding: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      color: #1f2937;  /* Tailwind's gray-800 */
    }
    .container {
      max-width: 800px;  /* Increased max-width */
      width: 100%;
      background-color: #fff; /* White background */
      padding: 30px;
      border-radius: 0.75rem;  /* Tailwind's rounded-lg */
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);  /* Tailwind's shadow-md */
    }
    h2 {
      font-size: 1.875rem; /* Tailwind's text-2xl */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 2rem;  /* Tailwind's mb-8 */
      color: #1e293b; /* Tailwind's gray-900 */
      text-align: center;
    }
    /* --- Message Styles --- */
    .message {
      margin-bottom: 1.5rem;  /* Tailwind's mb-6 */
      display: flex;
      flex-direction: column;
    }
    .message p {
      padding: 1rem;  /* Tailwind's p-4 */
      border-radius: 1rem;  /* Tailwind's rounded-lg */
      max-width: 80%; /* Limit message width */
    }
    .user p {
      background-color: #e0f2fe;  /* Tailwind's bg-blue-100 */
      color: #1d4ed8;  /* Tailwind's text-blue-700 */
      margin-left: auto; /* Push user message to the right */
    }
    .assistant p {
      background-color: #f0fdf4;  /* Tailwind's bg-green-100 */
      color: #15803d;  /* Tailwind's text-green-700 */
    }
    .message strong {
      font-size: 0.875rem; /* Tailwind's text-sm */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
    }
    .user strong {
        color: #1e40af; /* Tailwind's text-blue-800 */
    }
    .assistant strong {
        color: #16a34a; /* Tailwind's text-green-800 */
    }

    /* --- Form Styles --- */
    form {
      margin-top: 2rem;  /* Tailwind's mt-8 */
      display: flex;
      flex-direction: column;
      gap: 0.5rem; /* Tailwind's gap-2 */
    }
    textarea {
      width: 100%;
      padding: 0.75rem;  /* Tailwind's p-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      border: 1px solid #d1d5db;  /* Tailwind's border-gray-300 */
      resize: none;
      font-size: 1rem;  /* Tailwind's text-base */
      line-height: 1.5rem;  /* Tailwind's leading-relaxed */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
      box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow, more subtle */
    }
    textarea:focus {
      outline: none;
      border-color: #3b82f6;  /* Tailwind's border-blue-500 */
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);  /* Tailwind's ring-blue-500 with opacity */
    }
    input[type="submit"] {
      padding: 0.75rem 1.5rem;  /* Tailwind's px-6 py-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      background-color: #3b82f6;  /* Tailwind's bg-blue-500 */
      color: #fff;  /* White text */
      font-size: 1rem;  /* Tailwind's text-base */
      font-weight: 600;  /* Tailwind's font-semibold */
      cursor: pointer;
      transition: background-color 0.3s ease;  /* Smooth transition */
      border: none;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);  /* Tailwind's shadow-sm */
    }
    input[type="submit"]:hover {
      background-color: #2563eb;  /* Tailwind's bg-blue-700 on hover */
    }
    input[type="submit"]:focus {
      outline: none;
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);  /* Tailwind's ring-blue-500 with more opacity*/
    }

    /* --- Responsive Adjustments --- */
    @media (max-width: 768px) {  /* Medium screens and below (md breakpoint in Tailwind is 768px) */
      .container {
        padding: 20px;
      }
      textarea {
        height: 100px;  /* Make textarea taller on smaller screens */
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>🧠 GPT-4o Chat Assistant</h2>
    {% for msg in history %}
      <div class="message {{ msg.role }}">
        <p><strong>{{ msg.role.capitalize() }}:</strong> {{ msg.content }}</p>
      </div>
    {% endfor %}
    <form method="post">
      <textarea name="user_input" placeholder="Type your message..."></textarea><br>
      <input type="submit" value="Send Message">
    </form>
  </div>
</body>
</html>

Plantilla HTML:

  • Diseño Moderno: La plantilla presenta un enfoque de diseño contemporáneo inspirado en Tailwind CSS. Esto incluye:
    • Fuente limpia (Inter)
    • Espaciado y márgenes amplios
    • Esquinas redondeadas
    • Sombras sutiles
    • Paleta de colores consistente
  • Diseño Responsivo: Se agregó una media query para ajustar el diseño en pantallas más pequeñas (tabletas y teléfonos).
  • Formulario Mejorado: El formulario está estilizado con un estado de enfoque, mejores márgenes y un efecto suave al pasar el cursor.
  • HTML Semántico: Utiliza lang="en" en la etiqueta &lt;html&gt; para mejor accesibilidad.
  • Comentarios: Se agregaron comentarios para explicar el CSS, relacionándolo con Tailwind CSS cuando corresponde, para facilitar la comprensión.

Paso 3: Backend Flask Actualizado (app.py)

from flask import Flask, request, render_template, session, redirect, url_for
import openai
import os
from dotenv import load_dotenv
import time
from typing import List, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)
app.secret_key = os.urandom(24)  # Required for session management

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "conversation"  # Consistent key for session

# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors.
    Args:
        messages: A list of message dictionaries.
        model: The OpenAI model to use.
    Returns:
        The assistant's reply, or an error message.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        # Log the error for debugging
        print(f"OpenAI API error: {e}")
        return f"Sorry, there was an error communicating with the AI: {e}"
    except Exception as e:
        print(f"Unexpected error: {e}")
        return "Sorry, an unexpected error occurred."

def initialize_session_state():
    """Initializes session state."""
    if SESSION_MESSAGES_KEY not in session:
        session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if "model" not in session:
        session["model"] = DEFAULT_MODEL

def clear_conversation():
    """Clears the conversation history from the session."""
    session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    session.modified = True  # Ensure session is saved
    return redirect(url_for("chat"))  # Redirect to the chat route

# --- Routes ---
@app.route("/", methods=["GET", "POST"])
def chat():
    initialize_session_state()
    conversation = session[SESSION_MESSAGES_KEY]
    model = session["model"]

    if request.method == "POST":
        user_input = request.form["user_input"]
        conversation.append({"role": "user", "content": user_input})

        reply = get_openai_response(conversation, model)
        conversation.append({"role": "assistant", "content": reply})

        session[SESSION_MESSAGES_KEY] = conversation
        session.modified = True  # Important:  You need to mark the session as modified
        return render_template("chat.html", history=conversation[1:])  # Skip system message

    return render_template("chat.html", history=conversation[1:])  # Skip system message

@app.route("/clear", methods=["POST"])  # New route to handle clearing the chat
def clear_chat():
    return clear_conversation()

if __name__ == "__main__":
    app.run(debug=True)

Analicemos este código de aplicación Flask para un chatbot:

1. Importaciones y Configuración

  • Componentes esenciales de Flask e integración con OpenAI
  • Carga de variables de entorno con python-dotenv
  • Generación de clave secreta para gestión de sesiones

2. Configuración Principal

  • Modelo predeterminado establecido como "gpt-4o"
  • Prompt del sistema que define la personalidad y comportamiento de la IA
  • Gestión de sesiones para persistencia de conversaciones

3. Funciones Auxiliares

  • get_openai_response(): Gestiona la comunicación con la API de OpenAI, incluyendo manejo de errores
  • initialize_session_state(): Configura el estado inicial de la conversación y ajustes del modelo
  • clear_conversation(): Reinicia el historial del chat al estado inicial

4. Rutas

  • Ruta principal ("/"):
    • Maneja solicitudes GET y POST
    • Gestiona el flujo de conversación y el historial de mensajes
    • Renderiza la plantilla del chat con el historial de conversación
  • Ruta de limpieza ("/clear"):
    • Proporciona funcionalidad para reiniciar la conversación

El ejemplo implementa un chatbot robusto que mantiene el historial de conversación mediante sesiones de Flask, maneja eficientemente la comunicación con la API de OpenAI e incluye un manejo integral de errores para garantizar la fiabilidad.

4.2.4 Mejoras Opcionales

Aquí hay algunas funciones avanzadas que puedes implementar para mejorar la funcionalidad y experiencia de usuario de tu chatbot:

Alternador de modo oscuro usando CSS

  • Implementar un selector de tema que cambie el esquema de colores
    • Crear un botón de alternación con animaciones suaves de transición
    • Definir paletas de colores separadas para modos claro y oscuro
  • Usar variables CSS para una gestión fácil del tema
    • Definir variables CSS a nivel raíz para colores, sombras y fondos
    • Implementar una única fuente de verdad para los estilos relacionados con el tema
  • Almacenar preferencias del usuario en almacenamiento local
    • Guardar preferencia de tema usando la API localStorage del navegador
    • Aplicar automáticamente la preferencia guardada al recargar la página
    • Respetar la configuración de modo oscuro del sistema usando la media query prefers-color-scheme

Iconos de avatar para usuario y asistente

  • Añadir distinción visual entre participantes
    • Usar diferentes colores y formas para identificar claramente los mensajes de usuarios versus el asistente IA
    • Incluir señales visuales sutiles como orientación de mensajes (alineación izquierda/derecha)
  • Usar imágenes personalizadas o fotos de perfil predeterminadas
    • Permitir a los usuarios subir sus propias fotos de perfil
    • Proporcionar un conjunto predeterminado de avatares profesionales para usuarios que no suban imágenes personalizadas
    • Generar avatares únicos del asistente IA que reflejen su personalidad
  • Implementar transiciones suaves entre mensajes
    • Añadir animaciones de aparición gradual cuando aparecen nuevos mensajes
    • Incluir indicadores de escritura mientras la IA genera respuestas
    • Usar animaciones sutiles de escala al pasar el cursor sobre los mensajes

Entrada de voz a texto usando APIs del navegador

  • Integrar la API Web Speech para reconocimiento de voz
    • Usar la interfaz SpeechRecognition para capturar entrada de audio
    • Implementar manejo de errores para casos cuando el navegador no soporta reconocimiento de voz
    • Añadir manejo de permisos de micrófono y retroalimentación al usuario
  • Añadir retroalimentación de transcripción en tiempo real
    • Mostrar resultados provisionales mientras el usuario habla
    • Implementar indicadores visuales para el estado de escucha activa
    • Añadir puntuaciones de confianza para precisión de transcripción
  • Manejar soporte para múltiples idiomas
    • Configurar reconocimiento para diferentes idiomas usando etiquetas de idioma BCP 47
    • Permitir a los usuarios cambiar entre idiomas dinámicamente
    • Implementar detección de dialectos y manejo de acentos regionales

Respuestas de voz usando la salida TTS de OpenAI y JavaScript

  • Convertir respuestas del chatbot a voz natural
    • Usar la API Text-to-Speech de OpenAI para generar audio de alta calidad
    • Soportar múltiples idiomas y acentos para usuarios internacionales
    • Manejar preprocesamiento de texto para mejor pronunciación
  • Implementar controles de reproducción
    • Añadir control de reproducir/pausar, velocidad y volumen
    • Incluir barra de progreso para respuestas largas
    • Habilitar atajos de teclado para control rápido
  • Añadir opciones para diferentes voces y velocidades de habla
    • Ofrecer selección de personalidades de voz (casual, profesional, etc.)
    • Permitir velocidad de habla personalizable (0.5x a 2x)
    • Implementar controles de tono de voz y énfasis

En este capítulo, hemos explorado cómo transformar un chatbot básico en una interfaz sofisticada y amigable que ofrece una experiencia verdaderamente interactiva. Esta mejora se puede lograr a través de dos enfoques distintos:

Streamlit: Este framework moderno sobresale en el desarrollo rápido y ofrece numerosas ventajas para construir chatbots:

  • Componentes de interfaz de chat preconfigurados
    • Burbujas de mensajes, campos de entrada y diseños de chat listos para usar
    • Componentes integrados para carga y manejo de archivos
  • Gestión de estado simplificada
    • Manejo automático del estado de sesión y caché
    • Implementación sencilla del historial de conversación
  • Capacidades de prototipado rápido
    • Recarga en vivo para desarrollo veloz
    • API intuitiva para iteración rápida
  • Requisitos mínimos de configuración
    • Posibilidad de aplicaciones en un solo archivo
    • No requiere configuración compleja

Flask: Este micro-framework versátil proporciona a los desarrolladores control total mediante:

  • Control completo sobre la estructura HTML
    • Plantillas personalizadas para control preciso del diseño
    • Libertad para implementar cualquier patrón de diseño
  • Opciones de estilo CSS personalizadas
    • Control total sobre estilos y animaciones
    • Integración con cualquier framework CSS
  • Capacidades avanzadas de enrutamiento
    • Patrones de URL complejos y parámetros
    • Implementación de API RESTful
  • Gestión granular de sesiones
    • Manejo y almacenamiento personalizado de sesiones
    • Control preciso sobre datos de usuario

Hemos implementado varias características clave que transforman este chatbot básico en una aplicación de nivel profesional:

  • Gestión robusta de memoria de conversación
    • Implementa almacenamiento seguro de historial de chat
    • Mantiene el contexto a través de múltiples interacciones
    • Maneja la limpieza y gestión del estado de conversación
  • Visualización intuitiva del historial de chat
    • Clara organización y encadenamiento de mensajes
    • Separación visual distintiva entre respuestas de usuario e IA
    • Indicadores de marca de tiempo y estado de mensajes
  • Animaciones y transiciones fluidas de respuesta
    • Estados de carga durante llamadas a la API
    • Efectos de aparición gradual para nuevos mensajes
    • Desplazamiento suave a los mensajes más recientes
  • Elementos profesionales de diseño UI/UX
    • Esquema de colores y tipografía consistentes
    • Diseño responsivo para todas las pantallas
    • Elementos de interfaz que cumplen con la accesibilidad

Estas mejoras trabajan en conjunto para crear un chatbot que no solo funciona eficientemente sino que también proporciona una experiencia profesional y atractiva que se siente natural y receptiva para los usuarios. Cada característica ha sido implementada cuidadosamente para asegurar un rendimiento óptimo mientras mantiene una experiencia de usuario fluida durante todo el flujo de conversación.

4.2 Creación de Interfaces de Usuario Interactivas

Las interfaces de usuario son el puente entre la inteligencia de tu chatbot y sus usuarios. Una UI bien diseñada puede transformar un sistema de IA capaz en una herramienta atractiva y accesible que los usuarios disfrutan usar. Crear una interfaz efectiva para el chatbot requiere una cuidadosa consideración de los principios de experiencia de usuario, elementos de diseño visual y patrones de interacción.

Esta sección explora el arte y la ciencia de construir interfaces de chatbot intuitivas. Examinaremos tanto la implementación técnica como las consideraciones de diseño que hacen que un chatbot sea verdaderamente fácil de usar. Aprenderás a crear interfaces que no solo se vean profesionales sino que también proporcionen retroalimentación significativa, manejen errores con elegancia y guíen a los usuarios a través de conversaciones naturales.

Ya sea que estés construyendo un bot de servicio al cliente, un asistente virtual o una herramienta de aprendizaje impulsada por IA, los principios y técnicas cubiertos aquí te ayudarán a crear interfaces que mejoren en lugar de obstaculizar la experiencia del usuario. Veremos enfoques de implementación usando tanto Streamlit como Flask, dándote la flexibilidad de elegir las herramientas que mejor se adapten a las necesidades de tu proyecto.

4.2.1 Por qué la UI es Importante en un Chatbot

El éxito de un chatbot depende en gran medida de su interfaz de usuario y experiencia de usuario general. No importa cuán sofisticado sea tu modelo de IA, los usuarios tendrán dificultades para interactuar efectivamente con él si la interfaz es difícil de usar o poco intuitiva. Por eso es crucial crear interfaces bien diseñadas y fáciles de usar. Nos centraremos en construir UIs intuitivas, responsivas y fáciles de usar que no solo se vean profesionales sino que también creen un flujo natural de conversación entre el usuario y la IA.

Nuestro enfoque enfatiza tres aspectos fundamentales del diseño de interfaces que son críticos para crear un chatbot efectivo:

Experiencia de Usuario (UX)

Crear interfaces que sean fáciles de navegar y entender, con jerarquías visuales claras y patrones de interacción intuitivos. Una UX bien diseñada considera varios aspectos clave:

  1. Arquitectura de Información: Organizar el contenido en una estructura lógica y fácil de seguir que coincida con los modelos mentales de los usuarios.
  2. Diseño Visual: Usar esquemas de color, tipografía y espaciado consistentes para crear jerarquías visuales claras que guíen la atención de los usuarios.
  3. Diseño de Interacción: Implementar controles y patrones de navegación intuitivos que se sientan familiares y predecibles para los usuarios.
  4. Mecanismos de Retroalimentación: Proporcionar señales visuales y textuales claras que ayuden a los usuarios a entender:
    • Cuándo su mensaje está siendo procesado
    • Cuándo el chatbot está "pensando"
    • Si ocurre un error
    • Si su entrada fue recibida exitosamente
  5. Gestión de Carga Cognitiva: Minimizar el esfuerzo mental requerido para usar la interfaz mediante:
    • División de tareas complejas en pasos más pequeños
    • Uso de patrones de diseño familiares
    • Proporcionar instrucciones claras cuando sea necesario
    • Mantener un comportamiento consistente en toda la interfaz

Este enfoque reflexivo del diseño UX reduce la fricción, aumenta el compromiso del usuario y hace que el chatbot se sienta natural y sin esfuerzo de usar.

Capacidad de Respuesta

Asegurar que la interfaz proporcione retroalimentación inmediata y mantenga un rendimiento fluido en diferentes dispositivos y tamaños de pantalla. Esto involucra varios aspectos clave:

  1. Optimización del Rendimiento:
    • Implementar estados de carga eficientes que muestren a los usuarios que sus acciones están siendo procesadas
    • Optimizar tiempos de respuesta mediante técnicas como debouncing de solicitudes y caché
    • Usar carga progresiva para el historial de chat para manejar conversaciones grandes
  2. Compatibilidad con Dispositivos:
    • Usar principios de diseño responsivo para asegurar que el chatbot funcione sin problemas en todos los dispositivos
    • Implementar diseños fluidos que se ajusten a diferentes tamaños de pantalla
    • Asegurar elementos de interfaz amigables al tacto para usuarios móviles
    • Probar y optimizar para varios navegadores y plataformas
  3. Elementos UI Adaptativos:
    • Crear burbujas de chat flexibles que cambien de tamaño según el contenido
    • Implementar menús y controles plegables para pantallas más pequeñas
    • Usar unidades relativas (em, rem, vh, vw) en lugar de píxeles fijos
    • Asegurar un correcto ajuste de texto y legibilidad en todos los tamaños

La interfaz debe adaptarse dinámicamente a diferentes tamaños de pantalla mientras mantiene la funcionalidad y el atractivo visual, proporcionando una experiencia consistente ya sea que se acceda desde un smartphone, tablet o computadora de escritorio.

Accesibilidad

Hacer que el chatbot sea utilizable para personas con diferentes capacidades y conocimientos técnicos es crucial para garantizar un acceso inclusivo. Esto implica varias consideraciones clave:

  • Compatibilidad con Lectores de Pantalla
    • Implementación de etiquetas y roles ARIA apropiados para describir elementos de la interfaz
    • Asegurar una estructura de encabezados y navegación significativa
    • Proporcionar alternativas textuales para todo el contenido no textual
  • Navegación por Teclado
    • Soporte del control completo por teclado de todas las funciones
    • Implementación de indicadores visibles de enfoque
    • Creación de un orden lógico de tabulación a través de la interfaz
  • Diseño Visual
    • Mantener ratios de contraste de color suficientes (mínimo 4.5:1)
    • Evitar el uso del color como único medio para transmitir información
    • Permitir el redimensionamiento del texto sin pérdida de funcionalidad
  • Consideraciones Técnicas
    • Seguir los estándares de las Pautas de Accesibilidad para el Contenido Web (WCAG) 2.1 Nivel AA
    • Pruebas regulares con herramientas de accesibilidad y lectores de pantalla
    • Proporcionar alternativas para interacciones complejas

Al implementar estas características de accesibilidad, aseguras que tu chatbot pueda ser utilizado efectivamente por personas con diversas discapacidades, incluyendo impedimentos visuales, auditivos, motores y cognitivos. Esto no solo cumple con los requisitos legales sino que también demuestra un compromiso con los principios de diseño universal.

Para crear una interfaz de chatbot efectiva y fácil de usar, exploraremos estos componentes esenciales en detalle:

  1. Construcción de una Interfaz de Chat Intuitiva
    • Implementación de principios de diseño limpios y modernos que prioricen la legibilidad y el compromiso del usuario
    • Consideración cuidadosa del espaciado para crear espacio visual entre elementos
    • Uso estratégico de la tipografía para establecer una jerarquía clara de información
    • Elementos visuales consistentes que guíen a los usuarios a través del flujo de conversación
  2. Gestión del Historial de Conversación
    • Implementación de sistemas eficientes de almacenamiento y recuperación de registros de chat
    • Integración de funcionalidad de marcas temporales para mejor seguimiento de conversaciones
    • Creación de estilos visuales distintivos para mensajes de usuario y bot
    • Desarrollo de mecánicas de desplazamiento suave para conversaciones más largas
  3. Optimización de la Presentación de Respuestas
    • Selección cuidadosa de fuentes y tamaños de texto para máxima legibilidad
    • Implementación de patrones de espaciado consistentes entre elementos de mensaje
    • Consideraciones especiales de formato para diferentes tipos de contenido (bloques de código, listas, etc.)
    • Integración de indicadores visuales para estado y tipo de mensaje
  4. Implementación de Sistemas Robustos de Retroalimentación
    • Creación de animaciones de carga sutiles pero visibles durante la generación de respuestas
    • Desarrollo de mensajes de error claros que guíen a los usuarios hacia soluciones
    • Implementación de mecanismos de recuperación para escenarios comunes de error
    • Integración de indicadores de estado para mantener a los usuarios informados del estado del sistema

Obtendrás ejemplos completos tanto en Streamlit como en Flask, permitiéndote elegir el framework que mejor se adapte a tu estilo de desarrollo y requisitos del proyecto. Cada ejemplo incluye explicaciones detalladas y mejores prácticas para la implementación.

4.2.2 Interfaz de Chat Interactiva con Streamlit

Este ejemplo demuestra cómo crear un chatbot interactivo usando Streamlit y OpenAI, sobre el cual construiremos más adelante. Usando Streamlit, crearemos una interfaz de chat amigable que mantiene el historial de conversación. Este caso de uso presenta conceptos clave y mejores prácticas para construir un chatbot robusto e interactivo.

Paso 1: Instalar Dependencias

pip install streamlit openai python-dotenv
  • streamlit: Una librería de Python para crear aplicaciones web interactivas.
  • openai: La librería de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una librería para cargar variables de entorno desde un archivo .env.

Paso 2: Crear la Aplicación Streamlit (chatbot.py)

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.

    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.

    Returns:
        str: The assistant's reply, or an error message.

    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

def initialize_session_state():
    """
    Initializes session state variables.  This function should be called
    at the beginning of the main() function.  It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

# --- Main App ---
def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")

    initialize_session_state()  # Initialize session state

    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history) # corrected to clear_chat_history

    # Display chat history, রাখা changed to display_messages
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")

    # User input, রাখা outside the conditional block
    user_input = st.chat_input("Ask me anything...", key="user_input")

    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})

        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model) #added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response

        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})

        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()

if __name__ == "__main__":
    main()

Desglose del Código

Analicemos el código paso a paso.

Importaciones:

import streamlit as st
import openai
import os
from dotenv import load_dotenv
import time  # For handling potential API errors
from typing import List, Dict  # For type hinting

Importa las bibliotecas necesarias:

  • streamlit: Para crear la interfaz web.
  • openai: Para interactuar con la API de OpenAI.
  • os: Para acceder a las variables de entorno.
  • dotenv: Para cargar variables de entorno desde un archivo .env.
  • time: Para manejar posibles errores de API mediante esperas.
  • typing: Para anotaciones de tipo que mejoran la legibilidad del código.

Variables de Entorno:

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

Carga la clave API de OpenAI desde un archivo .env y la configura para la biblioteca OpenAI.

Constantes:

DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant.  Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "messages"  # Consistent key for session state
DISPLAY_MESSAGES_KEY = "display_messages"
  • DEFAULT_MODEL: El modelo predeterminado de OpenAI utilizado para el chatbot.
  • SYSTEM_PROMPT: El mensaje inicial enviado a la API de OpenAI para establecer el comportamiento del asistente.
  • SESSION_MESSAGES_KEY: Clave para usar en el historial principal de conversación en el estado de la sesión.
  • DISPLAY_MESSAGES_KEY: Clave para usar en el historial de conversación que se muestra en la interfaz de usuario.

Funciones Auxiliares:

  • get_openai_response():
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors with robust error handling.
    Args:
        messages (List[Dict[str, str]]): A list of message dictionaries, representing the conversation history.
        model (str, optional): The OpenAI model to use. Defaults to DEFAULT_MODEL.
    Returns:
        str: The assistant's reply, or an error message.
    Raises:
        openai.error.OpenAIError: If there is an error with the OpenAI API.
        Exception: For other unexpected errors.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60,  # Add a timeout to prevent hanging
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        st.error(f"OpenAI API Error: {e}")
        return f"Sorry, I encountered an error with the OpenAI API: {e}"
    except Exception as e:
        st.error(f"An unexpected error occurred: {e}")
        return "Sorry, I encountered an unexpected error."

Envía la entrada del usuario a la API de OpenAI y obtiene la respuesta. Esta función también incluye manejo de errores usando un bloque try...except para capturar posibles excepciones openai.error.OpenAIError y una Exception general para otros errores. Se agrega un tiempo límite para evitar que la aplicación se quede colgada indefinidamente.

  • initialize_session_state():
def initialize_session_state():
    """
    Initializes session state variables. This function should be called
    at the beginning of the main() function. It ensures that session
    state is initialized even if the user doesn't immediately enter a query.
    """
    if SESSION_MESSAGES_KEY not in st.session_state:
        st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if DISPLAY_MESSAGES_KEY not in st.session_state:
        st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]  # Separate list for displayed messages
    if "model" not in st.session_state:
        st.session_state.model = DEFAULT_MODEL

Inicializa las variables del estado de la sesión:

  • SESSION_MESSAGES_KEY: Almacena el historial completo de la conversación.
  • DISPLAY_MESSAGES_KEY: Almacena el historial de la conversación que se muestra al usuario.
  • model: El modelo LLM
  • clear_chat_history():
def clear_chat_history():
    """Clears the chat history and resets to the initial state."""
    st.session_state[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state[DISPLAY_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    st.session_state.user_input = ""  # Clear the input field
    st.rerun()  # Force a rerun to update the display

Borra el historial del chat cuando el usuario hace clic en el botón "Borrar Chat".

Aplicación Principal:

def main():
    """
    Main function to run the Streamlit application.
    """
    st.set_page_config(page_title="AI Chatbot", page_icon="🤖")
    st.title("🤖 GPT-4o Assistant")
    initialize_session_state()
    # --- Sidebar ---
    st.sidebar.header("Settings")
    model = st.sidebar.selectbox("Model", ["gpt-4o", "gpt-3.5-turbo"], index=0)
    st.session_state.model = model
    clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history)
    # Display chat history
    for message in st.session_state[DISPLAY_MESSAGES_KEY]:
        if message["role"] != "system":  # Don't display the system prompt
            speaker = "🧑‍💻 You" if message["role"] == "user" else "🤖 Assistant"
            with st.chat_message(message["role"]):
                st.markdown(f"**{speaker}:** {message['content']}")
    # User input
    user_input = st.chat_input("Ask me anything...", key="user_input")
    # Process user input
    if user_input:
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "user", "content": user_input})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "user", "content": user_input})
        # Add spinner while GPT-4o thinks
        with st.chat_message("assistant"):
            placeholder = st.empty()  # Reserve a placeholder for the response
            with st.spinner("Thinking..."):
                reply = get_openai_response(st.session_state[SESSION_MESSAGES_KEY], model=st.session_state.model)  # added model
            placeholder.markdown(f"**🤖 Assistant:** {reply}")  # Replace placeholder with full response
        st.session_state[SESSION_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        st.session_state[DISPLAY_MESSAGES_KEY].append({"role": "assistant", "content": reply})
        # Clear the input field after sending the message
        st.session_state.user_input = ""
        st.rerun()
if __name__ == "__main__":
    main()
  • st.set_page_config(page_title="AI Chatbot", page_icon="🤖"): Configura el título y el ícono de la página en la pestaña del navegador.
  • st.title("🤖 GPT-4o Assistant"): Establece el título de la aplicación Streamlit.
  • initialize_session_state(): Inicializa la sesión
  • st.sidebar.header("Settings"): Crea una sección de barra lateral titulada "Settings".
  • model = st.sidebar.selectbox(...): Crea un menú desplegable en la barra lateral para seleccionar el modelo de OpenAI.
  • clear_history_button = st.sidebar.button("Clear Chat", on_click=clear_chat_history): Agrega un botón a la barra lateral para borrar el historial del chat.
  • El historial del chat se muestra usando st.chat_message, con diferentes estilos para los mensajes del usuario y del asistente.
  • user_input = st.chat_input("Ask me anything...", key="user_input"): Crea un campo de entrada de texto para que el usuario escriba su consulta. El argumento key es importante para que Streamlit gestione el estado del campo de entrada.
  • La aplicación obtiene la entrada del usuario, la envía a la API de OpenAI usando la función get_openai_response, y muestra la respuesta.
  • El historial de la conversación se almacena en st.session_state.messages como una lista de diccionarios. Cada diccionario tiene un "role" (ya sea "user" o "assistant") y "content".
  • st.rerun() se utiliza para actualizar la pantalla después de que el asistente responde.
  • Ejecutar la aplicación:Para ejecutar la aplicación, guarda el código en un archivo llamado chatbot.py y ejecuta el siguiente comando en tu terminal:
streamlit run chatbot.py

4.2.3 Interfaz de Chat Personalizada con Flask + HTML/CSS

Este ejemplo implementa un chatbot usando Flask y el modelo GPT-4o de OpenAI, con énfasis en permitir que los desarrolladores personalicen la interfaz del chat usando su propio HTML y CSS. Este enfoque proporciona mayor flexibilidad en el diseño y la disposición en comparación con el uso de componentes de interfaz preconfigurados. Este código proporciona un chatbot robusto y personalizable, explicando conceptos clave y mejores prácticas para desarrolladores de nivel intermedio.

Paso 1: Instalar Dependencias

pip install flask openai python-dotenv
  • flask: Un framework web para construir la aplicación del chatbot.
  • openai: La biblioteca de Python de OpenAI para interactuar con el modelo GPT-4o.
  • python-dotenv: Una biblioteca para cargar variables de entorno desde un archivo .env.

Paso 2: Plantilla Actualizada de Flask (templates/chat.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GPT-4o Chat Assistant</title>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
  <style>
    /* --- General Styles --- */
    body {
      font-family: 'Inter', sans-serif;  /* Modern font */
      background-color: #f3f4f6;  /* Tailwind's gray-100 */
      padding: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      color: #1f2937;  /* Tailwind's gray-800 */
    }
    .container {
      max-width: 800px;  /* Increased max-width */
      width: 100%;
      background-color: #fff; /* White background */
      padding: 30px;
      border-radius: 0.75rem;  /* Tailwind's rounded-lg */
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);  /* Tailwind's shadow-md */
    }
    h2 {
      font-size: 1.875rem; /* Tailwind's text-2xl */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 2rem;  /* Tailwind's mb-8 */
      color: #1e293b; /* Tailwind's gray-900 */
      text-align: center;
    }
    /* --- Message Styles --- */
    .message {
      margin-bottom: 1.5rem;  /* Tailwind's mb-6 */
      display: flex;
      flex-direction: column;
    }
    .message p {
      padding: 1rem;  /* Tailwind's p-4 */
      border-radius: 1rem;  /* Tailwind's rounded-lg */
      max-width: 80%; /* Limit message width */
    }
    .user p {
      background-color: #e0f2fe;  /* Tailwind's bg-blue-100 */
      color: #1d4ed8;  /* Tailwind's text-blue-700 */
      margin-left: auto; /* Push user message to the right */
    }
    .assistant p {
      background-color: #f0fdf4;  /* Tailwind's bg-green-100 */
      color: #15803d;  /* Tailwind's text-green-700 */
    }
    .message strong {
      font-size: 0.875rem; /* Tailwind's text-sm */
      font-weight: 600;  /* Tailwind's font-semibold */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
    }
    .user strong {
        color: #1e40af; /* Tailwind's text-blue-800 */
    }
    .assistant strong {
        color: #16a34a; /* Tailwind's text-green-800 */
    }

    /* --- Form Styles --- */
    form {
      margin-top: 2rem;  /* Tailwind's mt-8 */
      display: flex;
      flex-direction: column;
      gap: 0.5rem; /* Tailwind's gap-2 */
    }
    textarea {
      width: 100%;
      padding: 0.75rem;  /* Tailwind's p-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      border: 1px solid #d1d5db;  /* Tailwind's border-gray-300 */
      resize: none;
      font-size: 1rem;  /* Tailwind's text-base */
      line-height: 1.5rem;  /* Tailwind's leading-relaxed */
      margin-bottom: 0.25rem; /* Tailwind's mb-1 */
      box-shadow: inset 0 2px 4px rgba(0,0,0,0.06); /* Inner shadow, more subtle */
    }
    textarea:focus {
      outline: none;
      border-color: #3b82f6;  /* Tailwind's border-blue-500 */
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);  /* Tailwind's ring-blue-500 with opacity */
    }
    input[type="submit"] {
      padding: 0.75rem 1.5rem;  /* Tailwind's px-6 py-3 */
      border-radius: 0.5rem;  /* Tailwind's rounded-md */
      background-color: #3b82f6;  /* Tailwind's bg-blue-500 */
      color: #fff;  /* White text */
      font-size: 1rem;  /* Tailwind's text-base */
      font-weight: 600;  /* Tailwind's font-semibold */
      cursor: pointer;
      transition: background-color 0.3s ease;  /* Smooth transition */
      border: none;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);  /* Tailwind's shadow-sm */
    }
    input[type="submit"]:hover {
      background-color: #2563eb;  /* Tailwind's bg-blue-700 on hover */
    }
    input[type="submit"]:focus {
      outline: none;
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);  /* Tailwind's ring-blue-500 with more opacity*/
    }

    /* --- Responsive Adjustments --- */
    @media (max-width: 768px) {  /* Medium screens and below (md breakpoint in Tailwind is 768px) */
      .container {
        padding: 20px;
      }
      textarea {
        height: 100px;  /* Make textarea taller on smaller screens */
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>🧠 GPT-4o Chat Assistant</h2>
    {% for msg in history %}
      <div class="message {{ msg.role }}">
        <p><strong>{{ msg.role.capitalize() }}:</strong> {{ msg.content }}</p>
      </div>
    {% endfor %}
    <form method="post">
      <textarea name="user_input" placeholder="Type your message..."></textarea><br>
      <input type="submit" value="Send Message">
    </form>
  </div>
</body>
</html>

Plantilla HTML:

  • Diseño Moderno: La plantilla presenta un enfoque de diseño contemporáneo inspirado en Tailwind CSS. Esto incluye:
    • Fuente limpia (Inter)
    • Espaciado y márgenes amplios
    • Esquinas redondeadas
    • Sombras sutiles
    • Paleta de colores consistente
  • Diseño Responsivo: Se agregó una media query para ajustar el diseño en pantallas más pequeñas (tabletas y teléfonos).
  • Formulario Mejorado: El formulario está estilizado con un estado de enfoque, mejores márgenes y un efecto suave al pasar el cursor.
  • HTML Semántico: Utiliza lang="en" en la etiqueta &lt;html&gt; para mejor accesibilidad.
  • Comentarios: Se agregaron comentarios para explicar el CSS, relacionándolo con Tailwind CSS cuando corresponde, para facilitar la comprensión.

Paso 3: Backend Flask Actualizado (app.py)

from flask import Flask, request, render_template, session, redirect, url_for
import openai
import os
from dotenv import load_dotenv
import time
from typing import List, Dict

load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

app = Flask(__name__)
app.secret_key = os.urandom(24)  # Required for session management

# --- Constants ---
DEFAULT_MODEL = "gpt-4o"
SYSTEM_PROMPT = "You are a helpful, friendly, and knowledgeable assistant. Answer all questions clearly, concisely, and in a conversational tone. When appropriate, provide code examples."
SESSION_MESSAGES_KEY = "conversation"  # Consistent key for session

# --- Helper Functions ---
def get_openai_response(messages: List[Dict[str, str]], model: str = DEFAULT_MODEL) -> str:
    """
    Sends a message to OpenAI's Chat API and handles potential errors.
    Args:
        messages: A list of message dictionaries.
        model: The OpenAI model to use.
    Returns:
        The assistant's reply, or an error message.
    """
    try:
        response = openai.ChatCompletion.create(
            model=model,
            messages=messages,
            timeout=60
        )
        return response.choices[0].message.content
    except openai.error.OpenAIError as e:
        # Log the error for debugging
        print(f"OpenAI API error: {e}")
        return f"Sorry, there was an error communicating with the AI: {e}"
    except Exception as e:
        print(f"Unexpected error: {e}")
        return "Sorry, an unexpected error occurred."

def initialize_session_state():
    """Initializes session state."""
    if SESSION_MESSAGES_KEY not in session:
        session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    if "model" not in session:
        session["model"] = DEFAULT_MODEL

def clear_conversation():
    """Clears the conversation history from the session."""
    session[SESSION_MESSAGES_KEY] = [{"role": "system", "content": SYSTEM_PROMPT}]
    session.modified = True  # Ensure session is saved
    return redirect(url_for("chat"))  # Redirect to the chat route

# --- Routes ---
@app.route("/", methods=["GET", "POST"])
def chat():
    initialize_session_state()
    conversation = session[SESSION_MESSAGES_KEY]
    model = session["model"]

    if request.method == "POST":
        user_input = request.form["user_input"]
        conversation.append({"role": "user", "content": user_input})

        reply = get_openai_response(conversation, model)
        conversation.append({"role": "assistant", "content": reply})

        session[SESSION_MESSAGES_KEY] = conversation
        session.modified = True  # Important:  You need to mark the session as modified
        return render_template("chat.html", history=conversation[1:])  # Skip system message

    return render_template("chat.html", history=conversation[1:])  # Skip system message

@app.route("/clear", methods=["POST"])  # New route to handle clearing the chat
def clear_chat():
    return clear_conversation()

if __name__ == "__main__":
    app.run(debug=True)

Analicemos este código de aplicación Flask para un chatbot:

1. Importaciones y Configuración

  • Componentes esenciales de Flask e integración con OpenAI
  • Carga de variables de entorno con python-dotenv
  • Generación de clave secreta para gestión de sesiones

2. Configuración Principal

  • Modelo predeterminado establecido como "gpt-4o"
  • Prompt del sistema que define la personalidad y comportamiento de la IA
  • Gestión de sesiones para persistencia de conversaciones

3. Funciones Auxiliares

  • get_openai_response(): Gestiona la comunicación con la API de OpenAI, incluyendo manejo de errores
  • initialize_session_state(): Configura el estado inicial de la conversación y ajustes del modelo
  • clear_conversation(): Reinicia el historial del chat al estado inicial

4. Rutas

  • Ruta principal ("/"):
    • Maneja solicitudes GET y POST
    • Gestiona el flujo de conversación y el historial de mensajes
    • Renderiza la plantilla del chat con el historial de conversación
  • Ruta de limpieza ("/clear"):
    • Proporciona funcionalidad para reiniciar la conversación

El ejemplo implementa un chatbot robusto que mantiene el historial de conversación mediante sesiones de Flask, maneja eficientemente la comunicación con la API de OpenAI e incluye un manejo integral de errores para garantizar la fiabilidad.

4.2.4 Mejoras Opcionales

Aquí hay algunas funciones avanzadas que puedes implementar para mejorar la funcionalidad y experiencia de usuario de tu chatbot:

Alternador de modo oscuro usando CSS

  • Implementar un selector de tema que cambie el esquema de colores
    • Crear un botón de alternación con animaciones suaves de transición
    • Definir paletas de colores separadas para modos claro y oscuro
  • Usar variables CSS para una gestión fácil del tema
    • Definir variables CSS a nivel raíz para colores, sombras y fondos
    • Implementar una única fuente de verdad para los estilos relacionados con el tema
  • Almacenar preferencias del usuario en almacenamiento local
    • Guardar preferencia de tema usando la API localStorage del navegador
    • Aplicar automáticamente la preferencia guardada al recargar la página
    • Respetar la configuración de modo oscuro del sistema usando la media query prefers-color-scheme

Iconos de avatar para usuario y asistente

  • Añadir distinción visual entre participantes
    • Usar diferentes colores y formas para identificar claramente los mensajes de usuarios versus el asistente IA
    • Incluir señales visuales sutiles como orientación de mensajes (alineación izquierda/derecha)
  • Usar imágenes personalizadas o fotos de perfil predeterminadas
    • Permitir a los usuarios subir sus propias fotos de perfil
    • Proporcionar un conjunto predeterminado de avatares profesionales para usuarios que no suban imágenes personalizadas
    • Generar avatares únicos del asistente IA que reflejen su personalidad
  • Implementar transiciones suaves entre mensajes
    • Añadir animaciones de aparición gradual cuando aparecen nuevos mensajes
    • Incluir indicadores de escritura mientras la IA genera respuestas
    • Usar animaciones sutiles de escala al pasar el cursor sobre los mensajes

Entrada de voz a texto usando APIs del navegador

  • Integrar la API Web Speech para reconocimiento de voz
    • Usar la interfaz SpeechRecognition para capturar entrada de audio
    • Implementar manejo de errores para casos cuando el navegador no soporta reconocimiento de voz
    • Añadir manejo de permisos de micrófono y retroalimentación al usuario
  • Añadir retroalimentación de transcripción en tiempo real
    • Mostrar resultados provisionales mientras el usuario habla
    • Implementar indicadores visuales para el estado de escucha activa
    • Añadir puntuaciones de confianza para precisión de transcripción
  • Manejar soporte para múltiples idiomas
    • Configurar reconocimiento para diferentes idiomas usando etiquetas de idioma BCP 47
    • Permitir a los usuarios cambiar entre idiomas dinámicamente
    • Implementar detección de dialectos y manejo de acentos regionales

Respuestas de voz usando la salida TTS de OpenAI y JavaScript

  • Convertir respuestas del chatbot a voz natural
    • Usar la API Text-to-Speech de OpenAI para generar audio de alta calidad
    • Soportar múltiples idiomas y acentos para usuarios internacionales
    • Manejar preprocesamiento de texto para mejor pronunciación
  • Implementar controles de reproducción
    • Añadir control de reproducir/pausar, velocidad y volumen
    • Incluir barra de progreso para respuestas largas
    • Habilitar atajos de teclado para control rápido
  • Añadir opciones para diferentes voces y velocidades de habla
    • Ofrecer selección de personalidades de voz (casual, profesional, etc.)
    • Permitir velocidad de habla personalizable (0.5x a 2x)
    • Implementar controles de tono de voz y énfasis

En este capítulo, hemos explorado cómo transformar un chatbot básico en una interfaz sofisticada y amigable que ofrece una experiencia verdaderamente interactiva. Esta mejora se puede lograr a través de dos enfoques distintos:

Streamlit: Este framework moderno sobresale en el desarrollo rápido y ofrece numerosas ventajas para construir chatbots:

  • Componentes de interfaz de chat preconfigurados
    • Burbujas de mensajes, campos de entrada y diseños de chat listos para usar
    • Componentes integrados para carga y manejo de archivos
  • Gestión de estado simplificada
    • Manejo automático del estado de sesión y caché
    • Implementación sencilla del historial de conversación
  • Capacidades de prototipado rápido
    • Recarga en vivo para desarrollo veloz
    • API intuitiva para iteración rápida
  • Requisitos mínimos de configuración
    • Posibilidad de aplicaciones en un solo archivo
    • No requiere configuración compleja

Flask: Este micro-framework versátil proporciona a los desarrolladores control total mediante:

  • Control completo sobre la estructura HTML
    • Plantillas personalizadas para control preciso del diseño
    • Libertad para implementar cualquier patrón de diseño
  • Opciones de estilo CSS personalizadas
    • Control total sobre estilos y animaciones
    • Integración con cualquier framework CSS
  • Capacidades avanzadas de enrutamiento
    • Patrones de URL complejos y parámetros
    • Implementación de API RESTful
  • Gestión granular de sesiones
    • Manejo y almacenamiento personalizado de sesiones
    • Control preciso sobre datos de usuario

Hemos implementado varias características clave que transforman este chatbot básico en una aplicación de nivel profesional:

  • Gestión robusta de memoria de conversación
    • Implementa almacenamiento seguro de historial de chat
    • Mantiene el contexto a través de múltiples interacciones
    • Maneja la limpieza y gestión del estado de conversación
  • Visualización intuitiva del historial de chat
    • Clara organización y encadenamiento de mensajes
    • Separación visual distintiva entre respuestas de usuario e IA
    • Indicadores de marca de tiempo y estado de mensajes
  • Animaciones y transiciones fluidas de respuesta
    • Estados de carga durante llamadas a la API
    • Efectos de aparición gradual para nuevos mensajes
    • Desplazamiento suave a los mensajes más recientes
  • Elementos profesionales de diseño UI/UX
    • Esquema de colores y tipografía consistentes
    • Diseño responsivo para todas las pantallas
    • Elementos de interfaz que cumplen con la accesibilidad

Estas mejoras trabajan en conjunto para crear un chatbot que no solo funciona eficientemente sino que también proporciona una experiencia profesional y atractiva que se siente natural y receptiva para los usuarios. Cada característica ha sido implementada cuidadosamente para asegurar un rendimiento óptimo mientras mantiene una experiencia de usuario fluida durante todo el flujo de conversación.