package renderers import ( "encoding/json" "fmt" "strings" "github.com/ollama/ollama/api" ) type GlmOcrRenderer struct { useImgTags bool } func (r *GlmOcrRenderer) renderContent(message api.Message, imageOffset int) (string, int) { var sb strings.Builder for range message.Images { if r.useImgTags { sb.WriteString(fmt.Sprintf("[img-%d]", imageOffset)) imageOffset++ } } sb.WriteString(message.Content) return sb.String(), imageOffset } func (r *GlmOcrRenderer) Render(messages []api.Message, tools []api.Tool, thinkValue *api.ThinkValue) (string, error) { var sb strings.Builder sb.WriteString("[gMASK]") if len(tools) > 0 { sb.WriteString("<|system|>\n") sb.WriteString("# Tools\n\n") sb.WriteString("You may call one or more functions to assist with the user query.\n\n") sb.WriteString("You are provided with function signatures within XML tags:\n") sb.WriteString("\n") for _, tool := range tools { d, _ := json.Marshal(tool) sb.WriteString(formatGLM47ToolJSON(d)) sb.WriteString("\n") } sb.WriteString("\n\n") sb.WriteString("For each function call, output the function name and arguments within the following XML format:\n") sb.WriteString("{function-name}{arg-key-1}{arg-value-1}{arg-key-2}{arg-value-2}...") } enableThinking := false thinkingExplicitlySet := false if thinkValue != nil { enableThinking = thinkValue.Bool() thinkingExplicitlySet = true } imageOffset := 0 for i, message := range messages { switch message.Role { case "user": sb.WriteString("<|user|>\n") content, nextOffset := r.renderContent(message, imageOffset) imageOffset = nextOffset sb.WriteString(content) if thinkingExplicitlySet && !enableThinking && !strings.HasSuffix(message.Content, "/nothink") { sb.WriteString("/nothink") } case "assistant": sb.WriteString("<|assistant|>\n") if message.Thinking != "" { sb.WriteString("" + strings.TrimSpace(message.Thinking) + "") } else { sb.WriteString("") } if message.Content != "" { sb.WriteString("\n" + strings.TrimSpace(message.Content)) } if len(message.ToolCalls) > 0 { for _, toolCall := range message.ToolCalls { sb.WriteString("\n" + toolCall.Function.Name) sb.WriteString(renderGlmOcrToolArguments(toolCall.Function.Arguments)) sb.WriteString("") } } sb.WriteString("\n") case "tool": if i == 0 || messages[i-1].Role != "tool" { sb.WriteString("<|observation|>") } sb.WriteString("\n\n") sb.WriteString(message.Content) sb.WriteString("\n\n") case "system": sb.WriteString("<|system|>\n") sb.WriteString(message.Content) sb.WriteString("\n") } } sb.WriteString("<|assistant|>\n") if thinkingExplicitlySet && !enableThinking { sb.WriteString("\n") } return sb.String(), nil } func renderGlmOcrToolArguments(args api.ToolCallFunctionArguments) string { var sb strings.Builder for key, value := range args.All() { sb.WriteString("" + key + "") var valueStr string if str, ok := value.(string); ok { valueStr = str } else { jsonBytes, err := json.Marshal(value) if err != nil { valueStr = fmt.Sprintf("%v", value) } else { valueStr = string(jsonBytes) } } sb.WriteString("" + valueStr + "") } return sb.String() }