modelpath.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package server
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/url"
  6. "os"
  7. "path/filepath"
  8. "regexp"
  9. "strings"
  10. "github.com/ollama/ollama/envconfig"
  11. )
  12. type ModelPath struct {
  13. ProtocolScheme string
  14. Registry string
  15. Namespace string
  16. Repository string
  17. Tag string
  18. }
  19. const (
  20. DefaultRegistry = "registry.ollama.ai"
  21. DefaultNamespace = "library"
  22. DefaultTag = "latest"
  23. DefaultProtocolScheme = "https"
  24. )
  25. var (
  26. ErrInvalidImageFormat = errors.New("invalid image format")
  27. ErrInvalidProtocol = errors.New("invalid protocol scheme")
  28. ErrInsecureProtocol = errors.New("insecure protocol http")
  29. ErrInvalidDigestFormat = errors.New("invalid digest format")
  30. )
  31. func ParseModelPath(name string) ModelPath {
  32. mp := ModelPath{
  33. ProtocolScheme: DefaultProtocolScheme,
  34. Registry: DefaultRegistry,
  35. Namespace: DefaultNamespace,
  36. Repository: "",
  37. Tag: DefaultTag,
  38. }
  39. before, after, found := strings.Cut(name, "://")
  40. if found {
  41. mp.ProtocolScheme = before
  42. name = after
  43. }
  44. name = strings.ReplaceAll(name, string(os.PathSeparator), "/")
  45. parts := strings.Split(name, "/")
  46. switch len(parts) {
  47. case 3:
  48. mp.Registry = parts[0]
  49. mp.Namespace = parts[1]
  50. mp.Repository = parts[2]
  51. case 2:
  52. mp.Namespace = parts[0]
  53. mp.Repository = parts[1]
  54. case 1:
  55. mp.Repository = parts[0]
  56. }
  57. if repo, tag, found := strings.Cut(mp.Repository, ":"); found {
  58. mp.Repository = repo
  59. mp.Tag = tag
  60. }
  61. return mp
  62. }
  63. var errModelPathInvalid = errors.New("invalid model path")
  64. func (mp ModelPath) GetNamespaceRepository() string {
  65. return fmt.Sprintf("%s/%s", mp.Namespace, mp.Repository)
  66. }
  67. func (mp ModelPath) GetFullTagname() string {
  68. return fmt.Sprintf("%s/%s/%s:%s", mp.Registry, mp.Namespace, mp.Repository, mp.Tag)
  69. }
  70. func (mp ModelPath) GetShortTagname() string {
  71. if mp.Registry == DefaultRegistry {
  72. if mp.Namespace == DefaultNamespace {
  73. return fmt.Sprintf("%s:%s", mp.Repository, mp.Tag)
  74. }
  75. return fmt.Sprintf("%s/%s:%s", mp.Namespace, mp.Repository, mp.Tag)
  76. }
  77. return fmt.Sprintf("%s/%s/%s:%s", mp.Registry, mp.Namespace, mp.Repository, mp.Tag)
  78. }
  79. // 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.
  80. func (mp ModelPath) GetManifestPath() (string, error) {
  81. if p := filepath.Join(mp.Registry, mp.Namespace, mp.Repository, mp.Tag); filepath.IsLocal(p) {
  82. return filepath.Join(envconfig.Models(), "manifests", p), nil
  83. }
  84. return "", errModelPathInvalid
  85. }
  86. func (mp ModelPath) BaseURL() *url.URL {
  87. return &url.URL{
  88. Scheme: mp.ProtocolScheme,
  89. Host: mp.Registry,
  90. }
  91. }
  92. func GetManifestPath() (string, error) {
  93. path := filepath.Join(envconfig.Models(), "manifests")
  94. if err := os.MkdirAll(path, 0o755); err != nil {
  95. return "", err
  96. }
  97. return path, nil
  98. }
  99. func GetBlobsPath(digest string) (string, error) {
  100. // only accept actual sha256 digests
  101. pattern := "^sha256[:-][0-9a-fA-F]{64}$"
  102. re := regexp.MustCompile(pattern)
  103. if digest != "" && !re.MatchString(digest) {
  104. return "", ErrInvalidDigestFormat
  105. }
  106. digest = strings.ReplaceAll(digest, ":", "-")
  107. path := filepath.Join(envconfig.Models(), "blobs", digest)
  108. dirPath := filepath.Dir(path)
  109. if digest == "" {
  110. dirPath = path
  111. }
  112. if err := os.MkdirAll(dirPath, 0o755); err != nil {
  113. return "", err
  114. }
  115. return path, nil
  116. }