aboutsummaryrefslogblamecommitdiffstats
path: root/openrouter.go
blob: 09e78b59b022295bda4eef8082e1d02b1b88b832 (plain) (tree)


































































































































































































                                                                                                                                  
                                                                                   



                 
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)
		}
	})

}