cmd.go 33 KB

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