diff --git a/google.go b/google.go new file mode 100644 index 0000000..3d301ff --- /dev/null +++ b/google.go @@ -0,0 +1,97 @@ +package summaraizer + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" +) + +// Google is a provider that uses Google as an AI provider. +type Google struct { + Model string // The Ai model to use. + Prompt string // The prompt to use for the AI model. + ApiToken string // The API Token for Google. +} + +func (a *Google) Summarize(reader io.Reader) (string, error) { + return decodeAndSummarize(reader, func(comments Comments) (string, error) { + prompt, err := resolvePrompt(a.Prompt, comments) + if err != nil { + return "", err + } + + request := googleRequest{ + GoogleContentsRequest: []googleContentsRequest{ + { + Parts: []googlePartsRequest{ + { + Text: prompt, + }, + }, + }, + }, + } + reqBodyBytes, err := json.Marshal(request) + if err != nil { + return "", err + } + + url := fmt.Sprintf( + "https://generativelanguage.googleapis.com/v1beta/models/%s:generateContent?key=%s", + a.Model, + a.ApiToken, + ) + req, err := http.NewRequest( + "POST", + url, + bytes.NewBuffer(reqBodyBytes), + ) + if err != nil { + return "", err + } + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + var response googleResponse + err = json.Unmarshal(respBody, &response) + if err != nil { + return "", err + } + + return response.Candidates[0].Content.Parts[0].Text, nil + }) +} + +type googleRequest struct { + GoogleContentsRequest []googleContentsRequest `json:"contents"` +} + +type googleContentsRequest struct { + Parts []googlePartsRequest `json:"parts"` +} + +type googlePartsRequest struct { + Text string `json:"text"` +} + +type googleResponse struct { + Candidates []struct { + Content struct { + Parts []struct { + Text string `json:"text"` + } `json:"parts"` + } `json:"content"` + } `json:"candidates"` +} diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 277ce8d..fe040a4 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -17,7 +17,7 @@ var rootCmd = &cobra.Command{ func NewRootCmd() *cobra.Command { rootCmd.AddCommand(githubCmd(), redditCmd(), gitlabCmd(), slackCmd()) - rootCmd.AddCommand(ollamaCmd(), openaiCmd(), anthropicCmd()) + rootCmd.AddCommand(ollamaCmd(), openaiCmd(), anthropicCmd(), googleCmd()) return rootCmd } @@ -218,6 +218,33 @@ func anthropicCmd() *cobra.Command { return cmd } +func googleCmd() *cobra.Command { + flagToken := "token" + cmd := &cobra.Command{ + Use: "google", + Short: "Summarizes using Google AI", + Long: "Summarizes using Google AI.", + RunE: func(cmd *cobra.Command, args []string) error { + aiModel, _ := cmd.Flags().GetString(aiFlagModel) + aiPrompt, _ := cmd.Flags().GetString(aiFlagPrompt) + apiToken, _ := cmd.Flags().GetString(flagToken) + + p := &summaraizer.Google{ + Model: aiModel, + Prompt: aiPrompt, + ApiToken: apiToken, + } + + return summarize(p) + }, + } + cmd.Flags().String(aiFlagModel, "gemini-1.5-flash-8b", "The AI model to use") + cmd.Flags().String(aiFlagPrompt, defaultPromptTemplate, "The prompt to use for the AI model") + cmd.Flags().String(flagToken, "", "The API Token for Google") + cmd.MarkFlagRequired(flagToken) + return cmd +} + var defaultPromptTemplate = ` I give you a discussion and you give me a summary. Each comment of the discussion is wrapped in a tag. diff --git a/internal/cli/docs/summaraizer.md b/internal/cli/docs/summaraizer.md index d0d9ce5..f6ee159 100644 --- a/internal/cli/docs/summaraizer.md +++ b/internal/cli/docs/summaraizer.md @@ -17,6 +17,7 @@ A tool to summarize comments from various sources using AI. * [summaraizer anthropic](summaraizer_anthropic.md) - Summarizes using Anthropic AI * [summaraizer github](summaraizer_github.md) - Summarizes using GitHub as source * [summaraizer gitlab](summaraizer_gitlab.md) - Summarizes using GitLab as source +* [summaraizer google](summaraizer_google.md) - Summarizes using Google AI * [summaraizer ollama](summaraizer_ollama.md) - Summarizes using Ollama AI * [summaraizer openai](summaraizer_openai.md) - Summarizes using OpenAI AI * [summaraizer reddit](summaraizer_reddit.md) - Summarizes using Reddit as source diff --git a/internal/cli/docs/summaraizer_google.md b/internal/cli/docs/summaraizer_google.md new file mode 100644 index 0000000..64055f0 --- /dev/null +++ b/internal/cli/docs/summaraizer_google.md @@ -0,0 +1,25 @@ +## summaraizer google + +Summarizes using Google AI + +### Synopsis + +Summarizes using Google AI. + +``` +summaraizer google [flags] +``` + +### Options + +``` + -h, --help help for google + --model string The AI model to use (default "gemini-1.5-flash-8b") + --prompt string The prompt to use for the AI model (default "\nI give you a discussion and you give me a summary.\nEach comment of the discussion is wrapped in a tag.\nYour summary should not be longer than 1200 chars.\nHere is the discussion:\n{{ range $comment := . }}\n{{ $comment.Body }}\n{{end}}\n") + --token string The API Token for Google +``` + +### SEE ALSO + +* [summaraizer](summaraizer.md) - Summarizes comments +