cmd.go 33 KB

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