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:
parent
e5d1ce4dde
commit
5c3491f425
4 changed files with 37 additions and 21 deletions
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue