cmd.go 23 KB

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