cmd.go 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  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. arch := resp.ModelInfo["general.architecture"].(string)
  612. modelData := [][]string{
  613. {"arch", arch},
  614. {"parameters", resp.Details.ParameterSize},
  615. {"quantization", resp.Details.QuantizationLevel},
  616. {"context length", fmt.Sprintf("%v", resp.ModelInfo[fmt.Sprintf("%s.context_length", arch)].(float64))},
  617. {"embedding length", fmt.Sprintf("%v", resp.ModelInfo[fmt.Sprintf("%s.embedding_length", arch)].(float64))},
  618. }
  619. mainTableData := [][]string{
  620. {"Model"},
  621. {renderSubTable(modelData, false)},
  622. }
  623. if resp.ProjectorInfo != nil {
  624. projectorData := [][]string{
  625. {"arch", "clip"},
  626. {"parameters", format.HumanNumber(uint64(resp.ProjectorInfo["general.parameter_count"].(float64)))},
  627. }
  628. if projectorType, ok := resp.ProjectorInfo["clip.projector_type"]; ok {
  629. projectorData = append(projectorData, []string{"projector type", projectorType.(string)})
  630. }
  631. projectorData = append(projectorData,
  632. []string{"embedding length", fmt.Sprintf("%v", resp.ProjectorInfo["clip.vision.embedding_length"].(float64))},
  633. []string{"projection dimensionality", fmt.Sprintf("%v", resp.ProjectorInfo["clip.vision.projection_dim"].(float64))},
  634. )
  635. mainTableData = append(mainTableData,
  636. []string{"Projector"},
  637. []string{renderSubTable(projectorData, false)},
  638. )
  639. }
  640. if resp.Parameters != "" {
  641. mainTableData = append(mainTableData, []string{"Parameters"}, []string{formatParams(resp.Parameters)})
  642. }
  643. if resp.System != "" {
  644. mainTableData = append(mainTableData, []string{"System"}, []string{renderSubTable(twoLines(resp.System), true)})
  645. }
  646. if resp.License != "" {
  647. mainTableData = append(mainTableData, []string{"License"}, []string{renderSubTable(twoLines(resp.License), true)})
  648. }
  649. table := tablewriter.NewWriter(os.Stdout)
  650. table.SetAutoWrapText(false)
  651. table.SetBorder(false)
  652. table.SetAlignment(tablewriter.ALIGN_LEFT)
  653. for _, v := range mainTableData {
  654. table.Append(v)
  655. }
  656. table.Render()
  657. }
  658. func renderSubTable(data [][]string, file bool) string {
  659. var buf bytes.Buffer
  660. table := tablewriter.NewWriter(&buf)
  661. table.SetAutoWrapText(!file)
  662. table.SetBorder(false)
  663. table.SetNoWhiteSpace(true)
  664. table.SetTablePadding("\t")
  665. table.SetAlignment(tablewriter.ALIGN_LEFT)
  666. for _, v := range data {
  667. table.Append(v)
  668. }
  669. table.Render()
  670. renderedTable := buf.String()
  671. lines := strings.Split(renderedTable, "\n")
  672. for i, line := range lines {
  673. lines[i] = "\t" + line
  674. }
  675. return strings.Join(lines, "\n")
  676. }
  677. func twoLines(s string) [][]string {
  678. lines := strings.Split(s, "\n")
  679. res := [][]string{}
  680. count := 0
  681. for _, line := range lines {
  682. line = strings.TrimSpace(line)
  683. if line != "" {
  684. count++
  685. res = append(res, []string{line})
  686. if count == 2 {
  687. return res
  688. }
  689. }
  690. }
  691. return res
  692. }
  693. func formatParams(s string) string {
  694. lines := strings.Split(s, "\n")
  695. table := [][]string{}
  696. for _, line := range lines {
  697. table = append(table, strings.Fields(line))
  698. }
  699. return renderSubTable(table, false)
  700. }
  701. func CopyHandler(cmd *cobra.Command, args []string) error {
  702. client, err := api.ClientFromEnvironment()
  703. if err != nil {
  704. return err
  705. }
  706. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  707. if err := client.Copy(cmd.Context(), &req); err != nil {
  708. return err
  709. }
  710. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  711. return nil
  712. }
  713. func PullHandler(cmd *cobra.Command, args []string) error {
  714. insecure, err := cmd.Flags().GetBool("insecure")
  715. if err != nil {
  716. return err
  717. }
  718. client, err := api.ClientFromEnvironment()
  719. if err != nil {
  720. return err
  721. }
  722. p := progress.NewProgress(os.Stderr)
  723. defer p.Stop()
  724. bars := make(map[string]*progress.Bar)
  725. var status string
  726. var spinner *progress.Spinner
  727. fn := func(resp api.ProgressResponse) error {
  728. if resp.Digest != "" {
  729. if spinner != nil {
  730. spinner.Stop()
  731. }
  732. bar, ok := bars[resp.Digest]
  733. if !ok {
  734. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  735. bars[resp.Digest] = bar
  736. p.Add(resp.Digest, bar)
  737. }
  738. bar.Set(resp.Completed)
  739. } else if status != resp.Status {
  740. if spinner != nil {
  741. spinner.Stop()
  742. }
  743. status = resp.Status
  744. spinner = progress.NewSpinner(status)
  745. p.Add(status, spinner)
  746. }
  747. return nil
  748. }
  749. request := api.PullRequest{Name: args[0], Insecure: insecure}
  750. if err := client.Pull(cmd.Context(), &request, fn); err != nil {
  751. return err
  752. }
  753. return nil
  754. }
  755. type generateContextKey string
  756. type runOptions struct {
  757. Model string
  758. ParentModel string
  759. Prompt string
  760. Messages []api.Message
  761. WordWrap bool
  762. Format string
  763. System string
  764. Images []api.ImageData
  765. Options map[string]interface{}
  766. MultiModal bool
  767. KeepAlive *api.Duration
  768. }
  769. type displayResponseState struct {
  770. lineLength int
  771. wordBuffer string
  772. }
  773. func displayResponse(content string, wordWrap bool, state *displayResponseState) {
  774. termWidth, _, _ := term.GetSize(int(os.Stdout.Fd()))
  775. if wordWrap && termWidth >= 10 {
  776. for _, ch := range content {
  777. if state.lineLength+1 > termWidth-5 {
  778. if runewidth.StringWidth(state.wordBuffer) > termWidth-10 {
  779. fmt.Printf("%s%c", state.wordBuffer, ch)
  780. state.wordBuffer = ""
  781. state.lineLength = 0
  782. continue
  783. }
  784. // backtrack the length of the last word and clear to the end of the line
  785. a := runewidth.StringWidth(state.wordBuffer)
  786. if a > 0 {
  787. fmt.Printf("\x1b[%dD", a)
  788. }
  789. fmt.Printf("\x1b[K\n")
  790. fmt.Printf("%s%c", state.wordBuffer, ch)
  791. chWidth := runewidth.RuneWidth(ch)
  792. state.lineLength = runewidth.StringWidth(state.wordBuffer) + chWidth
  793. } else {
  794. fmt.Print(string(ch))
  795. state.lineLength += runewidth.RuneWidth(ch)
  796. if runewidth.RuneWidth(ch) >= 2 {
  797. state.wordBuffer = ""
  798. continue
  799. }
  800. switch ch {
  801. case ' ':
  802. state.wordBuffer = ""
  803. case '\n':
  804. state.lineLength = 0
  805. default:
  806. state.wordBuffer += string(ch)
  807. }
  808. }
  809. }
  810. } else {
  811. fmt.Printf("%s%s", state.wordBuffer, content)
  812. if len(state.wordBuffer) > 0 {
  813. state.wordBuffer = ""
  814. }
  815. }
  816. }
  817. func chat(cmd *cobra.Command, opts runOptions) (*api.Message, error) {
  818. client, err := api.ClientFromEnvironment()
  819. if err != nil {
  820. return nil, err
  821. }
  822. p := progress.NewProgress(os.Stderr)
  823. defer p.StopAndClear()
  824. spinner := progress.NewSpinner("")
  825. p.Add("", spinner)
  826. cancelCtx, cancel := context.WithCancel(cmd.Context())
  827. defer cancel()
  828. sigChan := make(chan os.Signal, 1)
  829. signal.Notify(sigChan, syscall.SIGINT)
  830. go func() {
  831. <-sigChan
  832. cancel()
  833. }()
  834. var state *displayResponseState = &displayResponseState{}
  835. var latest api.ChatResponse
  836. var fullResponse strings.Builder
  837. var role string
  838. fn := func(response api.ChatResponse) error {
  839. p.StopAndClear()
  840. latest = response
  841. role = response.Message.Role
  842. content := response.Message.Content
  843. fullResponse.WriteString(content)
  844. displayResponse(content, opts.WordWrap, state)
  845. return nil
  846. }
  847. req := &api.ChatRequest{
  848. Model: opts.Model,
  849. Messages: opts.Messages,
  850. Format: opts.Format,
  851. Options: opts.Options,
  852. }
  853. if opts.KeepAlive != nil {
  854. req.KeepAlive = opts.KeepAlive
  855. }
  856. if err := client.Chat(cancelCtx, req, fn); err != nil {
  857. if errors.Is(err, context.Canceled) {
  858. return nil, nil
  859. }
  860. return nil, err
  861. }
  862. if len(opts.Messages) > 0 {
  863. fmt.Println()
  864. fmt.Println()
  865. }
  866. verbose, err := cmd.Flags().GetBool("verbose")
  867. if err != nil {
  868. return nil, err
  869. }
  870. if verbose {
  871. latest.Summary()
  872. }
  873. return &api.Message{Role: role, Content: fullResponse.String()}, nil
  874. }
  875. func generate(cmd *cobra.Command, opts runOptions) error {
  876. client, err := api.ClientFromEnvironment()
  877. if err != nil {
  878. return err
  879. }
  880. p := progress.NewProgress(os.Stderr)
  881. defer p.StopAndClear()
  882. spinner := progress.NewSpinner("")
  883. p.Add("", spinner)
  884. var latest api.GenerateResponse
  885. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  886. if !ok {
  887. generateContext = []int{}
  888. }
  889. ctx, cancel := context.WithCancel(cmd.Context())
  890. defer cancel()
  891. sigChan := make(chan os.Signal, 1)
  892. signal.Notify(sigChan, syscall.SIGINT)
  893. go func() {
  894. <-sigChan
  895. cancel()
  896. }()
  897. var state *displayResponseState = &displayResponseState{}
  898. fn := func(response api.GenerateResponse) error {
  899. p.StopAndClear()
  900. latest = response
  901. content := response.Response
  902. displayResponse(content, opts.WordWrap, state)
  903. return nil
  904. }
  905. if opts.MultiModal {
  906. opts.Prompt, opts.Images, err = extractFileData(opts.Prompt)
  907. if err != nil {
  908. return err
  909. }
  910. }
  911. request := api.GenerateRequest{
  912. Model: opts.Model,
  913. Prompt: opts.Prompt,
  914. Context: generateContext,
  915. Images: opts.Images,
  916. Format: opts.Format,
  917. System: opts.System,
  918. Options: opts.Options,
  919. KeepAlive: opts.KeepAlive,
  920. }
  921. if err := client.Generate(ctx, &request, fn); err != nil {
  922. if errors.Is(err, context.Canceled) {
  923. return nil
  924. }
  925. return err
  926. }
  927. if opts.Prompt != "" {
  928. fmt.Println()
  929. fmt.Println()
  930. }
  931. if !latest.Done {
  932. return nil
  933. }
  934. verbose, err := cmd.Flags().GetBool("verbose")
  935. if err != nil {
  936. return err
  937. }
  938. if verbose {
  939. latest.Summary()
  940. }
  941. ctx = context.WithValue(cmd.Context(), generateContextKey("context"), latest.Context)
  942. cmd.SetContext(ctx)
  943. return nil
  944. }
  945. func RunServer(_ *cobra.Command, _ []string) error {
  946. if err := initializeKeypair(); err != nil {
  947. return err
  948. }
  949. ln, err := net.Listen("tcp", envconfig.Host().Host)
  950. if err != nil {
  951. return err
  952. }
  953. err = server.Serve(ln)
  954. if errors.Is(err, http.ErrServerClosed) {
  955. return nil
  956. }
  957. return err
  958. }
  959. func initializeKeypair() error {
  960. home, err := os.UserHomeDir()
  961. if err != nil {
  962. return err
  963. }
  964. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  965. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  966. _, err = os.Stat(privKeyPath)
  967. if os.IsNotExist(err) {
  968. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  969. cryptoPublicKey, cryptoPrivateKey, err := ed25519.GenerateKey(rand.Reader)
  970. if err != nil {
  971. return err
  972. }
  973. privateKeyBytes, err := ssh.MarshalPrivateKey(cryptoPrivateKey, "")
  974. if err != nil {
  975. return err
  976. }
  977. if err := os.MkdirAll(filepath.Dir(privKeyPath), 0o755); err != nil {
  978. return fmt.Errorf("could not create directory %w", err)
  979. }
  980. if err := os.WriteFile(privKeyPath, pem.EncodeToMemory(privateKeyBytes), 0o600); err != nil {
  981. return err
  982. }
  983. sshPublicKey, err := ssh.NewPublicKey(cryptoPublicKey)
  984. if err != nil {
  985. return err
  986. }
  987. publicKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey)
  988. if err := os.WriteFile(pubKeyPath, publicKeyBytes, 0o644); err != nil {
  989. return err
  990. }
  991. fmt.Printf("Your new public key is: \n\n%s\n", publicKeyBytes)
  992. }
  993. return nil
  994. }
  995. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  996. client, err := api.ClientFromEnvironment()
  997. if err != nil {
  998. return err
  999. }
  1000. if err := client.Heartbeat(cmd.Context()); err != nil {
  1001. if !strings.Contains(err.Error(), " refused") {
  1002. return err
  1003. }
  1004. if err := startApp(cmd.Context(), client); err != nil {
  1005. return errors.New("could not connect to ollama app, is it running?")
  1006. }
  1007. }
  1008. return nil
  1009. }
  1010. func versionHandler(cmd *cobra.Command, _ []string) {
  1011. client, err := api.ClientFromEnvironment()
  1012. if err != nil {
  1013. return
  1014. }
  1015. serverVersion, err := client.Version(cmd.Context())
  1016. if err != nil {
  1017. fmt.Println("Warning: could not connect to a running Ollama instance")
  1018. }
  1019. if serverVersion != "" {
  1020. fmt.Printf("ollama version is %s\n", serverVersion)
  1021. }
  1022. if serverVersion != version.Version {
  1023. fmt.Printf("Warning: client version is %s\n", version.Version)
  1024. }
  1025. }
  1026. func appendEnvDocs(cmd *cobra.Command, envs []envconfig.EnvVar) {
  1027. if len(envs) == 0 {
  1028. return
  1029. }
  1030. envUsage := `
  1031. Environment Variables:
  1032. `
  1033. for _, e := range envs {
  1034. envUsage += fmt.Sprintf(" %-24s %s\n", e.Name, e.Description)
  1035. }
  1036. cmd.SetUsageTemplate(cmd.UsageTemplate() + envUsage)
  1037. }
  1038. func NewCLI() *cobra.Command {
  1039. log.SetFlags(log.LstdFlags | log.Lshortfile)
  1040. cobra.EnableCommandSorting = false
  1041. if runtime.GOOS == "windows" {
  1042. console.ConsoleFromFile(os.Stdin) //nolint:errcheck
  1043. }
  1044. rootCmd := &cobra.Command{
  1045. Use: "ollama",
  1046. Short: "Large language model runner",
  1047. SilenceUsage: true,
  1048. SilenceErrors: true,
  1049. CompletionOptions: cobra.CompletionOptions{
  1050. DisableDefaultCmd: true,
  1051. },
  1052. Run: func(cmd *cobra.Command, args []string) {
  1053. if version, _ := cmd.Flags().GetBool("version"); version {
  1054. versionHandler(cmd, args)
  1055. return
  1056. }
  1057. cmd.Print(cmd.UsageString())
  1058. },
  1059. }
  1060. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  1061. createCmd := &cobra.Command{
  1062. Use: "create MODEL",
  1063. Short: "Create a model from a Modelfile",
  1064. Args: cobra.ExactArgs(1),
  1065. PreRunE: checkServerHeartbeat,
  1066. RunE: CreateHandler,
  1067. }
  1068. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile")
  1069. createCmd.Flags().StringP("quantize", "q", "", "Quantize model to this level (e.g. q4_0)")
  1070. showCmd := &cobra.Command{
  1071. Use: "show MODEL",
  1072. Short: "Show information for a model",
  1073. Args: cobra.ExactArgs(1),
  1074. PreRunE: checkServerHeartbeat,
  1075. RunE: ShowHandler,
  1076. }
  1077. showCmd.Flags().Bool("license", false, "Show license of a model")
  1078. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  1079. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  1080. showCmd.Flags().Bool("template", false, "Show template of a model")
  1081. showCmd.Flags().Bool("system", false, "Show system message of a model")
  1082. runCmd := &cobra.Command{
  1083. Use: "run MODEL [PROMPT]",
  1084. Short: "Run a model",
  1085. Args: cobra.MinimumNArgs(1),
  1086. PreRunE: checkServerHeartbeat,
  1087. RunE: RunHandler,
  1088. }
  1089. runCmd.Flags().String("keepalive", "", "Duration to keep a model loaded (e.g. 5m)")
  1090. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  1091. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1092. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  1093. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  1094. serveCmd := &cobra.Command{
  1095. Use: "serve",
  1096. Aliases: []string{"start"},
  1097. Short: "Start ollama",
  1098. Args: cobra.ExactArgs(0),
  1099. RunE: RunServer,
  1100. }
  1101. pullCmd := &cobra.Command{
  1102. Use: "pull MODEL",
  1103. Short: "Pull a model from a registry",
  1104. Args: cobra.ExactArgs(1),
  1105. PreRunE: checkServerHeartbeat,
  1106. RunE: PullHandler,
  1107. }
  1108. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1109. pushCmd := &cobra.Command{
  1110. Use: "push MODEL",
  1111. Short: "Push a model to a registry",
  1112. Args: cobra.ExactArgs(1),
  1113. PreRunE: checkServerHeartbeat,
  1114. RunE: PushHandler,
  1115. }
  1116. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1117. listCmd := &cobra.Command{
  1118. Use: "list",
  1119. Aliases: []string{"ls"},
  1120. Short: "List models",
  1121. PreRunE: checkServerHeartbeat,
  1122. RunE: ListHandler,
  1123. }
  1124. psCmd := &cobra.Command{
  1125. Use: "ps",
  1126. Short: "List running models",
  1127. PreRunE: checkServerHeartbeat,
  1128. RunE: ListRunningHandler,
  1129. }
  1130. copyCmd := &cobra.Command{
  1131. Use: "cp SOURCE DESTINATION",
  1132. Short: "Copy a model",
  1133. Args: cobra.ExactArgs(2),
  1134. PreRunE: checkServerHeartbeat,
  1135. RunE: CopyHandler,
  1136. }
  1137. deleteCmd := &cobra.Command{
  1138. Use: "rm MODEL [MODEL...]",
  1139. Short: "Remove a model",
  1140. Args: cobra.MinimumNArgs(1),
  1141. PreRunE: checkServerHeartbeat,
  1142. RunE: DeleteHandler,
  1143. }
  1144. envVars := envconfig.AsMap()
  1145. envs := []envconfig.EnvVar{envVars["OLLAMA_HOST"]}
  1146. for _, cmd := range []*cobra.Command{
  1147. createCmd,
  1148. showCmd,
  1149. runCmd,
  1150. pullCmd,
  1151. pushCmd,
  1152. listCmd,
  1153. psCmd,
  1154. copyCmd,
  1155. deleteCmd,
  1156. serveCmd,
  1157. } {
  1158. switch cmd {
  1159. case runCmd:
  1160. appendEnvDocs(cmd, []envconfig.EnvVar{envVars["OLLAMA_HOST"], envVars["OLLAMA_NOHISTORY"]})
  1161. case serveCmd:
  1162. appendEnvDocs(cmd, []envconfig.EnvVar{
  1163. envVars["OLLAMA_DEBUG"],
  1164. envVars["OLLAMA_HOST"],
  1165. envVars["OLLAMA_KEEP_ALIVE"],
  1166. envVars["OLLAMA_MAX_LOADED_MODELS"],
  1167. envVars["OLLAMA_MAX_QUEUE"],
  1168. envVars["OLLAMA_MODELS"],
  1169. envVars["OLLAMA_NUM_PARALLEL"],
  1170. envVars["OLLAMA_NOPRUNE"],
  1171. envVars["OLLAMA_ORIGINS"],
  1172. envVars["OLLAMA_SCHED_SPREAD"],
  1173. envVars["OLLAMA_TMPDIR"],
  1174. envVars["OLLAMA_FLASH_ATTENTION"],
  1175. envVars["OLLAMA_LLM_LIBRARY"],
  1176. })
  1177. default:
  1178. appendEnvDocs(cmd, envs)
  1179. }
  1180. }
  1181. rootCmd.AddCommand(
  1182. serveCmd,
  1183. createCmd,
  1184. showCmd,
  1185. runCmd,
  1186. pullCmd,
  1187. pushCmd,
  1188. listCmd,
  1189. psCmd,
  1190. copyCmd,
  1191. deleteCmd,
  1192. )
  1193. return rootCmd
  1194. }