128 lines
3.3 KiB
Go
128 lines
3.3 KiB
Go
package llmapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
)
|
|
|
|
type RespParser interface {
|
|
ParseBytes(body []byte) (map[string]any, error)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
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
|
|
}
|