Agrega transcripción de audio (Whisper) en Telegram y corrige adjuntos en tareas
- Nueva config "whisper" reutilizando /app/ai-config (credenciales/endpoint
validables) y servicio de transcripción compatible con OpenAI/Groq.
- El webhook de Telegram ahora detecta notas de voz/audio, las transcribe
y procesa el texto resultante como si el usuario lo hubiera escrito.
- Fix: subir un archivo adjunto en un comentario de tarea sin escribir
texto era rechazado por el backend ("contenido requerido") aunque el
frontend sí lo permitía.
This commit is contained in:
@@ -177,7 +177,9 @@ func AddComentario(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
contenido := strings.TrimSpace(c.FormValue("contenido"))
|
||||
if contenido == "" {
|
||||
file, fileErr := c.FormFile("archivo")
|
||||
tieneArchivo := fileErr == nil && file != nil
|
||||
if contenido == "" && !tieneArchivo {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "contenido requerido"})
|
||||
}
|
||||
|
||||
@@ -185,8 +187,7 @@ func AddComentario(c *fiber.Ctx) error {
|
||||
archivosJSON := "[]"
|
||||
|
||||
// archivo adjunto opcional
|
||||
file, fileErr := c.FormFile("archivo")
|
||||
if fileErr == nil && file != nil {
|
||||
if tieneArchivo {
|
||||
if file.Size > 50*1024*1024 {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Máximo 50MB por archivo"})
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -37,6 +38,12 @@ type tgPhotoSize struct {
|
||||
Height int `json:"height"`
|
||||
}
|
||||
|
||||
type tgVoice struct {
|
||||
FileID string `json:"file_id"`
|
||||
Duration int `json:"duration"`
|
||||
MimeType string `json:"mime_type"`
|
||||
}
|
||||
|
||||
type tgMessage struct {
|
||||
MessageID int `json:"message_id"`
|
||||
From tgUser `json:"from"`
|
||||
@@ -45,6 +52,8 @@ type tgMessage struct {
|
||||
Caption string `json:"caption"`
|
||||
Document *tgDocument `json:"document"`
|
||||
Photo []tgPhotoSize `json:"photo"`
|
||||
Voice *tgVoice `json:"voice"`
|
||||
Audio *tgVoice `json:"audio"`
|
||||
}
|
||||
|
||||
type tgUpdate struct {
|
||||
@@ -77,7 +86,8 @@ func TelegramAgentWebhook(c *fiber.Ctx) error {
|
||||
text := strings.TrimSpace(msg.Text)
|
||||
caption := strings.TrimSpace(msg.Caption)
|
||||
hasAttachment := msg.Document != nil || len(msg.Photo) > 0
|
||||
if text == "" && caption == "" && !hasAttachment {
|
||||
hasAudio := msg.Voice != nil || msg.Audio != nil
|
||||
if text == "" && caption == "" && !hasAttachment && !hasAudio {
|
||||
return c.SendStatus(200)
|
||||
}
|
||||
|
||||
@@ -145,6 +155,46 @@ func TelegramAgentWebhook(c *fiber.Ctx) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Nota de voz o audio: se descarga, se transcribe con Whisper (config del
|
||||
// módulo "whisper" en /app/ai-config) y el texto resultante se procesa como
|
||||
// si el usuario lo hubiera escrito.
|
||||
if hasAudio {
|
||||
voice := msg.Voice
|
||||
if voice == nil {
|
||||
voice = msg.Audio
|
||||
}
|
||||
fileName := "audio.ogg"
|
||||
mimeType := voice.MimeType
|
||||
path, dlErr := services.DescargarDocumentoTelegram(tgCfg.BotToken, voice.FileID, fileName, mimeType)
|
||||
if dlErr != nil {
|
||||
log.Printf("[AGENT_WEBHOOK] Error descargando audio: %v", dlErr)
|
||||
sendAgentReply(tgCfg.BotToken, chatID, "No pude descargar el audio que enviaste, intenta de nuevo.")
|
||||
return c.SendStatus(200)
|
||||
}
|
||||
defer os.Remove(path)
|
||||
|
||||
whisperCfg, wErr := models.GetWhisperConfig()
|
||||
if wErr != nil {
|
||||
log.Printf("[AGENT_WEBHOOK] Whisper no configurado: %v", wErr)
|
||||
sendAgentReply(tgCfg.BotToken, chatID, "No pude transcribir el audio: no hay ninguna configuración de Whisper activa. Ve a /app/ai-config, crea o edita una config con módulo 'Transcripción de audio (Whisper)' y credenciales válidas de OpenAI o Groq.")
|
||||
return c.SendStatus(200)
|
||||
}
|
||||
|
||||
transcripcion, tErr := services.TranscribirAudio(whisperCfg, path)
|
||||
if tErr != nil {
|
||||
log.Printf("[AGENT_WEBHOOK] Error transcribiendo audio: %v", tErr)
|
||||
sendAgentReply(tgCfg.BotToken, chatID, fmt.Sprintf("No pude transcribir el audio: %s", tErr.Error()))
|
||||
return c.SendStatus(200)
|
||||
}
|
||||
log.Printf("[AGENT_WEBHOOK] Audio transcrito (chat %d): %s", chatID, transcripcion)
|
||||
|
||||
if caption != "" {
|
||||
text = transcripcion + " " + caption
|
||||
} else {
|
||||
text = transcripcion
|
||||
}
|
||||
}
|
||||
|
||||
// Procesar en goroutine para responder 200 inmediatamente a Telegram
|
||||
go func() {
|
||||
response, err := services.ProcessAgentMessage(chatID, text, ai)
|
||||
|
||||
Reference in New Issue
Block a user