cmd.go 34 KB

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