package engine // norm_image_validator.go -- 验证消息中的图片块不超过 API 尺寸限制. // // 来源:新增步骤,早期方案 normalize 未处理. // 场景:超大图片自动剥离(带替代文本). // 跨场景通用:仓储操作员拍的高清照片常超限; // 法律文件的扫描件也可能过大. import ( "fmt" "git.flytoex.net/yuanwei/flyto-agent/pkg/query" ) // DefaultMaxImageSizeBytes 默认图片大小限制:20MB. // Anthropic API 限制为 20MB(base64 编码后). const DefaultMaxImageSizeBytes int64 = 20 * 1024 * 1024 // ImageValidator 验证并处理超大图片块. // // 精妙之处(CLEVER): 不直接删除超大图片,而是替换为文本提示. // 这样模型知道"这里原来有一张图",可以据此做出合理回应 // (比如让用户重新上传小一点的版本),而不是莫名其妙地丢失信息. type ImageValidator struct { // MaxSizeBytes 图片大小限制(字节).如果为 0,使用默认值. MaxSizeBytes int64 } func (v *ImageValidator) Name() string { return "image_validator" } func (v *ImageValidator) Priority() int { return 50 } func (v *ImageValidator) maxSize() int64 { if v.MaxSizeBytes > 0 { return v.MaxSizeBytes } return DefaultMaxImageSizeBytes } func (v *ImageValidator) Normalize(messages []query.Message) []query.Message { if len(messages) == 0 { return messages } maxSize := v.maxSize() result := make([]query.Message, 0, len(messages)) for _, msg := range messages { modified := false newContent := make([]query.Content, 0, len(msg.Content)) for _, c := range msg.Content { if c.Type == query.ContentImage && c.SizeBytes > maxSize { // 超大图片替换为文本提示 newContent = append(newContent, query.Content{ Type: query.ContentText, Text: fmt.Sprintf( "[image removed: size %s exceeds limit %s]", formatBytes(c.SizeBytes), formatBytes(maxSize), ), }) modified = true } else { newContent = append(newContent, c) } } if modified { result = append(result, query.Message{ Role: msg.Role, Content: newContent, Time: msg.Time, Metadata: msg.Metadata, }) } else { result = append(result, msg) } } return result } // formatBytes 格式化字节数为人类可读形式. func formatBytes(b int64) string { const ( kb = 1024 mb = 1024 * kb gb = 1024 * mb ) switch { case b >= gb: return fmt.Sprintf("%.1fGB", float64(b)/float64(gb)) case b >= mb: return fmt.Sprintf("%.1fMB", float64(b)/float64(mb)) case b >= kb: return fmt.Sprintf("%.1fKB", float64(b)/float64(kb)) default: return fmt.Sprintf("%dB", b) } }