cmd.go 32 KB

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