cmd.go 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  1. package cmd
  2. import (
  3. "archive/zip"
  4. "bufio"
  5. "bytes"
  6. "context"
  7. "crypto/ed25519"
  8. "crypto/rand"
  9. "crypto/sha256"
  10. "encoding/pem"
  11. "errors"
  12. "fmt"
  13. "io"
  14. "log"
  15. "math"
  16. "net"
  17. "net/http"
  18. "os"
  19. "os/signal"
  20. "path/filepath"
  21. "regexp"
  22. "runtime"
  23. "strconv"
  24. "strings"
  25. "sync/atomic"
  26. "syscall"
  27. "time"
  28. "github.com/containerd/console"
  29. "github.com/mattn/go-runewidth"
  30. "github.com/olekukonko/tablewriter"
  31. "github.com/spf13/cobra"
  32. "golang.org/x/crypto/ssh"
  33. "golang.org/x/term"
  34. "github.com/ollama/ollama/api"
  35. "github.com/ollama/ollama/auth"
  36. "github.com/ollama/ollama/envconfig"
  37. "github.com/ollama/ollama/format"
  38. "github.com/ollama/ollama/parser"
  39. "github.com/ollama/ollama/progress"
  40. "github.com/ollama/ollama/server"
  41. "github.com/ollama/ollama/types/errtypes"
  42. "github.com/ollama/ollama/types/model"
  43. "github.com/ollama/ollama/version"
  44. )
  45. func CreateHandler(cmd *cobra.Command, args []string) error {
  46. filename, _ := cmd.Flags().GetString("file")
  47. filename, err := filepath.Abs(filename)
  48. if err != nil {
  49. return err
  50. }
  51. client, err := api.ClientFromEnvironment()
  52. if err != nil {
  53. return err
  54. }
  55. p := progress.NewProgress(os.Stderr)
  56. defer p.Stop()
  57. f, err := os.Open(filename)
  58. if err != nil {
  59. return err
  60. }
  61. defer f.Close()
  62. modelfile, err := parser.ParseFile(f)
  63. if err != nil {
  64. return err
  65. }
  66. home, err := os.UserHomeDir()
  67. if err != nil {
  68. return err
  69. }
  70. status := "transferring model data"
  71. spinner := progress.NewSpinner(status)
  72. p.Add(status, spinner)
  73. defer p.Stop()
  74. for i := range modelfile.Commands {
  75. switch modelfile.Commands[i].Name {
  76. case "model", "adapter":
  77. path := modelfile.Commands[i].Args
  78. if path == "~" {
  79. path = home
  80. } else if strings.HasPrefix(path, "~/") {
  81. path = filepath.Join(home, path[2:])
  82. }
  83. if !filepath.IsAbs(path) {
  84. path = filepath.Join(filepath.Dir(filename), path)
  85. }
  86. fi, err := os.Stat(path)
  87. if errors.Is(err, os.ErrNotExist) && modelfile.Commands[i].Name == "model" {
  88. continue
  89. } else if err != nil {
  90. return err
  91. }
  92. if fi.IsDir() {
  93. // this is likely a safetensors or pytorch directory
  94. // TODO make this work w/ adapters
  95. tempfile, err := tempZipFiles(path)
  96. if err != nil {
  97. return err
  98. }
  99. defer os.RemoveAll(tempfile)
  100. path = tempfile
  101. }
  102. digest, err := createBlob(cmd, client, path, spinner)
  103. if err != nil {
  104. return err
  105. }
  106. modelfile.Commands[i].Args = "@" + digest
  107. }
  108. }
  109. bars := make(map[string]*progress.Bar)
  110. fn := func(resp api.ProgressResponse) error {
  111. if resp.Digest != "" {
  112. spinner.Stop()
  113. bar, ok := bars[resp.Digest]
  114. if !ok {
  115. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  116. bars[resp.Digest] = bar
  117. p.Add(resp.Digest, bar)
  118. }
  119. bar.Set(resp.Completed)
  120. } else if status != resp.Status {
  121. spinner.Stop()
  122. status = resp.Status
  123. spinner = progress.NewSpinner(status)
  124. p.Add(status, spinner)
  125. }
  126. return nil
  127. }
  128. quantize, _ := cmd.Flags().GetString("quantize")
  129. request := api.CreateRequest{Name: args[0], Modelfile: modelfile.String(), Quantize: quantize}
  130. if err := client.Create(cmd.Context(), &request, fn); err != nil {
  131. return err
  132. }
  133. return nil
  134. }
  135. func tempZipFiles(path string) (string, error) {
  136. tempfile, err := os.CreateTemp("", "ollama-tf")
  137. if err != nil {
  138. return "", err
  139. }
  140. defer tempfile.Close()
  141. detectContentType := func(path string) (string, error) {
  142. f, err := os.Open(path)
  143. if err != nil {
  144. return "", err
  145. }
  146. defer f.Close()
  147. var b bytes.Buffer
  148. b.Grow(512)
  149. if _, err := io.CopyN(&b, f, 512); err != nil && !errors.Is(err, io.EOF) {
  150. return "", err
  151. }
  152. contentType, _, _ := strings.Cut(http.DetectContentType(b.Bytes()), ";")
  153. return contentType, nil
  154. }
  155. glob := func(pattern, contentType string) ([]string, error) {
  156. matches, err := filepath.Glob(pattern)
  157. if err != nil {
  158. return nil, err
  159. }
  160. for _, safetensor := range matches {
  161. if ct, err := detectContentType(safetensor); err != nil {
  162. return nil, err
  163. } else if ct != contentType {
  164. return nil, fmt.Errorf("invalid content type: expected %s for %s", ct, safetensor)
  165. }
  166. }
  167. return matches, nil
  168. }
  169. var files []string
  170. if st, _ := glob(filepath.Join(path, "model*.safetensors"), "application/octet-stream"); len(st) > 0 {
  171. // safetensors files might be unresolved git lfs references; skip if they are
  172. // covers model-x-of-y.safetensors, model.fp32-x-of-y.safetensors, model.safetensors
  173. files = append(files, st...)
  174. } else if st, _ := glob(filepath.Join(path, "adapters.safetensors"), "application/octet-stream"); len(st) > 0 {
  175. // covers adapters.safetensors
  176. files = append(files, st...)
  177. } else if st, _ := glob(filepath.Join(path, "adapter_model.safetensors"), "application/octet-stream"); len(st) > 0 {
  178. // covers adapter_model.safetensors
  179. files = append(files, st...)
  180. } else if pt, _ := glob(filepath.Join(path, "pytorch_model*.bin"), "application/zip"); len(pt) > 0 {
  181. // pytorch files might also be unresolved git lfs references; skip if they are
  182. // covers pytorch_model-x-of-y.bin, pytorch_model.fp32-x-of-y.bin, pytorch_model.bin
  183. files = append(files, pt...)
  184. } else if pt, _ := glob(filepath.Join(path, "consolidated*.pth"), "application/zip"); len(pt) > 0 {
  185. // pytorch files might also be unresolved git lfs references; skip if they are
  186. // covers consolidated.x.pth, consolidated.pth
  187. files = append(files, pt...)
  188. } else {
  189. return "", errors.New("no safetensors or torch files found")
  190. }
  191. // add configuration files, json files are detected as text/plain
  192. js, err := glob(filepath.Join(path, "*.json"), "text/plain")
  193. if err != nil {
  194. return "", err
  195. }
  196. files = append(files, js...)
  197. // bert models require a nested config.json
  198. // TODO(mxyng): merge this with the glob above
  199. js, err = glob(filepath.Join(path, "**/*.json"), "text/plain")
  200. if err != nil {
  201. return "", err
  202. }
  203. files = append(files, js...)
  204. if tks, _ := glob(filepath.Join(path, "tokenizer.model"), "application/octet-stream"); len(tks) > 0 {
  205. // add tokenizer.model if it exists, tokenizer.json is automatically picked up by the previous glob
  206. // tokenizer.model might be a unresolved git lfs reference; error if it is
  207. files = append(files, tks...)
  208. } else if tks, _ := glob(filepath.Join(path, "**/tokenizer.model"), "text/plain"); len(tks) > 0 {
  209. // some times tokenizer.model is in a subdirectory (e.g. meta-llama/Meta-Llama-3-8B)
  210. files = append(files, tks...)
  211. }
  212. zipfile := zip.NewWriter(tempfile)
  213. defer zipfile.Close()
  214. for _, file := range files {
  215. f, err := os.Open(file)
  216. if err != nil {
  217. return "", err
  218. }
  219. defer f.Close()
  220. fi, err := f.Stat()
  221. if err != nil {
  222. return "", err
  223. }
  224. zfi, err := zip.FileInfoHeader(fi)
  225. if err != nil {
  226. return "", err
  227. }
  228. zfi.Name, err = filepath.Rel(path, file)
  229. if err != nil {
  230. return "", err
  231. }
  232. zf, err := zipfile.CreateHeader(zfi)
  233. if err != nil {
  234. return "", err
  235. }
  236. if _, err := io.Copy(zf, f); err != nil {
  237. return "", err
  238. }
  239. }
  240. return tempfile.Name(), nil
  241. }
  242. func createBlob(cmd *cobra.Command, client *api.Client, path string, spinner *progress.Spinner) (string, error) {
  243. bin, err := os.Open(path)
  244. if err != nil {
  245. return "", err
  246. }
  247. defer bin.Close()
  248. // Get file info to retrieve the size
  249. fileInfo, err := bin.Stat()
  250. if err != nil {
  251. return "", err
  252. }
  253. fileSize := fileInfo.Size()
  254. hash := sha256.New()
  255. if _, err := io.Copy(hash, bin); err != nil {
  256. return "", err
  257. }
  258. if _, err := bin.Seek(0, io.SeekStart); err != nil {
  259. return "", err
  260. }
  261. var pw progressWriter
  262. status := "transferring model data 0%"
  263. spinner.SetMessage(status)
  264. done := make(chan struct{})
  265. defer close(done)
  266. go func() {
  267. ticker := time.NewTicker(60 * time.Millisecond)
  268. defer ticker.Stop()
  269. for {
  270. select {
  271. case <-ticker.C:
  272. spinner.SetMessage(fmt.Sprintf("transferring model data %d%%", int(100*pw.n.Load()/fileSize)))
  273. case <-done:
  274. spinner.SetMessage("transferring model data 100%")
  275. return
  276. }
  277. }
  278. }()
  279. digest := fmt.Sprintf("sha256:%x", hash.Sum(nil))
  280. if err = client.CreateBlob(cmd.Context(), digest, io.TeeReader(bin, &pw)); err != nil {
  281. return "", err
  282. }
  283. return digest, nil
  284. }
  285. type progressWriter struct {
  286. n atomic.Int64
  287. }
  288. func (w *progressWriter) Write(p []byte) (n int, err error) {
  289. w.n.Add(int64(len(p)))
  290. return len(p), nil
  291. }
  292. func loadOrUnloadModel(cmd *cobra.Command, opts *runOptions) error {
  293. p := progress.NewProgress(os.Stderr)
  294. defer p.StopAndClear()
  295. spinner := progress.NewSpinner("")
  296. p.Add("", spinner)
  297. client, err := api.ClientFromEnvironment()
  298. if err != nil {
  299. return err
  300. }
  301. req := &api.GenerateRequest{
  302. Model: opts.Model,
  303. KeepAlive: opts.KeepAlive,
  304. }
  305. return client.Generate(cmd.Context(), req, func(api.GenerateResponse) error { return nil })
  306. }
  307. func StopHandler(cmd *cobra.Command, args []string) error {
  308. opts := &runOptions{
  309. Model: args[0],
  310. KeepAlive: &api.Duration{Duration: 0},
  311. }
  312. if err := loadOrUnloadModel(cmd, opts); err != nil {
  313. if strings.Contains(err.Error(), "not found") {
  314. return fmt.Errorf("couldn't find model \"%s\" to stop", args[0])
  315. }
  316. }
  317. return nil
  318. }
  319. func RunHandler(cmd *cobra.Command, args []string) error {
  320. interactive := true
  321. opts := runOptions{
  322. Model: args[0],
  323. WordWrap: os.Getenv("TERM") == "xterm-256color",
  324. Options: map[string]interface{}{},
  325. }
  326. format, err := cmd.Flags().GetString("format")
  327. if err != nil {
  328. return err
  329. }
  330. opts.Format = format
  331. keepAlive, err := cmd.Flags().GetString("keepalive")
  332. if err != nil {
  333. return err
  334. }
  335. if keepAlive != "" {
  336. d, err := time.ParseDuration(keepAlive)
  337. if err != nil {
  338. return err
  339. }
  340. opts.KeepAlive = &api.Duration{Duration: d}
  341. }
  342. prompts := args[1:]
  343. // prepend stdin to the prompt if provided
  344. if !term.IsTerminal(int(os.Stdin.Fd())) {
  345. in, err := io.ReadAll(os.Stdin)
  346. if err != nil {
  347. return err
  348. }
  349. prompts = append([]string{string(in)}, prompts...)
  350. opts.WordWrap = false
  351. interactive = false
  352. }
  353. opts.Prompt = strings.Join(prompts, " ")
  354. if len(prompts) > 0 {
  355. interactive = false
  356. }
  357. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  358. if err != nil {
  359. return err
  360. }
  361. opts.WordWrap = !nowrap
  362. // Fill out the rest of the options based on information about the
  363. // model.
  364. client, err := api.ClientFromEnvironment()
  365. if err != nil {
  366. return err
  367. }
  368. name := args[0]
  369. info, err := func() (*api.ShowResponse, error) {
  370. showReq := &api.ShowRequest{Name: name}
  371. info, err := client.Show(cmd.Context(), showReq)
  372. var se api.StatusError
  373. if errors.As(err, &se) && se.StatusCode == http.StatusNotFound {
  374. if err := PullHandler(cmd, []string{name}); err != nil {
  375. return nil, err
  376. }
  377. return client.Show(cmd.Context(), &api.ShowRequest{Name: name})
  378. }
  379. return info, err
  380. }()
  381. if err != nil {
  382. return err
  383. }
  384. opts.MultiModal = len(info.ProjectorInfo) != 0
  385. opts.ParentModel = info.Details.ParentModel
  386. if interactive {
  387. if err := loadOrUnloadModel(cmd, &opts); err != nil {
  388. return err
  389. }
  390. for _, msg := range info.Messages {
  391. switch msg.Role {
  392. case "user":
  393. fmt.Printf(">>> %s\n", msg.Content)
  394. case "assistant":
  395. state := &displayResponseState{}
  396. displayResponse(msg.Content, opts.WordWrap, state)
  397. fmt.Println()
  398. fmt.Println()
  399. }
  400. }
  401. return generateInteractive(cmd, opts)
  402. }
  403. return generate(cmd, opts)
  404. }
  405. func errFromUnknownKey(unknownKeyErr error) error {
  406. // find SSH public key in the error message
  407. sshKeyPattern := `ssh-\w+ [^\s"]+`
  408. re := regexp.MustCompile(sshKeyPattern)
  409. matches := re.FindStringSubmatch(unknownKeyErr.Error())
  410. if len(matches) > 0 {
  411. serverPubKey := matches[0]
  412. localPubKey, err := auth.GetPublicKey()
  413. if err != nil {
  414. return unknownKeyErr
  415. }
  416. if runtime.GOOS == "linux" && serverPubKey != localPubKey {
  417. // try the ollama service public key
  418. svcPubKey, err := os.ReadFile("/usr/share/ollama/.ollama/id_ed25519.pub")
  419. if err != nil {
  420. return unknownKeyErr
  421. }
  422. localPubKey = strings.TrimSpace(string(svcPubKey))
  423. }
  424. // check if the returned public key matches the local public key, this prevents adding a remote key to the user's account
  425. if serverPubKey != localPubKey {
  426. return unknownKeyErr
  427. }
  428. var msg strings.Builder
  429. msg.WriteString(unknownKeyErr.Error())
  430. msg.WriteString("\n\nYour ollama key is:\n")
  431. msg.WriteString(localPubKey)
  432. msg.WriteString("\nAdd your key at:\n")
  433. msg.WriteString("https://ollama.com/settings/keys")
  434. return errors.New(msg.String())
  435. }
  436. return unknownKeyErr
  437. }
  438. func PushHandler(cmd *cobra.Command, args []string) error {
  439. client, err := api.ClientFromEnvironment()
  440. if err != nil {
  441. return err
  442. }
  443. insecure, err := cmd.Flags().GetBool("insecure")
  444. if err != nil {
  445. return err
  446. }
  447. p := progress.NewProgress(os.Stderr)
  448. defer p.Stop()
  449. bars := make(map[string]*progress.Bar)
  450. var status string
  451. var spinner *progress.Spinner
  452. fn := func(resp api.ProgressResponse) error {
  453. if resp.Digest != "" {
  454. if spinner != nil {
  455. spinner.Stop()
  456. }
  457. bar, ok := bars[resp.Digest]
  458. if !ok {
  459. bar = progress.NewBar(fmt.Sprintf("pushing %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  460. bars[resp.Digest] = bar
  461. p.Add(resp.Digest, bar)
  462. }
  463. bar.Set(resp.Completed)
  464. } else if status != resp.Status {
  465. if spinner != nil {
  466. spinner.Stop()
  467. }
  468. status = resp.Status
  469. spinner = progress.NewSpinner(status)
  470. p.Add(status, spinner)
  471. }
  472. return nil
  473. }
  474. request := api.PushRequest{Name: args[0], Insecure: insecure}
  475. if err := client.Push(cmd.Context(), &request, fn); err != nil {
  476. if spinner != nil {
  477. spinner.Stop()
  478. }
  479. if strings.Contains(err.Error(), "access denied") {
  480. return errors.New("you are not authorized to push to this namespace, create the model under a namespace you own")
  481. }
  482. host := model.ParseName(args[0]).Host
  483. isOllamaHost := strings.HasSuffix(host, ".ollama.ai") || strings.HasSuffix(host, ".ollama.com")
  484. if strings.Contains(err.Error(), errtypes.UnknownOllamaKeyErrMsg) && isOllamaHost {
  485. // the user has not added their ollama key to ollama.com
  486. // re-throw an error with a more user-friendly message
  487. return errFromUnknownKey(err)
  488. }
  489. return err
  490. }
  491. spinner.Stop()
  492. return nil
  493. }
  494. func ListHandler(cmd *cobra.Command, args []string) error {
  495. client, err := api.ClientFromEnvironment()
  496. if err != nil {
  497. return err
  498. }
  499. models, err := client.List(cmd.Context())
  500. if err != nil {
  501. return err
  502. }
  503. var data [][]string
  504. for _, m := range models.Models {
  505. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  506. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), format.HumanTime(m.ModifiedAt, "Never")})
  507. }
  508. }
  509. table := tablewriter.NewWriter(os.Stdout)
  510. table.SetHeader([]string{"NAME", "ID", "SIZE", "MODIFIED"})
  511. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  512. table.SetAlignment(tablewriter.ALIGN_LEFT)
  513. table.SetHeaderLine(false)
  514. table.SetBorder(false)
  515. table.SetNoWhiteSpace(true)
  516. table.SetTablePadding(" ")
  517. table.AppendBulk(data)
  518. table.Render()
  519. return nil
  520. }
  521. func ListRunningHandler(cmd *cobra.Command, args []string) error {
  522. client, err := api.ClientFromEnvironment()
  523. if err != nil {
  524. return err
  525. }
  526. models, err := client.ListRunning(cmd.Context())
  527. if err != nil {
  528. return err
  529. }
  530. var data [][]string
  531. for _, m := range models.Models {
  532. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  533. var procStr string
  534. switch {
  535. case m.SizeVRAM == 0:
  536. procStr = "100% CPU"
  537. case m.SizeVRAM == m.Size:
  538. procStr = "100% GPU"
  539. case m.SizeVRAM > m.Size || m.Size == 0:
  540. procStr = "Unknown"
  541. default:
  542. sizeCPU := m.Size - m.SizeVRAM
  543. cpuPercent := math.Round(float64(sizeCPU) / float64(m.Size) * 100)
  544. procStr = fmt.Sprintf("%d%%/%d%% CPU/GPU", int(cpuPercent), int(100-cpuPercent))
  545. }
  546. var until string
  547. delta := time.Since(m.ExpiresAt)
  548. if delta > 0 {
  549. until = "Stopping..."
  550. } else {
  551. until = format.HumanTime(m.ExpiresAt, "Never")
  552. }
  553. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), procStr, until})
  554. }
  555. }
  556. table := tablewriter.NewWriter(os.Stdout)
  557. table.SetHeader([]string{"NAME", "ID", "SIZE", "PROCESSOR", "UNTIL"})
  558. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  559. table.SetAlignment(tablewriter.ALIGN_LEFT)
  560. table.SetHeaderLine(false)
  561. table.SetBorder(false)
  562. table.SetNoWhiteSpace(true)
  563. table.SetTablePadding(" ")
  564. table.AppendBulk(data)
  565. table.Render()
  566. return nil
  567. }
  568. func DeleteHandler(cmd *cobra.Command, args []string) error {
  569. client, err := api.ClientFromEnvironment()
  570. if err != nil {
  571. return err
  572. }
  573. for _, name := range args {
  574. req := api.DeleteRequest{Name: name}
  575. if err := client.Delete(cmd.Context(), &req); err != nil {
  576. return err
  577. }
  578. fmt.Printf("deleted '%s'\n", name)
  579. }
  580. return nil
  581. }
  582. func ShowHandler(cmd *cobra.Command, args []string) error {
  583. client, err := api.ClientFromEnvironment()
  584. if err != nil {
  585. return err
  586. }
  587. license, errLicense := cmd.Flags().GetBool("license")
  588. modelfile, errModelfile := cmd.Flags().GetBool("modelfile")
  589. parameters, errParams := cmd.Flags().GetBool("parameters")
  590. system, errSystem := cmd.Flags().GetBool("system")
  591. template, errTemplate := cmd.Flags().GetBool("template")
  592. for _, boolErr := range []error{errLicense, errModelfile, errParams, errSystem, errTemplate} {
  593. if boolErr != nil {
  594. return errors.New("error retrieving flags")
  595. }
  596. }
  597. flagsSet := 0
  598. showType := ""
  599. if license {
  600. flagsSet++
  601. showType = "license"
  602. }
  603. if modelfile {
  604. flagsSet++
  605. showType = "modelfile"
  606. }
  607. if parameters {
  608. flagsSet++
  609. showType = "parameters"
  610. }
  611. if system {
  612. flagsSet++
  613. showType = "system"
  614. }
  615. if template {
  616. flagsSet++
  617. showType = "template"
  618. }
  619. if flagsSet > 1 {
  620. return errors.New("only one of '--license', '--modelfile', '--parameters', '--system', or '--template' can be specified")
  621. }
  622. req := api.ShowRequest{Name: args[0]}
  623. resp, err := client.Show(cmd.Context(), &req)
  624. if err != nil {
  625. return err
  626. }
  627. if flagsSet == 1 {
  628. switch showType {
  629. case "license":
  630. fmt.Println(resp.License)
  631. case "modelfile":
  632. fmt.Println(resp.Modelfile)
  633. case "parameters":
  634. fmt.Println(resp.Parameters)
  635. case "system":
  636. fmt.Println(resp.System)
  637. case "template":
  638. fmt.Println(resp.Template)
  639. }
  640. return nil
  641. }
  642. return showInfo(resp, os.Stdout)
  643. }
  644. func showInfo(resp *api.ShowResponse, w io.Writer) error {
  645. tableRender := func(header string, rows func() [][]string) {
  646. fmt.Fprintln(w, " ", header)
  647. table := tablewriter.NewWriter(w)
  648. table.SetAlignment(tablewriter.ALIGN_LEFT)
  649. table.SetBorder(false)
  650. table.SetNoWhiteSpace(true)
  651. table.SetTablePadding(" ")
  652. switch header {
  653. case "Template", "System", "License":
  654. table.SetColWidth(100)
  655. }
  656. table.AppendBulk(rows())
  657. table.Render()
  658. fmt.Fprintln(w)
  659. }
  660. tableRender("Model", func() (rows [][]string) {
  661. if resp.ModelInfo != nil {
  662. arch := resp.ModelInfo["general.architecture"].(string)
  663. rows = append(rows, []string{"", "architecture", arch})
  664. rows = append(rows, []string{"", "parameters", format.HumanNumber(uint64(resp.ModelInfo["general.parameter_count"].(float64)))})
  665. rows = append(rows, []string{"", "context length", strconv.FormatFloat(resp.ModelInfo[fmt.Sprintf("%s.context_length", arch)].(float64), 'f', -1, 64)})
  666. rows = append(rows, []string{"", "embedding length", strconv.FormatFloat(resp.ModelInfo[fmt.Sprintf("%s.embedding_length", arch)].(float64), 'f', -1, 64)})
  667. } else {
  668. rows = append(rows, []string{"", "architecture", resp.Details.Family})
  669. rows = append(rows, []string{"", "parameters", resp.Details.ParameterSize})
  670. }
  671. rows = append(rows, []string{"", "quantization", resp.Details.QuantizationLevel})
  672. return
  673. })
  674. if resp.ProjectorInfo != nil {
  675. tableRender("Projector", func() (rows [][]string) {
  676. arch := resp.ProjectorInfo["general.architecture"].(string)
  677. rows = append(rows, []string{"", "architecture", arch})
  678. rows = append(rows, []string{"", "parameters", format.HumanNumber(uint64(resp.ProjectorInfo["general.parameter_count"].(float64)))})
  679. rows = append(rows, []string{"", "embedding length", strconv.FormatFloat(resp.ProjectorInfo[fmt.Sprintf("%s.vision.embedding_length", arch)].(float64), 'f', -1, 64)})
  680. rows = append(rows, []string{"", "dimensions", strconv.FormatFloat(resp.ProjectorInfo[fmt.Sprintf("%s.vision.projection_dim", arch)].(float64), 'f', -1, 64)})
  681. return
  682. })
  683. }
  684. if resp.Parameters != "" {
  685. tableRender("Parameters", func() (rows [][]string) {
  686. scanner := bufio.NewScanner(strings.NewReader(resp.Parameters))
  687. for scanner.Scan() {
  688. if text := scanner.Text(); text != "" {
  689. rows = append(rows, append([]string{""}, strings.Fields(text)...))
  690. }
  691. }
  692. return
  693. })
  694. }
  695. head := func(s string, n int) (rows [][]string) {
  696. scanner := bufio.NewScanner(strings.NewReader(s))
  697. for scanner.Scan() && (len(rows) < n || n < 0) {
  698. if text := scanner.Text(); text != "" {
  699. rows = append(rows, []string{"", strings.TrimSpace(text)})
  700. }
  701. }
  702. return
  703. }
  704. if resp.System != "" {
  705. tableRender("System", func() [][]string {
  706. return head(resp.System, 2)
  707. })
  708. }
  709. if resp.License != "" {
  710. tableRender("License", func() [][]string {
  711. return head(resp.License, 2)
  712. })
  713. }
  714. return nil
  715. }
  716. func CopyHandler(cmd *cobra.Command, args []string) error {
  717. client, err := api.ClientFromEnvironment()
  718. if err != nil {
  719. return err
  720. }
  721. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  722. if err := client.Copy(cmd.Context(), &req); err != nil {
  723. return err
  724. }
  725. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  726. return nil
  727. }
  728. func PullHandler(cmd *cobra.Command, args []string) error {
  729. insecure, err := cmd.Flags().GetBool("insecure")
  730. if err != nil {
  731. return err
  732. }
  733. client, err := api.ClientFromEnvironment()
  734. if err != nil {
  735. return err
  736. }
  737. p := progress.NewProgress(os.Stderr)
  738. defer p.Stop()
  739. bars := make(map[string]*progress.Bar)
  740. var status string
  741. var spinner *progress.Spinner
  742. fn := func(resp api.ProgressResponse) error {
  743. if resp.Digest != "" {
  744. if spinner != nil {
  745. spinner.Stop()
  746. }
  747. bar, ok := bars[resp.Digest]
  748. if !ok {
  749. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  750. bars[resp.Digest] = bar
  751. p.Add(resp.Digest, bar)
  752. }
  753. bar.Set(resp.Completed)
  754. } else if status != resp.Status {
  755. if spinner != nil {
  756. spinner.Stop()
  757. }
  758. status = resp.Status
  759. spinner = progress.NewSpinner(status)
  760. p.Add(status, spinner)
  761. }
  762. return nil
  763. }
  764. request := api.PullRequest{Name: args[0], Insecure: insecure}
  765. if err := client.Pull(cmd.Context(), &request, fn); err != nil {
  766. return err
  767. }
  768. return nil
  769. }
  770. type generateContextKey string
  771. type runOptions struct {
  772. Model string
  773. ParentModel string
  774. Prompt string
  775. Messages []api.Message
  776. WordWrap bool
  777. Format string
  778. System string
  779. Images []api.ImageData
  780. Options map[string]interface{}
  781. MultiModal bool
  782. KeepAlive *api.Duration
  783. }
  784. type displayResponseState struct {
  785. lineLength int
  786. wordBuffer string
  787. }
  788. func displayResponse(content string, wordWrap bool, state *displayResponseState) {
  789. termWidth, _, _ := term.GetSize(int(os.Stdout.Fd()))
  790. if wordWrap && termWidth >= 10 {
  791. for _, ch := range content {
  792. if state.lineLength+1 > termWidth-5 {
  793. if runewidth.StringWidth(state.wordBuffer) > termWidth-10 {
  794. fmt.Printf("%s%c", state.wordBuffer, ch)
  795. state.wordBuffer = ""
  796. state.lineLength = 0
  797. continue
  798. }
  799. // backtrack the length of the last word and clear to the end of the line
  800. a := runewidth.StringWidth(state.wordBuffer)
  801. if a > 0 {
  802. fmt.Printf("\x1b[%dD", a)
  803. }
  804. fmt.Printf("\x1b[K\n")
  805. fmt.Printf("%s%c", state.wordBuffer, ch)
  806. chWidth := runewidth.RuneWidth(ch)
  807. state.lineLength = runewidth.StringWidth(state.wordBuffer) + chWidth
  808. } else {
  809. fmt.Print(string(ch))
  810. state.lineLength += runewidth.RuneWidth(ch)
  811. if runewidth.RuneWidth(ch) >= 2 {
  812. state.wordBuffer = ""
  813. continue
  814. }
  815. switch ch {
  816. case ' ':
  817. state.wordBuffer = ""
  818. case '\n':
  819. state.lineLength = 0
  820. default:
  821. state.wordBuffer += string(ch)
  822. }
  823. }
  824. }
  825. } else {
  826. fmt.Printf("%s%s", state.wordBuffer, content)
  827. if len(state.wordBuffer) > 0 {
  828. state.wordBuffer = ""
  829. }
  830. }
  831. }
  832. func chat(cmd *cobra.Command, opts runOptions) (*api.Message, error) {
  833. client, err := api.ClientFromEnvironment()
  834. if err != nil {
  835. return nil, err
  836. }
  837. p := progress.NewProgress(os.Stderr)
  838. defer p.StopAndClear()
  839. spinner := progress.NewSpinner("")
  840. p.Add("", spinner)
  841. cancelCtx, cancel := context.WithCancel(cmd.Context())
  842. defer cancel()
  843. sigChan := make(chan os.Signal, 1)
  844. signal.Notify(sigChan, syscall.SIGINT)
  845. go func() {
  846. <-sigChan
  847. cancel()
  848. }()
  849. var state *displayResponseState = &displayResponseState{}
  850. var latest api.ChatResponse
  851. var fullResponse strings.Builder
  852. var role string
  853. fn := func(response api.ChatResponse) error {
  854. p.StopAndClear()
  855. latest = response
  856. role = response.Message.Role
  857. content := response.Message.Content
  858. fullResponse.WriteString(content)
  859. displayResponse(content, opts.WordWrap, state)
  860. return nil
  861. }
  862. req := &api.ChatRequest{
  863. Model: opts.Model,
  864. Messages: opts.Messages,
  865. Format: opts.Format,
  866. Options: opts.Options,
  867. }
  868. if opts.KeepAlive != nil {
  869. req.KeepAlive = opts.KeepAlive
  870. }
  871. if err := client.Chat(cancelCtx, req, fn); err != nil {
  872. if errors.Is(err, context.Canceled) {
  873. return nil, nil
  874. }
  875. return nil, err
  876. }
  877. if len(opts.Messages) > 0 {
  878. fmt.Println()
  879. fmt.Println()
  880. }
  881. verbose, err := cmd.Flags().GetBool("verbose")
  882. if err != nil {
  883. return nil, err
  884. }
  885. if verbose {
  886. latest.Summary()
  887. }
  888. return &api.Message{Role: role, Content: fullResponse.String()}, nil
  889. }
  890. func generate(cmd *cobra.Command, opts runOptions) error {
  891. client, err := api.ClientFromEnvironment()
  892. if err != nil {
  893. return err
  894. }
  895. p := progress.NewProgress(os.Stderr)
  896. defer p.StopAndClear()
  897. spinner := progress.NewSpinner("")
  898. p.Add("", spinner)
  899. var latest api.GenerateResponse
  900. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  901. if !ok {
  902. generateContext = []int{}
  903. }
  904. ctx, cancel := context.WithCancel(cmd.Context())
  905. defer cancel()
  906. sigChan := make(chan os.Signal, 1)
  907. signal.Notify(sigChan, syscall.SIGINT)
  908. go func() {
  909. <-sigChan
  910. cancel()
  911. }()
  912. var state *displayResponseState = &displayResponseState{}
  913. fn := func(response api.GenerateResponse) error {
  914. p.StopAndClear()
  915. latest = response
  916. content := response.Response
  917. displayResponse(content, opts.WordWrap, state)
  918. return nil
  919. }
  920. if opts.MultiModal {
  921. opts.Prompt, opts.Images, err = extractFileData(opts.Prompt)
  922. if err != nil {
  923. return err
  924. }
  925. }
  926. request := api.GenerateRequest{
  927. Model: opts.Model,
  928. Prompt: opts.Prompt,
  929. Context: generateContext,
  930. Images: opts.Images,
  931. Format: opts.Format,
  932. System: opts.System,
  933. Options: opts.Options,
  934. KeepAlive: opts.KeepAlive,
  935. }
  936. if err := client.Generate(ctx, &request, fn); err != nil {
  937. if errors.Is(err, context.Canceled) {
  938. return nil
  939. }
  940. return err
  941. }
  942. if opts.Prompt != "" {
  943. fmt.Println()
  944. fmt.Println()
  945. }
  946. if !latest.Done {
  947. return nil
  948. }
  949. verbose, err := cmd.Flags().GetBool("verbose")
  950. if err != nil {
  951. return err
  952. }
  953. if verbose {
  954. latest.Summary()
  955. }
  956. ctx = context.WithValue(cmd.Context(), generateContextKey("context"), latest.Context)
  957. cmd.SetContext(ctx)
  958. return nil
  959. }
  960. func RunServer(_ *cobra.Command, _ []string) error {
  961. if err := initializeKeypair(); err != nil {
  962. return err
  963. }
  964. ln, err := net.Listen("tcp", envconfig.Host().Host)
  965. if err != nil {
  966. return err
  967. }
  968. err = server.Serve(ln)
  969. if errors.Is(err, http.ErrServerClosed) {
  970. return nil
  971. }
  972. return err
  973. }
  974. func initializeKeypair() error {
  975. home, err := os.UserHomeDir()
  976. if err != nil {
  977. return err
  978. }
  979. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  980. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  981. _, err = os.Stat(privKeyPath)
  982. if os.IsNotExist(err) {
  983. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  984. cryptoPublicKey, cryptoPrivateKey, err := ed25519.GenerateKey(rand.Reader)
  985. if err != nil {
  986. return err
  987. }
  988. privateKeyBytes, err := ssh.MarshalPrivateKey(cryptoPrivateKey, "")
  989. if err != nil {
  990. return err
  991. }
  992. if err := os.MkdirAll(filepath.Dir(privKeyPath), 0o755); err != nil {
  993. return fmt.Errorf("could not create directory %w", err)
  994. }
  995. if err := os.WriteFile(privKeyPath, pem.EncodeToMemory(privateKeyBytes), 0o600); err != nil {
  996. return err
  997. }
  998. sshPublicKey, err := ssh.NewPublicKey(cryptoPublicKey)
  999. if err != nil {
  1000. return err
  1001. }
  1002. publicKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey)
  1003. if err := os.WriteFile(pubKeyPath, publicKeyBytes, 0o644); err != nil {
  1004. return err
  1005. }
  1006. fmt.Printf("Your new public key is: \n\n%s\n", publicKeyBytes)
  1007. }
  1008. return nil
  1009. }
  1010. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  1011. client, err := api.ClientFromEnvironment()
  1012. if err != nil {
  1013. return err
  1014. }
  1015. if err := client.Heartbeat(cmd.Context()); err != nil {
  1016. if !strings.Contains(err.Error(), " refused") {
  1017. return err
  1018. }
  1019. if err := startApp(cmd.Context(), client); err != nil {
  1020. return errors.New("could not connect to ollama app, is it running?")
  1021. }
  1022. }
  1023. return nil
  1024. }
  1025. func versionHandler(cmd *cobra.Command, _ []string) {
  1026. client, err := api.ClientFromEnvironment()
  1027. if err != nil {
  1028. return
  1029. }
  1030. serverVersion, err := client.Version(cmd.Context())
  1031. if err != nil {
  1032. fmt.Println("Warning: could not connect to a running Ollama instance")
  1033. }
  1034. if serverVersion != "" {
  1035. fmt.Printf("ollama version is %s\n", serverVersion)
  1036. }
  1037. if serverVersion != version.Version {
  1038. fmt.Printf("Warning: client version is %s\n", version.Version)
  1039. }
  1040. }
  1041. func appendEnvDocs(cmd *cobra.Command, envs []envconfig.EnvVar) {
  1042. if len(envs) == 0 {
  1043. return
  1044. }
  1045. envUsage := `
  1046. Environment Variables:
  1047. `
  1048. for _, e := range envs {
  1049. envUsage += fmt.Sprintf(" %-24s %s\n", e.Name, e.Description)
  1050. }
  1051. cmd.SetUsageTemplate(cmd.UsageTemplate() + envUsage)
  1052. }
  1053. func NewCLI() *cobra.Command {
  1054. log.SetFlags(log.LstdFlags | log.Lshortfile)
  1055. cobra.EnableCommandSorting = false
  1056. if runtime.GOOS == "windows" {
  1057. console.ConsoleFromFile(os.Stdin) //nolint:errcheck
  1058. }
  1059. rootCmd := &cobra.Command{
  1060. Use: "ollama",
  1061. Short: "Large language model runner",
  1062. SilenceUsage: true,
  1063. SilenceErrors: true,
  1064. CompletionOptions: cobra.CompletionOptions{
  1065. DisableDefaultCmd: true,
  1066. },
  1067. Run: func(cmd *cobra.Command, args []string) {
  1068. if version, _ := cmd.Flags().GetBool("version"); version {
  1069. versionHandler(cmd, args)
  1070. return
  1071. }
  1072. cmd.Print(cmd.UsageString())
  1073. },
  1074. }
  1075. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  1076. createCmd := &cobra.Command{
  1077. Use: "create MODEL",
  1078. Short: "Create a model from a Modelfile",
  1079. Args: cobra.ExactArgs(1),
  1080. PreRunE: checkServerHeartbeat,
  1081. RunE: CreateHandler,
  1082. }
  1083. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile")
  1084. createCmd.Flags().StringP("quantize", "q", "", "Quantize model to this level (e.g. q4_0)")
  1085. showCmd := &cobra.Command{
  1086. Use: "show MODEL",
  1087. Short: "Show information for a model",
  1088. Args: cobra.ExactArgs(1),
  1089. PreRunE: checkServerHeartbeat,
  1090. RunE: ShowHandler,
  1091. }
  1092. showCmd.Flags().Bool("license", false, "Show license of a model")
  1093. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  1094. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  1095. showCmd.Flags().Bool("template", false, "Show template of a model")
  1096. showCmd.Flags().Bool("system", false, "Show system message of a model")
  1097. runCmd := &cobra.Command{
  1098. Use: "run MODEL [PROMPT]",
  1099. Short: "Run a model",
  1100. Args: cobra.MinimumNArgs(1),
  1101. PreRunE: checkServerHeartbeat,
  1102. RunE: RunHandler,
  1103. }
  1104. runCmd.Flags().String("keepalive", "", "Duration to keep a model loaded (e.g. 5m)")
  1105. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  1106. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1107. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  1108. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  1109. stopCmd := &cobra.Command{
  1110. Use: "stop MODEL",
  1111. Short: "Stop a running model",
  1112. Args: cobra.ExactArgs(1),
  1113. PreRunE: checkServerHeartbeat,
  1114. RunE: StopHandler,
  1115. }
  1116. serveCmd := &cobra.Command{
  1117. Use: "serve",
  1118. Aliases: []string{"start"},
  1119. Short: "Start ollama",
  1120. Args: cobra.ExactArgs(0),
  1121. RunE: RunServer,
  1122. }
  1123. pullCmd := &cobra.Command{
  1124. Use: "pull MODEL",
  1125. Short: "Pull a model from a registry",
  1126. Args: cobra.ExactArgs(1),
  1127. PreRunE: checkServerHeartbeat,
  1128. RunE: PullHandler,
  1129. }
  1130. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1131. pushCmd := &cobra.Command{
  1132. Use: "push MODEL",
  1133. Short: "Push a model to a registry",
  1134. Args: cobra.ExactArgs(1),
  1135. PreRunE: checkServerHeartbeat,
  1136. RunE: PushHandler,
  1137. }
  1138. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1139. listCmd := &cobra.Command{
  1140. Use: "list",
  1141. Aliases: []string{"ls"},
  1142. Short: "List models",
  1143. PreRunE: checkServerHeartbeat,
  1144. RunE: ListHandler,
  1145. }
  1146. psCmd := &cobra.Command{
  1147. Use: "ps",
  1148. Short: "List running models",
  1149. PreRunE: checkServerHeartbeat,
  1150. RunE: ListRunningHandler,
  1151. }
  1152. copyCmd := &cobra.Command{
  1153. Use: "cp SOURCE DESTINATION",
  1154. Short: "Copy a model",
  1155. Args: cobra.ExactArgs(2),
  1156. PreRunE: checkServerHeartbeat,
  1157. RunE: CopyHandler,
  1158. }
  1159. deleteCmd := &cobra.Command{
  1160. Use: "rm MODEL [MODEL...]",
  1161. Short: "Remove a model",
  1162. Args: cobra.MinimumNArgs(1),
  1163. PreRunE: checkServerHeartbeat,
  1164. RunE: DeleteHandler,
  1165. }
  1166. envVars := envconfig.AsMap()
  1167. envs := []envconfig.EnvVar{envVars["OLLAMA_HOST"]}
  1168. for _, cmd := range []*cobra.Command{
  1169. createCmd,
  1170. showCmd,
  1171. runCmd,
  1172. stopCmd,
  1173. pullCmd,
  1174. pushCmd,
  1175. listCmd,
  1176. psCmd,
  1177. copyCmd,
  1178. deleteCmd,
  1179. serveCmd,
  1180. } {
  1181. switch cmd {
  1182. case runCmd:
  1183. appendEnvDocs(cmd, []envconfig.EnvVar{envVars["OLLAMA_HOST"], envVars["OLLAMA_NOHISTORY"]})
  1184. case serveCmd:
  1185. appendEnvDocs(cmd, []envconfig.EnvVar{
  1186. envVars["OLLAMA_DEBUG"],
  1187. envVars["OLLAMA_HOST"],
  1188. envVars["OLLAMA_KEEP_ALIVE"],
  1189. envVars["OLLAMA_MAX_LOADED_MODELS"],
  1190. envVars["OLLAMA_MAX_QUEUE"],
  1191. envVars["OLLAMA_MODELS"],
  1192. envVars["OLLAMA_NUM_PARALLEL"],
  1193. envVars["OLLAMA_NOPRUNE"],
  1194. envVars["OLLAMA_ORIGINS"],
  1195. envVars["OLLAMA_SCHED_SPREAD"],
  1196. envVars["OLLAMA_TMPDIR"],
  1197. envVars["OLLAMA_FLASH_ATTENTION"],
  1198. envVars["OLLAMA_LLM_LIBRARY"],
  1199. envVars["OLLAMA_GPU_OVERHEAD"],
  1200. envVars["OLLAMA_LOAD_TIMEOUT"],
  1201. })
  1202. default:
  1203. appendEnvDocs(cmd, envs)
  1204. }
  1205. }
  1206. rootCmd.AddCommand(
  1207. serveCmd,
  1208. createCmd,
  1209. showCmd,
  1210. runCmd,
  1211. stopCmd,
  1212. pullCmd,
  1213. pushCmd,
  1214. listCmd,
  1215. psCmd,
  1216. copyCmd,
  1217. deleteCmd,
  1218. )
  1219. return rootCmd
  1220. }