cmd.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335
  1. package cmd
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/ed25519"
  6. "crypto/rand"
  7. "crypto/sha256"
  8. "encoding/pem"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "log"
  13. "net"
  14. "net/http"
  15. "os"
  16. "os/exec"
  17. "os/signal"
  18. "path/filepath"
  19. "regexp"
  20. "runtime"
  21. "slices"
  22. "strings"
  23. "syscall"
  24. "time"
  25. "github.com/olekukonko/tablewriter"
  26. "github.com/spf13/cobra"
  27. "golang.org/x/crypto/ssh"
  28. "golang.org/x/term"
  29. "github.com/jmorganca/ollama/api"
  30. "github.com/jmorganca/ollama/format"
  31. "github.com/jmorganca/ollama/parser"
  32. "github.com/jmorganca/ollama/progress"
  33. "github.com/jmorganca/ollama/readline"
  34. "github.com/jmorganca/ollama/server"
  35. "github.com/jmorganca/ollama/version"
  36. )
  37. type ImageData []byte
  38. func CreateHandler(cmd *cobra.Command, args []string) error {
  39. filename, _ := cmd.Flags().GetString("file")
  40. filename, err := filepath.Abs(filename)
  41. if err != nil {
  42. return err
  43. }
  44. client, err := api.ClientFromEnvironment()
  45. if err != nil {
  46. return err
  47. }
  48. p := progress.NewProgress(os.Stderr)
  49. defer p.Stop()
  50. bars := make(map[string]*progress.Bar)
  51. modelfile, err := os.ReadFile(filename)
  52. if err != nil {
  53. return err
  54. }
  55. commands, err := parser.Parse(bytes.NewReader(modelfile))
  56. if err != nil {
  57. return err
  58. }
  59. home, err := os.UserHomeDir()
  60. if err != nil {
  61. return err
  62. }
  63. status := "transferring model data"
  64. spinner := progress.NewSpinner(status)
  65. p.Add(status, spinner)
  66. for _, c := range commands {
  67. switch c.Name {
  68. case "model", "adapter":
  69. path := c.Args
  70. if path == "~" {
  71. path = home
  72. } else if strings.HasPrefix(path, "~/") {
  73. path = filepath.Join(home, path[2:])
  74. }
  75. if !filepath.IsAbs(path) {
  76. path = filepath.Join(filepath.Dir(filename), path)
  77. }
  78. bin, err := os.Open(path)
  79. if errors.Is(err, os.ErrNotExist) && c.Name == "model" {
  80. continue
  81. } else if err != nil {
  82. return err
  83. }
  84. defer bin.Close()
  85. hash := sha256.New()
  86. if _, err := io.Copy(hash, bin); err != nil {
  87. return err
  88. }
  89. bin.Seek(0, io.SeekStart)
  90. digest := fmt.Sprintf("sha256:%x", hash.Sum(nil))
  91. if err = client.CreateBlob(cmd.Context(), digest, bin); err != nil {
  92. return err
  93. }
  94. modelfile = bytes.ReplaceAll(modelfile, []byte(c.Args), []byte("@"+digest))
  95. }
  96. }
  97. fn := func(resp api.ProgressResponse) error {
  98. if resp.Digest != "" {
  99. spinner.Stop()
  100. bar, ok := bars[resp.Digest]
  101. if !ok {
  102. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  103. bars[resp.Digest] = bar
  104. p.Add(resp.Digest, bar)
  105. }
  106. bar.Set(resp.Completed)
  107. } else if status != resp.Status {
  108. spinner.Stop()
  109. status = resp.Status
  110. spinner = progress.NewSpinner(status)
  111. p.Add(status, spinner)
  112. }
  113. return nil
  114. }
  115. request := api.CreateRequest{Name: args[0], Modelfile: string(modelfile)}
  116. if err := client.Create(cmd.Context(), &request, fn); err != nil {
  117. return err
  118. }
  119. return nil
  120. }
  121. func RunHandler(cmd *cobra.Command, args []string) error {
  122. client, err := api.ClientFromEnvironment()
  123. if err != nil {
  124. return err
  125. }
  126. name := args[0]
  127. // check if the model exists on the server
  128. _, err = client.Show(cmd.Context(), &api.ShowRequest{Name: name})
  129. var statusError api.StatusError
  130. switch {
  131. case errors.As(err, &statusError) && statusError.StatusCode == http.StatusNotFound:
  132. if err := PullHandler(cmd, args); err != nil {
  133. return err
  134. }
  135. case err != nil:
  136. return err
  137. }
  138. return RunGenerate(cmd, args)
  139. }
  140. func PushHandler(cmd *cobra.Command, args []string) error {
  141. client, err := api.ClientFromEnvironment()
  142. if err != nil {
  143. return err
  144. }
  145. insecure, err := cmd.Flags().GetBool("insecure")
  146. if err != nil {
  147. return err
  148. }
  149. p := progress.NewProgress(os.Stderr)
  150. defer p.Stop()
  151. bars := make(map[string]*progress.Bar)
  152. var status string
  153. var spinner *progress.Spinner
  154. fn := func(resp api.ProgressResponse) error {
  155. if resp.Digest != "" {
  156. if spinner != nil {
  157. spinner.Stop()
  158. }
  159. bar, ok := bars[resp.Digest]
  160. if !ok {
  161. bar = progress.NewBar(fmt.Sprintf("pushing %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  162. bars[resp.Digest] = bar
  163. p.Add(resp.Digest, bar)
  164. }
  165. bar.Set(resp.Completed)
  166. } else if status != resp.Status {
  167. if spinner != nil {
  168. spinner.Stop()
  169. }
  170. status = resp.Status
  171. spinner = progress.NewSpinner(status)
  172. p.Add(status, spinner)
  173. }
  174. return nil
  175. }
  176. request := api.PushRequest{Name: args[0], Insecure: insecure}
  177. if err := client.Push(cmd.Context(), &request, fn); err != nil {
  178. return err
  179. }
  180. spinner.Stop()
  181. return nil
  182. }
  183. func ListHandler(cmd *cobra.Command, args []string) error {
  184. client, err := api.ClientFromEnvironment()
  185. if err != nil {
  186. return err
  187. }
  188. models, err := client.List(cmd.Context())
  189. if err != nil {
  190. return err
  191. }
  192. var data [][]string
  193. for _, m := range models.Models {
  194. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  195. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), format.HumanTime(m.ModifiedAt, "Never")})
  196. }
  197. }
  198. table := tablewriter.NewWriter(os.Stdout)
  199. table.SetHeader([]string{"NAME", "ID", "SIZE", "MODIFIED"})
  200. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  201. table.SetAlignment(tablewriter.ALIGN_LEFT)
  202. table.SetHeaderLine(false)
  203. table.SetBorder(false)
  204. table.SetNoWhiteSpace(true)
  205. table.SetTablePadding("\t")
  206. table.AppendBulk(data)
  207. table.Render()
  208. return nil
  209. }
  210. func DeleteHandler(cmd *cobra.Command, args []string) error {
  211. client, err := api.ClientFromEnvironment()
  212. if err != nil {
  213. return err
  214. }
  215. for _, name := range args {
  216. req := api.DeleteRequest{Name: name}
  217. if err := client.Delete(cmd.Context(), &req); err != nil {
  218. return err
  219. }
  220. fmt.Printf("deleted '%s'\n", name)
  221. }
  222. return nil
  223. }
  224. func ShowHandler(cmd *cobra.Command, args []string) error {
  225. client, err := api.ClientFromEnvironment()
  226. if err != nil {
  227. return err
  228. }
  229. if len(args) != 1 {
  230. return errors.New("missing model name")
  231. }
  232. license, errLicense := cmd.Flags().GetBool("license")
  233. modelfile, errModelfile := cmd.Flags().GetBool("modelfile")
  234. parameters, errParams := cmd.Flags().GetBool("parameters")
  235. system, errSystem := cmd.Flags().GetBool("system")
  236. template, errTemplate := cmd.Flags().GetBool("template")
  237. for _, boolErr := range []error{errLicense, errModelfile, errParams, errSystem, errTemplate} {
  238. if boolErr != nil {
  239. return errors.New("error retrieving flags")
  240. }
  241. }
  242. flagsSet := 0
  243. showType := ""
  244. if license {
  245. flagsSet++
  246. showType = "license"
  247. }
  248. if modelfile {
  249. flagsSet++
  250. showType = "modelfile"
  251. }
  252. if parameters {
  253. flagsSet++
  254. showType = "parameters"
  255. }
  256. if system {
  257. flagsSet++
  258. showType = "system"
  259. }
  260. if template {
  261. flagsSet++
  262. showType = "template"
  263. }
  264. if flagsSet > 1 {
  265. return errors.New("only one of '--license', '--modelfile', '--parameters', '--system', or '--template' can be specified")
  266. } else if flagsSet == 0 {
  267. return errors.New("one of '--license', '--modelfile', '--parameters', '--system', or '--template' must be specified")
  268. }
  269. req := api.ShowRequest{Name: args[0]}
  270. resp, err := client.Show(cmd.Context(), &req)
  271. if err != nil {
  272. return err
  273. }
  274. switch showType {
  275. case "license":
  276. fmt.Println(resp.License)
  277. case "modelfile":
  278. fmt.Println(resp.Modelfile)
  279. case "parameters":
  280. fmt.Println(resp.Parameters)
  281. case "system":
  282. fmt.Println(resp.System)
  283. case "template":
  284. fmt.Println(resp.Template)
  285. }
  286. return nil
  287. }
  288. func CopyHandler(cmd *cobra.Command, args []string) error {
  289. client, err := api.ClientFromEnvironment()
  290. if err != nil {
  291. return err
  292. }
  293. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  294. if err := client.Copy(cmd.Context(), &req); err != nil {
  295. return err
  296. }
  297. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  298. return nil
  299. }
  300. func PullHandler(cmd *cobra.Command, args []string) error {
  301. insecure, err := cmd.Flags().GetBool("insecure")
  302. if err != nil {
  303. return err
  304. }
  305. client, err := api.ClientFromEnvironment()
  306. if err != nil {
  307. return err
  308. }
  309. p := progress.NewProgress(os.Stderr)
  310. defer p.Stop()
  311. bars := make(map[string]*progress.Bar)
  312. var status string
  313. var spinner *progress.Spinner
  314. fn := func(resp api.ProgressResponse) error {
  315. if resp.Digest != "" {
  316. if spinner != nil {
  317. spinner.Stop()
  318. }
  319. bar, ok := bars[resp.Digest]
  320. if !ok {
  321. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  322. bars[resp.Digest] = bar
  323. p.Add(resp.Digest, bar)
  324. }
  325. bar.Set(resp.Completed)
  326. } else if status != resp.Status {
  327. if spinner != nil {
  328. spinner.Stop()
  329. }
  330. status = resp.Status
  331. spinner = progress.NewSpinner(status)
  332. p.Add(status, spinner)
  333. }
  334. return nil
  335. }
  336. request := api.PullRequest{Name: args[0], Insecure: insecure}
  337. if err := client.Pull(cmd.Context(), &request, fn); err != nil {
  338. return err
  339. }
  340. return nil
  341. }
  342. func RunGenerate(cmd *cobra.Command, args []string) error {
  343. interactive := true
  344. opts := generateOptions{
  345. Model: args[0],
  346. WordWrap: os.Getenv("TERM") == "xterm-256color",
  347. Options: map[string]interface{}{},
  348. Images: []ImageData{},
  349. }
  350. format, err := cmd.Flags().GetString("format")
  351. if err != nil {
  352. return err
  353. }
  354. opts.Format = format
  355. prompts := args[1:]
  356. // prepend stdin to the prompt if provided
  357. if !term.IsTerminal(int(os.Stdin.Fd())) {
  358. in, err := io.ReadAll(os.Stdin)
  359. if err != nil {
  360. return err
  361. }
  362. prompts = append([]string{string(in)}, prompts...)
  363. opts.WordWrap = false
  364. interactive = false
  365. }
  366. opts.Prompt = strings.Join(prompts, " ")
  367. if len(prompts) > 0 {
  368. interactive = false
  369. }
  370. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  371. if err != nil {
  372. return err
  373. }
  374. opts.WordWrap = !nowrap
  375. if !interactive {
  376. return generate(cmd, opts)
  377. }
  378. return generateInteractive(cmd, opts)
  379. }
  380. type generateContextKey string
  381. type generateOptions struct {
  382. Model string
  383. Prompt string
  384. WordWrap bool
  385. Format string
  386. System string
  387. Template string
  388. Images []ImageData
  389. Options map[string]interface{}
  390. }
  391. func generate(cmd *cobra.Command, opts generateOptions) error {
  392. client, err := api.ClientFromEnvironment()
  393. if err != nil {
  394. return err
  395. }
  396. p := progress.NewProgress(os.Stderr)
  397. defer p.StopAndClear()
  398. spinner := progress.NewSpinner("")
  399. p.Add("", spinner)
  400. var latest api.GenerateResponse
  401. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  402. if !ok {
  403. generateContext = []int{}
  404. }
  405. termWidth, _, err := term.GetSize(int(os.Stdout.Fd()))
  406. if err != nil {
  407. opts.WordWrap = false
  408. }
  409. ctx, cancel := context.WithCancel(cmd.Context())
  410. defer cancel()
  411. sigChan := make(chan os.Signal, 1)
  412. signal.Notify(sigChan, syscall.SIGINT)
  413. go func() {
  414. <-sigChan
  415. cancel()
  416. }()
  417. var currentLineLength int
  418. var wordBuffer string
  419. fn := func(response api.GenerateResponse) error {
  420. p.StopAndClear()
  421. latest = response
  422. termWidth, _, _ = term.GetSize(int(os.Stdout.Fd()))
  423. if opts.WordWrap && termWidth >= 10 {
  424. for _, ch := range response.Response {
  425. if currentLineLength+1 > termWidth-5 {
  426. if len(wordBuffer) > termWidth-10 {
  427. fmt.Printf("%s%c", wordBuffer, ch)
  428. wordBuffer = ""
  429. currentLineLength = 0
  430. continue
  431. }
  432. // backtrack the length of the last word and clear to the end of the line
  433. fmt.Printf("\x1b[%dD\x1b[K\n", len(wordBuffer))
  434. fmt.Printf("%s%c", wordBuffer, ch)
  435. currentLineLength = len(wordBuffer) + 1
  436. } else {
  437. fmt.Print(string(ch))
  438. currentLineLength += 1
  439. switch ch {
  440. case ' ':
  441. wordBuffer = ""
  442. case '\n':
  443. currentLineLength = 0
  444. default:
  445. wordBuffer += string(ch)
  446. }
  447. }
  448. }
  449. } else {
  450. fmt.Printf("%s%s", wordBuffer, response.Response)
  451. if len(wordBuffer) > 0 {
  452. wordBuffer = ""
  453. }
  454. }
  455. return nil
  456. }
  457. images := make([]api.ImageData, 0)
  458. for _, i := range opts.Images {
  459. images = append(images, api.ImageData(i))
  460. }
  461. request := api.GenerateRequest{
  462. Model: opts.Model,
  463. Prompt: opts.Prompt,
  464. Context: generateContext,
  465. Format: opts.Format,
  466. System: opts.System,
  467. Template: opts.Template,
  468. Options: opts.Options,
  469. Images: images,
  470. }
  471. if err := client.Generate(ctx, &request, fn); err != nil {
  472. if errors.Is(err, context.Canceled) {
  473. return nil
  474. }
  475. return err
  476. }
  477. if opts.Prompt != "" {
  478. fmt.Println()
  479. fmt.Println()
  480. }
  481. if !latest.Done {
  482. return nil
  483. }
  484. verbose, err := cmd.Flags().GetBool("verbose")
  485. if err != nil {
  486. return err
  487. }
  488. if verbose {
  489. latest.Summary()
  490. }
  491. ctx = context.WithValue(cmd.Context(), generateContextKey("context"), latest.Context)
  492. cmd.SetContext(ctx)
  493. return nil
  494. }
  495. type MultilineState int
  496. const (
  497. MultilineNone MultilineState = iota
  498. MultilinePrompt
  499. MultilineSystem
  500. MultilineTemplate
  501. )
  502. func modelIsMultiModal(cmd *cobra.Command, name string) bool {
  503. // get model details
  504. client, err := api.ClientFromEnvironment()
  505. if err != nil {
  506. fmt.Println("error: couldn't connect to ollama server")
  507. return false
  508. }
  509. req := api.ShowRequest{Name: name}
  510. resp, err := client.Show(cmd.Context(), &req)
  511. if err != nil {
  512. return false
  513. }
  514. return slices.Contains(resp.Details.Families, "clip")
  515. }
  516. func generateInteractive(cmd *cobra.Command, opts generateOptions) error {
  517. multiModal := modelIsMultiModal(cmd, opts.Model)
  518. // load the model
  519. loadOpts := generateOptions{
  520. Model: opts.Model,
  521. Prompt: "",
  522. Images: []ImageData{},
  523. }
  524. if err := generate(cmd, loadOpts); err != nil {
  525. return err
  526. }
  527. usage := func() {
  528. fmt.Fprintln(os.Stderr, "Available Commands:")
  529. fmt.Fprintln(os.Stderr, " /set Set session variables")
  530. fmt.Fprintln(os.Stderr, " /show Show model information")
  531. fmt.Fprintln(os.Stderr, " /bye Exit")
  532. fmt.Fprintln(os.Stderr, " /?, /help Help for a command")
  533. fmt.Fprintln(os.Stderr, "")
  534. fmt.Fprintln(os.Stderr, "Use \"\"\" to begin a multi-line message.")
  535. fmt.Fprintln(os.Stderr, "")
  536. }
  537. usageSet := func() {
  538. fmt.Fprintln(os.Stderr, "Available Commands:")
  539. fmt.Fprintln(os.Stderr, " /set parameter ... Set a parameter")
  540. fmt.Fprintln(os.Stderr, " /set system <string> Set system message")
  541. fmt.Fprintln(os.Stderr, " /set template <string> Set prompt template")
  542. fmt.Fprintln(os.Stderr, " /set history Enable history")
  543. fmt.Fprintln(os.Stderr, " /set nohistory Disable history")
  544. fmt.Fprintln(os.Stderr, " /set wordwrap Enable wordwrap")
  545. fmt.Fprintln(os.Stderr, " /set nowordwrap Disable wordwrap")
  546. fmt.Fprintln(os.Stderr, " /set format json Enable JSON mode")
  547. fmt.Fprintln(os.Stderr, " /set noformat Disable formatting")
  548. fmt.Fprintln(os.Stderr, " /set verbose Show LLM stats")
  549. fmt.Fprintln(os.Stderr, " /set quiet Disable LLM stats")
  550. fmt.Fprintln(os.Stderr, "")
  551. }
  552. usageShow := func() {
  553. fmt.Fprintln(os.Stderr, "Available Commands:")
  554. fmt.Fprintln(os.Stderr, " /show license Show model license")
  555. fmt.Fprintln(os.Stderr, " /show modelfile Show Modelfile for this model")
  556. fmt.Fprintln(os.Stderr, " /show parameters Show parameters for this model")
  557. fmt.Fprintln(os.Stderr, " /show system Show system message")
  558. fmt.Fprintln(os.Stderr, " /show template Show prompt template")
  559. fmt.Fprintln(os.Stderr, "")
  560. }
  561. // only list out the most common parameters
  562. usageParameters := func() {
  563. fmt.Fprintln(os.Stderr, "Available Parameters:")
  564. fmt.Fprintln(os.Stderr, " /set parameter seed <int> Random number seed")
  565. fmt.Fprintln(os.Stderr, " /set parameter num_predict <int> Max number of tokens to predict")
  566. fmt.Fprintln(os.Stderr, " /set parameter top_k <int> Pick from top k num of tokens")
  567. fmt.Fprintln(os.Stderr, " /set parameter top_p <float> Pick token based on sum of probabilities")
  568. fmt.Fprintln(os.Stderr, " /set parameter num_ctx <int> Set the context size")
  569. fmt.Fprintln(os.Stderr, " /set parameter temperature <float> Set creativity level")
  570. fmt.Fprintln(os.Stderr, " /set parameter repeat_penalty <float> How strongly to penalize repetitions")
  571. fmt.Fprintln(os.Stderr, " /set parameter repeat_last_n <int> Set how far back to look for repetitions")
  572. fmt.Fprintln(os.Stderr, " /set parameter num_gpu <int> The number of layers to send to the GPU")
  573. fmt.Fprintln(os.Stderr, " /set parameter stop \"<string>\", ... Set the stop parameters")
  574. fmt.Fprintln(os.Stderr, "")
  575. }
  576. scanner, err := readline.New(readline.Prompt{
  577. Prompt: ">>> ",
  578. AltPrompt: "... ",
  579. Placeholder: "Send a message (/? for help)",
  580. AltPlaceholder: `Use """ to end multi-line input`,
  581. })
  582. if err != nil {
  583. return err
  584. }
  585. fmt.Print(readline.StartBracketedPaste)
  586. defer fmt.Printf(readline.EndBracketedPaste)
  587. var multiline MultilineState
  588. var prompt string
  589. for {
  590. line, err := scanner.Readline()
  591. switch {
  592. case errors.Is(err, io.EOF):
  593. fmt.Println()
  594. return nil
  595. case errors.Is(err, readline.ErrInterrupt):
  596. if line == "" {
  597. fmt.Println("\nUse Ctrl-D or /bye to exit.")
  598. }
  599. scanner.Prompt.UseAlt = false
  600. prompt = ""
  601. continue
  602. case err != nil:
  603. return err
  604. }
  605. switch {
  606. case strings.HasPrefix(prompt, `"""`):
  607. // if the prompt so far starts with """ then we're in multiline mode
  608. // and we need to keep reading until we find a line that ends with """
  609. cut, found := strings.CutSuffix(line, `"""`)
  610. prompt += cut
  611. if !found {
  612. prompt += "\n"
  613. continue
  614. }
  615. prompt = strings.TrimPrefix(prompt, `"""`)
  616. scanner.Prompt.UseAlt = false
  617. switch multiline {
  618. case MultilineSystem:
  619. opts.System = prompt
  620. prompt = ""
  621. fmt.Println("Set system message.")
  622. case MultilineTemplate:
  623. opts.Template = prompt
  624. prompt = ""
  625. fmt.Println("Set prompt template.")
  626. }
  627. multiline = MultilineNone
  628. case strings.HasPrefix(line, `"""`) && len(prompt) == 0:
  629. scanner.Prompt.UseAlt = true
  630. multiline = MultilinePrompt
  631. prompt += line + "\n"
  632. continue
  633. case scanner.Pasting:
  634. prompt += line + "\n"
  635. continue
  636. case strings.HasPrefix(line, "/list"):
  637. args := strings.Fields(line)
  638. if err := ListHandler(cmd, args[1:]); err != nil {
  639. return err
  640. }
  641. case strings.HasPrefix(line, "/set"):
  642. args := strings.Fields(line)
  643. if len(args) > 1 {
  644. switch args[1] {
  645. case "history":
  646. scanner.HistoryEnable()
  647. case "nohistory":
  648. scanner.HistoryDisable()
  649. case "wordwrap":
  650. opts.WordWrap = true
  651. fmt.Println("Set 'wordwrap' mode.")
  652. case "nowordwrap":
  653. opts.WordWrap = false
  654. fmt.Println("Set 'nowordwrap' mode.")
  655. case "verbose":
  656. cmd.Flags().Set("verbose", "true")
  657. fmt.Println("Set 'verbose' mode.")
  658. case "quiet":
  659. cmd.Flags().Set("verbose", "false")
  660. fmt.Println("Set 'quiet' mode.")
  661. case "format":
  662. if len(args) < 3 || args[2] != "json" {
  663. fmt.Println("Invalid or missing format. For 'json' mode use '/set format json'")
  664. } else {
  665. opts.Format = args[2]
  666. fmt.Printf("Set format to '%s' mode.\n", args[2])
  667. }
  668. case "noformat":
  669. opts.Format = ""
  670. fmt.Println("Disabled format.")
  671. case "parameter":
  672. if len(args) < 4 {
  673. usageParameters()
  674. continue
  675. }
  676. var params []string
  677. for _, p := range args[3:] {
  678. params = append(params, p)
  679. }
  680. fp, err := api.FormatParams(map[string][]string{args[2]: params})
  681. if err != nil {
  682. fmt.Printf("Couldn't set parameter: %q\n\n", err)
  683. continue
  684. }
  685. fmt.Printf("Set parameter '%s' to '%s'\n\n", args[2], strings.Join(params, ", "))
  686. opts.Options[args[2]] = fp[args[2]]
  687. case "system", "template":
  688. if len(args) < 3 {
  689. usageSet()
  690. continue
  691. }
  692. line := strings.Join(args[2:], " ")
  693. line = strings.TrimPrefix(line, `"""`)
  694. if strings.HasPrefix(args[2], `"""`) {
  695. cut, found := strings.CutSuffix(line, `"""`)
  696. prompt += cut
  697. if found {
  698. if args[1] == "system" {
  699. opts.System = prompt
  700. fmt.Println("Set system message.")
  701. } else {
  702. opts.Template = prompt
  703. fmt.Println("Set prompt template.")
  704. }
  705. prompt = ""
  706. } else {
  707. prompt = `"""` + prompt + "\n"
  708. if args[1] == "system" {
  709. multiline = MultilineSystem
  710. } else {
  711. multiline = MultilineTemplate
  712. }
  713. scanner.Prompt.UseAlt = true
  714. }
  715. } else {
  716. opts.System = line
  717. fmt.Println("Set system message.")
  718. }
  719. default:
  720. fmt.Printf("Unknown command '/set %s'. Type /? for help\n", args[1])
  721. }
  722. } else {
  723. usageSet()
  724. }
  725. case strings.HasPrefix(line, "/show"):
  726. args := strings.Fields(line)
  727. if len(args) > 1 {
  728. client, err := api.ClientFromEnvironment()
  729. if err != nil {
  730. fmt.Println("error: couldn't connect to ollama server")
  731. return err
  732. }
  733. resp, err := client.Show(cmd.Context(), &api.ShowRequest{Name: opts.Model})
  734. if err != nil {
  735. fmt.Println("error: couldn't get model")
  736. return err
  737. }
  738. switch args[1] {
  739. case "license":
  740. if resp.License == "" {
  741. fmt.Print("No license was specified for this model.\n\n")
  742. } else {
  743. fmt.Println(resp.License)
  744. }
  745. case "modelfile":
  746. fmt.Println(resp.Modelfile)
  747. case "parameters":
  748. if resp.Parameters == "" {
  749. fmt.Print("No parameters were specified for this model.\n\n")
  750. } else {
  751. if len(opts.Options) > 0 {
  752. fmt.Println("User defined parameters:")
  753. for k, v := range opts.Options {
  754. fmt.Printf("%-*s %v\n", 30, k, v)
  755. }
  756. fmt.Println()
  757. }
  758. fmt.Println("Model defined parameters:")
  759. fmt.Println(resp.Parameters)
  760. }
  761. case "system":
  762. switch {
  763. case opts.System != "":
  764. fmt.Println(opts.System + "\n")
  765. case resp.System != "":
  766. fmt.Println(resp.System + "\n")
  767. default:
  768. fmt.Print("No system message was specified for this model.\n\n")
  769. }
  770. case "template":
  771. switch {
  772. case opts.Template != "":
  773. fmt.Println(opts.Template + "\n")
  774. case resp.Template != "":
  775. fmt.Println(resp.Template)
  776. default:
  777. fmt.Print("No prompt template was specified for this model.\n\n")
  778. }
  779. default:
  780. fmt.Printf("Unknown command '/show %s'. Type /? for help\n", args[1])
  781. }
  782. } else {
  783. usageShow()
  784. }
  785. case strings.HasPrefix(line, "/help"), strings.HasPrefix(line, "/?"):
  786. args := strings.Fields(line)
  787. if len(args) > 1 {
  788. switch args[1] {
  789. case "set", "/set":
  790. usageSet()
  791. case "show", "/show":
  792. usageShow()
  793. }
  794. } else {
  795. usage()
  796. }
  797. case line == "/exit", line == "/bye":
  798. return nil
  799. case strings.HasPrefix(line, "/"):
  800. args := strings.Fields(line)
  801. fmt.Printf("Unknown command '%s'. Type /? for help\n", args[0])
  802. continue
  803. default:
  804. prompt += line
  805. }
  806. if len(prompt) > 0 && multiline == MultilineNone {
  807. opts.Prompt = prompt
  808. if multiModal {
  809. newPrompt, images, err := extractFileNames(prompt)
  810. if err != nil {
  811. return err
  812. }
  813. opts.Prompt = newPrompt
  814. // reset the context if we find another image
  815. if len(images) > 0 {
  816. opts.Images = images
  817. ctx := cmd.Context()
  818. ctx = context.WithValue(ctx, generateContextKey("context"), []int{})
  819. cmd.SetContext(ctx)
  820. }
  821. if len(opts.Images) == 0 {
  822. fmt.Println("This model requires you to add a jpeg, png, or svg image.\n")
  823. prompt = ""
  824. continue
  825. }
  826. }
  827. if err := generate(cmd, opts); err != nil {
  828. return err
  829. }
  830. prompt = ""
  831. }
  832. }
  833. }
  834. func normalizeFilePath(fp string) string {
  835. // Define a map of escaped characters and their replacements
  836. replacements := map[string]string{
  837. "\\ ": " ", // Escaped space
  838. "\\(": "(", // Escaped left parenthesis
  839. "\\)": ")", // Escaped right parenthesis
  840. "\\[": "[", // Escaped left square bracket
  841. "\\]": "]", // Escaped right square bracket
  842. "\\{": "{", // Escaped left curly brace
  843. "\\}": "}", // Escaped right curly brace
  844. "\\$": "$", // Escaped dollar sign
  845. "\\&": "&", // Escaped ampersand
  846. "\\;": ";", // Escaped semicolon
  847. "\\'": "'", // Escaped single quote
  848. "\\\\": "\\", // Escaped backslash
  849. "\\*": "*", // Escaped asterisk
  850. "\\?": "?", // Escaped question mark
  851. }
  852. for escaped, actual := range replacements {
  853. fp = strings.ReplaceAll(fp, escaped, actual)
  854. }
  855. return fp
  856. }
  857. func extractFileNames(input string) (string, []ImageData, error) {
  858. // Regex to match file paths starting with / or ./ and include escaped spaces (\ or %20)
  859. // and followed by more characters and a file extension
  860. regexPattern := `(?:\./|/)[\S\\ ]+?\.(?i:jpg|jpeg|png|svg)\b`
  861. re := regexp.MustCompile(regexPattern)
  862. filePaths := re.FindAllString(input, -1)
  863. var imgs []ImageData
  864. for _, fp := range filePaths {
  865. nfp := normalizeFilePath(fp)
  866. data, err := getImageData(nfp)
  867. if err != nil {
  868. if os.IsNotExist(err) {
  869. continue
  870. }
  871. fmt.Printf("Couldn't process image: %q\n", err)
  872. return "", imgs, err
  873. }
  874. fmt.Printf("Added image '%s'\n", nfp)
  875. input = strings.ReplaceAll(input, fp, "")
  876. imgs = append(imgs, data)
  877. }
  878. return input, imgs, nil
  879. }
  880. func RunServer(cmd *cobra.Command, _ []string) error {
  881. host, port, err := net.SplitHostPort(os.Getenv("OLLAMA_HOST"))
  882. if err != nil {
  883. host, port = "127.0.0.1", "11434"
  884. if ip := net.ParseIP(strings.Trim(os.Getenv("OLLAMA_HOST"), "[]")); ip != nil {
  885. host = ip.String()
  886. }
  887. }
  888. if err := initializeKeypair(); err != nil {
  889. return err
  890. }
  891. ln, err := net.Listen("tcp", net.JoinHostPort(host, port))
  892. if err != nil {
  893. return err
  894. }
  895. var origins []string
  896. if o := os.Getenv("OLLAMA_ORIGINS"); o != "" {
  897. origins = strings.Split(o, ",")
  898. }
  899. return server.Serve(ln, origins)
  900. }
  901. func getImageData(filePath string) ([]byte, error) {
  902. file, err := os.Open(filePath)
  903. if err != nil {
  904. return nil, err
  905. }
  906. defer file.Close()
  907. buf := make([]byte, 512)
  908. _, err = file.Read(buf)
  909. if err != nil {
  910. return nil, err
  911. }
  912. contentType := http.DetectContentType(buf)
  913. allowedTypes := []string{"image/jpeg", "image/jpg", "image/svg+xml", "image/png"}
  914. if !slices.Contains(allowedTypes, contentType) {
  915. return nil, fmt.Errorf("invalid image type: %s", contentType)
  916. }
  917. info, err := file.Stat()
  918. if err != nil {
  919. return nil, err
  920. }
  921. // Check if the file size exceeds 100MB
  922. var maxSize int64 = 100 * 1024 * 1024 // 100MB in bytes
  923. if info.Size() > maxSize {
  924. return nil, fmt.Errorf("file size exceeds maximum limit (100MB).")
  925. }
  926. buf = make([]byte, info.Size())
  927. _, err = file.Seek(0, 0)
  928. if err != nil {
  929. return nil, err
  930. }
  931. _, err = io.ReadFull(file, buf)
  932. if err != nil {
  933. return nil, err
  934. }
  935. return buf, nil
  936. }
  937. func initializeKeypair() error {
  938. home, err := os.UserHomeDir()
  939. if err != nil {
  940. return err
  941. }
  942. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  943. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  944. _, err = os.Stat(privKeyPath)
  945. if os.IsNotExist(err) {
  946. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  947. _, privKey, err := ed25519.GenerateKey(rand.Reader)
  948. if err != nil {
  949. return err
  950. }
  951. privKeyBytes, err := format.OpenSSHPrivateKey(privKey, "")
  952. if err != nil {
  953. return err
  954. }
  955. err = os.MkdirAll(filepath.Dir(privKeyPath), 0o755)
  956. if err != nil {
  957. return fmt.Errorf("could not create directory %w", err)
  958. }
  959. err = os.WriteFile(privKeyPath, pem.EncodeToMemory(privKeyBytes), 0o600)
  960. if err != nil {
  961. return err
  962. }
  963. sshPrivateKey, err := ssh.NewSignerFromKey(privKey)
  964. if err != nil {
  965. return err
  966. }
  967. pubKeyData := ssh.MarshalAuthorizedKey(sshPrivateKey.PublicKey())
  968. err = os.WriteFile(pubKeyPath, pubKeyData, 0o644)
  969. if err != nil {
  970. return err
  971. }
  972. fmt.Printf("Your new public key is: \n\n%s\n", string(pubKeyData))
  973. }
  974. return nil
  975. }
  976. func startMacApp(ctx context.Context, client *api.Client) error {
  977. exe, err := os.Executable()
  978. if err != nil {
  979. return err
  980. }
  981. link, err := os.Readlink(exe)
  982. if err != nil {
  983. return err
  984. }
  985. if !strings.Contains(link, "Ollama.app") {
  986. return fmt.Errorf("could not find ollama app")
  987. }
  988. path := strings.Split(link, "Ollama.app")
  989. if err := exec.Command("/usr/bin/open", "-a", path[0]+"Ollama.app").Run(); err != nil {
  990. return err
  991. }
  992. // wait for the server to start
  993. timeout := time.After(5 * time.Second)
  994. tick := time.Tick(500 * time.Millisecond)
  995. for {
  996. select {
  997. case <-timeout:
  998. return errors.New("timed out waiting for server to start")
  999. case <-tick:
  1000. if err := client.Heartbeat(ctx); err == nil {
  1001. return nil // server has started
  1002. }
  1003. }
  1004. }
  1005. }
  1006. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  1007. client, err := api.ClientFromEnvironment()
  1008. if err != nil {
  1009. return err
  1010. }
  1011. if err := client.Heartbeat(cmd.Context()); err != nil {
  1012. if !strings.Contains(err.Error(), "connection refused") {
  1013. return err
  1014. }
  1015. if runtime.GOOS == "darwin" {
  1016. if err := startMacApp(cmd.Context(), client); err != nil {
  1017. return fmt.Errorf("could not connect to ollama app, is it running?")
  1018. }
  1019. } else {
  1020. return fmt.Errorf("could not connect to ollama server, run 'ollama serve' to start it")
  1021. }
  1022. }
  1023. return nil
  1024. }
  1025. func versionHandler(cmd *cobra.Command, _ []string) {
  1026. client, err := api.ClientFromEnvironment()
  1027. if err != nil {
  1028. return
  1029. }
  1030. serverVersion, err := client.Version(cmd.Context())
  1031. if err != nil {
  1032. fmt.Println("Warning: could not connect to a running Ollama instance")
  1033. }
  1034. if serverVersion != "" {
  1035. fmt.Printf("ollama version is %s\n", serverVersion)
  1036. }
  1037. if serverVersion != version.Version {
  1038. fmt.Printf("Warning: client version is %s\n", version.Version)
  1039. }
  1040. }
  1041. func NewCLI() *cobra.Command {
  1042. log.SetFlags(log.LstdFlags | log.Lshortfile)
  1043. cobra.EnableCommandSorting = false
  1044. rootCmd := &cobra.Command{
  1045. Use: "ollama",
  1046. Short: "Large language model runner",
  1047. SilenceUsage: true,
  1048. SilenceErrors: true,
  1049. CompletionOptions: cobra.CompletionOptions{
  1050. DisableDefaultCmd: true,
  1051. },
  1052. Run: func(cmd *cobra.Command, args []string) {
  1053. if version, _ := cmd.Flags().GetBool("version"); version {
  1054. versionHandler(cmd, args)
  1055. return
  1056. }
  1057. cmd.Print(cmd.UsageString())
  1058. },
  1059. }
  1060. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  1061. createCmd := &cobra.Command{
  1062. Use: "create MODEL",
  1063. Short: "Create a model from a Modelfile",
  1064. Args: cobra.ExactArgs(1),
  1065. PreRunE: checkServerHeartbeat,
  1066. RunE: CreateHandler,
  1067. }
  1068. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
  1069. showCmd := &cobra.Command{
  1070. Use: "show MODEL",
  1071. Short: "Show information for a model",
  1072. Args: cobra.ExactArgs(1),
  1073. PreRunE: checkServerHeartbeat,
  1074. RunE: ShowHandler,
  1075. }
  1076. showCmd.Flags().Bool("license", false, "Show license of a model")
  1077. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  1078. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  1079. showCmd.Flags().Bool("template", false, "Show template of a model")
  1080. showCmd.Flags().Bool("system", false, "Show system message of a model")
  1081. runCmd := &cobra.Command{
  1082. Use: "run MODEL [PROMPT]",
  1083. Short: "Run a model",
  1084. Args: cobra.MinimumNArgs(1),
  1085. PreRunE: checkServerHeartbeat,
  1086. RunE: RunHandler,
  1087. }
  1088. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  1089. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1090. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  1091. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  1092. serveCmd := &cobra.Command{
  1093. Use: "serve",
  1094. Aliases: []string{"start"},
  1095. Short: "Start ollama",
  1096. Args: cobra.ExactArgs(0),
  1097. RunE: RunServer,
  1098. }
  1099. pullCmd := &cobra.Command{
  1100. Use: "pull MODEL",
  1101. Short: "Pull a model from a registry",
  1102. Args: cobra.ExactArgs(1),
  1103. PreRunE: checkServerHeartbeat,
  1104. RunE: PullHandler,
  1105. }
  1106. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1107. pushCmd := &cobra.Command{
  1108. Use: "push MODEL",
  1109. Short: "Push a model to a registry",
  1110. Args: cobra.ExactArgs(1),
  1111. PreRunE: checkServerHeartbeat,
  1112. RunE: PushHandler,
  1113. }
  1114. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1115. listCmd := &cobra.Command{
  1116. Use: "list",
  1117. Aliases: []string{"ls"},
  1118. Short: "List models",
  1119. PreRunE: checkServerHeartbeat,
  1120. RunE: ListHandler,
  1121. }
  1122. copyCmd := &cobra.Command{
  1123. Use: "cp SOURCE TARGET",
  1124. Short: "Copy a model",
  1125. Args: cobra.ExactArgs(2),
  1126. PreRunE: checkServerHeartbeat,
  1127. RunE: CopyHandler,
  1128. }
  1129. deleteCmd := &cobra.Command{
  1130. Use: "rm MODEL [MODEL...]",
  1131. Short: "Remove a model",
  1132. Args: cobra.MinimumNArgs(1),
  1133. PreRunE: checkServerHeartbeat,
  1134. RunE: DeleteHandler,
  1135. }
  1136. rootCmd.AddCommand(
  1137. serveCmd,
  1138. createCmd,
  1139. showCmd,
  1140. runCmd,
  1141. pullCmd,
  1142. pushCmd,
  1143. listCmd,
  1144. copyCmd,
  1145. deleteCmd,
  1146. )
  1147. return rootCmd
  1148. }