101 lines
3 KiB
Go
101 lines
3 KiB
Go
package main
|
|
|
|
import (
|
|
"embed"
|
|
"flag"
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.chandlerswift.com/chandlerswift/svs-services-server/completion"
|
|
llamaserver "git.chandlerswift.com/chandlerswift/svs-services-server/completion/llama-server"
|
|
"git.chandlerswift.com/chandlerswift/svs-services-server/completion/openrouter"
|
|
"git.chandlerswift.com/chandlerswift/svs-services-server/db"
|
|
"git.chandlerswift.com/chandlerswift/svs-services-server/site"
|
|
)
|
|
|
|
//go:embed templates/index.html
|
|
var indexTemplate string
|
|
|
|
//go:embed templates/404.html
|
|
var notFoundTemplate string
|
|
|
|
//go:embed headshots/*
|
|
var headshots embed.FS
|
|
|
|
var tmpl = template.Must(template.New("index").Parse(indexTemplate))
|
|
var notFoundTmpl = template.Must(template.New("404").Parse(notFoundTemplate))
|
|
|
|
var completionProviders map[string]completion.CompletionProvider = map[string]completion.CompletionProvider{
|
|
"openrouter": openrouter.OpenRouterProvider{
|
|
Token: os.Getenv("OPENROUTER_API_KEY"),
|
|
Model: "openai/gpt-oss-120b",
|
|
},
|
|
"llama-server": llamaserver.LlamaServerProvider{
|
|
Host: "http://localhost:8080",
|
|
Model: "gpt-oss-20b-Q4_K_M",
|
|
},
|
|
}
|
|
|
|
func parseService(host string) (h string, err error) {
|
|
parts := strings.Split(host, ".")
|
|
if len(parts) != 3 {
|
|
return "", fmt.Errorf("Unexpected number of parts in hostname; expected 3, got %v", len(parts))
|
|
}
|
|
return parts[0], nil
|
|
}
|
|
|
|
func main() {
|
|
// use flag package to parse args:
|
|
port := flag.String("port", "64434", "Port to listen on") // echo "svs" | base64 -d | od -An -t u2
|
|
address := flag.String("address", "", "Address to listen on")
|
|
completionProviderName := flag.String("completion-provider", "llama-server", "Completion provider to use (openrouter, llama-server, …)")
|
|
dbpath := flag.String("database", "svs-services.db", "Path to SQLite database file")
|
|
flag.Parse()
|
|
|
|
err := db.InitDatabase(*dbpath)
|
|
if err != nil {
|
|
log.Fatalf("Failed to initialize database: %v", err)
|
|
}
|
|
|
|
addr := fmt.Sprintf("%s:%s", *address, *port)
|
|
|
|
fmt.Println("Using completion provider", *completionProviderName)
|
|
defaultCompletionProvider := completionProviders[*completionProviderName]
|
|
// for err := defaultCompletionProvider.Health(); err != nil; err = defaultCompletionProvider.Health() {
|
|
// fmt.Println("Waiting for Llama server to be healthy... (%v)", err)
|
|
// time.Sleep(1 * time.Second)
|
|
// }
|
|
|
|
http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
|
|
service, err := parseService(r.Host)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
siteData, err := site.GetSiteData(service, defaultCompletionProvider)
|
|
if err != nil {
|
|
http.Error(w, "Could not generate site", 500)
|
|
log.Printf("Getting site data for service %v: %v", service, err)
|
|
return
|
|
}
|
|
|
|
if r.URL.Path != "/" {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
notFoundTmpl.Execute(w, siteData)
|
|
return
|
|
}
|
|
|
|
tmpl.Execute(w, siteData)
|
|
})
|
|
// Serve embedded headshots file
|
|
http.Handle("GET /headshots/", http.FileServer(http.FS(headshots)))
|
|
|
|
fmt.Println("Starting server on", addr)
|
|
panic(http.ListenAndServe(addr, nil))
|
|
|
|
}
|