package llmapi import ( "encoding/json" "errors" "fmt" "io" "log/slog" "strings" ) type RespParser interface { ParseBytes(body []byte) (map[string]any, error) MakePayload(prompt string) io.Reader } // DeepSeekParser: deepseek implementation of RespParser type deepSeekParser struct { log *slog.Logger } func NewDeepSeekParser(log *slog.Logger) *deepSeekParser { return &deepSeekParser{log: log} } func (p *deepSeekParser) ParseBytes(body []byte) (map[string]any, error) { // parsing logic here dsResp := DSResp{} if err := json.Unmarshal(body, &dsResp); err != nil { p.log.Error("failed to unmarshall", "error", err) return nil, err } if len(dsResp.Choices) == 0 { p.log.Error("empty choices", "dsResp", dsResp) err := errors.New("empty choices in dsResp") return nil, err } text := dsResp.Choices[0].Text li := strings.Index(text, "{") ri := strings.LastIndex(text, "}") if li < 0 || ri < 1 { p.log.Error("not a json", "msg", text) err := fmt.Errorf("fn: ParseBytes, not a json; data: %s", text) return nil, err } sj := text[li : ri+1] respMap := make(map[string]any) if err := json.Unmarshal([]byte(sj), &respMap); err != nil { p.log.Error("failed to unmarshal response", "error", err, "string-json", sj) return nil, err } return respMap, nil } func (p *deepSeekParser) MakePayload(prompt string) io.Reader { return strings.NewReader(fmt.Sprintf(`{ "model": "deepseek-chat", "prompt": "%s", "echo": false, "frequency_penalty": 0, "logprobs": 0, "max_tokens": 1024, "presence_penalty": 0, "stop": null, "stream": false, "stream_options": null, "suffix": null, "temperature": 1, "top_p": 1 }`, prompt)) } // llama.cpp implementation of RespParser type lcpRespParser struct { log *slog.Logger } func NewLCPRespParser(log *slog.Logger) *lcpRespParser { return &lcpRespParser{log: log} } func (p *lcpRespParser) ParseBytes(body []byte) (map[string]any, error) { // parsing logic here resp := LLMResp{} if err := json.Unmarshal(body, &resp); err != nil { p.log.Error("failed to unmarshal", "error", err) return nil, err } // if len(resp.Choices) == 0 { // p.log.Error("empty choices", "resp", resp) // err := errors.New("empty choices in resp") // return nil, err // } // text := resp.Choices[0].Message.Content text := resp.Content li := strings.Index(text, "{") ri := strings.LastIndex(text, "}") if li < 0 || ri < 1 { p.log.Error("not a json", "msg", text) err := fmt.Errorf("fn: ParseBytes, not a json; data: %s", text) return nil, err } sj := text[li : ri+1] respMap := make(map[string]any) if err := json.Unmarshal([]byte(sj), &respMap); err != nil { p.log.Error("failed to unmarshal response", "error", err, "string-json", sj) return nil, err } return respMap, nil } func (p *lcpRespParser) MakePayload(prompt string) io.Reader { return strings.NewReader(fmt.Sprintf(`{ "model": "local-model", "prompt": "%s", "frequency_penalty": 0, "max_tokens": 1024, "stop": null, "stream": false, "temperature": 0.4, "top_p": 1 }`, prompt)) } type openRouterParser struct { log *slog.Logger } func NewOpenRouterParser(log *slog.Logger) *openRouterParser { return &openRouterParser{log: log} } func (p *openRouterParser) ParseBytes(body []byte) (map[string]any, error) { // parsing logic here resp := OpenRouterResp{} if err := json.Unmarshal(body, &resp); err != nil { p.log.Error("failed to unmarshal", "error", err) return nil, err } if len(resp.Choices) == 0 { p.log.Error("empty choices", "resp", resp) err := errors.New("empty choices in resp") return nil, err } text := resp.Choices[0].Message.Content li := strings.Index(text, "{") ri := strings.LastIndex(text, "}") if li < 0 || ri < 1 { p.log.Error("not a json", "msg", text) err := fmt.Errorf("fn: ParseBytes, not a json; data: %s", text) return nil, err } sj := text[li : ri+1] respMap := make(map[string]any) if err := json.Unmarshal([]byte(sj), &respMap); err != nil { p.log.Error("failed to unmarshal response", "error", err, "string-json", sj) return nil, err } return respMap, nil } func (p *openRouterParser) MakePayload(prompt string) io.Reader { strPayload := fmt.Sprintf(`{ "model": "deepseek/deepseek-chat-v3-0324:free", "messages": [ { "role": "user", "content": "%s" } ] }`, prompt) p.log.Debug("made openrouter payload", "payload", strPayload) return strings.NewReader(strPayload) }