// 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 }