cmd.go 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319
  1. package cmd
  2. import (
  3. "archive/zip"
  4. "bytes"
  5. "context"
  6. "crypto/sha256"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "log"
  11. "math"
  12. "net"
  13. "net/http"
  14. "os"
  15. "os/signal"
  16. "path/filepath"
  17. "regexp"
  18. "runtime"
  19. "slices"
  20. "strings"
  21. "syscall"
  22. "time"
  23. "github.com/containerd/console"
  24. "github.com/mattn/go-runewidth"
  25. "github.com/olekukonko/tablewriter"
  26. "github.com/spf13/cobra"
  27. "golang.org/x/crypto/ssh"
  28. "golang.org/x/term"
  29. "github.com/ollama/ollama/api"
  30. "github.com/ollama/ollama/auth"
  31. "github.com/ollama/ollama/envconfig"
  32. "github.com/ollama/ollama/format"
  33. "github.com/ollama/ollama/parser"
  34. "github.com/ollama/ollama/progress"
  35. "github.com/ollama/ollama/server"
  36. "github.com/ollama/ollama/types/errtypes"
  37. "github.com/ollama/ollama/types/model"
  38. "github.com/ollama/ollama/version"
  39. )
  40. func CreateHandler(cmd *cobra.Command, args []string) error {
  41. filename, _ := cmd.Flags().GetString("file")
  42. filename, err := filepath.Abs(filename)
  43. if err != nil {
  44. return err
  45. }
  46. client, err := api.ClientFromEnvironment()
  47. if err != nil {
  48. return err
  49. }
  50. p := progress.NewProgress(os.Stderr)
  51. defer p.Stop()
  52. f, err := os.Open(filename)
  53. if err != nil {
  54. return err
  55. }
  56. defer f.Close()
  57. modelfile, err := parser.ParseFile(f)
  58. if err != nil {
  59. return err
  60. }
  61. home, err := os.UserHomeDir()
  62. if err != nil {
  63. return err
  64. }
  65. status := "transferring model data"
  66. spinner := progress.NewSpinner(status)
  67. p.Add(status, spinner)
  68. for i := range modelfile.Commands {
  69. switch modelfile.Commands[i].Name {
  70. case "model", "adapter":
  71. path := modelfile.Commands[i].Args
  72. if path == "~" {
  73. path = home
  74. } else if strings.HasPrefix(path, "~/") {
  75. path = filepath.Join(home, path[2:])
  76. }
  77. if !filepath.IsAbs(path) {
  78. path = filepath.Join(filepath.Dir(filename), path)
  79. }
  80. fi, err := os.Stat(path)
  81. if errors.Is(err, os.ErrNotExist) && modelfile.Commands[i].Name == "model" {
  82. continue
  83. } else if err != nil {
  84. return err
  85. }
  86. if fi.IsDir() {
  87. // this is likely a safetensors or pytorch directory
  88. // TODO make this work w/ adapters
  89. tempfile, err := tempZipFiles(path)
  90. if err != nil {
  91. return err
  92. }
  93. defer os.RemoveAll(tempfile)
  94. path = tempfile
  95. }
  96. digest, err := createBlob(cmd, client, path)
  97. if err != nil {
  98. return err
  99. }
  100. modelfile.Commands[i].Args = "@" + digest
  101. }
  102. }
  103. bars := make(map[string]*progress.Bar)
  104. fn := func(resp api.ProgressResponse) error {
  105. if resp.Digest != "" {
  106. spinner.Stop()
  107. bar, ok := bars[resp.Digest]
  108. if !ok {
  109. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  110. bars[resp.Digest] = bar
  111. p.Add(resp.Digest, bar)
  112. }
  113. bar.Set(resp.Completed)
  114. } else if status != resp.Status {
  115. spinner.Stop()
  116. status = resp.Status
  117. spinner = progress.NewSpinner(status)
  118. p.Add(status, spinner)
  119. }
  120. return nil
  121. }
  122. quantize, _ := cmd.Flags().GetString("quantize")
  123. request := api.CreateRequest{Name: args[0], Modelfile: modelfile.String(), Quantize: quantize}
  124. if err := client.Create(cmd.Context(), &request, fn); err != nil {
  125. return err
  126. }
  127. return nil
  128. }
  129. func tempZipFiles(path string) (string, error) {
  130. tempfile, err := os.CreateTemp("", "ollama-tf")
  131. if err != nil {
  132. return "", err
  133. }
  134. defer tempfile.Close()
  135. detectContentType := func(path string) (string, error) {
  136. f, err := os.Open(path)
  137. if err != nil {
  138. return "", err
  139. }
  140. defer f.Close()
  141. var b bytes.Buffer
  142. b.Grow(512)
  143. if _, err := io.CopyN(&b, f, 512); err != nil && !errors.Is(err, io.EOF) {
  144. return "", err
  145. }
  146. contentType, _, _ := strings.Cut(http.DetectContentType(b.Bytes()), ";")
  147. return contentType, nil
  148. }
  149. glob := func(pattern, contentType string) ([]string, error) {
  150. matches, err := filepath.Glob(pattern)
  151. if err != nil {
  152. return nil, err
  153. }
  154. for _, safetensor := range matches {
  155. if ct, err := detectContentType(safetensor); err != nil {
  156. return nil, err
  157. } else if ct != contentType {
  158. return nil, fmt.Errorf("invalid content type: expected %s for %s", ct, safetensor)
  159. }
  160. }
  161. return matches, nil
  162. }
  163. var files []string
  164. if st, _ := glob(filepath.Join(path, "model*.safetensors"), "application/octet-stream"); len(st) > 0 {
  165. // safetensors files might be unresolved git lfs references; skip if they are
  166. // covers model-x-of-y.safetensors, model.fp32-x-of-y.safetensors, model.safetensors
  167. files = append(files, st...)
  168. } else if pt, _ := glob(filepath.Join(path, "pytorch_model*.bin"), "application/zip"); len(pt) > 0 {
  169. // pytorch files might also be unresolved git lfs references; skip if they are
  170. // covers pytorch_model-x-of-y.bin, pytorch_model.fp32-x-of-y.bin, pytorch_model.bin
  171. files = append(files, pt...)
  172. } else if pt, _ := glob(filepath.Join(path, "consolidated*.pth"), "application/zip"); len(pt) > 0 {
  173. // pytorch files might also be unresolved git lfs references; skip if they are
  174. // covers consolidated.x.pth, consolidated.pth
  175. files = append(files, pt...)
  176. } else {
  177. return "", errors.New("no safetensors or torch files found")
  178. }
  179. // add configuration files, json files are detected as text/plain
  180. js, err := glob(filepath.Join(path, "*.json"), "text/plain")
  181. if err != nil {
  182. return "", err
  183. }
  184. files = append(files, js...)
  185. if tks, _ := glob(filepath.Join(path, "tokenizer.model"), "application/octet-stream"); len(tks) > 0 {
  186. // add tokenizer.model if it exists, tokenizer.json is automatically picked up by the previous glob
  187. // tokenizer.model might be a unresolved git lfs reference; error if it is
  188. files = append(files, tks...)
  189. } else if tks, _ := glob(filepath.Join(path, "**/tokenizer.model"), "text/plain"); len(tks) > 0 {
  190. // some times tokenizer.model is in a subdirectory (e.g. meta-llama/Meta-Llama-3-8B)
  191. files = append(files, tks...)
  192. }
  193. zipfile := zip.NewWriter(tempfile)
  194. defer zipfile.Close()
  195. for _, file := range files {
  196. f, err := os.Open(file)
  197. if err != nil {
  198. return "", err
  199. }
  200. defer f.Close()
  201. fi, err := f.Stat()
  202. if err != nil {
  203. return "", err
  204. }
  205. zfi, err := zip.FileInfoHeader(fi)
  206. if err != nil {
  207. return "", err
  208. }
  209. zf, err := zipfile.CreateHeader(zfi)
  210. if err != nil {
  211. return "", err
  212. }
  213. if _, err := io.Copy(zf, f); err != nil {
  214. return "", err
  215. }
  216. }
  217. return tempfile.Name(), nil
  218. }
  219. func createBlob(cmd *cobra.Command, client *api.Client, path string) (string, error) {
  220. bin, err := os.Open(path)
  221. if err != nil {
  222. return "", err
  223. }
  224. defer bin.Close()
  225. hash := sha256.New()
  226. if _, err := io.Copy(hash, bin); err != nil {
  227. return "", err
  228. }
  229. if _, err := bin.Seek(0, io.SeekStart); err != nil {
  230. return "", err
  231. }
  232. digest := fmt.Sprintf("sha256:%x", hash.Sum(nil))
  233. if err = client.CreateBlob(cmd.Context(), digest, bin); err != nil {
  234. return "", err
  235. }
  236. return digest, nil
  237. }
  238. func RunHandler(cmd *cobra.Command, args []string) error {
  239. interactive := true
  240. opts := runOptions{
  241. Model: args[0],
  242. WordWrap: os.Getenv("TERM") == "xterm-256color",
  243. Options: map[string]interface{}{},
  244. }
  245. format, err := cmd.Flags().GetString("format")
  246. if err != nil {
  247. return err
  248. }
  249. opts.Format = format
  250. keepAlive, err := cmd.Flags().GetString("keepalive")
  251. if err != nil {
  252. return err
  253. }
  254. if keepAlive != "" {
  255. d, err := time.ParseDuration(keepAlive)
  256. if err != nil {
  257. return err
  258. }
  259. opts.KeepAlive = &api.Duration{Duration: d}
  260. }
  261. prompts := args[1:]
  262. // prepend stdin to the prompt if provided
  263. if !term.IsTerminal(int(os.Stdin.Fd())) {
  264. in, err := io.ReadAll(os.Stdin)
  265. if err != nil {
  266. return err
  267. }
  268. prompts = append([]string{string(in)}, prompts...)
  269. opts.WordWrap = false
  270. interactive = false
  271. }
  272. opts.Prompt = strings.Join(prompts, " ")
  273. if len(prompts) > 0 {
  274. interactive = false
  275. }
  276. nowrap, err := cmd.Flags().GetBool("nowordwrap")
  277. if err != nil {
  278. return err
  279. }
  280. opts.WordWrap = !nowrap
  281. // Fill out the rest of the options based on information about the
  282. // model.
  283. client, err := api.ClientFromEnvironment()
  284. if err != nil {
  285. return err
  286. }
  287. name := args[0]
  288. info, err := func() (*api.ShowResponse, error) {
  289. showReq := &api.ShowRequest{Name: name}
  290. info, err := client.Show(cmd.Context(), showReq)
  291. var se api.StatusError
  292. if errors.As(err, &se) && se.StatusCode == http.StatusNotFound {
  293. if err := PullHandler(cmd, []string{name}); err != nil {
  294. return nil, err
  295. }
  296. return client.Show(cmd.Context(), &api.ShowRequest{Name: name})
  297. }
  298. return info, err
  299. }()
  300. if err != nil {
  301. return err
  302. }
  303. opts.MultiModal = slices.Contains(info.Details.Families, "clip")
  304. opts.ParentModel = info.Details.ParentModel
  305. opts.Messages = append(opts.Messages, info.Messages...)
  306. if interactive {
  307. return generateInteractive(cmd, opts)
  308. }
  309. return generate(cmd, opts)
  310. }
  311. func errFromUnknownKey(unknownKeyErr error) error {
  312. // find SSH public key in the error message
  313. sshKeyPattern := `ssh-\w+ [^\s"]+`
  314. re := regexp.MustCompile(sshKeyPattern)
  315. matches := re.FindStringSubmatch(unknownKeyErr.Error())
  316. if len(matches) > 0 {
  317. serverPubKey := matches[0]
  318. publicKey, err := auth.GetPublicKey()
  319. if err != nil {
  320. return unknownKeyErr
  321. }
  322. localPubKey := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey)))
  323. if runtime.GOOS == "linux" && serverPubKey != localPubKey {
  324. // try the ollama service public key
  325. svcPubKey, err := os.ReadFile("/usr/share/ollama/.ollama/id_ed25519.pub")
  326. if err != nil {
  327. return unknownKeyErr
  328. }
  329. localPubKey = strings.TrimSpace(string(svcPubKey))
  330. }
  331. // check if the returned public key matches the local public key, this prevents adding a remote key to the user's account
  332. if serverPubKey != localPubKey {
  333. return unknownKeyErr
  334. }
  335. var msg strings.Builder
  336. msg.WriteString(unknownKeyErr.Error())
  337. msg.WriteString("\n\nYour ollama key is:\n")
  338. msg.WriteString(localPubKey)
  339. msg.WriteString("\nAdd your key at:\n")
  340. msg.WriteString("https://ollama.com/settings/keys")
  341. return errors.New(msg.String())
  342. }
  343. return unknownKeyErr
  344. }
  345. func PushHandler(cmd *cobra.Command, args []string) error {
  346. client, err := api.ClientFromEnvironment()
  347. if err != nil {
  348. return err
  349. }
  350. insecure, err := cmd.Flags().GetBool("insecure")
  351. if err != nil {
  352. return err
  353. }
  354. p := progress.NewProgress(os.Stderr)
  355. defer p.Stop()
  356. bars := make(map[string]*progress.Bar)
  357. var status string
  358. var spinner *progress.Spinner
  359. fn := func(resp api.ProgressResponse) error {
  360. if resp.Digest != "" {
  361. if spinner != nil {
  362. spinner.Stop()
  363. }
  364. bar, ok := bars[resp.Digest]
  365. if !ok {
  366. bar = progress.NewBar(fmt.Sprintf("pushing %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  367. bars[resp.Digest] = bar
  368. p.Add(resp.Digest, bar)
  369. }
  370. bar.Set(resp.Completed)
  371. } else if status != resp.Status {
  372. if spinner != nil {
  373. spinner.Stop()
  374. }
  375. status = resp.Status
  376. spinner = progress.NewSpinner(status)
  377. p.Add(status, spinner)
  378. }
  379. return nil
  380. }
  381. request := api.PushRequest{Name: args[0], Insecure: insecure}
  382. if err := client.Push(cmd.Context(), &request, fn); err != nil {
  383. if spinner != nil {
  384. spinner.Stop()
  385. }
  386. if strings.Contains(err.Error(), "access denied") {
  387. return errors.New("you are not authorized to push to this namespace, create the model under a namespace you own")
  388. }
  389. host := model.ParseName(args[0]).Host
  390. isOllamaHost := strings.HasSuffix(host, ".ollama.ai") || strings.HasSuffix(host, ".ollama.com")
  391. if strings.Contains(err.Error(), errtypes.UnknownOllamaKeyErrMsg) && isOllamaHost {
  392. // the user has not added their ollama key to ollama.com
  393. // re-throw an error with a more user-friendly message
  394. return errFromUnknownKey(err)
  395. }
  396. return err
  397. }
  398. spinner.Stop()
  399. return nil
  400. }
  401. func ListHandler(cmd *cobra.Command, args []string) error {
  402. client, err := api.ClientFromEnvironment()
  403. if err != nil {
  404. return err
  405. }
  406. models, err := client.List(cmd.Context())
  407. if err != nil {
  408. return err
  409. }
  410. var data [][]string
  411. for _, m := range models.Models {
  412. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  413. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), format.HumanTime(m.ModifiedAt, "Never")})
  414. }
  415. }
  416. table := tablewriter.NewWriter(os.Stdout)
  417. table.SetHeader([]string{"NAME", "ID", "SIZE", "MODIFIED"})
  418. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  419. table.SetAlignment(tablewriter.ALIGN_LEFT)
  420. table.SetHeaderLine(false)
  421. table.SetBorder(false)
  422. table.SetNoWhiteSpace(true)
  423. table.SetTablePadding("\t")
  424. table.AppendBulk(data)
  425. table.Render()
  426. return nil
  427. }
  428. func ListRunningHandler(cmd *cobra.Command, args []string) error {
  429. client, err := api.ClientFromEnvironment()
  430. if err != nil {
  431. return err
  432. }
  433. models, err := client.ListRunning(cmd.Context())
  434. if err != nil {
  435. return err
  436. }
  437. var data [][]string
  438. for _, m := range models.Models {
  439. if len(args) == 0 || strings.HasPrefix(m.Name, args[0]) {
  440. var procStr string
  441. switch {
  442. case m.SizeVRAM == 0:
  443. procStr = "100% CPU"
  444. case m.SizeVRAM == m.Size:
  445. procStr = "100% GPU"
  446. case m.SizeVRAM > m.Size || m.Size == 0:
  447. procStr = "Unknown"
  448. default:
  449. sizeCPU := m.Size - m.SizeVRAM
  450. cpuPercent := math.Round(float64(sizeCPU) / float64(m.Size) * 100)
  451. procStr = fmt.Sprintf("%d%%/%d%% CPU/GPU", int(cpuPercent), int(100-cpuPercent))
  452. }
  453. data = append(data, []string{m.Name, m.Digest[:12], format.HumanBytes(m.Size), procStr, format.HumanTime(m.ExpiresAt, "Never")})
  454. }
  455. }
  456. table := tablewriter.NewWriter(os.Stdout)
  457. table.SetHeader([]string{"NAME", "ID", "SIZE", "PROCESSOR", "UNTIL"})
  458. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  459. table.SetAlignment(tablewriter.ALIGN_LEFT)
  460. table.SetHeaderLine(false)
  461. table.SetBorder(false)
  462. table.SetNoWhiteSpace(true)
  463. table.SetTablePadding("\t")
  464. table.AppendBulk(data)
  465. table.Render()
  466. return nil
  467. }
  468. func DeleteHandler(cmd *cobra.Command, args []string) error {
  469. client, err := api.ClientFromEnvironment()
  470. if err != nil {
  471. return err
  472. }
  473. for _, name := range args {
  474. req := api.DeleteRequest{Name: name}
  475. if err := client.Delete(cmd.Context(), &req); err != nil {
  476. return err
  477. }
  478. fmt.Printf("deleted '%s'\n", name)
  479. }
  480. return nil
  481. }
  482. func ShowHandler(cmd *cobra.Command, args []string) error {
  483. client, err := api.ClientFromEnvironment()
  484. if err != nil {
  485. return err
  486. }
  487. license, errLicense := cmd.Flags().GetBool("license")
  488. modelfile, errModelfile := cmd.Flags().GetBool("modelfile")
  489. parameters, errParams := cmd.Flags().GetBool("parameters")
  490. system, errSystem := cmd.Flags().GetBool("system")
  491. template, errTemplate := cmd.Flags().GetBool("template")
  492. for _, boolErr := range []error{errLicense, errModelfile, errParams, errSystem, errTemplate} {
  493. if boolErr != nil {
  494. return errors.New("error retrieving flags")
  495. }
  496. }
  497. flagsSet := 0
  498. showType := ""
  499. if license {
  500. flagsSet++
  501. showType = "license"
  502. }
  503. if modelfile {
  504. flagsSet++
  505. showType = "modelfile"
  506. }
  507. if parameters {
  508. flagsSet++
  509. showType = "parameters"
  510. }
  511. if system {
  512. flagsSet++
  513. showType = "system"
  514. }
  515. if template {
  516. flagsSet++
  517. showType = "template"
  518. }
  519. if flagsSet > 1 {
  520. return errors.New("only one of '--license', '--modelfile', '--parameters', '--system', or '--template' can be specified")
  521. }
  522. req := api.ShowRequest{Name: args[0]}
  523. resp, err := client.Show(cmd.Context(), &req)
  524. if err != nil {
  525. return err
  526. }
  527. if flagsSet == 1 {
  528. switch showType {
  529. case "license":
  530. fmt.Println(resp.License)
  531. case "modelfile":
  532. fmt.Println(resp.Modelfile)
  533. case "parameters":
  534. fmt.Println(resp.Parameters)
  535. case "system":
  536. fmt.Println(resp.System)
  537. case "template":
  538. fmt.Println(resp.Template)
  539. }
  540. return nil
  541. }
  542. showInfo(resp)
  543. return nil
  544. }
  545. func showInfo(resp *api.ShowResponse) {
  546. arch := resp.ModelInfo["general.architecture"].(string)
  547. modelData := [][]string{
  548. {"arch", arch},
  549. {"parameters", resp.Details.ParameterSize},
  550. {"quantization", resp.Details.QuantizationLevel},
  551. {"context length", fmt.Sprintf("%v", resp.ModelInfo[fmt.Sprintf("%s.context_length", arch)].(float64))},
  552. {"embedding length", fmt.Sprintf("%v", resp.ModelInfo[fmt.Sprintf("%s.embedding_length", arch)].(float64))},
  553. }
  554. mainTableData := [][]string{
  555. {"Model"},
  556. {renderSubTable(modelData, false)},
  557. }
  558. if resp.ProjectorInfo != nil {
  559. projectorData := [][]string{
  560. {"arch", "clip"},
  561. {"parameters", format.HumanNumber(uint64(resp.ProjectorInfo["general.parameter_count"].(float64)))},
  562. }
  563. if projectorType, ok := resp.ProjectorInfo["clip.projector_type"]; ok {
  564. projectorData = append(projectorData, []string{"projector type", projectorType.(string)})
  565. }
  566. projectorData = append(projectorData,
  567. []string{"embedding length", fmt.Sprintf("%v", resp.ProjectorInfo["clip.vision.embedding_length"].(float64))},
  568. []string{"projection dimensionality", fmt.Sprintf("%v", resp.ProjectorInfo["clip.vision.projection_dim"].(float64))},
  569. )
  570. mainTableData = append(mainTableData,
  571. []string{"Projector"},
  572. []string{renderSubTable(projectorData, false)},
  573. )
  574. }
  575. if resp.Parameters != "" {
  576. mainTableData = append(mainTableData, []string{"Parameters"}, []string{formatParams(resp.Parameters)})
  577. }
  578. if resp.System != "" {
  579. mainTableData = append(mainTableData, []string{"System"}, []string{renderSubTable(twoLines(resp.System), true)})
  580. }
  581. if resp.License != "" {
  582. mainTableData = append(mainTableData, []string{"License"}, []string{renderSubTable(twoLines(resp.License), true)})
  583. }
  584. table := tablewriter.NewWriter(os.Stdout)
  585. table.SetAutoWrapText(false)
  586. table.SetBorder(false)
  587. table.SetAlignment(tablewriter.ALIGN_LEFT)
  588. for _, v := range mainTableData {
  589. table.Append(v)
  590. }
  591. table.Render()
  592. }
  593. func renderSubTable(data [][]string, file bool) string {
  594. var buf bytes.Buffer
  595. table := tablewriter.NewWriter(&buf)
  596. table.SetAutoWrapText(!file)
  597. table.SetBorder(false)
  598. table.SetNoWhiteSpace(true)
  599. table.SetTablePadding("\t")
  600. table.SetAlignment(tablewriter.ALIGN_LEFT)
  601. for _, v := range data {
  602. table.Append(v)
  603. }
  604. table.Render()
  605. renderedTable := buf.String()
  606. lines := strings.Split(renderedTable, "\n")
  607. for i, line := range lines {
  608. lines[i] = "\t" + line
  609. }
  610. return strings.Join(lines, "\n")
  611. }
  612. func twoLines(s string) [][]string {
  613. lines := strings.Split(s, "\n")
  614. res := [][]string{}
  615. count := 0
  616. for _, line := range lines {
  617. line = strings.TrimSpace(line)
  618. if line != "" {
  619. count++
  620. res = append(res, []string{line})
  621. if count == 2 {
  622. return res
  623. }
  624. }
  625. }
  626. return res
  627. }
  628. func formatParams(s string) string {
  629. lines := strings.Split(s, "\n")
  630. table := [][]string{}
  631. for _, line := range lines {
  632. table = append(table, strings.Fields(line))
  633. }
  634. return renderSubTable(table, false)
  635. }
  636. func CopyHandler(cmd *cobra.Command, args []string) error {
  637. client, err := api.ClientFromEnvironment()
  638. if err != nil {
  639. return err
  640. }
  641. req := api.CopyRequest{Source: args[0], Destination: args[1]}
  642. if err := client.Copy(cmd.Context(), &req); err != nil {
  643. return err
  644. }
  645. fmt.Printf("copied '%s' to '%s'\n", args[0], args[1])
  646. return nil
  647. }
  648. func PullHandler(cmd *cobra.Command, args []string) error {
  649. insecure, err := cmd.Flags().GetBool("insecure")
  650. if err != nil {
  651. return err
  652. }
  653. client, err := api.ClientFromEnvironment()
  654. if err != nil {
  655. return err
  656. }
  657. p := progress.NewProgress(os.Stderr)
  658. defer p.Stop()
  659. bars := make(map[string]*progress.Bar)
  660. var status string
  661. var spinner *progress.Spinner
  662. fn := func(resp api.ProgressResponse) error {
  663. if resp.Digest != "" {
  664. if spinner != nil {
  665. spinner.Stop()
  666. }
  667. bar, ok := bars[resp.Digest]
  668. if !ok {
  669. bar = progress.NewBar(fmt.Sprintf("pulling %s...", resp.Digest[7:19]), resp.Total, resp.Completed)
  670. bars[resp.Digest] = bar
  671. p.Add(resp.Digest, bar)
  672. }
  673. bar.Set(resp.Completed)
  674. } else if status != resp.Status {
  675. if spinner != nil {
  676. spinner.Stop()
  677. }
  678. status = resp.Status
  679. spinner = progress.NewSpinner(status)
  680. p.Add(status, spinner)
  681. }
  682. return nil
  683. }
  684. request := api.PullRequest{Name: args[0], Insecure: insecure}
  685. if err := client.Pull(cmd.Context(), &request, fn); err != nil {
  686. return err
  687. }
  688. return nil
  689. }
  690. type generateContextKey string
  691. type runOptions struct {
  692. Model string
  693. ParentModel string
  694. Prompt string
  695. Messages []api.Message
  696. WordWrap bool
  697. Format string
  698. System string
  699. Images []api.ImageData
  700. Options map[string]interface{}
  701. MultiModal bool
  702. KeepAlive *api.Duration
  703. }
  704. type displayResponseState struct {
  705. lineLength int
  706. wordBuffer string
  707. }
  708. func displayResponse(content string, wordWrap bool, state *displayResponseState) {
  709. termWidth, _, _ := term.GetSize(int(os.Stdout.Fd()))
  710. if wordWrap && termWidth >= 10 {
  711. for _, ch := range content {
  712. if state.lineLength+1 > termWidth-5 {
  713. if runewidth.StringWidth(state.wordBuffer) > termWidth-10 {
  714. fmt.Printf("%s%c", state.wordBuffer, ch)
  715. state.wordBuffer = ""
  716. state.lineLength = 0
  717. continue
  718. }
  719. // backtrack the length of the last word and clear to the end of the line
  720. a := runewidth.StringWidth(state.wordBuffer)
  721. if a > 0 {
  722. fmt.Printf("\x1b[%dD", a)
  723. }
  724. fmt.Printf("\x1b[K\n")
  725. fmt.Printf("%s%c", state.wordBuffer, ch)
  726. chWidth := runewidth.RuneWidth(ch)
  727. state.lineLength = runewidth.StringWidth(state.wordBuffer) + chWidth
  728. } else {
  729. fmt.Print(string(ch))
  730. state.lineLength += runewidth.RuneWidth(ch)
  731. if runewidth.RuneWidth(ch) >= 2 {
  732. state.wordBuffer = ""
  733. continue
  734. }
  735. switch ch {
  736. case ' ':
  737. state.wordBuffer = ""
  738. case '\n':
  739. state.lineLength = 0
  740. default:
  741. state.wordBuffer += string(ch)
  742. }
  743. }
  744. }
  745. } else {
  746. fmt.Printf("%s%s", state.wordBuffer, content)
  747. if len(state.wordBuffer) > 0 {
  748. state.wordBuffer = ""
  749. }
  750. }
  751. }
  752. func chat(cmd *cobra.Command, opts runOptions) (*api.Message, error) {
  753. client, err := api.ClientFromEnvironment()
  754. if err != nil {
  755. return nil, err
  756. }
  757. p := progress.NewProgress(os.Stderr)
  758. defer p.StopAndClear()
  759. spinner := progress.NewSpinner("")
  760. p.Add("", spinner)
  761. cancelCtx, cancel := context.WithCancel(cmd.Context())
  762. defer cancel()
  763. sigChan := make(chan os.Signal, 1)
  764. signal.Notify(sigChan, syscall.SIGINT)
  765. go func() {
  766. <-sigChan
  767. cancel()
  768. }()
  769. var state *displayResponseState = &displayResponseState{}
  770. var latest api.ChatResponse
  771. var fullResponse strings.Builder
  772. var role string
  773. fn := func(response api.ChatResponse) error {
  774. p.StopAndClear()
  775. latest = response
  776. role = response.Message.Role
  777. content := response.Message.Content
  778. fullResponse.WriteString(content)
  779. displayResponse(content, opts.WordWrap, state)
  780. return nil
  781. }
  782. req := &api.ChatRequest{
  783. Model: opts.Model,
  784. Messages: opts.Messages,
  785. Format: opts.Format,
  786. Options: opts.Options,
  787. }
  788. if opts.KeepAlive != nil {
  789. req.KeepAlive = opts.KeepAlive
  790. }
  791. if err := client.Chat(cancelCtx, req, fn); err != nil {
  792. if errors.Is(err, context.Canceled) {
  793. return nil, nil
  794. }
  795. return nil, err
  796. }
  797. if len(opts.Messages) > 0 {
  798. fmt.Println()
  799. fmt.Println()
  800. }
  801. verbose, err := cmd.Flags().GetBool("verbose")
  802. if err != nil {
  803. return nil, err
  804. }
  805. if verbose {
  806. latest.Summary()
  807. }
  808. return &api.Message{Role: role, Content: fullResponse.String()}, nil
  809. }
  810. func generate(cmd *cobra.Command, opts runOptions) error {
  811. client, err := api.ClientFromEnvironment()
  812. if err != nil {
  813. return err
  814. }
  815. p := progress.NewProgress(os.Stderr)
  816. defer p.StopAndClear()
  817. spinner := progress.NewSpinner("")
  818. p.Add("", spinner)
  819. var latest api.GenerateResponse
  820. generateContext, ok := cmd.Context().Value(generateContextKey("context")).([]int)
  821. if !ok {
  822. generateContext = []int{}
  823. }
  824. ctx, cancel := context.WithCancel(cmd.Context())
  825. defer cancel()
  826. sigChan := make(chan os.Signal, 1)
  827. signal.Notify(sigChan, syscall.SIGINT)
  828. go func() {
  829. <-sigChan
  830. cancel()
  831. }()
  832. var state *displayResponseState = &displayResponseState{}
  833. fn := func(response api.GenerateResponse) error {
  834. p.StopAndClear()
  835. latest = response
  836. content := response.Response
  837. displayResponse(content, opts.WordWrap, state)
  838. return nil
  839. }
  840. if opts.MultiModal {
  841. opts.Prompt, opts.Images, err = extractFileData(opts.Prompt)
  842. if err != nil {
  843. return err
  844. }
  845. }
  846. request := api.GenerateRequest{
  847. Model: opts.Model,
  848. Prompt: opts.Prompt,
  849. Context: generateContext,
  850. Images: opts.Images,
  851. Format: opts.Format,
  852. System: opts.System,
  853. Options: opts.Options,
  854. KeepAlive: opts.KeepAlive,
  855. }
  856. if err := client.Generate(ctx, &request, fn); err != nil {
  857. if errors.Is(err, context.Canceled) {
  858. return nil
  859. }
  860. return err
  861. }
  862. if opts.Prompt != "" {
  863. fmt.Println()
  864. fmt.Println()
  865. }
  866. if !latest.Done {
  867. return nil
  868. }
  869. verbose, err := cmd.Flags().GetBool("verbose")
  870. if err != nil {
  871. return err
  872. }
  873. if verbose {
  874. latest.Summary()
  875. }
  876. ctx = context.WithValue(cmd.Context(), generateContextKey("context"), latest.Context)
  877. cmd.SetContext(ctx)
  878. return nil
  879. }
  880. func RunServer(cmd *cobra.Command, _ []string) error {
  881. if _, err := auth.GetPublicKey(); err != nil {
  882. return err
  883. }
  884. ln, err := net.Listen("tcp", net.JoinHostPort(envconfig.Host.Host, envconfig.Host.Port))
  885. if err != nil {
  886. return err
  887. }
  888. err = server.Serve(ln)
  889. if errors.Is(err, http.ErrServerClosed) {
  890. return nil
  891. }
  892. return err
  893. }
  894. func checkServerHeartbeat(cmd *cobra.Command, _ []string) error {
  895. client, err := api.ClientFromEnvironment()
  896. if err != nil {
  897. return err
  898. }
  899. if err := client.Heartbeat(cmd.Context()); err != nil {
  900. if !strings.Contains(err.Error(), " refused") {
  901. return err
  902. }
  903. if err := startApp(cmd.Context(), client); err != nil {
  904. return fmt.Errorf("could not connect to ollama app, is it running?")
  905. }
  906. }
  907. return nil
  908. }
  909. func versionHandler(cmd *cobra.Command, _ []string) {
  910. client, err := api.ClientFromEnvironment()
  911. if err != nil {
  912. return
  913. }
  914. serverVersion, err := client.Version(cmd.Context())
  915. if err != nil {
  916. fmt.Println("Warning: could not connect to a running Ollama instance")
  917. }
  918. if serverVersion != "" {
  919. fmt.Printf("ollama version is %s\n", serverVersion)
  920. }
  921. if serverVersion != version.Version {
  922. fmt.Printf("Warning: client version is %s\n", version.Version)
  923. }
  924. }
  925. func appendEnvDocs(cmd *cobra.Command, envs []envconfig.EnvVar) {
  926. if len(envs) == 0 {
  927. return
  928. }
  929. envUsage := `
  930. Environment Variables:
  931. `
  932. for _, e := range envs {
  933. envUsage += fmt.Sprintf(" %-24s %s\n", e.Name, e.Description)
  934. }
  935. cmd.SetUsageTemplate(cmd.UsageTemplate() + envUsage)
  936. }
  937. func NewCLI() *cobra.Command {
  938. log.SetFlags(log.LstdFlags | log.Lshortfile)
  939. cobra.EnableCommandSorting = false
  940. if runtime.GOOS == "windows" {
  941. console.ConsoleFromFile(os.Stdin) //nolint:errcheck
  942. }
  943. rootCmd := &cobra.Command{
  944. Use: "ollama",
  945. Short: "Large language model runner",
  946. SilenceUsage: true,
  947. SilenceErrors: true,
  948. CompletionOptions: cobra.CompletionOptions{
  949. DisableDefaultCmd: true,
  950. },
  951. Run: func(cmd *cobra.Command, args []string) {
  952. if version, _ := cmd.Flags().GetBool("version"); version {
  953. versionHandler(cmd, args)
  954. return
  955. }
  956. cmd.Print(cmd.UsageString())
  957. },
  958. }
  959. rootCmd.Flags().BoolP("version", "v", false, "Show version information")
  960. createCmd := &cobra.Command{
  961. Use: "create MODEL",
  962. Short: "Create a model from a Modelfile",
  963. Args: cobra.ExactArgs(1),
  964. PreRunE: checkServerHeartbeat,
  965. RunE: CreateHandler,
  966. }
  967. createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile")
  968. createCmd.Flags().StringP("quantize", "q", "", "Quantize model to this level (e.g. q4_0)")
  969. showCmd := &cobra.Command{
  970. Use: "show MODEL",
  971. Short: "Show information for a model",
  972. Args: cobra.ExactArgs(1),
  973. PreRunE: checkServerHeartbeat,
  974. RunE: ShowHandler,
  975. }
  976. showCmd.Flags().Bool("license", false, "Show license of a model")
  977. showCmd.Flags().Bool("modelfile", false, "Show Modelfile of a model")
  978. showCmd.Flags().Bool("parameters", false, "Show parameters of a model")
  979. showCmd.Flags().Bool("template", false, "Show template of a model")
  980. showCmd.Flags().Bool("system", false, "Show system message of a model")
  981. runCmd := &cobra.Command{
  982. Use: "run MODEL [PROMPT]",
  983. Short: "Run a model",
  984. Args: cobra.MinimumNArgs(1),
  985. PreRunE: checkServerHeartbeat,
  986. RunE: RunHandler,
  987. }
  988. runCmd.Flags().String("keepalive", "", "Duration to keep a model loaded (e.g. 5m)")
  989. runCmd.Flags().Bool("verbose", false, "Show timings for response")
  990. runCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  991. runCmd.Flags().Bool("nowordwrap", false, "Don't wrap words to the next line automatically")
  992. runCmd.Flags().String("format", "", "Response format (e.g. json)")
  993. serveCmd := &cobra.Command{
  994. Use: "serve",
  995. Aliases: []string{"start"},
  996. Short: "Start ollama",
  997. Args: cobra.ExactArgs(0),
  998. RunE: RunServer,
  999. }
  1000. pullCmd := &cobra.Command{
  1001. Use: "pull MODEL",
  1002. Short: "Pull a model from a registry",
  1003. Args: cobra.ExactArgs(1),
  1004. PreRunE: checkServerHeartbeat,
  1005. RunE: PullHandler,
  1006. }
  1007. pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1008. pushCmd := &cobra.Command{
  1009. Use: "push MODEL",
  1010. Short: "Push a model to a registry",
  1011. Args: cobra.ExactArgs(1),
  1012. PreRunE: checkServerHeartbeat,
  1013. RunE: PushHandler,
  1014. }
  1015. pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
  1016. listCmd := &cobra.Command{
  1017. Use: "list",
  1018. Aliases: []string{"ls"},
  1019. Short: "List models",
  1020. PreRunE: checkServerHeartbeat,
  1021. RunE: ListHandler,
  1022. }
  1023. psCmd := &cobra.Command{
  1024. Use: "ps",
  1025. Short: "List running models",
  1026. PreRunE: checkServerHeartbeat,
  1027. RunE: ListRunningHandler,
  1028. }
  1029. copyCmd := &cobra.Command{
  1030. Use: "cp SOURCE DESTINATION",
  1031. Short: "Copy a model",
  1032. Args: cobra.ExactArgs(2),
  1033. PreRunE: checkServerHeartbeat,
  1034. RunE: CopyHandler,
  1035. }
  1036. deleteCmd := &cobra.Command{
  1037. Use: "rm MODEL [MODEL...]",
  1038. Short: "Remove a model",
  1039. Args: cobra.MinimumNArgs(1),
  1040. PreRunE: checkServerHeartbeat,
  1041. RunE: DeleteHandler,
  1042. }
  1043. envVars := envconfig.AsMap()
  1044. envs := []envconfig.EnvVar{envVars["OLLAMA_HOST"]}
  1045. for _, cmd := range []*cobra.Command{
  1046. createCmd,
  1047. showCmd,
  1048. runCmd,
  1049. pullCmd,
  1050. pushCmd,
  1051. listCmd,
  1052. psCmd,
  1053. copyCmd,
  1054. deleteCmd,
  1055. serveCmd,
  1056. } {
  1057. switch cmd {
  1058. case runCmd:
  1059. appendEnvDocs(cmd, []envconfig.EnvVar{envVars["OLLAMA_HOST"], envVars["OLLAMA_NOHISTORY"]})
  1060. case serveCmd:
  1061. appendEnvDocs(cmd, []envconfig.EnvVar{
  1062. envVars["OLLAMA_DEBUG"],
  1063. envVars["OLLAMA_HOST"],
  1064. envVars["OLLAMA_KEEP_ALIVE"],
  1065. envVars["OLLAMA_MAX_LOADED_MODELS"],
  1066. envVars["OLLAMA_MAX_QUEUE"],
  1067. envVars["OLLAMA_MODELS"],
  1068. envVars["OLLAMA_NUM_PARALLEL"],
  1069. envVars["OLLAMA_NOPRUNE"],
  1070. envVars["OLLAMA_ORIGINS"],
  1071. envVars["OLLAMA_TMPDIR"],
  1072. envVars["OLLAMA_FLASH_ATTENTION"],
  1073. envVars["OLLAMA_LLM_LIBRARY"],
  1074. })
  1075. default:
  1076. appendEnvDocs(cmd, envs)
  1077. }
  1078. }
  1079. rootCmd.AddCommand(
  1080. serveCmd,
  1081. createCmd,
  1082. showCmd,
  1083. runCmd,
  1084. pullCmd,
  1085. pushCmd,
  1086. listCmd,
  1087. psCmd,
  1088. copyCmd,
  1089. deleteCmd,
  1090. )
  1091. return rootCmd
  1092. }