ai/chatgpt improved

This commit is contained in:
teraflops 2025-06-08 13:19:11 +02:00
parent 252e76ce0c
commit 20d09cd1a2
2 changed files with 149 additions and 178 deletions

View File

@ -1,221 +1,90 @@
import requests import requests
import logging
import re
import os import os
import re
from datetime import datetime from datetime import datetime
# Configuración de logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("AI-Plugin")
# Variables de entorno necesarias
HUGGINGFACE_API_KEY = os.getenv("HUGGINGFACE_API_KEY") HUGGINGFACE_API_KEY = os.getenv("HUGGINGFACE_API_KEY")
BRAVE_API_KEY = os.getenv("BRAVE_API_KEY") BRAVE_API_KEY = os.getenv("BRAVE_API_KEY")
MODEL_ID = os.getenv("HUGGINGFACE_MODEL", "deepseek/deepseek-v3-0324") MODEL_ID = os.getenv("HUGGINGFACE_MODEL", "deepseek/deepseek-v3-0324")
# Endpoints
HF_API_URL = "https://router.huggingface.co/novita/v3/openai/chat/completions" HF_API_URL = "https://router.huggingface.co/novita/v3/openai/chat/completions"
BRAVE_URL = "https://api.search.brave.com/res/v1/web/search" BRAVE_URL = "https://api.search.brave.com/res/v1/web/search"
# Headers
HEADERS_HF = { HEADERS_HF = {
"Authorization": f"Bearer {HUGGINGFACE_API_KEY}", "Authorization": f"Bearer {HUGGINGFACE_API_KEY}",
"Content-Type": "application/json" "Content-Type": "application/json"
} }
HEADERS_BRAVE = { HEADERS_BRAVE = {
"Accept": "application/json", "Accept": "application/json",
"X-Subscription-Token": BRAVE_API_KEY "X-Subscription-Token": BRAVE_API_KEY
} }
def buscar_en_brave(consulta, max_results=3):
def respuesta_desactualizada(texto): params = {"q": consulta, "count": max_results, "safesearch": "moderate"}
"""Detecta si la respuesta contiene fechas antiguas en relación al mes/año actual.""" try:
texto = texto.lower() res = requests.get(BRAVE_URL, headers=HEADERS_BRAVE, params=params, timeout=10)
ahora = datetime.now() res.raise_for_status()
data = res.json()
# Lista de años pasados (2020 hasta el año anterior) resultados = data.get("web", {}).get("results", [])
anyos_pasados = [str(a) for a in range(2020, ahora.year)] return [
if any(a in texto for a in anyos_pasados): f"{r.get('title', '').strip()}: {r.get('description', '').strip()}"
return True for r in resultados if r.get("description")
]
# Lista de meses pasados del mismo año (enero - mes anterior) except Exception as e:
meses_ordenados = [ return [f"⚠️ Error al consultar Brave: {e}"]
"enero", "febrero", "marzo", "abril", "mayo", "junio",
"julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"
]
mes_actual_idx = ahora.month - 1
meses_pasados = meses_ordenados[:mes_actual_idx]
for mes in meses_pasados:
if f"{mes} de {ahora.year}" in texto:
return True
return False
def sanitize_response(text, remove_first_line=True): def inferir_con_huggingface(pregunta, resultados_web=None):
"""Limpia etiquetas HTML y fragmentos redundantes."""
clean_text = re.sub(r"<.*?>", "", text)
clean_text = re.sub(r"&quot;", '"', clean_text)
clean_text = re.sub(r"&amp;", "&", clean_text)
clean_text = clean_text.strip()
instrucciones_a_eliminar = [
"Resume y humaniza esta información en lenguaje natural:",
"Responde en español:",
"A continuación tienes un conjunto de textos o fragmentos sacados de sitios web. Tu tarea es analizarlos, eliminar información redundante o poco útil, y resumir todo en un único párrafo claro y natural para un humano. No repitas los títulos ni hagas listas. Explica como si le contaras a un amigo:"
]
for instruccion in instrucciones_a_eliminar:
if clean_text.lower().startswith(instruccion.lower()):
clean_text = clean_text[len(instruccion):].strip()
return clean_text
def query_huggingface(prompt, is_humanization=False):
"""Consulta el modelo DeepSeek en Hugging Face Router."""
if not HUGGINGFACE_API_KEY: if not HUGGINGFACE_API_KEY:
logger.error("No se ha definido la variable HUGGINGFACE_API_KEY.") return "⚠️ Falta la variable HUGGINGFACE_API_KEY."
return None
# Incluir fecha real en el prompt del usuario fecha_actual = datetime.now().strftime("%d de %B de %Y")
fecha_actual = datetime.now().strftime("%d de %B de %Y") # ej: "11 de abril de 2025"
prompt_con_fecha = f"Hoy es {fecha_actual}. {prompt.strip()}"
# Prompt de sistema personalizado system_prompt = (
if is_humanization: "Eres un asistente útil que responde siempre en español claro y natural. "
system_prompt = ( "Responde con base únicamente en los datos proporcionados. Si no hay información clara, di que no puedes confirmarlo."
"Tu tarea es analizar fragmentos de sitios web y resumir la información relevante " )
"en un único párrafo claro, sin repetir títulos ni hacer listas. Sé directo, preciso y "
"habla como si lo explicaras a un amigo en español." user_prompt = f"Fecha actual: {fecha_actual}.\nPregunta: {pregunta}"
)
else: if resultados_web:
system_prompt = ( contexto = "\n".join(f"{i+1}. {r}" for i, r in enumerate(resultados_web))
"Eres un asistente útil que siempre responde en español. " user_prompt += f"\n\nResultados web:\n{contexto}"
"Ignora nombres de usuario como 'teraflops'. "
"Si no conoces información actualizada a la fecha de hoy, indica que no estás seguro. "
"No inventes datos si no los sabes."
)
payload = { payload = {
"model": MODEL_ID, "model": MODEL_ID,
"messages": [ "messages": [
{"role": "system", "content": system_prompt}, {"role": "system", "content": system_prompt},
{"role": "user", "content": prompt_con_fecha} {"role": "user", "content": user_prompt}
], ],
"temperature": 0.7, "temperature": 0.7,
"max_tokens": 300 "max_tokens": 400
} }
try: try:
response = requests.post(HF_API_URL, headers=HEADERS_HF, json=payload, timeout=120) res = requests.post(HF_API_URL, headers=HEADERS_HF, json=payload, timeout=60)
response.raise_for_status() res.raise_for_status()
content = response.json()["choices"][0]["message"]["content"] return res.json()["choices"][0]["message"]["content"].strip()
logger.info(f"[DEBUG] Respuesta cruda de Hugging Face:\n{content}") except Exception as e:
return sanitize_response(content) return f"⚠️ Error al consultar Hugging Face: {e}"
except requests.exceptions.RequestException as e:
logger.error(f"[ERROR] Fallo al conectar con Hugging Face: {e}")
return None
def buscar_en_brave(consulta):
"""Consulta Brave Search y decide si humanizar o mostrar mensaje de fallback."""
if not BRAVE_API_KEY:
logger.error("No se ha definido la variable BRAVE_API_KEY.")
return None
params = {"q": consulta, "count": 3, "safesearch": "moderate"}
try:
logger.info(f"[DEBUG] Consultando Brave Search con: {consulta}")
response = requests.get(BRAVE_URL, headers=HEADERS_BRAVE, params=params, timeout=30)
response.raise_for_status()
data = response.json()
resultados = data.get("web", {}).get("results", [])
if not resultados:
logger.warning("Brave no devolvió resultados.")
return "No encontré información relevante en Brave Search."
informacion_bruta = "\n".join(
f"{res.get('title', 'Sin título')}: {res.get('description', 'Sin descripción')}"
for res in resultados
)
logger.info(f"[DEBUG] Resultados de Brave crudos:\n{informacion_bruta}")
# Palabras clave genéricas que suelen indicar contenido útil
palabras_utiles = [
"2025", "abril", "marzo", "versión", "version", "released", "linux",
"resultado", "marcador", "gol", "victoria", "derrota", "ganó", "1-0", "2-1",
"empate", "directo", "esta noche", "hoy", "final", "resumen", "publicado",
"disponible", "estreno", "actualización", "presentación", "valencia", "sevilla"
]
texto_brave = informacion_bruta.lower()
pistas_utiles = any(p in texto_brave for p in palabras_utiles)
if not pistas_utiles:
logger.info("[DEBUG] Brave devolvió resultados ambiguos.")
return (
"📡 Brave Search encontró resultados poco claros. "
"No se halló información confirmada. Puedes revisar sitios oficiales para más detalles."
)
# Si hay contenido con pistas útiles, lo pasamos a Hugging Face para humanizar
resumen = query_huggingface(sanitize_response(informacion_bruta), is_humanization=True)
return resumen
except requests.exceptions.RequestException as e:
logger.error(f"[ERROR] Fallo en Brave Search: {e}")
return None
def procesar_consulta(prompt): def procesar_consulta(prompt):
"""Intenta responder usando HF, y si falla, pregunta a Brave.""" resultados = buscar_en_brave(prompt)
logger.info(f"[DEBUG] ⏳ Consultando Hugging Face con: {prompt}") respuesta = inferir_con_huggingface(prompt, resultados if resultados else None)
respuesta_hf = query_huggingface(prompt)
if not respuesta_hf:
return "No se obtuvo respuesta de Hugging Face."
patron_generica = re.compile(
r"(no hay información.*?|"
r"no tengo.*?información|"
r"consulta.*?sitios? web oficiales|"
r"aún no se ha anunciado|"
r"lo siento, pero no puedo responder a eso|"
r"no tengo suficiente información|"
r"no puedo proporcionar esa información|"
r"te recomiendo verificar fuentes oficiales)",
re.IGNORECASE
)
# 🔧 Este bloque estaba fuera de la función — lo metemos correctamente dentro
if patron_generica.search(respuesta_hf) or respuesta_desactualizada(respuesta_hf):
logger.info("[DEBUG] Hugging Face dio respuesta genérica o desactualizada, consultando Brave...")
respuesta_brave = buscar_en_brave(prompt)
return f"📡 Fuente: Brave Search\n{respuesta_brave or 'No se encontró información útil.'}"
return f"🧠 Fuente: Hugging Face\n{respuesta_hf}"
def run(sender, *args):
"""Manejador del comando .ai"""
if not args:
return "Por favor, proporciona una consulta."
consulta = " ".join(args).strip()
logger.info(f"[.ai] Procesando consulta: {consulta}")
respuesta = procesar_consulta(consulta)
return respuesta or "No se encontró información disponible." return respuesta or "No se encontró información disponible."
def help(): def run(sender, *args):
return "Uso: .ai <pregunta> - Responde con IA usando Hugging Face y Brave Search si es necesario." if not args:
return "Uso: .ai <pregunta>"
consulta = " ".join(args).strip()
return procesar_consulta(consulta)
def help():
return "Uso: .ai <pregunta> - Responde con Hugging Face y contexto de Brave Search si es necesario."

102
plugins/chatgpt.py Normal file
View File

@ -0,0 +1,102 @@
import requests
import os
import re
from datetime import datetime
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
BRAVE_API_KEY = os.getenv("BRAVE_API_KEY")
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o")
OPENAI_API_URL = "https://api.openai.com/v1/chat/completions"
BRAVE_URL = "https://api.search.brave.com/res/v1/web/search"
HEADERS_OPENAI = {
"Authorization": f"Bearer {OPENAI_API_KEY}",
"Content-Type": "application/json"
}
HEADERS_BRAVE = {
"Accept": "application/json",
"X-Subscription-Token": BRAVE_API_KEY
}
def buscar_en_brave(consulta, max_results=3):
"""Busca en Brave Search y devuelve los mejores resultados web."""
params = {"q": consulta, "count": max_results, "safesearch": "moderate"}
try:
res = requests.get(BRAVE_URL, headers=HEADERS_BRAVE, params=params, timeout=10)
res.raise_for_status()
data = res.json()
resultados = data.get("web", {}).get("results", [])
return [
f"{r.get('title', '').strip()}: {r.get('description', '').strip()}"
for r in resultados if r.get("description")
]
except Exception as e:
return [f"⚠️ Error al consultar Brave: {e}"]
def inferir_con_openai(pregunta, resultados_web=None):
"""Genera una respuesta usando OpenAI, con contexto opcional."""
fecha_actual = datetime.now().strftime("%d de %B de %Y")
system_prompt = (
"Eres un asistente que responde preguntas basándote en resultados web proporcionados. "
"Debes analizar cuidadosamente si hay suficiente información para confirmar una respuesta. "
"Si encuentras frases como 'X ganó Y', 'X venció a Y', 'X es campeón', considera que eso es suficiente para afirmar el resultado, "
"siempre que provenga de una fuente confiable. "
"Si los resultados son vagos o contradictorios, di que no puedes confirmarlo aún."
)
user_prompt = f"Fecha actual: {fecha_actual}.\nPregunta: {pregunta}"
if resultados_web:
contexto = "\n".join(f"{i+1}. {r}" for i, r in enumerate(resultados_web))
user_prompt += f"\n\nResultados web:\n{contexto}"
payload = {
"model": OPENAI_MODEL,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
"temperature": 0.7,
"max_tokens": 400
}
try:
res = requests.post(OPENAI_API_URL, headers=HEADERS_OPENAI, json=payload, timeout=60)
res.raise_for_status()
return res.json()["choices"][0]["message"]["content"].strip()
except Exception as e:
return f"⚠️ Error al consultar OpenAI: {e}"
def procesar_consulta(prompt):
"""Busca en Brave y deja que OpenAI razone libremente con esos resultados."""
resultados = buscar_en_brave(prompt)
# Aunque no haya resultados útiles, seguimos con OpenAI para que juzgue
respuesta = inferir_con_openai(prompt, resultados if resultados else None)
return respuesta or "No se encontró información disponible."
def help():
return (
"Uso: .chatgpt <pregunta>\n"
"Consulta la IA de OpenAI con contexto de Brave Search si está disponible.\n"
"Ejemplo: .chatgpt ¿Quién ganó la Champions League 2025?"
)
def run(sender, *args):
if not args:
return "Uso: .ai <pregunta>"
consulta = " ".join(args).strip()
return procesar_consulta(consulta)