cmd.go 34 KB

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