cmd.go 35 KB

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