|
@@ -575,48 +575,31 @@ func (s *Server) CreateModelHandler(c *gin.Context) {
|
|
}
|
|
}
|
|
|
|
|
|
func (s *Server) DeleteModelHandler(c *gin.Context) {
|
|
func (s *Server) DeleteModelHandler(c *gin.Context) {
|
|
- var req api.DeleteRequest
|
|
|
|
- err := c.ShouldBindJSON(&req)
|
|
|
|
- switch {
|
|
|
|
- case errors.Is(err, io.EOF):
|
|
|
|
|
|
+ var r api.DeleteRequest
|
|
|
|
+ if err := c.ShouldBindJSON(&r); errors.Is(err, io.EOF) {
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "missing request body"})
|
|
return
|
|
return
|
|
- case err != nil:
|
|
|
|
|
|
+ } else if err != nil {
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- var model string
|
|
|
|
- if req.Model != "" {
|
|
|
|
- model = req.Model
|
|
|
|
- } else if req.Name != "" {
|
|
|
|
- model = req.Name
|
|
|
|
- } else {
|
|
|
|
- c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "model is required"})
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if err := DeleteModel(model); err != nil {
|
|
|
|
- if os.IsNotExist(err) {
|
|
|
|
- c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found", model)})
|
|
|
|
- } else {
|
|
|
|
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
|
|
- }
|
|
|
|
|
|
+ n := model.ParseName(cmp.Or(r.Model, r.Name))
|
|
|
|
+ if !n.IsValid() {
|
|
|
|
+ c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("name %q is invalid", cmp.Or(r.Model, r.Name))})
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- manifestsPath, err := GetManifestPath()
|
|
|
|
|
|
+ m, err := ParseNamedManifest(n)
|
|
if err != nil {
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- if err := PruneDirectory(manifestsPath); err != nil {
|
|
|
|
|
|
+ if err := m.Remove(); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
return
|
|
}
|
|
}
|
|
-
|
|
|
|
- c.JSON(http.StatusOK, nil)
|
|
|
|
}
|
|
}
|
|
|
|
|
|
func (s *Server) ShowModelHandler(c *gin.Context) {
|
|
func (s *Server) ShowModelHandler(c *gin.Context) {
|
|
@@ -720,72 +703,42 @@ func GetModelInfo(req api.ShowRequest) (*api.ShowResponse, error) {
|
|
}
|
|
}
|
|
|
|
|
|
func (s *Server) ListModelsHandler(c *gin.Context) {
|
|
func (s *Server) ListModelsHandler(c *gin.Context) {
|
|
- manifests, err := GetManifestPath()
|
|
|
|
|
|
+ ms, err := Manifests()
|
|
if err != nil {
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
models := []api.ModelResponse{}
|
|
models := []api.ModelResponse{}
|
|
- if err := filepath.Walk(manifests, func(path string, info os.FileInfo, _ error) error {
|
|
|
|
- if !info.IsDir() {
|
|
|
|
- rel, err := filepath.Rel(manifests, path)
|
|
|
|
- if err != nil {
|
|
|
|
- return err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if hidden, err := filepath.Match(".*", filepath.Base(rel)); err != nil {
|
|
|
|
- return err
|
|
|
|
- } else if hidden {
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- n := model.ParseNameFromFilepath(rel)
|
|
|
|
- if !n.IsValid() {
|
|
|
|
- slog.Warn("bad manifest filepath", "path", rel)
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- m, err := ParseNamedManifest(n)
|
|
|
|
- if err != nil {
|
|
|
|
- slog.Warn("bad manifest", "name", n, "error", err)
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- f, err := m.Config.Open()
|
|
|
|
- if err != nil {
|
|
|
|
- slog.Warn("bad manifest config filepath", "name", n, "error", err)
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
- defer f.Close()
|
|
|
|
-
|
|
|
|
- var c ConfigV2
|
|
|
|
- if err := json.NewDecoder(f).Decode(&c); err != nil {
|
|
|
|
- slog.Warn("bad manifest config", "name", n, "error", err)
|
|
|
|
- return nil
|
|
|
|
- }
|
|
|
|
|
|
+ for n, m := range ms {
|
|
|
|
+ f, err := m.Config.Open()
|
|
|
|
+ if err != nil {
|
|
|
|
+ slog.Warn("bad manifest filepath", "name", n, "error", err)
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ defer f.Close()
|
|
|
|
|
|
- // tag should never be masked
|
|
|
|
- models = append(models, api.ModelResponse{
|
|
|
|
- Model: n.DisplayShortest(),
|
|
|
|
- Name: n.DisplayShortest(),
|
|
|
|
- Size: m.Size(),
|
|
|
|
- Digest: m.Digest,
|
|
|
|
- ModifiedAt: info.ModTime(),
|
|
|
|
- Details: api.ModelDetails{
|
|
|
|
- Format: c.ModelFormat,
|
|
|
|
- Family: c.ModelFamily,
|
|
|
|
- Families: c.ModelFamilies,
|
|
|
|
- ParameterSize: c.ModelType,
|
|
|
|
- QuantizationLevel: c.FileType,
|
|
|
|
- },
|
|
|
|
- })
|
|
|
|
|
|
+ var cf ConfigV2
|
|
|
|
+ if err := json.NewDecoder(f).Decode(&cf); err != nil {
|
|
|
|
+ slog.Warn("bad manifest config", "name", n, "error", err)
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
|
|
|
|
- return nil
|
|
|
|
- }); err != nil {
|
|
|
|
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
|
|
- return
|
|
|
|
|
|
+ // tag should never be masked
|
|
|
|
+ models = append(models, api.ModelResponse{
|
|
|
|
+ Model: n.DisplayShortest(),
|
|
|
|
+ Name: n.DisplayShortest(),
|
|
|
|
+ Size: m.Size(),
|
|
|
|
+ Digest: m.digest,
|
|
|
|
+ ModifiedAt: m.fi.ModTime(),
|
|
|
|
+ Details: api.ModelDetails{
|
|
|
|
+ Format: cf.ModelFormat,
|
|
|
|
+ Family: cf.ModelFamily,
|
|
|
|
+ Families: cf.ModelFamilies,
|
|
|
|
+ ParameterSize: cf.ModelType,
|
|
|
|
+ QuantizationLevel: cf.FileType,
|
|
|
|
+ },
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
|
|
slices.SortStableFunc(models, func(i, j api.ModelResponse) int {
|
|
slices.SortStableFunc(models, func(i, j api.ModelResponse) int {
|