From 89c79bec8cf7a7b04f761fcc5306d2edf47a4164 Mon Sep 17 00:00:00 2001 From: royjhan <65097070+royjhan@users.noreply.github.com> Date: Sat, 15 Jun 2024 20:53:56 -0700 Subject: [PATCH] Add ModifiedAt Field to /api/show (#5033) * Add Mod Time to Show * Error Handling --- api/types.go | 1 + server/routes.go | 56 ++++++++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/api/types.go b/api/types.go index d99cf3bc..d62079ae 100644 --- a/api/types.go +++ b/api/types.go @@ -238,6 +238,7 @@ type ShowResponse struct { System string `json:"system,omitempty"` Details ModelDetails `json:"details,omitempty"` Messages []Message `json:"messages,omitempty"` + ModifiedAt time.Time `json:"modified_at,omitempty"` } // CopyRequest is the request passed to [Client.Copy]. diff --git a/server/routes.go b/server/routes.go index 188fe974..f36fe1b0 100644 --- a/server/routes.go +++ b/server/routes.go @@ -646,9 +646,12 @@ func (s *Server) ShowModelHandler(c *gin.Context) { resp, err := GetModelInfo(req) if err != nil { - if os.IsNotExist(err) { + switch { + case os.IsNotExist(err): c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("model '%s' not found", req.Model)}) - } else { + case err.Error() == "invalid model name": + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + default: c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } return @@ -658,44 +661,55 @@ func (s *Server) ShowModelHandler(c *gin.Context) { } func GetModelInfo(req api.ShowRequest) (*api.ShowResponse, error) { - model, err := GetModel(req.Model) + m, err := GetModel(req.Model) if err != nil { return nil, err } modelDetails := api.ModelDetails{ - ParentModel: model.ParentModel, - Format: model.Config.ModelFormat, - Family: model.Config.ModelFamily, - Families: model.Config.ModelFamilies, - ParameterSize: model.Config.ModelType, - QuantizationLevel: model.Config.FileType, + ParentModel: m.ParentModel, + Format: m.Config.ModelFormat, + Family: m.Config.ModelFamily, + Families: m.Config.ModelFamilies, + ParameterSize: m.Config.ModelType, + QuantizationLevel: m.Config.FileType, } if req.System != "" { - model.System = req.System + m.System = req.System } if req.Template != "" { - model.Template = req.Template + m.Template = req.Template } msgs := make([]api.Message, 0) - for _, msg := range model.Messages { + for _, msg := range m.Messages { msgs = append(msgs, api.Message{Role: msg.Role, Content: msg.Content}) } + n := model.ParseName(req.Model) + if !n.IsValid() { + return nil, fmt.Errorf("invalid model name") + } + + manifest, err := ParseNamedManifest(n) + if err != nil { + return nil, err + } + resp := &api.ShowResponse{ - License: strings.Join(model.License, "\n"), - System: model.System, - Template: model.Template, - Details: modelDetails, - Messages: msgs, + License: strings.Join(m.License, "\n"), + System: m.System, + Template: m.Template, + Details: modelDetails, + Messages: msgs, + ModifiedAt: manifest.fi.ModTime(), } var params []string cs := 30 - for k, v := range model.Options { + for k, v := range m.Options { switch val := v.(type) { case []interface{}: for _, nv := range val { @@ -709,15 +723,15 @@ func GetModelInfo(req api.ShowRequest) (*api.ShowResponse, error) { for k, v := range req.Options { if _, ok := req.Options[k]; ok { - model.Options[k] = v + m.Options[k] = v } } var sb strings.Builder fmt.Fprintln(&sb, "# Modelfile generated by \"ollama show\"") fmt.Fprintln(&sb, "# To build a new Modelfile based on this, replace FROM with:") - fmt.Fprintf(&sb, "# FROM %s\n\n", model.ShortName) - fmt.Fprint(&sb, model.String()) + fmt.Fprintf(&sb, "# FROM %s\n\n", m.ShortName) + fmt.Fprint(&sb, m.String()) resp.Modelfile = sb.String() return resp, nil