swap to fly.io

This commit is contained in:
Adrien Bouvais 2024-05-29 13:01:20 +02:00
parent a5a322cd38
commit f2f6547b22
13 changed files with 129 additions and 124 deletions

View File

@ -1 +1 @@
data/ data

38
Chat.go
View File

@ -398,8 +398,8 @@ func generateLimitReachedChatHTML() string {
// TODO Replace by live API call // TODO Replace by live API call
stripeTable := ` stripeTable := `
<stripe-pricing-table <stripe-pricing-table
pricing-table-id="prctbl_1OxrazP2nW0okNQymYvskUk7" pricing-table-id="prctbl_1PJAxDP2nW0okNQyY0Q3mbg4"
publishable-key="pk_test_51OxXuWP2nW0okNQy2jyS70vx7WHZzDskvQazsitSDJQ3ifVHPqAkMv7orCePwRGRTarNn8uMuaxbVqD2Zg80oRc600epN4ycQ4" publishable-key="pk_live_51OxXuWP2nW0okNQyme1qdwbL535jbMmM1uIUi6U5zcvEUUwKraktmpCzudXNdPSTxlHpw2FbCtxpwbyFFcasQ7aj000tJJGpWW"
customer-session-client-secret="` + clientSecretSession + `"> customer-session-client-secret="` + clientSecretSession + `">
</stripe-pricing-table>` </stripe-pricing-table>`
@ -449,8 +449,7 @@ func GetEditMessageFormHandler(c *fiber.Ctx) error {
rows = 10 rows = 10
} }
tmpl := pongo2.Must(pongo2.FromFile("views/partials/message-edit-form.html")) out, err := messageEditTmpl.Execute(pongo2.Context{"Content": message.Content, "ID": id, "Rows": rows})
out, err := tmpl.Execute(pongo2.Context{"Content": message.Content, "ID": id, "Rows": rows})
if err != nil { if err != nil {
fmt.Println("Error executing user template") fmt.Println("Error executing user template")
panic(err) panic(err)
@ -608,7 +607,7 @@ func LoadUsageKPIHandler(c *fiber.Ctx) error {
TotalCount += usage.TotalCount 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, "usages": usages,
"TotalCost": TotalCost, "TotalCost": TotalCost,
"TotalCount": TotalCount, "TotalCount": TotalCount,
@ -624,29 +623,6 @@ func LoadUsageKPIHandler(c *fiber.Ctx) error {
return c.SendString(out) 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 { func GenerateModelPopoverHTML(refresh bool) string {
openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys() openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys()
@ -676,7 +652,7 @@ func GenerateModelPopoverHTML(refresh bool) string {
modelInfos := GetAvailableModels() modelInfos := GetAvailableModels()
out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-models.html")).Execute(pongo2.Context{ out, err := modelPopoverTmpl.Execute(pongo2.Context{
"IsLogin": checkIfLogin(), "IsLogin": checkIfLogin(),
"OpenaiExists": openaiExists, "OpenaiExists": openaiExists,
"AnthropicExists": anthropicExists, "AnthropicExists": anthropicExists,
@ -720,7 +696,7 @@ func GenerateConversationPopoverHTML(isActive bool) string {
panic(err) panic(err)
} }
out, err := pongo2.Must(pongo2.FromFile("views/partials/popover-conversation.html")).Execute(pongo2.Context{ out, err := conversationPopoverTmpl.Execute(pongo2.Context{
"Conversations": conversations, "Conversations": conversations,
"IsActive": isActive, "IsActive": isActive,
}) })
@ -768,7 +744,7 @@ func LoadSettingsHandler(c *fiber.Ctx) error {
openaiExists, anthropicExists, mistralExists, groqExists, gooseaiExists, googleExists := getExistingKeys() 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(), "IsLogin": checkIfLogin(),
"OpenaiExists": openaiExists, "OpenaiExists": openaiExists,
"AnthropicExists": anthropicExists, "AnthropicExists": anthropicExists,

View File

@ -72,11 +72,13 @@ func TestMistralKey(apiKey string) bool {
jsonBody, err := json.Marshal(requestBody) jsonBody, err := json.Marshal(requestBody)
if err != nil { if err != nil {
fmt.Println("Error marshalling request to Mistral")
return false return false
} }
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
if err != nil { if err != nil {
fmt.Println("Error creating request to Mistral")
return false return false
} }
@ -87,21 +89,25 @@ func TestMistralKey(apiKey string) bool {
client := &http.Client{} client := &http.Client{}
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
fmt.Println("Error sending request to Mistral")
return false return false
} }
defer resp.Body.Close() defer resp.Body.Close()
body, err := io.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
fmt.Println("Error reading response from Mistral")
return false return false
} }
var chatCompletionResponse MistralChatCompletionResponse var chatCompletionResponse MistralChatCompletionResponse
err = json.Unmarshal(body, &chatCompletionResponse) err = json.Unmarshal(body, &chatCompletionResponse)
if err != nil { if err != nil {
fmt.Println("Error unmarshalling response from Mistral")
return false return false
} }
if chatCompletionResponse.Usage.CompletionTokens == 0 { if chatCompletionResponse.Usage.CompletionTokens == 0 {
fmt.Println("No response from Mistral")
return false return false
} }
return true return true

View File

@ -31,8 +31,8 @@ func generatePricingTableChatHTML() string {
// TODO Replace by live API call // TODO Replace by live API call
stripeTable := ` stripeTable := `
<stripe-pricing-table <stripe-pricing-table
pricing-table-id="prctbl_1OxrazP2nW0okNQymYvskUk7" pricing-table-id="prctbl_1PJAxDP2nW0okNQyY0Q3mbg4"
publishable-key="pk_test_51OxXuWP2nW0okNQy2jyS70vx7WHZzDskvQazsitSDJQ3ifVHPqAkMv7orCePwRGRTarNn8uMuaxbVqD2Zg80oRc600epN4ycQ4" publishable-key="pk_live_51OxXuWP2nW0okNQyme1qdwbL535jbMmM1uIUi6U5zcvEUUwKraktmpCzudXNdPSTxlHpw2FbCtxpwbyFFcasQ7aj000tJJGpWW"
customer-session-client-secret="` + clientSecretSession + `"> customer-session-client-secret="` + clientSecretSession + `">
</stripe-pricing-table>` </stripe-pricing-table>`

View File

@ -1,3 +0,0 @@
docker build -t mrbounty1/jade:jadeAlpha1 .
docker push mrbounty1/jade:jadeAlpha1

View File

@ -196,7 +196,7 @@ func insertUserMessage(content string) edgedb.UUID {
conversation := global currentConversation, conversation := global currentConversation,
selected := true, selected := true,
llm := ( llm := (
SELECT LLM FILTER .id = <uuid>"32cb4f0c-1c3f-11ef-9247-2fac0086a7d1" SELECT LLM FILTER .id = <uuid>"f777f024-1da9-11ef-afd4-bf1c8b177a62"
) )
} }
`, &inserted, "user", content, lastArea.ID) `, &inserted, "user", content, lastArea.ID)

21
fly.toml Normal file
View File

@ -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"

41
main.go
View File

@ -32,19 +32,30 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"log" "log"
"os"
"sync" "sync"
"github.com/flosch/pongo2" "github.com/flosch/pongo2"
"github.com/gofiber/fiber/v2" "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/logger"
"github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/template/django/v3" "github.com/gofiber/template/django/v3"
"github.com/stripe/stripe-go" "github.com/stripe/stripe-go"
) )
var userTmpl *pongo2.Template var (
var botTmpl *pongo2.Template userTmpl *pongo2.Template
var selectBtnTmpl *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 // SSE event structure
type SSE struct { type SSE struct {
@ -52,12 +63,6 @@ type SSE struct {
Data string Data string
} }
// Global channel and mutex
var (
clients = make(map[chan SSE]bool)
mu sync.Mutex
)
// Function to send events to all clients // Function to send events to all clients
func sendEvent(event, data string) { func sendEvent(event, data string) {
mu.Lock() mu.Lock()
@ -69,12 +74,17 @@ func sendEvent(event, data string) {
} }
func main() { func main() {
// TODO Change key to env and the live one // Use STRIPE_KEY environment variable
stripe.Key = "sk_test_51OxXuWP2nW0okNQyiNAOcBTTWZSiyP1el5KOmV3yIv1DQR0415YPsH1eb89SLrsOFj80o9p2AxGOy042e53yDvZN00jHxHAbE6" stripe.Key = os.Getenv("STRIPE_KEY")
botTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-bot.html")) botTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-bot.html"))
userTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-user.html")) userTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-user.html"))
selectBtnTmpl = pongo2.Must(pongo2.FromFile("views/partials/model-selection-btn.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 // Import HTML using django engine/template
engine := django.New("./views", ".html") engine := django.New("./views", ".html")
@ -82,11 +92,13 @@ func main() {
// Create new Fiber instance // Create new Fiber instance
app := fiber.New(fiber.Config{ app := fiber.New(fiber.Config{
Views: engine, Views: engine,
AppName: "JADE 2.0", AppName: "JADE",
EnablePrintRoutes: true, EnablePrintRoutes: true,
}) })
defer app.Shutdown()
// Add default logger // Add default logger
app.Use(favicon.New())
app.Use(logger.New()) app.Use(logger.New())
app.Use(recover.New()) app.Use(recover.New())
@ -118,7 +130,6 @@ func main() {
app.Get("/loadConversationSelection", LoadConversationSelectionHandler) app.Get("/loadConversationSelection", LoadConversationSelectionHandler)
app.Get("/refreshConversationSelection", RefreshConversationSelectionHandler) app.Get("/refreshConversationSelection", RefreshConversationSelectionHandler)
app.Get("/loadUsageKPI", LoadUsageKPIHandler) app.Get("/loadUsageKPI", LoadUsageKPIHandler)
app.Get("/loadKeys", LoadKeysHandler)
app.Get("/loadSettings", LoadSettingsHandler) app.Get("/loadSettings", LoadSettingsHandler)
app.Post("/updateLLMPositionBatch", updateLLMPositionBatch) app.Post("/updateLLMPositionBatch", updateLLMPositionBatch)
app.Get("/createConversation", CreateConversationHandler) app.Get("/createConversation", CreateConversationHandler)
@ -175,7 +186,9 @@ func main() {
}) })
// Start server // 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 // The route to add keys, idk where to put it so it's here

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

View File

@ -1,5 +1,5 @@
body { body {
padding-bottom: 155px; padding-bottom: 40px;
} }
html { html {

View File

@ -57,9 +57,7 @@
textarea.addEventListener('keydown', handleTextareaKeydown); textarea.addEventListener('keydown', handleTextareaKeydown);
function toggleSendButton() { function toggleSendButton() {
const sendButton = document.getElementById('chat-input-send-btn'); document.getElementById('chat-input-send-btn').disabled = textarea.value.trim().length === 0 || document.getElementsByClassName('selected icon-llm').length === 0;
const selectedLLMIds = JSON.parse(getSelectedModelsIDs());
sendButton.disabled = textarea.value.trim() === '' || selectedLLMIds.length === 0;
} }
function clearTextArea() { function clearTextArea() {
@ -75,12 +73,10 @@
} }
function handleTextareaKeydown(event) { 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 // Check if the cursor is in the textarea
if (event.target === textarea) { // Trigger the same action as the send button
// Trigger the same action as the send button document.getElementById('chat-input-send-btn').click();
document.getElementById('chat-input-send-btn').click();
}
} }
} }
</script> </script>

View File

@ -86,6 +86,63 @@
button.innerHTML = originalText; button.innerHTML = originalText;
}, 2000); }, 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) : '[]';
}
</script> </script>
</body> </body>

View File

@ -127,11 +127,13 @@
}) })
document.getElementById('create-model-button').addEventListener('click', function () { document.getElementById('create-model-button').addEventListener('click', function () {
console.log('create model');
document.getElementById('models-list').classList.add('is-hidden'); document.getElementById('models-list').classList.add('is-hidden');
document.getElementById('models-creation').classList.remove('is-hidden'); document.getElementById('models-creation').classList.remove('is-hidden');
}); });
document.getElementById('cancel-create-model-button').addEventListener('click', function () { document.getElementById('cancel-create-model-button').addEventListener('click', function () {
console.log('cancel create model');
document.getElementById('models-list').classList.remove('is-hidden'); document.getElementById('models-list').classList.remove('is-hidden');
document.getElementById('models-creation').classList.add('is-hidden'); document.getElementById('models-creation').classList.add('is-hidden');
}); });
@ -161,68 +163,5 @@
event.preventDefault(); event.preventDefault();
} }
}); });
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) : '[]';
}
function toggleSendButton() {
var selectedModels = document.getElementsByClassName('selected');
var sendButton = document.getElementById('chat-input-send-btn');
sendButton.disabled = selectedModels.length === 0;
}
</script> </script>
</div> </div>