cmd.go 23 KB

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