Files
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

149 lines
4.2 KiB
Go

package vision
import (
"context"
"fmt"
"git.yeij.top/AskaEth/Cyrene_v2/pkg/plugins/sdk"
)
// toolParameters 返回视觉工具与 OCR 工具共用的输入 JSON Schema。
// 它每次调用都新建一个 map,而不是共享包级
// 变量。
func toolParameters() map[string]any {
return map[string]any{
"type": "object",
"properties": map[string]any{
"image": map[string]any{
"type": "string",
"description": "The image: a local path, an http(s) URL, or a base64/data: URI.",
},
"prompt": map[string]any{
"type": "string",
"description": "Optional instruction for the vision model (vision tool only).",
},
},
"required": []any{"image"},
}
}
// VisionTool 把 VisionAdapter 包装成 sdk.Tool,使 M2 工具循环能调用
// 它并把描述作为工具结果返回,从而让图像不进入
// 主模型上下文。它可安全并发使用。
type VisionTool struct {
name string
adapter VisionAdapter
}
// NewVisionTool 用给定名字与适配器构造一个 VisionTool。
func NewVisionTool(name string, adapter VisionAdapter) *VisionTool {
return &VisionTool{name: name, adapter: adapter}
}
// Name 返回智能体用来调用该工具的工具标识。
func (t *VisionTool) Name() string { return t.name }
// Description 说明该工具做什么。
func (t *VisionTool) Description() string {
return "Understand an image and return a description of its contents."
}
// Parameters 返回输入 JSON Schema。
func (t *VisionTool) Parameters() (map[string]any, error) {
return toolParameters(), nil
}
// Execute 对 args 中的图像运行适配器并返回描述。
func (t *VisionTool) Execute(ctx context.Context, args any) (any, error) {
image, prompt, err := toolArgs(args)
if err != nil {
return nil, err
}
ref, err := ParseImageRef(image)
if err != nil {
return nil, err
}
desc, err := t.adapter.Describe(ctx, ref, prompt)
if err != nil {
return nil, err
}
return map[string]any{"description": desc}, nil
}
// OCRTool 把 OCRAdapter 包装成 sdk.Tool。它把抽取出的文字作为
// 工具结果返回。它可安全并发使用。
type OCRTool struct {
name string
adapter OCRAdapter
}
// NewOCRTool 用给定名字与适配器构造一个 OCRTool。
func NewOCRTool(name string, adapter OCRAdapter) *OCRTool {
return &OCRTool{name: name, adapter: adapter}
}
// Name 返回工具标识。
func (t *OCRTool) Name() string { return t.name }
// Description 说明该工具做什么。
func (t *OCRTool) Description() string {
return "Extract text from an image (OCR) and return the recognized text."
}
// Parameters 返回输入 JSON Schema。
func (t *OCRTool) Parameters() (map[string]any, error) {
return toolParameters(), nil
}
// Execute 对 args 中的图像运行 OCR 适配器并返回文字。
func (t *OCRTool) Execute(ctx context.Context, args any) (any, error) {
image, _, err := toolArgs(args)
if err != nil {
return nil, err
}
ref, err := ParseImageRef(image)
if err != nil {
return nil, err
}
text, err := t.adapter.Extract(ctx, ref)
if err != nil {
return nil, err
}
return map[string]any{"text": text}, nil
}
// RegisterTools 经 SDK 辅助函数把视觉工具与 OCR 工具注册到 r。
// 每个工具仅在其指针非 nil 时注册。它返回
// 第一个注册错误;全部注册成功时返回 nil。
func RegisterTools(r sdk.Registrar, tool *VisionTool, ocr *OCRTool) error {
if r == nil {
return sdk.ErrNilRegistrar
}
if tool != nil {
if err := sdk.RegisterTool(r, tool); err != nil {
return fmt.Errorf("vision: register tool %q: %w", tool.Name(), err)
}
}
if ocr != nil {
if err := sdk.RegisterTool(r, ocr); err != nil {
return fmt.Errorf("vision: register tool %q: %w", ocr.Name(), err)
}
}
return nil
}
// toolArgs 把 sdk.Tool.Execute 的 args 解码为图像字符串与一个可选的
// prompt。args 必须是含非空 "image" 字符串的 map[string]any。
func toolArgs(args any) (image, prompt string, err error) {
m, ok := args.(map[string]any)
if !ok {
return "", "", fmt.Errorf("vision: %w: args must be an object", ErrBadArgs)
}
image, _ = m["image"].(string)
if image == "" {
return "", "", fmt.Errorf("vision: %w: missing image", ErrBadArgs)
}
prompt, _ = m["prompt"].(string)
return image, prompt, nil
}