cmd.go 28 KB

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