cmd.go 23 KB

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