cmd.go 19 KB

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