cmd.go 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333
  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 prompt")
  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 prompt")
  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 + "\n"
  611. if !found {
  612. continue
  613. }
  614. prompt = strings.TrimPrefix(prompt, `"""`)
  615. scanner.Prompt.UseAlt = false
  616. switch multiline {
  617. case MultilineSystem:
  618. opts.System = prompt
  619. prompt = ""
  620. fmt.Println("Set system template.")
  621. case MultilineTemplate:
  622. opts.Template = prompt
  623. prompt = ""
  624. fmt.Println("Set model template.")
  625. }
  626. multiline = MultilineNone
  627. case strings.HasPrefix(line, `"""`) && len(prompt) == 0:
  628. scanner.Prompt.UseAlt = true
  629. multiline = MultilinePrompt
  630. prompt += line + "\n"
  631. continue
  632. case scanner.Pasting:
  633. prompt += line + "\n"
  634. continue
  635. case strings.HasPrefix(line, "/list"):
  636. args := strings.Fields(line)
  637. if err := ListHandler(cmd, args[1:]); err != nil {
  638. return err
  639. }
  640. case strings.HasPrefix(line, "/set"):
  641. args := strings.Fields(line)
  642. if len(args) > 1 {
  643. switch args[1] {
  644. case "history":
  645. scanner.HistoryEnable()
  646. case "nohistory":
  647. scanner.HistoryDisable()
  648. case "wordwrap":
  649. opts.WordWrap = true
  650. fmt.Println("Set 'wordwrap' mode.")
  651. case "nowordwrap":
  652. opts.WordWrap = false
  653. fmt.Println("Set 'nowordwrap' mode.")
  654. case "verbose":
  655. cmd.Flags().Set("verbose", "true")
  656. fmt.Println("Set 'verbose' mode.")
  657. case "quiet":
  658. cmd.Flags().Set("verbose", "false")
  659. fmt.Println("Set 'quiet' mode.")
  660. case "format":
  661. if len(args) < 3 || args[2] != "json" {
  662. fmt.Println("Invalid or missing format. For 'json' mode use '/set format json'")
  663. } else {
  664. opts.Format = args[2]
  665. fmt.Printf("Set format to '%s' mode.\n", args[2])
  666. }
  667. case "noformat":
  668. opts.Format = ""
  669. fmt.Println("Disabled format.")
  670. case "parameter":
  671. if len(args) < 4 {
  672. usageParameters()
  673. continue
  674. }
  675. var params []string
  676. for _, p := range args[3:] {
  677. params = append(params, p)
  678. }
  679. fp, err := api.FormatParams(map[string][]string{args[2]: params})
  680. if err != nil {
  681. fmt.Printf("Couldn't set parameter: %q\n\n", err)
  682. continue
  683. }
  684. fmt.Printf("Set parameter '%s' to '%s'\n\n", args[2], strings.Join(params, ", "))
  685. opts.Options[args[2]] = fp[args[2]]
  686. case "system", "template":
  687. if len(args) < 3 {
  688. usageSet()
  689. continue
  690. }
  691. line := strings.Join(args[2:], " ")
  692. line = strings.TrimPrefix(line, `"""`)
  693. if strings.HasPrefix(args[2], `"""`) {
  694. cut, found := strings.CutSuffix(line, `"""`)
  695. prompt += cut + "\n"
  696. if found {
  697. opts.System = prompt
  698. if args[1] == "system" {
  699. fmt.Println("Set system template.")
  700. } else {
  701. fmt.Println("Set prompt template.")
  702. }
  703. prompt = ""
  704. } else {
  705. prompt = `"""` + prompt
  706. if args[1] == "system" {
  707. multiline = MultilineSystem
  708. } else {
  709. multiline = MultilineTemplate
  710. }
  711. scanner.Prompt.UseAlt = true
  712. }
  713. } else {
  714. opts.System = line
  715. fmt.Println("Set system template.")
  716. }
  717. default:
  718. fmt.Printf("Unknown command '/set %s'. Type /? for help\n", args[1])
  719. }
  720. } else {
  721. usageSet()
  722. }
  723. case strings.HasPrefix(line, "/show"):
  724. args := strings.Fields(line)
  725. if len(args) > 1 {
  726. client, err := api.ClientFromEnvironment()
  727. if err != nil {
  728. fmt.Println("error: couldn't connect to ollama server")
  729. return err
  730. }
  731. resp, err := client.Show(cmd.Context(), &api.ShowRequest{Name: opts.Model})
  732. if err != nil {
  733. fmt.Println("error: couldn't get model")
  734. return err
  735. }
  736. switch args[1] {
  737. case "license":
  738. if resp.License == "" {
  739. fmt.Print("No license was specified for this model.\n\n")
  740. } else {
  741. fmt.Println(resp.License)
  742. }
  743. case "modelfile":
  744. fmt.Println(resp.Modelfile)
  745. case "parameters":
  746. if resp.Parameters == "" {
  747. fmt.Print("No parameters were specified for this model.\n\n")
  748. } else {
  749. if len(opts.Options) > 0 {
  750. fmt.Println("User defined parameters:")
  751. for k, v := range opts.Options {
  752. fmt.Printf("%-*s %v\n", 30, k, v)
  753. }
  754. fmt.Println()
  755. }
  756. fmt.Println("Model defined parameters:")
  757. fmt.Println(resp.Parameters)
  758. }
  759. case "system":
  760. switch {
  761. case opts.System != "":
  762. fmt.Println(opts.System + "\n")
  763. case resp.System != "":
  764. fmt.Println(resp.System + "\n")
  765. default:
  766. fmt.Print("No system prompt was specified for this model.\n\n")
  767. }
  768. case "template":
  769. switch {
  770. case opts.Template != "":
  771. fmt.Println(opts.Template + "\n")
  772. case resp.Template != "":
  773. fmt.Println(resp.Template)
  774. default:
  775. fmt.Print("No prompt template was specified for this model.\n\n")
  776. }
  777. default:
  778. fmt.Printf("Unknown command '/show %s'. Type /? for help\n", args[1])
  779. }
  780. } else {
  781. usageShow()
  782. }
  783. case strings.HasPrefix(line, "/help"), strings.HasPrefix(line, "/?"):
  784. args := strings.Fields(line)
  785. if len(args) > 1 {
  786. switch args[1] {
  787. case "set", "/set":
  788. usageSet()
  789. case "show", "/show":
  790. usageShow()
  791. }
  792. } else {
  793. usage()
  794. }
  795. case line == "/exit", line == "/bye":
  796. return nil
  797. case strings.HasPrefix(line, "/"):
  798. args := strings.Fields(line)
  799. fmt.Printf("Unknown command '%s'. Type /? for help\n", args[0])
  800. continue
  801. default:
  802. prompt += line
  803. }
  804. if len(prompt) > 0 && multiline == MultilineNone {
  805. opts.Prompt = prompt
  806. if multiModal {
  807. newPrompt, images, err := extractFileNames(prompt)
  808. if err != nil {
  809. return err
  810. }
  811. opts.Prompt = newPrompt
  812. // reset the context if we find another image
  813. if len(images) > 0 {
  814. opts.Images = images
  815. ctx := cmd.Context()
  816. ctx = context.WithValue(ctx, generateContextKey("context"), []int{})
  817. cmd.SetContext(ctx)
  818. }
  819. if len(opts.Images) == 0 {
  820. fmt.Println("This model requires you to add a jpeg, png, or svg image.\n")
  821. prompt = ""
  822. continue
  823. }
  824. }
  825. if err := generate(cmd, opts); err != nil {
  826. return err
  827. }
  828. prompt = ""
  829. }
  830. }
  831. }
  832. func normalizeFilePath(fp string) string {
  833. // Define a map of escaped characters and their replacements
  834. replacements := map[string]string{
  835. "\\ ": " ", // Escaped space
  836. "\\(": "(", // Escaped left parenthesis
  837. "\\)": ")", // Escaped right parenthesis
  838. "\\[": "[", // Escaped left square bracket
  839. "\\]": "]", // Escaped right square bracket
  840. "\\{": "{", // Escaped left curly brace
  841. "\\}": "}", // Escaped right curly brace
  842. "\\$": "$", // Escaped dollar sign
  843. "\\&": "&", // Escaped ampersand
  844. "\\;": ";", // Escaped semicolon
  845. "\\'": "'", // Escaped single quote
  846. "\\\\": "\\", // Escaped backslash
  847. "\\*": "*", // Escaped asterisk
  848. "\\?": "?", // Escaped question mark
  849. }
  850. for escaped, actual := range replacements {
  851. fp = strings.ReplaceAll(fp, escaped, actual)
  852. }
  853. return fp
  854. }
  855. func extractFileNames(input string) (string, []ImageData, error) {
  856. // Regex to match file paths starting with / or ./ and include escaped spaces (\ or %20)
  857. // and followed by more characters and a file extension
  858. regexPattern := `(?:\./|/)[\S\\ ]+?\.(?i:jpg|jpeg|png|svg)\b`
  859. re := regexp.MustCompile(regexPattern)
  860. filePaths := re.FindAllString(input, -1)
  861. var imgs []ImageData
  862. for _, fp := range filePaths {
  863. nfp := normalizeFilePath(fp)
  864. data, err := getImageData(nfp)
  865. if err != nil {
  866. if os.IsNotExist(err) {
  867. continue
  868. }
  869. fmt.Printf("Couldn't process image: %q\n", err)
  870. return "", imgs, err
  871. }
  872. fmt.Printf("Added image '%s'\n", nfp)
  873. input = strings.ReplaceAll(input, fp, "")
  874. imgs = append(imgs, data)
  875. }
  876. return input, imgs, nil
  877. }
  878. func RunServer(cmd *cobra.Command, _ []string) error {
  879. host, port, err := net.SplitHostPort(os.Getenv("OLLAMA_HOST"))
  880. if err != nil {
  881. host, port = "127.0.0.1", "11434"
  882. if ip := net.ParseIP(strings.Trim(os.Getenv("OLLAMA_HOST"), "[]")); ip != nil {
  883. host = ip.String()
  884. }
  885. }
  886. if err := initializeKeypair(); err != nil {
  887. return err
  888. }
  889. ln, err := net.Listen("tcp", net.JoinHostPort(host, port))
  890. if err != nil {
  891. return err
  892. }
  893. var origins []string
  894. if o := os.Getenv("OLLAMA_ORIGINS"); o != "" {
  895. origins = strings.Split(o, ",")
  896. }
  897. return server.Serve(ln, origins)
  898. }
  899. func getImageData(filePath string) ([]byte, error) {
  900. file, err := os.Open(filePath)
  901. if err != nil {
  902. return nil, err
  903. }
  904. defer file.Close()
  905. buf := make([]byte, 512)
  906. _, err = file.Read(buf)
  907. if err != nil {
  908. return nil, err
  909. }
  910. contentType := http.DetectContentType(buf)
  911. allowedTypes := []string{"image/jpeg", "image/jpg", "image/svg+xml", "image/png"}
  912. if !slices.Contains(allowedTypes, contentType) {
  913. return nil, fmt.Errorf("invalid image type: %s", contentType)
  914. }
  915. info, err := file.Stat()
  916. if err != nil {
  917. return nil, err
  918. }
  919. // Check if the file size exceeds 100MB
  920. var maxSize int64 = 100 * 1024 * 1024 // 100MB in bytes
  921. if info.Size() > maxSize {
  922. return nil, fmt.Errorf("file size exceeds maximum limit (100MB).")
  923. }
  924. buf = make([]byte, info.Size())
  925. _, err = file.Seek(0, 0)
  926. if err != nil {
  927. return nil, err
  928. }
  929. _, err = io.ReadFull(file, buf)
  930. if err != nil {
  931. return nil, err
  932. }
  933. return buf, nil
  934. }
  935. func initializeKeypair() error {
  936. home, err := os.UserHomeDir()
  937. if err != nil {
  938. return err
  939. }
  940. privKeyPath := filepath.Join(home, ".ollama", "id_ed25519")
  941. pubKeyPath := filepath.Join(home, ".ollama", "id_ed25519.pub")
  942. _, err = os.Stat(privKeyPath)
  943. if os.IsNotExist(err) {
  944. fmt.Printf("Couldn't find '%s'. Generating new private key.\n", privKeyPath)
  945. _, privKey, err := ed25519.GenerateKey(rand.Reader)
  946. if err != nil {
  947. return err
  948. }
  949. privKeyBytes, err := format.OpenSSHPrivateKey(privKey, "")
  950. if err != nil {
  951. return err
  952. }
  953. err = os.MkdirAll(filepath.Dir(privKeyPath), 0o755)
  954. if err != nil {
  955. return fmt.Errorf("could not create directory %w", err)
  956. }
  957. err = os.WriteFile(privKeyPath, pem.EncodeToMemory(privKeyBytes), 0o600)
  958. if err != nil {
  959. return err
  960. }
  961. sshPrivateKey, err := ssh.NewSignerFromKey(privKey)
  962. if err != nil {
  963. return err
  964. }
  965. pubKeyData := ssh.MarshalAuthorizedKey(sshPrivateKey.PublicKey())
  966. err = os.WriteFile(pubKeyPath, pubKeyData, 0o644)
  967. if err != nil {
  968. return err
  969. }
  970. fmt.Printf("Your new public key is: \n\n%s\n", string(pubKeyData))
  971. }
  972. return nil
  973. }
  974. func startMacApp(ctx context.Context, client *api.Client) error {
  975. exe, err := os.Executable()
  976. if err != nil {
  977. return err
  978. }
  979. link, err := os.Readlink(exe)
  980. if err != nil {
  981. return err
  982. }
  983. if !strings.Contains(link, "Ollama.app") {
  984. return fmt.Errorf("could not find ollama app")
  985. }
  986. path := strings.Split(link, "Ollama.app")
  987. if err := exec.Command("/usr/bin/open", "-a", path[0]+"Ollama.app").Run(); err != nil {
  988. return err
  989. }
  990. // wait for the server to start
  991. timeout := time.After(5 * time.Second)
  992. tick := time.Tick(500 * time.Millisecond)
  993. for {
  994. select {
  995. case <-timeout:
  996. return errors.New("timed out waiting for server to start")
  997. case <-tick:
  998. if err := client.Heartbeat(ctx); err == nil {
  999. return nil // server has started
  1000. }
  1001. }
  1002. }
  1003. }
  1004. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  1005. client, err := api.ClientFromEnvironment()
  1006. if err != nil {
  1007. return err
  1008. }
  1009. if err := client.Heartbeat(cmd.Context()); err != nil {
  1010. if !strings.Contains(err.Error(), "connection refused") {
  1011. return err
  1012. }
  1013. if runtime.GOOS == "darwin" {
  1014. if err := startMacApp(cmd.Context(), client); err != nil {
  1015. return fmt.Errorf("could not connect to ollama app, is it running?")
  1016. }
  1017. } else {
  1018. return fmt.Errorf("could not connect to ollama server, run 'ollama serve' to start it")
  1019. }
  1020. }
  1021. return nil
  1022. }
  1023. func versionHandler(cmd *cobra.Command, _ []string) {
  1024. client, err := api.ClientFromEnvironment()
  1025. if err != nil {
  1026. return
  1027. }
  1028. serverVersion, err := client.Version(cmd.Context())
  1029. if err != nil {
  1030. fmt.Println("Warning: could not connect to a running Ollama instance")
  1031. }
  1032. if serverVersion != "" {
  1033. fmt.Printf("ollama version is %s\n", serverVersion)
  1034. }
  1035. if serverVersion != version.Version {
  1036. fmt.Printf("Warning: client version is %s\n", version.Version)
  1037. }
  1038. }
  1039. func NewCLI() *cobra.Command {
  1040. log.SetFlags(log.LstdFlags | log.Lshortfile)
  1041. cobra.EnableCommandSorting = false
  1042. rootCmd := &cobra.Command{
  1043. Use: "ollama",
  1044. Short: "Large language model runner",
  1045. SilenceUsage: true,
  1046. SilenceErrors: true,
  1047. CompletionOptions: cobra.CompletionOptions{
  1048. DisableDefaultCmd: true,
  1049. },
  1050. Run: func(cmd *cobra.Command, args []string) {
  1051. if version, _ := cmd.Flags().GetBool("version"); version {
  1052. versionHandler(cmd, args)
  1053. return
  1054. }
  1055. cmd.Print(cmd.UsageString())
  1056. },
  1057. }
  1058. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  1059. createCmd := &cobra.Command{
  1060. Use: "create MODEL",
  1061. Short: "Create a model from a Modelfile",
  1062. Args: cobra.ExactArgs(1),
  1063. PreRunE: checkServerHeartbeat,
  1064. RunE: CreateHandler,
  1065. }
  1066. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
  1067. showCmd := &cobra.Command{
  1068. Use: "show MODEL",
  1069. Short: "Show information for a model",
  1070. Args: cobra.ExactArgs(1),
  1071. PreRunE: checkServerHeartbeat,
  1072. RunE: ShowHandler,
  1073. }
  1074. showCmd.Flags().Bool("license", false, "Show license of a model")
  1075. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  1076. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  1077. showCmd.Flags().Bool("template", false, "Show template of a model")
  1078. showCmd.Flags().Bool("system", false, "Show system prompt of a model")
  1079. runCmd := &cobra.Command{
  1080. Use: "run MODEL [PROMPT]",
  1081. Short: "Run a model",
  1082. Args: cobra.MinimumNArgs(1),
  1083. PreRunE: checkServerHeartbeat,
  1084. RunE: RunHandler,
  1085. }
  1086. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  1087. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1088. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  1089. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  1090. serveCmd := &cobra.Command{
  1091. Use: "serve",
  1092. Aliases: []string{"start"},
  1093. Short: "Start ollama",
  1094. Args: cobra.ExactArgs(0),
  1095. RunE: RunServer,
  1096. }
  1097. pullCmd := &cobra.Command{
  1098. Use: "pull MODEL",
  1099. Short: "Pull a model from a registry",
  1100. Args: cobra.ExactArgs(1),
  1101. PreRunE: checkServerHeartbeat,
  1102. RunE: PullHandler,
  1103. }
  1104. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1105. pushCmd := &cobra.Command{
  1106. Use: "push MODEL",
  1107. Short: "Push a model to a registry",
  1108. Args: cobra.ExactArgs(1),
  1109. PreRunE: checkServerHeartbeat,
  1110. RunE: PushHandler,
  1111. }
  1112. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1113. listCmd := &cobra.Command{
  1114. Use: "list",
  1115. Aliases: []string{"ls"},
  1116. Short: "List models",
  1117. PreRunE: checkServerHeartbeat,
  1118. RunE: ListHandler,
  1119. }
  1120. copyCmd := &cobra.Command{
  1121. Use: "cp SOURCE TARGET",
  1122. Short: "Copy a model",
  1123. Args: cobra.ExactArgs(2),
  1124. PreRunE: checkServerHeartbeat,
  1125. RunE: CopyHandler,
  1126. }
  1127. deleteCmd := &cobra.Command{
  1128. Use: "rm MODEL [MODEL...]",
  1129. Short: "Remove a model",
  1130. Args: cobra.MinimumNArgs(1),
  1131. PreRunE: checkServerHeartbeat,
  1132. RunE: DeleteHandler,
  1133. }
  1134. rootCmd.AddCommand(
  1135. serveCmd,
  1136. createCmd,
  1137. showCmd,
  1138. runCmd,
  1139. pullCmd,
  1140. pushCmd,
  1141. listCmd,
  1142. copyCmd,
  1143. deleteCmd,
  1144. )
  1145. return rootCmd
  1146. }