cmd.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. package cmd
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/ed25519"
  6. "crypto/rand"
  7. "crypto/sha256"
  8. "encoding/pem"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "log"
  13. "net"
  14. "net/http"
  15. "os"
  16. "os/exec"
  17. "os/signal"
  18. "path/filepath"
  19. "runtime"
  20. "strings"
  21. "syscall"
  22. "time"
  23. "github.com/olekukonko/tablewriter"
  24. "github.com/spf13/cobra"
  25. "golang.org/x/crypto/ssh"
  26. "golang.org/x/term"
  27. "github.com/jmorganca/ollama/api"
  28. "github.com/jmorganca/ollama/format"
  29. "github.com/jmorganca/ollama/parser"
  30. "github.com/jmorganca/ollama/progress"
  31. "github.com/jmorganca/ollama/server"
  32. "github.com/jmorganca/ollama/version"
  33. )
  34. type ImageData []byte
  35. func CreateHandler(cmd *cobra.Command, args []string) error {
  36. filename, _ := cmd.Flags().GetString("file")
  37. filename, err := filepath.Abs(filename)
  38. if err != nil {
  39. return err
  40. }
  41. client, err := api.ClientFromEnvironment()
  42. if err != nil {
  43. return err
  44. }
  45. p := progress.NewProgress(os.Stderr)
  46. defer p.Stop()
  47. bars := make(map[string]*progress.Bar)
  48. modelfile, err := os.ReadFile(filename)
  49. if err != nil {
  50. return err
  51. }
  52. commands, err := parser.Parse(bytes.NewReader(modelfile))
  53. if err != nil {
  54. return err
  55. }
  56. home, err := os.UserHomeDir()
  57. if err != nil {
  58. return err
  59. }
  60. status := "transferring model data"
  61. spinner := progress.NewSpinner(status)
  62. p.Add(status, spinner)
  63. for _, c := range commands {
  64. switch c.Name {
  65. case "model", "adapter":
  66. path := c.Args
  67. if path == "~" {
  68. path = home
  69. } else if strings.HasPrefix(path, "~/") {
  70. path = filepath.Join(home, path[2:])
  71. }
  72. if !filepath.IsAbs(path) {
  73. path = filepath.Join(filepath.Dir(filename), path)
  74. }
  75. bin, err := os.Open(path)
  76. if errors.Is(err, os.ErrNotExist) && c.Name == "model" {
  77. continue
  78. } else if err != nil {
  79. return err
  80. }
  81. defer bin.Close()
  82. hash := sha256.New()
  83. if _, err := io.Copy(hash, bin); err != nil {
  84. return err
  85. }
  86. bin.Seek(0, io.SeekStart)
  87. digest := fmt.Sprintf("sha256:%x", hash.Sum(nil))
  88. if err = client.CreateBlob(cmd.Context(), digest, bin); err != nil {
  89. return err
  90. }
  91. modelfile = bytes.ReplaceAll(modelfile, []byte(c.Args), []byte("@"+digest))
  92. }
  93. }
  94. fn := func(resp api.ProgressResponse) error {
  95. if resp.Digest != "" {
  96. spinner.Stop()
  97. bar, ok := bars[resp.Digest]
  98. if !ok {
  99. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  100. bars[resp.Digest] = bar
  101. p.Add(resp.Digest, bar)
  102. }
  103. bar.Set(resp.Completed)
  104. } else if status != resp.Status {
  105. spinner.Stop()
  106. status = resp.Status
  107. spinner = progress.NewSpinner(status)
  108. p.Add(status, spinner)
  109. }
  110. return nil
  111. }
  112. request := api.CreateRequest{Name: args[0], Modelfile: string(modelfile)}
  113. if err := client.Create(cmd.Context(), &request, fn); err != nil {
  114. return err
  115. }
  116. return nil
  117. }
  118. func RunHandler(cmd *cobra.Command, args []string) error {
  119. client, err := api.ClientFromEnvironment()
  120. if err != nil {
  121. return err
  122. }
  123. name := args[0]
  124. // check if the model exists on the server
  125. model, err := client.Show(cmd.Context(), &api.ShowRequest{Model: name})
  126. var statusError api.StatusError
  127. switch {
  128. case errors.As(err, &statusError) && statusError.StatusCode == http.StatusNotFound:
  129. if err := PullHandler(cmd, []string{name}); err != nil {
  130. return err
  131. }
  132. case err != nil:
  133. return err
  134. }
  135. if model.Details.Format != "gguf" {
  136. // pull and retry to see if the model has been updated
  137. parts := strings.Split(name, string(os.PathSeparator))
  138. if len(parts) == 1 {
  139. // this is a library model, log some info
  140. fmt.Fprintln(os.Stderr, "This model is no longer compatible with Ollama. Pulling a new version...")
  141. }
  142. if err := PullHandler(cmd, []string{name}); err != nil {
  143. fmt.Printf("Error: %s\n", err)
  144. return fmt.Errorf("unsupported model, please update this model to gguf format") // relay the original error
  145. }
  146. }
  147. return RunGenerate(cmd, args)
  148. }
  149. func PushHandler(cmd *cobra.Command, args []string) error {
  150. client, err := api.ClientFromEnvironment()
  151. if err != nil {
  152. return err
  153. }
  154. insecure, err := cmd.Flags().GetBool("insecure")
  155. if err != nil {
  156. return err
  157. }
  158. p := progress.NewProgress(os.Stderr)
  159. defer p.Stop()
  160. bars := make(map[string]*progress.Bar)
  161. var status string
  162. var spinner *progress.Spinner
  163. fn := func(resp api.ProgressResponse) error {
  164. if resp.Digest != "" {
  165. if spinner != nil {
  166. spinner.Stop()
  167. }
  168. bar, ok := bars[resp.Digest]
  169. if !ok {
  170. bar = progress.NewBar(fmt.Sprintf("pushing %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  171. bars[resp.Digest] = bar
  172. p.Add(resp.Digest, bar)
  173. }
  174. bar.Set(resp.Completed)
  175. } else if status != resp.Status {
  176. if spinner != nil {
  177. spinner.Stop()
  178. }
  179. status = resp.Status
  180. spinner = progress.NewSpinner(status)
  181. p.Add(status, spinner)
  182. }
  183. return nil
  184. }
  185. request := api.PushRequest{Name: args[0], Insecure: insecure}
  186. if err := client.Push(cmd.Context(), &request, fn); err != nil {
  187. return err
  188. }
  189. spinner.Stop()
  190. return nil
  191. }
  192. func ListHandler(cmd *cobra.Command, args []string) error {
  193. client, err := api.ClientFromEnvironment()
  194. if err != nil {
  195. return err
  196. }
  197. models, err := client.List(cmd.Context())
  198. if err != nil {
  199. return err
  200. }
  201. var data [][]string
  202. for _, m := range models.Models {
  203. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  204. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), format.HumanTime(m.ModifiedAt, "Never")})
  205. }
  206. }
  207. table := tablewriter.NewWriter(os.Stdout)
  208. table.SetHeader([]string{"NAME", "ID", "SIZE", "MODIFIED"})
  209. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  210. table.SetAlignment(tablewriter.ALIGN_LEFT)
  211. table.SetHeaderLine(false)
  212. table.SetBorder(false)
  213. table.SetNoWhiteSpace(true)
  214. table.SetTablePadding("\t")
  215. table.AppendBulk(data)
  216. table.Render()
  217. return nil
  218. }
  219. func DeleteHandler(cmd *cobra.Command, args []string) error {
  220. client, err := api.ClientFromEnvironment()
  221. if err != nil {
  222. return err
  223. }
  224. for _, name := range args {
  225. req := api.DeleteRequest{Name: name}
  226. if err := client.Delete(cmd.Context(), &req); err != nil {
  227. return err
  228. }
  229. fmt.Printf("deleted '%s'\n", name)
  230. }
  231. return nil
  232. }
  233. func ShowHandler(cmd *cobra.Command, args []string) error {
  234. client, err := api.ClientFromEnvironment()
  235. if err != nil {
  236. return err
  237. }
  238. if len(args) != 1 {
  239. return errors.New("missing model name")
  240. }
  241. license, errLicense := cmd.Flags().GetBool("license")
  242. modelfile, errModelfile := cmd.Flags().GetBool("modelfile")
  243. parameters, errParams := cmd.Flags().GetBool("parameters")
  244. system, errSystem := cmd.Flags().GetBool("system")
  245. template, errTemplate := cmd.Flags().GetBool("template")
  246. for _, boolErr := range []error{errLicense, errModelfile, errParams, errSystem, errTemplate} {
  247. if boolErr != nil {
  248. return errors.New("error retrieving flags")
  249. }
  250. }
  251. flagsSet := 0
  252. showType := ""
  253. if license {
  254. flagsSet++
  255. showType = "license"
  256. }
  257. if modelfile {
  258. flagsSet++
  259. showType = "modelfile"
  260. }
  261. if parameters {
  262. flagsSet++
  263. showType = "parameters"
  264. }
  265. if system {
  266. flagsSet++
  267. showType = "system"
  268. }
  269. if template {
  270. flagsSet++
  271. showType = "template"
  272. }
  273. if flagsSet > 1 {
  274. return errors.New("only one of '--license', '--modelfile', '--parameters', '--system', or '--template' can be specified")
  275. } else if flagsSet == 0 {
  276. return errors.New("one of '--license', '--modelfile', '--parameters', '--system', or '--template' must be specified")
  277. }
  278. req := api.ShowRequest{Model: args[0]}
  279. resp, err := client.Show(cmd.Context(), &req)
  280. if err != nil {
  281. return err
  282. }
  283. switch showType {
  284. case "license":
  285. fmt.Println(resp.License)
  286. case "modelfile":
  287. fmt.Println(resp.Modelfile)
  288. case "parameters":
  289. fmt.Println(resp.Parameters)
  290. case "system":
  291. fmt.Println(resp.System)
  292. case "template":
  293. fmt.Println(resp.Template)
  294. }
  295. return nil
  296. }
  297. func CopyHandler(cmd *cobra.Command, args []string) error {
  298. client, err := api.ClientFromEnvironment()
  299. if err != nil {
  300. return err
  301. }
  302. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  303. if err := client.Copy(cmd.Context(), &req); err != nil {
  304. return err
  305. }
  306. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  307. return nil
  308. }
  309. func PullHandler(cmd *cobra.Command, args []string) error {
  310. insecure, err := cmd.Flags().GetBool("insecure")
  311. if err != nil {
  312. return err
  313. }
  314. client, err := api.ClientFromEnvironment()
  315. if err != nil {
  316. return err
  317. }
  318. p := progress.NewProgress(os.Stderr)
  319. defer p.Stop()
  320. bars := make(map[string]*progress.Bar)
  321. var status string
  322. var spinner *progress.Spinner
  323. fn := func(resp api.ProgressResponse) error {
  324. if resp.Digest != "" {
  325. if spinner != nil {
  326. spinner.Stop()
  327. }
  328. bar, ok := bars[resp.Digest]
  329. if !ok {
  330. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  331. bars[resp.Digest] = bar
  332. p.Add(resp.Digest, bar)
  333. }
  334. bar.Set(resp.Completed)
  335. } else if status != resp.Status {
  336. if spinner != nil {
  337. spinner.Stop()
  338. }
  339. status = resp.Status
  340. spinner = progress.NewSpinner(status)
  341. p.Add(status, spinner)
  342. }
  343. return nil
  344. }
  345. request := api.PullRequest{Name: args[0], Insecure: insecure}
  346. if err := client.Pull(cmd.Context(), &request, fn); err != nil {
  347. return err
  348. }
  349. return nil
  350. }
  351. func RunGenerate(cmd *cobra.Command, args []string) error {
  352. interactive := true
  353. opts := generateOptions{
  354. Model: args[0],
  355. WordWrap: os.Getenv("TERM") == "xterm-256color",
  356. Options: map[string]interface{}{},
  357. Images: []ImageData{},
  358. }
  359. format, err := cmd.Flags().GetString("format")
  360. if err != nil {
  361. return err
  362. }
  363. opts.Format = format
  364. prompts := args[1:]
  365. // prepend stdin to the prompt if provided
  366. if !term.IsTerminal(int(os.Stdin.Fd())) {
  367. in, err := io.ReadAll(os.Stdin)
  368. if err != nil {
  369. return err
  370. }
  371. prompts = append([]string{string(in)}, prompts...)
  372. opts.WordWrap = false
  373. interactive = false
  374. }
  375. opts.Prompt = strings.Join(prompts, " ")
  376. if len(prompts) > 0 {
  377. interactive = false
  378. }
  379. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  380. if err != nil {
  381. return err
  382. }
  383. opts.WordWrap = !nowrap
  384. if !interactive {
  385. return generate(cmd, opts)
  386. }
  387. return generateInteractive(cmd, opts)
  388. }
  389. type generateContextKey string
  390. type generateOptions struct {
  391. Model string
  392. Prompt string
  393. WordWrap bool
  394. Format string
  395. System string
  396. Template string
  397. Images []ImageData
  398. Options map[string]interface{}
  399. }
  400. func generate(cmd *cobra.Command, opts generateOptions) error {
  401. client, err := api.ClientFromEnvironment()
  402. if err != nil {
  403. return err
  404. }
  405. p := progress.NewProgress(os.Stderr)
  406. defer p.StopAndClear()
  407. spinner := progress.NewSpinner("")
  408. p.Add("", spinner)
  409. var latest api.GenerateResponse
  410. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  411. if !ok {
  412. generateContext = []int{}
  413. }
  414. termWidth, _, err := term.GetSize(int(os.Stdout.Fd()))
  415. if err != nil {
  416. opts.WordWrap = false
  417. }
  418. ctx, cancel := context.WithCancel(cmd.Context())
  419. defer cancel()
  420. sigChan := make(chan os.Signal, 1)
  421. signal.Notify(sigChan, syscall.SIGINT)
  422. go func() {
  423. <-sigChan
  424. cancel()
  425. }()
  426. var currentLineLength int
  427. var wordBuffer string
  428. fn := func(response api.GenerateResponse) error {
  429. p.StopAndClear()
  430. latest = response
  431. termWidth, _, _ = term.GetSize(int(os.Stdout.Fd()))
  432. if opts.WordWrap && termWidth >= 10 {
  433. for _, ch := range response.Response {
  434. if currentLineLength+1 > termWidth-5 {
  435. if len(wordBuffer) > termWidth-10 {
  436. fmt.Printf("%s%c", wordBuffer, ch)
  437. wordBuffer = ""
  438. currentLineLength = 0
  439. continue
  440. }
  441. // backtrack the length of the last word and clear to the end of the line
  442. fmt.Printf("\x1b[%dD\x1b[K\n", len(wordBuffer))
  443. fmt.Printf("%s%c", wordBuffer, ch)
  444. currentLineLength = len(wordBuffer) + 1
  445. } else {
  446. fmt.Print(string(ch))
  447. currentLineLength += 1
  448. switch ch {
  449. case ' ':
  450. wordBuffer = ""
  451. case '\n':
  452. currentLineLength = 0
  453. default:
  454. wordBuffer += string(ch)
  455. }
  456. }
  457. }
  458. } else {
  459. fmt.Printf("%s%s", wordBuffer, response.Response)
  460. if len(wordBuffer) > 0 {
  461. wordBuffer = ""
  462. }
  463. }
  464. return nil
  465. }
  466. images := make([]api.ImageData, 0)
  467. for _, i := range opts.Images {
  468. images = append(images, api.ImageData(i))
  469. }
  470. request := api.GenerateRequest{
  471. Model: opts.Model,
  472. Prompt: opts.Prompt,
  473. Context: generateContext,
  474. Format: opts.Format,
  475. System: opts.System,
  476. Template: opts.Template,
  477. Options: opts.Options,
  478. Images: images,
  479. }
  480. if err := client.Generate(ctx, &request, fn); err != nil {
  481. if errors.Is(err, context.Canceled) {
  482. return nil
  483. }
  484. return err
  485. }
  486. if opts.Prompt != "" {
  487. fmt.Println()
  488. fmt.Println()
  489. }
  490. if !latest.Done {
  491. return nil
  492. }
  493. verbose, err := cmd.Flags().GetBool("verbose")
  494. if err != nil {
  495. return err
  496. }
  497. if verbose {
  498. latest.Summary()
  499. }
  500. ctx = context.WithValue(cmd.Context(), generateContextKey("context"), latest.Context)
  501. cmd.SetContext(ctx)
  502. return nil
  503. }
  504. func RunServer(cmd *cobra.Command, _ []string) error {
  505. host, port, err := net.SplitHostPort(os.Getenv("OLLAMA_HOST"))
  506. if err != nil {
  507. host, port = "127.0.0.1", "11434"
  508. if ip := net.ParseIP(strings.Trim(os.Getenv("OLLAMA_HOST"), "[]")); ip != nil {
  509. host = ip.String()
  510. }
  511. }
  512. if err := initializeKeypair(); err != nil {
  513. return err
  514. }
  515. ln, err := net.Listen("tcp", net.JoinHostPort(host, port))
  516. if err != nil {
  517. return err
  518. }
  519. return server.Serve(ln)
  520. }
  521. func initializeKeypair() error {
  522. home, err := os.UserHomeDir()
  523. if err != nil {
  524. return err
  525. }
  526. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  527. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  528. _, err = os.Stat(privKeyPath)
  529. if os.IsNotExist(err) {
  530. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  531. _, privKey, err := ed25519.GenerateKey(rand.Reader)
  532. if err != nil {
  533. return err
  534. }
  535. privKeyBytes, err := format.OpenSSHPrivateKey(privKey, "")
  536. if err != nil {
  537. return err
  538. }
  539. err = os.MkdirAll(filepath.Dir(privKeyPath), 0o755)
  540. if err != nil {
  541. return fmt.Errorf("could not create directory %w", err)
  542. }
  543. err = os.WriteFile(privKeyPath, pem.EncodeToMemory(privKeyBytes), 0o600)
  544. if err != nil {
  545. return err
  546. }
  547. sshPrivateKey, err := ssh.NewSignerFromKey(privKey)
  548. if err != nil {
  549. return err
  550. }
  551. pubKeyData := ssh.MarshalAuthorizedKey(sshPrivateKey.PublicKey())
  552. err = os.WriteFile(pubKeyPath, pubKeyData, 0o644)
  553. if err != nil {
  554. return err
  555. }
  556. fmt.Printf("Your new public key is: \n\n%s\n", string(pubKeyData))
  557. }
  558. return nil
  559. }
  560. func startMacApp(ctx context.Context, client *api.Client) error {
  561. exe, err := os.Executable()
  562. if err != nil {
  563. return err
  564. }
  565. link, err := os.Readlink(exe)
  566. if err != nil {
  567. return err
  568. }
  569. if !strings.Contains(link, "Ollama.app") {
  570. return fmt.Errorf("could not find ollama app")
  571. }
  572. path := strings.Split(link, "Ollama.app")
  573. if err := exec.Command("/usr/bin/open", "-a", path[0]+"Ollama.app").Run(); err != nil {
  574. return err
  575. }
  576. // wait for the server to start
  577. timeout := time.After(5 * time.Second)
  578. tick := time.Tick(500 * time.Millisecond)
  579. for {
  580. select {
  581. case <-timeout:
  582. return errors.New("timed out waiting for server to start")
  583. case <-tick:
  584. if err := client.Heartbeat(ctx); err == nil {
  585. return nil // server has started
  586. }
  587. }
  588. }
  589. }
  590. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  591. client, err := api.ClientFromEnvironment()
  592. if err != nil {
  593. return err
  594. }
  595. if err := client.Heartbeat(cmd.Context()); err != nil {
  596. if !strings.Contains(err.Error(), "connection refused") {
  597. return err
  598. }
  599. if runtime.GOOS == "darwin" {
  600. if err := startMacApp(cmd.Context(), client); err != nil {
  601. return fmt.Errorf("could not connect to ollama app, is it running?")
  602. }
  603. } else {
  604. return fmt.Errorf("could not connect to ollama server, run 'ollama serve' to start it")
  605. }
  606. }
  607. return nil
  608. }
  609. func versionHandler(cmd *cobra.Command, _ []string) {
  610. client, err := api.ClientFromEnvironment()
  611. if err != nil {
  612. return
  613. }
  614. serverVersion, err := client.Version(cmd.Context())
  615. if err != nil {
  616. fmt.Println("Warning: could not connect to a running Ollama instance")
  617. }
  618. if serverVersion != "" {
  619. fmt.Printf("ollama version is %s\n", serverVersion)
  620. }
  621. if serverVersion != version.Version {
  622. fmt.Printf("Warning: client version is %s\n", version.Version)
  623. }
  624. }
  625. func NewCLI() *cobra.Command {
  626. log.SetFlags(log.LstdFlags | log.Lshortfile)
  627. cobra.EnableCommandSorting = false
  628. rootCmd := &cobra.Command{
  629. Use: "ollama",
  630. Short: "Large language model runner",
  631. SilenceUsage: true,
  632. SilenceErrors: true,
  633. CompletionOptions: cobra.CompletionOptions{
  634. DisableDefaultCmd: true,
  635. },
  636. Run: func(cmd *cobra.Command, args []string) {
  637. if version, _ := cmd.Flags().GetBool("version"); version {
  638. versionHandler(cmd, args)
  639. return
  640. }
  641. cmd.Print(cmd.UsageString())
  642. },
  643. }
  644. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  645. createCmd := &cobra.Command{
  646. Use: "create MODEL",
  647. Short: "Create a model from a Modelfile",
  648. Args: cobra.ExactArgs(1),
  649. PreRunE: checkServerHeartbeat,
  650. RunE: CreateHandler,
  651. }
  652. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
  653. showCmd := &cobra.Command{
  654. Use: "show MODEL",
  655. Short: "Show information for a model",
  656. Args: cobra.ExactArgs(1),
  657. PreRunE: checkServerHeartbeat,
  658. RunE: ShowHandler,
  659. }
  660. showCmd.Flags().Bool("license", false, "Show license of a model")
  661. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  662. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  663. showCmd.Flags().Bool("template", false, "Show template of a model")
  664. showCmd.Flags().Bool("system", false, "Show system message of a model")
  665. runCmd := &cobra.Command{
  666. Use: "run MODEL [PROMPT]",
  667. Short: "Run a model",
  668. Args: cobra.MinimumNArgs(1),
  669. PreRunE: checkServerHeartbeat,
  670. RunE: RunHandler,
  671. }
  672. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  673. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  674. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  675. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  676. serveCmd := &cobra.Command{
  677. Use: "serve",
  678. Aliases: []string{"start"},
  679. Short: "Start ollama",
  680. Args: cobra.ExactArgs(0),
  681. RunE: RunServer,
  682. }
  683. pullCmd := &cobra.Command{
  684. Use: "pull MODEL",
  685. Short: "Pull a model from a registry",
  686. Args: cobra.ExactArgs(1),
  687. PreRunE: checkServerHeartbeat,
  688. RunE: PullHandler,
  689. }
  690. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  691. pushCmd := &cobra.Command{
  692. Use: "push MODEL",
  693. Short: "Push a model to a registry",
  694. Args: cobra.ExactArgs(1),
  695. PreRunE: checkServerHeartbeat,
  696. RunE: PushHandler,
  697. }
  698. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  699. listCmd := &cobra.Command{
  700. Use: "list",
  701. Aliases: []string{"ls"},
  702. Short: "List models",
  703. PreRunE: checkServerHeartbeat,
  704. RunE: ListHandler,
  705. }
  706. copyCmd := &cobra.Command{
  707. Use: "cp SOURCE TARGET",
  708. Short: "Copy a model",
  709. Args: cobra.ExactArgs(2),
  710. PreRunE: checkServerHeartbeat,
  711. RunE: CopyHandler,
  712. }
  713. deleteCmd := &cobra.Command{
  714. Use: "rm MODEL [MODEL...]",
  715. Short: "Remove a model",
  716. Args: cobra.MinimumNArgs(1),
  717. PreRunE: checkServerHeartbeat,
  718. RunE: DeleteHandler,
  719. }
  720. rootCmd.AddCommand(
  721. serveCmd,
  722. createCmd,
  723. showCmd,
  724. runCmd,
  725. pullCmd,
  726. pushCmd,
  727. listCmd,
  728. copyCmd,
  729. deleteCmd,
  730. )
  731. return rootCmd
  732. }