diff --git a/Chat.go b/Chat.go index f88a918..c804ba1 100644 --- a/Chat.go +++ b/Chat.go @@ -531,7 +531,7 @@ func generateLimitReachedChatHTML(c *fiber.Ctx) string { return htmlString } -// Buton actions +// Button actions func GetEditMessageFormHandler(c *fiber.Ctx) error { id := c.FormValue("id") idUUID, _ := edgedb.ParseUUID(id) @@ -727,7 +727,7 @@ func LoadUsageKPIHandler(c *fiber.Ctx) error { } func GenerateModelPopoverHTML(refresh bool, c *fiber.Ctx) string { - openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists, perplexityExists := getExistingKeys(c) + openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists, perplexityExists, fireworksExists := getExistingKeys(c) var llms []LLM err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Query(edgeCtx, ` @@ -765,7 +765,8 @@ func GenerateModelPopoverHTML(refresh bool, c *fiber.Ctx) string { "GooseaiExists": gooseaiExists, "GoogleExists": googleExists, "PerplexityExists": perplexityExists, - "AnyExists": openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists || perplexityExists, + "FireworksExists": fireworksExists, + "AnyExists": fireworksExists || openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists || perplexityExists, "LLMs": llms, "ModelInfos": modelInfos, "DeleteUpdate": refresh, @@ -856,7 +857,7 @@ func LoadSettingsHandler(c *fiber.Ctx) error { stripeSubLink := "https://billing.stripe.com/p/login/6oE6sc0PTfvq1Hi288?prefilled_email=" + user.Email - openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists, perplexityExists := getExistingKeys(c) + openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists, perplexityExists, fireworksExists := getExistingKeys(c) isPremium, isBasic := IsCurrentUserSubscribed(c) out, err := settingPopoverTmpl.Execute(pongo2.Context{ @@ -868,7 +869,8 @@ func LoadSettingsHandler(c *fiber.Ctx) error { "GooseaiExists": gooseaiExists, "GoogleExists": googleExists, "PerplexityExists": perplexityExists, - "AnyExists": openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists || perplexityExists, + "FireworksExists": fireworksExists, + "AnyExists": fireworksExists || openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists || perplexityExists, "isPremium": isPremium, "isBasic": isBasic, "StripeSubLink": stripeSubLink, diff --git a/MyUtils.go b/MyUtils.go index e83ef14..9b99b3f 100644 --- a/MyUtils.go +++ b/MyUtils.go @@ -78,9 +78,9 @@ func addCodeHeader(htmlContent string, languages []string) string { return updatedHTML } -func getExistingKeys(c *fiber.Ctx) (bool, bool, bool, bool, bool, bool, bool) { +func getExistingKeys(c *fiber.Ctx) (bool, bool, bool, bool, bool, bool, bool, bool) { if edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}) == nil { - return false, false, false, false, false, false, false + return false, false, false, false, false, false, false, false } var ( @@ -91,6 +91,7 @@ func getExistingKeys(c *fiber.Ctx) (bool, bool, bool, bool, bool, bool, bool) { gooseaiExists bool googleExists bool perplexityExists bool + fireworksExists bool ) err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, ` @@ -170,7 +171,18 @@ func getExistingKeys(c *fiber.Ctx) (bool, bool, bool, bool, bool, bool, bool) { panic(err) } - return openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists, perplexityExists + err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, ` + select exists ( + select global currentUser.setting.keys + filter .company.name = "fireworks" + ); + `, &fireworksExists) + if err != nil { + fmt.Println("Error checking if Fireworks key exists") + panic(err) + } + + return openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists, perplexityExists, fireworksExists } func Message2RequestMessage(messages []Message, context string) []RequestMessage { diff --git a/Request.go b/Request.go index b6c5ceb..0603d95 100644 --- a/Request.go +++ b/Request.go @@ -164,6 +164,8 @@ func GenerateMultipleMessagesHandler(c *fiber.Ctx) error { addMessageFunc = addGoogleMessage case "perplexity": addMessageFunc = addPerplexityMessage + case "fireworks": + addMessageFunc = addFireworkMessage } var messageID edgedb.UUID diff --git a/RequestFirework.go b/RequestFirework.go new file mode 100644 index 0000000..407f93d --- /dev/null +++ b/RequestFirework.go @@ -0,0 +1,184 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/edgedb/edgedb-go" + "github.com/gofiber/fiber/v2" +) + +type FireworkChatCompletionRequest struct { + Model string `json:"model"` + Messages []RequestMessage `json:"messages"` + Temperature float64 `json:"temperature"` +} + +type FireworkChatCompletionResponse struct { + ID string `json:"id"` + Object string `json:"object"` + Created int64 `json:"created"` + Model string `json:"model"` + Usage FireworkUsage `json:"usage"` + Choices []FireworkChoice `json:"choices"` +} + +type FireworkUsage struct { + PromptTokens int32 `json:"prompt_tokens"` + CompletionTokens int32 `json:"completion_tokens"` + TotalTokens int32 `json:"total_tokens"` +} + +type FireworkChoice struct { + Message Message `json:"message"` + FinishReason string `json:"finish_reason"` + Index int `json:"index"` +} + +func addFireworkMessage(c *fiber.Ctx, llm LLM, selected bool) edgedb.UUID { + Messages := getAllSelectedMessages(c) + + chatCompletion, err := RequestFirework(c, llm.Model.ModelID, Messages, float64(llm.Temperature), llm.Context) + if err != nil { + fmt.Println("Error fetching user profile") + panic(err) + } else if len(chatCompletion.Choices) == 0 { + fmt.Println("No response from OpenAI") + id := insertBotMessage(c, "No response from Firework", selected, llm.ID) + return id + } else { + Content := chatCompletion.Choices[0].Message.Content + id := insertBotMessage(c, Content, selected, llm.ID) + return id + } +} + +func TestFireworkKey(apiKey string) bool { + url := "https://api.fireworks.ai/inference/v1/chat/completions" + + // Convert messages to OpenAI format + fireworkMessages := []RequestMessage{ + { + Role: "user", + Content: "Hello", + }, + } + + requestBody := OpenaiChatCompletionRequest{ + Model: "accounts/fireworks/models/llama-v2-7b-chat", + Messages: fireworkMessages, + 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 + } + + var chatCompletionResponse FireworkChatCompletionResponse + err = json.Unmarshal(body, &chatCompletionResponse) + if err != nil { + return false + } + if chatCompletionResponse.Usage.CompletionTokens == 0 { + return false + } + return true +} + +func RequestFirework(c *fiber.Ctx, model string, messages []Message, temperature float64, context string) (FireworkChatCompletionResponse, error) { + var apiKey string + err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, ` + with + filtered_keys := ( + select Key { + key + } filter .company.name = $0 AND .$0 + LIMIT 1 + `, &usedModelInfo, model) + if err != nil { + return FireworkChatCompletionResponse{}, fmt.Errorf("error getting model info: %w", err) + } + + var inputCost float32 = float32(chatCompletionResponse.Usage.PromptTokens) * usedModelInfo.InputPrice + var outputCost float32 = float32(chatCompletionResponse.Usage.CompletionTokens) * usedModelInfo.OutputPrice + addUsage(c, inputCost, outputCost, chatCompletionResponse.Usage.PromptTokens, chatCompletionResponse.Usage.CompletionTokens, model) + + return chatCompletionResponse, nil +} diff --git a/main.go b/main.go index cfa487e..65f4bfc 100644 --- a/main.go +++ b/main.go @@ -191,6 +191,7 @@ func addKeys(c *fiber.Ctx) error { "gooseai": c.FormValue("goose_key"), "google": c.FormValue("google_key"), "perplexity": c.FormValue("perplexity_key"), + "fireworks": c.FormValue("fireworks_key"), } testFunctions := map[string]func(string) bool{ @@ -201,6 +202,7 @@ func addKeys(c *fiber.Ctx) error { "gooseai": TestGooseaiKey, "google": TestGoogleKey, "perplexity": TestPerplexityKey, + "fireworks": TestFireworkKey, } for company, key := range keys { diff --git a/static/icons/fireworks.png b/static/icons/fireworks.png new file mode 100644 index 0000000..5e63ac5 Binary files /dev/null and b/static/icons/fireworks.png differ diff --git a/static/icons/groq.png b/static/icons/groq.png index 64baa83..96ee4f7 100644 Binary files a/static/icons/groq.png and b/static/icons/groq.png differ diff --git a/static/icons/image.png b/static/icons/image.png deleted file mode 100644 index 252ffb8..0000000 Binary files a/static/icons/image.png and /dev/null differ diff --git a/static/icons/old/fireworks.png b/static/icons/old/fireworks.png new file mode 100644 index 0000000..9545b98 Binary files /dev/null and b/static/icons/old/fireworks.png differ diff --git a/static/icons/old/groq.png b/static/icons/old/groq.png new file mode 100644 index 0000000..64baa83 Binary files /dev/null and b/static/icons/old/groq.png differ diff --git a/static/icons/old/perplexity.png b/static/icons/old/perplexity.png new file mode 100644 index 0000000..cfa8ed6 Binary files /dev/null and b/static/icons/old/perplexity.png differ diff --git a/static/icons/perplexity.png b/static/icons/perplexity.png index cfa8ed6..c7c9452 100644 Binary files a/static/icons/perplexity.png and b/static/icons/perplexity.png differ diff --git a/static/icons/perplexity2.png b/static/icons/perplexity2.png deleted file mode 100644 index a34538e..0000000 Binary files a/static/icons/perplexity2.png and /dev/null differ diff --git a/views/layouts/main.html b/views/layouts/main.html index 8e5305d..d9ef4a1 100644 --- a/views/layouts/main.html +++ b/views/layouts/main.html @@ -23,13 +23,26 @@ + + + - + - {{embed}} + {{ embed }}