diff --git a/cmd/cmd.go b/cmd/cmd.go index 915fa993..c393a9e2 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -25,6 +25,7 @@ import ( "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" "golang.org/x/crypto/ssh" + "golang.org/x/exp/slices" "golang.org/x/term" "github.com/jmorganca/ollama/api" @@ -147,7 +148,7 @@ func RunHandler(cmd *cobra.Command, args []string) error { name := args[0] // check if the model exists on the server - _, err = client.Show(cmd.Context(), &api.ShowRequest{Name: name}) + show, err := client.Show(cmd.Context(), &api.ShowRequest{Name: name}) var statusError api.StatusError switch { case errors.As(err, &statusError) && statusError.StatusCode == http.StatusNotFound: @@ -158,7 +159,50 @@ func RunHandler(cmd *cobra.Command, args []string) error { return err } - return RunGenerate(cmd, args) + interactive := true + + opts := runOptions{ + Model: args[0], + WordWrap: os.Getenv("TERM") == "xterm-256color", + Options: map[string]interface{}{}, + MultiModal: slices.Contains(show.Details.Families, "clip"), + ParentModel: show.Details.ParentModel, + } + + format, err := cmd.Flags().GetString("format") + if err != nil { + return err + } + opts.Format = format + + prompts := args[1:] + // prepend stdin to the prompt if provided + if !term.IsTerminal(int(os.Stdin.Fd())) { + in, err := io.ReadAll(os.Stdin) + if err != nil { + return err + } + + prompts = append([]string{string(in)}, prompts...) + opts.WordWrap = false + interactive = false + } + opts.Prompt = strings.Join(prompts, " ") + if len(prompts) > 0 { + interactive = false + } + + nowrap, err := cmd.Flags().GetBool("nowordwrap") + if err != nil { + return err + } + opts.WordWrap = !nowrap + + if !interactive { + return generate(cmd, opts) + } + + return generateInteractive(cmd, opts) } func PushHandler(cmd *cobra.Command, args []string) error { @@ -410,51 +454,6 @@ func PullHandler(cmd *cobra.Command, args []string) error { return nil } -func RunGenerate(cmd *cobra.Command, args []string) error { - interactive := true - - opts := runOptions{ - Model: args[0], - WordWrap: os.Getenv("TERM") == "xterm-256color", - Options: map[string]interface{}{}, - } - - format, err := cmd.Flags().GetString("format") - if err != nil { - return err - } - opts.Format = format - - prompts := args[1:] - // prepend stdin to the prompt if provided - if !term.IsTerminal(int(os.Stdin.Fd())) { - in, err := io.ReadAll(os.Stdin) - if err != nil { - return err - } - - prompts = append([]string{string(in)}, prompts...) - opts.WordWrap = false - interactive = false - } - opts.Prompt = strings.Join(prompts, " ") - if len(prompts) > 0 { - interactive = false - } - - nowrap, err := cmd.Flags().GetBool("nowordwrap") - if err != nil { - return err - } - opts.WordWrap = !nowrap - - if !interactive { - return generate(cmd, opts) - } - - return generateInteractive(cmd, opts) -} - type generateContextKey string type runOptions struct { @@ -630,10 +629,18 @@ func generate(cmd *cobra.Command, opts runOptions) error { return nil } + if opts.MultiModal { + opts.Prompt, opts.Images, err = extractFileData(opts.Prompt) + if err != nil { + return err + } + } + request := api.GenerateRequest{ Model: opts.Model, Prompt: opts.Prompt, Context: generateContext, + Images: opts.Images, Format: opts.Format, System: opts.System, Template: opts.Template, diff --git a/cmd/interactive.go b/cmd/interactive.go index 690cd107..fe450cf9 100644 --- a/cmd/interactive.go +++ b/cmd/interactive.go @@ -601,10 +601,10 @@ func extractFileData(input string) (string, []api.ImageData, error) { if os.IsNotExist(err) { continue } - fmt.Printf("Couldn't process image: %q\n", err) + fmt.Fprintf(os.Stderr, "Couldn't process image: %q\n", err) return "", imgs, err } - fmt.Printf("Added image '%s'\n", nfp) + fmt.Fprintf(os.Stderr, "Added image '%s'\n", nfp) input = strings.ReplaceAll(input, fp, "") imgs = append(imgs, data) }