cmd.go 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. package cmd
  2. import (
  3. "archive/zip"
  4. "bytes"
  5. "context"
  6. "crypto/ed25519"
  7. "crypto/rand"
  8. "crypto/sha256"
  9. "encoding/pem"
  10. "errors"
  11. "fmt"
  12. "io"
  13. "log"
  14. "net"
  15. "net/http"
  16. "os"
  17. "os/signal"
  18. "path/filepath"
  19. "runtime"
  20. "strings"
  21. "syscall"
  22. "time"
  23. "github.com/containerd/console"
  24. "github.com/olekukonko/tablewriter"
  25. "github.com/spf13/cobra"
  26. "golang.org/x/crypto/ssh"
  27. "golang.org/x/exp/slices"
  28. "golang.org/x/term"
  29. "github.com/ollama/ollama/api"
  30. "github.com/ollama/ollama/format"
  31. "github.com/ollama/ollama/parser"
  32. "github.com/ollama/ollama/progress"
  33. "github.com/ollama/ollama/server"
  34. "github.com/ollama/ollama/version"
  35. )
  36. func CreateHandler(cmd *cobra.Command, args []string) error {
  37. filename, _ := cmd.Flags().GetString("file")
  38. filename, err := filepath.Abs(filename)
  39. if err != nil {
  40. return err
  41. }
  42. client, err := api.ClientFromEnvironment()
  43. if err != nil {
  44. return err
  45. }
  46. p := progress.NewProgress(os.Stderr)
  47. defer p.Stop()
  48. bars := make(map[string]*progress.Bar)
  49. modelfile, err := os.ReadFile(filename)
  50. if err != nil {
  51. return err
  52. }
  53. commands, err := parser.Parse(bytes.NewReader(modelfile))
  54. if err != nil {
  55. return err
  56. }
  57. home, err := os.UserHomeDir()
  58. if err != nil {
  59. return err
  60. }
  61. status := "transferring model data"
  62. spinner := progress.NewSpinner(status)
  63. p.Add(status, spinner)
  64. for _, c := range commands {
  65. switch c.Name {
  66. case "model", "adapter":
  67. path := c.Args
  68. if path == "~" {
  69. path = home
  70. } else if strings.HasPrefix(path, "~/") {
  71. path = filepath.Join(home, path[2:])
  72. }
  73. if !filepath.IsAbs(path) {
  74. path = filepath.Join(filepath.Dir(filename), path)
  75. }
  76. fi, err := os.Stat(path)
  77. if errors.Is(err, os.ErrNotExist) && c.Name == "model" {
  78. continue
  79. } else if err != nil {
  80. return err
  81. }
  82. // TODO make this work w/ adapters
  83. if fi.IsDir() {
  84. tf, err := os.CreateTemp("", "ollama-tf")
  85. if err != nil {
  86. return err
  87. }
  88. defer os.RemoveAll(tf.Name())
  89. zf := zip.NewWriter(tf)
  90. files := []string{}
  91. tfiles, err := filepath.Glob(filepath.Join(path, "pytorch_model-*.bin"))
  92. if err != nil {
  93. return err
  94. } else if len(tfiles) == 0 {
  95. tfiles, err = filepath.Glob(filepath.Join(path, "model-*.safetensors"))
  96. if err != nil {
  97. return err
  98. }
  99. }
  100. files = append(files, tfiles...)
  101. if len(files) == 0 {
  102. return fmt.Errorf("no models were found in '%s'", path)
  103. }
  104. // add the safetensor/torch config file + tokenizer
  105. files = append(files, filepath.Join(path, "config.json"))
  106. files = append(files, filepath.Join(path, "params.json"))
  107. files = append(files, filepath.Join(path, "added_tokens.json"))
  108. files = append(files, filepath.Join(path, "tokenizer.model"))
  109. for _, fn := range files {
  110. f, err := os.Open(fn)
  111. // just skip whatever files aren't there
  112. if os.IsNotExist(err) {
  113. if strings.HasSuffix(fn, "tokenizer.model") {
  114. // try the parent dir before giving up
  115. parentDir := filepath.Dir(path)
  116. newFn := filepath.Join(parentDir, "tokenizer.model")
  117. f, err = os.Open(newFn)
  118. if os.IsNotExist(err) {
  119. continue
  120. } else if err != nil {
  121. return err
  122. }
  123. } else {
  124. continue
  125. }
  126. } else if err != nil {
  127. return err
  128. }
  129. fi, err := f.Stat()
  130. if err != nil {
  131. return err
  132. }
  133. h, err := zip.FileInfoHeader(fi)
  134. if err != nil {
  135. return err
  136. }
  137. h.Name = filepath.Base(fn)
  138. h.Method = zip.Store
  139. w, err := zf.CreateHeader(h)
  140. if err != nil {
  141. return err
  142. }
  143. _, err = io.Copy(w, f)
  144. if err != nil {
  145. return err
  146. }
  147. }
  148. if err := zf.Close(); err != nil {
  149. return err
  150. }
  151. if err := tf.Close(); err != nil {
  152. return err
  153. }
  154. path = tf.Name()
  155. }
  156. digest, err := createBlob(cmd, client, path)
  157. if err != nil {
  158. return err
  159. }
  160. modelfile = bytes.ReplaceAll(modelfile, []byte(c.Args), []byte("@"+digest))
  161. }
  162. }
  163. fn := func(resp api.ProgressResponse) error {
  164. if resp.Digest != "" {
  165. spinner.Stop()
  166. bar, ok := bars[resp.Digest]
  167. if !ok {
  168. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  169. bars[resp.Digest] = bar
  170. p.Add(resp.Digest, bar)
  171. }
  172. bar.Set(resp.Completed)
  173. } else if status != resp.Status {
  174. spinner.Stop()
  175. status = resp.Status
  176. spinner = progress.NewSpinner(status)
  177. p.Add(status, spinner)
  178. }
  179. return nil
  180. }
  181. quantization, _ := cmd.Flags().GetString("quantization")
  182. request := api.CreateRequest{Name: args[0], Modelfile: string(modelfile), Quantization: quantization}
  183. if err := client.Create(cmd.Context(), &request, fn); err != nil {
  184. return err
  185. }
  186. return nil
  187. }
  188. func createBlob(cmd *cobra.Command, client *api.Client, path string) (string, error) {
  189. bin, err := os.Open(path)
  190. if err != nil {
  191. return "", err
  192. }
  193. defer bin.Close()
  194. hash := sha256.New()
  195. if _, err := io.Copy(hash, bin); err != nil {
  196. return "", err
  197. }
  198. if _, err := bin.Seek(0, io.SeekStart); err != nil {
  199. return "", err
  200. }
  201. digest := fmt.Sprintf("sha256:%x", hash.Sum(nil))
  202. if err = client.CreateBlob(cmd.Context(), digest, bin); err != nil {
  203. return "", err
  204. }
  205. return digest, nil
  206. }
  207. func RunHandler(cmd *cobra.Command, args []string) error {
  208. if os.Getenv("OLLAMA_MODELS") != "" {
  209. return errors.New("OLLAMA_MODELS must only be set for 'ollama serve'")
  210. }
  211. if err := checkServerHeartbeat(cmd, args); err != nil {
  212. return err
  213. }
  214. client, err := api.ClientFromEnvironment()
  215. if err != nil {
  216. return err
  217. }
  218. name := args[0]
  219. // check if the model exists on the server
  220. show, err := client.Show(cmd.Context(), &api.ShowRequest{Name: name})
  221. var statusError api.StatusError
  222. switch {
  223. case errors.As(err, &statusError) && statusError.StatusCode == http.StatusNotFound:
  224. if err := PullHandler(cmd, []string{name}); err != nil {
  225. return err
  226. }
  227. show, err = client.Show(cmd.Context(), &api.ShowRequest{Name: name})
  228. if err != nil {
  229. return err
  230. }
  231. case err != nil:
  232. return err
  233. }
  234. interactive := true
  235. opts := runOptions{
  236. Model: args[0],
  237. WordWrap: os.Getenv("TERM") == "xterm-256color",
  238. Options: map[string]interface{}{},
  239. MultiModal: slices.Contains(show.Details.Families, "clip"),
  240. ParentModel: show.Details.ParentModel,
  241. }
  242. format, err := cmd.Flags().GetString("format")
  243. if err != nil {
  244. return err
  245. }
  246. opts.Format = format
  247. prompts := args[1:]
  248. // prepend stdin to the prompt if provided
  249. if !term.IsTerminal(int(os.Stdin.Fd())) {
  250. in, err := io.ReadAll(os.Stdin)
  251. if err != nil {
  252. return err
  253. }
  254. prompts = append([]string{string(in)}, prompts...)
  255. opts.WordWrap = false
  256. interactive = false
  257. }
  258. opts.Prompt = strings.Join(prompts, " ")
  259. if len(prompts) > 0 {
  260. interactive = false
  261. }
  262. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  263. if err != nil {
  264. return err
  265. }
  266. opts.WordWrap = !nowrap
  267. if !interactive {
  268. return generate(cmd, opts)
  269. }
  270. return generateInteractive(cmd, opts)
  271. }
  272. func PushHandler(cmd *cobra.Command, args []string) error {
  273. client, err := api.ClientFromEnvironment()
  274. if err != nil {
  275. return err
  276. }
  277. insecure, err := cmd.Flags().GetBool("insecure")
  278. if err != nil {
  279. return err
  280. }
  281. p := progress.NewProgress(os.Stderr)
  282. defer p.Stop()
  283. bars := make(map[string]*progress.Bar)
  284. var status string
  285. var spinner *progress.Spinner
  286. fn := func(resp api.ProgressResponse) error {
  287. if resp.Digest != "" {
  288. if spinner != nil {
  289. spinner.Stop()
  290. }
  291. bar, ok := bars[resp.Digest]
  292. if !ok {
  293. bar = progress.NewBar(fmt.Sprintf("pushing %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  294. bars[resp.Digest] = bar
  295. p.Add(resp.Digest, bar)
  296. }
  297. bar.Set(resp.Completed)
  298. } else if status != resp.Status {
  299. if spinner != nil {
  300. spinner.Stop()
  301. }
  302. status = resp.Status
  303. spinner = progress.NewSpinner(status)
  304. p.Add(status, spinner)
  305. }
  306. return nil
  307. }
  308. request := api.PushRequest{Name: args[0], Insecure: insecure}
  309. if err := client.Push(cmd.Context(), &request, fn); err != nil {
  310. return err
  311. }
  312. spinner.Stop()
  313. return nil
  314. }
  315. func ListHandler(cmd *cobra.Command, args []string) error {
  316. client, err := api.ClientFromEnvironment()
  317. if err != nil {
  318. return err
  319. }
  320. models, err := client.List(cmd.Context())
  321. if err != nil {
  322. return err
  323. }
  324. var data [][]string
  325. for _, m := range models.Models {
  326. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  327. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), format.HumanTime(m.ModifiedAt, "Never")})
  328. }
  329. }
  330. table := tablewriter.NewWriter(os.Stdout)
  331. table.SetHeader([]string{"NAME", "ID", "SIZE", "MODIFIED"})
  332. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  333. table.SetAlignment(tablewriter.ALIGN_LEFT)
  334. table.SetHeaderLine(false)
  335. table.SetBorder(false)
  336. table.SetNoWhiteSpace(true)
  337. table.SetTablePadding("\t")
  338. table.AppendBulk(data)
  339. table.Render()
  340. return nil
  341. }
  342. func DeleteHandler(cmd *cobra.Command, args []string) error {
  343. client, err := api.ClientFromEnvironment()
  344. if err != nil {
  345. return err
  346. }
  347. for _, name := range args {
  348. req := api.DeleteRequest{Name: name}
  349. if err := client.Delete(cmd.Context(), &req); err != nil {
  350. return err
  351. }
  352. fmt.Printf("deleted '%s'\n", name)
  353. }
  354. return nil
  355. }
  356. func ShowHandler(cmd *cobra.Command, args []string) error {
  357. client, err := api.ClientFromEnvironment()
  358. if err != nil {
  359. return err
  360. }
  361. if len(args) != 1 {
  362. return errors.New("missing model name")
  363. }
  364. license, errLicense := cmd.Flags().GetBool("license")
  365. modelfile, errModelfile := cmd.Flags().GetBool("modelfile")
  366. parameters, errParams := cmd.Flags().GetBool("parameters")
  367. system, errSystem := cmd.Flags().GetBool("system")
  368. template, errTemplate := cmd.Flags().GetBool("template")
  369. for _, boolErr := range []error{errLicense, errModelfile, errParams, errSystem, errTemplate} {
  370. if boolErr != nil {
  371. return errors.New("error retrieving flags")
  372. }
  373. }
  374. flagsSet := 0
  375. showType := ""
  376. if license {
  377. flagsSet++
  378. showType = "license"
  379. }
  380. if modelfile {
  381. flagsSet++
  382. showType = "modelfile"
  383. }
  384. if parameters {
  385. flagsSet++
  386. showType = "parameters"
  387. }
  388. if system {
  389. flagsSet++
  390. showType = "system"
  391. }
  392. if template {
  393. flagsSet++
  394. showType = "template"
  395. }
  396. if flagsSet > 1 {
  397. return errors.New("only one of '--license', '--modelfile', '--parameters', '--system', or '--template' can be specified")
  398. } else if flagsSet == 0 {
  399. return errors.New("one of '--license', '--modelfile', '--parameters', '--system', or '--template' must be specified")
  400. }
  401. req := api.ShowRequest{Name: args[0]}
  402. resp, err := client.Show(cmd.Context(), &req)
  403. if err != nil {
  404. return err
  405. }
  406. switch showType {
  407. case "license":
  408. fmt.Println(resp.License)
  409. case "modelfile":
  410. fmt.Println(resp.Modelfile)
  411. case "parameters":
  412. fmt.Println(resp.Parameters)
  413. case "system":
  414. fmt.Println(resp.System)
  415. case "template":
  416. fmt.Println(resp.Template)
  417. }
  418. return nil
  419. }
  420. func CopyHandler(cmd *cobra.Command, args []string) error {
  421. client, err := api.ClientFromEnvironment()
  422. if err != nil {
  423. return err
  424. }
  425. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  426. if err := client.Copy(cmd.Context(), &req); err != nil {
  427. return err
  428. }
  429. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  430. return nil
  431. }
  432. func PullHandler(cmd *cobra.Command, args []string) error {
  433. insecure, err := cmd.Flags().GetBool("insecure")
  434. if err != nil {
  435. return err
  436. }
  437. client, err := api.ClientFromEnvironment()
  438. if err != nil {
  439. return err
  440. }
  441. p := progress.NewProgress(os.Stderr)
  442. defer p.Stop()
  443. bars := make(map[string]*progress.Bar)
  444. var status string
  445. var spinner *progress.Spinner
  446. fn := func(resp api.ProgressResponse) error {
  447. if resp.Digest != "" {
  448. if spinner != nil {
  449. spinner.Stop()
  450. }
  451. bar, ok := bars[resp.Digest]
  452. if !ok {
  453. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  454. bars[resp.Digest] = bar
  455. p.Add(resp.Digest, bar)
  456. }
  457. bar.Set(resp.Completed)
  458. } else if status != resp.Status {
  459. if spinner != nil {
  460. spinner.Stop()
  461. }
  462. status = resp.Status
  463. spinner = progress.NewSpinner(status)
  464. p.Add(status, spinner)
  465. }
  466. return nil
  467. }
  468. request := api.PullRequest{Name: args[0], Insecure: insecure}
  469. if err := client.Pull(cmd.Context(), &request, fn); err != nil {
  470. return err
  471. }
  472. return nil
  473. }
  474. type generateContextKey string
  475. type runOptions struct {
  476. Model string
  477. ParentModel string
  478. Prompt string
  479. Messages []api.Message
  480. WordWrap bool
  481. Format string
  482. System string
  483. Template string
  484. Images []api.ImageData
  485. Options map[string]interface{}
  486. MultiModal bool
  487. }
  488. type displayResponseState struct {
  489. lineLength int
  490. wordBuffer string
  491. }
  492. func displayResponse(content string, wordWrap bool, state *displayResponseState) {
  493. termWidth, _, _ := term.GetSize(int(os.Stdout.Fd()))
  494. if wordWrap && termWidth >= 10 {
  495. for _, ch := range content {
  496. if state.lineLength+1 > termWidth-5 {
  497. if len(state.wordBuffer) > termWidth-10 {
  498. fmt.Printf("%s%c", state.wordBuffer, ch)
  499. state.wordBuffer = ""
  500. state.lineLength = 0
  501. continue
  502. }
  503. // backtrack the length of the last word and clear to the end of the line
  504. fmt.Printf("\x1b[%dD\x1b[K\n", len(state.wordBuffer))
  505. fmt.Printf("%s%c", state.wordBuffer, ch)
  506. state.lineLength = len(state.wordBuffer) + 1
  507. } else {
  508. fmt.Print(string(ch))
  509. state.lineLength += 1
  510. switch ch {
  511. case ' ':
  512. state.wordBuffer = ""
  513. case '\n':
  514. state.lineLength = 0
  515. default:
  516. state.wordBuffer += string(ch)
  517. }
  518. }
  519. }
  520. } else {
  521. fmt.Printf("%s%s", state.wordBuffer, content)
  522. if len(state.wordBuffer) > 0 {
  523. state.wordBuffer = ""
  524. }
  525. }
  526. }
  527. func chat(cmd *cobra.Command, opts runOptions) (*api.Message, error) {
  528. client, err := api.ClientFromEnvironment()
  529. if err != nil {
  530. return nil, err
  531. }
  532. p := progress.NewProgress(os.Stderr)
  533. defer p.StopAndClear()
  534. spinner := progress.NewSpinner("")
  535. p.Add("", spinner)
  536. cancelCtx, cancel := context.WithCancel(cmd.Context())
  537. defer cancel()
  538. sigChan := make(chan os.Signal, 1)
  539. signal.Notify(sigChan, syscall.SIGINT)
  540. go func() {
  541. <-sigChan
  542. cancel()
  543. }()
  544. var state *displayResponseState = &displayResponseState{}
  545. var latest api.ChatResponse
  546. var fullResponse strings.Builder
  547. var role string
  548. fn := func(response api.ChatResponse) error {
  549. p.StopAndClear()
  550. latest = response
  551. role = response.Message.Role
  552. content := response.Message.Content
  553. fullResponse.WriteString(content)
  554. displayResponse(content, opts.WordWrap, state)
  555. return nil
  556. }
  557. req := &api.ChatRequest{
  558. Model: opts.Model,
  559. Messages: opts.Messages,
  560. Format: opts.Format,
  561. Options: opts.Options,
  562. }
  563. if err := client.Chat(cancelCtx, req, fn); err != nil {
  564. if errors.Is(err, context.Canceled) {
  565. return nil, nil
  566. }
  567. return nil, err
  568. }
  569. if len(opts.Messages) > 0 {
  570. fmt.Println()
  571. fmt.Println()
  572. }
  573. verbose, err := cmd.Flags().GetBool("verbose")
  574. if err != nil {
  575. return nil, err
  576. }
  577. if verbose {
  578. latest.Summary()
  579. }
  580. return &api.Message{Role: role, Content: fullResponse.String()}, nil
  581. }
  582. func generate(cmd *cobra.Command, opts runOptions) error {
  583. client, err := api.ClientFromEnvironment()
  584. if err != nil {
  585. return err
  586. }
  587. p := progress.NewProgress(os.Stderr)
  588. defer p.StopAndClear()
  589. spinner := progress.NewSpinner("")
  590. p.Add("", spinner)
  591. var latest api.GenerateResponse
  592. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  593. if !ok {
  594. generateContext = []int{}
  595. }
  596. ctx, cancel := context.WithCancel(cmd.Context())
  597. defer cancel()
  598. sigChan := make(chan os.Signal, 1)
  599. signal.Notify(sigChan, syscall.SIGINT)
  600. go func() {
  601. <-sigChan
  602. cancel()
  603. }()
  604. var state *displayResponseState = &displayResponseState{}
  605. fn := func(response api.GenerateResponse) error {
  606. p.StopAndClear()
  607. latest = response
  608. content := response.Response
  609. displayResponse(content, opts.WordWrap, state)
  610. return nil
  611. }
  612. if opts.MultiModal {
  613. opts.Prompt, opts.Images, err = extractFileData(opts.Prompt)
  614. if err != nil {
  615. return err
  616. }
  617. }
  618. request := api.GenerateRequest{
  619. Model: opts.Model,
  620. Prompt: opts.Prompt,
  621. Context: generateContext,
  622. Images: opts.Images,
  623. Format: opts.Format,
  624. System: opts.System,
  625. Template: opts.Template,
  626. Options: opts.Options,
  627. }
  628. if err := client.Generate(ctx, &request, fn); err != nil {
  629. if errors.Is(err, context.Canceled) {
  630. return nil
  631. }
  632. return err
  633. }
  634. if opts.Prompt != "" {
  635. fmt.Println()
  636. fmt.Println()
  637. }
  638. if !latest.Done {
  639. return nil
  640. }
  641. verbose, err := cmd.Flags().GetBool("verbose")
  642. if err != nil {
  643. return err
  644. }
  645. if verbose {
  646. latest.Summary()
  647. }
  648. ctx = context.WithValue(cmd.Context(), generateContextKey("context"), latest.Context)
  649. cmd.SetContext(ctx)
  650. return nil
  651. }
  652. func RunServer(cmd *cobra.Command, _ []string) error {
  653. host, port, err := net.SplitHostPort(strings.Trim(os.Getenv("OLLAMA_HOST"), "\"'"))
  654. if err != nil {
  655. host, port = "127.0.0.1", "11434"
  656. if ip := net.ParseIP(strings.Trim(os.Getenv("OLLAMA_HOST"), "[]")); ip != nil {
  657. host = ip.String()
  658. }
  659. }
  660. if err := initializeKeypair(); err != nil {
  661. return err
  662. }
  663. ln, err := net.Listen("tcp", net.JoinHostPort(host, port))
  664. if err != nil {
  665. return err
  666. }
  667. return server.Serve(ln)
  668. }
  669. func initializeKeypair() error {
  670. home, err := os.UserHomeDir()
  671. if err != nil {
  672. return err
  673. }
  674. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  675. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  676. _, err = os.Stat(privKeyPath)
  677. if os.IsNotExist(err) {
  678. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  679. cryptoPublicKey, cryptoPrivateKey, err := ed25519.GenerateKey(rand.Reader)
  680. if err != nil {
  681. return err
  682. }
  683. privateKeyBytes, err := ssh.MarshalPrivateKey(cryptoPrivateKey, "")
  684. if err != nil {
  685. return err
  686. }
  687. if err := os.MkdirAll(filepath.Dir(privKeyPath), 0o755); err != nil {
  688. return fmt.Errorf("could not create directory %w", err)
  689. }
  690. if err := os.WriteFile(privKeyPath, pem.EncodeToMemory(privateKeyBytes), 0o600); err != nil {
  691. return err
  692. }
  693. sshPublicKey, err := ssh.NewPublicKey(cryptoPublicKey)
  694. if err != nil {
  695. return err
  696. }
  697. publicKeyBytes := ssh.MarshalAuthorizedKey(sshPublicKey)
  698. if err := os.WriteFile(pubKeyPath, publicKeyBytes, 0o644); err != nil {
  699. return err
  700. }
  701. fmt.Printf("Your new public key is: \n\n%s\n", publicKeyBytes)
  702. }
  703. return nil
  704. }
  705. //nolint:unused
  706. func waitForServer(ctx context.Context, client *api.Client) error {
  707. // wait for the server to start
  708. timeout := time.After(5 * time.Second)
  709. tick := time.Tick(500 * time.Millisecond)
  710. for {
  711. select {
  712. case <-timeout:
  713. return errors.New("timed out waiting for server to start")
  714. case <-tick:
  715. if err := client.Heartbeat(ctx); err == nil {
  716. return nil // server has started
  717. }
  718. }
  719. }
  720. }
  721. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  722. client, err := api.ClientFromEnvironment()
  723. if err != nil {
  724. return err
  725. }
  726. if err := client.Heartbeat(cmd.Context()); err != nil {
  727. if !strings.Contains(err.Error(), " refused") {
  728. return err
  729. }
  730. if err := startApp(cmd.Context(), client); err != nil {
  731. return fmt.Errorf("could not connect to ollama app, is it running?")
  732. }
  733. }
  734. return nil
  735. }
  736. func versionHandler(cmd *cobra.Command, _ []string) {
  737. client, err := api.ClientFromEnvironment()
  738. if err != nil {
  739. return
  740. }
  741. serverVersion, err := client.Version(cmd.Context())
  742. if err != nil {
  743. fmt.Println("Warning: could not connect to a running Ollama instance")
  744. }
  745. if serverVersion != "" {
  746. fmt.Printf("ollama version is %s\n", serverVersion)
  747. }
  748. if serverVersion != version.Version {
  749. fmt.Printf("Warning: client version is %s\n", version.Version)
  750. }
  751. }
  752. func appendHostEnvDocs(cmd *cobra.Command) {
  753. const hostEnvDocs = `
  754. Environment Variables:
  755. OLLAMA_HOST The host:port or base URL of the Ollama server (e.g. http://localhost:11434)
  756. `
  757. cmd.SetUsageTemplate(cmd.UsageTemplate() + hostEnvDocs)
  758. }
  759. func NewCLI() *cobra.Command {
  760. log.SetFlags(log.LstdFlags | log.Lshortfile)
  761. cobra.EnableCommandSorting = false
  762. if runtime.GOOS == "windows" {
  763. console.ConsoleFromFile(os.Stdin) //nolint:errcheck
  764. }
  765. rootCmd := &cobra.Command{
  766. Use: "ollama",
  767. Short: "Large language model runner",
  768. SilenceUsage: true,
  769. SilenceErrors: true,
  770. CompletionOptions: cobra.CompletionOptions{
  771. DisableDefaultCmd: true,
  772. },
  773. Run: func(cmd *cobra.Command, args []string) {
  774. if version, _ := cmd.Flags().GetBool("version"); version {
  775. versionHandler(cmd, args)
  776. return
  777. }
  778. cmd.Print(cmd.UsageString())
  779. },
  780. }
  781. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  782. createCmd := &cobra.Command{
  783. Use: "create MODEL",
  784. Short: "Create a model from a Modelfile",
  785. Args: cobra.ExactArgs(1),
  786. PreRunE: checkServerHeartbeat,
  787. RunE: CreateHandler,
  788. }
  789. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
  790. createCmd.Flags().StringP("quantization", "q", "", "Quantization level.")
  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 message of a model")
  803. runCmd := &cobra.Command{
  804. Use: "run MODEL [PROMPT]",
  805. Short: "Run a model",
  806. Args: cobra.MinimumNArgs(1),
  807. RunE: RunHandler,
  808. }
  809. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  810. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  811. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  812. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  813. serveCmd := &cobra.Command{
  814. Use: "serve",
  815. Aliases: []string{"start"},
  816. Short: "Start ollama",
  817. Args: cobra.ExactArgs(0),
  818. RunE: RunServer,
  819. }
  820. serveCmd.SetUsageTemplate(serveCmd.UsageTemplate() + `
  821. Environment Variables:
  822. OLLAMA_HOST The host:port to bind to (default "127.0.0.1:11434")
  823. OLLAMA_ORIGINS A comma separated list of allowed origins.
  824. OLLAMA_MODELS The path to the models directory (default is "~/.ollama/models")
  825. OLLAMA_KEEP_ALIVE The duration that models stay loaded in memory (default is "5m")
  826. OLLAMA_DEBUG Set to 1 to enable additional debug logging
  827. `)
  828. pullCmd := &cobra.Command{
  829. Use: "pull MODEL",
  830. Short: "Pull a model from a registry",
  831. Args: cobra.ExactArgs(1),
  832. PreRunE: checkServerHeartbeat,
  833. RunE: PullHandler,
  834. }
  835. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  836. pushCmd := &cobra.Command{
  837. Use: "push MODEL",
  838. Short: "Push a model to a registry",
  839. Args: cobra.ExactArgs(1),
  840. PreRunE: checkServerHeartbeat,
  841. RunE: PushHandler,
  842. }
  843. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  844. listCmd := &cobra.Command{
  845. Use: "list",
  846. Aliases: []string{"ls"},
  847. Short: "List models",
  848. PreRunE: checkServerHeartbeat,
  849. RunE: ListHandler,
  850. }
  851. copyCmd := &cobra.Command{
  852. Use: "cp SOURCE TARGET",
  853. Short: "Copy a model",
  854. Args: cobra.ExactArgs(2),
  855. PreRunE: checkServerHeartbeat,
  856. RunE: CopyHandler,
  857. }
  858. deleteCmd := &cobra.Command{
  859. Use: "rm MODEL [MODEL...]",
  860. Short: "Remove a model",
  861. Args: cobra.MinimumNArgs(1),
  862. PreRunE: checkServerHeartbeat,
  863. RunE: DeleteHandler,
  864. }
  865. for _, cmd := range []*cobra.Command{
  866. createCmd,
  867. showCmd,
  868. runCmd,
  869. pullCmd,
  870. pushCmd,
  871. listCmd,
  872. copyCmd,
  873. deleteCmd,
  874. } {
  875. appendHostEnvDocs(cmd)
  876. }
  877. rootCmd.AddCommand(
  878. serveCmd,
  879. createCmd,
  880. showCmd,
  881. runCmd,
  882. pullCmd,
  883. pushCmd,
  884. listCmd,
  885. copyCmd,
  886. deleteCmd,
  887. )
  888. return rootCmd
  889. }