Files
Cyrene_v2/internal/runtime/multimodal/vision/vision.go
T
AskaEth b0fbb8bc0d
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(comments): 注释中文化 · internal/runtime/multimodal(21 文件,纯替换)
- 只翻注释/文档字符串,代码零变化:go/scanner 词法流比对 21 文件 token+字面量全等,增删行数 1:1(467/467)
- 刻意保留非散文英文:JSON Schema description、工具 Description() 返回值、adapter prompt、API 路径与命令示例、环境变量名
- 逐行确认代码前缀未变,未触碰其他模块
2026-10-04 12:28:16 +08:00

80 lines
2.7 KiB
Go

// Package vision 实现 DevDocs/design/06-多模态.md §0 所述的
// 分层图像路由。
//
// 携带图像内容的请求先由 DetectMultimodal 检查。
// 随后 VisionRouter 选出其中一条分层路由:主模型
// 直连(当它接受图像时)、工具形态的 vision/OCR 适配器(当主模型
// 自评较差或看不见图像时),或 OCR 工具(当
// 图像以文字为主时)。vision/OCR 适配器经能力注册中心
// 注册为 sdk.Tool 能力,其输出即工具
// 结果,因此图像本身从不占用主模型上下文。
//
// 图像可来自本地路径、http(s) URL 或 base64/data: URI。
package vision
import (
"strings"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
)
// DetectMultimodal 报告 msgs 是否含任何非文本内容部件,
// 即是否需要多模态处理。当前 model 只区分
// 文本与图像内容,因此这等价于某条消息携带
// 图像部件;判断写成「非文本」是为了让未来的内容类型
// (音频)无需返工即可扩展。
func DetectMultimodal(msgs []model.Message) bool {
for _, m := range msgs {
for _, part := range m.Content {
if part.Type != model.ContentTypeText {
return true
}
}
}
return false
}
// ImageSource 归类一副图像的字节来自何处。
type ImageSource string
const (
// SourcePath 是本地文件系统路径。
SourcePath ImageSource = "path"
// SourceURL 是 http(s):// URL。
SourceURL ImageSource = "url"
// SourceBase64 是 base64 载荷,可选地包在 data: URI 中。
SourceBase64 ImageSource = "base64"
)
// ImageRef 是单个图像引用及其已归类的来源种类。
type ImageRef struct {
// Source 是归类后的来源种类。
Source ImageSource
// Data 是本地路径、URL 或 base64/data: 载荷。
Data string
}
// ParseImageRef 把原始图像来源字符串归类为 ImageRef。空
// 输入被拒绝。磁盘上存在的本地路径归类为路径;
// http(s) URL 归类为 URL;其余所有值(含 data: URI)都视为
// base64 载荷。这样无需猜测 MIME 即可保持路由确定性。
func ParseImageRef(src string) (ImageRef, error) {
if src == "" {
return ImageRef{}, ErrNoImage
}
if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
return ImageRef{Source: SourceURL, Data: src}, nil
}
if strings.HasPrefix(src, "file://") {
return ImageRef{Source: SourcePath, Data: strings.TrimPrefix(src, "file://")}, nil
}
// data: URI 本身就是 base64;按 base64 处理,而非路径。
if strings.HasPrefix(src, "data:") {
return ImageRef{Source: SourceBase64, Data: src}, nil
}
if fileExists(src) {
return ImageRef{Source: SourcePath, Data: src}, nil
}
return ImageRef{Source: SourceBase64, Data: src}, nil
}