Barely working per request response
This commit is contained in:
parent
bb8f53a018
commit
1b73a97ff1
30
Chat.go
30
Chat.go
@ -15,11 +15,6 @@ import (
|
||||
func ChatPageHandler(c *fiber.Ctx) error {
|
||||
authCookie := c.Cookies("jade-edgedb-auth-token", "")
|
||||
|
||||
go func() {
|
||||
fmt.Println("Sending test event")
|
||||
sseChanel.SendEvent("test", "Hello from server")
|
||||
}()
|
||||
|
||||
if authCookie != "" && !checkIfLogin() {
|
||||
edgeClient = edgeClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": authCookie})
|
||||
}
|
||||
@ -141,19 +136,16 @@ func generateChatHTML() string {
|
||||
|
||||
func GetMessageContentHandler(c *fiber.Ctx) error {
|
||||
messageId := c.FormValue("id")
|
||||
onlyContent := c.FormValue("onlyContent")
|
||||
onlyContent := c.FormValue("onlyContent") // To init the text area of the edit message form
|
||||
|
||||
messageUUID, err := edgedb.ParseUUID(messageId)
|
||||
if err != nil {
|
||||
fmt.Println("Error in uuid.FromString: in DeleteMessageHandler")
|
||||
fmt.Println(err)
|
||||
}
|
||||
messageUUID, _ := edgedb.ParseUUID(messageId)
|
||||
|
||||
var selectedMessage Message
|
||||
err = edgeClient.QuerySingle(context.Background(), `
|
||||
err := edgeClient.QuerySingle(context.Background(), `
|
||||
SELECT Message {
|
||||
model_id,
|
||||
content
|
||||
content,
|
||||
area
|
||||
}
|
||||
FILTER
|
||||
.id = <uuid>$0;
|
||||
@ -162,12 +154,11 @@ func GetMessageContentHandler(c *fiber.Ctx) error {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
modelID, _ := selectedMessage.ModelID.Get()
|
||||
|
||||
if onlyContent == "true" {
|
||||
return c.SendString(markdownToHTML(selectedMessage.Content))
|
||||
}
|
||||
|
||||
modelID, _ := selectedMessage.ModelID.Get()
|
||||
out := "<div class='message-header'>"
|
||||
out += "<p>"
|
||||
out += model2Name(modelID)
|
||||
@ -303,15 +294,6 @@ func RedoMessageHandler(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
selectedModelIds := []string{}
|
||||
for ModelInfo := range ModelsInfos {
|
||||
out := c.FormValue("model-check-" + ModelsInfos[ModelInfo].ID)
|
||||
if out != "" {
|
||||
selectedModelIds = append(selectedModelIds, ModelsInfos[ModelInfo].ID)
|
||||
}
|
||||
}
|
||||
lastSelectedModelIds = removeDuplicate(selectedModelIds)
|
||||
|
||||
return c.SendString(messageOut)
|
||||
}
|
||||
|
||||
|
231
Request.go
231
Request.go
@ -28,62 +28,69 @@ type CompanyInfo struct {
|
||||
ModelInfos []ModelInfo
|
||||
}
|
||||
|
||||
type SelectedModel struct {
|
||||
ID string
|
||||
Name string
|
||||
Icon string
|
||||
}
|
||||
|
||||
var CompanyInfos []CompanyInfo
|
||||
var ModelsInfos []ModelInfo
|
||||
|
||||
type MultipleModelsCompletionRequest struct {
|
||||
ModelIds []string
|
||||
Messages []Message
|
||||
Message string
|
||||
}
|
||||
|
||||
type BotContentMessage struct {
|
||||
Content string
|
||||
Hidden bool
|
||||
}
|
||||
|
||||
var lastSelectedModelIds []string
|
||||
|
||||
func addUsage(inputCost float32, outputCost float32, inputToken int32, outputToken int32, modelID string) {
|
||||
// Create a new usage
|
||||
err := edgeClient.Execute(edgeCtx, `
|
||||
INSERT Usage {
|
||||
input_cost := <float32>$0,
|
||||
output_cost := <float32>$1,
|
||||
input_token := <int32>$2,
|
||||
output_token := <int32>$3,
|
||||
model_id := <str>$4,
|
||||
user := global currentUser
|
||||
}
|
||||
`, inputCost, outputCost, inputToken, outputToken, modelID)
|
||||
if err != nil {
|
||||
fmt.Println("Error in edgedb.QuerySingle: in addUsage")
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateMultipleMessages(c *fiber.Ctx) error {
|
||||
message := c.FormValue("message", "")
|
||||
selectedModelIds := []string{}
|
||||
for ModelInfo := range ModelsInfos {
|
||||
out := c.FormValue("model-check-" + ModelsInfos[ModelInfo].ID)
|
||||
if out != "" {
|
||||
selectedModelIds = append(selectedModelIds, ModelsInfos[ModelInfo].ID)
|
||||
}
|
||||
}
|
||||
|
||||
_, position := insertArea()
|
||||
messageID := insertUserMessage(message)
|
||||
|
||||
out := ""
|
||||
messageOut, _ := userTmpl.Execute(pongo2.Context{"Content": markdownToHTML(message), "ID": messageID.String()})
|
||||
out += messageOut
|
||||
|
||||
var selectedModels []SelectedModel
|
||||
for i := range selectedModelIds {
|
||||
selectedModels = append(selectedModels, SelectedModel{ID: selectedModelIds[i], Name: model2Name(selectedModelIds[i]), Icon: model2Icon(selectedModelIds[i])})
|
||||
}
|
||||
|
||||
messageOut, _ = botTmpl.Execute(pongo2.Context{"IsPlaceholder": true, "selectedModels": selectedModels, "ConversationAreaId": position + 1})
|
||||
out += messageOut
|
||||
|
||||
go HandleGenerateMultipleMessages(selectedModelIds)
|
||||
|
||||
return c.SendString(out)
|
||||
}
|
||||
|
||||
func HandleGenerateMultipleMessages(selectedModelIds []string) {
|
||||
insertArea()
|
||||
|
||||
// Create a wait group to synchronize the goroutines
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Add the length of lastSelectedModelIds goroutines to the wait group
|
||||
wg.Add(len(lastSelectedModelIds))
|
||||
// Add the length of selectedModelIds goroutines to the wait group
|
||||
wg.Add(len(selectedModelIds))
|
||||
|
||||
for i := range lastSelectedModelIds {
|
||||
// Create a channel to receive the index of the first completed goroutine
|
||||
firstDone := make(chan int, 1)
|
||||
|
||||
for i := range selectedModelIds {
|
||||
idx := i
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
// Create a context with a 1-minute timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel() // Ensure the context is cancelled to free resources
|
||||
|
||||
// Use a channel to signal the completion of addxxxMessage
|
||||
done := make(chan struct{}, 1)
|
||||
|
||||
// Determine which message function to call based on the model
|
||||
var addMessageFunc func(modelID string, selected bool) edgedb.UUID
|
||||
switch model2Icon(lastSelectedModelIds[idx]) {
|
||||
switch model2Icon(selectedModelIds[idx]) {
|
||||
case "openai":
|
||||
addMessageFunc = addOpenaiMessage
|
||||
case "anthropic":
|
||||
@ -94,62 +101,110 @@ func GenerateMultipleMessages(c *fiber.Ctx) error {
|
||||
addMessageFunc = addGroqMessage
|
||||
}
|
||||
|
||||
// Call the selected addMessageFunc in a goroutine
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if addMessageFunc != nil {
|
||||
addMessageFunc(lastSelectedModelIds[idx], idx == 0)
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
var messageID edgedb.UUID
|
||||
if addMessageFunc != nil {
|
||||
messageID = addMessageFunc(selectedModelIds[idx], idx == 0)
|
||||
}
|
||||
|
||||
// Use select to wait on multiple channel operations
|
||||
var message Message
|
||||
err := edgeClient.QuerySingle(edgeCtx, `
|
||||
SELECT Message {
|
||||
model_id,
|
||||
content,
|
||||
area
|
||||
}
|
||||
FILTER .id = <uuid>$0;
|
||||
`, &message, messageID)
|
||||
if err != nil {
|
||||
fmt.Println("Error in edgedb.QuerySingle: in GenerateMultipleMessages")
|
||||
log.Fatal(err)
|
||||
}
|
||||
modelID, _ := message.ModelID.Get()
|
||||
|
||||
var area Area
|
||||
err = edgeClient.QuerySingle(edgeCtx, `
|
||||
SELECT Area {
|
||||
position
|
||||
}
|
||||
FILTER .id = <uuid>$0;
|
||||
`, &area, message.Area.ID)
|
||||
if err != nil {
|
||||
fmt.Println("Error in edgedb.QuerySingle: in GenerateMultipleMessages")
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(area)
|
||||
|
||||
// Check if the context's deadline is exceeded
|
||||
select {
|
||||
case <-ctx.Done(): // Context's deadline is exceeded
|
||||
// Insert a bot message indicating a timeout
|
||||
insertBotMessage(lastSelectedModelIds[idx]+" too long to answer", idx == 0, lastSelectedModelIds[idx])
|
||||
case <-done: // addMessageFunc completed within the deadline
|
||||
// No action needed, the function completed successfully
|
||||
case <-ctx.Done():
|
||||
// The context's deadline was exceeded
|
||||
fmt.Printf("Goroutine %d timed out\n", idx)
|
||||
default:
|
||||
// Send the index of the completed goroutine to the firstDone channel
|
||||
select {
|
||||
case firstDone <- idx:
|
||||
// Generate the HTML content
|
||||
out := "<div class='message-header'>"
|
||||
out += "<p>"
|
||||
out += model2Name(modelID)
|
||||
out += " </p>"
|
||||
out += "</div>"
|
||||
out += "<div class='message-body'>"
|
||||
out += " <ct class='content'>"
|
||||
out += markdownToHTML(message.Content)
|
||||
out += " </ct>"
|
||||
out += "</div>"
|
||||
|
||||
fmt.Println("Sending event from first")
|
||||
fmt.Println("swapContent-" + fmt.Sprintf("%d", area.Position))
|
||||
|
||||
// Send Content event
|
||||
sseChanel.SendEvent(
|
||||
"swapContent-"+fmt.Sprintf("%d", area.Position),
|
||||
out,
|
||||
)
|
||||
|
||||
out, err := modelSelecBtnTmpl.Execute(map[string]interface{}{
|
||||
"message": message,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("Error in modelSelecBtnTmpl.Execute: in GenerateMultipleMessages")
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Send Content event
|
||||
sseChanel.SendEvent(
|
||||
"swapSelectionBtn-"+modelID,
|
||||
out,
|
||||
)
|
||||
|
||||
// Send Icon Swap event
|
||||
sseChanel.SendEvent(
|
||||
"swapIcon-"+fmt.Sprintf("%d", area.Position),
|
||||
`<img src="icons/`+model2Icon(modelID)+`.png" alt="User Image">`,
|
||||
)
|
||||
default:
|
||||
out, err := modelSelecBtnTmpl.Execute(map[string]interface{}{
|
||||
"message": message,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("Error in modelSelecBtnTmpl.Execute: in GenerateMultipleMessages")
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(("Sending event"))
|
||||
|
||||
// Send Content event
|
||||
sseChanel.SendEvent(
|
||||
"swapSelectionBtn-"+modelID,
|
||||
out,
|
||||
)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for all goroutines to finish
|
||||
wg.Wait()
|
||||
|
||||
fmt.Println("Done!")
|
||||
|
||||
return c.SendString(generateChatHTML())
|
||||
}
|
||||
|
||||
func RequestMultipleMessagesHandler(c *fiber.Ctx) error {
|
||||
message := c.FormValue("message", "")
|
||||
|
||||
selectedModelIds := []string{}
|
||||
for ModelInfo := range ModelsInfos {
|
||||
out := c.FormValue("model-check-" + ModelsInfos[ModelInfo].ID)
|
||||
if out != "" {
|
||||
selectedModelIds = append(selectedModelIds, ModelsInfos[ModelInfo].ID)
|
||||
}
|
||||
}
|
||||
lastSelectedModelIds = selectedModelIds
|
||||
|
||||
out := RequestMultipleMessages(message, selectedModelIds)
|
||||
|
||||
return c.SendString(out)
|
||||
}
|
||||
|
||||
func RequestMultipleMessages(message string, selectedModelIds []string) string {
|
||||
// Add an Area with the user message inside
|
||||
insertArea()
|
||||
messageID := insertUserMessage(message)
|
||||
|
||||
out := ""
|
||||
messageOut, _ := userTmpl.Execute(pongo2.Context{"Content": markdownToHTML(message), "ID": messageID.String()})
|
||||
out += messageOut
|
||||
|
||||
messageOut, _ = botTmpl.Execute(pongo2.Context{"IsPlaceholder": true})
|
||||
out += messageOut
|
||||
|
||||
return out
|
||||
}
|
||||
|
@ -11,15 +11,10 @@ import (
|
||||
)
|
||||
|
||||
type AnthropicChatCompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []AnthropicMessage `json:"messages"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type AnthropicMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
Model string `json:"model"`
|
||||
Messages []Message `json:"messages"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type AnthropicChatCompletionResponse struct {
|
||||
@ -104,30 +99,10 @@ func addAnthropicMessage(modelID string, selected bool) edgedb.UUID {
|
||||
return edgedb.UUID{}
|
||||
}
|
||||
|
||||
func EdgeMessages2AnthropicMessages(messages []Message) []AnthropicMessage {
|
||||
AnthropicMessages := make([]AnthropicMessage, len(messages))
|
||||
for i, msg := range messages {
|
||||
var role string
|
||||
switch msg.Role {
|
||||
case "user":
|
||||
role = "user"
|
||||
case "bot":
|
||||
role = "assistant"
|
||||
default:
|
||||
role = "system"
|
||||
}
|
||||
AnthropicMessages[i] = AnthropicMessage{
|
||||
Role: role,
|
||||
Content: msg.Content,
|
||||
}
|
||||
}
|
||||
return AnthropicMessages
|
||||
}
|
||||
|
||||
func TestAnthropicKey(apiKey string) bool {
|
||||
url := "https://api.anthropic.com/v1/messages"
|
||||
|
||||
AnthropicMessages := []AnthropicMessage{
|
||||
AnthropicMessages := []Message{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Hello",
|
||||
@ -195,11 +170,9 @@ func RequestAnthropic(model string, messages []Message, maxTokens int, temperatu
|
||||
|
||||
url := "https://api.anthropic.com/v1/messages"
|
||||
|
||||
AnthropicMessages := EdgeMessages2AnthropicMessages(messages)
|
||||
|
||||
requestBody := AnthropicChatCompletionRequest{
|
||||
Model: model,
|
||||
Messages: AnthropicMessages,
|
||||
Messages: ChangeRoleBot2Assistant(messages),
|
||||
MaxTokens: maxTokens,
|
||||
Temperature: temperature,
|
||||
}
|
||||
|
@ -11,14 +11,9 @@ import (
|
||||
)
|
||||
|
||||
type GroqChatCompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []GroqMessage `json:"messages"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type GroqMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
Model string `json:"model"`
|
||||
Messages []Message `json:"messages"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type GroqChatCompletionResponse struct {
|
||||
@ -37,9 +32,9 @@ type GroqUsage struct {
|
||||
}
|
||||
|
||||
type GroqChoice struct {
|
||||
Message GroqMessage `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Index int `json:"index"`
|
||||
Message Message `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -106,31 +101,11 @@ func addGroqMessage(modelID string, selected bool) edgedb.UUID {
|
||||
return edgedb.UUID{}
|
||||
}
|
||||
|
||||
func EdgeMessages2GroqMessages(messages []Message) []GroqMessage {
|
||||
groqMessages := make([]GroqMessage, len(messages))
|
||||
for i, msg := range messages {
|
||||
var role string
|
||||
switch msg.Role {
|
||||
case "user":
|
||||
role = "user"
|
||||
case "bot":
|
||||
role = "assistant"
|
||||
default:
|
||||
role = "system"
|
||||
}
|
||||
groqMessages[i] = GroqMessage{
|
||||
Role: role,
|
||||
Content: msg.Content,
|
||||
}
|
||||
}
|
||||
return groqMessages
|
||||
}
|
||||
|
||||
func TestGroqKey(apiKey string) bool {
|
||||
url := "https://api.groq.com/openai/v1/chat/completions"
|
||||
|
||||
// Convert messages to Qroq format
|
||||
groqMessages := []GroqMessage{
|
||||
groqMessages := []Message{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Hello",
|
||||
@ -199,12 +174,9 @@ func RequestGroq(model string, messages []Message, temperature float64) (GroqCha
|
||||
|
||||
url := "https://api.groq.com/openai/v1/chat/completions"
|
||||
|
||||
// Convert messages to Qroq format
|
||||
groqMessages := EdgeMessages2GroqMessages(messages)
|
||||
|
||||
requestBody := GroqChatCompletionRequest{
|
||||
Model: model,
|
||||
Messages: groqMessages,
|
||||
Messages: ChangeRoleBot2Assistant(messages),
|
||||
Temperature: temperature,
|
||||
}
|
||||
|
||||
|
@ -11,16 +11,10 @@ import (
|
||||
)
|
||||
|
||||
type MistralChatCompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []MistralMessage `json:"messages"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
Model string `json:"model"`
|
||||
Messages []Message `json:"messages"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type MistralMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type MistralChatCompletionResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
@ -37,9 +31,9 @@ type MistralUsage struct {
|
||||
}
|
||||
|
||||
type MistralChoice struct {
|
||||
Message MistralMessage `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Index int `json:"index"`
|
||||
Message Message `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -139,31 +133,11 @@ func addMistralMessage(modelID string, selected bool) edgedb.UUID {
|
||||
return edgedb.UUID{}
|
||||
}
|
||||
|
||||
func EdgeMessages2MistralMessages(messages []Message) []MistralMessage {
|
||||
mistralMessages := make([]MistralMessage, len(messages))
|
||||
for i, msg := range messages {
|
||||
var role string
|
||||
switch msg.Role {
|
||||
case "user":
|
||||
role = "user"
|
||||
case "bot":
|
||||
role = "assistant"
|
||||
default:
|
||||
role = "system"
|
||||
}
|
||||
mistralMessages[i] = MistralMessage{
|
||||
Role: role,
|
||||
Content: msg.Content,
|
||||
}
|
||||
}
|
||||
return mistralMessages
|
||||
}
|
||||
|
||||
func TestMistralKey(apiKey string) bool {
|
||||
url := "https://api.mistral.ai/v1/chat/completions"
|
||||
|
||||
// Convert messages to Mistral format
|
||||
mistralMessages := []MistralMessage{
|
||||
mistralMessages := []Message{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Hello",
|
||||
@ -237,12 +211,9 @@ func RequestMistral(model string, messages []Message, temperature float64) (Mist
|
||||
|
||||
url := "https://api.mistral.ai/v1/chat/completions"
|
||||
|
||||
// Convert messages to OpenAI format
|
||||
mistralMessages := EdgeMessages2MistralMessages(messages)
|
||||
|
||||
requestBody := MistralChatCompletionRequest{
|
||||
Model: model,
|
||||
Messages: mistralMessages,
|
||||
Messages: ChangeRoleBot2Assistant(messages),
|
||||
Temperature: temperature,
|
||||
}
|
||||
|
||||
|
@ -11,14 +11,9 @@ import (
|
||||
)
|
||||
|
||||
type OpenaiChatCompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []OpenaiMessage `json:"messages"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type OpenaiMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
Model string `json:"model"`
|
||||
Messages []Message `json:"messages"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
}
|
||||
|
||||
type OpenaiChatCompletionResponse struct {
|
||||
@ -37,9 +32,9 @@ type OpenaiUsage struct {
|
||||
}
|
||||
|
||||
type OpenaiChoice struct {
|
||||
Message OpenaiMessage `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Index int `json:"index"`
|
||||
Message Message `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -117,31 +112,11 @@ func addOpenaiMessage(modelID string, selected bool) edgedb.UUID {
|
||||
return edgedb.UUID{}
|
||||
}
|
||||
|
||||
func EdgeMessages2OpenaiMessages(messages []Message) []OpenaiMessage {
|
||||
openaiMessages := make([]OpenaiMessage, len(messages))
|
||||
for i, msg := range messages {
|
||||
var role string
|
||||
switch msg.Role {
|
||||
case "user":
|
||||
role = "user"
|
||||
case "bot":
|
||||
role = "assistant"
|
||||
default:
|
||||
role = "system"
|
||||
}
|
||||
openaiMessages[i] = OpenaiMessage{
|
||||
Role: role,
|
||||
Content: msg.Content,
|
||||
}
|
||||
}
|
||||
return openaiMessages
|
||||
}
|
||||
|
||||
func TestOpenaiKey(apiKey string) bool {
|
||||
url := "https://api.openai.com/v1/chat/completions"
|
||||
|
||||
// Convert messages to OpenAI format
|
||||
openaiMessages := []OpenaiMessage{
|
||||
openaiMessages := []Message{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Hello",
|
||||
@ -208,12 +183,9 @@ func RequestOpenai(model string, messages []Message, temperature float64) (Opena
|
||||
|
||||
url := "https://api.openai.com/v1/chat/completions"
|
||||
|
||||
// Convert messages to OpenAI format
|
||||
openaiMessages := EdgeMessages2OpenaiMessages(messages)
|
||||
|
||||
requestBody := OpenaiChatCompletionRequest{
|
||||
Model: model,
|
||||
Messages: openaiMessages,
|
||||
Messages: ChangeRoleBot2Assistant(messages),
|
||||
Temperature: temperature,
|
||||
}
|
||||
|
||||
|
38
database.go
38
database.go
@ -40,7 +40,7 @@ type Conversation struct {
|
||||
|
||||
type Area struct {
|
||||
ID edgedb.UUID `edgedb:"id"`
|
||||
Position int `edgedb:"position"`
|
||||
Position int64 `edgedb:"position"`
|
||||
Conv Conversation `edgedb:"conversation"`
|
||||
}
|
||||
|
||||
@ -111,6 +111,24 @@ func checkIfLogin() bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func addUsage(inputCost float32, outputCost float32, inputToken int32, outputToken int32, modelID string) {
|
||||
// Create a new usage
|
||||
err := edgeClient.Execute(edgeCtx, `
|
||||
INSERT Usage {
|
||||
input_cost := <float32>$0,
|
||||
output_cost := <float32>$1,
|
||||
input_token := <int32>$2,
|
||||
output_token := <int32>$3,
|
||||
model_id := <str>$4,
|
||||
user := global currentUser
|
||||
}
|
||||
`, inputCost, outputCost, inputToken, outputToken, modelID)
|
||||
if err != nil {
|
||||
fmt.Println("Error in edgedb.QuerySingle: in addUsage")
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func insertNewConversation() edgedb.UUID {
|
||||
var inserted struct{ id edgedb.UUID }
|
||||
err := edgeClient.QuerySingle(edgeCtx, `
|
||||
@ -126,7 +144,7 @@ func insertNewConversation() edgedb.UUID {
|
||||
return inserted.id
|
||||
}
|
||||
|
||||
func insertArea() edgedb.UUID {
|
||||
func insertArea() (edgedb.UUID, int64) {
|
||||
// If the Default conversation doesn't exist, create it.
|
||||
var convExists bool
|
||||
edgeClient.QuerySingle(edgeCtx, `
|
||||
@ -157,7 +175,21 @@ func insertArea() edgedb.UUID {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return inserted.id
|
||||
var positionSet struct{ position int64 }
|
||||
err = edgeClient.QuerySingle(edgeCtx, `
|
||||
SELECT Area {
|
||||
position
|
||||
}
|
||||
FILTER .conversation.name = 'Default' AND .conversation.user = global currentUser
|
||||
ORDER BY .position
|
||||
LIMIT 1
|
||||
`, &positionSet)
|
||||
if err != nil {
|
||||
fmt.Println("Error in edgedb.QuerySingle: in insertArea")
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return inserted.id, positionSet.position
|
||||
}
|
||||
|
||||
func insertUserMessage(content string) edgedb.UUID {
|
||||
|
9
main.go
9
main.go
@ -12,11 +12,13 @@ import (
|
||||
|
||||
var userTmpl *pongo2.Template
|
||||
var botTmpl *pongo2.Template
|
||||
var modelSelecBtnTmpl *pongo2.Template
|
||||
var sseChanel *ssefiber.FiberSSEChannel
|
||||
|
||||
func main() {
|
||||
botTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-bot.html"))
|
||||
userTmpl = pongo2.Must(pongo2.FromFile("views/partials/message-user.html"))
|
||||
modelSelecBtnTmpl = pongo2.Must(pongo2.FromFile("views/partials/model-selection-btn.html"))
|
||||
|
||||
// Import HTML using django engine/template
|
||||
engine := django.New("./views", ".html")
|
||||
@ -28,7 +30,7 @@ func main() {
|
||||
EnablePrintRoutes: true,
|
||||
})
|
||||
sse := ssefiber.New(app, "/sse")
|
||||
sseChanel = sse.CreateChannel("sse", "/sse")
|
||||
sseChanel = sse.CreateChannel("sse", "")
|
||||
|
||||
// Add default logger
|
||||
app.Use(logger.New())
|
||||
@ -41,7 +43,6 @@ func main() {
|
||||
app.Get("/loadChat", LoadChatHandler)
|
||||
|
||||
// Chat routes
|
||||
app.Post("/requestMultipleMessages", RequestMultipleMessagesHandler)
|
||||
app.Post("/deleteMessage", DeleteMessageHandler)
|
||||
app.Get("/generateMultipleMessages", GenerateMultipleMessages)
|
||||
app.Get("/messageContent", GetMessageContentHandler)
|
||||
@ -66,6 +67,10 @@ func main() {
|
||||
|
||||
app.Get("/test", func(c *fiber.Ctx) error {
|
||||
fmt.Println("Hello from test")
|
||||
go sseChanel.SendEvent(
|
||||
"swapIcon-1",
|
||||
`<img src="icons/groq.png" alt="User Image">`,
|
||||
)
|
||||
return c.SendString("")
|
||||
})
|
||||
|
||||
|
BIN
static/My logo - background (1).png
Normal file
BIN
static/My logo - background (1).png
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 KiB |
@ -47,10 +47,6 @@ html {
|
||||
--bulma-primary: #126d0f;
|
||||
}
|
||||
|
||||
.button.is-primary {
|
||||
background-color: #1ebc19;
|
||||
}
|
||||
|
||||
/* Chat input stuff */
|
||||
.chat-input-container {
|
||||
display: flex;
|
||||
|
20
utils.go
20
utils.go
@ -124,3 +124,23 @@ func removeDuplicate(s []string) []string {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ChangeRoleBot2Assistant(messages []Message) []Message {
|
||||
openaiMessages := make([]Message, len(messages))
|
||||
for i, msg := range messages {
|
||||
var role string
|
||||
switch msg.Role {
|
||||
case "user":
|
||||
role = "user"
|
||||
case "bot":
|
||||
role = "assistant"
|
||||
default:
|
||||
role = "system"
|
||||
}
|
||||
openaiMessages[i] = Message{
|
||||
Role: role,
|
||||
Content: msg.Content,
|
||||
}
|
||||
}
|
||||
return openaiMessages
|
||||
}
|
||||
|
@ -18,8 +18,13 @@
|
||||
<i class="fa-solid fa-broom"></i>
|
||||
</span>
|
||||
</button>
|
||||
<button type="submit" class="button is-small" hx-get="/test" hx-swap="beforeend">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-vials"></i>
|
||||
</span>
|
||||
</button>
|
||||
<button disabled type="submit" class="send-button button is-primary is-small"
|
||||
hx-post="/requestMultipleMessages" hx-swap="beforeend settle:200ms" hx-target="#chat-messages"
|
||||
hx-get="/generateMultipleMessages" hx-swap="beforeend settle:200ms" hx-target="#chat-messages"
|
||||
id="chat-input-send-btn" class="chat-input" hx-include="[name='message'], [name^='model-check-']"
|
||||
onclick="clearTextArea()">
|
||||
<span class="icon">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html data-theme="dark" lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
@ -11,11 +11,12 @@
|
||||
|
||||
<link rel="stylesheet" href="/animations.css">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
|
||||
<script src="https://unpkg.com/htmx.org@1.9.12/dist/ext/sse.js"></script>
|
||||
</head>
|
||||
|
||||
<body hx-ext="sse" sse-connect="/sse">
|
||||
|
||||
{{embed}}
|
||||
|
||||
|
@ -1,24 +1,33 @@
|
||||
<div class="message-bot mt-3">
|
||||
<div class="columns is-mobile">
|
||||
<div class="column is-narrow" id="icon-column">
|
||||
<!-- Left column with the icon -->
|
||||
{% if IsPlaceholder %}
|
||||
|
||||
<figure class="image is-48x48" style="flex-shrink: 0;" id="selectedIcon-{{ ConversationAreaId }}"
|
||||
sse-swap="swapIcon-{{ ConversationAreaId }}">
|
||||
<img src="icons/bouvai2.png" alt="User Image">
|
||||
</figure>
|
||||
|
||||
{% else %}
|
||||
|
||||
{% for message in Messages %}
|
||||
{% if not message.Hidden %}
|
||||
<figure class="image is-48x48" style="flex-shrink: 0;">
|
||||
<img id="selectedIcon-{{ ConversationAreaId }}" src="icons/{{ message.Icon }}.png" alt="User Image">
|
||||
<figure class="image is-48x48" style="flex-shrink: 0;" id="selectedIcon-{{ ConversationAreaId }}"
|
||||
sse-swap="swapIcon-{{ ConversationAreaId }}">
|
||||
<img src="icons/{{ message.Icon }}.png" alt="User Image">
|
||||
</figure>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if IsPlaceholder %}
|
||||
<figure class="image is-48x48" style="flex-shrink: 0;">
|
||||
<img src="icons/bouvai2.png" alt="User Image">
|
||||
</figure>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="column" id="content-column">
|
||||
{% if not IsPlaceholder %}
|
||||
<div class="is-flex is-align-items-start">
|
||||
<div class="message-content" id="content-{{ ConversationAreaId }}">
|
||||
<div class="message-content" id="content-{{ ConversationAreaId }}"
|
||||
sse-swap="swapContent-{{ ConversationAreaId }}">
|
||||
{% for message in Messages %}
|
||||
{% if not message.Hidden %}
|
||||
<div class="message-header">
|
||||
@ -55,21 +64,34 @@
|
||||
</button>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% elif IsPlaceholder %}
|
||||
<hx hx-get="/generateMultipleMessages" hx-trigger="load" hx-swap="outerHTML" hx-indicator="#spinner"
|
||||
hx-target="#chat-container">
|
||||
</hx>
|
||||
|
||||
<div class="message-content" {% if message.Hidden %}style="display: none;" {% endif %}>
|
||||
{% elif IsPlaceholder %}
|
||||
<div class="is-flex is-align-items-start">
|
||||
<div class="message-content" id="content-{{ ConversationAreaId }}"
|
||||
sse-swap="swapContent-{{ ConversationAreaId }}">
|
||||
<div class="message-body">
|
||||
<div class="content">
|
||||
<img id="spinner" class="htmx-indicator" src="/puff.svg" />
|
||||
<img src="/puff.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="is-flex is-justify-content mt-2">
|
||||
{% for selectedModel in selectedModels %}
|
||||
<button disable class="button is-small is-primary message-button is-outlined mr-1"
|
||||
sse-swap="swapSelectionBtn-{{ selectedModel.ID }}" hx-swap="outerHTML">
|
||||
<span class="icon is-small">
|
||||
<!--img src="icons/{{ selectedModel.Icon }}.png" alt="{{ selectedModel.Name }}"
|
||||
style="max-height: 100%; max-width: 100%;"-->
|
||||
<img src="/puff.svg" />
|
||||
</span>
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
7
views/partials/model-selection-btn.html
Normal file
7
views/partials/model-selection-btn.html
Normal file
@ -0,0 +1,7 @@
|
||||
<button class="button is-small is-primary message-button is-outlined mr-1" hx-get="/messageContent?id={{ message.Id }}"
|
||||
hx-target="#content-{{ ConversationAreaId }}" onclick="updateIcon('{{ message.Icon }}', '{{ ConversationAreaId }}')"
|
||||
title="{{ message.Name }}">
|
||||
<span class="icon is-small">
|
||||
<img src="icons/{{ message.Icon }}.png" alt="{{ message.Name }}" style="max-height: 100%; max-width: 100%;">
|
||||
</span>
|
||||
</button>
|
Loading…
x
Reference in New Issue
Block a user