config.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. package envconfig
  2. import (
  3. "fmt"
  4. "log/slog"
  5. "math"
  6. "net"
  7. "net/url"
  8. "os"
  9. "path/filepath"
  10. "runtime"
  11. "strconv"
  12. "strings"
  13. "time"
  14. )
  15. // Host returns the scheme and host. Host can be configured via the OLLAMA_HOST environment variable.
  16. // Default is scheme "http" and host "127.0.0.1:11434"
  17. func Host() *url.URL {
  18. defaultPort := "11434"
  19. s := strings.TrimSpace(Var("OLLAMA_HOST"))
  20. scheme, hostport, ok := strings.Cut(s, "://")
  21. switch {
  22. case !ok:
  23. scheme, hostport = "http", s
  24. case scheme == "http":
  25. defaultPort = "80"
  26. case scheme == "https":
  27. defaultPort = "443"
  28. }
  29. // trim trailing slashes
  30. hostport = strings.TrimRight(hostport, "/")
  31. host, port, err := net.SplitHostPort(hostport)
  32. if err != nil {
  33. host, port = "127.0.0.1", defaultPort
  34. if ip := net.ParseIP(strings.Trim(hostport, "[]")); ip != nil {
  35. host = ip.String()
  36. } else if hostport != "" {
  37. host = hostport
  38. }
  39. }
  40. if n, err := strconv.ParseInt(port, 10, 32); err != nil || n > 65535 || n < 0 {
  41. slog.Warn("invalid port, using default", "port", port, "default", defaultPort)
  42. return &url.URL{
  43. Scheme: scheme,
  44. Host: net.JoinHostPort(host, defaultPort),
  45. }
  46. }
  47. return &url.URL{
  48. Scheme: scheme,
  49. Host: net.JoinHostPort(host, port),
  50. }
  51. }
  52. // HasCustomOrigins returns true if custom origins are configured. Origins can be configured via the OLLAMA_ORIGINS environment variable.
  53. func HasCustomOrigins() bool {
  54. return Var("OLLAMA_ORIGINS") != ""
  55. }
  56. // Origins returns a list of allowed origins. Origins can be configured via the OLLAMA_ORIGINS environment variable.
  57. func Origins() (origins []string) {
  58. if s := Var("OLLAMA_ORIGINS"); s != "" {
  59. origins = strings.Split(s, ",")
  60. }
  61. for _, origin := range []string{"localhost", "127.0.0.1", "0.0.0.0"} {
  62. origins = append(origins,
  63. fmt.Sprintf("http://%s", origin),
  64. fmt.Sprintf("https://%s", origin),
  65. fmt.Sprintf("http://%s", net.JoinHostPort(origin, "*")),
  66. fmt.Sprintf("https://%s", net.JoinHostPort(origin, "*")),
  67. )
  68. }
  69. origins = append(origins,
  70. "app://*",
  71. "file://*",
  72. "tauri://*",
  73. )
  74. return origins
  75. }
  76. // Models returns the path to the models directory. Models directory can be configured via the OLLAMA_MODELS environment variable.
  77. // Default is $HOME/.ollama/models
  78. func Models() string {
  79. if s := Var("OLLAMA_MODELS"); s != "" {
  80. return s
  81. }
  82. home, err := os.UserHomeDir()
  83. if err != nil {
  84. panic(err)
  85. }
  86. return filepath.Join(home, ".ollama", "models")
  87. }
  88. // KeepAlive returns the duration that models stay loaded in memory. KeepAlive can be configured via the OLLAMA_KEEP_ALIVE environment variable.
  89. // Negative values are treated as infinite. Zero is treated as no keep alive.
  90. // Default is 5 minutes.
  91. func KeepAlive() (keepAlive time.Duration) {
  92. keepAlive = 5 * time.Minute
  93. if s := Var("OLLAMA_KEEP_ALIVE"); s != "" {
  94. if d, err := time.ParseDuration(s); err == nil {
  95. keepAlive = d
  96. } else if n, err := strconv.ParseInt(s, 10, 64); err == nil {
  97. keepAlive = time.Duration(n) * time.Second
  98. }
  99. }
  100. if keepAlive < 0 {
  101. return time.Duration(math.MaxInt64)
  102. }
  103. return keepAlive
  104. }
  105. func Bool(k string) func() bool {
  106. return func() bool {
  107. if s := Var(k); s != "" {
  108. b, err := strconv.ParseBool(s)
  109. if err != nil {
  110. return true
  111. }
  112. return b
  113. }
  114. return false
  115. }
  116. }
  117. var (
  118. // Debug enabled additional debug information.
  119. Debug = Bool("OLLAMA_DEBUG")
  120. // FlashAttention enables the experimental flash attention feature.
  121. FlashAttention = Bool("OLLAMA_FLASH_ATTENTION")
  122. // NoHistory disables readline history.
  123. NoHistory = Bool("OLLAMA_NOHISTORY")
  124. // NoPrune disables pruning of model blobs on startup.
  125. NoPrune = Bool("OLLAMA_NOPRUNE")
  126. // SchedSpread allows scheduling models across all GPUs.
  127. SchedSpread = Bool("OLLAMA_SCHED_SPREAD")
  128. // IntelGPU enables experimental Intel GPU detection.
  129. IntelGPU = Bool("OLLAMA_INTEL_GPU")
  130. )
  131. func String(s string) func() string {
  132. return func() string {
  133. return Var(s)
  134. }
  135. }
  136. var (
  137. LLMLibrary = String("OLLAMA_LLM_LIBRARY")
  138. TmpDir = String("OLLAMA_TMPDIR")
  139. CudaVisibleDevices = String("CUDA_VISIBLE_DEVICES")
  140. HipVisibleDevices = String("HIP_VISIBLE_DEVICES")
  141. RocrVisibleDevices = String("ROCR_VISIBLE_DEVICES")
  142. GpuDeviceOrdinal = String("GPU_DEVICE_ORDINAL")
  143. HsaOverrideGfxVersion = String("HSA_OVERRIDE_GFX_VERSION")
  144. )
  145. func RunnersDir() (p string) {
  146. if p := Var("OLLAMA_RUNNERS_DIR"); p != "" {
  147. return p
  148. }
  149. if runtime.GOOS != "windows" {
  150. return
  151. }
  152. defer func() {
  153. if p == "" {
  154. slog.Error("unable to locate llm runner directory. Set OLLAMA_RUNNERS_DIR to the location of 'ollama_runners'")
  155. }
  156. }()
  157. // On Windows we do not carry the payloads inside the main executable
  158. exe, err := os.Executable()
  159. if err != nil {
  160. return
  161. }
  162. cwd, err := os.Getwd()
  163. if err != nil {
  164. return
  165. }
  166. var paths []string
  167. for _, root := range []string{filepath.Dir(exe), cwd} {
  168. paths = append(paths,
  169. root,
  170. filepath.Join(root, "windows-"+runtime.GOARCH),
  171. filepath.Join(root, "dist", "windows-"+runtime.GOARCH),
  172. )
  173. }
  174. // Try a few variations to improve developer experience when building from source in the local tree
  175. for _, path := range paths {
  176. candidate := filepath.Join(path, "ollama_runners")
  177. if _, err := os.Stat(candidate); err == nil {
  178. p = candidate
  179. break
  180. }
  181. }
  182. return p
  183. }
  184. func Uint(key string, defaultValue uint) func() uint {
  185. return func() uint {
  186. if s := Var(key); s != "" {
  187. if n, err := strconv.ParseUint(s, 10, 64); err != nil {
  188. slog.Warn("invalid environment variable, using default", "key", key, "value", s, "default", defaultValue)
  189. } else {
  190. return uint(n)
  191. }
  192. }
  193. return defaultValue
  194. }
  195. }
  196. var (
  197. // NumParallel sets the number of parallel model requests. NumParallel can be configured via the OLLAMA_NUM_PARALLEL environment variable.
  198. NumParallel = Uint("OLLAMA_NUM_PARALLEL", 0)
  199. // MaxRunners sets the maximum number of loaded models. MaxRunners can be configured via the OLLAMA_MAX_LOADED_MODELS environment variable.
  200. MaxRunners = Uint("OLLAMA_MAX_LOADED_MODELS", 0)
  201. // MaxQueue sets the maximum number of queued requests. MaxQueue can be configured via the OLLAMA_MAX_QUEUE environment variable.
  202. MaxQueue = Uint("OLLAMA_MAX_QUEUE", 512)
  203. // MaxVRAM sets a maximum VRAM override in bytes. MaxVRAM can be configured via the OLLAMA_MAX_VRAM environment variable.
  204. MaxVRAM = Uint("OLLAMA_MAX_VRAM", 0)
  205. )
  206. type EnvVar struct {
  207. Name string
  208. Value any
  209. Description string
  210. }
  211. func AsMap() map[string]EnvVar {
  212. ret := map[string]EnvVar{
  213. "OLLAMA_DEBUG": {"OLLAMA_DEBUG", Debug(), "Show additional debug information (e.g. OLLAMA_DEBUG=1)"},
  214. "OLLAMA_FLASH_ATTENTION": {"OLLAMA_FLASH_ATTENTION", FlashAttention(), "Enabled flash attention"},
  215. "OLLAMA_HOST": {"OLLAMA_HOST", Host(), "IP Address for the ollama server (default 127.0.0.1:11434)"},
  216. "OLLAMA_KEEP_ALIVE": {"OLLAMA_KEEP_ALIVE", KeepAlive(), "The duration that models stay loaded in memory (default \"5m\")"},
  217. "OLLAMA_LLM_LIBRARY": {"OLLAMA_LLM_LIBRARY", LLMLibrary(), "Set LLM library to bypass autodetection"},
  218. "OLLAMA_MAX_LOADED_MODELS": {"OLLAMA_MAX_LOADED_MODELS", MaxRunners(), "Maximum number of loaded models per GPU"},
  219. "OLLAMA_MAX_QUEUE": {"OLLAMA_MAX_QUEUE", MaxQueue(), "Maximum number of queued requests"},
  220. "OLLAMA_MODELS": {"OLLAMA_MODELS", Models(), "The path to the models directory"},
  221. "OLLAMA_NOHISTORY": {"OLLAMA_NOHISTORY", NoHistory(), "Do not preserve readline history"},
  222. "OLLAMA_NOPRUNE": {"OLLAMA_NOPRUNE", NoPrune(), "Do not prune model blobs on startup"},
  223. "OLLAMA_NUM_PARALLEL": {"OLLAMA_NUM_PARALLEL", NumParallel(), "Maximum number of parallel requests"},
  224. "OLLAMA_ORIGINS": {"OLLAMA_ORIGINS", Origins(), "A comma separated list of allowed origins"},
  225. "OLLAMA_RUNNERS_DIR": {"OLLAMA_RUNNERS_DIR", RunnersDir(), "Location for runners"},
  226. "OLLAMA_SCHED_SPREAD": {"OLLAMA_SCHED_SPREAD", SchedSpread(), "Always schedule model across all GPUs"},
  227. "OLLAMA_TMPDIR": {"OLLAMA_TMPDIR", TmpDir(), "Location for temporary files"},
  228. }
  229. if runtime.GOOS != "darwin" {
  230. ret["CUDA_VISIBLE_DEVICES"] = EnvVar{"CUDA_VISIBLE_DEVICES", CudaVisibleDevices(), "Set which NVIDIA devices are visible"}
  231. ret["HIP_VISIBLE_DEVICES"] = EnvVar{"HIP_VISIBLE_DEVICES", HipVisibleDevices(), "Set which AMD devices are visible"}
  232. ret["ROCR_VISIBLE_DEVICES"] = EnvVar{"ROCR_VISIBLE_DEVICES", RocrVisibleDevices(), "Set which AMD devices are visible"}
  233. ret["GPU_DEVICE_ORDINAL"] = EnvVar{"GPU_DEVICE_ORDINAL", GpuDeviceOrdinal(), "Set which AMD devices are visible"}
  234. ret["HSA_OVERRIDE_GFX_VERSION"] = EnvVar{"HSA_OVERRIDE_GFX_VERSION", HsaOverrideGfxVersion(), "Override the gfx used for all detected AMD GPUs"}
  235. ret["OLLAMA_INTEL_GPU"] = EnvVar{"OLLAMA_INTEL_GPU", IntelGPU(), "Enable experimental Intel GPU detection"}
  236. }
  237. return ret
  238. }
  239. func Values() map[string]string {
  240. vals := make(map[string]string)
  241. for k, v := range AsMap() {
  242. vals[k] = fmt.Sprintf("%v", v.Value)
  243. }
  244. return vals
  245. }
  246. // Var returns an environment variable stripped of leading and trailing quotes or spaces
  247. func Var(key string) string {
  248. return strings.Trim(strings.TrimSpace(os.Getenv(key)), "\"'")
  249. }