allow for a configurable ollama model storage directory (#897)

* allow for a configurable ollama models directory

- set OLLAMA_MODELS in the environment that ollama is running in to change where model files are stored
- update docs

Co-Authored-By: Jeffrey Morgan <jmorganca@gmail.com>
Co-Authored-By: Jay Nakrani <dhananjaynakrani@gmail.com>
Co-Authored-By: Akhil Acharya <akhilcacharya@gmail.com>
Co-Authored-By: Sasha Devol <sasha.devol@protonmail.com>
This commit is contained in:
Bruce MacDonald 2023-10-27 10:19:59 -04:00 committed by GitHub
parent e5d1ce4dde
commit 5c3491f425
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 21 deletions

View file

@ -18,10 +18,6 @@ import (
"github.com/jmorganca/ollama/version" "github.com/jmorganca/ollama/version"
) )
const DefaultHost = "127.0.0.1:11434"
var envHost = os.Getenv("OLLAMA_HOST")
type Client struct { type Client struct {
base *url.URL base *url.URL
http http.Client http http.Client

View file

@ -60,3 +60,7 @@ systemctl restart ollama
- macOS: Raw model data is stored under `~/.ollama/models`. - macOS: Raw model data is stored under `~/.ollama/models`.
- Linux: Raw model data is stored under `/usr/share/ollama/.ollama/models` - Linux: Raw model data is stored under `/usr/share/ollama/.ollama/models`
### How can I change where Ollama stores models?
To modify where models are stored, you can use the `OLLAMA_MODELS` environment variable. Note that on Linux this means defining `OLLAMA_MODELS` in a drop-in `/etc/systemd/system/ollama.service.d` service file, reloading systemd, and restarting the ollama service.

View file

@ -131,7 +131,7 @@ func (m *ManifestV2) GetTotalSize() (total int64) {
} }
func GetManifest(mp ModelPath) (*ManifestV2, string, error) { func GetManifest(mp ModelPath) (*ManifestV2, string, error) {
fp, err := mp.GetManifestPath(false) fp, err := mp.GetManifestPath()
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -595,10 +595,13 @@ func CreateManifest(name string, cfg *LayerReader, layers []*Layer) error {
return err return err
} }
fp, err := mp.GetManifestPath(true) fp, err := mp.GetManifestPath()
if err != nil { if err != nil {
return err return err
} }
if err := os.MkdirAll(filepath.Dir(fp), 0o755); err != nil {
return err
}
return os.WriteFile(fp, manifestJSON, 0o644) return os.WriteFile(fp, manifestJSON, 0o644)
} }
@ -710,16 +713,19 @@ func CreateLayer(f io.ReadSeeker) (*LayerReader, error) {
func CopyModel(src, dest string) error { func CopyModel(src, dest string) error {
srcModelPath := ParseModelPath(src) srcModelPath := ParseModelPath(src)
srcPath, err := srcModelPath.GetManifestPath(false) srcPath, err := srcModelPath.GetManifestPath()
if err != nil { if err != nil {
return err return err
} }
destModelPath := ParseModelPath(dest) destModelPath := ParseModelPath(dest)
destPath, err := destModelPath.GetManifestPath(true) destPath, err := destModelPath.GetManifestPath()
if err != nil { if err != nil {
return err return err
} }
if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
return err
}
// copy the file // copy the file
input, err := os.ReadFile(srcPath) input, err := os.ReadFile(srcPath)
@ -882,7 +888,7 @@ func DeleteModel(name string) error {
return err return err
} }
fp, err := mp.GetManifestPath(false) fp, err := mp.GetManifestPath()
if err != nil { if err != nil {
return err return err
} }
@ -1121,10 +1127,13 @@ func PullModel(ctx context.Context, name string, regOpts *RegistryOptions, fn fu
return err return err
} }
fp, err := mp.GetManifestPath(true) fp, err := mp.GetManifestPath()
if err != nil { if err != nil {
return err return err
} }
if err := os.MkdirAll(filepath.Dir(fp), 0o755); err != nil {
return err
}
err = os.WriteFile(fp, manifestJSON, 0o644) err = os.WriteFile(fp, manifestJSON, 0o644)
if err != nil { if err != nil {

View file

@ -85,20 +85,27 @@ func (mp ModelPath) GetShortTagname() string {
return fmt.Sprintf("%s/%s/%s:%s", mp.Registry, mp.Namespace, mp.Repository, mp.Tag) return fmt.Sprintf("%s/%s/%s:%s", mp.Registry, mp.Namespace, mp.Repository, mp.Tag)
} }
func (mp ModelPath) GetManifestPath(createDir bool) (string, error) { // modelsDir returns the value of the OLLAMA_MODELS environment variable or the user's home directory if OLLAMA_MODELS is not set.
// The models directory is where Ollama stores its model files and manifests.
func modelsDir() (string, error) {
if models, exists := os.LookupEnv("OLLAMA_MODELS"); exists {
return models, nil
}
home, err := os.UserHomeDir() home, err := os.UserHomeDir()
if err != nil { if err != nil {
return "", err return "", err
} }
return filepath.Join(home, ".ollama", "models"), nil
}
path := filepath.Join(home, ".ollama", "models", "manifests", mp.Registry, mp.Namespace, mp.Repository, mp.Tag) // GetManifestPath returns the path to the manifest file for the given model path, it is up to the caller to create the directory if it does not exist.
if createDir { func (mp ModelPath) GetManifestPath() (string, error) {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { dir, err := modelsDir()
return "", err if err != nil {
} return "", err
} }
return path, nil return filepath.Join(dir, "manifests", mp.Registry, mp.Namespace, mp.Repository, mp.Tag), nil
} }
func (mp ModelPath) BaseURL() *url.URL { func (mp ModelPath) BaseURL() *url.URL {
@ -109,12 +116,12 @@ func (mp ModelPath) BaseURL() *url.URL {
} }
func GetManifestPath() (string, error) { func GetManifestPath() (string, error) {
home, err := os.UserHomeDir() dir, err := modelsDir()
if err != nil { if err != nil {
return "", err return "", err
} }
path := filepath.Join(home, ".ollama", "models", "manifests") path := filepath.Join(dir, "manifests")
if err := os.MkdirAll(path, 0o755); err != nil { if err := os.MkdirAll(path, 0o755); err != nil {
return "", err return "", err
} }
@ -123,7 +130,7 @@ func GetManifestPath() (string, error) {
} }
func GetBlobsPath(digest string) (string, error) { func GetBlobsPath(digest string) (string, error) {
home, err := os.UserHomeDir() dir, err := modelsDir()
if err != nil { if err != nil {
return "", err return "", err
} }
@ -132,7 +139,7 @@ func GetBlobsPath(digest string) (string, error) {
digest = strings.ReplaceAll(digest, ":", "-") digest = strings.ReplaceAll(digest, ":", "-")
} }
path := filepath.Join(home, ".ollama", "models", "blobs", digest) path := filepath.Join(dir, "blobs", digest)
dirPath := filepath.Dir(path) dirPath := filepath.Dir(path)
if digest == "" { if digest == "" {
dirPath = path dirPath = path