flux-schnell and triposr come with llmgw as presets: their workflow, custom nodes, packages and licence as they were found and tried on the PoC, and a profile that says the card it needs rather than a class, so the entry places on any site's cards. TripoSR's workflow is built in, with the LLMGWPrepareForMesh node that keeps a picture's background out of the mesh, which the copy in the document had left out. `ctl model add PRESET` adds one, and has the nodes install ComfyUI when the cluster's settings name none; `ctl model presets` lists them; the console's add-model dialog offers them beside a definition file. A ComfyUI build is now also checked to keep its order on a Turing card, so a node's installed cu13 is not replaced by the cu126 build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
108 lines
3.4 KiB
Go
108 lines
3.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/control/adminapi"
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/control/catalog"
|
|
)
|
|
|
|
// presetAdmin is an admin API holding settings, which records the models
|
|
// added and the settings put.
|
|
type presetAdmin struct {
|
|
mu sync.Mutex
|
|
settings string
|
|
added []catalog.Model
|
|
put []string
|
|
}
|
|
|
|
func (a *presetAdmin) client(t *testing.T) func() *ctlClient {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
body, _ := io.ReadAll(r.Body)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
switch {
|
|
case r.Method == http.MethodPost && r.URL.Path == "/api/v1/models":
|
|
var m catalog.Model
|
|
_ = json.Unmarshal(body, &m)
|
|
a.added = append(a.added, m)
|
|
_ = json.NewEncoder(w).Encode(map[string]string{"name": m.Name})
|
|
case r.Method == http.MethodGet && r.URL.Path == "/api/v1/settings":
|
|
_ = json.NewEncoder(w).Encode(adminapi.SettingsView{Version: 1, Body: a.settings})
|
|
case r.Method == http.MethodPut && r.URL.Path == "/api/v1/settings":
|
|
var req adminapi.SettingsRequest
|
|
_ = json.Unmarshal(body, &req)
|
|
a.put = append(a.put, req.Body)
|
|
a.settings = req.Body
|
|
_ = json.NewEncoder(w).Encode(adminapi.SettingsView{Version: 2, Body: req.Body})
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
return func() *ctlClient { return newCtlClient(strings.TrimPrefix(srv.URL, "http://"), "") }
|
|
}
|
|
|
|
func runModelAdd(t *testing.T, client func() *ctlClient, args ...string) (string, error) {
|
|
t.Helper()
|
|
cmd := newModelAddCmd(client)
|
|
var out bytes.Buffer
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
cmd.SetArgs(append(args, "--no-source-check"))
|
|
err := cmd.ExecuteContext(t.Context())
|
|
return out.String(), err
|
|
}
|
|
|
|
func TestAPresetIsAddedByNameAndHasTheNodesInstallComfyUI(t *testing.T) {
|
|
a := &presetAdmin{settings: "router:\n retries: 2\n"}
|
|
out, err := runModelAdd(t, a.client(t), "triposr")
|
|
if err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
if len(a.added) != 1 || a.added[0].Name != "triposr" || a.added[0].ComfyUI.Workflow != "triposr" {
|
|
t.Fatalf("added %+v", a.added)
|
|
}
|
|
if len(a.put) != 1 || !strings.Contains(a.put[0], "comfyui: 0.39.2") || !strings.Contains(a.put[0], "retries: 2") {
|
|
t.Fatalf("settings put %q", a.put)
|
|
}
|
|
if !strings.Contains(out, "install ComfyUI 0.39.2") {
|
|
t.Errorf("not said:\n%s", out)
|
|
}
|
|
}
|
|
|
|
func TestAClusterThatNamesItsComfyUIKeepsIt(t *testing.T) {
|
|
for _, settings := range []string{"engines:\n comfyui: 0.38.0\n", "engines:\n comfyui: \"\"\n"} {
|
|
a := &presetAdmin{settings: settings}
|
|
out, err := runModelAdd(t, a.client(t), "flux-schnell")
|
|
if err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
if len(a.put) != 0 {
|
|
t.Errorf("%q: settings changed to %q", settings, a.put)
|
|
}
|
|
if none := strings.Contains(settings, `""`); none != strings.Contains(out, "set to none") {
|
|
t.Errorf("%q: %s", settings, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAnUnknownPresetNamesTheOnesThereAre(t *testing.T) {
|
|
a := &presetAdmin{}
|
|
_, err := runModelAdd(t, a.client(t), "sdxl")
|
|
if err == nil || !strings.Contains(err.Error(), "flux-schnell, triposr") || len(a.added) != 0 {
|
|
t.Errorf("%v, added %v", err, a.added)
|
|
}
|
|
if _, err := runModelAdd(t, a.client(t), "triposr", "-f", "x.yaml"); err == nil {
|
|
t.Error("a preset and a file were both taken")
|
|
}
|
|
}
|