cmd.go 31 KB

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