cmd.go 25 KB

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