package main import ( "bytes" "context" "encoding/json" "log" "net" "net/http" "net/url" "strings" "time" "github.com/alecthomas/chroma/v2/quick" "github.com/lrstanley/girc" "golang.org/x/net/proxy" ) func DoORRequest( appConfig *TomlConfig, memory *[]MemoryElement, prompt string, ) (string, error) { var jsonPayload []byte var err error memoryElement := MemoryElement{ Role: "user", Content: prompt, } if len(*memory) > appConfig.MemoryLimit { *memory = []MemoryElement{} for _, context := range appConfig.Context { *memory = append(*memory, MemoryElement{ Role: "assistant", Content: context, }) } } *memory = append(*memory, memoryElement) ollamaRequest := OllamaChatRequest{ Model: appConfig.Model, Messages: *memory, } jsonPayload, err = json.Marshal(ollamaRequest) if err != nil { return "", err } log.Printf("json payload: %s", string(jsonPayload)) ctx, cancel := context.WithTimeout(context.Background(), time.Duration(appConfig.RequestTimeout)*time.Second) defer cancel() request, err := http.NewRequest(http.MethodPost, appConfig.Endpoint, bytes.NewBuffer(jsonPayload)) if err != nil { return "", err } request = request.WithContext(ctx) request.Header.Set("content-type", "application/json") request.Header.Set("Authorization", "Bearer "+appConfig.Apikey) var httpClient http.Client var dialer proxy.Dialer if appConfig.LLMProxy != "" { proxyURL, err := url.Parse(appConfig.IRCProxy) if err != nil { cancel() log.Fatal(err.Error()) } dialer, err = proxy.FromURL(proxyURL, &net.Dialer{Timeout: time.Duration(appConfig.RequestTimeout) * time.Second}) if err != nil { cancel() log.Fatal(err.Error()) } httpClient = http.Client{ Transport: &http.Transport{ Dial: dialer.Dial, }, } } response, err := httpClient.Do(request) if err != nil { return "", err } defer response.Body.Close() log.Println("response body:", response.Body) var orresponse ORResponse err = json.NewDecoder(response.Body).Decode(&orresponse) if err != nil { return "", err } var result string for _, choice := range orresponse.Choices { result += choice.Message.Content + "\n" } return result, nil } func ORRequestProcessor( appConfig *TomlConfig, client *girc.Client, event girc.Event, memory *[]MemoryElement, prompt string, ) string { response, err := DoORRequest(appConfig, memory, prompt) if err != nil { client.Cmd.ReplyTo(event, "error: "+err.Error()) return "" } assistantElement := MemoryElement{ Role: "assistant", Content: response, } *memory = append(*memory, assistantElement) log.Println(response) var writer bytes.Buffer err = quick.Highlight(&writer, response, "markdown", appConfig.ChromaFormatter, appConfig.ChromaStyle) if err != nil { client.Cmd.ReplyTo(event, "error: "+err.Error()) return "" } return writer.String() } func ORHandler( irc *girc.Client, appConfig *TomlConfig, memory *[]MemoryElement) { irc.Handlers.AddBg(girc.PRIVMSG, func(client *girc.Client, event girc.Event) { if !strings.HasPrefix(event.Last(), appConfig.IrcNick+": ") { return } if appConfig.AdminOnly { byAdmin := false for _, admin := range appConfig.Admins { if event.Source.Name == admin { byAdmin = true } } if !byAdmin { return } } prompt := strings.TrimPrefix(event.Last(), appConfig.IrcNick+": ") log.Println(prompt) if string(prompt[0]) == "/" { runCommand(client, event, appConfig) return } result := ORRequestProcessor(appConfig, client, event, memory, prompt) if result != "" { SendToIRC(client, event, result, appConfig.ChromaFormatter) } }) }