|
@@ -10,7 +10,9 @@ import (
|
|
"net"
|
|
"net"
|
|
"net/http"
|
|
"net/http"
|
|
"os"
|
|
"os"
|
|
|
|
+ "os/exec"
|
|
"path/filepath"
|
|
"path/filepath"
|
|
|
|
+ "runtime"
|
|
"strings"
|
|
"strings"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
@@ -431,7 +433,6 @@ func generateInteractive(cmd *cobra.Command, model string) error {
|
|
usage()
|
|
usage()
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
-
|
|
|
|
} else {
|
|
} else {
|
|
usage()
|
|
usage()
|
|
continue
|
|
continue
|
|
@@ -525,6 +526,38 @@ func RunServer(_ *cobra.Command, _ []string) error {
|
|
return server.Serve(ln)
|
|
return server.Serve(ln)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func checkServerHeartbeat(_ *cobra.Command, _ []string) error {
|
|
|
|
+ client := api.NewClient()
|
|
|
|
+ if err := client.Heartbeat(context.Background()); err != nil {
|
|
|
|
+ if strings.Contains(err.Error(), "connection refused") {
|
|
|
|
+ if runtime.GOOS == "darwin" {
|
|
|
|
+ // if the mac app is available, start it
|
|
|
|
+ if _, err := os.Stat("/Applications/Ollama.app"); err == nil {
|
|
|
|
+ if err := exec.Command("/usr/bin/open", "-a", "/Applications/Ollama.app").Run(); err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ // wait for the server to start
|
|
|
|
+ timeout := time.After(5 * time.Second)
|
|
|
|
+ tick := time.Tick(500 * time.Millisecond)
|
|
|
|
+ for {
|
|
|
|
+ select {
|
|
|
|
+ case <-timeout:
|
|
|
|
+ return errors.New("timed out waiting for server to start")
|
|
|
|
+ case <-tick:
|
|
|
|
+ if err := client.Heartbeat(context.Background()); err == nil {
|
|
|
|
+ return nil // server has started
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return fmt.Errorf("could not connect to ollama server, run 'ollama serve' to start it")
|
|
|
|
+ }
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
+
|
|
func NewCLI() *cobra.Command {
|
|
func NewCLI() *cobra.Command {
|
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
|
|
|
|
|
@@ -540,19 +573,21 @@ func NewCLI() *cobra.Command {
|
|
cobra.EnableCommandSorting = false
|
|
cobra.EnableCommandSorting = false
|
|
|
|
|
|
createCmd := &cobra.Command{
|
|
createCmd := &cobra.Command{
|
|
- Use: "create MODEL",
|
|
|
|
- Short: "Create a model from a Modelfile",
|
|
|
|
- Args: cobra.MinimumNArgs(1),
|
|
|
|
- RunE: CreateHandler,
|
|
|
|
|
|
+ Use: "create MODEL",
|
|
|
|
+ Short: "Create a model from a Modelfile",
|
|
|
|
+ Args: cobra.MinimumNArgs(1),
|
|
|
|
+ PreRunE: checkServerHeartbeat,
|
|
|
|
+ RunE: CreateHandler,
|
|
}
|
|
}
|
|
|
|
|
|
createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
|
|
createCmd.Flags().StringP("file", "f", "Modelfile", "Name of the Modelfile (default \"Modelfile\")")
|
|
|
|
|
|
runCmd := &cobra.Command{
|
|
runCmd := &cobra.Command{
|
|
- Use: "run MODEL [PROMPT]",
|
|
|
|
- Short: "Run a model",
|
|
|
|
- Args: cobra.MinimumNArgs(1),
|
|
|
|
- RunE: RunHandler,
|
|
|
|
|
|
+ Use: "run MODEL [PROMPT]",
|
|
|
|
+ Short: "Run a model",
|
|
|
|
+ Args: cobra.MinimumNArgs(1),
|
|
|
|
+ PreRunE: checkServerHeartbeat,
|
|
|
|
+ RunE: RunHandler,
|
|
}
|
|
}
|
|
|
|
|
|
runCmd.Flags().Bool("verbose", false, "Show timings for response")
|
|
runCmd.Flags().Bool("verbose", false, "Show timings for response")
|
|
@@ -565,19 +600,21 @@ func NewCLI() *cobra.Command {
|
|
}
|
|
}
|
|
|
|
|
|
pullCmd := &cobra.Command{
|
|
pullCmd := &cobra.Command{
|
|
- Use: "pull MODEL",
|
|
|
|
- Short: "Pull a model from a registry",
|
|
|
|
- Args: cobra.MinimumNArgs(1),
|
|
|
|
- RunE: PullHandler,
|
|
|
|
|
|
+ Use: "pull MODEL",
|
|
|
|
+ Short: "Pull a model from a registry",
|
|
|
|
+ Args: cobra.MinimumNArgs(1),
|
|
|
|
+ PreRunE: checkServerHeartbeat,
|
|
|
|
+ RunE: PullHandler,
|
|
}
|
|
}
|
|
|
|
|
|
pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
|
|
pullCmd.Flags().Bool("insecure", false, "Use an insecure registry")
|
|
|
|
|
|
pushCmd := &cobra.Command{
|
|
pushCmd := &cobra.Command{
|
|
- Use: "push MODEL",
|
|
|
|
- Short: "Push a model to a registry",
|
|
|
|
- Args: cobra.MinimumNArgs(1),
|
|
|
|
- RunE: PushHandler,
|
|
|
|
|
|
+ Use: "push MODEL",
|
|
|
|
+ Short: "Push a model to a registry",
|
|
|
|
+ Args: cobra.MinimumNArgs(1),
|
|
|
|
+ PreRunE: checkServerHeartbeat,
|
|
|
|
+ RunE: PushHandler,
|
|
}
|
|
}
|
|
|
|
|
|
pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
|
|
pushCmd.Flags().Bool("insecure", false, "Use an insecure registry")
|
|
@@ -586,21 +623,24 @@ func NewCLI() *cobra.Command {
|
|
Use: "list",
|
|
Use: "list",
|
|
Aliases: []string{"ls"},
|
|
Aliases: []string{"ls"},
|
|
Short: "List models",
|
|
Short: "List models",
|
|
|
|
+ PreRunE: checkServerHeartbeat,
|
|
RunE: ListHandler,
|
|
RunE: ListHandler,
|
|
}
|
|
}
|
|
|
|
|
|
copyCmd := &cobra.Command{
|
|
copyCmd := &cobra.Command{
|
|
- Use: "cp",
|
|
|
|
- Short: "Copy a model",
|
|
|
|
- Args: cobra.MinimumNArgs(2),
|
|
|
|
- RunE: CopyHandler,
|
|
|
|
|
|
+ Use: "cp",
|
|
|
|
+ Short: "Copy a model",
|
|
|
|
+ Args: cobra.MinimumNArgs(2),
|
|
|
|
+ PreRunE: checkServerHeartbeat,
|
|
|
|
+ RunE: CopyHandler,
|
|
}
|
|
}
|
|
|
|
|
|
deleteCmd := &cobra.Command{
|
|
deleteCmd := &cobra.Command{
|
|
- Use: "rm",
|
|
|
|
- Short: "Remove a model",
|
|
|
|
- Args: cobra.MinimumNArgs(1),
|
|
|
|
- RunE: DeleteHandler,
|
|
|
|
|
|
+ Use: "rm",
|
|
|
|
+ Short: "Remove a model",
|
|
|
|
+ Args: cobra.MinimumNArgs(1),
|
|
|
|
+ PreRunE: checkServerHeartbeat,
|
|
|
|
+ RunE: DeleteHandler,
|
|
}
|
|
}
|
|
|
|
|
|
rootCmd.AddCommand(
|
|
rootCmd.AddCommand(
|