diff --git a/.gitignore b/.gitignore index 7c981e6f..742aea9b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules # Temporary directory for debugging extension samples _debug _metadata +*.swp # vim temp files diff --git a/functional-samples/ai.gemini-in-the-cloud/.gitignore b/functional-samples/ai.gemini-in-the-cloud/.gitignore new file mode 100644 index 00000000..1521c8b7 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/.gitignore @@ -0,0 +1 @@ +dist diff --git a/functional-samples/ai.gemini-in-the-cloud/README.md b/functional-samples/ai.gemini-in-the-cloud/README.md new file mode 100644 index 00000000..b260bb87 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/README.md @@ -0,0 +1,23 @@ +# On-device AI with Gemini Nano + +This sample demonstrates how to use the Gemini Cloud API in a Chrome Extension. + +## Overview + +The extension provides a chat interface for the Gemini API. To learn more about the API head over to [https://ai.google.dev/](https://ai.google.dev/). + +## Running this extension + +1. Clone this repository. +2. Download the Gemini API client by running: + ```sh + npm install + ``` +3. [Retrieve an API key](https://ai.google.dev/gemini-api/docs/api-key) and update [functional-samples/ai.gemini-in-the-cloud/sidepanel/index.js](functional-samples/ai.gemini-in-the-cloud/sidepanel/index.js) (only for testing). +4. Compile the JS bundle for the sidepanel implementation by running: + ```sh + npm run build + ``` +5. Load this directory in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked). +6. Click the extension icon. +7. Interact with the prompt API in the sidebar. diff --git a/functional-samples/ai.gemini-in-the-cloud/background.js b/functional-samples/ai.gemini-in-the-cloud/background.js new file mode 100644 index 00000000..d7262b80 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/background.js @@ -0,0 +1,3 @@ +chrome.sidePanel + .setPanelBehavior({ openPanelOnActionClick: true }) + .catch((error) => console.error(error)); diff --git a/functional-samples/ai.gemini-in-the-cloud/images/icon128.png b/functional-samples/ai.gemini-in-the-cloud/images/icon128.png new file mode 100644 index 00000000..78790619 Binary files /dev/null and b/functional-samples/ai.gemini-in-the-cloud/images/icon128.png differ diff --git a/functional-samples/ai.gemini-in-the-cloud/images/icon16.png b/functional-samples/ai.gemini-in-the-cloud/images/icon16.png new file mode 100644 index 00000000..a8eb458c Binary files /dev/null and b/functional-samples/ai.gemini-in-the-cloud/images/icon16.png differ diff --git a/functional-samples/ai.gemini-in-the-cloud/images/icon32.png b/functional-samples/ai.gemini-in-the-cloud/images/icon32.png new file mode 100644 index 00000000..838c426c Binary files /dev/null and b/functional-samples/ai.gemini-in-the-cloud/images/icon32.png differ diff --git a/functional-samples/ai.gemini-in-the-cloud/images/icon48.png b/functional-samples/ai.gemini-in-the-cloud/images/icon48.png new file mode 100644 index 00000000..932bdfe4 Binary files /dev/null and b/functional-samples/ai.gemini-in-the-cloud/images/icon48.png differ diff --git a/functional-samples/ai.gemini-in-the-cloud/manifest.json b/functional-samples/ai.gemini-in-the-cloud/manifest.json new file mode 100644 index 00000000..9f7574c3 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/manifest.json @@ -0,0 +1,22 @@ +{ + "name": "Google Gemini Demo", + "version": "0.1", + "manifest_version": 3, + "description": "Try the Gemini Models.", + "background": { + "service_worker": "background.js" + }, + "permissions": ["sidePanel"], + "side_panel": { + "default_path": "sidepanel/index.html" + }, + "action": { + "default_icon": { + "16": "images/icon16.png", + "32": "images/icon32.png", + "48": "images/icon48.png", + "128": "images/icon128.png" + }, + "default_title": "Open Chat Interface" + } +} diff --git a/functional-samples/ai.gemini-in-the-cloud/package-lock.json b/functional-samples/ai.gemini-in-the-cloud/package-lock.json new file mode 100644 index 00000000..8aafc456 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/package-lock.json @@ -0,0 +1,288 @@ +{ + "name": "Chrome Extensions Gemini Demo", + "version": "1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "Chrome Extensions Gemini Demo", + "version": "1.0", + "devDependencies": { + "@google/generative-ai": "0.15.0", + "rollup": "4.19.0" + } + }, + "node_modules/@google/generative-ai": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.15.0.tgz", + "integrity": "sha512-zs37judcTYFJf1U7tnuqnh7gdzF6dcWj9pNRxjA5JTONRoiQ0htrRdbefRFiewOIfXwhun5t9hbd2ray7812eQ==", + "dev": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.0.tgz", + "integrity": "sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.0.tgz", + "integrity": "sha512-RDxUSY8D1tWYfn00DDi5myxKgOk6RvWPxhmWexcICt/MEC6yEMr4HNCu1sXXYLw8iAsg0D44NuU+qNq7zVWCrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.0.tgz", + "integrity": "sha512-emvKHL4B15x6nlNTBMtIaC9tLPRpeA5jMvRLXVbl/W9Ie7HhkrE7KQjvgS9uxgatL1HmHWDXk5TTS4IaNJxbAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.0.tgz", + "integrity": "sha512-fO28cWA1dC57qCd+D0rfLC4VPbh6EOJXrreBmFLWPGI9dpMlER2YwSPZzSGfq11XgcEpPukPTfEVFtw2q2nYJg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.0.tgz", + "integrity": "sha512-2Rn36Ubxdv32NUcfm0wB1tgKqkQuft00PtM23VqLuCUR4N5jcNWDoV5iBC9jeGdgS38WK66ElncprqgMUOyomw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.0.tgz", + "integrity": "sha512-gJuzIVdq/X1ZA2bHeCGCISe0VWqCoNT8BvkQ+BfsixXwTOndhtLUpOg0A1Fcx/+eA6ei6rMBzlOz4JzmiDw7JQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.0.tgz", + "integrity": "sha512-0EkX2HYPkSADo9cfeGFoQ7R0/wTKb7q6DdwI4Yn/ULFE1wuRRCHybxpl2goQrx4c/yzK3I8OlgtBu4xvted0ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.0.tgz", + "integrity": "sha512-GlIQRj9px52ISomIOEUq/IojLZqzkvRpdP3cLgIE1wUWaiU5Takwlzpz002q0Nxxr1y2ZgxC2obWxjr13lvxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.0.tgz", + "integrity": "sha512-N6cFJzssruDLUOKfEKeovCKiHcdwVYOT1Hs6dovDQ61+Y9n3Ek4zXvtghPPelt6U0AH4aDGnDLb83uiJMkWYzQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.0.tgz", + "integrity": "sha512-2DnD3mkS2uuam/alF+I7M84koGwvn3ZVD7uG+LEWpyzo/bq8+kKnus2EVCkcvh6PlNB8QPNFOz6fWd5N8o1CYg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.0.tgz", + "integrity": "sha512-D6pkaF7OpE7lzlTOFCB2m3Ngzu2ykw40Nka9WmKGUOTS3xcIieHe82slQlNq69sVB04ch73thKYIWz/Ian8DUA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.0.tgz", + "integrity": "sha512-HBndjQLP8OsdJNSxpNIN0einbDmRFg9+UQeZV1eiYupIRuZsDEoeGU43NQsS34Pp166DtwQOnpcbV/zQxM+rWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.0.tgz", + "integrity": "sha512-HxfbvfCKJe/RMYJJn0a12eiOI9OOtAUF4G6ozrFUK95BNyoJaSiBjIOHjZskTUffUrB84IPKkFG9H9nEvJGW6A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.0.tgz", + "integrity": "sha512-HxDMKIhmcguGTiP5TsLNolwBUK3nGGUEoV/BO9ldUBoMLBssvh4J0X8pf11i1fTV7WShWItB1bKAKjX4RQeYmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.0.tgz", + "integrity": "sha512-xItlIAZZaiG/u0wooGzRsx11rokP4qyc/79LkAOdznGRAbOFc+SfEdfUOszG1odsHNgwippUJavag/+W/Etc6Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.0.tgz", + "integrity": "sha512-xNo5fV5ycvCCKqiZcpB65VMR11NJB+StnxHz20jdqRAktfdfzhgjTiJ2doTDQE/7dqGaV5I7ZGqKpgph6lCIag==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/rollup": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.19.0.tgz", + "integrity": "sha512-5r7EYSQIowHsK4eTZ0Y81qpZuJz+MUuYeqmmYmRMl1nwhdmbiYqt5jwzf6u7wyOzJgYqtCRMtVRKOtHANBz7rA==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.19.0", + "@rollup/rollup-android-arm64": "4.19.0", + "@rollup/rollup-darwin-arm64": "4.19.0", + "@rollup/rollup-darwin-x64": "4.19.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.19.0", + "@rollup/rollup-linux-arm-musleabihf": "4.19.0", + "@rollup/rollup-linux-arm64-gnu": "4.19.0", + "@rollup/rollup-linux-arm64-musl": "4.19.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.19.0", + "@rollup/rollup-linux-riscv64-gnu": "4.19.0", + "@rollup/rollup-linux-s390x-gnu": "4.19.0", + "@rollup/rollup-linux-x64-gnu": "4.19.0", + "@rollup/rollup-linux-x64-musl": "4.19.0", + "@rollup/rollup-win32-arm64-msvc": "4.19.0", + "@rollup/rollup-win32-ia32-msvc": "4.19.0", + "@rollup/rollup-win32-x64-msvc": "4.19.0", + "fsevents": "~2.3.2" + } + } + } +} diff --git a/functional-samples/ai.gemini-in-the-cloud/package.json b/functional-samples/ai.gemini-in-the-cloud/package.json new file mode 100644 index 00000000..8b856c61 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/package.json @@ -0,0 +1,12 @@ +{ + "name": "Chrome Extensions Gemini Demo", + "version": "1.0", + "scripts": { + "build": "rollup sidepanel/index.js --file dist/sidepanel.bundle.js --format iife" + }, + "private": true, + "devDependencies": { + "@google/generative-ai": "0.15.0", + "rollup": "4.19.0" + } +} diff --git a/functional-samples/ai.gemini-in-the-cloud/sidepanel/index.css b/functional-samples/ai.gemini-in-the-cloud/sidepanel/index.css new file mode 100644 index 00000000..d88a10d5 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/sidepanel/index.css @@ -0,0 +1,82 @@ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, + Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + color: #1f1f1f; + background-color: #f2f2f2; + font-size: 16px; + padding: 8px; +} + +input, +button, +textarea, +select { + font-family: inherit; + font-size: inherit; +} + +button { + background: #333; + color: white; + border-radius: 8px; + border: none; + min-width: 100px; + padding: 8px; + margin: 16px 0; + cursor: pointer; +} + +button.primary { + background: #333; + color: white; +} + +button.secondary { + background: #ccc; + color: black; +} + +button[disabled] { + background: #ddd; + color: #aaa; +} + +input[type='range'] { + margin-top: 16px; + accent-color: black; +} + +textarea { + --padding: 32px; + width: calc(100% - var(--padding)); + max-width: calc(100% - var(--padding)); +} + +.text, +textarea { + background-color: white; + padding: 16px; + border-radius: 16px; + box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px, rgb(51, 51, 51) 0px 0px 0px 3px; + outline: none; +} + +.blink { + animation: 1s ease-in-out 1s infinite reverse both running blink; +} + +@keyframes blink { + 25% { + opacity: 0.5; + } + 50% { + opacity: 0; + } + 75% { + opacity: 0.5; + } +} + +[hidden] { + display: none; +} diff --git a/functional-samples/ai.gemini-in-the-cloud/sidepanel/index.html b/functional-samples/ai.gemini-in-the-cloud/sidepanel/index.html new file mode 100644 index 00000000..9c6deff5 --- /dev/null +++ b/functional-samples/ai.gemini-in-the-cloud/sidepanel/index.html @@ -0,0 +1,34 @@ + + +
+ + + +