Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deep Chat integration #294

Merged
merged 6 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/private-deep-chat/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module private-chat

go 1.22.0
94 changes: 94 additions & 0 deletions examples/private-deep-chat/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package main

import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strings"
)

// Run a web server that serves static content and proxies inference
// requests to KubeAI.
// Control access with basic auth.
func main() {
kubeAIURL, err := url.Parse(os.Getenv("KUBEAI_ADDR"))
if err != nil {
log.Fatalf("failed to parse KubeAI address: %v", err)
}

staticHandler := http.FileServer(http.Dir("static"))
proxyHandler := httputil.NewSingleHostReverseProxy(kubeAIURL)

http.Handle("/", authUser(staticHandler))
http.Handle("/openai/", authUserToKubeAI(proxyHandler)) //authUserToKubeAI(proxyHandler))

listenAddr := os.Getenv("LISTEN_ADDR")
log.Printf("listening on %s", listenAddr)
log.Fatal(http.ListenAndServe(listenAddr, nil))
}

func authUser(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if _, matches := authenticate(user, pass); !ok || !matches {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
h.ServeHTTP(w, r)
})
}

func authUserToKubeAI(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, basicAuthProvided := r.BasicAuth()

tenancy, authenticated := authenticate(user, pass)

log.Printf("%s: %s - authenticating: basicAuthProvided=%t, user=%q, pass=%q, tenancy=%q, authenticated=%t",
r.Method, r.URL.Path,
basicAuthProvided,
user, pass, strings.Join(tenancy, ","),
authenticated,
)

if !basicAuthProvided || !authenticated || len(tenancy) == 0 {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}

r.Header.Set("X-Label-Selector", fmt.Sprintf("tenancy in (%s)",
strings.Join(tenancy, ","),
))

h.ServeHTTP(w, r)
})
}

// authenticate checks the provided username and password.
// If the user is authenticated, it returns the tenancy groups the user belongs to.
func authenticate(user, pass string) ([]string, bool) {
// In a real application, this would be a database lookup.
userTable := map[string]struct {
password string
tenancy []string
}{
"nick": {"nickspass", []string{"group-a"}},
"sam": {"samspass", []string{"group-b"}},
"joe": {"joespass", []string{"group-a", "group-b"}},
}

row, ok := userTable[user]
if !ok {
return nil, false
}
if row.password != pass {
return nil, false
}

return row.tenancy, true
}
19 changes: 19 additions & 0 deletions examples/private-deep-chat/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
</head>
<script type="module" src="https://unpkg.com/deep-chat@2.0.1/dist/deepChat.bundle.js"></script>

<body>
<deep-chat id="chat-element" style="border-radius: 10px; width: 96vw; height: calc(100vh - 70px); padding-top: 10px"
messageStyles='{"default": {"shared": {"innerContainer": {"fontSize": "1rem"}}}}'
inputAreaStyle='{"fontSize": "1rem"}'
connect='{"url":"/openai/v1/chat/completions", "credentials": "same-origin", "stream": true}'
nstogner marked this conversation as resolved.
Show resolved Hide resolved
directConnection='{"openAI":{"chat": {"model": "gemma2-2b-cpu"}, "key": "placeholder", "validateKeyProperty": false}}'
textInput='{"placeholder":{"text": "Welcome to the demo!"}}'>
</deep-chat>
</body>

</html>
Loading