diff --git a/Chat.go b/Chat.go index ec48210..928eb72 100644 --- a/Chat.go +++ b/Chat.go @@ -379,7 +379,7 @@ func LoadKeysHandler(c *fiber.Ctx) error { if !checkIfLogin() { return c.SendString("") } - openaiExists, anthropicExists, mistralExists, groqExists := getExistingKeys() + openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys() out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-keys.html")).Execute(pongo2.Context{ "IsLogin": checkIfLogin(), @@ -387,7 +387,9 @@ func LoadKeysHandler(c *fiber.Ctx) error { "AnthropicExists": anthropicExists, "MistralExists": mistralExists, "GroqExists": groqExists, - "AnyExists": openaiExists || anthropicExists || mistralExists || groqExists, + "GooseaiExists": gooseaiExists, + "GoogleExists": googleExists, + "AnyExists": openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists, }) if err != nil { c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ diff --git a/Request.go b/Request.go index 2ee3246..0a4c8f7 100644 --- a/Request.go +++ b/Request.go @@ -24,7 +24,7 @@ func GeneratePlaceholderHandler(c *fiber.Ctx) error { // Step 1 I create a User message and send it as output with a placeholder // that will make a request to GenerateMultipleMessagesHandler when loading message := c.FormValue("message", "") - selectedLLMIds := []string{"1e5a07c4-12fe-11ef-8da6-67d29b408c53", "3cd15ca8-1433-11ef-9f22-93f2b78c78de", "95774e62-1447-11ef-bfea-33f555b75c17", "af3d8686-1447-11ef-bfea-07d880a979ff"} // TODO Hanle in the UI + selectedLLMIds := []string{"1e5a07c4-12fe-11ef-8da6-67d29b408c53", "3cd15ca8-1433-11ef-9f22-93f2b78c78de", "95774e62-1447-11ef-bfea-33f555b75c17", "af3d8686-1447-11ef-bfea-07d880a979ff", "be7a922a-1478-11ef-a819-238de8775b87"} // TODO Hanle in the UI var selectedLLMs []LLM var selectedLLM LLM @@ -105,6 +105,8 @@ func GenerateMultipleMessagesHandler(c *fiber.Ctx) error { addMessageFunc = addMistralMessage case "groq": addMessageFunc = addGroqMessage + case "gooseai": + addMessageFunc = addGooseaiMessage } var messageID edgedb.UUID diff --git a/RequestGoogle.go b/RequestGoogle.go new file mode 100644 index 0000000..3486dcf --- /dev/null +++ b/RequestGoogle.go @@ -0,0 +1,188 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/edgedb/edgedb-go" +) + +type GoogleRequestMessage struct { + Role string `json:"role"` + Parts []GooglePart `json:"parts"` +} + +type GooglePart struct { + Text string `json:"text"` +} + +type GoogleChatCompletionRequest struct { + Messages []GoogleRequestMessage `json:"contents"` +} + +type GoogleChatCompletionResponse struct { + ID string `json:"id"` + Object string `json:"object"` + Created int64 `json:"created"` + Model string `json:"model"` + Usage GoogleUsage `json:"usage"` + Choices []GoogleChoice `json:"choices"` +} + +type GoogleUsage struct { + PromptTokens int32 `json:"prompt_tokens"` + CompletionTokens int32 `json:"completion_tokens"` + TotalTokens int32 `json:"total_tokens"` +} + +type GoogleChoice struct { + Message Message `json:"message"` + FinishReason string `json:"finish_reason"` + Index int `json:"index"` +} + +func addGoogleMessage(llm LLM, selected bool) edgedb.UUID { + Messages := getAllSelectedMessages() + + chatCompletion, err := RequestGoogle(llm.Model.ModelID, Messages, float64(llm.Temperature)) + if err != nil { + fmt.Println("Error:", err) + } else if len(chatCompletion.Choices) == 0 { + fmt.Println("No response from OpenAI") + id := insertBotMessage("No response from OpenAI", selected, llm.ID) + return id + } else { + Content := chatCompletion.Choices[0].Message.Content + id := insertBotMessage(Content, selected, llm.ID) + return id + } + return edgedb.UUID{} +} + +func TestGoogleKey(apiKey string) bool { + url := "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=" + apiKey + + googlePart := GooglePart{ + Text: "Hello", + } + // Convert messages to OpenAI format + googleMessages := []GoogleRequestMessage{ + { + Role: "user", + Parts: []GooglePart{googlePart}, + }, + } + + requestBody := GoogleChatCompletionRequest{ + Messages: googleMessages, + } + + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return false + } + + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) + if err != nil { + return false + } + + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return false + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + fmt.Println(string(body)) + + var chatCompletionResponse GoogleChatCompletionResponse + err = json.Unmarshal(body, &chatCompletionResponse) + if err != nil { + return false + } + if chatCompletionResponse.Usage.CompletionTokens == 0 { + return false + } + return true +} + +func RequestGoogle(model string, messages []Message, temperature float64) (OpenaiChatCompletionResponse, error) { + var apiKey string + err := edgeClient.QuerySingle(edgeCtx, ` + with + filtered_keys := ( + select Key { + key + } filter .company.name = $0 AND .$0 + `, &usedModelInfo, model) + + var inputCost float32 = float32(chatCompletionResponse.Usage.PromptTokens) * usedModelInfo.InputPrice + var outputCost float32 = float32(chatCompletionResponse.Usage.CompletionTokens) * usedModelInfo.OutputPrice + addUsage(inputCost, outputCost, chatCompletionResponse.Usage.PromptTokens, chatCompletionResponse.Usage.CompletionTokens, model) + + return chatCompletionResponse, nil +} diff --git a/RequestGooseai.go b/RequestGooseai.go new file mode 100644 index 0000000..f0ccb95 --- /dev/null +++ b/RequestGooseai.go @@ -0,0 +1,155 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/edgedb/edgedb-go" +) + +type GooseaiCompletionRequest struct { + Model string `json:"model"` + Prompt []string `json:"prompt"` + Temperature float64 `json:"temperature"` +} + +type GooseaiCompletionResponse struct { + ID string `json:"id"` + Created int64 `json:"created"` + Model string `json:"model"` + Choices []GooseaiChoice `json:"choices"` +} + +type GooseaiChoice struct { + Text string `json:"text"` + FinishReason string `json:"finish_reason"` + Index int `json:"index"` +} + +func addGooseaiMessage(llm LLM, selected bool) edgedb.UUID { + Messages := getAllSelectedMessages() + + chatCompletion, err := RequestGooseai(llm.Model.ModelID, Messages, float64(llm.Temperature)) + if err != nil { + fmt.Println("Error:", err) + } else if len(chatCompletion.Choices) == 0 { + fmt.Println("No response from GooseAI") + id := insertBotMessage("No response from GooseAI", selected, llm.ID) + return id + } else { + Content := chatCompletion.Choices[0].Text + id := insertBotMessage(Content, selected, llm.ID) + return id + } + return edgedb.UUID{} +} + +func TestGooseaiKey(apiKey string) bool { + url := "https://api.goose.ai/v1/engines/gpt-j-6b/completions" + + requestBody := GooseaiCompletionRequest{ + Model: "gpt-j-6b", + Prompt: []string{"Hello, how are you?"}, + Temperature: 0, + } + + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return false + } + + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) + if err != nil { + return false + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+apiKey) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return false + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + // Print the response body + fmt.Println(string(body)) + + var chatCompletionResponse GooseaiCompletionResponse + err = json.Unmarshal(body, &chatCompletionResponse) + if err != nil { + return false + } + if chatCompletionResponse.Choices[0].Text == "" { + return false + } + return true +} + +func RequestGooseai(model string, messages []Message, temperature float64) (GooseaiCompletionResponse, error) { + var apiKey string + err := edgeClient.QuerySingle(edgeCtx, ` + with + filtered_keys := ( + select Key { + key + } filter .company.name = "gooseai" AND .$0 + } filter .company.name = $0 AND .$0 + } filter .company.name = $0 AND .$0 + } filter .company.name = $0 AND .$0 - ); - `, &Exists, openaiKey) - if err != nil { - fmt.Println("Error in edgedb.QuerySingle: in addOpenaiKey: ", err) - return c.SendString("") - } - if Exists { - fmt.Println("OpenAI key already exists") - return c.SendString("") - } - if !TestOpenaiKey(openaiKey) { fmt.Println("Invalid OpenAI API Key") return c.SendString("Invalid OpenAI API Key\n") } // Check if the company key already exists - err = edgeClient.QuerySingle(edgeCtx, ` + err := edgeClient.QuerySingle(edgeCtx, ` select exists ( select global currentUser.setting.keys filter .company.name = "openai" @@ -188,16 +174,18 @@ func addKeys(c *fiber.Ctx) error { } } else { err = edgeClient.Execute(edgeCtx, ` + WITH + c := (SELECT Company FILTER .name = "openai" LIMIT 1) UPDATE global currentUser.setting SET { keys += ( INSERT Key { - company := $0, - key := $1, - name := $2, + company := c, + key := $0, + name := "OpenAI API Key", } ) - }`, "openai", openaiKey, "OpenAI API Key") + }`, openaiKey) if err != nil { fmt.Println("Error in edgedb.QuerySingle: in addOpenaiKey") fmt.Println(err) @@ -207,29 +195,13 @@ func addKeys(c *fiber.Ctx) error { // Handle Anthropic key if anthropicKey != "" { - // Check if the OpenAI key already exists - err := edgeClient.QuerySingle(edgeCtx, ` - select exists ( - select global currentUser.setting.keys - filter .company.name = "anthropic" AND .key = $0 - ); - `, &Exists, openaiKey) - if err != nil { - fmt.Println("Error in edgedb.QuerySingle: in addAnthropicKey: ", err) - return c.SendString("") - } - if Exists { - fmt.Println("Anthropic key already exists") - return c.SendString("") - } - if !TestAnthropicKey(anthropicKey) { fmt.Println("Invalid Anthropic API Key") return c.SendString("Invalid Anthropic API Key\n") } // Check if the company key already exists - err = edgeClient.QuerySingle(edgeCtx, ` + err := edgeClient.QuerySingle(edgeCtx, ` select exists ( select global currentUser.setting.keys filter .company.name = "anthropic" @@ -253,11 +225,13 @@ func addKeys(c *fiber.Ctx) error { } } else { err = edgeClient.Execute(edgeCtx, ` + WITH + c := (SELECT Company FILTER .name = "anthropic" LIMIT 1) UPDATE global currentUser.setting SET { keys += ( INSERT Key { - company := "anthropic", + company := c, key := $0, name := "Anthropic API Key", } @@ -272,29 +246,13 @@ func addKeys(c *fiber.Ctx) error { // Handle Mistral key if mistralKey != "" { - // Check if the OpenAI key already exists - err := edgeClient.QuerySingle(edgeCtx, ` - select exists ( - select global currentUser.setting.keys - filter .company.name = "mistral" AND .key = $0 - ); - `, &Exists, openaiKey) - if err != nil { - fmt.Println("Error in edgedb.QuerySingle: in addMistralKey: ", err) - return c.SendString("") - } - if Exists { - fmt.Println("Mistral key already exists") - return c.SendString("") - } - if !TestMistralKey(mistralKey) { fmt.Println("Invalid Mistral API Key") return c.SendString("Invalid Mistral API Key\n") } // Check if the company key already exists - err = edgeClient.QuerySingle(edgeCtx, ` + err := edgeClient.QuerySingle(edgeCtx, ` select exists ( select global currentUser.setting.keys filter .company.name = "mistral" @@ -318,11 +276,13 @@ func addKeys(c *fiber.Ctx) error { } } else { err = edgeClient.Execute(edgeCtx, ` + WITH + c := (SELECT Company FILTER .name = "mistral" LIMIT 1) UPDATE global currentUser.setting SET { keys += ( INSERT Key { - company := "mistral", + company := c, key := $0, name := "Mistral API Key", } @@ -337,29 +297,13 @@ func addKeys(c *fiber.Ctx) error { // Handle Groq key if groqKey != "" { - // Check if the OpenAI key already exists - err := edgeClient.QuerySingle(edgeCtx, ` - select exists ( - select global currentUser.setting.keys - filter .company.name = "groq" AND .key = $0 - ); - `, &Exists, openaiKey) - if err != nil { - fmt.Println("Error in edgedb.QuerySingle: in addGroqKey: ", err) - return c.SendString("") - } - if Exists { - fmt.Println("Groq key already exists") - return c.SendString("") - } - if !TestGroqKey(groqKey) { fmt.Println("Invalid Groq API Key") return c.SendString("Invalid Groq API Key\n") } // Check if the company key already exists - err = edgeClient.QuerySingle(edgeCtx, ` + err := edgeClient.QuerySingle(edgeCtx, ` select exists ( select global currentUser.setting.keys filter .company.name = "groq" @@ -383,11 +327,13 @@ func addKeys(c *fiber.Ctx) error { } } else { err = edgeClient.Execute(edgeCtx, ` + WITH + c := (SELECT Company FILTER .name = "groq" LIMIT 1) UPDATE global currentUser.setting SET { keys += ( INSERT Key { - company := "groq", + company := c, key := $0, name := "Groq API Key", } @@ -400,5 +346,107 @@ func addKeys(c *fiber.Ctx) error { } } + // Handle Gooseai key + if gooseaiKey != "" { + if !TestGooseaiKey(gooseaiKey) { + fmt.Println("Invalid Gooseai API Key") + return c.SendString("Invalid Gooseai API Key\n") + } + + // Check if the company key already exists + err := edgeClient.QuerySingle(edgeCtx, ` + select exists ( + select global currentUser.setting.keys + filter .company.name = "gooseai" + ); + `, &Exists) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle: in addGooseaiKey") + fmt.Println(err) + } + + if Exists { + err = edgeClient.Execute(edgeCtx, ` + UPDATE Key filter .company.name = "gooseai" AND .key = $0 + SET { + key := $0, + } + `, gooseaiKey) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle: in addGooseaiKey") + fmt.Println(err) + } + } else { + err = edgeClient.Execute(edgeCtx, ` + WITH + c := (SELECT Company FILTER .name = "gooseai" LIMIT 1) + UPDATE global currentUser.setting + SET { + keys += ( + INSERT Key { + company := c, + key := $0, + name := "Gooseai API Key", + } + ) + }`, gooseaiKey) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle: in addGooseaiKey") + fmt.Println(err) + } + } + } + + // Handle Google key + if googleKey != "" { + if !TestGoogleKey(googleKey) { + fmt.Println("Invalid Google API Key") + return c.SendString("Invalid Google API Key\n") + } + + // Check if the company key already exists + err := edgeClient.QuerySingle(edgeCtx, ` + select exists ( + select global currentUser.setting.keys + filter .company.name = "google" + ); + `, &Exists) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle: in addGoogleKey") + fmt.Println(err) + } + + if Exists { + err = edgeClient.Execute(edgeCtx, ` + UPDATE Key filter .company.name = "google" AND .key = $0 + SET { + key := $0, + } + `, googleKey) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle: in addGoogleKey") + fmt.Println(err) + } + } else { + err = edgeClient.Execute(edgeCtx, ` + WITH + c := (SELECT Company FILTER .name = "google" LIMIT 1) + UPDATE global currentUser.setting + SET { + keys += ( + INSERT Key { + company := c, + key := $0, + name := "Google API Key", + } + ) + }`, googleKey) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle: in addGoogleKey") + fmt.Println(err) + } + } + } + return c.SendString("") } diff --git a/static/icons/azure.png b/static/icons/azure.png new file mode 100644 index 0000000..06ef419 Binary files /dev/null and b/static/icons/azure.png differ diff --git a/static/icons/gemini.png b/static/icons/gemini.png new file mode 100644 index 0000000..63f11cd Binary files /dev/null and b/static/icons/gemini.png differ diff --git a/static/icons/gooseai.png b/static/icons/gooseai.png new file mode 100644 index 0000000..e45c996 Binary files /dev/null and b/static/icons/gooseai.png differ diff --git a/static/icons/groq.png b/static/icons/groq.png index c3c5165..64baa83 100644 Binary files a/static/icons/groq.png and b/static/icons/groq.png differ diff --git a/utils.go b/utils.go index c8d596c..671d149 100644 --- a/utils.go +++ b/utils.go @@ -38,15 +38,19 @@ func addCopyButtonsToCode(htmlContent string) string { return updatedHTML } -func getExistingKeys() (bool, bool, bool, bool) { +func getExistingKeys() (bool, bool, bool, bool, bool, bool) { if edgeClient == nil { - return false, false, false, false + return false, false, false, false, false, false } - var openaiExists bool - var anthropicExists bool - var mistralExists bool - var groqExists bool + var ( + openaiExists bool + anthropicExists bool + mistralExists bool + groqExists bool + gooseaiExists bool + googleExists bool + ) err := edgeClient.QuerySingle(edgeCtx, ` select exists ( @@ -93,7 +97,29 @@ func getExistingKeys() (bool, bool, bool, bool) { panic(err) } - return openaiExists, anthropicExists, mistralExists, groqExists + err = edgeClient.QuerySingle(edgeCtx, ` + select exists ( + select global currentUser.setting.keys + filter .company.name = "gooseai" + ); + `, &gooseaiExists) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle checking for gooseai: ", err) + panic(err) + } + + err = edgeClient.QuerySingle(edgeCtx, ` + select exists ( + select global currentUser.setting.keys + filter .company.name = "google" + ); + `, &googleExists) + if err != nil { + fmt.Println("Error in edgedb.QuerySingle checking for google: ", err) + panic(err) + } + + return openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists } func Message2RequestMessage(messages []Message) []RequestMessage { diff --git a/views/partials/popover-keys.html b/views/partials/popover-keys.html index e439391..e08f1c7 100644 --- a/views/partials/popover-keys.html +++ b/views/partials/popover-keys.html @@ -40,6 +40,25 @@

+
+

+ + + + +

+
+
+

+ + + + +

+