feat: leer el contenido real del documento adjunto con Claude

Antes solo se avisaba en texto "llegó un documento" — la IA nunca veía el
archivo, por eso siempre tenía que preguntar cliente y monto. Ahora, cuando
el proveedor activo es Anthropic, se le adjunta la imagen/PDF real (base64)
al mensaje para que Claude lo lea directamente y extraiga cliente, monto y
número de factura, llamando a adjuntar_factura sin pedir confirmación salvo
que de verdad no pueda determinar cliente o monto.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Lizandro GD
2026-08-03 02:01:12 +00:00
co-authored by Claude Sonnet 5
parent b292d98cf6
commit cd0ca6d232
2 changed files with 91 additions and 9 deletions
@@ -7,6 +7,7 @@ import (
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
@@ -100,3 +101,38 @@ func PopFacturaAttachment(chatID int64) (*FacturaAttachment, bool) {
}
return a, true
}
// PeekFacturaAttachment consulta el archivo pendiente de un chat sin removerlo
// (se usa para leer su contenido y pasárselo al modelo antes de que la tool
// adjuntar_factura lo consuma de verdad).
func PeekFacturaAttachment(chatID int64) (*FacturaAttachment, bool) {
facturaAttachmentsMu.Lock()
defer facturaAttachmentsMu.Unlock()
a, ok := facturaAttachments[chatID]
if !ok || time.Since(a.StagedAt) > facturaAttachmentTTL {
return nil, false
}
return a, true
}
// ResolverMimeType usa el mime_type que mandó Telegram si vino, y si no,
// adivina por la extensión del archivo (Claude solo acepta ciertos tipos).
func ResolverMimeType(mimeType, filename string) string {
if mimeType != "" {
return mimeType
}
switch strings.ToLower(filepath.Ext(filename)) {
case ".pdf":
return "application/pdf"
case ".jpg", ".jpeg":
return "image/jpeg"
case ".png":
return "image/png"
case ".webp":
return "image/webp"
case ".gif":
return "image/gif"
default:
return "application/octet-stream"
}
}