cmd.go 28 KB

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