cmd.go 2.55 KB
Newer Older
Jeffrey Morgan's avatar
Jeffrey Morgan committed
1
2
3
4
package cmd

import (
	"context"
Bruce MacDonald's avatar
Bruce MacDonald committed
5
	"fmt"
Jeffrey Morgan's avatar
Jeffrey Morgan committed
6
7
8
9
	"log"
	"net"
	"os"
	"path"
Bruce MacDonald's avatar
Bruce MacDonald committed
10
	"sync"
Jeffrey Morgan's avatar
Jeffrey Morgan committed
11

Bruce MacDonald's avatar
Bruce MacDonald committed
12
	"github.com/gosuri/uiprogress"
Jeffrey Morgan's avatar
Jeffrey Morgan committed
13
14
	"github.com/jmorganca/ollama/api"
	"github.com/jmorganca/ollama/server"
Jeffrey Morgan's avatar
Jeffrey Morgan committed
15
	"github.com/spf13/cobra"
Jeffrey Morgan's avatar
Jeffrey Morgan committed
16
17
)

Bruce MacDonald's avatar
Bruce MacDonald committed
18
func cacheDir() string {
Jeffrey Morgan's avatar
Jeffrey Morgan committed
19
20
21
22
23
	home, err := os.UserHomeDir()
	if err != nil {
		panic(err)
	}

Bruce MacDonald's avatar
Bruce MacDonald committed
24
	return path.Join(home, ".ollama")
Jeffrey Morgan's avatar
Jeffrey Morgan committed
25
26
}

Bruce MacDonald's avatar
Bruce MacDonald committed
27
28
29
30
func bytesToGB(bytes int) float64 {
	return float64(bytes) / float64(1<<30)
}

Bruce MacDonald's avatar
Bruce MacDonald committed
31
32
33
34
35
36
37
38
func run(model string) error {
	client, err := NewAPIClient()
	if err != nil {
		return err
	}
	pr := api.PullRequest{
		Model: model,
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
39
40
41
42
	var bar *uiprogress.Bar
	mutex := &sync.Mutex{}
	var progressData api.PullProgress

Bruce MacDonald's avatar
Bruce MacDonald committed
43
	pullCallback := func(progress api.PullProgress) {
Bruce MacDonald's avatar
Bruce MacDonald committed
44
45
46
		mutex.Lock()
		progressData = progress
		if bar == nil {
Bruce MacDonald's avatar
Bruce MacDonald committed
47
48
			uiprogress.Start()
			bar = uiprogress.AddBar(int(progress.Total))
Bruce MacDonald's avatar
Bruce MacDonald committed
49
50
51
52
53
54
55
56
57
			bar.PrependFunc(func(b *uiprogress.Bar) string {
				return fmt.Sprintf("Downloading: %.2f GB / %.2f GB", bytesToGB(progressData.Completed), bytesToGB(progressData.Total))
			})
			bar.AppendFunc(func(b *uiprogress.Bar) string {
				return fmt.Sprintf(" %d%%", int((float64(progressData.Completed)/float64(progressData.Total))*100))
			})
		}
		bar.Set(int(progress.Completed))
		mutex.Unlock()
Bruce MacDonald's avatar
Bruce MacDonald committed
58
	}
Bruce MacDonald's avatar
Bruce MacDonald committed
59
60
61
62
63
	if err := client.Pull(context.Background(), &pr, pullCallback); err != nil {
		return err
	}
	fmt.Println("Up to date.")
	return nil
Bruce MacDonald's avatar
Bruce MacDonald committed
64
65
}

Jeffrey Morgan's avatar
Jeffrey Morgan committed
66
func serve() error {
Michael Yang's avatar
Michael Yang committed
67
	ln, err := net.Listen("tcp", "127.0.0.1:11434")
Jeffrey Morgan's avatar
Jeffrey Morgan committed
68
69
70
71
72
73
74
75
	if err != nil {
		return err
	}

	return server.Serve(ln)
}

func NewAPIClient() (*api.Client, error) {
Jeffrey Morgan's avatar
Jeffrey Morgan committed
76
	return &api.Client{
Michael Yang's avatar
Michael Yang committed
77
		URL: "http://localhost:11434",
Jeffrey Morgan's avatar
Jeffrey Morgan committed
78
79
80
81
82
83
84
	}, nil
}

func NewCLI() *cobra.Command {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	rootCmd := &cobra.Command{
Jeffrey Morgan's avatar
Jeffrey Morgan committed
85
		Use:   "ollama",
86
		Short: "Large language model runner",
Jeffrey Morgan's avatar
Jeffrey Morgan committed
87
88
89
90
91
92
		CompletionOptions: cobra.CompletionOptions{
			DisableDefaultCmd: true,
		},
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			// Disable usage printing on errors
			cmd.SilenceUsage = true
Bruce MacDonald's avatar
Bruce MacDonald committed
93
94
95
96
			// create the models directory and it's parent
			if err := os.MkdirAll(path.Join(cacheDir(), "models"), 0o700); err != nil {
				panic(err)
			}
Jeffrey Morgan's avatar
Jeffrey Morgan committed
97
98
99
100
101
102
		},
	}

	cobra.EnableCommandSorting = false

	runCmd := &cobra.Command{
Bruce MacDonald's avatar
Bruce MacDonald committed
103
		Use:   "run MODEL",
Jeffrey Morgan's avatar
Jeffrey Morgan committed
104
		Short: "Run a model",
Bruce MacDonald's avatar
Bruce MacDonald committed
105
106
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
Bruce MacDonald's avatar
Bruce MacDonald committed
107
			return run(args[0])
Jeffrey Morgan's avatar
Jeffrey Morgan committed
108
109
110
111
112
113
114
115
		},
	}

	serveCmd := &cobra.Command{
		Use:     "serve",
		Aliases: []string{"start"},
		Short:   "Start ollama",
		RunE: func(cmd *cobra.Command, args []string) error {
Jeffrey Morgan's avatar
Jeffrey Morgan committed
116
			return serve()
Jeffrey Morgan's avatar
Jeffrey Morgan committed
117
118
119
120
121
		},
	}

	rootCmd.AddCommand(
		serveCmd,
122
		runCmd,
Jeffrey Morgan's avatar
Jeffrey Morgan committed
123
124
125
126
	)

	return rootCmd
}