diff --git a/.dockerignore b/.dockerignore
index 8fce603..6320cd2 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1 +1 @@
-data/
+data
\ No newline at end of file
diff --git a/Chat.go b/Chat.go
index ec52b15..622cec5 100644
--- a/Chat.go
+++ b/Chat.go
@@ -398,8 +398,8 @@ func generateLimitReachedChatHTML() string {
// TODO Replace by live API call
stripeTable := `
`
@@ -449,8 +449,7 @@ func GetEditMessageFormHandler(c *fiber.Ctx) error {
rows = 10
}
- tmpl := pongo2.Must(pongo2.FromFile("views/partials/message-edit-form.html"))
- out, err := tmpl.Execute(pongo2.Context{"Content": message.Content, "ID": id, "Rows": rows})
+ out, err := messageEditTmpl.Execute(pongo2.Context{"Content": message.Content, "ID": id, "Rows": rows})
if err != nil {
fmt.Println("Error executing user template")
panic(err)
@@ -608,7 +607,7 @@ func LoadUsageKPIHandler(c *fiber.Ctx) error {
TotalCount += usage.TotalCount
}
- out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-usage.html")).Execute(pongo2.Context{
+ out, err := usagePopoverTmpl.Execute(pongo2.Context{
"usages": usages,
"TotalCost": TotalCost,
"TotalCount": TotalCount,
@@ -624,29 +623,6 @@ func LoadUsageKPIHandler(c *fiber.Ctx) error {
return c.SendString(out)
}
-func LoadKeysHandler(c *fiber.Ctx) error {
- if !checkIfLogin() {
- return c.SendString("")
- }
- openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys()
-
- out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-keys.html")).Execute(pongo2.Context{
- "IsLogin": checkIfLogin(),
- "OpenaiExists": openaiExists,
- "AnthropicExists": anthropicExists,
- "MistralExists": mistralExists,
- "GroqExists": groqExists,
- "GooseaiExists": gooseaiExists,
- "GoogleExists": googleExists,
- "AnyExists": openaiExists || anthropicExists || mistralExists || groqExists || gooseaiExists || googleExists,
- })
- if err != nil {
- fmt.Println("Error loading keys")
- panic(err)
- }
- return c.SendString(out)
-}
-
func GenerateModelPopoverHTML(refresh bool) string {
openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys()
@@ -676,7 +652,7 @@ func GenerateModelPopoverHTML(refresh bool) string {
modelInfos := GetAvailableModels()
- out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-models.html")).Execute(pongo2.Context{
+ out, err := modelPopoverTmpl.Execute(pongo2.Context{
"IsLogin": checkIfLogin(),
"OpenaiExists": openaiExists,
"AnthropicExists": anthropicExists,
@@ -720,7 +696,7 @@ func GenerateConversationPopoverHTML(isActive bool) string {
panic(err)
}
- out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-conversation.html")).Execute(pongo2.Context{
+ out, err := conversationPopoverTmpl.Execute(pongo2.Context{
"Conversations": conversations,
"IsActive": isActive,
})
@@ -768,7 +744,7 @@ func LoadSettingsHandler(c *fiber.Ctx) error {
openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys()
- out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-settings.html")).Execute(pongo2.Context{
+ out, err := settingPopoverTmpl.Execute(pongo2.Context{
"IsLogin": checkIfLogin(),
"OpenaiExists": openaiExists,
"AnthropicExists": anthropicExists,
diff --git a/RequestMistral.go b/RequestMistral.go
index 8807e89..669b8aa 100644
--- a/RequestMistral.go
+++ b/RequestMistral.go
@@ -72,11 +72,13 @@ func TestMistralKey(apiKey string) bool {
jsonBody, err := json.Marshal(requestBody)
if err != nil {
+ fmt.Println("Error marshalling request to Mistral")
return false
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
if err != nil {
+ fmt.Println("Error creating request to Mistral")
return false
}
@@ -87,21 +89,25 @@ func TestMistralKey(apiKey string) bool {
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
+ fmt.Println("Error sending request to Mistral")
return false
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
+ fmt.Println("Error reading response from Mistral")
return false
}
var chatCompletionResponse MistralChatCompletionResponse
err = json.Unmarshal(body, &chatCompletionResponse)
if err != nil {
+ fmt.Println("Error unmarshalling response from Mistral")
return false
}
if chatCompletionResponse.Usage.CompletionTokens == 0 {
+ fmt.Println("No response from Mistral")
return false
}
return true
diff --git a/Stripe.go b/Stripe.go
index 13b6b75..8cb29d3 100644
--- a/Stripe.go
+++ b/Stripe.go
@@ -31,8 +31,8 @@ func generatePricingTableChatHTML() string {
// TODO Replace by live API call
stripeTable := `
`
diff --git a/_commands.md b/_commands.md
deleted file mode 100644
index ef5508b..0000000
--- a/_commands.md
+++ /dev/null
@@ -1,3 +0,0 @@
-
-docker build -t mrbounty1/jade:jadeAlpha1 .
-docker push mrbounty1/jade:jadeAlpha1
\ No newline at end of file
diff --git a/database.go b/database.go
index 310d95e..9122841 100644
--- a/database.go
+++ b/database.go
@@ -196,7 +196,7 @@ func insertUserMessage(content string) edgedb.UUID {
conversation := global currentConversation,
selected := true,
llm := (
- SELECT LLM FILTER .id = "32cb4f0c-1c3f-11ef-9247-2fac0086a7d1"
+ SELECT LLM FILTER .id = "f777f024-1da9-11ef-afd4-bf1c8b177a62"
)
}
`, &inserted, "user", content, lastArea.ID)
diff --git a/fly.toml b/fly.toml
new file mode 100644
index 0000000..52365b2
--- /dev/null
+++ b/fly.toml
@@ -0,0 +1,21 @@
+# fly.toml app configuration file generated for jade-2-0 on 2024-05-28T19:35:25+02:00
+#
+# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
+#
+
+app = 'jade-2-0'
+primary_region = 'cdg'
+
+[build]
+
+[http_service]
+ internal_port = 8080
+ force_https = true
+ auto_stop_machines = true
+ auto_start_machines = true
+ min_machines_running = 0
+ processes = ['app']
+
+[[vm]]
+ size = 'shared-cpu-1x'
+ memory = "256MB"
\ No newline at end of file
diff --git a/main.go b/main.go
index d6ed758..807e7f3 100644
--- a/main.go
+++ b/main.go
@@ -32,19 +32,30 @@ import (
"bufio"
"fmt"
"log"
+ "os"
"sync"
"github.com/flosch/pongo2"
"github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/favicon"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/template/django/v3"
"github.com/stripe/stripe-go"
)
-var userTmpl *pongo2.Template
-var botTmpl *pongo2.Template
-var selectBtnTmpl *pongo2.Template
+var (
+ userTmpl *pongo2.Template
+ botTmpl *pongo2.Template
+ selectBtnTmpl *pongo2.Template
+ modelPopoverTmpl *pongo2.Template
+ usagePopoverTmpl *pongo2.Template
+ settingPopoverTmpl *pongo2.Template
+ messageEditTmpl *pongo2.Template
+ conversationPopoverTmpl *pongo2.Template
+ clients = make(map[chan SSE]bool)
+ mu sync.Mutex
+)
// SSE event structure
type SSE struct {
@@ -52,12 +63,6 @@ type SSE struct {
Data string
}
-// Global channel and mutex
-var (
- clients = make(map[chan SSE]bool)
- mu sync.Mutex
-)
-
// Function to send events to all clients
func sendEvent(event, data string) {
mu.Lock()
@@ -69,12 +74,17 @@ func sendEvent(event, data string) {
}
func main() {
- // TODO Change key to env and the live one
- stripe.Key = "sk_test_51OxXuWP2nW0okNQyiNAOcBTTWZSiyP1el5KOmV3yIv1DQR0415YPsH1eb89SLrsOFj80o9p2AxGOy042e53yDvZN00jHxHAbE6"
+ // Use STRIPE_KEY environment variable
+ stripe.Key = os.Getenv("STRIPE_KEY")
botTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-bot.html"))
userTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-user.html"))
selectBtnTmpl = pongo2.Must(pongo2.FromFile("views/partials/model-selection-btn.html"))
+ modelPopoverTmpl = pongo2.Must(pongo2.FromFile("views/partials/popover-models.html"))
+ conversationPopoverTmpl = pongo2.Must(pongo2.FromFile("views/partials/popover-conversation.html"))
+ usagePopoverTmpl = pongo2.Must(pongo2.FromFile("views/partials/popover-usage.html"))
+ settingPopoverTmpl = pongo2.Must(pongo2.FromFile("views/partials/popover-settings.html"))
+ messageEditTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-edit-form.html"))
// Import HTML using django engine/template
engine := django.New("./views", ".html")
@@ -82,11 +92,13 @@ func main() {
// Create new Fiber instance
app := fiber.New(fiber.Config{
Views: engine,
- AppName: "JADE 2.0",
+ AppName: "JADE",
EnablePrintRoutes: true,
})
+ defer app.Shutdown()
// Add default logger
+ app.Use(favicon.New())
app.Use(logger.New())
app.Use(recover.New())
@@ -118,7 +130,6 @@ func main() {
app.Get("/loadConversationSelection", LoadConversationSelectionHandler)
app.Get("/refreshConversationSelection", RefreshConversationSelectionHandler)
app.Get("/loadUsageKPI", LoadUsageKPIHandler)
- app.Get("/loadKeys", LoadKeysHandler)
app.Get("/loadSettings", LoadSettingsHandler)
app.Post("/updateLLMPositionBatch", updateLLMPositionBatch)
app.Get("/createConversation", CreateConversationHandler)
@@ -175,7 +186,9 @@ func main() {
})
// Start server
- log.Fatal(app.Listen(":8080"))
+ if err := app.Listen(":8080"); err != nil {
+ log.Fatal(err)
+ }
}
// The route to add keys, idk where to put it so it's here
diff --git a/static/favicon.ico b/static/favicon.ico
new file mode 100644
index 0000000..4a25080
Binary files /dev/null and b/static/favicon.ico differ
diff --git a/static/style.css b/static/style.css
index 706e1e1..bfcc4bd 100644
--- a/static/style.css
+++ b/static/style.css
@@ -1,5 +1,5 @@
body {
- padding-bottom: 155px;
+ padding-bottom: 40px;
}
html {
diff --git a/views/chat.html b/views/chat.html
index c789346..f49317e 100644
--- a/views/chat.html
+++ b/views/chat.html
@@ -57,9 +57,7 @@
textarea.addEventListener('keydown', handleTextareaKeydown);
function toggleSendButton() {
- const sendButton = document.getElementById('chat-input-send-btn');
- const selectedLLMIds = JSON.parse(getSelectedModelsIDs());
- sendButton.disabled = textarea.value.trim() === '' || selectedLLMIds.length === 0;
+ document.getElementById('chat-input-send-btn').disabled = textarea.value.trim().length === 0 || document.getElementsByClassName('selected icon-llm').length === 0;
}
function clearTextArea() {
@@ -75,12 +73,10 @@
}
function handleTextareaKeydown(event) {
- if (event.metaKey && event.key === 'Enter') {
+ if (event.metaKey && event.key === 'Enter' && event.target === textarea && textarea.value.trim() !== '' && document.getElementsByClassName('selected icon-llm').length !== 0) {
// Check if the cursor is in the textarea
- if (event.target === textarea) {
- // Trigger the same action as the send button
- document.getElementById('chat-input-send-btn').click();
- }
+ // Trigger the same action as the send button
+ document.getElementById('chat-input-send-btn').click();
}
}
\ No newline at end of file
diff --git a/views/layouts/main.html b/views/layouts/main.html
index 2ad6fbd..ab7bb78 100644
--- a/views/layouts/main.html
+++ b/views/layouts/main.html
@@ -86,6 +86,63 @@
button.innerHTML = originalText;
}, 2000);
}
+
+ let lastSelectedIndex = null;
+
+ function toggleSelection(element) {
+ const elements = Array.from(document.getElementsByClassName('icon-llm'));
+ const index = elements.indexOf(element);
+
+ if (document.body.classList.contains('shift-pressed') && lastSelectedIndex !== null) {
+ const [start, end] = [lastSelectedIndex, index].sort((a, b) => a - b);
+ let allSelected = true;
+ for (let i = start; i <= end; i++) {
+ if (!elements[i].classList.contains('selected')) {
+ allSelected = false;
+ break;
+ }
+ }
+ for (let i = start; i <= end; i++) {
+ if (allSelected) {
+ elements[i].classList.remove('selected');
+ elements[i].classList.add('unselected');
+ } else {
+ elements[i].classList.add('selected');
+ elements[i].classList.remove('unselected');
+ }
+ }
+ lastSelectedIndex = null;
+
+ const elements2 = Array.from(document.getElementsByClassName('icon-text'));
+ for (let i = 0; i < elements2.length; i++) {
+ elements2[i].classList.remove('shiftselected');
+ }
+ } else if (document.body.classList.contains('shift-pressed') && lastSelectedIndex === null) {
+ lastSelectedIndex = index;
+ element.classList.toggle('shiftselected');
+ } else {
+ element.classList.toggle('selected');
+ element.classList.toggle('unselected');
+ }
+
+ // If at least one model is selected, enable the delete button
+ if (document.getElementsByClassName('selected icon-llm').length > 0) {
+ document.getElementById('delete-model-button').disabled = false;
+ } else {
+ document.getElementById('delete-model-button').disabled = true;
+ }
+
+ toggleSendButton();
+ }
+
+ function getSelectedModelsIDs() {
+ var selectedModelsIDs = [];
+ var selectedModels = document.getElementsByClassName('selected icon-llm');
+ for (var i = 0; i < selectedModels.length; i++) {
+ selectedModelsIDs.push(selectedModels[i].getAttribute('data-id'));
+ }
+ return selectedModelsIDs.length > 0 ? JSON.stringify(selectedModelsIDs) : '[]';
+ }