cmd.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971
  1. package cmd
  2. import (
  3. "bufio"
  4. "context"
  5. "crypto/ed25519"
  6. "crypto/rand"
  7. "encoding/pem"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "log"
  12. "net"
  13. "net/http"
  14. "os"
  15. "os/exec"
  16. "os/signal"
  17. "path/filepath"
  18. "runtime"
  19. "strings"
  20. "syscall"
  21. "time"
  22. "github.com/dustin/go-humanize"
  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/progressbar"
  30. "github.com/jmorganca/ollama/readline"
  31. "github.com/jmorganca/ollama/server"
  32. "github.com/jmorganca/ollama/version"
  33. )
  34. func CreateHandler(cmd *cobra.Command, args []string) error {
  35. filename, _ := cmd.Flags().GetString("file")
  36. filename, err := filepath.Abs(filename)
  37. if err != nil {
  38. return err
  39. }
  40. client, err := api.ClientFromEnvironment()
  41. if err != nil {
  42. return err
  43. }
  44. var spinner *Spinner
  45. var currentDigest string
  46. var bar *progressbar.ProgressBar
  47. request := api.CreateRequest{Name: args[0], Path: filename}
  48. fn := func(resp api.ProgressResponse) error {
  49. if resp.Digest != currentDigest && resp.Digest != "" {
  50. if spinner != nil {
  51. spinner.Stop()
  52. }
  53. currentDigest = resp.Digest
  54. // pulling
  55. bar = progressbar.DefaultBytes(
  56. resp.Total,
  57. resp.Status,
  58. )
  59. bar.Set64(resp.Completed)
  60. } else if resp.Digest == currentDigest && resp.Digest != "" {
  61. bar.Set64(resp.Completed)
  62. } else {
  63. currentDigest = ""
  64. if spinner != nil {
  65. spinner.Stop()
  66. }
  67. spinner = NewSpinner(resp.Status)
  68. go spinner.Spin(100 * time.Millisecond)
  69. }
  70. return nil
  71. }
  72. if err := client.Create(context.Background(), &request, fn); err != nil {
  73. return err
  74. }
  75. if spinner != nil {
  76. spinner.Stop()
  77. if spinner.description != "success" {
  78. return errors.New("unexpected end to create model")
  79. }
  80. }
  81. return nil
  82. }
  83. func RunHandler(cmd *cobra.Command, args []string) error {
  84. client, err := api.ClientFromEnvironment()
  85. if err != nil {
  86. return err
  87. }
  88. name := args[0]
  89. // check if the model exists on the server
  90. _, err = client.Show(context.Background(), &api.ShowRequest{Name: name})
  91. var statusError api.StatusError
  92. switch {
  93. case errors.As(err, &statusError) && statusError.StatusCode == http.StatusNotFound:
  94. if err := PullHandler(cmd, args); err != nil {
  95. return err
  96. }
  97. case err != nil:
  98. return err
  99. }
  100. return RunGenerate(cmd, args)
  101. }
  102. func PushHandler(cmd *cobra.Command, args []string) error {
  103. client, err := api.ClientFromEnvironment()
  104. if err != nil {
  105. return err
  106. }
  107. insecure, err := cmd.Flags().GetBool("insecure")
  108. if err != nil {
  109. return err
  110. }
  111. var currentDigest string
  112. var bar *progressbar.ProgressBar
  113. request := api.PushRequest{Name: args[0], Insecure: insecure}
  114. fn := func(resp api.ProgressResponse) error {
  115. if resp.Digest != currentDigest && resp.Digest != "" {
  116. currentDigest = resp.Digest
  117. bar = progressbar.DefaultBytes(
  118. resp.Total,
  119. fmt.Sprintf("pushing %s...", resp.Digest[7:19]),
  120. )
  121. bar.Set64(resp.Completed)
  122. } else if resp.Digest == currentDigest && resp.Digest != "" {
  123. bar.Set64(resp.Completed)
  124. } else {
  125. currentDigest = ""
  126. fmt.Println(resp.Status)
  127. }
  128. return nil
  129. }
  130. if err := client.Push(context.Background(), &request, fn); err != nil {
  131. return err
  132. }
  133. if bar != nil && !bar.IsFinished() {
  134. return errors.New("unexpected end to push model")
  135. }
  136. return nil
  137. }
  138. func ListHandler(cmd *cobra.Command, args []string) error {
  139. client, err := api.ClientFromEnvironment()
  140. if err != nil {
  141. return err
  142. }
  143. models, err := client.List(context.Background())
  144. if err != nil {
  145. return err
  146. }
  147. var data [][]string
  148. for _, m := range models.Models {
  149. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  150. data = append(data, []string{m.Name, m.Digest[:12], humanize.Bytes(uint64(m.Size)), format.HumanTime(m.ModifiedAt, "Never")})
  151. }
  152. }
  153. table := tablewriter.NewWriter(os.Stdout)
  154. table.SetHeader([]string{"NAME", "ID", "SIZE", "MODIFIED"})
  155. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  156. table.SetAlignment(tablewriter.ALIGN_LEFT)
  157. table.SetHeaderLine(false)
  158. table.SetBorder(false)
  159. table.SetNoWhiteSpace(true)
  160. table.SetTablePadding("\t")
  161. table.AppendBulk(data)
  162. table.Render()
  163. return nil
  164. }
  165. func DeleteHandler(cmd *cobra.Command, args []string) error {
  166. client, err := api.ClientFromEnvironment()
  167. if err != nil {
  168. return err
  169. }
  170. for _, name := range args {
  171. req := api.DeleteRequest{Name: name}
  172. if err := client.Delete(context.Background(), &req); err != nil {
  173. return err
  174. }
  175. fmt.Printf("deleted '%s'\n", name)
  176. }
  177. return nil
  178. }
  179. func ShowHandler(cmd *cobra.Command, args []string) error {
  180. client, err := api.ClientFromEnvironment()
  181. if err != nil {
  182. return err
  183. }
  184. if len(args) != 1 {
  185. return errors.New("missing model name")
  186. }
  187. license, errLicense := cmd.Flags().GetBool("license")
  188. modelfile, errModelfile := cmd.Flags().GetBool("modelfile")
  189. parameters, errParams := cmd.Flags().GetBool("parameters")
  190. system, errSystem := cmd.Flags().GetBool("system")
  191. template, errTemplate := cmd.Flags().GetBool("template")
  192. for _, boolErr := range []error{errLicense, errModelfile, errParams, errSystem, errTemplate} {
  193. if boolErr != nil {
  194. return errors.New("error retrieving flags")
  195. }
  196. }
  197. flagsSet := 0
  198. showType := ""
  199. if license {
  200. flagsSet++
  201. showType = "license"
  202. }
  203. if modelfile {
  204. flagsSet++
  205. showType = "modelfile"
  206. }
  207. if parameters {
  208. flagsSet++
  209. showType = "parameters"
  210. }
  211. if system {
  212. flagsSet++
  213. showType = "system"
  214. }
  215. if template {
  216. flagsSet++
  217. showType = "template"
  218. }
  219. if flagsSet > 1 {
  220. return errors.New("only one of '--license', '--modelfile', '--parameters', '--system', or '--template' can be specified")
  221. } else if flagsSet == 0 {
  222. return errors.New("one of '--license', '--modelfile', '--parameters', '--system', or '--template' must be specified")
  223. }
  224. req := api.ShowRequest{Name: args[0]}
  225. resp, err := client.Show(context.Background(), &req)
  226. if err != nil {
  227. return err
  228. }
  229. switch showType {
  230. case "license":
  231. fmt.Println(resp.License)
  232. case "modelfile":
  233. fmt.Println(resp.Modelfile)
  234. case "parameters":
  235. fmt.Println(resp.Parameters)
  236. case "system":
  237. fmt.Println(resp.System)
  238. case "template":
  239. fmt.Println(resp.Template)
  240. }
  241. return nil
  242. }
  243. func CopyHandler(cmd *cobra.Command, args []string) error {
  244. client, err := api.ClientFromEnvironment()
  245. if err != nil {
  246. return err
  247. }
  248. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  249. if err := client.Copy(context.Background(), &req); err != nil {
  250. return err
  251. }
  252. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  253. return nil
  254. }
  255. func PullHandler(cmd *cobra.Command, args []string) error {
  256. insecure, err := cmd.Flags().GetBool("insecure")
  257. if err != nil {
  258. return err
  259. }
  260. return pull(args[0], insecure)
  261. }
  262. func pull(model string, insecure bool) error {
  263. client, err := api.ClientFromEnvironment()
  264. if err != nil {
  265. return err
  266. }
  267. var currentDigest string
  268. var bar *progressbar.ProgressBar
  269. request := api.PullRequest{Name: model, Insecure: insecure}
  270. fn := func(resp api.ProgressResponse) error {
  271. if resp.Digest != currentDigest && resp.Digest != "" {
  272. currentDigest = resp.Digest
  273. bar = progressbar.DefaultBytes(
  274. resp.Total,
  275. fmt.Sprintf("pulling %s...", resp.Digest[7:19]),
  276. )
  277. bar.Set64(resp.Completed)
  278. } else if resp.Digest == currentDigest && resp.Digest != "" {
  279. bar.Set64(resp.Completed)
  280. } else {
  281. currentDigest = ""
  282. fmt.Println(resp.Status)
  283. }
  284. return nil
  285. }
  286. if err := client.Pull(context.Background(), &request, fn); err != nil {
  287. return err
  288. }
  289. if bar != nil && !bar.IsFinished() {
  290. return errors.New("unexpected end to pull model")
  291. }
  292. return nil
  293. }
  294. func RunGenerate(cmd *cobra.Command, args []string) error {
  295. if len(args) > 1 {
  296. // join all args into a single prompt
  297. wordWrap := false
  298. if term.IsTerminal(int(os.Stdout.Fd())) {
  299. wordWrap = true
  300. }
  301. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  302. if err != nil {
  303. return err
  304. }
  305. if nowrap {
  306. wordWrap = false
  307. }
  308. format, err := cmd.Flags().GetString("format")
  309. if err != nil {
  310. return err
  311. }
  312. return generate(cmd, args[0], strings.Join(args[1:], " "), wordWrap, format)
  313. }
  314. if readline.IsTerminal(int(os.Stdin.Fd())) {
  315. return generateInteractive(cmd, args[0])
  316. }
  317. return generateBatch(cmd, args[0])
  318. }
  319. type generateContextKey string
  320. func generate(cmd *cobra.Command, model, prompt string, wordWrap bool, format string) error {
  321. client, err := api.ClientFromEnvironment()
  322. if err != nil {
  323. return err
  324. }
  325. spinner := NewSpinner("")
  326. go spinner.Spin(60 * time.Millisecond)
  327. var latest api.GenerateResponse
  328. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  329. if !ok {
  330. generateContext = []int{}
  331. }
  332. termWidth, _, err := term.GetSize(int(0))
  333. if err != nil {
  334. wordWrap = false
  335. }
  336. cancelCtx, cancel := context.WithCancel(context.Background())
  337. defer cancel()
  338. sigChan := make(chan os.Signal, 1)
  339. signal.Notify(sigChan, syscall.SIGINT)
  340. var abort bool
  341. go func() {
  342. <-sigChan
  343. cancel()
  344. abort = true
  345. }()
  346. var currentLineLength int
  347. var wordBuffer string
  348. request := api.GenerateRequest{Model: model, Prompt: prompt, Context: generateContext, Format: format}
  349. fn := func(response api.GenerateResponse) error {
  350. if !spinner.IsFinished() {
  351. spinner.Finish()
  352. }
  353. latest = response
  354. if wordWrap {
  355. for _, ch := range response.Response {
  356. if currentLineLength+1 > termWidth-5 {
  357. // backtrack the length of the last word and clear to the end of the line
  358. fmt.Printf("\x1b[%dD\x1b[K\n", len(wordBuffer))
  359. fmt.Printf("%s%c", wordBuffer, ch)
  360. currentLineLength = len(wordBuffer) + 1
  361. } else {
  362. fmt.Print(string(ch))
  363. currentLineLength += 1
  364. switch ch {
  365. case ' ':
  366. wordBuffer = ""
  367. case '\n':
  368. currentLineLength = 0
  369. default:
  370. wordBuffer += string(ch)
  371. }
  372. }
  373. }
  374. } else {
  375. fmt.Print(response.Response)
  376. }
  377. return nil
  378. }
  379. if err := client.Generate(cancelCtx, &request, fn); err != nil {
  380. if strings.Contains(err.Error(), "context canceled") && abort {
  381. spinner.Finish()
  382. return nil
  383. }
  384. return err
  385. }
  386. if prompt != "" {
  387. fmt.Println()
  388. fmt.Println()
  389. }
  390. if !latest.Done {
  391. if abort {
  392. return nil
  393. }
  394. return errors.New("unexpected end of response")
  395. }
  396. verbose, err := cmd.Flags().GetBool("verbose")
  397. if err != nil {
  398. return err
  399. }
  400. if verbose {
  401. latest.Summary()
  402. }
  403. ctx := cmd.Context()
  404. ctx = context.WithValue(ctx, generateContextKey("context"), latest.Context)
  405. cmd.SetContext(ctx)
  406. return nil
  407. }
  408. func generateInteractive(cmd *cobra.Command, model string) error {
  409. // load the model
  410. if err := generate(cmd, model, "", false, ""); err != nil {
  411. return err
  412. }
  413. usage := func() {
  414. fmt.Fprintln(os.Stderr, "Available Commands:")
  415. fmt.Fprintln(os.Stderr, " /set Set session variables")
  416. fmt.Fprintln(os.Stderr, " /show Show model information")
  417. fmt.Fprintln(os.Stderr, " /bye Exit")
  418. fmt.Fprintln(os.Stderr, " /?, /help Help for a command")
  419. fmt.Fprintln(os.Stderr, "")
  420. fmt.Fprintln(os.Stderr, "Use \"\"\" to begin a multi-line message.")
  421. fmt.Fprintln(os.Stderr, "")
  422. }
  423. usageSet := func() {
  424. fmt.Fprintln(os.Stderr, "Available Commands:")
  425. fmt.Fprintln(os.Stderr, " /set history Enable history")
  426. fmt.Fprintln(os.Stderr, " /set nohistory Disable history")
  427. fmt.Fprintln(os.Stderr, " /set wordwrap Enable wordwrap")
  428. fmt.Fprintln(os.Stderr, " /set nowordwrap Disable wordwrap")
  429. fmt.Fprintln(os.Stderr, " /set format json Enable JSON mode")
  430. fmt.Fprintln(os.Stderr, " /set noformat Disable formatting")
  431. fmt.Fprintln(os.Stderr, " /set verbose Show LLM stats")
  432. fmt.Fprintln(os.Stderr, " /set quiet Disable LLM stats")
  433. fmt.Fprintln(os.Stderr, "")
  434. }
  435. usageShow := func() {
  436. fmt.Fprintln(os.Stderr, "Available Commands:")
  437. fmt.Fprintln(os.Stderr, " /show license Show model license")
  438. fmt.Fprintln(os.Stderr, " /show modelfile Show Modelfile for this model")
  439. fmt.Fprintln(os.Stderr, " /show parameters Show parameters for this model")
  440. fmt.Fprintln(os.Stderr, " /show system Show system prompt")
  441. fmt.Fprintln(os.Stderr, " /show template Show prompt template")
  442. fmt.Fprintln(os.Stderr, "")
  443. }
  444. prompt := readline.Prompt{
  445. Prompt: ">>> ",
  446. AltPrompt: "... ",
  447. Placeholder: "Send a message (/? for help)",
  448. AltPlaceholder: `Use """ to end multi-line input`,
  449. }
  450. scanner, err := readline.New(prompt)
  451. if err != nil {
  452. return err
  453. }
  454. var format string
  455. var wordWrap bool
  456. termType := os.Getenv("TERM")
  457. if termType == "xterm-256color" {
  458. wordWrap = true
  459. }
  460. // override wrapping if the user turned it off
  461. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  462. if err != nil {
  463. return err
  464. }
  465. if nowrap {
  466. wordWrap = false
  467. }
  468. fmt.Print(readline.StartBracketedPaste)
  469. defer fmt.Printf(readline.EndBracketedPaste)
  470. var multiLineBuffer string
  471. for {
  472. line, err := scanner.Readline()
  473. switch {
  474. case errors.Is(err, io.EOF):
  475. fmt.Println()
  476. return nil
  477. case errors.Is(err, readline.ErrInterrupt):
  478. if line == "" {
  479. fmt.Println("\nUse Ctrl-D or /bye to exit.")
  480. }
  481. continue
  482. case err != nil:
  483. return err
  484. }
  485. line = strings.TrimSpace(line)
  486. switch {
  487. case scanner.Prompt.UseAlt:
  488. if strings.HasSuffix(line, `"""`) {
  489. scanner.Prompt.UseAlt = false
  490. multiLineBuffer += strings.TrimSuffix(line, `"""`)
  491. line = multiLineBuffer
  492. multiLineBuffer = ""
  493. } else {
  494. multiLineBuffer += line + " "
  495. continue
  496. }
  497. case strings.HasPrefix(line, `"""`):
  498. scanner.Prompt.UseAlt = true
  499. multiLineBuffer = strings.TrimPrefix(line, `"""`) + " "
  500. continue
  501. case strings.HasPrefix(line, "/list"):
  502. args := strings.Fields(line)
  503. if err := ListHandler(cmd, args[1:]); err != nil {
  504. return err
  505. }
  506. case strings.HasPrefix(line, "/set"):
  507. args := strings.Fields(line)
  508. if len(args) > 1 {
  509. switch args[1] {
  510. case "history":
  511. scanner.HistoryEnable()
  512. case "nohistory":
  513. scanner.HistoryDisable()
  514. case "wordwrap":
  515. wordWrap = true
  516. fmt.Println("Set 'wordwrap' mode.")
  517. case "nowordwrap":
  518. wordWrap = false
  519. fmt.Println("Set 'nowordwrap' mode.")
  520. case "verbose":
  521. cmd.Flags().Set("verbose", "true")
  522. fmt.Println("Set 'verbose' mode.")
  523. case "quiet":
  524. cmd.Flags().Set("verbose", "false")
  525. fmt.Println("Set 'quiet' mode.")
  526. case "format":
  527. if len(args) < 3 || args[2] != "json" {
  528. fmt.Println("Invalid or missing format. For 'json' mode use '/set format json'")
  529. } else {
  530. format = args[2]
  531. fmt.Printf("Set format to '%s' mode.\n", args[2])
  532. }
  533. case "noformat":
  534. format = ""
  535. fmt.Println("Disabled format.")
  536. default:
  537. fmt.Printf("Unknown command '/set %s'. Type /? for help\n", args[1])
  538. }
  539. } else {
  540. usageSet()
  541. }
  542. case strings.HasPrefix(line, "/show"):
  543. args := strings.Fields(line)
  544. if len(args) > 1 {
  545. client, err := api.ClientFromEnvironment()
  546. if err != nil {
  547. fmt.Println("error: couldn't connect to ollama server")
  548. return err
  549. }
  550. resp, err := client.Show(cmd.Context(), &api.ShowRequest{Name: model})
  551. if err != nil {
  552. fmt.Println("error: couldn't get model")
  553. return err
  554. }
  555. switch args[1] {
  556. case "license":
  557. if resp.License == "" {
  558. fmt.Print("No license was specified for this model.\n\n")
  559. } else {
  560. fmt.Println(resp.License)
  561. }
  562. case "modelfile":
  563. fmt.Println(resp.Modelfile)
  564. case "parameters":
  565. if resp.Parameters == "" {
  566. fmt.Print("No parameters were specified for this model.\n\n")
  567. } else {
  568. fmt.Println(resp.Parameters)
  569. }
  570. case "system":
  571. if resp.System == "" {
  572. fmt.Print("No system prompt was specified for this model.\n\n")
  573. } else {
  574. fmt.Println(resp.System)
  575. }
  576. case "template":
  577. if resp.Template == "" {
  578. fmt.Print("No prompt template was specified for this model.\n\n")
  579. } else {
  580. fmt.Println(resp.Template)
  581. }
  582. default:
  583. fmt.Printf("Unknown command '/show %s'. Type /? for help\n", args[1])
  584. }
  585. } else {
  586. usageShow()
  587. }
  588. case strings.HasPrefix(line, "/help"), strings.HasPrefix(line, "/?"):
  589. args := strings.Fields(line)
  590. if len(args) > 1 {
  591. switch args[1] {
  592. case "set", "/set":
  593. usageSet()
  594. case "show", "/show":
  595. usageShow()
  596. }
  597. } else {
  598. usage()
  599. }
  600. case line == "/exit", line == "/bye":
  601. return nil
  602. case strings.HasPrefix(line, "/"):
  603. args := strings.Fields(line)
  604. fmt.Printf("Unknown command '%s'. Type /? for help\n", args[0])
  605. }
  606. if len(line) > 0 && line[0] != '/' {
  607. if err := generate(cmd, model, line, wordWrap, format); err != nil {
  608. return err
  609. }
  610. }
  611. }
  612. }
  613. func generateBatch(cmd *cobra.Command, model string) error {
  614. scanner := bufio.NewScanner(os.Stdin)
  615. for scanner.Scan() {
  616. prompt := scanner.Text()
  617. fmt.Printf(">>> %s\n", prompt)
  618. if err := generate(cmd, model, prompt, false, ""); err != nil {
  619. return err
  620. }
  621. }
  622. return nil
  623. }
  624. func RunServer(cmd *cobra.Command, _ []string) error {
  625. host, port, err := net.SplitHostPort(os.Getenv("OLLAMA_HOST"))
  626. if err != nil {
  627. host, port = "127.0.0.1", "11434"
  628. if ip := net.ParseIP(strings.Trim(os.Getenv("OLLAMA_HOST"), "[]")); ip != nil {
  629. host = ip.String()
  630. }
  631. }
  632. if err := initializeKeypair(); err != nil {
  633. return err
  634. }
  635. ln, err := net.Listen("tcp", net.JoinHostPort(host, port))
  636. if err != nil {
  637. return err
  638. }
  639. var origins []string
  640. if o := os.Getenv("OLLAMA_ORIGINS"); o != "" {
  641. origins = strings.Split(o, ",")
  642. }
  643. return server.Serve(ln, origins)
  644. }
  645. func initializeKeypair() error {
  646. home, err := os.UserHomeDir()
  647. if err != nil {
  648. return err
  649. }
  650. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  651. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  652. _, err = os.Stat(privKeyPath)
  653. if os.IsNotExist(err) {
  654. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  655. _, privKey, err := ed25519.GenerateKey(rand.Reader)
  656. if err != nil {
  657. return err
  658. }
  659. privKeyBytes, err := format.OpenSSHPrivateKey(privKey, "")
  660. if err != nil {
  661. return err
  662. }
  663. err = os.MkdirAll(filepath.Dir(privKeyPath), 0o755)
  664. if err != nil {
  665. return fmt.Errorf("could not create directory %w", err)
  666. }
  667. err = os.WriteFile(privKeyPath, pem.EncodeToMemory(privKeyBytes), 0o600)
  668. if err != nil {
  669. return err
  670. }
  671. sshPrivateKey, err := ssh.NewSignerFromKey(privKey)
  672. if err != nil {
  673. return err
  674. }
  675. pubKeyData := ssh.MarshalAuthorizedKey(sshPrivateKey.PublicKey())
  676. err = os.WriteFile(pubKeyPath, pubKeyData, 0o644)
  677. if err != nil {
  678. return err
  679. }
  680. fmt.Printf("Your new public key is: \n\n%s\n", string(pubKeyData))
  681. }
  682. return nil
  683. }
  684. func startMacApp(client *api.Client) error {
  685. exe, err := os.Executable()
  686. if err != nil {
  687. return err
  688. }
  689. link, err := os.Readlink(exe)
  690. if err != nil {
  691. return err
  692. }
  693. if !strings.Contains(link, "Ollama.app") {
  694. return fmt.Errorf("could not find ollama app")
  695. }
  696. path := strings.Split(link, "Ollama.app")
  697. if err := exec.Command("/usr/bin/open", "-a", path[0]+"Ollama.app").Run(); err != nil {
  698. return err
  699. }
  700. // wait for the server to start
  701. timeout := time.After(5 * time.Second)
  702. tick := time.Tick(500 * time.Millisecond)
  703. for {
  704. select {
  705. case <-timeout:
  706. return errors.New("timed out waiting for server to start")
  707. case <-tick:
  708. if err := client.Heartbeat(context.Background()); err == nil {
  709. return nil // server has started
  710. }
  711. }
  712. }
  713. }
  714. func checkServerHeartbeat(_ *cobra.Command, _ []string) error {
  715. client, err := api.ClientFromEnvironment()
  716. if err != nil {
  717. return err
  718. }
  719. if err := client.Heartbeat(context.Background()); err != nil {
  720. if !strings.Contains(err.Error(), "connection refused") {
  721. return err
  722. }
  723. if runtime.GOOS == "darwin" {
  724. if err := startMacApp(client); err != nil {
  725. return fmt.Errorf("could not connect to ollama app, is it running?")
  726. }
  727. } else {
  728. return fmt.Errorf("could not connect to ollama server, run 'ollama serve' to start it")
  729. }
  730. }
  731. return nil
  732. }
  733. func NewCLI() *cobra.Command {
  734. log.SetFlags(log.LstdFlags | log.Lshortfile)
  735. rootCmd := &cobra.Command{
  736. Use: "ollama",
  737. Short: "Large language model runner",
  738. SilenceUsage: true,
  739. SilenceErrors: true,
  740. CompletionOptions: cobra.CompletionOptions{
  741. DisableDefaultCmd: true,
  742. },
  743. Version: version.Version,
  744. }
  745. cobra.EnableCommandSorting = false
  746. createCmd := &cobra.Command{
  747. Use: "create MODEL",
  748. Short: "Create a model from a Modelfile",
  749. Args: cobra.ExactArgs(1),
  750. PreRunE: checkServerHeartbeat,
  751. RunE: CreateHandler,
  752. }
  753. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
  754. showCmd := &cobra.Command{
  755. Use: "show MODEL",
  756. Short: "Show information for a model",
  757. Args: cobra.ExactArgs(1),
  758. PreRunE: checkServerHeartbeat,
  759. RunE: ShowHandler,
  760. }
  761. showCmd.Flags().Bool("license", false, "Show license of a model")
  762. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  763. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  764. showCmd.Flags().Bool("template", false, "Show template of a model")
  765. showCmd.Flags().Bool("system", false, "Show system prompt of a model")
  766. runCmd := &cobra.Command{
  767. Use: "run MODEL [PROMPT]",
  768. Short: "Run a model",
  769. Args: cobra.MinimumNArgs(1),
  770. PreRunE: checkServerHeartbeat,
  771. RunE: RunHandler,
  772. }
  773. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  774. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  775. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  776. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  777. serveCmd := &cobra.Command{
  778. Use: "serve",
  779. Aliases: []string{"start"},
  780. Short: "Start ollama",
  781. Args: cobra.ExactArgs(0),
  782. RunE: RunServer,
  783. }
  784. pullCmd := &cobra.Command{
  785. Use: "pull MODEL",
  786. Short: "Pull a model from a registry",
  787. Args: cobra.ExactArgs(1),
  788. PreRunE: checkServerHeartbeat,
  789. RunE: PullHandler,
  790. }
  791. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  792. pushCmd := &cobra.Command{
  793. Use: "push MODEL",
  794. Short: "Push a model to a registry",
  795. Args: cobra.ExactArgs(1),
  796. PreRunE: checkServerHeartbeat,
  797. RunE: PushHandler,
  798. }
  799. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  800. listCmd := &cobra.Command{
  801. Use: "list",
  802. Aliases: []string{"ls"},
  803. Short: "List models",
  804. PreRunE: checkServerHeartbeat,
  805. RunE: ListHandler,
  806. }
  807. copyCmd := &cobra.Command{
  808. Use: "cp SOURCE TARGET",
  809. Short: "Copy a model",
  810. Args: cobra.ExactArgs(2),
  811. PreRunE: checkServerHeartbeat,
  812. RunE: CopyHandler,
  813. }
  814. deleteCmd := &cobra.Command{
  815. Use: "rm MODEL [MODEL...]",
  816. Short: "Remove a model",
  817. Args: cobra.MinimumNArgs(1),
  818. PreRunE: checkServerHeartbeat,
  819. RunE: DeleteHandler,
  820. }
  821. rootCmd.AddCommand(
  822. serveCmd,
  823. createCmd,
  824. showCmd,
  825. runCmd,
  826. pullCmd,
  827. pushCmd,
  828. listCmd,
  829. copyCmd,
  830. deleteCmd,
  831. )
  832. return rootCmd
  833. }