config.go 10.1 KB
Newer Older
mashun1's avatar
v1  
mashun1 committed
1
2
3
4
5
package envconfig

import (
	"fmt"
	"log/slog"
xuxzh1's avatar
init  
xuxzh1 committed
6
7
8
	"math"
	"net"
	"net/url"
mashun1's avatar
v1  
mashun1 committed
9
10
11
12
13
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
xuxzh1's avatar
init  
xuxzh1 committed
14
	"time"
mashun1's avatar
v1  
mashun1 committed
15
16
)

xuxzh1's avatar
init  
xuxzh1 committed
17
18
19
20
// Host returns the scheme and host. Host can be configured via the OLLAMA_HOST environment variable.
// Default is scheme "http" and host "127.0.0.1:11434"
func Host() *url.URL {
	defaultPort := "11434"
mashun1's avatar
v1  
mashun1 committed
21

xuxzh1's avatar
init  
xuxzh1 committed
22
23
24
25
26
27
28
29
30
31
	s := strings.TrimSpace(Var("OLLAMA_HOST"))
	scheme, hostport, ok := strings.Cut(s, "://")
	switch {
	case !ok:
		scheme, hostport = "http", s
	case scheme == "http":
		defaultPort = "80"
	case scheme == "https":
		defaultPort = "443"
	}
mashun1's avatar
v1  
mashun1 committed
32

xuxzh1's avatar
update  
xuxzh1 committed
33
	hostport, path, _ := strings.Cut(hostport, "/")
xuxzh1's avatar
init  
xuxzh1 committed
34
35
36
37
38
39
40
41
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		host, port = "127.0.0.1", defaultPort
		if ip := net.ParseIP(strings.Trim(hostport, "[]")); ip != nil {
			host = ip.String()
		} else if hostport != "" {
			host = hostport
		}
mashun1's avatar
v1  
mashun1 committed
42
43
	}

xuxzh1's avatar
init  
xuxzh1 committed
44
45
	if n, err := strconv.ParseInt(port, 10, 32); err != nil || n > 65535 || n < 0 {
		slog.Warn("invalid port, using default", "port", port, "default", defaultPort)
xuxzh1's avatar
update  
xuxzh1 committed
46
		port = defaultPort
mashun1's avatar
v1  
mashun1 committed
47
48
	}

xuxzh1's avatar
init  
xuxzh1 committed
49
50
51
	return &url.URL{
		Scheme: scheme,
		Host:   net.JoinHostPort(host, port),
xuxzh1's avatar
update  
xuxzh1 committed
52
		Path:   path,
xuxzh1's avatar
init  
xuxzh1 committed
53
	}
mashun1's avatar
v1  
mashun1 committed
54
55
}

xuxzh1's avatar
init  
xuxzh1 committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Origins returns a list of allowed origins. Origins can be configured via the OLLAMA_ORIGINS environment variable.
func Origins() (origins []string) {
	if s := Var("OLLAMA_ORIGINS"); s != "" {
		origins = strings.Split(s, ",")
	}

	for _, origin := range []string{"localhost", "127.0.0.1", "0.0.0.0"} {
		origins = append(origins,
			fmt.Sprintf("http://%s", origin),
			fmt.Sprintf("https://%s", origin),
			fmt.Sprintf("http://%s", net.JoinHostPort(origin, "*")),
			fmt.Sprintf("https://%s", net.JoinHostPort(origin, "*")),
		)
	}
mashun1's avatar
v1  
mashun1 committed
70

xuxzh1's avatar
init  
xuxzh1 committed
71
72
73
74
	origins = append(origins,
		"app://*",
		"file://*",
		"tauri://*",
xuxzh1's avatar
update  
xuxzh1 committed
75
		"vscode-webview://*",
xuxzh1's avatar
init  
xuxzh1 committed
76
	)
mashun1's avatar
v1  
mashun1 committed
77

xuxzh1's avatar
init  
xuxzh1 committed
78
	return origins
mashun1's avatar
v1  
mashun1 committed
79
80
}

xuxzh1's avatar
init  
xuxzh1 committed
81
82
83
84
85
// Models returns the path to the models directory. Models directory can be configured via the OLLAMA_MODELS environment variable.
// Default is $HOME/.ollama/models
func Models() string {
	if s := Var("OLLAMA_MODELS"); s != "" {
		return s
mashun1's avatar
v1  
mashun1 committed
86
87
	}

xuxzh1's avatar
init  
xuxzh1 committed
88
89
90
	home, err := os.UserHomeDir()
	if err != nil {
		panic(err)
mashun1's avatar
v1  
mashun1 committed
91
92
	}

xuxzh1's avatar
init  
xuxzh1 committed
93
94
	return filepath.Join(home, ".ollama", "models")
}
mashun1's avatar
v1  
mashun1 committed
95

xuxzh1's avatar
init  
xuxzh1 committed
96
97
98
99
100
101
102
103
104
105
// KeepAlive returns the duration that models stay loaded in memory. KeepAlive can be configured via the OLLAMA_KEEP_ALIVE environment variable.
// Negative values are treated as infinite. Zero is treated as no keep alive.
// Default is 5 minutes.
func KeepAlive() (keepAlive time.Duration) {
	keepAlive = 5 * time.Minute
	if s := Var("OLLAMA_KEEP_ALIVE"); s != "" {
		if d, err := time.ParseDuration(s); err == nil {
			keepAlive = d
		} else if n, err := strconv.ParseInt(s, 10, 64); err == nil {
			keepAlive = time.Duration(n) * time.Second
mashun1's avatar
v1  
mashun1 committed
106
		}
xuxzh1's avatar
init  
xuxzh1 committed
107
	}
mashun1's avatar
v1  
mashun1 committed
108

xuxzh1's avatar
init  
xuxzh1 committed
109
110
111
112
113
114
	if keepAlive < 0 {
		return time.Duration(math.MaxInt64)
	}

	return keepAlive
}
mashun1's avatar
v1  
mashun1 committed
115

xuxzh1's avatar
update  
xuxzh1 committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// LoadTimeout returns the duration for stall detection during model loads. LoadTimeout can be configured via the OLLAMA_LOAD_TIMEOUT environment variable.
// Zero or Negative values are treated as infinite.
// Default is 5 minutes.
func LoadTimeout() (loadTimeout time.Duration) {
	loadTimeout = 5 * time.Minute
	if s := Var("OLLAMA_LOAD_TIMEOUT"); s != "" {
		if d, err := time.ParseDuration(s); err == nil {
			loadTimeout = d
		} else if n, err := strconv.ParseInt(s, 10, 64); err == nil {
			loadTimeout = time.Duration(n) * time.Second
		}
	}

	if loadTimeout <= 0 {
		return time.Duration(math.MaxInt64)
	}

	return loadTimeout
}

xuxzh1's avatar
init  
xuxzh1 committed
136
137
138
139
140
141
func Bool(k string) func() bool {
	return func() bool {
		if s := Var(k); s != "" {
			b, err := strconv.ParseBool(s)
			if err != nil {
				return true
mashun1's avatar
v1  
mashun1 committed
142
			}
xuxzh1's avatar
init  
xuxzh1 committed
143
144

			return b
mashun1's avatar
v1  
mashun1 committed
145
		}
xuxzh1's avatar
init  
xuxzh1 committed
146
147

		return false
mashun1's avatar
v1  
mashun1 committed
148
	}
xuxzh1's avatar
init  
xuxzh1 committed
149
}
mashun1's avatar
v1  
mashun1 committed
150

xuxzh1's avatar
init  
xuxzh1 committed
151
152
153
154
155
156
157
158
159
160
161
162
163
var (
	// Debug enabled additional debug information.
	Debug = Bool("OLLAMA_DEBUG")
	// FlashAttention enables the experimental flash attention feature.
	FlashAttention = Bool("OLLAMA_FLASH_ATTENTION")
	// NoHistory disables readline history.
	NoHistory = Bool("OLLAMA_NOHISTORY")
	// NoPrune disables pruning of model blobs on startup.
	NoPrune = Bool("OLLAMA_NOPRUNE")
	// SchedSpread allows scheduling models across all GPUs.
	SchedSpread = Bool("OLLAMA_SCHED_SPREAD")
	// IntelGPU enables experimental Intel GPU detection.
	IntelGPU = Bool("OLLAMA_INTEL_GPU")
xuxzh1's avatar
update  
xuxzh1 committed
164
165
	// MultiUserCache optimizes prompt caching for multi-user scenarios
	MultiUserCache = Bool("OLLAMA_MULTIUSER_CACHE")
xuxzh1's avatar
init  
xuxzh1 committed
166
)
mashun1's avatar
v1  
mashun1 committed
167

xuxzh1's avatar
init  
xuxzh1 committed
168
169
170
func String(s string) func() string {
	return func() string {
		return Var(s)
mashun1's avatar
v1  
mashun1 committed
171
	}
xuxzh1's avatar
init  
xuxzh1 committed
172
173
174
175
176
}

var (
	LLMLibrary = String("OLLAMA_LLM_LIBRARY")
	TmpDir     = String("OLLAMA_TMPDIR")
mashun1's avatar
v1  
mashun1 committed
177

xuxzh1's avatar
init  
xuxzh1 committed
178
179
180
181
182
183
	CudaVisibleDevices    = String("CUDA_VISIBLE_DEVICES")
	HipVisibleDevices     = String("HIP_VISIBLE_DEVICES")
	RocrVisibleDevices    = String("ROCR_VISIBLE_DEVICES")
	GpuDeviceOrdinal      = String("GPU_DEVICE_ORDINAL")
	HsaOverrideGfxVersion = String("HSA_OVERRIDE_GFX_VERSION")
)
mashun1's avatar
v1  
mashun1 committed
184

xuxzh1's avatar
init  
xuxzh1 committed
185
186
187
188
189
190
191
192
func Uint(key string, defaultValue uint) func() uint {
	return func() uint {
		if s := Var(key); s != "" {
			if n, err := strconv.ParseUint(s, 10, 64); err != nil {
				slog.Warn("invalid environment variable, using default", "key", key, "value", s, "default", defaultValue)
			} else {
				return uint(n)
			}
mashun1's avatar
v1  
mashun1 committed
193
		}
xuxzh1's avatar
init  
xuxzh1 committed
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

		return defaultValue
	}
}

var (
	// NumParallel sets the number of parallel model requests. NumParallel can be configured via the OLLAMA_NUM_PARALLEL environment variable.
	NumParallel = Uint("OLLAMA_NUM_PARALLEL", 0)
	// MaxRunners sets the maximum number of loaded models. MaxRunners can be configured via the OLLAMA_MAX_LOADED_MODELS environment variable.
	MaxRunners = Uint("OLLAMA_MAX_LOADED_MODELS", 0)
	// MaxQueue sets the maximum number of queued requests. MaxQueue can be configured via the OLLAMA_MAX_QUEUE environment variable.
	MaxQueue = Uint("OLLAMA_MAX_QUEUE", 512)
	// MaxVRAM sets a maximum VRAM override in bytes. MaxVRAM can be configured via the OLLAMA_MAX_VRAM environment variable.
	MaxVRAM = Uint("OLLAMA_MAX_VRAM", 0)
)

xuxzh1's avatar
update  
xuxzh1 committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
func Uint64(key string, defaultValue uint64) func() uint64 {
	return func() uint64 {
		if s := Var(key); s != "" {
			if n, err := strconv.ParseUint(s, 10, 64); err != nil {
				slog.Warn("invalid environment variable, using default", "key", key, "value", s, "default", defaultValue)
			} else {
				return n
			}
		}

		return defaultValue
	}
}

// Set aside VRAM per GPU
var GpuOverhead = Uint64("OLLAMA_GPU_OVERHEAD", 0)

xuxzh1's avatar
init  
xuxzh1 committed
227
228
229
230
231
232
233
234
235
236
type EnvVar struct {
	Name        string
	Value       any
	Description string
}

func AsMap() map[string]EnvVar {
	ret := map[string]EnvVar{
		"OLLAMA_DEBUG":             {"OLLAMA_DEBUG", Debug(), "Show additional debug information (e.g. OLLAMA_DEBUG=1)"},
		"OLLAMA_FLASH_ATTENTION":   {"OLLAMA_FLASH_ATTENTION", FlashAttention(), "Enabled flash attention"},
xuxzh1's avatar
update  
xuxzh1 committed
237
		"OLLAMA_GPU_OVERHEAD":      {"OLLAMA_GPU_OVERHEAD", GpuOverhead(), "Reserve a portion of VRAM per GPU (bytes)"},
xuxzh1's avatar
init  
xuxzh1 committed
238
239
240
		"OLLAMA_HOST":              {"OLLAMA_HOST", Host(), "IP Address for the ollama server (default 127.0.0.1:11434)"},
		"OLLAMA_KEEP_ALIVE":        {"OLLAMA_KEEP_ALIVE", KeepAlive(), "The duration that models stay loaded in memory (default \"5m\")"},
		"OLLAMA_LLM_LIBRARY":       {"OLLAMA_LLM_LIBRARY", LLMLibrary(), "Set LLM library to bypass autodetection"},
xuxzh1's avatar
update  
xuxzh1 committed
241
		"OLLAMA_LOAD_TIMEOUT":      {"OLLAMA_LOAD_TIMEOUT", LoadTimeout(), "How long to allow model loads to stall before giving up (default \"5m\")"},
xuxzh1's avatar
init  
xuxzh1 committed
242
243
244
245
246
247
248
249
250
		"OLLAMA_MAX_LOADED_MODELS": {"OLLAMA_MAX_LOADED_MODELS", MaxRunners(), "Maximum number of loaded models per GPU"},
		"OLLAMA_MAX_QUEUE":         {"OLLAMA_MAX_QUEUE", MaxQueue(), "Maximum number of queued requests"},
		"OLLAMA_MODELS":            {"OLLAMA_MODELS", Models(), "The path to the models directory"},
		"OLLAMA_NOHISTORY":         {"OLLAMA_NOHISTORY", NoHistory(), "Do not preserve readline history"},
		"OLLAMA_NOPRUNE":           {"OLLAMA_NOPRUNE", NoPrune(), "Do not prune model blobs on startup"},
		"OLLAMA_NUM_PARALLEL":      {"OLLAMA_NUM_PARALLEL", NumParallel(), "Maximum number of parallel requests"},
		"OLLAMA_ORIGINS":           {"OLLAMA_ORIGINS", Origins(), "A comma separated list of allowed origins"},
		"OLLAMA_SCHED_SPREAD":      {"OLLAMA_SCHED_SPREAD", SchedSpread(), "Always schedule model across all GPUs"},
		"OLLAMA_TMPDIR":            {"OLLAMA_TMPDIR", TmpDir(), "Location for temporary files"},
xuxzh1's avatar
update  
xuxzh1 committed
251
252
253
254
255
256
		"OLLAMA_MULTIUSER_CACHE":   {"OLLAMA_MULTIUSER_CACHE", MultiUserCache(), "Optimize prompt caching for multi-user scenarios"},

		// Informational
		"HTTP_PROXY":  {"HTTP_PROXY", String("HTTP_PROXY")(), "HTTP proxy"},
		"HTTPS_PROXY": {"HTTPS_PROXY", String("HTTPS_PROXY")(), "HTTPS proxy"},
		"NO_PROXY":    {"NO_PROXY", String("NO_PROXY")(), "No proxy"},
xuxzh1's avatar
init  
xuxzh1 committed
257
	}
xuxzh1's avatar
update  
xuxzh1 committed
258
259
260
261
262
263
264
265

	if runtime.GOOS != "windows" {
		// Windows environment variables are case-insensitive so there's no need to duplicate them
		ret["http_proxy"] = EnvVar{"http_proxy", String("http_proxy")(), "HTTP proxy"}
		ret["https_proxy"] = EnvVar{"https_proxy", String("https_proxy")(), "HTTPS proxy"}
		ret["no_proxy"] = EnvVar{"no_proxy", String("no_proxy")(), "No proxy"}
	}

xuxzh1's avatar
init  
xuxzh1 committed
266
267
	if runtime.GOOS != "darwin" {
		ret["CUDA_VISIBLE_DEVICES"] = EnvVar{"CUDA_VISIBLE_DEVICES", CudaVisibleDevices(), "Set which NVIDIA devices are visible"}
xuxzh1's avatar
update  
xuxzh1 committed
268
269
270
		ret["HIP_VISIBLE_DEVICES"] = EnvVar{"HIP_VISIBLE_DEVICES", HipVisibleDevices(), "Set which AMD devices are visible by numeric ID"}
		ret["ROCR_VISIBLE_DEVICES"] = EnvVar{"ROCR_VISIBLE_DEVICES", RocrVisibleDevices(), "Set which AMD devices are visible by UUID or numeric ID"}
		ret["GPU_DEVICE_ORDINAL"] = EnvVar{"GPU_DEVICE_ORDINAL", GpuDeviceOrdinal(), "Set which AMD devices are visible by numeric ID"}
xuxzh1's avatar
init  
xuxzh1 committed
271
272
		ret["HSA_OVERRIDE_GFX_VERSION"] = EnvVar{"HSA_OVERRIDE_GFX_VERSION", HsaOverrideGfxVersion(), "Override the gfx used for all detected AMD GPUs"}
		ret["OLLAMA_INTEL_GPU"] = EnvVar{"OLLAMA_INTEL_GPU", IntelGPU(), "Enable experimental Intel GPU detection"}
mashun1's avatar
v1  
mashun1 committed
273
	}
xuxzh1's avatar
update  
xuxzh1 committed
274

xuxzh1's avatar
init  
xuxzh1 committed
275
276
277
278
279
280
281
282
283
284
	return ret
}

func Values() map[string]string {
	vals := make(map[string]string)
	for k, v := range AsMap() {
		vals[k] = fmt.Sprintf("%v", v.Value)
	}
	return vals
}
mashun1's avatar
v1  
mashun1 committed
285

xuxzh1's avatar
init  
xuxzh1 committed
286
287
288
// Var returns an environment variable stripped of leading and trailing quotes or spaces
func Var(key string) string {
	return strings.Trim(strings.TrimSpace(os.Getenv(key)), "\"'")
mashun1's avatar
v1  
mashun1 committed
289
}
xuxzh1's avatar
update  
xuxzh1 committed
290
291
292
293
294
295
296
297
298

// On windows, we keep the binary at the top directory, but
// other platforms use a "bin" directory, so this returns ".."
func LibRelativeToExe() string {
	if runtime.GOOS == "windows" {
		return "."
	}
	return ".."
}