Merge branch 'codex/model-management'

This commit is contained in:
tian 2026-05-05 12:01:33 +08:00
commit 452d344b34
6 changed files with 121 additions and 0 deletions

View File

@ -0,0 +1,20 @@
package httpapi
import "net/http"
func (s *Server) handleModelsStatus(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
errorJSON(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
if !s.authorize(r, false) {
errorJSON(w, http.StatusUnauthorized, "unauthorized")
return
}
items, err := s.store.ListInstalledModels()
if err != nil {
errorJSON(w, http.StatusInternalServerError, "internal error: "+err.Error())
return
}
writeJSON(w, http.StatusOK, map[string]any{"models": items})
}

View File

@ -0,0 +1,41 @@
package httpapi
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"rk3588sys/agent/internal/modelstore"
)
func TestHandleModelsStatusReturnsInstalledModels(t *testing.T) {
dir := t.TempDir()
store := modelstore.New(dir, 8)
itemDir := store.FilesDir()
if err := os.MkdirAll(itemDir, 0o755); err != nil {
t.Fatalf("MkdirAll: %v", err)
}
modelPath := filepath.Join(itemDir, "face_det_scrfd_500m_640_rk3588__abc.rknn")
if err := os.WriteFile(modelPath, []byte("abc"), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
if err := os.WriteFile(store.ManifestPath(), []byte(`{"items":[{"name":"face_det_scrfd_500m_640_rk3588","sha256":"abc","path":"`+filepath.ToSlash(modelPath)+`","size":3,"mtime_ms":1}]}`), 0o644); err != nil {
t.Fatalf("WriteFile manifest: %v", err)
}
srv := &Server{store: store}
req := httptest.NewRequest(http.MethodGet, "/v1/models/status", nil)
rr := httptest.NewRecorder()
srv.handleModelsStatus(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
}
if !strings.Contains(rr.Body.String(), "face_det_scrfd_500m_640_rk3588") {
t.Fatalf("expected response to include model name, got %s", rr.Body.String())
}
}

View File

@ -127,6 +127,7 @@ func New(agentCfg config.AgentConfig, baseDir string, ms *mediaserver.Client, st
mux.HandleFunc("/v1/face-gallery", s.handleFaceGallery)
mux.HandleFunc("/v1/face-gallery/reload", s.handleFaceGalleryReload)
mux.HandleFunc("/v1/models", s.handleModelsList)
mux.HandleFunc("/v1/models/status", s.handleModelsStatus)
mux.HandleFunc("/v1/models/", s.handleModelUpload)
mux.HandleFunc("/v1/media-server/reload", s.handleMediaReload)
mux.HandleFunc("/v1/media-server/rollback", s.handleMediaRollback)

View File

@ -26,6 +26,15 @@ type Manifest struct {
Items []Item `json:"items"`
}
type InstalledModel struct {
Name string `json:"name"`
FileName string `json:"file_name"`
Sha256 string `json:"sha256"`
Path string `json:"path"`
Size int64 `json:"size"`
MtimeMS int64 `json:"mtime_ms"`
}
type Store struct {
ModelsDir string
MaxUploadBytes int64
@ -136,6 +145,26 @@ func (s *Store) List() (Manifest, error) {
return m, nil
}
func (s *Store) ListInstalledModels() ([]InstalledModel, error) {
manifest, err := s.List()
if err != nil {
return nil, err
}
items := make([]InstalledModel, 0, len(manifest.Items))
for _, item := range manifest.Items {
fileName := filepath.Base(filepath.FromSlash(item.Path))
items = append(items, InstalledModel{
Name: item.Name,
FileName: fileName,
Sha256: item.Sha256,
Path: item.Path,
Size: item.Size,
MtimeMS: item.MtimeMS,
})
}
return items, nil
}
func (s *Store) upsertManifest(item Item) error {
m, err := s.List()
if err != nil {

View File

@ -0,0 +1,30 @@
package modelstore
import (
"os"
"path/filepath"
"testing"
)
func TestListInstalledModelsUsesManifestEntries(t *testing.T) {
dir := t.TempDir()
store := New(dir, 8)
if err := os.MkdirAll(store.FilesDir(), 0o755); err != nil {
t.Fatalf("MkdirAll: %v", err)
}
modelPath := filepath.Join(store.FilesDir(), "face_det_scrfd_500m_640_rk3588__abc.rknn")
if err := os.WriteFile(modelPath, []byte("abc"), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
if err := os.WriteFile(store.ManifestPath(), []byte(`{"items":[{"name":"face_det_scrfd_500m_640_rk3588","sha256":"abc","path":"`+filepath.ToSlash(modelPath)+`","size":3,"mtime_ms":1}]}`), 0o644); err != nil {
t.Fatalf("WriteFile manifest: %v", err)
}
items, err := store.ListInstalledModels()
if err != nil {
t.Fatalf("ListInstalledModels: %v", err)
}
if len(items) != 1 || items[0].FileName == "" {
t.Fatalf("unexpected installed models: %#v", items)
}
}

Binary file not shown.