cmd.go 32 KB

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