modelpath.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package server
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/url"
  6. "os"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. )
  11. type ModelPath struct {
  12. ProtocolScheme string
  13. Registry string
  14. Namespace string
  15. Repository string
  16. Tag string
  17. }
  18. const (
  19. DefaultRegistry = "registry.ollama.ai"
  20. DefaultNamespace = "library"
  21. DefaultTag = "latest"
  22. DefaultProtocolScheme = "https"
  23. )
  24. var (
  25. ErrInvalidImageFormat = errors.New("invalid image format")
  26. ErrInvalidProtocol = errors.New("invalid protocol scheme")
  27. ErrInsecureProtocol = errors.New("insecure protocol http")
  28. )
  29. func ParseModelPath(name string) ModelPath {
  30. mp := ModelPath{
  31. ProtocolScheme: DefaultProtocolScheme,
  32. Registry: DefaultRegistry,
  33. Namespace: DefaultNamespace,
  34. Repository: "",
  35. Tag: DefaultTag,
  36. }
  37. before, after, found := strings.Cut(name, "://")
  38. if found {
  39. mp.ProtocolScheme = before
  40. name = after
  41. }
  42. parts := strings.Split(name, string(os.PathSeparator))
  43. switch len(parts) {
  44. case 3:
  45. mp.Registry = parts[0]
  46. mp.Namespace = parts[1]
  47. mp.Repository = parts[2]
  48. case 2:
  49. mp.Namespace = parts[0]
  50. mp.Repository = parts[1]
  51. case 1:
  52. mp.Repository = parts[0]
  53. }
  54. if repo, tag, found := strings.Cut(mp.Repository, ":"); found {
  55. mp.Repository = repo
  56. mp.Tag = tag
  57. }
  58. return mp
  59. }
  60. func (mp ModelPath) GetNamespaceRepository() string {
  61. return fmt.Sprintf("%s/%s", mp.Namespace, mp.Repository)
  62. }
  63. func (mp ModelPath) GetFullTagname() string {
  64. return fmt.Sprintf("%s/%s/%s:%s", mp.Registry, mp.Namespace, mp.Repository, mp.Tag)
  65. }
  66. func (mp ModelPath) GetShortTagname() string {
  67. if mp.Registry == DefaultRegistry {
  68. if mp.Namespace == DefaultNamespace {
  69. return fmt.Sprintf("%s:%s", mp.Repository, mp.Tag)
  70. }
  71. return fmt.Sprintf("%s/%s:%s", mp.Namespace, mp.Repository, mp.Tag)
  72. }
  73. return fmt.Sprintf("%s/%s/%s:%s", mp.Registry, mp.Namespace, mp.Repository, mp.Tag)
  74. }
  75. // modelsDir returns the value of the OLLAMA_MODELS environment variable or the user's home directory if OLLAMA_MODELS is not set.
  76. // The models directory is where Ollama stores its model files and manifests.
  77. func modelsDir() (string, error) {
  78. if models, exists := os.LookupEnv("OLLAMA_MODELS"); exists {
  79. return models, nil
  80. }
  81. home, err := os.UserHomeDir()
  82. if err != nil {
  83. return "", err
  84. }
  85. return filepath.Join(home, ".ollama", "models"), nil
  86. }
  87. // 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.
  88. func (mp ModelPath) GetManifestPath() (string, error) {
  89. dir, err := modelsDir()
  90. if err != nil {
  91. return "", err
  92. }
  93. return filepath.Join(dir, "manifests", mp.Registry, mp.Namespace, mp.Repository, mp.Tag), nil
  94. }
  95. func (mp ModelPath) BaseURL() *url.URL {
  96. return &url.URL{
  97. Scheme: mp.ProtocolScheme,
  98. Host: mp.Registry,
  99. }
  100. }
  101. func GetManifestPath() (string, error) {
  102. dir, err := modelsDir()
  103. if err != nil {
  104. return "", err
  105. }
  106. path := filepath.Join(dir, "manifests")
  107. if err := os.MkdirAll(path, 0o755); err != nil {
  108. return "", err
  109. }
  110. return path, nil
  111. }
  112. func GetBlobsPath(digest string) (string, error) {
  113. dir, err := modelsDir()
  114. if err != nil {
  115. return "", err
  116. }
  117. if runtime.GOOS == "windows" {
  118. digest = strings.ReplaceAll(digest, ":", "-")
  119. }
  120. path := filepath.Join(dir, "blobs", digest)
  121. dirPath := filepath.Dir(path)
  122. if digest == "" {
  123. dirPath = path
  124. }
  125. if err := os.MkdirAll(dirPath, 0o755); err != nil {
  126. return "", err
  127. }
  128. return path, nil
  129. }