cmd.go 32 KB

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