cmd.go 31 KB

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