Feat: Agregar agente Groq con integración RAG

- Nuevo módulo groq_agent.py para consultas a la API de Groq
- Panel de administración en /groq para configurar API key, modelo y prompt
- Comando /rag en Discord y Telegram para consultar el RAG
- Sistema de prompt personalizable guardado en base de datos
- Soporte para variables de entorno en Docker
- Fix: starlette version para evitar bug con Jinja2
This commit is contained in:
2026-03-26 21:23:19 -06:00
parent 48f7a80dc4
commit 8398e988b0
16 changed files with 1073 additions and 41 deletions

View File

@@ -14,7 +14,7 @@ from pydantic import BaseModel
from dotenv import load_dotenv
from passlib.hash import pbkdf2_sha256 as hasher
from botdiscord.config import load_config, get_web_config, get_libretranslate_url, get_db_type
from botdiscord.config import load_config, get_web_config, get_libretranslate_url, get_db_type, get_groq_config
# Asegurar que las variables de entorno se carguen correctamente
load_dotenv()
@@ -703,6 +703,162 @@ async def metrics_page(request: Request):
"username": username
})
@app.get("/groq")
async def groq_page(request: Request):
if request.cookies.get("auth") != "ok":
return RedirectResponse(url="/login")
from botdiscord.database import get_bot_config, set_bot_config
groq_config = get_groq_config()
# Default prompt
default_prompt = """Eres el General Reserves, comandante del ejército de Last War: Survival Game.
IDIOMA - IMPORTANTE:
1. Detecta el idioma de la PREGUNTA del usuario
2. Si NO es inglés, tradúcela al inglés ANTES de consultar el RAG
3. Cuando recibas la respuesta del RAG, tradúcela al MISMO IDIOMA de la pregunta original
4. RESPONDE SIEMPRE en el mismo idioma que te habló el usuario
SALUDOS: Saluda como "¡A la orden, recruit! 🎖️" o "¡Reporting for duty!"
FORMATO DE RESPUESTA:
- Primero saluda al usuario
- Da la información encontrada
- NUNCA repitas información varias veces
- Sé conciso
RESTRICCIONES:
1. SOLO responde sobre Last War: Survival Game
2. NUNCA inventes información
3. Si no hay datos en el RAG, responde con humor gentil: "¡Mi radar no detectó eso, recruit! 🤔"
Usa el sistema RAG para buscar información."""
# Always use default prompt (user can edit and save custom one)
groq_config["system_prompt"] = default_prompt
# Check if user has a custom prompt saved
saved_prompt = get_bot_config("groq_system_prompt")
if saved_prompt:
groq_config["system_prompt"] = saved_prompt
groq_config["has_custom_prompt"] = True
else:
groq_config["has_custom_prompt"] = False
groq_models = [
{"id": "llama-3.3-70b-versatile", "name": "Llama 3.3 70B (Versatile)"},
{"id": "llama-3.1-70b-versatile", "name": "Llama 3.1 70B (Versatile)"},
{"id": "llama-3.1-8b-instant", "name": "Llama 3.1 8B (Instant)"},
{"id": "mixtral-8x7b-32768", "name": "Mixtral 8x7B"},
{"id": "gemma2-9b-it", "name": "Gemma 2 9B"},
]
return templates.TemplateResponse("groq.html", {
"request": request,
"groq_config": groq_config,
"groq_models": groq_models,
"is_admin": request.cookies.get("username") == "nickpons666"
})
@app.post("/groq/save")
async def save_groq_config(request: Request):
if request.cookies.get("auth") != "ok":
raise HTTPException(status_code=401)
form = await request.form()
api_key = form.get("api_key", "")
model = form.get("model", "llama-3.3-70b-versatile")
rag_url = form.get("rag_url", "http://localhost:8004")
system_prompt = form.get("system_prompt", "")
config = load_config()
if "groq" not in config:
config["groq"] = {}
config["groq"]["api_key"] = api_key
config["groq"]["model"] = model
config["groq"]["rag_url"] = rag_url
import yaml
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.yaml")
with open(config_path, "w") as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
if system_prompt:
from botdiscord.database import set_bot_config
set_bot_config("groq_system_prompt", system_prompt)
from botdiscord.groq_agent import reload_config
reload_config()
return RedirectResponse(url="/groq?saved=1", status_code=status.HTTP_303_SEE_OTHER)
@app.post("/groq/reset-prompt")
async def reset_groq_prompt(request: Request):
if request.cookies.get("auth") != "ok":
raise HTTPException(status_code=401)
from botdiscord.database import set_bot_config
set_bot_config("groq_system_prompt", "")
from botdiscord.groq_agent import reload_config
reload_config()
return RedirectResponse(url="/groq?reset=1", status_code=status.HTTP_303_SEE_OTHER)
@app.post("/groq/test")
async def test_groq_agent(request: Request):
if request.cookies.get("auth") != "ok":
raise HTTPException(status_code=401)
form = await request.form()
test_question = form.get("test_question", "")
if not test_question:
return RedirectResponse(url="/groq?error=no_question", status_code=status.HTTP_303_SEE_OTHER)
from botdiscord.groq_agent import chat_with_rag
try:
result = await chat_with_rag(test_question)
response = result.get("response", "Sin respuesta")
sources = result.get("sources", [])
rag_result = result.get("rag_result", {})
rag_answer = rag_result.get("answer", "") if rag_result else ""
return templates.TemplateResponse("groq.html", {
"request": request,
"groq_config": get_groq_config(),
"groq_models": [
{"id": "llama-3.3-70b-versatile", "name": "Llama 3.3 70B (Versatile)"},
{"id": "llama-3.1-70b-versatile", "name": "Llama 3.1 70B (Versatile)"},
{"id": "llama-3.1-8b-instant", "name": "Llama 3.1 8B (Instant)"},
{"id": "mixtral-8x7b-32768", "name": "Mixtral 8x7B"},
{"id": "gemma2-9b-it", "name": "Gemma 2 9B"},
],
"is_admin": request.cookies.get("username") == "nickpons666",
"test_result": {
"question": test_question,
"response": response,
"sources": sources,
"rag_answer": rag_answer
}
})
except Exception as e:
return templates.TemplateResponse("groq.html", {
"request": request,
"groq_config": get_groq_config(),
"groq_models": [
{"id": "llama-3.3-70b-versatile", "name": "Llama 3.3 70B (Versatile)"},
{"id": "llama-3.1-70b-versatile", "name": "Llama 3.1 70B (Versatile)"},
{"id": "llama-3.1-8b-instant", "name": "Llama 3.1 8B (Instant)"},
{"id": "mixtral-8x7b-32768", "name": "Mixtral 8x7B"},
{"id": "gemma2-9b-it", "name": "Gemma 2 9B"},
],
"is_admin": request.cookies.get("username") == "nickpons666",
"test_error": str(e)
})
if __name__ == "__main__":
import uvicorn
web_config = get_web_config()