# Crear tu primer Chatbot con LangChain y OpenAI

## ¿Por qué LangChain?
LangChain es una **librería de orquestación** que simplifica la creación de aplicaciones que usan modelos de lenguaje (LLMs). En lugar de lidiar con peticiones HTTP directas a la API de OpenAI, te ofrece:

* Componentes reutilizables: prompts, cadenas de llamadas, memorias.
* Abstracciones para integrar bases de datos, buscadores, archivos, etc.
* Un ecosistema en rápido crecimiento que permite escalar tu idea en minutos.

---

## Requisitos previos
1. Conocimientos básicos de Python ≥ 3.8.
2. Una cuenta en OpenAI con créditos activos.
3. Terminal de comandos (macOS/Linux) o PowerShell (Windows).

---

## Paso 1. Consigue y protege tu clave de OpenAI
1. Entra en [https://platform.openai.com/account/api-keys](https://platform.openai.com/account/api-keys) y genera una nueva clave.
2. Guarda la cadena en un gestor de contraseñas o variable de entorno; **no** la subas a GitHub.

Ejemplo de archivo `.env` (agrega en la raíz del proyecto):

```bash
OPENAI_API_KEY="tu_clave_aquí"
```

---

## Paso 2. Prepara el entorno de trabajo
```bash
# 1. Crea y activa un entorno virtual
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate

# 2. Actualiza pip
pip install --upgrade pip
```

---

## Paso 3. Instala las dependencias
```bash
pip install langchain openai python-dotenv
```

* `langchain`: la estrella del tutorial.
* `openai`: cliente oficial de OpenAI (LangChain lo usa internamente).
* `python-dotenv`: carga la variable `OPENAI_API_KEY` desde el archivo `.env`.

---

## Paso 4. Código mínimo viable del chatbot
Crea `chatbot.py`:

```python
"""chatbot.py
Chatbot de consola usando LangChain + OpenAI.
"""
from langchain.chat_models import ChatOpenAI
from langchain.schema import (SystemMessage, HumanMessage)
from dotenv import load_dotenv
import os

# Carga la variable OPENAI_API_KEY desde .env
env_path = os.path.join(os.path.dirname(__file__), '.env')
load_dotenv(env_path)

# 1️⃣ Configura el modelo de chat
chat = ChatOpenAI(
    model_name="gpt-3.5-turbo",  # Cambia a gpt-4 si tu cuenta lo permite
    temperature=0.7,             # 0 = respuestas más deterministas, 1 = más creativas
    streaming=True               # Muestra tokens en tiempo real
)

# 2️⃣ Mensaje de sistema: define la personalidad del bot
system_message = SystemMessage(
    content="Eres un asistente experto en recetas de cocina latina."
)

print("\n🤖  Bot listo. Escribe 'salir' para terminar.\n")

while True:
    user_input = input("Tú: ")
    if user_input.lower() in {"salir", "exit", "quit"}:
        break

    # 3️⃣ Crea el mensaje del usuario
    human_message = HumanMessage(content=user_input)

    # 4️⃣ Llama al modelo
    response = chat([system_message, human_message])

    # 5️⃣ Muestra la respuesta del bot
    print(f"\n🤖: {response.content}\n")
```

Ejecuta:
```bash
python chatbot.py
```

¡Listo! Tienes un chatbot especializado en recetas latinas funcionando en tu terminal.

---

## Paso 5. Añade memoria de conversación
El script anterior no recuerda mensajes anteriores. LangChain lo soluciona con `ConversationBufferMemory` y `ConversationChain`.

```python
# memoria_chatbot.py
from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
from dotenv import load_dotenv
import os

load_dotenv()

llm = ChatOpenAI(temperature=0.7)

# Almacena el historial completo en RAM
memory = ConversationBufferMemory(return_messages=True)

conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=False  # True para depurar
)

print("\n🤖  Memoria activada. Escribe 'salir' para terminar.\n")
while True:
    user_input = input("Tú: ")
    if user_input.lower() == "salir":
        break

    # LangChain gestiona la conversación internamente
    response = conversation.predict(input=user_input)
    print(f"\n🤖: {response}\n")
```

Beneficios:
* El bot recuerda el contexto y puede dar respuestas coherentes en diálogos largos.
* Podrás almacenar la memoria en bases de datos o vectores con cambios mínimos.

---

## Paso 6. Personaliza prompts y herramientas
LangChain permite enriquecer tu bot con:

1. Prompts más complejos (`ChatPromptTemplate`).
2. Herramientas externas (`llm-math`, Google Search, APIs propias).
3. Cadenas (Chains) como `RetrievalQA` para conectarte a un índice de documentos.

Ejemplo sencillo de prompt template:

```python
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI

model = ChatOpenAI()

prompt = ChatPromptTemplate.from_messages([
    ("system", "Eres un bot que traduce español a inglés."),
    ("human", "{texto_es}")
])

print(prompt.format(texto_es="¿Cómo estás?"))
# --> {'role': 'human', 'content': '¿Cómo estás?'}

response = model(prompt.format_messages(texto_es="¿Cómo estás?"))
print(response.content)
```

---

## Paso 7. Despliegue rápido como API
Usa **FastAPI** para exponer tu chatbot en la web.

```bash
pip install fastapi uvicorn[standard]
```

`app.py`:
```python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
import os
from dotenv import load_dotenv

load_dotenv()

app = FastAPI()

class Msg(BaseModel):
    session_id: str
    text: str

# Un diccionario simple de memorias por sesión
active_sessions = {}

@app.post("/chat")
async def chat_endpoint(msg: Msg):
    if msg.session_id not in active_sessions:
        active_sessions[msg.session_id] = ConversationChain(
            llm=ChatOpenAI(),
            memory=ConversationBufferMemory(return_messages=True)
        )

    conversation = active_sessions[msg.session_id]
    try:
        response = conversation.predict(input=msg.text)
        return {"answer": response}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
```

Lanza el servidor:
```bash
uvicorn app:app --reload --port 8000
```
Ahora realiza peticiones `POST` a `http://localhost:8000/chat` con cualquier herramienta REST.

---

## Buenas prácticas finales
1. Limita el número de tokens para reducir costos (`max_tokens`).
2. Usa `retry` y `timeout` para lidiar con errores de red.
3. Cifra y guarda tu clave en variables seguras en producción.
4. Versiona tus prompts como parte del código.
5. Mide el uso con los dashboards de OpenAI o tu propia analítica.

---

## Próximos pasos sugeridos
* Conectar un motor de vectores (Weaviate, Pinecone) y usar `RetrievalQA` para un bot basado en tus documentos.
* Añadir autenticación JWT a la API.
* Desplegar en plataformas serverless (Vercel, AWS Lambda, Google Cloud Run).

¡Ya tienes la base para explorar el enorme ecosistema de LangChain y crear chatbots más potentes y especializados!
