cmd.go 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  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. "net"
  15. "net/http"
  16. "os"
  17. "os/signal"
  18. "path/filepath"
  19. "regexp"
  20. "runtime"
  21. "strings"
  22. "syscall"
  23. "time"
  24. "github.com/containerd/console"
  25. "github.com/olekukonko/tablewriter"
  26. "github.com/spf13/cobra"
  27. "golang.org/x/crypto/ssh"
  28. "golang.org/x/exp/slices"
  29. "golang.org/x/term"
  30. "github.com/ollama/ollama/api"
  31. "github.com/ollama/ollama/auth"
  32. "github.com/ollama/ollama/format"
  33. "github.com/ollama/ollama/progress"
  34. "github.com/ollama/ollama/server"
  35. "github.com/ollama/ollama/types/errtypes"
  36. "github.com/ollama/ollama/types/model"
  37. "github.com/ollama/ollama/version"
  38. )
  39. func CreateHandler(cmd *cobra.Command, args []string) error {
  40. filename, _ := cmd.Flags().GetString("file")
  41. filename, err := filepath.Abs(filename)
  42. if err != nil {
  43. return err
  44. }
  45. client, err := api.ClientFromEnvironment()
  46. if err != nil {
  47. return err
  48. }
  49. p := progress.NewProgress(os.Stderr)
  50. defer p.Stop()
  51. f, err := os.Open(filename)
  52. if err != nil {
  53. return err
  54. }
  55. defer f.Close()
  56. modelfile, err := model.ParseFile(f)
  57. if err != nil {
  58. return err
  59. }
  60. home, err := os.UserHomeDir()
  61. if err != nil {
  62. return err
  63. }
  64. status := "transferring model data"
  65. spinner := progress.NewSpinner(status)
  66. p.Add(status, spinner)
  67. for i := range modelfile.Commands {
  68. switch modelfile.Commands[i].Name {
  69. case "model", "adapter":
  70. path := modelfile.Commands[i].Args
  71. if path == "~" {
  72. path = home
  73. } else if strings.HasPrefix(path, "~/") {
  74. path = filepath.Join(home, path[2:])
  75. }
  76. if !filepath.IsAbs(path) {
  77. path = filepath.Join(filepath.Dir(filename), path)
  78. }
  79. fi, err := os.Stat(path)
  80. if errors.Is(err, os.ErrNotExist) && modelfile.Commands[i].Name == "model" {
  81. continue
  82. } else if err != nil {
  83. return err
  84. }
  85. if fi.IsDir() {
  86. // this is likely a safetensors or pytorch directory
  87. // TODO make this work w/ adapters
  88. tempfile, err := tempZipFiles(path)
  89. if err != nil {
  90. return err
  91. }
  92. defer os.RemoveAll(tempfile)
  93. path = tempfile
  94. }
  95. digest, err := createBlob(cmd, client, path)
  96. if err != nil {
  97. return err
  98. }
  99. modelfile.Commands[i].Args = "@" + digest
  100. }
  101. }
  102. bars := make(map[string]*progress.Bar)
  103. fn := func(resp api.ProgressResponse) error {
  104. if resp.Digest != "" {
  105. spinner.Stop()
  106. bar, ok := bars[resp.Digest]
  107. if !ok {
  108. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  109. bars[resp.Digest] = bar
  110. p.Add(resp.Digest, bar)
  111. }
  112. bar.Set(resp.Completed)
  113. } else if status != resp.Status {
  114. spinner.Stop()
  115. status = resp.Status
  116. spinner = progress.NewSpinner(status)
  117. p.Add(status, spinner)
  118. }
  119. return nil
  120. }
  121. quantize, _ := cmd.Flags().GetString("quantize")
  122. request := api.CreateRequest{Name: args[0], Modelfile: modelfile.String(), Quantize: quantize}
  123. if err := client.Create(cmd.Context(), &request, fn); err != nil {
  124. return err
  125. }
  126. return nil
  127. }
  128. func tempZipFiles(path string) (string, error) {
  129. tempfile, err := os.CreateTemp("", "ollama-tf")
  130. if err != nil {
  131. return "", err
  132. }
  133. defer tempfile.Close()
  134. zipfile := zip.NewWriter(tempfile)
  135. defer zipfile.Close()
  136. detectContentType := func(path string) (string, error) {
  137. f, err := os.Open(path)
  138. if err != nil {
  139. return "", err
  140. }
  141. defer f.Close()
  142. var b bytes.Buffer
  143. b.Grow(512)
  144. if _, err := io.CopyN(&b, f, 512); err != nil && !errors.Is(err, io.EOF) {
  145. return "", err
  146. }
  147. contentType, _, _ := strings.Cut(http.DetectContentType(b.Bytes()), ";")
  148. return contentType, nil
  149. }
  150. glob := func(pattern, contentType string) ([]string, error) {
  151. matches, err := filepath.Glob(pattern)
  152. if err != nil {
  153. return nil, err
  154. }
  155. for _, safetensor := range matches {
  156. if ct, err := detectContentType(safetensor); err != nil {
  157. return nil, err
  158. } else if ct != contentType {
  159. return nil, fmt.Errorf("invalid content type: expected %s for %s", ct, safetensor)
  160. }
  161. }
  162. return matches, nil
  163. }
  164. var files []string
  165. if st, _ := glob(filepath.Join(path, "model*.safetensors"), "application/octet-stream"); len(st) > 0 {
  166. // safetensors files might be unresolved git lfs references; skip if they are
  167. // covers model-x-of-y.safetensors, model.fp32-x-of-y.safetensors, model.safetensors
  168. files = append(files, st...)
  169. } else if pt, _ := glob(filepath.Join(path, "pytorch_model*.bin"), "application/zip"); len(pt) > 0 {
  170. // pytorch files might also be unresolved git lfs references; skip if they are
  171. // covers pytorch_model-x-of-y.bin, pytorch_model.fp32-x-of-y.bin, pytorch_model.bin
  172. files = append(files, pt...)
  173. } else if pt, _ := glob(filepath.Join(path, "consolidated*.pth"), "application/octet-stream"); len(pt) > 0 {
  174. // pytorch files might also be unresolved git lfs references; skip if they are
  175. // covers consolidated.x.pth, consolidated.pth
  176. files = append(files, pt...)
  177. } else {
  178. return "", errors.New("no safetensors or torch files found")
  179. }
  180. // add configuration files, json files are detected as text/plain
  181. js, err := glob(filepath.Join(path, "*.json"), "text/plain")
  182. if err != nil {
  183. return "", err
  184. }
  185. files = append(files, js...)
  186. if tks, _ := glob(filepath.Join(path, "tokenizer.model"), "application/octet-stream"); len(tks) > 0 {
  187. // add tokenizer.model if it exists, tokenizer.json is automatically picked up by the previous glob
  188. // tokenizer.model might be a unresolved git lfs reference; error if it is
  189. files = append(files, tks...)
  190. } else if tks, _ := glob(filepath.Join(path, "**/tokenizer.model"), "text/plain"); len(tks) > 0 {
  191. // some times tokenizer.model is in a subdirectory (e.g. meta-llama/Meta-Llama-3-8B)
  192. files = append(files, tks...)
  193. }
  194. for _, file := range files {
  195. f, err := os.Open(file)
  196. if err != nil {
  197. return "", err
  198. }
  199. defer f.Close()
  200. fi, err := f.Stat()
  201. if err != nil {
  202. return "", err
  203. }
  204. zfi, err := zip.FileInfoHeader(fi)
  205. if err != nil {
  206. return "", err
  207. }
  208. zf, err := zipfile.CreateHeader(zfi)
  209. if err != nil {
  210. return "", err
  211. }
  212. if _, err := io.Copy(zf, f); err != nil {
  213. return "", err
  214. }
  215. }
  216. return tempfile.Name(), nil
  217. }
  218. func createBlob(cmd *cobra.Command, client *api.Client, path string) (string, error) {
  219. bin, err := os.Open(path)
  220. if err != nil {
  221. return "", err
  222. }
  223. defer bin.Close()
  224. hash := sha256.New()
  225. if _, err := io.Copy(hash, bin); err != nil {
  226. return "", err
  227. }
  228. if _, err := bin.Seek(0, io.SeekStart); err != nil {
  229. return "", err
  230. }
  231. digest := fmt.Sprintf("sha256:%x", hash.Sum(nil))
  232. if err = client.CreateBlob(cmd.Context(), digest, bin); err != nil {
  233. return "", err
  234. }
  235. return digest, nil
  236. }
  237. func RunHandler(cmd *cobra.Command, args []string) error {
  238. client, err := api.ClientFromEnvironment()
  239. if err != nil {
  240. return err
  241. }
  242. name := args[0]
  243. // check if the model exists on the server
  244. show, err := client.Show(cmd.Context(), &api.ShowRequest{Name: name})
  245. var statusError api.StatusError
  246. switch {
  247. case errors.As(err, &statusError) && statusError.StatusCode == http.StatusNotFound:
  248. if err := PullHandler(cmd, []string{name}); err != nil {
  249. return err
  250. }
  251. show, err = client.Show(cmd.Context(), &api.ShowRequest{Name: name})
  252. if err != nil {
  253. return err
  254. }
  255. case err != nil:
  256. return err
  257. }
  258. interactive := true
  259. opts := runOptions{
  260. Model: args[0],
  261. WordWrap: os.Getenv("TERM") == "xterm-256color",
  262. Options: map[string]interface{}{},
  263. MultiModal: slices.Contains(show.Details.Families, "clip"),
  264. ParentModel: show.Details.ParentModel,
  265. }
  266. format, err := cmd.Flags().GetString("format")
  267. if err != nil {
  268. return err
  269. }
  270. opts.Format = format
  271. prompts := args[1:]
  272. // prepend stdin to the prompt if provided
  273. if !term.IsTerminal(int(os.Stdin.Fd())) {
  274. in, err := io.ReadAll(os.Stdin)
  275. if err != nil {
  276. return err
  277. }
  278. prompts = append([]string{string(in)}, prompts...)
  279. opts.WordWrap = false
  280. interactive = false
  281. }
  282. opts.Prompt = strings.Join(prompts, " ")
  283. if len(prompts) > 0 {
  284. interactive = false
  285. }
  286. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  287. if err != nil {
  288. return err
  289. }
  290. opts.WordWrap = !nowrap
  291. if !interactive {
  292. return generate(cmd, opts)
  293. }
  294. return generateInteractive(cmd, opts)
  295. }
  296. func errFromUnknownKey(unknownKeyErr error) error {
  297. // find SSH public key in the error message
  298. sshKeyPattern := `ssh-\w+ [^\s"]+`
  299. re := regexp.MustCompile(sshKeyPattern)
  300. matches := re.FindStringSubmatch(unknownKeyErr.Error())
  301. if len(matches) > 0 {
  302. serverPubKey := matches[0]
  303. localPubKey, err := auth.GetPublicKey()
  304. if err != nil {
  305. return unknownKeyErr
  306. }
  307. if runtime.GOOS == "linux" && serverPubKey != localPubKey {
  308. // try the ollama service public key
  309. svcPubKey, err := os.ReadFile("/usr/share/ollama/.ollama/id_ed25519.pub")
  310. if err != nil {
  311. return unknownKeyErr
  312. }
  313. localPubKey = strings.TrimSpace(string(svcPubKey))
  314. }
  315. // check if the returned public key matches the local public key, this prevents adding a remote key to the user's account
  316. if serverPubKey != localPubKey {
  317. return unknownKeyErr
  318. }
  319. var msg strings.Builder
  320. msg.WriteString(unknownKeyErr.Error())
  321. msg.WriteString("\n\nYour ollama key is:\n")
  322. msg.WriteString(localPubKey)
  323. msg.WriteString("\nAdd your key at:\n")
  324. msg.WriteString("https://ollama.com/settings/keys")
  325. return errors.New(msg.String())
  326. }
  327. return unknownKeyErr
  328. }
  329. func PushHandler(cmd *cobra.Command, args []string) error {
  330. client, err := api.ClientFromEnvironment()
  331. if err != nil {
  332. return err
  333. }
  334. insecure, err := cmd.Flags().GetBool("insecure")
  335. if err != nil {
  336. return err
  337. }
  338. p := progress.NewProgress(os.Stderr)
  339. defer p.Stop()
  340. bars := make(map[string]*progress.Bar)
  341. var status string
  342. var spinner *progress.Spinner
  343. fn := func(resp api.ProgressResponse) error {
  344. if resp.Digest != "" {
  345. if spinner != nil {
  346. spinner.Stop()
  347. }
  348. bar, ok := bars[resp.Digest]
  349. if !ok {
  350. bar = progress.NewBar(fmt.Sprintf("pushing %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  351. bars[resp.Digest] = bar
  352. p.Add(resp.Digest, bar)
  353. }
  354. bar.Set(resp.Completed)
  355. } else if status != resp.Status {
  356. if spinner != nil {
  357. spinner.Stop()
  358. }
  359. status = resp.Status
  360. spinner = progress.NewSpinner(status)
  361. p.Add(status, spinner)
  362. }
  363. return nil
  364. }
  365. request := api.PushRequest{Name: args[0], Insecure: insecure}
  366. if err := client.Push(cmd.Context(), &request, fn); err != nil {
  367. if spinner != nil {
  368. spinner.Stop()
  369. }
  370. if strings.Contains(err.Error(), "access denied") {
  371. return errors.New("you are not authorized to push to this namespace, create the model under a namespace you own")
  372. }
  373. host := model.ParseName(args[0]).Host
  374. isOllamaHost := strings.HasSuffix(host, ".ollama.ai") || strings.HasSuffix(host, ".ollama.com")
  375. if strings.Contains(err.Error(), errtypes.UnknownOllamaKeyErrMsg) && isOllamaHost {
  376. // the user has not added their ollama key to ollama.com
  377. // re-throw an error with a more user-friendly message
  378. return errFromUnknownKey(err)
  379. }
  380. return err
  381. }
  382. spinner.Stop()
  383. return nil
  384. }
  385. func ListHandler(cmd *cobra.Command, args []string) error {
  386. client, err := api.ClientFromEnvironment()
  387. if err != nil {
  388. return err
  389. }
  390. models, err := client.List(cmd.Context())
  391. if err != nil {
  392. return err
  393. }
  394. var data [][]string
  395. for _, m := range models.Models {
  396. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  397. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), format.HumanTime(m.ModifiedAt, "Never")})
  398. }
  399. }
  400. table := tablewriter.NewWriter(os.Stdout)
  401. table.SetHeader([]string{"NAME", "ID", "SIZE", "MODIFIED"})
  402. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  403. table.SetAlignment(tablewriter.ALIGN_LEFT)
  404. table.SetHeaderLine(false)
  405. table.SetBorder(false)
  406. table.SetNoWhiteSpace(true)
  407. table.SetTablePadding("\t")
  408. table.AppendBulk(data)
  409. table.Render()
  410. return nil
  411. }
  412. func DeleteHandler(cmd *cobra.Command, args []string) error {
  413. client, err := api.ClientFromEnvironment()
  414. if err != nil {
  415. return err
  416. }
  417. for _, name := range args {
  418. req := api.DeleteRequest{Name: name}
  419. if err := client.Delete(cmd.Context(), &req); err != nil {
  420. return err
  421. }
  422. fmt.Printf("deleted '%s'\n", name)
  423. }
  424. return nil
  425. }
  426. func ShowHandler(cmd *cobra.Command, args []string) error {
  427. client, err := api.ClientFromEnvironment()
  428. if err != nil {
  429. return err
  430. }
  431. if len(args) != 1 {
  432. return errors.New("missing model name")
  433. }
  434. license, errLicense := cmd.Flags().GetBool("license")
  435. modelfile, errModelfile := cmd.Flags().GetBool("modelfile")
  436. parameters, errParams := cmd.Flags().GetBool("parameters")
  437. system, errSystem := cmd.Flags().GetBool("system")
  438. template, errTemplate := cmd.Flags().GetBool("template")
  439. for _, boolErr := range []error{errLicense, errModelfile, errParams, errSystem, errTemplate} {
  440. if boolErr != nil {
  441. return errors.New("error retrieving flags")
  442. }
  443. }
  444. flagsSet := 0
  445. showType := ""
  446. if license {
  447. flagsSet++
  448. showType = "license"
  449. }
  450. if modelfile {
  451. flagsSet++
  452. showType = "modelfile"
  453. }
  454. if parameters {
  455. flagsSet++
  456. showType = "parameters"
  457. }
  458. if system {
  459. flagsSet++
  460. showType = "system"
  461. }
  462. if template {
  463. flagsSet++
  464. showType = "template"
  465. }
  466. if flagsSet > 1 {
  467. return errors.New("only one of '--license', '--modelfile', '--parameters', '--system', or '--template' can be specified")
  468. } else if flagsSet == 0 {
  469. return errors.New("one of '--license', '--modelfile', '--parameters', '--system', or '--template' must be specified")
  470. }
  471. req := api.ShowRequest{Name: args[0]}
  472. resp, err := client.Show(cmd.Context(), &req)
  473. if err != nil {
  474. return err
  475. }
  476. switch showType {
  477. case "license":
  478. fmt.Println(resp.License)
  479. case "modelfile":
  480. fmt.Println(resp.Modelfile)
  481. case "parameters":
  482. fmt.Println(resp.Parameters)
  483. case "system":
  484. fmt.Println(resp.System)
  485. case "template":
  486. fmt.Println(resp.Template)
  487. }
  488. return nil
  489. }
  490. func CopyHandler(cmd *cobra.Command, args []string) error {
  491. client, err := api.ClientFromEnvironment()
  492. if err != nil {
  493. return err
  494. }
  495. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  496. if err := client.Copy(cmd.Context(), &req); err != nil {
  497. return err
  498. }
  499. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  500. return nil
  501. }
  502. func PullHandler(cmd *cobra.Command, args []string) error {
  503. insecure, err := cmd.Flags().GetBool("insecure")
  504. if err != nil {
  505. return err
  506. }
  507. client, err := api.ClientFromEnvironment()
  508. if err != nil {
  509. return err
  510. }
  511. p := progress.NewProgress(os.Stderr)
  512. defer p.Stop()
  513. bars := make(map[string]*progress.Bar)
  514. var status string
  515. var spinner *progress.Spinner
  516. fn := func(resp api.ProgressResponse) error {
  517. if resp.Digest != "" {
  518. if spinner != nil {
  519. spinner.Stop()
  520. }
  521. bar, ok := bars[resp.Digest]
  522. if !ok {
  523. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  524. bars[resp.Digest] = bar
  525. p.Add(resp.Digest, bar)
  526. }
  527. bar.Set(resp.Completed)
  528. } else if status != resp.Status {
  529. if spinner != nil {
  530. spinner.Stop()
  531. }
  532. status = resp.Status
  533. spinner = progress.NewSpinner(status)
  534. p.Add(status, spinner)
  535. }
  536. return nil
  537. }
  538. request := api.PullRequest{Name: args[0], Insecure: insecure}
  539. if err := client.Pull(cmd.Context(), &request, fn); err != nil {
  540. return err
  541. }
  542. return nil
  543. }
  544. type generateContextKey string
  545. type runOptions struct {
  546. Model string
  547. ParentModel string
  548. Prompt string
  549. Messages []api.Message
  550. WordWrap bool
  551. Format string
  552. System string
  553. Template string
  554. Images []api.ImageData
  555. Options map[string]interface{}
  556. MultiModal bool
  557. }
  558. type displayResponseState struct {
  559. lineLength int
  560. wordBuffer string
  561. }
  562. func displayResponse(content string, wordWrap bool, state *displayResponseState) {
  563. termWidth, _, _ := term.GetSize(int(os.Stdout.Fd()))
  564. if wordWrap && termWidth >= 10 {
  565. for _, ch := range content {
  566. if state.lineLength+1 > termWidth-5 {
  567. if len(state.wordBuffer) > termWidth-10 {
  568. fmt.Printf("%s%c", state.wordBuffer, ch)
  569. state.wordBuffer = ""
  570. state.lineLength = 0
  571. continue
  572. }
  573. // backtrack the length of the last word and clear to the end of the line
  574. fmt.Printf("\x1b[%dD\x1b[K\n", len(state.wordBuffer))
  575. fmt.Printf("%s%c", state.wordBuffer, ch)
  576. state.lineLength = len(state.wordBuffer) + 1
  577. } else {
  578. fmt.Print(string(ch))
  579. state.lineLength += 1
  580. switch ch {
  581. case ' ':
  582. state.wordBuffer = ""
  583. case '\n':
  584. state.lineLength = 0
  585. default:
  586. state.wordBuffer += string(ch)
  587. }
  588. }
  589. }
  590. } else {
  591. fmt.Printf("%s%s", state.wordBuffer, content)
  592. if len(state.wordBuffer) > 0 {
  593. state.wordBuffer = ""
  594. }
  595. }
  596. }
  597. func chat(cmd *cobra.Command, opts runOptions) (*api.Message, error) {
  598. client, err := api.ClientFromEnvironment()
  599. if err != nil {
  600. return nil, err
  601. }
  602. p := progress.NewProgress(os.Stderr)
  603. defer p.StopAndClear()
  604. spinner := progress.NewSpinner("")
  605. p.Add("", spinner)
  606. cancelCtx, cancel := context.WithCancel(cmd.Context())
  607. defer cancel()
  608. sigChan := make(chan os.Signal, 1)
  609. signal.Notify(sigChan, syscall.SIGINT)
  610. go func() {
  611. <-sigChan
  612. cancel()
  613. }()
  614. var state *displayResponseState = &displayResponseState{}
  615. var latest api.ChatResponse
  616. var fullResponse strings.Builder
  617. var role string
  618. fn := func(response api.ChatResponse) error {
  619. p.StopAndClear()
  620. latest = response
  621. role = response.Message.Role
  622. content := response.Message.Content
  623. fullResponse.WriteString(content)
  624. displayResponse(content, opts.WordWrap, state)
  625. return nil
  626. }
  627. req := &api.ChatRequest{
  628. Model: opts.Model,
  629. Messages: opts.Messages,
  630. Format: opts.Format,
  631. Options: opts.Options,
  632. }
  633. if err := client.Chat(cancelCtx, req, fn); err != nil {
  634. if errors.Is(err, context.Canceled) {
  635. return nil, nil
  636. }
  637. return nil, err
  638. }
  639. if len(opts.Messages) > 0 {
  640. fmt.Println()
  641. fmt.Println()
  642. }
  643. verbose, err := cmd.Flags().GetBool("verbose")
  644. if err != nil {
  645. return nil, err
  646. }
  647. if verbose {
  648. latest.Summary()
  649. }
  650. return &api.Message{Role: role, Content: fullResponse.String()}, nil
  651. }
  652. func generate(cmd *cobra.Command, opts runOptions) error {
  653. client, err := api.ClientFromEnvironment()
  654. if err != nil {
  655. return err
  656. }
  657. p := progress.NewProgress(os.Stderr)
  658. defer p.StopAndClear()
  659. spinner := progress.NewSpinner("")
  660. p.Add("", spinner)
  661. var latest api.GenerateResponse
  662. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  663. if !ok {
  664. generateContext = []int{}
  665. }
  666. ctx, cancel := context.WithCancel(cmd.Context())
  667. defer cancel()
  668. sigChan := make(chan os.Signal, 1)
  669. signal.Notify(sigChan, syscall.SIGINT)
  670. go func() {
  671. <-sigChan
  672. cancel()
  673. }()
  674. var state *displayResponseState = &displayResponseState{}
  675. fn := func(response api.GenerateResponse) error {
  676. p.StopAndClear()
  677. latest = response
  678. content := response.Response
  679. displayResponse(content, opts.WordWrap, state)
  680. return nil
  681. }
  682. if opts.MultiModal {
  683. opts.Prompt, opts.Images, err = extractFileData(opts.Prompt)
  684. if err != nil {
  685. return err
  686. }
  687. }
  688. request := api.GenerateRequest{
  689. Model: opts.Model,
  690. Prompt: opts.Prompt,
  691. Context: generateContext,
  692. Images: opts.Images,
  693. Format: opts.Format,
  694. System: opts.System,
  695. Template: opts.Template,
  696. Options: opts.Options,
  697. }
  698. if err := client.Generate(ctx, &request, fn); err != nil {
  699. if errors.Is(err, context.Canceled) {
  700. return nil
  701. }
  702. return err
  703. }
  704. if opts.Prompt != "" {
  705. fmt.Println()
  706. fmt.Println()
  707. }
  708. if !latest.Done {
  709. return nil
  710. }
  711. verbose, err := cmd.Flags().GetBool("verbose")
  712. if err != nil {
  713. return err
  714. }
  715. if verbose {
  716. latest.Summary()
  717. }
  718. ctx = context.WithValue(cmd.Context(), generateContextKey("context"), latest.Context)
  719. cmd.SetContext(ctx)
  720. return nil
  721. }
  722. func RunServer(cmd *cobra.Command, _ []string) error {
  723. // retrieve the OLLAMA_HOST environment variable
  724. ollamaHost, err := api.GetOllamaHost()
  725. if err != nil {
  726. return err
  727. }
  728. if err := initializeKeypair(); err != nil {
  729. return err
  730. }
  731. ln, err := net.Listen("tcp", net.JoinHostPort(ollamaHost.Host, ollamaHost.Port))
  732. if err != nil {
  733. return err
  734. }
  735. err = server.Serve(ln)
  736. if errors.Is(err, http.ErrServerClosed) {
  737. return nil
  738. }
  739. return err
  740. }
  741. func initializeKeypair() error {
  742. home, err := os.UserHomeDir()
  743. if err != nil {
  744. return err
  745. }
  746. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  747. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  748. _, err = os.Stat(privKeyPath)
  749. if os.IsNotExist(err) {
  750. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  751. cryptoPublicKey, cryptoPrivateKey, err := ed25519.GenerateKey(rand.Reader)
  752. if err != nil {
  753. return err
  754. }
  755. privateKeyBytes, err := ssh.MarshalPrivateKey(cryptoPrivateKey, "")
  756. if err != nil {
  757. return err
  758. }
  759. if err := os.MkdirAll(filepath.Dir(privKeyPath), 0o755); err != nil {
  760. return fmt.Errorf("could not create directory %w", err)
  761. }
  762. if err := os.WriteFile(privKeyPath, pem.EncodeToMemory(privateKeyBytes), 0o600); err != nil {
  763. return err
  764. }
  765. sshPublicKey, err := ssh.NewPublicKey(cryptoPublicKey)
  766. if err != nil {
  767. return err
  768. }
  769. publicKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey)
  770. if err := os.WriteFile(pubKeyPath, publicKeyBytes, 0o644); err != nil {
  771. return err
  772. }
  773. fmt.Printf("Your new public key is: \n\n%s\n", publicKeyBytes)
  774. }
  775. return nil
  776. }
  777. //nolint:unused
  778. func waitForServer(ctx context.Context, client *api.Client) error {
  779. // wait for the server to start
  780. timeout := time.After(5 * time.Second)
  781. tick := time.Tick(500 * time.Millisecond)
  782. for {
  783. select {
  784. case <-timeout:
  785. return errors.New("timed out waiting for server to start")
  786. case <-tick:
  787. if err := client.Heartbeat(ctx); err == nil {
  788. return nil // server has started
  789. }
  790. }
  791. }
  792. }
  793. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  794. client, err := api.ClientFromEnvironment()
  795. if err != nil {
  796. return err
  797. }
  798. if err := client.Heartbeat(cmd.Context()); err != nil {
  799. if !strings.Contains(err.Error(), " refused") {
  800. return err
  801. }
  802. if err := startApp(cmd.Context(), client); err != nil {
  803. return fmt.Errorf("could not connect to ollama app, is it running?")
  804. }
  805. }
  806. return nil
  807. }
  808. func versionHandler(cmd *cobra.Command, _ []string) {
  809. client, err := api.ClientFromEnvironment()
  810. if err != nil {
  811. return
  812. }
  813. serverVersion, err := client.Version(cmd.Context())
  814. if err != nil {
  815. fmt.Println("Warning: could not connect to a running Ollama instance")
  816. }
  817. if serverVersion != "" {
  818. fmt.Printf("ollama version is %s\n", serverVersion)
  819. }
  820. if serverVersion != version.Version {
  821. fmt.Printf("Warning: client version is %s\n", version.Version)
  822. }
  823. }
  824. func appendHostEnvDocs(cmd *cobra.Command) {
  825. const hostEnvDocs = `
  826. Environment Variables:
  827. OLLAMA_HOST The host:port or base URL of the Ollama server (e.g. http://localhost:11434)
  828. `
  829. cmd.SetUsageTemplate(cmd.UsageTemplate() + hostEnvDocs)
  830. }
  831. func NewCLI() *cobra.Command {
  832. log.SetFlags(log.LstdFlags | log.Lshortfile)
  833. cobra.EnableCommandSorting = false
  834. if runtime.GOOS == "windows" {
  835. console.ConsoleFromFile(os.Stdin) //nolint:errcheck
  836. }
  837. rootCmd := &cobra.Command{
  838. Use: "ollama",
  839. Short: "Large language model runner",
  840. SilenceUsage: true,
  841. SilenceErrors: true,
  842. CompletionOptions: cobra.CompletionOptions{
  843. DisableDefaultCmd: true,
  844. },
  845. Run: func(cmd *cobra.Command, args []string) {
  846. if version, _ := cmd.Flags().GetBool("version"); version {
  847. versionHandler(cmd, args)
  848. return
  849. }
  850. cmd.Print(cmd.UsageString())
  851. },
  852. }
  853. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  854. createCmd := &cobra.Command{
  855. Use: "create MODEL",
  856. Short: "Create a model from a Modelfile",
  857. Args: cobra.ExactArgs(1),
  858. PreRunE: checkServerHeartbeat,
  859. RunE: CreateHandler,
  860. }
  861. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile")
  862. createCmd.Flags().StringP("quantize", "q", "", "Quantize model to this level (e.g. q4_0)")
  863. showCmd := &cobra.Command{
  864. Use: "show MODEL",
  865. Short: "Show information for a model",
  866. Args: cobra.ExactArgs(1),
  867. PreRunE: checkServerHeartbeat,
  868. RunE: ShowHandler,
  869. }
  870. showCmd.Flags().Bool("license", false, "Show license of a model")
  871. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  872. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  873. showCmd.Flags().Bool("template", false, "Show template of a model")
  874. showCmd.Flags().Bool("system", false, "Show system message of a model")
  875. runCmd := &cobra.Command{
  876. Use: "run MODEL [PROMPT]",
  877. Short: "Run a model",
  878. Args: cobra.MinimumNArgs(1),
  879. PreRunE: checkServerHeartbeat,
  880. RunE: RunHandler,
  881. }
  882. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  883. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  884. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  885. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  886. serveCmd := &cobra.Command{
  887. Use: "serve",
  888. Aliases: []string{"start"},
  889. Short: "Start ollama",
  890. Args: cobra.ExactArgs(0),
  891. RunE: RunServer,
  892. }
  893. serveCmd.SetUsageTemplate(serveCmd.UsageTemplate() + `
  894. Environment Variables:
  895. OLLAMA_HOST The host:port to bind to (default "127.0.0.1:11434")
  896. OLLAMA_ORIGINS A comma separated list of allowed origins.
  897. OLLAMA_MODELS The path to the models directory (default is "~/.ollama/models")
  898. OLLAMA_KEEP_ALIVE The duration that models stay loaded in memory (default is "5m")
  899. OLLAMA_DEBUG Set to 1 to enable additional debug logging
  900. `)
  901. pullCmd := &cobra.Command{
  902. Use: "pull MODEL",
  903. Short: "Pull a model from a registry",
  904. Args: cobra.ExactArgs(1),
  905. PreRunE: checkServerHeartbeat,
  906. RunE: PullHandler,
  907. }
  908. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  909. pushCmd := &cobra.Command{
  910. Use: "push MODEL",
  911. Short: "Push a model to a registry",
  912. Args: cobra.ExactArgs(1),
  913. PreRunE: checkServerHeartbeat,
  914. RunE: PushHandler,
  915. }
  916. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  917. listCmd := &cobra.Command{
  918. Use: "list",
  919. Aliases: []string{"ls"},
  920. Short: "List models",
  921. PreRunE: checkServerHeartbeat,
  922. RunE: ListHandler,
  923. }
  924. copyCmd := &cobra.Command{
  925. Use: "cp SOURCE DESTINATION",
  926. Short: "Copy a model",
  927. Args: cobra.ExactArgs(2),
  928. PreRunE: checkServerHeartbeat,
  929. RunE: CopyHandler,
  930. }
  931. deleteCmd := &cobra.Command{
  932. Use: "rm MODEL [MODEL...]",
  933. Short: "Remove a model",
  934. Args: cobra.MinimumNArgs(1),
  935. PreRunE: checkServerHeartbeat,
  936. RunE: DeleteHandler,
  937. }
  938. for _, cmd := range []*cobra.Command{
  939. createCmd,
  940. showCmd,
  941. runCmd,
  942. pullCmd,
  943. pushCmd,
  944. listCmd,
  945. copyCmd,
  946. deleteCmd,
  947. } {
  948. appendHostEnvDocs(cmd)
  949. }
  950. rootCmd.AddCommand(
  951. serveCmd,
  952. createCmd,
  953. showCmd,
  954. runCmd,
  955. pullCmd,
  956. pushCmd,
  957. listCmd,
  958. copyCmd,
  959. deleteCmd,
  960. )
  961. return rootCmd
  962. }