- Add a react UI to replace the plain HTML one. - Serve as a foundation for better GUI interactions
102 lines
2.2 KiB
Go
102 lines
2.2 KiB
Go
package proxy
|
|
|
|
import (
|
|
"net/http"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type Model struct {
|
|
Id string `json:"id"`
|
|
State string `json:"state"`
|
|
}
|
|
|
|
func addApiHandlers(pm *ProxyManager) {
|
|
// Add API endpoints for React to consume
|
|
apiGroup := pm.ginEngine.Group("/api")
|
|
{
|
|
apiGroup.GET("/models", pm.apiListModels)
|
|
apiGroup.GET("/modelsSSE", pm.apiListModelsSSE)
|
|
apiGroup.POST("/models/unload", pm.apiUnloadAllModels)
|
|
}
|
|
}
|
|
|
|
func (pm *ProxyManager) apiUnloadAllModels(c *gin.Context) {
|
|
pm.StopProcesses(StopImmediately)
|
|
c.JSON(http.StatusOK, gin.H{"msg": "ok"})
|
|
}
|
|
|
|
func (pm *ProxyManager) getModelStatus() []Model {
|
|
// Extract keys and sort them
|
|
models := []Model{}
|
|
|
|
modelIDs := make([]string, 0, len(pm.config.Models))
|
|
for modelID := range pm.config.Models {
|
|
modelIDs = append(modelIDs, modelID)
|
|
}
|
|
sort.Strings(modelIDs)
|
|
|
|
// Iterate over sorted keys
|
|
for _, modelID := range modelIDs {
|
|
// Get process state
|
|
processGroup := pm.findGroupByModelName(modelID)
|
|
state := "unknown"
|
|
if processGroup != nil {
|
|
process := processGroup.processes[modelID]
|
|
if process != nil {
|
|
var stateStr string
|
|
switch process.CurrentState() {
|
|
case StateReady:
|
|
stateStr = "ready"
|
|
case StateStarting:
|
|
stateStr = "starting"
|
|
case StateStopping:
|
|
stateStr = "stopping"
|
|
case StateShutdown:
|
|
stateStr = "shutdown"
|
|
case StateStopped:
|
|
stateStr = "stopped"
|
|
default:
|
|
stateStr = "unknown"
|
|
}
|
|
state = stateStr
|
|
}
|
|
}
|
|
models = append(models, Model{
|
|
Id: modelID,
|
|
State: state,
|
|
})
|
|
}
|
|
|
|
return models
|
|
}
|
|
|
|
func (pm *ProxyManager) apiListModels(c *gin.Context) {
|
|
c.JSON(http.StatusOK, pm.getModelStatus())
|
|
}
|
|
|
|
// stream the models as a SSE
|
|
func (pm *ProxyManager) apiListModelsSSE(c *gin.Context) {
|
|
c.Header("Content-Type", "text/event-stream")
|
|
c.Header("Cache-Control", "no-cache")
|
|
c.Header("Connection", "keep-alive")
|
|
c.Header("X-Content-Type-Options", "nosniff")
|
|
|
|
notify := c.Request.Context().Done()
|
|
|
|
// Stream new events
|
|
for {
|
|
select {
|
|
case <-notify:
|
|
return
|
|
default:
|
|
models := pm.getModelStatus()
|
|
c.SSEvent("message", models)
|
|
c.Writer.Flush()
|
|
<-time.After(1000 * time.Millisecond)
|
|
}
|
|
}
|
|
}
|