From 46a0403b0fa5fbbcd04aeaac19b418b90598dfaf Mon Sep 17 00:00:00 2001 From: DBT Date: Sat, 28 Feb 2026 02:49:13 +0000 Subject: [PATCH] media abstraction: add structured MediaItem model and expose media-source audit in task queue detail --- pkg/agent/loop.go | 2 ++ pkg/bus/types.go | 9 ++++++++ pkg/channels/base.go | 42 +++++++++++++++++++++++++++++++++++ webui/src/i18n/index.ts | 2 ++ webui/src/pages/TaskAudit.tsx | 16 +++++++++++++ 5 files changed, 71 insertions(+) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 7145ae5..0322ae1 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -374,6 +374,8 @@ func (al *AgentLoop) appendTaskAuditEvent(taskID string, msg bus.InboundMessage, "retry_count": 0, "log": logText, "input_preview": truncate(strings.ReplaceAll(msg.Content, "\n", " "), 180), + "media_count": len(msg.MediaItems), + "media_items": msg.MediaItems, } b, _ := json.Marshal(row) f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) diff --git a/pkg/bus/types.go b/pkg/bus/types.go index ae82ae9..0abf323 100644 --- a/pkg/bus/types.go +++ b/pkg/bus/types.go @@ -1,11 +1,20 @@ package bus +type MediaItem struct { + Source string `json:"source,omitempty"` + Type string `json:"type,omitempty"` + Ref string `json:"ref,omitempty"` + Path string `json:"path,omitempty"` + Channel string `json:"channel,omitempty"` +} + type InboundMessage struct { Channel string `json:"channel"` SenderID string `json:"sender_id"` ChatID string `json:"chat_id"` Content string `json:"content"` Media []string `json:"media,omitempty"` + MediaItems []MediaItem `json:"media_items,omitempty"` SessionKey string `json:"session_key"` Metadata map[string]string `json:"metadata,omitempty"` } diff --git a/pkg/channels/base.go b/pkg/channels/base.go index 16822ea..53c1101 100644 --- a/pkg/channels/base.go +++ b/pkg/channels/base.go @@ -3,6 +3,7 @@ package channels import ( "context" "fmt" + "path/filepath" "strings" "sync/atomic" @@ -96,6 +97,7 @@ func (c *BaseChannel) HandleMessage(senderID, chatID, content string, media []st ChatID: chatID, Content: content, Media: media, + MediaItems: toMediaItems(c.name, media), Metadata: metadata, SessionKey: sessionKey, } @@ -103,6 +105,46 @@ func (c *BaseChannel) HandleMessage(senderID, chatID, content string, media []st c.bus.PublishInbound(msg) } +func toMediaItems(channel string, media []string) []bus.MediaItem { + if len(media) == 0 { + return nil + } + out := make([]bus.MediaItem, 0, len(media)) + for _, m := range media { + item := bus.MediaItem{Channel: channel, Ref: m, Source: "raw", Type: "unknown"} + switch { + case strings.HasPrefix(m, "feishu:image:"): + item.Source = "feishu" + item.Type = "image" + case strings.HasPrefix(m, "feishu:file:"): + item.Source = "feishu" + item.Type = "file" + case strings.HasPrefix(m, "telegram:"): + item.Source = "telegram" + item.Type = "remote" + case strings.HasPrefix(m, "http://") || strings.HasPrefix(m, "https://"): + item.Source = "url" + item.Type = "remote" + default: + ext := strings.ToLower(filepath.Ext(m)) + item.Path = m + switch ext { + case ".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp": + item.Type = "image" + case ".mp4", ".mov", ".webm", ".avi": + item.Type = "video" + case ".mp3", ".wav", ".ogg", ".m4a": + item.Type = "audio" + default: + item.Type = "file" + } + item.Source = "local" + } + out = append(out, item) + } + return out +} + func (c *BaseChannel) setRunning(running bool) { c.running.Store(running) } diff --git a/webui/src/i18n/index.ts b/webui/src/i18n/index.ts index faa8296..ea410b5 100644 --- a/webui/src/i18n/index.ts +++ b/webui/src/i18n/index.ts @@ -18,6 +18,7 @@ const resources = { taskDetail: 'Task Detail', taskQueue: 'Task Queue', taskLogs: 'Task Logs', + mediaSources: 'Media Sources', error: 'Error', noTaskAudit: 'No task audit records', selectTask: 'Select a task from the left list', @@ -170,6 +171,7 @@ const resources = { taskDetail: '任务详情', taskQueue: '任务队列', taskLogs: '任务日志', + mediaSources: '媒体来源', error: '错误', noTaskAudit: '暂无任务审计记录', selectTask: '请从左侧选择任务', diff --git a/webui/src/pages/TaskAudit.tsx b/webui/src/pages/TaskAudit.tsx index f22d3c1..5d6d9f7 100644 --- a/webui/src/pages/TaskAudit.tsx +++ b/webui/src/pages/TaskAudit.tsx @@ -15,6 +15,7 @@ type TaskAuditItem = { error?: string; input_preview?: string; logs?: string[]; + media_items?: Array<{ source?: string; type?: string; ref?: string; path?: string; channel?: string }>; [key: string]: any; }; @@ -110,6 +111,21 @@ const TaskAudit: React.FC = () => {
{Array.isArray(selected.logs) && selected.logs.length ? selected.logs.join('\n') : '-'}
+
+
{t('mediaSources')}
+
+ {Array.isArray(selected.media_items) && selected.media_items.length > 0 ? ( +
+ {selected.media_items.map((m, i) => ( +
+ [{m.channel || '-'}] {m.source || '-'} / {m.type || '-'} · {m.path || m.ref || '-'} +
+ ))} +
+ ) : '-'} +
+
+
{t('rawJson')}
{selectedPretty}