Files
Luminary/internal/handler/admin/workflows.go
T
renjue 76ba500417
CI / docker (push) Successful in 2m4s
Initial commit: Luminary AI Gateway
OpenAI-compatible AI gateway with Vue admin UI, multi-provider egress,
ingress key governance, monitoring, and security controls.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 21:46:16 +08:00

117 lines
3.0 KiB
Go

package admin
import (
"encoding/json"
"net/http"
"github.com/gin-gonic/gin"
"github.com/rose_cat707/luminary/internal/model"
"github.com/rose_cat707/luminary/internal/prediction"
)
func (h *Handler) GetWorkflowParamMeta(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"txt2img": prediction.Txt2ImgParams,
"img2img": prediction.Img2ImgParams,
})
}
func (h *Handler) AnalyzeWorkflow(c *gin.Context) {
var req struct {
WorkflowJSON string `json:"workflow_json"`
WorkflowType model.WorkflowType `json:"workflow_type"`
}
if err := c.ShouldBindJSON(&req); err != nil || req.WorkflowJSON == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "workflow_json required"})
return
}
if req.WorkflowType == "" {
req.WorkflowType = model.WorkflowTxt2Img
}
result, err := prediction.AnalyzeWorkflow(req.WorkflowJSON, req.WorkflowType)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, result)
}
func (h *Handler) GetPrediction(c *gin.Context) {
if h.predictions == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
p, err := h.predictions.GetDBPrediction(c.Param("id"))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
images, _ := h.images.ListByPrediction(p.ID)
c.JSON(http.StatusOK, gin.H{
"prediction": h.predictions.APIView(p, h.publicBaseURL()),
"images": images,
})
}
func (h *Handler) ServeAdminImage(c *gin.Context) {
if h.images == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
img, err := h.images.Get(c.Param("id"))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
c.Header("Content-Type", img.Mime)
c.File(img.LocalPath)
}
func bindingFromSuggestions(suggestions []prediction.BindingSuggestion, overrides map[string]*prediction.NodeField) prediction.InputBinding {
binding := prediction.InputBinding{}
for _, s := range suggestions {
if o, ok := overrides[s.Param]; ok && o != nil {
if o.Node != "" && o.Field != "" {
binding[s.Param] = o
}
continue
}
if s.Node != "" && s.Field != "" {
binding[s.Param] = &prediction.NodeField{Node: s.Node, Field: s.Field}
}
}
return binding
}
func validateImageModelCreate(req struct {
ModelID string
DisplayName string
WorkflowType model.WorkflowType
WorkflowJSON string
InputBindingJSON string
InputBinding map[string]*prediction.NodeField
}) error {
if req.WorkflowJSON == "" {
return nil
}
var workflow map[string]any
if err := json.Unmarshal([]byte(req.WorkflowJSON), &workflow); err != nil {
return err
}
var binding prediction.InputBinding
if req.InputBindingJSON != "" {
b, err := prediction.ParseBinding(req.InputBindingJSON)
if err != nil {
return err
}
binding = b
} else if req.InputBinding != nil {
binding = req.InputBinding
}
wt := req.WorkflowType
if wt == "" {
wt = model.WorkflowTxt2Img
}
return binding.Validate(workflow, prediction.RequiredBindings(wt))
}