Files
cbc2027/services/ai_summary_service.py
renato97 ee8fc183be feat: Sistema CBCFacil completo con cola secuencial
- Implementa ProcessingMonitor singleton para procesamiento secuencial de archivos
- Agrega AI summary service con soporte para MiniMax API
- Agrega PDF generator para resúmenes
- Agrega watchers para monitoreo de carpeta remota
- Mejora sistema de notificaciones Telegram
- Implementa gestión de VRAM para GPU
- Configuración mediante variables de entorno (sin hardcoded secrets)
- .env y transcriptions/ agregados a .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:35:39 +00:00

159 lines
5.4 KiB
Python

"""AI Summary Service using Anthropic/Z.AI API (GLM)."""
import logging
import os
from typing import Optional
import requests
logger = logging.getLogger(__name__)
class AISummaryService:
"""Service for AI-powered text summarization using Anthropic/Z.AI API."""
def __init__(
self,
auth_token: Optional[str] = None,
base_url: Optional[str] = None,
model: Optional[str] = None,
timeout: int = 120,
) -> None:
"""Initialize the AI Summary Service.
Args:
auth_token: API authentication token. Defaults to ANTHROPIC_AUTH_TOKEN env var.
base_url: API base URL. Defaults to ANTHROPIC_BASE_URL env var.
model: Model identifier. Defaults to ANTHROPIC_MODEL env var.
timeout: Request timeout in seconds. Defaults to 120.
"""
self.auth_token = auth_token or os.getenv("ANTHROPIC_AUTH_TOKEN")
# Normalize base_url: remove /anthropic suffix if present
raw_base_url = base_url or os.getenv("ANTHROPIC_BASE_URL")
if raw_base_url and raw_base_url.endswith("/anthropic"):
raw_base_url = raw_base_url[:-len("/anthropic")]
self.base_url = raw_base_url
self.model = model or os.getenv("ANTHROPIC_MODEL", "glm-4")
self.timeout = timeout
self._available = bool(self.auth_token and self.base_url)
if self._available:
logger.info(
"AISummaryService initialized with model=%s, base_url=%s",
self.model,
self.base_url,
)
else:
logger.debug("AISummaryService: no configuration found, running in silent mode")
@property
def is_available(self) -> bool:
"""Check if the service is properly configured."""
return self._available
def summarize(self, text: str, prompt_template: Optional[str] = None) -> str:
"""Summarize the given text using the AI API.
Args:
text: The text to summarize.
prompt_template: Optional custom prompt template. If None, uses default.
Returns:
The summarized text.
Raises:
RuntimeError: If the service is not configured.
requests.RequestException: If the API call fails.
"""
if not self._available:
logger.debug("AISummaryService not configured, returning original text")
return text
default_prompt = "Resume el siguiente texto de manera clara y concisa:"
prompt = prompt_template.format(text=text) if prompt_template else f"{default_prompt}\n\n{text}"
payload = {
"model": self.model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 2048,
"temperature": 0.7,
}
headers = {
"Authorization": f"Bearer {self.auth_token}",
"Content-Type": "application/json",
}
try:
logger.debug("Calling AI API for summarization (text length: %d)", len(text))
response = requests.post(
f"{self.base_url}/v1/chat/completions",
json=payload,
headers=headers,
timeout=self.timeout,
)
response.raise_for_status()
result = response.json()
summary = result.get("choices", [{}])[0].get("message", {}).get("content", "")
logger.info("Summarization completed successfully (output length: %d)", len(summary))
return summary
except requests.Timeout:
logger.error("AI API request timed out after %d seconds", self.timeout)
raise requests.RequestException(f"Request timed out after {self.timeout}s") from None
except requests.RequestException as e:
logger.error("AI API request failed: %s", str(e))
raise
def fix_latex(self, text: str) -> str:
"""Fix LaTeX formatting issues in the given text.
Args:
text: The text containing LaTeX to fix.
Returns:
The text with corrected LaTeX formatting.
"""
if not self._available:
logger.debug("AISummaryService not configured, returning original text")
return text
prompt = (
"Corrige los errores de formato LaTeX en el siguiente texto. "
"Mantén el contenido pero corrige la sintaxis de LaTeX:\n\n"
f"{text}"
)
payload = {
"model": self.model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 4096,
"temperature": 0.3,
}
headers = {
"Authorization": f"Bearer {self.auth_token}",
"Content-Type": "application/json",
}
try:
logger.debug("Calling AI API for LaTeX fixing (text length: %d)", len(text))
response = requests.post(
f"{self.base_url}/v1/chat/completions",
json=payload,
headers=headers,
timeout=self.timeout,
)
response.raise_for_status()
result = response.json()
fixed = result.get("choices", [{}])[0].get("message", {}).get("content", "")
logger.info("LaTeX fixing completed successfully")
return fixed
except requests.RequestException as e:
logger.error("LaTeX fixing failed: %s", str(e))
return text