feat: registrar proyectos con fases, adjuntar documentos y asignar tareas por Telegram
- crear_fase_proyecto: agrega fases/etapas a un proyecto (se puede llamar varias veces seguidas para cargar todas las fases de un proyecto nuevo). - adjuntar_documento_proyecto: guarda el archivo que el usuario acaba de enviar por Telegram como documento del proyecto (mismo mecanismo de adjuntos ya usado para facturas — se generalizó TelegramAttachment para servir a ambos casos). - listar_usuarios + asignado_id en crear_tarea + asignar_tarea: permite asignar tareas a alguien del equipo por Telegram, disparando la misma notificación (Telegram/email/sistema) que ya dispara el dashboard. - El prompt del sistema ahora indica cómo decidir entre adjuntar_factura y adjuntar_documento_proyecto según el contexto del archivo recibido. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
cd0ca6d232
commit
a0b2e9ae0a
@@ -12,20 +12,21 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// FacturaAttachment es un archivo que un usuario envió por Telegram y que queda
|
||||
// "pendiente" hasta que el agente lo asocie a una factura (o expire).
|
||||
type FacturaAttachment struct {
|
||||
// TelegramAttachment es un archivo que un usuario envió por Telegram y que queda
|
||||
// "pendiente" hasta que el agente lo asocie a una factura o a un documento de
|
||||
// proyecto (o expire).
|
||||
type TelegramAttachment struct {
|
||||
Path string
|
||||
OriginalName string
|
||||
MimeType string
|
||||
StagedAt time.Time
|
||||
}
|
||||
|
||||
const facturaAttachmentTTL = 15 * time.Minute
|
||||
const telegramAttachmentTTL = 15 * time.Minute
|
||||
|
||||
var (
|
||||
facturaAttachmentsMu sync.Mutex
|
||||
facturaAttachments = map[int64]*FacturaAttachment{}
|
||||
telegramAttachmentsMu sync.Mutex
|
||||
telegramAttachments = map[int64]*TelegramAttachment{}
|
||||
)
|
||||
|
||||
// DescargarDocumentoTelegram descarga un archivo de Telegram (por file_id) usando
|
||||
@@ -75,41 +76,42 @@ func DescargarDocumentoTelegram(botToken, fileID, originalName, mimeType string)
|
||||
return localPath, nil
|
||||
}
|
||||
|
||||
// StageFacturaAttachment registra un archivo ya descargado como pendiente para el
|
||||
// chat, a la espera de que el agente lo asocie a una factura con la tool adjuntar_factura.
|
||||
func StageFacturaAttachment(chatID int64, path, originalName, mimeType string) {
|
||||
facturaAttachmentsMu.Lock()
|
||||
defer facturaAttachmentsMu.Unlock()
|
||||
facturaAttachments[chatID] = &FacturaAttachment{
|
||||
// StageTelegramAttachment registra un archivo ya descargado como pendiente para el
|
||||
// chat, a la espera de que el agente lo asocie a algo (adjuntar_factura o
|
||||
// adjuntar_documento_proyecto).
|
||||
func StageTelegramAttachment(chatID int64, path, originalName, mimeType string) {
|
||||
telegramAttachmentsMu.Lock()
|
||||
defer telegramAttachmentsMu.Unlock()
|
||||
telegramAttachments[chatID] = &TelegramAttachment{
|
||||
Path: path, OriginalName: originalName, MimeType: mimeType, StagedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// PopFacturaAttachment retorna y remueve el archivo pendiente de un chat, si
|
||||
// PopTelegramAttachment retorna y remueve el archivo pendiente de un chat, si
|
||||
// existe y no expiró (si expiró, borra el archivo temporal del disco).
|
||||
func PopFacturaAttachment(chatID int64) (*FacturaAttachment, bool) {
|
||||
facturaAttachmentsMu.Lock()
|
||||
defer facturaAttachmentsMu.Unlock()
|
||||
a, ok := facturaAttachments[chatID]
|
||||
func PopTelegramAttachment(chatID int64) (*TelegramAttachment, bool) {
|
||||
telegramAttachmentsMu.Lock()
|
||||
defer telegramAttachmentsMu.Unlock()
|
||||
a, ok := telegramAttachments[chatID]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
delete(facturaAttachments, chatID)
|
||||
if time.Since(a.StagedAt) > facturaAttachmentTTL {
|
||||
delete(telegramAttachments, chatID)
|
||||
if time.Since(a.StagedAt) > telegramAttachmentTTL {
|
||||
_ = os.Remove(a.Path)
|
||||
return nil, false
|
||||
}
|
||||
return a, true
|
||||
}
|
||||
|
||||
// PeekFacturaAttachment consulta el archivo pendiente de un chat sin removerlo
|
||||
// PeekTelegramAttachment 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 {
|
||||
func PeekTelegramAttachment(chatID int64) (*TelegramAttachment, bool) {
|
||||
telegramAttachmentsMu.Lock()
|
||||
defer telegramAttachmentsMu.Unlock()
|
||||
a, ok := telegramAttachments[chatID]
|
||||
if !ok || time.Since(a.StagedAt) > telegramAttachmentTTL {
|
||||
return nil, false
|
||||
}
|
||||
return a, true
|
||||
|
||||
Reference in New Issue
Block a user