use parser.Format instead of templating modelfile
This commit is contained in:
parent
176ad3aa6e
commit
9cf0f2e973
3 changed files with 54 additions and 75 deletions
|
@ -32,7 +32,7 @@ var (
|
|||
)
|
||||
|
||||
func Format(cmds []Command) string {
|
||||
var b bytes.Buffer
|
||||
var sb strings.Builder
|
||||
for _, cmd := range cmds {
|
||||
name := cmd.Name
|
||||
args := cmd.Args
|
||||
|
@ -43,19 +43,18 @@ func Format(cmds []Command) string {
|
|||
args = cmd.Args
|
||||
case "license", "template", "system", "adapter":
|
||||
args = quote(args)
|
||||
// pass
|
||||
case "message":
|
||||
role, message, _ := strings.Cut(cmd.Args, ": ")
|
||||
args = role + " " + quote(message)
|
||||
default:
|
||||
name = "parameter"
|
||||
args = cmd.Name + " " + cmd.Args
|
||||
args = cmd.Name + " " + quote(cmd.Args)
|
||||
}
|
||||
|
||||
fmt.Fprintln(&b, strings.ToUpper(name), args)
|
||||
fmt.Fprintln(&sb, strings.ToUpper(name), args)
|
||||
}
|
||||
|
||||
return b.String()
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func Parse(r io.Reader) (cmds []Command, err error) {
|
||||
|
@ -225,12 +224,12 @@ func parseRuneForState(r rune, cs state) (state, rune, error) {
|
|||
}
|
||||
|
||||
func quote(s string) string {
|
||||
if strings.Contains(s, "\n") || strings.HasSuffix(s, " ") {
|
||||
if strings.Contains(s, "\n") || strings.HasPrefix(s, " ") || strings.HasSuffix(s, " ") {
|
||||
if strings.Contains(s, "\"") {
|
||||
return `"""` + s + `"""`
|
||||
}
|
||||
|
||||
return strconv.Quote(s)
|
||||
return `"` + s + `"`
|
||||
}
|
||||
|
||||
return s
|
||||
|
|
104
server/images.go
104
server/images.go
|
@ -21,7 +21,6 @@ import (
|
|||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
|
@ -64,6 +63,48 @@ func (m *Model) IsEmbedding() bool {
|
|||
return slices.Contains(m.Config.ModelFamilies, "bert") || slices.Contains(m.Config.ModelFamilies, "nomic-bert")
|
||||
}
|
||||
|
||||
func (m *Model) Commands() (cmds []parser.Command) {
|
||||
cmds = append(cmds, parser.Command{Name: "model", Args: m.ModelPath})
|
||||
|
||||
if m.Template != "" {
|
||||
cmds = append(cmds, parser.Command{Name: "template", Args: m.Template})
|
||||
}
|
||||
|
||||
if m.System != "" {
|
||||
cmds = append(cmds, parser.Command{Name: "system", Args: m.System})
|
||||
}
|
||||
|
||||
for _, adapter := range m.AdapterPaths {
|
||||
cmds = append(cmds, parser.Command{Name: "adapter", Args: adapter})
|
||||
}
|
||||
|
||||
for _, projector := range m.ProjectorPaths {
|
||||
cmds = append(cmds, parser.Command{Name: "projector", Args: projector})
|
||||
}
|
||||
|
||||
for k, v := range m.Options {
|
||||
switch v := v.(type) {
|
||||
case []any:
|
||||
for _, s := range v {
|
||||
cmds = append(cmds, parser.Command{Name: k, Args: fmt.Sprintf("%v", s)})
|
||||
}
|
||||
default:
|
||||
cmds = append(cmds, parser.Command{Name: k, Args: fmt.Sprintf("%v", v)})
|
||||
}
|
||||
}
|
||||
|
||||
for _, license := range m.License {
|
||||
cmds = append(cmds, parser.Command{Name: "license", Args: license})
|
||||
}
|
||||
|
||||
for _, msg := range m.Messages {
|
||||
cmds = append(cmds, parser.Command{Name: "message", Args: fmt.Sprintf("%s %s", msg.Role, msg.Content)})
|
||||
}
|
||||
|
||||
return cmds
|
||||
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
|
@ -901,67 +942,6 @@ func DeleteModel(name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func ShowModelfile(model *Model) (string, error) {
|
||||
var mt struct {
|
||||
*Model
|
||||
From string
|
||||
Parameters map[string][]any
|
||||
}
|
||||
|
||||
mt.Parameters = make(map[string][]any)
|
||||
for k, v := range model.Options {
|
||||
if s, ok := v.([]any); ok {
|
||||
mt.Parameters[k] = s
|
||||
continue
|
||||
}
|
||||
|
||||
mt.Parameters[k] = []any{v}
|
||||
}
|
||||
|
||||
mt.Model = model
|
||||
mt.From = model.ModelPath
|
||||
|
||||
if model.ParentModel != "" {
|
||||
mt.From = model.ParentModel
|
||||
}
|
||||
|
||||
modelFile := `# Modelfile generated by "ollama show"
|
||||
# To build a new Modelfile based on this one, replace the FROM line with:
|
||||
# FROM {{ .ShortName }}
|
||||
|
||||
FROM {{ .From }}
|
||||
TEMPLATE """{{ .Template }}"""
|
||||
|
||||
{{- if .System }}
|
||||
SYSTEM """{{ .System }}"""
|
||||
{{- end }}
|
||||
|
||||
{{- range $adapter := .AdapterPaths }}
|
||||
ADAPTER {{ $adapter }}
|
||||
{{- end }}
|
||||
|
||||
{{- range $k, $v := .Parameters }}
|
||||
{{- range $parameter := $v }}
|
||||
PARAMETER {{ $k }} {{ printf "%#v" $parameter }}
|
||||
{{- end }}
|
||||
{{- end }}`
|
||||
|
||||
tmpl, err := template.New("").Parse(modelFile)
|
||||
if err != nil {
|
||||
slog.Info(fmt.Sprintf("error parsing template: %q", err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
if err = tmpl.Execute(&buf, mt); err != nil {
|
||||
slog.Info(fmt.Sprintf("error executing template: %q", err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func PushModel(ctx context.Context, name string, regOpts *registryOptions, fn func(api.ProgressResponse)) error {
|
||||
mp := ParseModelPath(name)
|
||||
fn(api.ProgressResponse{Status: "retrieving manifest"})
|
||||
|
|
|
@ -728,12 +728,12 @@ func GetModelInfo(req api.ShowRequest) (*api.ShowResponse, error) {
|
|||
}
|
||||
}
|
||||
|
||||
mf, err := ShowModelfile(model)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp.Modelfile = mf
|
||||
var sb strings.Builder
|
||||
fmt.Fprintln(&sb, "# Modelfile generate 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, parser.Format(model.Commands()))
|
||||
resp.Modelfile = sb.String()
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue