Working login logup and logout + placeholder welcome message
This commit is contained in:
parent
56f09d6d49
commit
ed64fc01d8
44
Chat.go
44
Chat.go
@ -12,7 +12,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ChatPageHandler(c *fiber.Ctx) error {
|
func ChatPageHandler(c *fiber.Ctx) error {
|
||||||
return c.Render("chat", fiber.Map{}, "layouts/main")
|
authCookie := c.Cookies("jade-edgedb-auth-token", "")
|
||||||
|
|
||||||
|
if authCookie != "" && !checkIfLogin() {
|
||||||
|
edgeClient = edgeClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": authCookie})
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Current User: ", getCurrentUser())
|
||||||
|
|
||||||
|
return c.Render("chat", fiber.Map{"IsLogin": checkIfLogin()}, "layouts/main")
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadModelSelectionHandler(c *fiber.Ctx) error {
|
func LoadModelSelectionHandler(c *fiber.Ctx) error {
|
||||||
@ -45,8 +53,6 @@ func LoadUsageKPIHandler(c *fiber.Ctx) error {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(TotalUsage)
|
|
||||||
|
|
||||||
out, err := pongo2.Must(pongo2.FromFile("views/partials/usagePopover.html")).Execute(pongo2.Context{
|
out, err := pongo2.Must(pongo2.FromFile("views/partials/usagePopover.html")).Execute(pongo2.Context{
|
||||||
"TotalUsage": TotalUsage,
|
"TotalUsage": TotalUsage,
|
||||||
})
|
})
|
||||||
@ -85,7 +91,11 @@ func DeleteMessageHandler(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LoadChatHandler(c *fiber.Ctx) error {
|
func LoadChatHandler(c *fiber.Ctx) error {
|
||||||
return c.SendString(generateChatHTML())
|
if checkIfLogin() {
|
||||||
|
return c.SendString(generateChatHTML())
|
||||||
|
} else {
|
||||||
|
return c.SendString(generateWelcomeChatHTML())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type NextMessage struct {
|
type NextMessage struct {
|
||||||
@ -115,7 +125,6 @@ func generateChatHTML() string {
|
|||||||
// Reset NextMessages when a user message is encountered
|
// Reset NextMessages when a user message is encountered
|
||||||
NextMessages = []NextMessage{}
|
NextMessages = []NextMessage{}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(i)
|
|
||||||
modelID, exist := message.ModelID.Get()
|
modelID, exist := message.ModelID.Get()
|
||||||
if !exist {
|
if !exist {
|
||||||
modelID = "gpt-3.5-turbo"
|
modelID = "gpt-3.5-turbo"
|
||||||
@ -199,3 +208,28 @@ func GetMessageContentHandler(c *fiber.Ctx) error {
|
|||||||
|
|
||||||
return c.SendString(out)
|
return c.SendString(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateWelcomeChatHTML() string {
|
||||||
|
htmlString := "<div class='columns is-centered' id='chat-container'><div class='column is-12-mobile is-8-tablet is-6-desktop' id='chat-messages'>"
|
||||||
|
|
||||||
|
NextMessages := []NextMessage{}
|
||||||
|
nextMsg := NextMessage{
|
||||||
|
Icon: "bouvai2", // Assuming Icon is a field you want to include from Message
|
||||||
|
Content: markdownToHTML("Hi, I'm Bouvai. How can I help you today?"),
|
||||||
|
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})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
htmlString += botOut
|
||||||
|
htmlString += "<div style='height: 10px;'></div>"
|
||||||
|
htmlString += "</div></div>"
|
||||||
|
|
||||||
|
// Render the HTML template with the messages
|
||||||
|
return htmlString
|
||||||
|
}
|
||||||
|
23
database.go
23
database.go
@ -73,15 +73,8 @@ func init() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Change
|
|
||||||
edgeCtx = ctx
|
edgeCtx = ctx
|
||||||
var clientUUID edgedb.UUID
|
edgeClient = client
|
||||||
clientUUID, err = edgedb.ParseUUID("9323365e-0b09-11ef-8f41-c3575d386283")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error in edgedb.ParseUUID: in init")
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
edgeClient = client.WithGlobals(map[string]interface{}{"current_user_id": clientUUID})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLastArea() edgedb.UUID {
|
func getLastArea() edgedb.UUID {
|
||||||
@ -99,15 +92,21 @@ func getLastArea() edgedb.UUID {
|
|||||||
return inserted.id
|
return inserted.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkIfLogin() bool {
|
func getCurrentUser() User {
|
||||||
var result User
|
var result User
|
||||||
err := edgeClient.QuerySingle(edgeCtx, "SELECT global currentUser LIMIT 1;", &result)
|
err := edgeClient.QuerySingle(edgeCtx, "SELECT global currentUser LIMIT 1;", &result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error in edgedb.QuerySingle: in checkIfLogin")
|
fmt.Println("Error in edgedb.QuerySingle: in getCurrentUser")
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return false
|
return User{}
|
||||||
}
|
}
|
||||||
return true
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkIfLogin() bool {
|
||||||
|
var result User
|
||||||
|
err := edgeClient.QuerySingle(edgeCtx, "SELECT global currentUser LIMIT 1;", &result)
|
||||||
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertArea() edgedb.UUID {
|
func insertArea() edgedb.UUID {
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using extension auth;
|
using extension auth;
|
||||||
|
|
||||||
module default {
|
module default {
|
||||||
global current_user_id: uuid;
|
|
||||||
global currentUser := (
|
global currentUser := (
|
||||||
|
assert_single((
|
||||||
select User
|
select User
|
||||||
filter .id = global current_user_id
|
filter .identity = global ext::auth::ClientTokenIdentity
|
||||||
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
type User {
|
type User {
|
||||||
@ -58,13 +59,13 @@ module default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Usage {
|
type Usage {
|
||||||
required model_id: str;
|
required model_id: str;
|
||||||
required user: User;
|
user: User;
|
||||||
input_cost: float32;
|
input_cost: float32;
|
||||||
output_cost: float32;
|
output_cost: float32;
|
||||||
input_token: int32;
|
input_token: int32;
|
||||||
output_token: int32;
|
output_token: int32;
|
||||||
required date: datetime {
|
required date: datetime {
|
||||||
default := datetime_current();
|
default := datetime_current();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
dbschema/migrations/00017-m1g3r5w.edgeql
Normal file
11
dbschema/migrations/00017-m1g3r5w.edgeql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
CREATE MIGRATION m1g3r5wwsplyqphor3yvb7dzp2txacgd6ed3udrpvakuoz3e2zj7ka
|
||||||
|
ONTO m1t2tddtq2grfxf4ldn6aj4yotvwiqclsrks6chobvs33d5mcd62mq
|
||||||
|
{
|
||||||
|
DROP GLOBAL default::currentUser;
|
||||||
|
CREATE GLOBAL default::current_user := (std::assert_single((SELECT
|
||||||
|
default::User
|
||||||
|
FILTER
|
||||||
|
(.identity = GLOBAL ext::auth::ClientTokenIdentity)
|
||||||
|
)));
|
||||||
|
DROP GLOBAL default::current_user_id;
|
||||||
|
};
|
5
dbschema/migrations/00018-m1c2b3o.edgeql
Normal file
5
dbschema/migrations/00018-m1c2b3o.edgeql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
CREATE MIGRATION m1c2b3o4bhfgldk3kebneqyv6oxfgmorrp62uv5rreu773ryed3azq
|
||||||
|
ONTO m1g3r5wwsplyqphor3yvb7dzp2txacgd6ed3udrpvakuoz3e2zj7ka
|
||||||
|
{
|
||||||
|
ALTER GLOBAL default::current_user RENAME TO default::currentUser;
|
||||||
|
};
|
9
dbschema/migrations/00019-m1rzoj5.edgeql
Normal file
9
dbschema/migrations/00019-m1rzoj5.edgeql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
CREATE MIGRATION m1rzoj5rvhxkec6tsew6dc6bd3ksrrmf7t3k532avozbg4722xulhq
|
||||||
|
ONTO m1c2b3o4bhfgldk3kebneqyv6oxfgmorrp62uv5rreu773ryed3azq
|
||||||
|
{
|
||||||
|
ALTER TYPE default::Usage {
|
||||||
|
ALTER LINK user {
|
||||||
|
RESET OPTIONALITY;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
127
login.go
127
login.go
@ -8,62 +8,106 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/edgedb/edgedb-go"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const EDGEDB_AUTH_BASE_URL = "http://127.0.0.1:10700/db/main/ext/auth"
|
const EDGEDB_AUTH_BASE_URL = "http://127.0.0.1:10700/db/main/ext/auth"
|
||||||
|
|
||||||
func generatePKCE() (string, string) {
|
func generatePKCE() (string, string) {
|
||||||
fmt.Println("Generating PKCE")
|
verifier_source := make([]byte, 32)
|
||||||
verifier := make([]byte, 32)
|
_, err := rand.Read(verifier_source)
|
||||||
_, err := rand.Read(verifier)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
challenge := sha256.Sum256(verifier)
|
verifier := base64.RawURLEncoding.EncodeToString(verifier_source)
|
||||||
|
challenge := sha256.Sum256([]byte(verifier))
|
||||||
var URLEncoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")
|
return verifier, base64.RawURLEncoding.EncodeToString(challenge[:])
|
||||||
var RawURLEncoding = URLEncoding.WithPadding(base64.NoPadding)
|
|
||||||
encodedVerifier := RawURLEncoding.EncodeToString(verifier)
|
|
||||||
encodedChallenge := RawURLEncoding.EncodeToString(challenge[:])
|
|
||||||
|
|
||||||
fmt.Println("verifier: " + encodedVerifier)
|
|
||||||
fmt.Println("challenge: " + encodedChallenge)
|
|
||||||
|
|
||||||
return encodedVerifier, encodedChallenge
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUiSignIn(c *fiber.Ctx) error {
|
func handleUiSignIn(c *fiber.Ctx) error {
|
||||||
verifier, challenge := generatePKCE()
|
verifier, challenge := generatePKCE()
|
||||||
|
|
||||||
fmt.Println("handleUiSignIn verifier: " + verifier)
|
c.Cookie(&fiber.Cookie{
|
||||||
fmt.Println("handleUiSignIn challenge: " + challenge)
|
Name: "jade-edgedb-pkce-verifier",
|
||||||
|
Value: verifier,
|
||||||
cookie := new(fiber.Cookie)
|
HTTPOnly: true,
|
||||||
cookie.Name = "jade-edgedb-pkce-verifier"
|
Path: "/",
|
||||||
cookie.Value = verifier
|
Secure: true,
|
||||||
cookie.Expires = time.Now().Add(10 * time.Minute)
|
SameSite: "Strict",
|
||||||
c.Cookie(cookie)
|
})
|
||||||
|
|
||||||
return c.Redirect(fmt.Sprintf("%s/ui/signup?challenge=%s", EDGEDB_AUTH_BASE_URL, challenge), fiber.StatusTemporaryRedirect)
|
return c.Redirect(fmt.Sprintf("%s/ui/signup?challenge=%s", EDGEDB_AUTH_BASE_URL, challenge), fiber.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUiSignUp(c *fiber.Ctx) error {
|
func handleCallbackSignup(c *fiber.Ctx) error {
|
||||||
verifier, challenge := generatePKCE()
|
code := c.Query("code")
|
||||||
|
if code == "" {
|
||||||
|
error := c.Query("error")
|
||||||
|
return c.Status(fiber.StatusBadRequest).SendString(fmt.Sprintf("OAuth callback is missing 'code'. OAuth provider responded with error: %s", error))
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("handleUiSignUp verifier: " + verifier)
|
verifier := c.Cookies("jade-edgedb-pkce-verifier")
|
||||||
fmt.Println("handleUiSignUp challenge: " + challenge)
|
if verifier == "" {
|
||||||
|
return c.Status(fiber.StatusBadRequest).SendString("Could not find 'verifier' in the cookie store. Is this the same user agent/browser that started the authorization flow?")
|
||||||
|
}
|
||||||
|
|
||||||
cookie := new(fiber.Cookie)
|
codeExchangeURL := fmt.Sprintf("%s/token?code=%s&verifier=%s", EDGEDB_AUTH_BASE_URL, code, verifier)
|
||||||
cookie.Name = "jade-edgedb-pkce-verifier"
|
resp, err := http.Get(codeExchangeURL)
|
||||||
cookie.Value = verifier
|
if err != nil {
|
||||||
cookie.Expires = time.Now().Add(10 * time.Minute)
|
return c.Status(fiber.StatusBadRequest).SendString(fmt.Sprintf("Error from the auth server: %s", err.Error()))
|
||||||
c.Cookie(cookie)
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
return c.Redirect(fmt.Sprintf("%s/ui/signup?challenge=%s", EDGEDB_AUTH_BASE_URL, challenge), fiber.StatusTemporaryRedirect)
|
if resp.StatusCode != fiber.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return c.Status(fiber.StatusBadRequest).SendString(fmt.Sprintf("Error from the auth server: %s", string(body)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenResponse struct {
|
||||||
|
AuthToken string `json:"auth_token"`
|
||||||
|
IdentityID string `json:"identity_id"`
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&tokenResponse)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).SendString(fmt.Sprintf("Error decoding auth server response: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Cookie(&fiber.Cookie{
|
||||||
|
Name: "jade-edgedb-auth-token",
|
||||||
|
Value: tokenResponse.AuthToken,
|
||||||
|
HTTPOnly: true,
|
||||||
|
Path: "/",
|
||||||
|
Secure: true,
|
||||||
|
SameSite: "Strict",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a new User and attach the identity
|
||||||
|
var identityUUID edgedb.UUID
|
||||||
|
identityUUID, err = edgedb.ParseUUID(tokenResponse.IdentityID)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("Error in edgedb.ParseUUID: in handleCallbackSignup: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = edgeClient.Execute(edgeCtx, `
|
||||||
|
INSERT User {
|
||||||
|
setting := (
|
||||||
|
INSERT Setting {
|
||||||
|
default_model := "gpt-3.5-turbo"
|
||||||
|
}
|
||||||
|
),
|
||||||
|
identity := (SELECT ext::auth::Identity FILTER .id = <uuid>$0)
|
||||||
|
}
|
||||||
|
`, identityUUID)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("Error in edgedb.QuerySingle: in handleCallbackSignup: %s", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
edgeClient = edgeClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": tokenResponse.AuthToken})
|
||||||
|
|
||||||
|
return c.Redirect("/", fiber.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCallback(c *fiber.Ctx) error {
|
func handleCallback(c *fiber.Ctx) error {
|
||||||
@ -78,11 +122,7 @@ func handleCallback(c *fiber.Ctx) error {
|
|||||||
return c.Status(fiber.StatusBadRequest).SendString("Could not find 'verifier' in the cookie store. Is this the same user agent/browser that started the authorization flow?")
|
return c.Status(fiber.StatusBadRequest).SendString("Could not find 'verifier' in the cookie store. Is this the same user agent/browser that started the authorization flow?")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("handleCallback code: " + code)
|
|
||||||
fmt.Println("handleCallback verifier: " + verifier)
|
|
||||||
|
|
||||||
codeExchangeURL := fmt.Sprintf("%s/token?code=%s&verifier=%s", EDGEDB_AUTH_BASE_URL, code, verifier)
|
codeExchangeURL := fmt.Sprintf("%s/token?code=%s&verifier=%s", EDGEDB_AUTH_BASE_URL, code, verifier)
|
||||||
fmt.Println("codeExchangeURL: " + codeExchangeURL)
|
|
||||||
resp, err := http.Get(codeExchangeURL)
|
resp, err := http.Get(codeExchangeURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusBadRequest).SendString(fmt.Sprintf("Error from the auth server: %s", err.Error()))
|
return c.Status(fiber.StatusBadRequest).SendString(fmt.Sprintf("Error from the auth server: %s", err.Error()))
|
||||||
@ -103,7 +143,7 @@ func handleCallback(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.Cookie(&fiber.Cookie{
|
c.Cookie(&fiber.Cookie{
|
||||||
Name: "edgedb-auth-token",
|
Name: "jade-edgedb-auth-token",
|
||||||
Value: tokenResponse.AuthToken,
|
Value: tokenResponse.AuthToken,
|
||||||
HTTPOnly: true,
|
HTTPOnly: true,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
@ -111,8 +151,13 @@ func handleCallback(c *fiber.Ctx) error {
|
|||||||
SameSite: "Strict",
|
SameSite: "Strict",
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("Login successful")
|
edgeClient = edgeClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": tokenResponse.AuthToken})
|
||||||
fmt.Println("edgedb-auth-token: " + tokenResponse.AuthToken)
|
|
||||||
|
|
||||||
return c.SendStatus(fiber.StatusNoContent)
|
return c.Redirect("/", fiber.StatusTemporaryRedirect)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSignOut(c *fiber.Ctx) error {
|
||||||
|
c.ClearCookie("jade-edgedb-auth-token")
|
||||||
|
edgeClient = edgeClient.WithGlobals(map[string]interface{}{"ext::auth::client_token": ""})
|
||||||
|
return c.Redirect("/", fiber.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
34
main.go
34
main.go
@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/flosch/pongo2"
|
"github.com/flosch/pongo2"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||||
@ -32,24 +30,26 @@ func main() {
|
|||||||
// Add static files
|
// Add static files
|
||||||
app.Static("/", "./static")
|
app.Static("/", "./static")
|
||||||
|
|
||||||
// Add routes
|
// Main routes
|
||||||
app.Get("/", ChatPageHandler) // Complete chat page
|
app.Get("/", ChatPageHandler)
|
||||||
app.Post("/requestMultipleMessages", RequestMultipleMessages) // Request multiple messages
|
app.Get("/loadChat", LoadChatHandler)
|
||||||
app.Get("/loadChat", LoadChatHandler) // Load chat
|
|
||||||
app.Post("/deleteMessage", DeleteMessageHandler) // Delete message
|
// Chat routes
|
||||||
app.Get("/loadModelSelection", LoadModelSelectionHandler) // Load model selection
|
app.Post("/requestMultipleMessages", RequestMultipleMessages)
|
||||||
app.Get("/loadUsageKPI", LoadUsageKPIHandler) // Load usage KPI
|
app.Post("/deleteMessage", DeleteMessageHandler)
|
||||||
app.Get("/generateMultipleMessages", GenerateMultipleMessages) // Generate multiple messages
|
app.Get("/generateMultipleMessages", GenerateMultipleMessages)
|
||||||
app.Get("/messageContent", GetMessageContentHandler)
|
app.Get("/messageContent", GetMessageContentHandler)
|
||||||
|
|
||||||
app.Get("/signin", handleUiSignIn)
|
// Popovers
|
||||||
app.Get("/signup", handleUiSignUp)
|
app.Get("/loadModelSelection", LoadModelSelectionHandler)
|
||||||
app.Get("/callback", handleCallback)
|
app.Get("/loadUsageKPI", LoadUsageKPIHandler)
|
||||||
|
|
||||||
|
// Authentication
|
||||||
|
app.Get("/signin", handleUiSignIn)
|
||||||
|
app.Get("/signout", handleSignOut)
|
||||||
|
app.Get("/callback", handleCallback)
|
||||||
|
app.Get("/callbackSignup", handleCallbackSignup)
|
||||||
|
|
||||||
app.Get("test", func(c *fiber.Ctx) error {
|
|
||||||
fmt.Println("test")
|
|
||||||
return c.SendString("")
|
|
||||||
})
|
|
||||||
// Start server
|
// Start server
|
||||||
app.Listen(":8080")
|
app.Listen(":8080")
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
.my-indicator {
|
body,
|
||||||
display: none;
|
html {
|
||||||
}
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
.htmx-request .my-indicator {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.htmx-request.my-indicator {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg text {
|
|
||||||
font-family: 'Russo One', sans-serif;
|
|
||||||
text-transform: uppercase;
|
|
||||||
fill: #000;
|
|
||||||
stroke: #000;
|
|
||||||
font-size: 240px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stuff for message boxes */
|
||||||
.message-content {
|
.message-content {
|
||||||
background-color: #303030;
|
background-color: #303030;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@ -28,6 +15,7 @@ svg text {
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
max-width: 662px;
|
max-width: 662px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chat-messages .message-content pre code {
|
#chat-messages .message-content pre code {
|
||||||
@ -36,17 +24,23 @@ svg text {
|
|||||||
white-space: inherit;
|
white-space: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.copy-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content pre {
|
/* Style for the overall chat container */
|
||||||
font-family: monospace;
|
|
||||||
background-color: #363636 !important;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#chat-messages {
|
#chat-messages {
|
||||||
max-width: 780px;
|
max-width: 780px;
|
||||||
@ -55,23 +49,13 @@ svg text {
|
|||||||
margin-bottom: 180px;
|
margin-bottom: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chat-input-form {
|
/* Primary color */
|
||||||
max-width: 900px;
|
|
||||||
margin: auto;
|
|
||||||
width: 98%;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--bulma-body-background-color: #202020;
|
--bulma-body-background-color: #202020;
|
||||||
--bulma-primary: #126d0f;
|
--bulma-primary: #126d0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
body,
|
/* Chat input stuff */
|
||||||
html {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-input-container {
|
.chat-input-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -106,4 +90,26 @@ html {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indicator */
|
||||||
|
.my-indicator {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.htmx-request .my-indicator {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.htmx-request.my-indicator {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo */
|
||||||
|
svg text {
|
||||||
|
font-family: 'Russo One', sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
fill: #000;
|
||||||
|
stroke: #000;
|
||||||
|
font-size: 240px;
|
||||||
}
|
}
|
18
utils.go
18
utils.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
@ -19,7 +20,22 @@ func markdownToHTML(markdownText string) string {
|
|||||||
panic(err) // Handle the error appropriately
|
panic(err) // Handle the error appropriately
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf.String()
|
return addCopyButtonsToCode(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func addCopyButtonsToCode(htmlContent string) string {
|
||||||
|
buttonHTML := `<button class="copy-button" onclick="copyCode(this)"><i class="fa-solid fa-copy"></i></button>`
|
||||||
|
|
||||||
|
// Regular expression pattern to match <pre> elements and insert the button right before <code>
|
||||||
|
pattern := `(<pre[^>]*>)`
|
||||||
|
|
||||||
|
// Compile the regular expression
|
||||||
|
re := regexp.MustCompile(pattern)
|
||||||
|
|
||||||
|
// Replace each matched <pre> element with the updated HTML
|
||||||
|
updatedHTML := re.ReplaceAllString(htmlContent, "$1"+buttonHTML)
|
||||||
|
|
||||||
|
return updatedHTML
|
||||||
}
|
}
|
||||||
|
|
||||||
func model2Icon(model string) string {
|
func model2Icon(model string) string {
|
||||||
|
@ -12,12 +12,15 @@
|
|||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
{% if IsLogin %}
|
||||||
|
<a class="button is-light is-small" href="/signout">
|
||||||
|
Log out
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
<a class="button is-light is-small" href="/signin">
|
<a class="button is-light is-small" href="/signin">
|
||||||
Log in
|
Log in
|
||||||
</a>
|
</a>
|
||||||
<a class="button is-primary" href="/signup">
|
{% endif %}
|
||||||
<strong>Sign up</strong>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user