cmd.go 33 KB

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