package main import ( "context" "encoding/json" "fmt" "net/url" "sort" "strings" "time" "github.com/edgedb/edgedb-go" "github.com/flosch/pongo2" "github.com/gofiber/fiber/v2" ) func ChatPageHandler(c *fiber.Ctx) error { authCookie := c.Cookies("jade-edgedb-auth-token", "") if authCookie != "" && !checkIfLogin() { edgeClient = edgeClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": authCookie}) } var ( isSub bool limitReach bool ) if !checkIfLogin() { isSub = false limitReach = false } else { isSub = IsCurrentUserSubscribed() limitReach = IsCurrentUserLimiteReached() } return c.Render("chat", fiber.Map{"IsLogin": checkIfLogin(), "HaveKey": checkIfHaveKey(), "IsSubscribed": isSub, "IsLimiteReached": limitReach}, "layouts/main") } func DeleteMessageHandler(c *fiber.Ctx) error { messageId := c.FormValue("id") messageUUID, err := edgedb.ParseUUID(messageId) if err != nil { fmt.Println("Error parsing UUID") panic(err) } // Delete all messages err = edgeClient.Execute(edgeCtx, ` WITH messageArea := (SELECT Message FILTER .id = $0).area DELETE Area FILTER .position >= messageArea.position AND .conversation = messageArea.conversation; `, messageUUID) if err != nil { fmt.Println("Error deleting messages") panic(err) } return c.SendString(generateChatHTML()) } func LoadChatHandler(c *fiber.Ctx) error { deleteLLMtoDelete() if checkIfLogin() { if IsCurrentUserLimiteReached() && !IsCurrentUserSubscribed() { return c.SendString(generateLimitReachedChatHTML()) } else if !checkIfHaveKey() { return c.SendString(generateEnterKeyChatHTML()) } return c.SendString(generateChatHTML()) } else { return c.SendString(generateWelcomeChatHTML()) } } type TemplateMessage struct { Icon string Content string Hidden bool Id string Name string Model string ModelID string } func generateChatHTML() string { // Println the name of the current conversation var currentConv Conversation err := edgeClient.QuerySingle(edgeCtx, ` SELECT global currentConversation { name }`, ¤tConv) if err != nil { fmt.Println("Error getting current conversation") panic(err) } fmt.Println("Current conversation: ", currentConv.Name) // Maybe redo that to be area by area because look like shit rn. It come from early stage of dev. It work tho soooo... var Messages []Message err = edgeClient.Query(edgeCtx, ` SELECT Message { id, selected, role, content, date, llm : { name, modelInfo : { modelID, name, company : { icon } } } } FILTER .conversation = global currentConversation AND .conversation.user = global currentUser ORDER BY .date ASC `, &Messages) if err != nil { fmt.Println("Error getting messages") panic(err) } htmlString := "
" var templateMessages []TemplateMessage for i, message := range Messages { if message.Role == "user" { htmlContent := markdownToHTML(message.Content) userOut, err := userTmpl.Execute(pongo2.Context{"Content": htmlContent, "ID": message.ID.String()}) if err != nil { fmt.Println("Error executing user template") panic(err) } htmlString += userOut // Reset NextMessages when a user message is encountered templateMessages = []TemplateMessage{} } else { // For bot messages, add them to NextMessages with only the needed fields templateMessage := TemplateMessage{ Icon: message.LLM.Model.Company.Icon, // Assuming Icon is a field you want to include from Message Content: markdownToHTML(message.Content), Hidden: !message.Selected, // Assuming Hidden is a field you want to include from Message Id: message.ID.String(), Name: message.LLM.Name, Model: message.LLM.Model.Name, ModelID: message.LLM.Model.ModelID, } templateMessages = append(templateMessages, templateMessage) // Check if the next message is not a bot or if it's the last message if i+1 == len(Messages) || Messages[i+1].Role != "bot" { sort.Slice(templateMessages, func(i, j int) bool { if !templateMessages[i].Hidden && templateMessages[j].Hidden { return true } if templateMessages[i].Hidden && !templateMessages[j].Hidden { return false } return true }) botOut, err := botTmpl.Execute(pongo2.Context{"Messages": templateMessages, "ConversationAreaId": i}) if err != nil { fmt.Println("Error executing bot template") panic(err) } htmlString += botOut htmlString += "
" } } } htmlString += "
" // Render the HTML template with the messages return htmlString } func GetUserMessageHandler(c *fiber.Ctx) error { id := c.FormValue("id") messageUUID, _ := edgedb.ParseUUID(id) var selectedMessage Message err := edgeClient.QuerySingle(context.Background(), ` SELECT Message { content } FILTER .id = $0; `, &selectedMessage, messageUUID) if err != nil { fmt.Println("Error getting message") panic(err) } out, err := userTmpl.Execute(pongo2.Context{"Content": markdownToHTML(selectedMessage.Content), "ID": id}) if err != nil { fmt.Println("Error executing user template") panic(err) } return c.SendString(out) } func GetMessageContentHandler(c *fiber.Ctx) error { messageId := c.FormValue("id") onlyContent := c.FormValue("onlyContent") // To init the text area of the edit message form messageUUID, _ := edgedb.ParseUUID(messageId) var selectedMessage Message err := edgeClient.QuerySingle(context.Background(), ` SELECT Message { content, llm : { name, modelInfo : { modelID, name, } } } FILTER .id = $0; `, &selectedMessage, messageUUID) if err != nil { panic(err) } if onlyContent == "true" { return c.SendString(markdownToHTML(selectedMessage.Content)) } out := "
" out += "

" out += "" + selectedMessage.LLM.Name + " " + selectedMessage.LLM.Model.ModelID + "" out += "

" out += "
" out += "
" out += " " out += markdownToHTML(selectedMessage.Content) out += " " out += "
" // Update the selected value of messages in the database err = edgeClient.Execute(edgeCtx, ` WITH m := (SELECT Message FILTER .id = $0) UPDATE Message FILTER .area = m.area SET {selected := false}; `, messageUUID) if err != nil { panic(err) } _ = edgeClient.Execute(edgeCtx, ` UPDATE Message FILTER .id = $0 SET {selected := true}; `, messageUUID) return c.SendString(out) } func generateWelcomeChatHTML() string { welcomeMessage := `To start using JADE, please login.` loginButton := ` Log in ` htmlString := "
" NextMessages := []TemplateMessage{} nextMsg := TemplateMessage{ Icon: "icons/bouvai2.png", // Assuming Icon is a field you want to include from Message Content: "
" + markdownToHTML(welcomeMessage) + loginButton, Hidden: false, // Assuming Hidden is a field you want to include from Message Id: "0", Name: "JADE", } NextMessages = append(NextMessages, nextMsg) botOut, err := botTmpl.Execute(pongo2.Context{"Messages": NextMessages, "ConversationAreaId": 0, "NotClickable": true}) if err != nil { fmt.Println("Error executing bot template") panic(err) } htmlString += botOut htmlString += "
" htmlString += "
" // Render the HTML template with the messages return htmlString } func generateEnterKeyChatHTML() string { welcomeMessage := `

To start using JADE, please enter at least one key in the settings.

` htmlString := "
" NextMessages := []TemplateMessage{} nextMsg := TemplateMessage{ Icon: "icons/bouvai2.png", // Assuming Icon is a field you want to include from Message Content: welcomeMessage, Hidden: false, // Assuming Hidden is a field you want to include from Message Id: "0", Name: "JADE", } NextMessages = append(NextMessages, nextMsg) botOut, err := botTmpl.Execute(pongo2.Context{"Messages": NextMessages, "ConversationAreaId": 0, "NotClickable": true}) if err != nil { fmt.Println("Error executing bot template") panic(err) } htmlString += botOut htmlString += "
" htmlString += "
" // Render the HTML template with the messages return htmlString } func generateTermAndServiceHandler(c *fiber.Ctx) error { return c.SendString(generateTermAndServiceChatHTML()) } func generateTermAndServiceChatHTML() string { welcomeMessage := `

TODO Add terms and service.

` closeBtn := ` ` htmlString := "
" NextMessages := []TemplateMessage{} nextMsg := TemplateMessage{ Icon: "icons/bouvai2.png", // Assuming Icon is a field you want to include from Message Content: welcomeMessage + closeBtn, Hidden: false, // Assuming Hidden is a field you want to include from Message Id: "0", Name: "JADE", } NextMessages = append(NextMessages, nextMsg) botOut, err := botTmpl.Execute(pongo2.Context{"Messages": NextMessages, "ConversationAreaId": 0, "NotClickable": true}) if err != nil { fmt.Println("Error executing bot template") panic(err) } htmlString += botOut htmlString += "
" htmlString += "
" // Render the HTML template with the messages return htmlString } func generateLimitReachedChatHTML() string { welcomeMessage := `You have reached the maximum number of messages for a free account. Please upgrade your account to continue using JADE.` var result User err := edgeClient.QuerySingle(edgeCtx, "SELECT global currentUser { stripe_id, email } LIMIT 1;", &result) if err != nil { fmt.Println("Error getting current user") panic(err) } clientSecretSession := CreateClientSecretSession() // TODO Replace by live API call stripeTable := ` ` htmlString := "
" NextMessages := []TemplateMessage{} nextMsg := TemplateMessage{ Icon: "icons/bouvai2.png", // Assuming Icon is a field you want to include from Message Content: "
" + markdownToHTML(welcomeMessage) + "
" + stripeTable, Hidden: false, // Assuming Hidden is a field you want to include from Message Id: "0", Name: "JADE", } NextMessages = append(NextMessages, nextMsg) botOut, err := botTmpl.Execute(pongo2.Context{"Messages": NextMessages, "ConversationAreaId": 0, "NotClickable": true}) if err != nil { fmt.Println("Error executing bot template") panic(err) } htmlString += botOut htmlString += "
" htmlString += "
" // Render the HTML template with the messages return htmlString } // Buton actions func GetEditMessageFormHandler(c *fiber.Ctx) error { id := c.FormValue("id") idUUID, _ := edgedb.ParseUUID(id) var message Message err := edgeClient.QuerySingle(context.Background(), ` SELECT Message { content } FILTER .id = $0; `, &message, idUUID) if err != nil { fmt.Println("Error getting message") panic(err) } // Calculate the number of rows based on the length of the content rows := len(strings.Split(message.Content, "\n")) if rows < 10 { rows = 10 } out, err := messageEditTmpl.Execute(pongo2.Context{"Content": message.Content, "ID": id, "Rows": rows}) if err != nil { fmt.Println("Error executing user template") panic(err) } return c.SendString(out) } func RedoMessageHandler(c *fiber.Ctx) error { messageId := c.FormValue("id") messageUUID, _ := edgedb.ParseUUID(messageId) var selectedLLMIds []string err := json.Unmarshal([]byte(c.FormValue("selectedLLMIds")), &selectedLLMIds) if err != nil { fmt.Println("Error unmarshalling selected LLM IDs") panic(err) } var message Message err = edgeClient.QuerySingle(context.Background(), ` SELECT Message { content } FILTER .id = $0; `, &message, messageUUID) if err != nil { fmt.Println("Error getting message") panic(err) } // Delete messages err = edgeClient.Execute(edgeCtx, ` WITH messageArea := (SELECT Message FILTER .id = $0).area DELETE Area FILTER .position > messageArea.position AND .conversation = messageArea.conversation AND .conversation.user = global currentUser; `, messageUUID) if err != nil { fmt.Println("Error deleting messages") panic(err) } return c.SendString(GeneratePlaceholderHTML(message.Content, selectedLLMIds, false)) } func EditMessageHandler(c *fiber.Ctx) error { messageId := c.FormValue("id") message := c.FormValue("message") messageUUID, _ := edgedb.ParseUUID(messageId) var selectedLLMIds []string err := json.Unmarshal([]byte(c.FormValue("selectedLLMIds")), &selectedLLMIds) if err != nil { fmt.Println("Error unmarshalling selected LLM IDs") panic(err) } if len(selectedLLMIds) == 0 { return c.SendString("") } // Delete messages err = edgeClient.Execute(edgeCtx, ` WITH messageArea := (SELECT Message FILTER .id = $0).area DELETE Area FILTER .position >= messageArea.position AND .conversation = messageArea.conversation AND .conversation.user = global currentUser; `, messageUUID) if err != nil { fmt.Println("Error deleting messages") panic(err) } return c.SendString(GeneratePlaceholderHTML(message, selectedLLMIds, true)) } func ClearChatHandler(c *fiber.Ctx) error { // Delete the default conversation err := edgeClient.Execute(edgeCtx, ` DELETE Area FILTER .conversation = global currentConversation; `) if err != nil { fmt.Println("Error deleting messages") panic(err) } return c.SendString(generateChatHTML()) } // Popover stuff func LoadUsageKPIHandler(c *fiber.Ctx) error { if !checkIfLogin() || !checkIfHaveKey() { return c.SendString("") } InputDateID := c.FormValue("month", time.Now().Format("01-2006")) offset := c.FormValue("offset") IsActive := false var InputDate time.Time InputDate, err := time.Parse("01-2006", InputDateID) if err != nil { fmt.Println("Error parsing date") panic(err) } if offset == "-1" { InputDate = InputDate.AddDate(0, -1, 0) IsActive = true } else if offset == "1" { InputDate = InputDate.AddDate(0, 1, 0) IsActive = true } type UsageKPI struct { Key struct { ModelID string `edgedb:"model_id"` } `edgedb:"key"` TotalCost float32 `edgedb:"total_cost"` TotalCount int64 `edgedb:"total_count"` } var usages []UsageKPI err = edgeClient.Query(edgeCtx, ` WITH U := ( SELECT Usage FILTER .user = global currentUser and .date >= $0 AND .date < $1 ), grouped := ( GROUP U { model_id, input_cost, output_cost, } BY .model_id ) SELECT grouped { key := .key { model_id }, total_count := count(.elements), total_cost := sum(.elements.input_cost) + sum(.elements.output_cost), } FILTER .total_count > 0 ORDER BY .total_cost DESC `, &usages, InputDate, InputDate.AddDate(0, 1, 0)) if err != nil { fmt.Println("Error getting usage") panic(err) } BeautifullDate := InputDate.Format("Jan 2006") var ( TotalCount int64 TotalCost float32 ) for _, usage := range usages { TotalCost += usage.TotalCost TotalCount += usage.TotalCount } out, err := usagePopoverTmpl.Execute(pongo2.Context{ "usages": usages, "TotalCost": TotalCost, "TotalCount": TotalCount, "Date": BeautifullDate, "DateID": InputDate.Format("01-2006"), "IsActive": IsActive, }) if err != nil { fmt.Println("Error generating usage") panic(err) } return c.SendString(out) } func GenerateModelPopoverHTML(refresh bool) string { openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys() var llms []LLM err := edgeClient.Query(edgeCtx, ` SELECT LLM { id, name, context, temperature, modelInfo : { modelID, name, company : { name, icon } } } FILTER .user = global currentUser AND .name != 'none' AND .to_delete = false ORDER BY .position `, &llms) if err != nil { fmt.Println("Error loading LLMs") panic(err) } modelInfos := GetAvailableModels() out, err := modelPopoverTmpl.Execute(pongo2.Context{ "IsLogin": checkIfLogin(), "OpenaiExists": openaiExists, "AnthropicExists": anthropicExists, "MistralExists": mistralExists, "GroqExists": groqExists, "GooseaiExists": gooseaiExists, "GoogleExists": googleExists, "AnyExists": openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists, "LLMs": llms, "ModelInfos": modelInfos, "DeleteUpdate": refresh, "IsSub": IsCurrentUserSubscribed(), }) if err != nil { fmt.Println("Error generating model popover") panic(err) } return out } func LoadModelSelectionHandler(c *fiber.Ctx) error { if !checkIfLogin() || !checkIfHaveKey() { return c.SendString("") } return c.SendString(GenerateModelPopoverHTML(false)) } func GenerateConversationPopoverHTML(isActive bool) string { var conversations []Conversation err := edgeClient.Query(edgeCtx, ` SELECT Conversation { name, position, id } FILTER .user = global currentUser ORDER BY .position `, &conversations) if err != nil { fmt.Println("Error loading conversations") panic(err) } out, err := conversationPopoverTmpl.Execute(pongo2.Context{ "Conversations": conversations, "IsActive": isActive, }) if err != nil { fmt.Println("Error generating conversation popover") panic(err) } return out } func LoadConversationSelectionHandler(c *fiber.Ctx) error { if !checkIfLogin() || !checkIfHaveKey() { return c.SendString("") } return c.SendString(GenerateConversationPopoverHTML(false)) } func RefreshConversationSelectionHandler(c *fiber.Ctx) error { IsActive := c.FormValue("IsActive") == "true" return c.SendString(GenerateConversationPopoverHTML(!IsActive)) } func LoadSettingsHandler(c *fiber.Ctx) error { if !checkIfLogin() { return c.SendString("") } var user User err := edgeClient.QuerySingle(edgeCtx, ` SELECT User { email } FILTER .id = global currentUser.id `, &user) if err != nil { fmt.Println("Error loading user") panic(err) } // Percent encoding of the email user.Email = url.QueryEscape(user.Email) stripeSubLink := "https://billing.stripe.com/p/login/test_eVa5kC1q7dogaaIcMM?prefilled_email=" + user.Email openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys() out, err := settingPopoverTmpl.Execute(pongo2.Context{ "IsLogin": checkIfLogin(), "OpenaiExists": openaiExists, "AnthropicExists": anthropicExists, "MistralExists": mistralExists, "GroqExists": groqExists, "GooseaiExists": gooseaiExists, "GoogleExists": googleExists, "AnyExists": openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists, "IsSub": IsCurrentUserSubscribed(), "StripeSubLink": stripeSubLink, }) if err != nil { fmt.Println("Error loading settings") panic(err) } return c.SendString(out) } func CreateConversationHandler(c *fiber.Ctx) error { name := c.FormValue("conversation-name-input") if name == "" { name = "New Conversation" } err := edgeClient.Execute(edgeCtx, ` WITH C := ( SELECT Conversation FILTER .user = global currentUser ) INSERT Conversation { name := $0, user := global currentUser, position := count(C) + 1 } `, name) if err != nil { fmt.Println("Error creating conversation") panic(err) } return c.SendString(GenerateConversationPopoverHTML(true)) } func DeleteConversationHandler(c *fiber.Ctx) error { conversationId := c.FormValue("conversationId") conversationUUID, err := edgedb.ParseUUID(conversationId) if err != nil { fmt.Println("Error parsing UUID") panic(err) } err = edgeClient.Execute(edgeCtx, ` DELETE Conversation FILTER .user = global currentUser AND .id = $0; `, conversationUUID) if err != nil { fmt.Println("Error deleting conversation") panic(err) } return c.SendString(GenerateConversationPopoverHTML(true)) } func SelectConversationHandler(c *fiber.Ctx) error { conversationId := c.FormValue("conversation-id") conversationUUID, err := edgedb.ParseUUID(conversationId) if err != nil { fmt.Println("Error parsing UUID") panic(err) } edgeClient = edgeClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token"), "currentConversationID": conversationUUID}) return c.SendString(generateChatHTML()) }