cmd.go 31 KB

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