浏览代码

check server is running before running command

Bruce MacDonald 1 年之前
父节点
当前提交
e72fe7945f
共有 2 个文件被更改,包括 72 次插入25 次删除
  1. 7 0
      api/client.go
  2. 65 25
      cmd/cmd.go

+ 7 - 0
api/client.go

@@ -223,3 +223,10 @@ func (c *Client) Delete(ctx context.Context, req *DeleteRequest) error {
 	}
 	return nil
 }
+
+func (c *Client) Heartbeat(ctx context.Context) error {
+	if err := c.do(ctx, http.MethodGet, "/", nil, nil); err != nil {
+		return err
+	}
+	return nil
+}

+ 65 - 25
cmd/cmd.go

@@ -10,7 +10,9 @@ import (
 	"net"
 	"net/http"
 	"os"
+	"os/exec"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"time"
 
@@ -431,7 +433,6 @@ func generateInteractive(cmd *cobra.Command, model string) error {
 							usage()
 							continue
 						}
-
 					} else {
 						usage()
 						continue
@@ -525,6 +526,38 @@ func RunServer(_ *cobra.Command, _ []string) error {
 	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 {
 	log.SetFlags(log.LstdFlags | log.Lshortfile)
 
@@ -540,19 +573,21 @@ func NewCLI() *cobra.Command {
 	cobra.EnableCommandSorting = false
 
 	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\")")
 
 	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")
@@ -565,19 +600,21 @@ func NewCLI() *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")
 
 	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")
@@ -586,21 +623,24 @@ func NewCLI() *cobra.Command {
 		Use:     "list",
 		Aliases: []string{"ls"},
 		Short:   "List models",
+		PreRunE: checkServerHeartbeat,
 		RunE:    ListHandler,
 	}
 
 	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{
-		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(