-
Notifications
You must be signed in to change notification settings - Fork 108
feat: Add AI Generated Cat add-on sample #213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
d969052
feat: Add AI Generated Cat add-on sample
google-labs-jules[bot] 155f465
feat: Add AI Generated Cat add-on sample
google-labs-jules[bot] 3206bd7
Update apps-script/generative-ai/cat-add-on/README.md
vinay-google 4dd08af
Update apps-script/generative-ai/cat-add-on/README.md
vinay-google 4815daa
feat: Add AI Generated Cat add-on sample
google-labs-jules[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| /** | ||
| * Copyright 2025 Google LLC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| // --- Add-on Entry Points --- | ||
|
|
||
| /** | ||
| * Returns the add-on's homepage card. | ||
| * | ||
| * @param {GoogleAppsScript.Addons.EventObject} e The event object. | ||
| * @returns {GoogleAppsScript.Card_Service.Card} The constructed Card object. | ||
| */ | ||
| function onHomepage(e) { | ||
| // Calls the card builder function defined in CardBuilder.js | ||
| return createCatCard(); | ||
| } | ||
|
|
||
| /** | ||
| * Handles the button click action to refresh the card with a new cat image. | ||
| * | ||
| * @param {GoogleAppsScript.Addons.EventObject} e The event object. | ||
| * @returns {GoogleAppsScript.Card_Service.ActionResponse} The action response to update the card. | ||
| */ | ||
| function updateCatImage(e) { | ||
| // Re-run the function that generates the new image and builds the card. | ||
| const updatedCard = createCatCard(); | ||
|
|
||
| // Create an ActionResponse to push the new card to the user's interface. | ||
| return CardService.newActionResponseBuilder() | ||
| .setNavigation(CardService.newNavigation().updateCard(updatedCard)) | ||
| .build(); | ||
| } | ||
|
|
||
| // NOTE: This function needs access to the global constants defined in Configuration.gs | ||
|
|
||
| /** | ||
| * Creates a card with an AI-generated cat image and a refresh button. | ||
| * | ||
| * @returns {GoogleAppsScript.Card_Service.Card} The card object. | ||
| */ | ||
| function createCatCard() { | ||
| // Calls the API function defined in VertexAI.js | ||
| const imageDataUri = generateImage(IMAGE_PROMPT); | ||
|
|
||
| // Define the action to be taken when the button is clicked | ||
| // Calls the function defined in Code.gs | ||
| const updateAction = CardService.newAction() | ||
| .setFunctionName('updateCatImage'); | ||
|
|
||
| // Create the "Generate New Cat" button | ||
| const button = CardService.newTextButton() | ||
| .setText('Generate New Cat 🐈') | ||
| .setTextButtonStyle(CardService.TextButtonStyle.FILLED) | ||
| .setOnClickAction(updateAction); | ||
|
|
||
| // Create the image widget using the generated Data URI | ||
| const imageWidget = CardService.newImage() | ||
| .setImageUrl(imageDataUri) | ||
| .setAltText('An AI-generated cat'); | ||
|
|
||
| // Build the card structure | ||
| const header = CardService.newCardHeader().setTitle('AI Generated Cat'); | ||
| const section = CardService.newCardSection() | ||
| .addWidget(imageWidget) | ||
| .addWidget(button); | ||
|
|
||
| return CardService.newCardBuilder() | ||
| .setHeader(header) | ||
| .addSection(section) | ||
| .build(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /** | ||
| * Copyright 2025 Google LLC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| // --- Configuration & Constants --- | ||
|
|
||
| /** | ||
| * Your Google Cloud Project ID for Vertex AI access. | ||
| * ⚠️ WARNING: Update this value before running. | ||
| * NOTE: Ensure the Apps Script project has the 'https://www.googleapis.com/auth/cloud-platform' scope. | ||
| */ | ||
| const PROJECT_ID = 'your-project-id'; | ||
| const MODEL_ID = 'gemini-2.5-flash-image'; | ||
| const IMAGE_PROMPT = 'A high-quality, photorealistic image of a random cat.'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| # AI Generated Cat - Google Workspace Add-on | ||
|
|
||
| This Google Workspace Add-on displays an AI-generated image of a cat in the Gmail side panel. Users can click a button to generate a new cat image. | ||
|
|
||
| The add-on leverages the Gemini 2.5 Flash image model via the Google Vertex AI API. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Before you begin, ensure you have the following: | ||
|
|
||
| 1. **Google Cloud Project:** A Google Cloud project to host the add-on and enable the Vertex AI API. | ||
| 2. **Google Cloud SDK:** The `gcloud` command-line tool installed and authenticated. You can find installation instructions [here](https://cloud.google.com/sdk/docs/install). | ||
| 3. **clasp:** The command-line tool for Apps Script development. Install it using npm: | ||
| ```bash | ||
| npm install -g @google/clasp | ||
| ``` | ||
|
|
||
| ## Setup and Configuration | ||
|
|
||
| 1. **Enable the Vertex AI API:** | ||
|
|
||
| Enable the Vertex AI API in your Google Cloud project: | ||
| ```bash | ||
| gcloud services enable aiplatform.googleapis.com --project=YOUR_PROJECT_ID | ||
| ``` | ||
| Replace `YOUR_PROJECT_ID` with your actual Google Cloud project ID. | ||
|
|
||
| 2. **Configure the Project ID:** | ||
|
|
||
| Open the `Configuration.js` file and update the `PROJECT_ID` constant with your Google Cloud project ID: | ||
| ```javascript | ||
| const PROJECT_ID = 'YOUR_PROJECT_ID'; | ||
| ``` | ||
|
|
||
| 3. **Log in to clasp:** | ||
|
|
||
| Authenticate `clasp` with your Google account: | ||
| ```bash | ||
| clasp login | ||
vinay-google marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ``` | ||
|
|
||
| ## Deployment | ||
|
|
||
| 1. **Push the Apps Script Project:** | ||
|
|
||
| Use `clasp` to push your local code to your Apps Script project: | ||
| ```bash | ||
| clasp push | ||
| ``` | ||
|
|
||
| 2. **Create a Google Workspace Add-on Deployment:** | ||
vinay-google marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Create a deployment for your add-on using the `gcloud` command: | ||
| ```bash | ||
| gcloud workspace-add-ons deployments create my-deployment \ | ||
| --project=YOUR_PROJECT_ID \ | ||
| --add-on-type=GMAIL \ | ||
| --name="AI Generated Cat" \ | ||
| --description="An add-on that shows AI generated cats." \ | ||
| --script-id=YOUR_SCRIPT_ID | ||
| ``` | ||
| - Replace `YOUR_PROJECT_ID` with your Google Cloud project ID. | ||
| - Replace `YOUR_SCRIPT_ID` with your Apps Script project's script ID. You can find this in the `.clasp.json` file or in the Apps Script editor URL. | ||
|
|
||
| ## Installation | ||
|
|
||
| To install the add-on for your own account, use the following command: | ||
|
|
||
| ```bash | ||
| gcloud workspace-add-ons deployments install my-deployment --project=YOUR_PROJECT_ID | ||
| ``` | ||
| - Replace `my-deployment` with the name of the deployment you created in the previous step. | ||
| - Replace `YOUR_PROJECT_ID` with your Google Cloud project ID. | ||
|
|
||
| After installation, you should see the "AI Generated Cat" add-on in your Gmail side panel. | ||
|
|
||
| ## OAuth Scopes | ||
|
|
||
| This add-on requires the following OAuth scopes: | ||
|
|
||
| * `https://www.googleapis.com/auth/cloud-platform`: To access the Vertex AI API. | ||
| * `https://www.googleapis.com/auth/gmail.addons.execute`: To run as a Gmail add-on. | ||
| * `https://www.googleapis.com/auth/script.external_request`: To make external HTTP requests using `UrlFetchApp`. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /** | ||
| * Copyright 2025 Google LLC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| /** | ||
| * Generates an image using the gemini-2.5-flash-image model on Vertex AI | ||
| * and returns it as a Data URI. | ||
| * | ||
| * @param {string} prompt The text prompt to generate the image from. | ||
| * @returns {string} A Data URI string (e.g., 'data:image/png;base64,...') or a fallback image URL on error. | ||
| */ | ||
| function generateImage(prompt) { | ||
| // Uses global constants from Configuration.gs | ||
| const ENDPOINT = `https://aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/global/publishers/google/models/${MODEL_ID}:generateContent`; | ||
|
|
||
| const payload = { | ||
| generationConfig: { | ||
| responseModalities: ['IMAGE', 'TEXT'], | ||
| imageConfig: { | ||
| aspectRatio: '1:1', | ||
| } | ||
| }, | ||
| contents: [{ | ||
| role: 'user', | ||
| parts: [{ | ||
| text: prompt | ||
| }] | ||
| }] | ||
| }; | ||
|
|
||
| const options = { | ||
| method: 'post', | ||
| contentType: 'application/json', | ||
| headers: { | ||
| Authorization: `Bearer ${ScriptApp.getOAuthToken()}`, | ||
| Accept: 'application/json' | ||
| }, | ||
| payload: JSON.stringify(payload), | ||
| muteHttpExceptions: true | ||
| }; | ||
|
|
||
| try { | ||
| const response = UrlFetchApp.fetch(ENDPOINT, options); | ||
| const responseBody = response.getContentText(); | ||
| const responseData = JSON.parse(responseBody); | ||
|
|
||
| if (response.getResponseCode() !== 200) { | ||
| console.error(`Vertex AI API Error (${response.getResponseCode()}): ${responseBody}`); | ||
| const errorMessage = responseData?.error?.message || 'Unknown API Error'; | ||
| throw new Error(`Vertex AI API call failed: ${errorMessage}`); | ||
| } | ||
|
|
||
| const imagePart = responseData.candidates?.[0]?.content?.parts?.find( | ||
| part => part.inlineData?.mimeType?.startsWith('image/') | ||
| ); | ||
|
|
||
| if (!imagePart) { | ||
| console.error(`No image data found in response: ${responseBody}`); | ||
| throw new Error('Image generation failed or no image data was returned.'); | ||
| } | ||
|
|
||
| const { data: base64Data, mimeType } = imagePart.inlineData; | ||
|
|
||
| return `data:${mimeType};base64,${base64Data}`; | ||
|
|
||
| } catch (e) { | ||
| console.error(`An error occurred during image generation: ${e.toString()}`); | ||
| return 'https://www.google.com/images/errors/robot.png'; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| { | ||
| "timeZone": "America/New_York", | ||
| "dependencies": {}, | ||
| "exceptionLogging": "STACKDRIVER", | ||
| "runtimeVersion": "V8", | ||
| "oauthScopes": [ | ||
| "https://www.googleapis.com/auth/cloud-platform", | ||
| "https://www.googleapis.com/auth/gmail.addons.execute", | ||
| "https://www.googleapis.com/auth/script.external_request" | ||
| ], | ||
| "gmail": { | ||
| "name": "AI Generated Cat", | ||
| "logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/pets/v12/gm_blue-48dp/1x/gm_pets_gm_blue_48dp.png", | ||
| "homepageTrigger": { | ||
| "runFunction": "onHomepage" | ||
| } | ||
| }, | ||
| "urlFetchWhitelist": [ | ||
| "https://*.googleapis.com/" | ||
| ] | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.