$0
SET {selected := true};
`, messageUUID)
return c.SendString(out)
}
func generateWelcomeChatHTML() string {
welcomeMessage, err := welcomeChatTmpl.Execute(pongo2.Context{})
if err != nil {
fmt.Println("Error executing welcome chat template")
panic(err)
}
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, "DontShowName": 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 generateHelpChatHandler(c *fiber.Ctx) error {
return c.SendString(generateHelpChatHTML())
}
func generateHelpChatHTML() string {
out, err := explainLLMconvChatTmpl.Execute(pongo2.Context{})
if err != nil {
fmt.Println("Error executing explain LLM and Conversation template")
panic(err)
}
htmlString := ""
closeBtn := `
`
NextMessages := []TemplateMessage{}
nextMsg := TemplateMessage{
Icon: "icons/bouvai2.png", // Assuming Icon is a field you want to include from Message
Content: out + 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, "DontShowName": 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 := `
API keys
JADE require at least one API key to work. Add one in the settings at the bottom right of the page.
API keys are unique codes that allow you to access and use different Large Language Model (LLM) providers.
Most providers offer free credits when you first sign up or per minute, which means you have a balance in your account that you can use to generate messages.
You pay for the service based on the number of tokens input and generated. A token is a small unit of text, roughly equivalent to 3 characters. So, a small input and output text will cost very little.
Pricing Examples
- For $1, you can ask 2,000 questions to GPT-4o, or 20,000 to GPT-3.5 turbo (around 100 tokens per message).
- For 1 message it would cost you $0.0005 for GPT-4o or $0.00005 for GPT-3.5 turbo (around 100 tokens per message).
- For 1 large text, like a PDF with 30,000 characters (60-120 pages), you would pay around $0.05 per message for GPT-4o or $0.005 for GPT-3.5 turbo.
Remember, prices and token limits may vary depending on the provider and the specific LLM you're using.
Start for free
Groq and Google offer free messages per minutes, enough for a conversation. Allowing you to use their models with JADE for free.
OpenAI and Anthropic offer 5$ of free credits when creating an account. So you can try JADE with their models for free.
Get a key
To get a key and learn more about the different LLM providers and their offerings, check out their websites:
Get OpenAI API key
Get Anthropic API key
Get Mistral API key
Get Groq API key
Get Google API key
Get Perplexity API key
Get Fireworks API key
`
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, "DontShowName": 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 := `
Terms of Service
1. Acceptance of Terms
By using JADE (the "App"), you agree to be bound by these Terms of Service ("Terms"). If you do not agree to these Terms, please do not use the App.
2. Description of Service
The App is a chatbot that makes requests to various third-party APIs to provide information and services. The App is provided "as is" and "as available" without any warranties of any kind.
3. User Responsibilities
- You are responsible for any content you generate or share using the App.
- You agree not to use the App for any unlawful or harmful activities.
4. Authentication and Payment
- Authentication for the App is managed by Google and GitHub. We are not responsible for any issues related to authentication, including but not limited to, unauthorized access or data breaches. Please refer to Google and GitHub's respective terms of service and privacy policies for more information.
- Payments for any services within the App are processed by Stripe. We are not responsible for any issues related to payment processing, including but not limited to, transaction errors or unauthorized transactions. Please refer to Stripe's terms of service and privacy policy for more information.
5. Disclaimer of Warranties
- The App is provided without warranties of any kind, either express or implied, including but not limited to, implied warranties of merchantability, fitness for a particular purpose, or non-infringement.
- We do not guarantee the accuracy, completeness, or usefulness of any information provided by the App.
6. Limitation of Liability
- In no event shall BouvAI, its affiliates, or its licensors be liable for any indirect, incidental, special, consequential, or punitive damages, including but not limited to, loss of profits, data, use, goodwill, or other intangible losses, resulting from (i) your use or inability to use the App; (ii) any unauthorized access to or use of our servers and/or any personal information stored therein; (iii) any bugs, viruses, trojan horses, or the like that may be transmitted to or through our App by any third party; or (iv) any errors or omissions in any content or for any loss or damage incurred as a result of the use of any content posted, emailed, transmitted, or otherwise made available through the App, whether based on warranty, contract, tort (including negligence), or any other legal theory, whether or not we have been informed of the possibility of such damage.
7. Data Privacy
- We are not responsible for any data leaks or breaches that may occur. Users are advised to use the App at their own risk.
- Stored data include messages, conversations, usage, bots and keys. I do not strore any personal infos, google and github send me your email, name and avatar as minimum at your first login but I do not save them.
8. Changes to the Terms
We reserve the right to modify these Terms at any time. Any changes will be effective immediately upon posting the updated Terms on our website or within the App. Your continued use of the App after any such changes constitutes your acceptance of the new Terms.
9. Governing Law
These Terms shall be governed and construed in accordance with the laws of Luxembourg, without regard to its conflict of law principles.
10. Contact Information
If you have any questions about these Terms, please contact us at adrien.bouvais@bouvai.com.
BouvAI
`
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, "DontShowName": 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(c *fiber.Ctx) 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 := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, "SELECT global currentUser { stripe_id, email } LIMIT 1;", &result)
if err != nil {
fmt.Println("Error getting current user")
panic(err)
}
clientSecretSession := CreateClientSecretSession(c)
stripeTable := `
`
htmlString := ""
NextMessages := []TemplateMessage{}
nextMsg := TemplateMessage{
Icon: "icons/bouvai2.png", // Assuming Icon is a field you want to include from Message
Content: "
" + 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
}
func GetSelectionBtnHandler(c *fiber.Ctx) error {
messageId := c.FormValue("id")
messageUUID, err := edgedb.ParseUUID(messageId)
if err != nil {
fmt.Println("Error parsing UUID")
panic(err)
}
var message Message
err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(edgeCtx, `
SELECT Message {
id,
content,
area : {
id,
position
},
llm : {
modelInfo : {
modelID,
name,
company : {
icon,
}
}
}
}
FILTER .id = $0;
`, &message, messageUUID)
if err != nil {
fmt.Println("Error getting message")
panic(err)
}
templateMessage := TemplateMessage{
Icon: message.LLM.Model.Company.Icon,
Content: message.Content,
Hidden: false,
Id: message.ID.String(),
Name: message.LLM.Model.Name,
ModelID: message.LLM.Model.ModelID,
}
outBtn, err := selectBtnTmpl.Execute(map[string]interface{}{
"message": templateMessage,
"ConversationAreaId": message.Area.Position,
})
if err != nil {
fmt.Println("Error generating HTML content")
panic(err)
}
outBtn = strings.ReplaceAll(outBtn, "\n", "")
return c.SendString(outBtn)
}
// Button actions
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 = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).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(c))
}
func GetEditMessageFormHandler(c *fiber.Ctx) error {
id := c.FormValue("id")
idUUID, _ := edgedb.ParseUUID(id)
var message Message
err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).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 = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).QuerySingle(context.Background(), `
SELECT Message { content }
FILTER .id = $0;
`, &message, messageUUID)
if err != nil {
fmt.Println("Error getting message")
panic(err)
}
// Delete messages
err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).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(c, 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 = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).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(c, message, selectedLLMIds, true))
}
func ClearChatHandler(c *fiber.Ctx) error {
// Delete the default conversation
err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Execute(edgeCtx, `
DELETE Area
FILTER .conversation = global currentConversation;
`)
if err != nil {
fmt.Println("Error deleting messages")
panic(err)
}
return c.SendString(generateChatHTML(c))
}
// Popover stuff
func LoadUsageKPIHandler(c *fiber.Ctx) error {
if !checkIfLogin(c) || !checkIfHaveKey(c) {
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 = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).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, c *fiber.Ctx) string {
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, `
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)
}
var modelInfos []ModelInfo
err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Query(edgeCtx, `
SELECT ModelInfo {
modelID,
name,
company : {
name,
icon
}
}
FILTER .modelID != 'none' AND .company.name != 'huggingface' AND .company IN global currentUser.setting.keys.company
ORDER BY .company.name ASC THEN .name ASC
`, &modelInfos)
if err != nil {
fmt.Println("Error getting models")
panic(err)
}
isPremium, isBasic := IsCurrentUserSubscribed(c)
out, err := modelPopoverTmpl.Execute(pongo2.Context{
"IsLogin": checkIfLogin(c),
"OpenaiExists": openaiExists,
"AnthropicExists": anthropicExists,
"MistralExists": mistralExists,
"GroqExists": groqExists,
"GooseaiExists": gooseaiExists,
"GoogleExists": googleExists,
"PerplexityExists": perplexityExists,
"FireworksExists": fireworksExists,
"AnyExists": fireworksExists || openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists || perplexityExists,
"LLMs": llms,
"ModelInfos": modelInfos,
"DeleteUpdate": refresh,
"IsSub": isPremium || isBasic,
})
if err != nil {
fmt.Println("Error generating model popover")
panic(err)
}
return out
}
func LoadModelSelectionHandler(c *fiber.Ctx) error {
if !checkIfLogin(c) || !checkIfHaveKey(c) {
return c.SendString("")
}
return c.SendString(GenerateModelPopoverHTML(false, c))
}
func GenerateConversationPopoverHTML(isActive bool, c *fiber.Ctx) string {
var conversations []Conversation
err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Query(edgeCtx, `
SELECT Conversation {
name,
position,
selected,
id
}
FILTER .user = global currentUser
ORDER BY .position
`, &conversations)
if err != nil {
fmt.Println("Error loading conversations")
panic(err)
}
selectedIsDefault := false
for _, conversation := range conversations {
if conversation.Name == "Default" && conversation.Selected {
selectedIsDefault = true
}
}
out, err := conversationPopoverTmpl.Execute(pongo2.Context{
"Conversations": conversations,
"IsActive": isActive,
"SelectedIsDefault": selectedIsDefault,
})
if err != nil {
fmt.Println("Error generating conversation popover")
panic(err)
}
return out
}
func LoadConversationSelectionHandler(c *fiber.Ctx) error {
if !checkIfLogin(c) || !checkIfHaveKey(c) {
return c.SendString("")
}
return c.SendString(GenerateConversationPopoverHTML(false, c))
}
func RefreshConversationSelectionHandler(c *fiber.Ctx) error {
IsActive := c.FormValue("IsActive") == "true"
return c.SendString(GenerateConversationPopoverHTML(!IsActive, c))
}
func LoadSettingsHandler(c *fiber.Ctx) error {
if !checkIfLogin(c) {
return c.SendString("")
}
var user User
err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).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/6oE6sc0PTfvq1Hi288?prefilled_email=" + user.Email
openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists, perplexityExists, fireworksExists := getExistingKeys(c)
isPremium, isBasic := IsCurrentUserSubscribed(c)
out, err := settingPopoverTmpl.Execute(pongo2.Context{
"IsLogin": checkIfLogin(c),
"OpenaiExists": openaiExists,
"AnthropicExists": anthropicExists,
"MistralExists": mistralExists,
"GroqExists": groqExists,
"GooseaiExists": gooseaiExists,
"GoogleExists": googleExists,
"PerplexityExists": perplexityExists,
"FireworksExists": fireworksExists,
"AnyExists": fireworksExists || openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists || perplexityExists,
"isPremium": isPremium,
"isBasic": isBasic,
"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 := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).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, c))
}
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 = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Execute(edgeCtx, `
DELETE Conversation
FILTER .user = global currentUser AND .id = $0;
`, conversationUUID)
if err != nil {
fmt.Println("Error deleting conversation")
panic(err)
}
// Select the default conversation
err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Execute(edgeCtx, `
UPDATE Conversation
FILTER .user = global currentUser AND .name = 'Default'
SET {
selected := true
};
`)
if err != nil {
fmt.Println("Error selecting default conversation")
panic(err)
}
reloadChatTriggerHTML := `
`
return c.SendString(GenerateConversationPopoverHTML(true, c) + reloadChatTriggerHTML)
}
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)
}
err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Execute(edgeCtx, `
UPDATE Conversation
FILTER .user = global currentUser
SET {
selected := false
};
`, conversationUUID)
if err != nil {
fmt.Println("Error unselecting conversations")
panic(err)
}
err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Execute(edgeCtx, `
UPDATE Conversation
FILTER .user = global currentUser AND .id = $0
SET {
selected := true
};
`, conversationUUID)
if err != nil {
fmt.Println("Error selecting conversations")
panic(err)
}
return c.SendString(generateChatHTML(c))
}
func ArchiveDefaultConversationHandler(c *fiber.Ctx) error {
name := c.FormValue("conversation-name-input")
err := edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Execute(edgeCtx, `
UPDATE Conversation
FILTER .user = global currentUser AND .name = 'Default'
SET {
name := $0
};
`, name)
if err != nil {
fmt.Println("Error archiving default conversation")
panic(err)
}
err = edgeGlobalClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": c.Cookies("jade-edgedb-auth-token")}).Execute(edgeCtx, `
WITH
C := (
SELECT Conversation
FILTER .user = global currentUser
)
INSERT Conversation {
name := "Default",
user := global currentUser,
position := count(C) + 1
}
`, name)
if err != nil {
fmt.Println("Error creating conversation")
panic(err)
}
return c.SendString(GenerateConversationPopoverHTML(true, c))
}