cmd.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  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/readline"
  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(context.Background(), &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(context.Background(), &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, 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(context.Background(), &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(context.Background())
  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(context.Background(), &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{Name: args[0]}
  267. resp, err := client.Show(context.Background(), &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(context.Background(), &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(context.Background(), &request, fn); err != nil {
  335. return err
  336. }
  337. return nil
  338. }
  339. func RunGenerate(cmd *cobra.Command, args []string) error {
  340. format, err := cmd.Flags().GetString("format")
  341. if err != nil {
  342. return err
  343. }
  344. prompts := args[1:]
  345. // prepend stdin to the prompt if provided
  346. if !term.IsTerminal(int(os.Stdin.Fd())) {
  347. in, err := io.ReadAll(os.Stdin)
  348. if err != nil {
  349. return err
  350. }
  351. prompts = append([]string{string(in)}, prompts...)
  352. }
  353. // output is being piped
  354. if !term.IsTerminal(int(os.Stdout.Fd())) {
  355. return generate(cmd, args[0], strings.Join(prompts, " "), false, format)
  356. }
  357. wordWrap := os.Getenv("TERM") == "xterm-256color"
  358. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  359. if err != nil {
  360. return err
  361. }
  362. if nowrap {
  363. wordWrap = false
  364. }
  365. // prompts are provided via stdin or args so don't enter interactive mode
  366. if len(prompts) > 0 {
  367. return generate(cmd, args[0], strings.Join(prompts, " "), wordWrap, format)
  368. }
  369. return generateInteractive(cmd, args[0], wordWrap, format)
  370. }
  371. type generateContextKey string
  372. func generate(cmd *cobra.Command, model, prompt string, wordWrap bool, format string) error {
  373. client, err := api.ClientFromEnvironment()
  374. if err != nil {
  375. return err
  376. }
  377. p := progress.NewProgress(os.Stderr)
  378. defer p.StopAndClear()
  379. spinner := progress.NewSpinner("")
  380. p.Add("", spinner)
  381. var latest api.GenerateResponse
  382. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  383. if !ok {
  384. generateContext = []int{}
  385. }
  386. termWidth, _, err := term.GetSize(int(os.Stdout.Fd()))
  387. if err != nil {
  388. wordWrap = false
  389. }
  390. cancelCtx, cancel := context.WithCancel(context.Background())
  391. defer cancel()
  392. sigChan := make(chan os.Signal, 1)
  393. signal.Notify(sigChan, syscall.SIGINT)
  394. var abort bool
  395. go func() {
  396. <-sigChan
  397. cancel()
  398. abort = true
  399. }()
  400. var currentLineLength int
  401. var wordBuffer string
  402. request := api.GenerateRequest{Model: model, Prompt: prompt, Context: generateContext, Format: format}
  403. fn := func(response api.GenerateResponse) error {
  404. p.StopAndClear()
  405. latest = response
  406. if wordWrap {
  407. for _, ch := range response.Response {
  408. if currentLineLength+1 > termWidth-5 {
  409. // backtrack the length of the last word and clear to the end of the line
  410. fmt.Printf("\x1b[%dD\x1b[K\n", len(wordBuffer))
  411. fmt.Printf("%s%c", wordBuffer, ch)
  412. currentLineLength = len(wordBuffer) + 1
  413. } else {
  414. fmt.Print(string(ch))
  415. currentLineLength += 1
  416. switch ch {
  417. case ' ':
  418. wordBuffer = ""
  419. case '\n':
  420. currentLineLength = 0
  421. default:
  422. wordBuffer += string(ch)
  423. }
  424. }
  425. }
  426. } else {
  427. fmt.Print(response.Response)
  428. }
  429. return nil
  430. }
  431. if err := client.Generate(cancelCtx, &request, fn); err != nil {
  432. if strings.Contains(err.Error(), "context canceled") && abort {
  433. return nil
  434. }
  435. return err
  436. }
  437. if prompt != "" {
  438. fmt.Println()
  439. fmt.Println()
  440. }
  441. if !latest.Done {
  442. if abort {
  443. return nil
  444. }
  445. return errors.New("unexpected end of response")
  446. }
  447. verbose, err := cmd.Flags().GetBool("verbose")
  448. if err != nil {
  449. return err
  450. }
  451. if verbose {
  452. latest.Summary()
  453. }
  454. ctx := cmd.Context()
  455. ctx = context.WithValue(ctx, generateContextKey("context"), latest.Context)
  456. cmd.SetContext(ctx)
  457. return nil
  458. }
  459. func generateInteractive(cmd *cobra.Command, model string, wordWrap bool, format string) error {
  460. // load the model
  461. if err := generate(cmd, model, "", false, ""); err != nil {
  462. return err
  463. }
  464. usage := func() {
  465. fmt.Fprintln(os.Stderr, "Available Commands:")
  466. fmt.Fprintln(os.Stderr, " /set Set session variables")
  467. fmt.Fprintln(os.Stderr, " /show Show model information")
  468. fmt.Fprintln(os.Stderr, " /bye Exit")
  469. fmt.Fprintln(os.Stderr, " /?, /help Help for a command")
  470. fmt.Fprintln(os.Stderr, "")
  471. fmt.Fprintln(os.Stderr, "Use \"\"\" to begin a multi-line message.")
  472. fmt.Fprintln(os.Stderr, "")
  473. }
  474. usageSet := func() {
  475. fmt.Fprintln(os.Stderr, "Available Commands:")
  476. fmt.Fprintln(os.Stderr, " /set history Enable history")
  477. fmt.Fprintln(os.Stderr, " /set nohistory Disable history")
  478. fmt.Fprintln(os.Stderr, " /set wordwrap Enable wordwrap")
  479. fmt.Fprintln(os.Stderr, " /set nowordwrap Disable wordwrap")
  480. fmt.Fprintln(os.Stderr, " /set format json Enable JSON mode")
  481. fmt.Fprintln(os.Stderr, " /set noformat Disable formatting")
  482. fmt.Fprintln(os.Stderr, " /set verbose Show LLM stats")
  483. fmt.Fprintln(os.Stderr, " /set quiet Disable LLM stats")
  484. fmt.Fprintln(os.Stderr, "")
  485. }
  486. usageShow := func() {
  487. fmt.Fprintln(os.Stderr, "Available Commands:")
  488. fmt.Fprintln(os.Stderr, " /show license Show model license")
  489. fmt.Fprintln(os.Stderr, " /show modelfile Show Modelfile for this model")
  490. fmt.Fprintln(os.Stderr, " /show parameters Show parameters for this model")
  491. fmt.Fprintln(os.Stderr, " /show system Show system prompt")
  492. fmt.Fprintln(os.Stderr, " /show template Show prompt template")
  493. fmt.Fprintln(os.Stderr, "")
  494. }
  495. scanner, err := readline.New(readline.Prompt{
  496. Prompt: ">>> ",
  497. AltPrompt: "... ",
  498. Placeholder: "Send a message (/? for help)",
  499. AltPlaceholder: `Use """ to end multi-line input`,
  500. })
  501. if err != nil {
  502. return err
  503. }
  504. fmt.Print(readline.StartBracketedPaste)
  505. defer fmt.Printf(readline.EndBracketedPaste)
  506. var prompt string
  507. for {
  508. line, err := scanner.Readline()
  509. switch {
  510. case errors.Is(err, io.EOF):
  511. fmt.Println()
  512. return nil
  513. case errors.Is(err, readline.ErrInterrupt):
  514. if line == "" {
  515. fmt.Println("\nUse Ctrl-D or /bye to exit.")
  516. }
  517. scanner.Prompt.UseAlt = false
  518. prompt = ""
  519. continue
  520. case err != nil:
  521. return err
  522. }
  523. switch {
  524. case strings.HasPrefix(prompt, `"""`):
  525. // if the prompt so far starts with """ then we're in multiline mode
  526. // and we need to keep reading until we find a line that ends with """
  527. cut, found := strings.CutSuffix(line, `"""`)
  528. prompt += cut + "\n"
  529. if !found {
  530. continue
  531. }
  532. prompt = strings.TrimPrefix(prompt, `"""`)
  533. scanner.Prompt.UseAlt = false
  534. case strings.HasPrefix(line, `"""`) && len(prompt) == 0:
  535. scanner.Prompt.UseAlt = true
  536. prompt += line + "\n"
  537. continue
  538. case scanner.Pasting:
  539. prompt += line + "\n"
  540. continue
  541. case strings.HasPrefix(line, "/list"):
  542. args := strings.Fields(line)
  543. if err := ListHandler(cmd, args[1:]); err != nil {
  544. return err
  545. }
  546. case strings.HasPrefix(line, "/set"):
  547. args := strings.Fields(line)
  548. if len(args) > 1 {
  549. switch args[1] {
  550. case "history":
  551. scanner.HistoryEnable()
  552. case "nohistory":
  553. scanner.HistoryDisable()
  554. case "wordwrap":
  555. wordWrap = true
  556. fmt.Println("Set 'wordwrap' mode.")
  557. case "nowordwrap":
  558. wordWrap = false
  559. fmt.Println("Set 'nowordwrap' mode.")
  560. case "verbose":
  561. cmd.Flags().Set("verbose", "true")
  562. fmt.Println("Set 'verbose' mode.")
  563. case "quiet":
  564. cmd.Flags().Set("verbose", "false")
  565. fmt.Println("Set 'quiet' mode.")
  566. case "format":
  567. if len(args) < 3 || args[2] != "json" {
  568. fmt.Println("Invalid or missing format. For 'json' mode use '/set format json'")
  569. } else {
  570. format = args[2]
  571. fmt.Printf("Set format to '%s' mode.\n", args[2])
  572. }
  573. case "noformat":
  574. format = ""
  575. fmt.Println("Disabled format.")
  576. default:
  577. fmt.Printf("Unknown command '/set %s'. Type /? for help\n", args[1])
  578. }
  579. } else {
  580. usageSet()
  581. }
  582. case strings.HasPrefix(line, "/show"):
  583. args := strings.Fields(line)
  584. if len(args) > 1 {
  585. client, err := api.ClientFromEnvironment()
  586. if err != nil {
  587. fmt.Println("error: couldn't connect to ollama server")
  588. return err
  589. }
  590. resp, err := client.Show(cmd.Context(), &api.ShowRequest{Name: model})
  591. if err != nil {
  592. fmt.Println("error: couldn't get model")
  593. return err
  594. }
  595. switch args[1] {
  596. case "license":
  597. if resp.License == "" {
  598. fmt.Print("No license was specified for this model.\n\n")
  599. } else {
  600. fmt.Println(resp.License)
  601. }
  602. case "modelfile":
  603. fmt.Println(resp.Modelfile)
  604. case "parameters":
  605. if resp.Parameters == "" {
  606. fmt.Print("No parameters were specified for this model.\n\n")
  607. } else {
  608. fmt.Println(resp.Parameters)
  609. }
  610. case "system":
  611. if resp.System == "" {
  612. fmt.Print("No system prompt was specified for this model.\n\n")
  613. } else {
  614. fmt.Println(resp.System)
  615. }
  616. case "template":
  617. if resp.Template == "" {
  618. fmt.Print("No prompt template was specified for this model.\n\n")
  619. } else {
  620. fmt.Println(resp.Template)
  621. }
  622. default:
  623. fmt.Printf("Unknown command '/show %s'. Type /? for help\n", args[1])
  624. }
  625. } else {
  626. usageShow()
  627. }
  628. case strings.HasPrefix(line, "/help"), strings.HasPrefix(line, "/?"):
  629. args := strings.Fields(line)
  630. if len(args) > 1 {
  631. switch args[1] {
  632. case "set", "/set":
  633. usageSet()
  634. case "show", "/show":
  635. usageShow()
  636. }
  637. } else {
  638. usage()
  639. }
  640. case line == "/exit", line == "/bye":
  641. return nil
  642. case strings.HasPrefix(line, "/"):
  643. args := strings.Fields(line)
  644. fmt.Printf("Unknown command '%s'. Type /? for help\n", args[0])
  645. continue
  646. default:
  647. prompt += line
  648. }
  649. if len(prompt) > 0 && prompt[0] != '/' {
  650. if err := generate(cmd, model, prompt, wordWrap, format); err != nil {
  651. return err
  652. }
  653. prompt = ""
  654. }
  655. }
  656. }
  657. func RunServer(cmd *cobra.Command, _ []string) error {
  658. host, port, err := net.SplitHostPort(os.Getenv("OLLAMA_HOST"))
  659. if err != nil {
  660. host, port = "127.0.0.1", "11434"
  661. if ip := net.ParseIP(strings.Trim(os.Getenv("OLLAMA_HOST"), "[]")); ip != nil {
  662. host = ip.String()
  663. }
  664. }
  665. if err := initializeKeypair(); err != nil {
  666. return err
  667. }
  668. ln, err := net.Listen("tcp", net.JoinHostPort(host, port))
  669. if err != nil {
  670. return err
  671. }
  672. var origins []string
  673. if o := os.Getenv("OLLAMA_ORIGINS"); o != "" {
  674. origins = strings.Split(o, ",")
  675. }
  676. return server.Serve(ln, origins)
  677. }
  678. func initializeKeypair() error {
  679. home, err := os.UserHomeDir()
  680. if err != nil {
  681. return err
  682. }
  683. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  684. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  685. _, err = os.Stat(privKeyPath)
  686. if os.IsNotExist(err) {
  687. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  688. _, privKey, err := ed25519.GenerateKey(rand.Reader)
  689. if err != nil {
  690. return err
  691. }
  692. privKeyBytes, err := format.OpenSSHPrivateKey(privKey, "")
  693. if err != nil {
  694. return err
  695. }
  696. err = os.MkdirAll(filepath.Dir(privKeyPath), 0o755)
  697. if err != nil {
  698. return fmt.Errorf("could not create directory %w", err)
  699. }
  700. err = os.WriteFile(privKeyPath, pem.EncodeToMemory(privKeyBytes), 0o600)
  701. if err != nil {
  702. return err
  703. }
  704. sshPrivateKey, err := ssh.NewSignerFromKey(privKey)
  705. if err != nil {
  706. return err
  707. }
  708. pubKeyData := ssh.MarshalAuthorizedKey(sshPrivateKey.PublicKey())
  709. err = os.WriteFile(pubKeyPath, pubKeyData, 0o644)
  710. if err != nil {
  711. return err
  712. }
  713. fmt.Printf("Your new public key is: \n\n%s\n", string(pubKeyData))
  714. }
  715. return nil
  716. }
  717. func startMacApp(client *api.Client) error {
  718. exe, err := os.Executable()
  719. if err != nil {
  720. return err
  721. }
  722. link, err := os.Readlink(exe)
  723. if err != nil {
  724. return err
  725. }
  726. if !strings.Contains(link, "Ollama.app") {
  727. return fmt.Errorf("could not find ollama app")
  728. }
  729. path := strings.Split(link, "Ollama.app")
  730. if err := exec.Command("/usr/bin/open", "-a", path[0]+"Ollama.app").Run(); err != nil {
  731. return err
  732. }
  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(context.Background()); err == nil {
  742. return nil // server has started
  743. }
  744. }
  745. }
  746. }
  747. func checkServerHeartbeat(_ *cobra.Command, _ []string) error {
  748. client, err := api.ClientFromEnvironment()
  749. if err != nil {
  750. return err
  751. }
  752. if err := client.Heartbeat(context.Background()); err != nil {
  753. if !strings.Contains(err.Error(), "connection refused") {
  754. return err
  755. }
  756. if runtime.GOOS == "darwin" {
  757. if err := startMacApp(client); err != nil {
  758. return fmt.Errorf("could not connect to ollama app, is it running?")
  759. }
  760. } else {
  761. return fmt.Errorf("could not connect to ollama server, run 'ollama serve' to start it")
  762. }
  763. }
  764. return nil
  765. }
  766. func NewCLI() *cobra.Command {
  767. log.SetFlags(log.LstdFlags | log.Lshortfile)
  768. rootCmd := &cobra.Command{
  769. Use: "ollama",
  770. Short: "Large language model runner",
  771. SilenceUsage: true,
  772. SilenceErrors: true,
  773. CompletionOptions: cobra.CompletionOptions{
  774. DisableDefaultCmd: true,
  775. },
  776. Version: version.Version,
  777. }
  778. cobra.EnableCommandSorting = false
  779. createCmd := &cobra.Command{
  780. Use: "create MODEL",
  781. Short: "Create a model from a Modelfile",
  782. Args: cobra.ExactArgs(1),
  783. PreRunE: checkServerHeartbeat,
  784. RunE: CreateHandler,
  785. }
  786. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
  787. showCmd := &cobra.Command{
  788. Use: "show MODEL",
  789. Short: "Show information for a model",
  790. Args: cobra.ExactArgs(1),
  791. PreRunE: checkServerHeartbeat,
  792. RunE: ShowHandler,
  793. }
  794. showCmd.Flags().Bool("license", false, "Show license of a model")
  795. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  796. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  797. showCmd.Flags().Bool("template", false, "Show template of a model")
  798. showCmd.Flags().Bool("system", false, "Show system prompt of a model")
  799. runCmd := &cobra.Command{
  800. Use: "run MODEL [PROMPT]",
  801. Short: "Run a model",
  802. Args: cobra.MinimumNArgs(1),
  803. PreRunE: checkServerHeartbeat,
  804. RunE: RunHandler,
  805. }
  806. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  807. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  808. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  809. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  810. serveCmd := &cobra.Command{
  811. Use: "serve",
  812. Aliases: []string{"start"},
  813. Short: "Start ollama",
  814. Args: cobra.ExactArgs(0),
  815. RunE: RunServer,
  816. }
  817. pullCmd := &cobra.Command{
  818. Use: "pull MODEL",
  819. Short: "Pull a model from a registry",
  820. Args: cobra.ExactArgs(1),
  821. PreRunE: checkServerHeartbeat,
  822. RunE: PullHandler,
  823. }
  824. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  825. pushCmd := &cobra.Command{
  826. Use: "push MODEL",
  827. Short: "Push a model to a registry",
  828. Args: cobra.ExactArgs(1),
  829. PreRunE: checkServerHeartbeat,
  830. RunE: PushHandler,
  831. }
  832. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  833. listCmd := &cobra.Command{
  834. Use: "list",
  835. Aliases: []string{"ls"},
  836. Short: "List models",
  837. PreRunE: checkServerHeartbeat,
  838. RunE: ListHandler,
  839. }
  840. copyCmd := &cobra.Command{
  841. Use: "cp SOURCE TARGET",
  842. Short: "Copy a model",
  843. Args: cobra.ExactArgs(2),
  844. PreRunE: checkServerHeartbeat,
  845. RunE: CopyHandler,
  846. }
  847. deleteCmd := &cobra.Command{
  848. Use: "rm MODEL [MODEL...]",
  849. Short: "Remove a model",
  850. Args: cobra.MinimumNArgs(1),
  851. PreRunE: checkServerHeartbeat,
  852. RunE: DeleteHandler,
  853. }
  854. rootCmd.AddCommand(
  855. serveCmd,
  856. createCmd,
  857. showCmd,
  858. runCmd,
  859. pullCmd,
  860. pushCmd,
  861. listCmd,
  862. copyCmd,
  863. deleteCmd,
  864. )
  865. return rootCmd
  866. }