model.go 2.78 KB
Newer Older
Michael Yang's avatar
Michael Yang committed
1
2
3
4
5
package server

import (
	"bytes"
	"context"
Michael Yang's avatar
tools  
Michael Yang committed
6
	"encoding/json"
Michael Yang's avatar
Michael Yang committed
7
8
9
	"errors"
	"fmt"
	"io"
10
	"log/slog"
Michael Yang's avatar
Michael Yang committed
11
12
13
14
	"net/http"
	"os"

	"github.com/ollama/ollama/api"
Michael Yang's avatar
Michael Yang committed
15
	"github.com/ollama/ollama/fs/ggml"
Michael Yang's avatar
Michael Yang committed
16
	"github.com/ollama/ollama/template"
Michael Yang's avatar
Michael Yang committed
17
18
19
	"github.com/ollama/ollama/types/model"
)

Michael Yang's avatar
Michael Yang committed
20
var intermediateBlobs map[string]string = make(map[string]string)
21

22
type layerGGML struct {
23
	Layer
Michael Yang's avatar
Michael Yang committed
24
	*ggml.GGML
Michael Yang's avatar
Michael Yang committed
25
26
}

27
func parseFromModel(ctx context.Context, name model.Name, fn func(api.ProgressResponse)) (layers []*layerGGML, err error) {
28
	m, err := ParseNamedManifest(name)
Michael Yang's avatar
Michael Yang committed
29
30
	switch {
	case errors.Is(err, os.ErrNotExist):
Michael Yang's avatar
Michael Yang committed
31
		if err := PullModel(ctx, name.String(), &registryOptions{}, fn); err != nil {
Michael Yang's avatar
Michael Yang committed
32
33
34
			return nil, err
		}

35
		m, err = ParseNamedManifest(name)
Michael Yang's avatar
Michael Yang committed
36
37
38
		if err != nil {
			return nil, err
		}
Michael Yang's avatar
Michael Yang committed
39
40
41
42
	case err != nil:
		return nil, err
	}

43
44
	for _, layer := range m.Layers {
		layer, err := NewLayerFromLayer(layer.Digest, layer.MediaType, name.DisplayShortest())
Michael Yang's avatar
Michael Yang committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
		if err != nil {
			return nil, err
		}

		switch layer.MediaType {
		case "application/vnd.ollama.image.model",
			"application/vnd.ollama.image.projector",
			"application/vnd.ollama.image.adapter":
			blobpath, err := GetBlobsPath(layer.Digest)
			if err != nil {
				return nil, err
			}

			blob, err := os.Open(blobpath)
			if err != nil {
				return nil, err
			}
			defer blob.Close()

64
			f, err := ggml.Decode(blob, -1)
Michael Yang's avatar
Michael Yang committed
65
66
67
			if err != nil {
				return nil, err
			}
Michael Yang's avatar
Michael Yang committed
68

Michael Yang's avatar
Michael Yang committed
69
			layers = append(layers, &layerGGML{layer, f})
Michael Yang's avatar
Michael Yang committed
70
		default:
71
			layers = append(layers, &layerGGML{layer, nil})
Michael Yang's avatar
Michael Yang committed
72
73
74
75
76
77
		}
	}

	return layers, nil
}

78
79
80
func detectChatTemplate(layers []*layerGGML) ([]*layerGGML, error) {
	for _, layer := range layers {
		if s := layer.GGML.KV().ChatTemplate(); s != "" {
Michael Yang's avatar
Michael Yang committed
81
			if t, err := template.Named(s); err != nil {
82
				slog.Debug("template detection", "error", err, "template", s)
83
			} else {
84
				layer, err := NewLayer(t.Reader(), "application/vnd.ollama.image.template")
85
86
87
88
				if err != nil {
					return nil, err
				}

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
				layer.status = fmt.Sprintf("using autodetected template %s", t.Name)
				layers = append(layers, &layerGGML{layer, nil})

				if t.Parameters != nil {
					var b bytes.Buffer
					if err := json.NewEncoder(&b).Encode(t.Parameters); err != nil {
						return nil, err
					}

					layer, err := NewLayer(&b, "application/vnd.ollama.image.params")
					if err != nil {
						return nil, err
					}

					layers = append(layers, &layerGGML{layer, nil})
				}
105
106
107
108
			}
		}
	}

Michael Yang's avatar
Michael Yang committed
109
110
111
112
113
114
115
116
117
	return layers, nil
}

func detectContentType(r io.Reader) (string, error) {
	var b bytes.Buffer
	if _, err := io.Copy(&b, r); err != nil {
		return "", err
	}

Michael Yang's avatar
Michael Yang committed
118
	if contentType := ggml.DetectContentType(b.Bytes()); contentType != "" {
Michael Yang's avatar
Michael Yang committed
119
120
121
122
123
124
125
126
127
		return contentType, nil
	}

	if contentType := http.DetectContentType(b.Bytes()); contentType != "application/octet-stream" {
		return contentType, nil
	}

	return "unknown", nil
}