cmd.go 20 KB

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