cmd.go 34 KB

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