commit
9ec7e37534
7 changed files with 47 additions and 36 deletions
|
@ -10,7 +10,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmorganca/ollama/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DefaultHost = "localhost:11434"
|
const DefaultHost = "localhost:11434"
|
||||||
|
@ -83,21 +86,21 @@ func (c *Client) do(ctx context.Context, method, path string, reqData, respData
|
||||||
reqBody = bytes.NewReader(data)
|
reqBody = bytes.NewReader(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
url := c.Base.JoinPath(path).String()
|
requestURL := c.Base.JoinPath(path)
|
||||||
|
request, err := http.NewRequestWithContext(ctx, method, requestURL.String(), reqBody)
|
||||||
req, err := http.NewRequestWithContext(ctx, method, url, reqBody)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
request.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("Accept", "application/json")
|
request.Header.Set("Accept", "application/json")
|
||||||
|
request.Header.Set("User-Agent", fmt.Sprintf("ollama/%s (%s %s) Go/%s", version.Version, runtime.GOARCH, runtime.GOOS, runtime.Version()))
|
||||||
|
|
||||||
for k, v := range c.Headers {
|
for k, v := range c.Headers {
|
||||||
req.Header[k] = v
|
request.Header[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
respObj, err := c.HTTP.Do(req)
|
respObj, err := c.HTTP.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -131,13 +134,15 @@ func (c *Client) stream(ctx context.Context, method, path string, data any, fn f
|
||||||
buf = bytes.NewBuffer(bts)
|
buf = bytes.NewBuffer(bts)
|
||||||
}
|
}
|
||||||
|
|
||||||
request, err := http.NewRequestWithContext(ctx, method, c.Base.JoinPath(path).String(), buf)
|
requestURL := c.Base.JoinPath(path)
|
||||||
|
request, err := http.NewRequestWithContext(ctx, method, requestURL.String(), buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
request.Header.Set("Content-Type", "application/json")
|
request.Header.Set("Content-Type", "application/json")
|
||||||
request.Header.Set("Accept", "application/json")
|
request.Header.Set("Accept", "application/json")
|
||||||
|
request.Header.Set("User-Agent", fmt.Sprintf("ollama/%s (%s %s) Go/%s", version.Version, runtime.GOARCH, runtime.GOOS, runtime.Version()))
|
||||||
|
|
||||||
response, err := http.DefaultClient.Do(request)
|
response, err := http.DefaultClient.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/jmorganca/ollama/format"
|
"github.com/jmorganca/ollama/format"
|
||||||
"github.com/jmorganca/ollama/progressbar"
|
"github.com/jmorganca/ollama/progressbar"
|
||||||
"github.com/jmorganca/ollama/server"
|
"github.com/jmorganca/ollama/server"
|
||||||
|
"github.com/jmorganca/ollama/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateHandler(cmd *cobra.Command, args []string) error {
|
func CreateHandler(cmd *cobra.Command, args []string) error {
|
||||||
|
@ -731,6 +732,7 @@ func NewCLI() *cobra.Command {
|
||||||
CompletionOptions: cobra.CompletionOptions{
|
CompletionOptions: cobra.CompletionOptions{
|
||||||
DisableDefaultCmd: true,
|
DisableDefaultCmd: true,
|
||||||
},
|
},
|
||||||
|
Version: version.Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
cobra.EnableCommandSorting = false
|
cobra.EnableCommandSorting = false
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
|
|
||||||
|
GO_LDFLAGS="-X github.com/jmorganca/ollama/version.Version=$VERSION"
|
||||||
|
|
||||||
# build universal binary
|
# build universal binary
|
||||||
CGO_ENABLED=1 GOARCH=arm64 go build -o dist/ollama-darwin-arm64
|
CGO_ENABLED=1 GOARCH=arm64 go build -ldflags "$GO_LDFLAGS" -o dist/ollama-darwin-arm64
|
||||||
CGO_ENABLED=1 GOARCH=amd64 go build -o dist/ollama-darwin-amd64
|
CGO_ENABLED=1 GOARCH=amd64 go build -ldflags "$GO_LDFLAGS" -o dist/ollama-darwin-amd64
|
||||||
lipo -create -output dist/ollama dist/ollama-darwin-arm64 dist/ollama-darwin-amd64
|
lipo -create -output dist/ollama dist/ollama-darwin-arm64 dist/ollama-darwin-amd64
|
||||||
rm dist/ollama-darwin-amd64 dist/ollama-darwin-arm64
|
rm dist/ollama-darwin-amd64 dist/ollama-darwin-arm64
|
||||||
codesign --deep --force --options=runtime --sign "$APPLE_IDENTITY" --timestamp dist/ollama
|
codesign --deep --force --options=runtime --sign "$APPLE_IDENTITY" --timestamp dist/ollama
|
||||||
|
|
|
@ -94,10 +94,8 @@ func getAuthToken(ctx context.Context, redirData AuthRedirect, regOpts *Registry
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
headers := map[string]string{
|
headers := make(http.Header)
|
||||||
"Authorization": sig,
|
headers.Set("Authorization", sig)
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := makeRequest(ctx, "GET", url, headers, nil, regOpts)
|
resp, err := makeRequest(ctx, "GET", url, headers, nil, regOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("couldn't get token: %q", err)
|
log.Printf("couldn't get token: %q", err)
|
||||||
|
|
|
@ -156,9 +156,9 @@ func doDownload(ctx context.Context, opts downloadOpts, f *FileDownload) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/v2/%s/blobs/%s", opts.mp.Registry, opts.mp.GetNamespaceRepository(), f.Digest)
|
url := fmt.Sprintf("%s/v2/%s/blobs/%s", opts.mp.Registry, opts.mp.GetNamespaceRepository(), f.Digest)
|
||||||
headers := map[string]string{
|
|
||||||
"Range": fmt.Sprintf("bytes=%d-", size),
|
headers := make(http.Header)
|
||||||
}
|
headers.Set("Range", fmt.Sprintf("bytes=%d-", size))
|
||||||
|
|
||||||
resp, err := makeRequest(ctx, "GET", url, headers, nil, opts.regOpts)
|
resp, err := makeRequest(ctx, "GET", url, headers, nil, opts.regOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ import (
|
||||||
"github.com/jmorganca/ollama/llm"
|
"github.com/jmorganca/ollama/llm"
|
||||||
"github.com/jmorganca/ollama/parser"
|
"github.com/jmorganca/ollama/parser"
|
||||||
"github.com/jmorganca/ollama/vector"
|
"github.com/jmorganca/ollama/vector"
|
||||||
|
"github.com/jmorganca/ollama/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MaxRetries = 3
|
const MaxRetries = 3
|
||||||
|
@ -978,15 +980,14 @@ func PushModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
|
||||||
|
|
||||||
fn(api.ProgressResponse{Status: "pushing manifest"})
|
fn(api.ProgressResponse{Status: "pushing manifest"})
|
||||||
url := fmt.Sprintf("%s/v2/%s/manifests/%s", mp.Registry, mp.GetNamespaceRepository(), mp.Tag)
|
url := fmt.Sprintf("%s/v2/%s/manifests/%s", mp.Registry, mp.GetNamespaceRepository(), mp.Tag)
|
||||||
headers := map[string]string{
|
|
||||||
"Content-Type": "application/vnd.docker.distribution.manifest.v2+json",
|
|
||||||
}
|
|
||||||
|
|
||||||
manifestJSON, err := json.Marshal(manifest)
|
manifestJSON, err := json.Marshal(manifest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
headers := make(http.Header)
|
||||||
|
headers.Set("Content-Type", "application/vnd.docker.distribution.manifest.v2+json")
|
||||||
resp, err := makeRequestWithRetry(ctx, "PUT", url, headers, bytes.NewReader(manifestJSON), regOpts)
|
resp, err := makeRequestWithRetry(ctx, "PUT", url, headers, bytes.NewReader(manifestJSON), regOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1072,10 +1073,9 @@ func PullModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
|
||||||
|
|
||||||
func pullModelManifest(ctx context.Context, mp ModelPath, regOpts *RegistryOptions) (*ManifestV2, error) {
|
func pullModelManifest(ctx context.Context, mp ModelPath, regOpts *RegistryOptions) (*ManifestV2, error) {
|
||||||
url := fmt.Sprintf("%s/v2/%s/manifests/%s", mp.Registry, mp.GetNamespaceRepository(), mp.Tag)
|
url := fmt.Sprintf("%s/v2/%s/manifests/%s", mp.Registry, mp.GetNamespaceRepository(), mp.Tag)
|
||||||
headers := map[string]string{
|
|
||||||
"Accept": "application/vnd.docker.distribution.manifest.v2+json",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
headers := make(http.Header)
|
||||||
|
headers.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json")
|
||||||
resp, err := makeRequest(ctx, "GET", url, headers, nil, regOpts)
|
resp, err := makeRequest(ctx, "GET", url, headers, nil, regOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("couldn't get manifest: %v", err)
|
log.Printf("couldn't get manifest: %v", err)
|
||||||
|
@ -1200,11 +1200,10 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
|
||||||
|
|
||||||
sectionReader := io.NewSectionReader(f, int64(completed), chunk)
|
sectionReader := io.NewSectionReader(f, int64(completed), chunk)
|
||||||
|
|
||||||
headers := make(map[string]string)
|
headers := make(http.Header)
|
||||||
headers["Content-Type"] = "application/octet-stream"
|
headers.Set("Content-Type", "application/octet-stream")
|
||||||
headers["Content-Length"] = strconv.Itoa(int(chunk))
|
headers.Set("Content-Length", strconv.Itoa(int(chunk)))
|
||||||
headers["Content-Range"] = fmt.Sprintf("%d-%d", completed, completed+sectionReader.Size()-1)
|
headers.Set("Content-Range", fmt.Sprintf("%d-%d", completed, completed+sectionReader.Size()-1))
|
||||||
|
|
||||||
resp, err := makeRequestWithRetry(ctx, "PATCH", url, headers, sectionReader, regOpts)
|
resp, err := makeRequestWithRetry(ctx, "PATCH", url, headers, sectionReader, regOpts)
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
if err != nil && !errors.Is(err, io.EOF) {
|
||||||
fn(api.ProgressResponse{
|
fn(api.ProgressResponse{
|
||||||
|
@ -1234,9 +1233,9 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
|
||||||
|
|
||||||
url = fmt.Sprintf("%s&digest=%s", url, layer.Digest)
|
url = fmt.Sprintf("%s&digest=%s", url, layer.Digest)
|
||||||
|
|
||||||
headers := make(map[string]string)
|
headers := make(http.Header)
|
||||||
headers["Content-Type"] = "application/octet-stream"
|
headers.Set("Content-Type", "application/octet-stream")
|
||||||
headers["Content-Length"] = "0"
|
headers.Set("Content-Length", "0")
|
||||||
|
|
||||||
// finish the upload
|
// finish the upload
|
||||||
resp, err := makeRequest(ctx, "PUT", url, headers, nil, regOpts)
|
resp, err := makeRequest(ctx, "PUT", url, headers, nil, regOpts)
|
||||||
|
@ -1253,7 +1252,7 @@ func uploadBlobChunked(ctx context.Context, mp ModelPath, url string, layer *Lay
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRequestWithRetry(ctx context.Context, method, url string, headers map[string]string, body io.ReadSeeker, regOpts *RegistryOptions) (*http.Response, error) {
|
func makeRequestWithRetry(ctx context.Context, method, url string, headers http.Header, body io.ReadSeeker, regOpts *RegistryOptions) (*http.Response, error) {
|
||||||
var status string
|
var status string
|
||||||
for try := 0; try < MaxRetries; try++ {
|
for try := 0; try < MaxRetries; try++ {
|
||||||
resp, err := makeRequest(ctx, method, url, headers, body, regOpts)
|
resp, err := makeRequest(ctx, method, url, headers, body, regOpts)
|
||||||
|
@ -1292,7 +1291,7 @@ func makeRequestWithRetry(ctx context.Context, method, url string, headers map[s
|
||||||
return nil, fmt.Errorf("max retry exceeded: %v", status)
|
return nil, fmt.Errorf("max retry exceeded: %v", status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRequest(ctx context.Context, method, url string, headers map[string]string, body io.Reader, regOpts *RegistryOptions) (*http.Response, error) {
|
func makeRequest(ctx context.Context, method, url string, headers http.Header, body io.Reader, regOpts *RegistryOptions) (*http.Response, error) {
|
||||||
if !strings.HasPrefix(url, "http") {
|
if !strings.HasPrefix(url, "http") {
|
||||||
if regOpts.Insecure {
|
if regOpts.Insecure {
|
||||||
url = "http://" + url
|
url = "http://" + url
|
||||||
|
@ -1306,15 +1305,17 @@ func makeRequest(ctx context.Context, method, url string, headers map[string]str
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if headers != nil {
|
||||||
|
req.Header = headers
|
||||||
|
}
|
||||||
|
|
||||||
if regOpts.Token != "" {
|
if regOpts.Token != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+regOpts.Token)
|
req.Header.Set("Authorization", "Bearer "+regOpts.Token)
|
||||||
} else if regOpts.Username != "" && regOpts.Password != "" {
|
} else if regOpts.Username != "" && regOpts.Password != "" {
|
||||||
req.SetBasicAuth(regOpts.Username, regOpts.Password)
|
req.SetBasicAuth(regOpts.Username, regOpts.Password)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range headers {
|
req.Header.Set("User-Agent", fmt.Sprintf("ollama/%s (%s %s) Go/%s", version.Version, runtime.GOARCH, runtime.GOOS, runtime.Version()))
|
||||||
req.Header.Set(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
|
3
version/version.go
Normal file
3
version/version.go
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
package version
|
||||||
|
|
||||||
|
var Version string = "0.0.0"
|
Loading…
Reference in a new issue