cmd.go 37 KB

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