Improve prompt API sample (#1344)

* Improve prompt API sample

* Render response as markdown
* Fix initial maxK and temperature values
* Add privacy statement (for webstore submission)
* Regenerate key and trial token

* fix formatting errors

* Update functional-samples/ai.gemini-on-device/sidepanel/index.js

Update maxTemperature

Co-authored-by: Thomas Steiner <tomac@google.com>

* Update functional-samples/ai.gemini-on-device/sidepanel/index.js

Better string comparison

Co-authored-by: Thomas Steiner <tomac@google.com>

---------

Co-authored-by: Thomas Steiner <tomac@google.com>
This commit is contained in:
Sebastian Benz
2024-11-08 15:35:27 +01:00
committed by GitHub
parent d2fd736ac0
commit 69f946b35e
10 changed files with 1577 additions and 20 deletions

1
.gitignore vendored
View File

@@ -4,4 +4,5 @@ node_modules
# Temporary directory for debugging extension samples # Temporary directory for debugging extension samples
_debug _debug
_metadata _metadata
dist
*.swp # vim temp files *.swp # vim temp files

View File

@@ -1,3 +1,4 @@
_archive _archive
third-party third-party
node_modules node_modules
dist

View File

@@ -0,0 +1,3 @@
dist
node_modules
*.swp

View File

@@ -1,14 +1,14 @@
{ {
"name": "Chrome Built-in AI Demo", "name": "Chrome Prompt AI Demo",
"version": "0.1", "version": "0.1",
"manifest_version": 3, "manifest_version": 3,
"description": "Try the built-in AI preview in Chrome.", "description": "Try Chrome's built-in prompt API.",
"background": { "background": {
"service_worker": "background.js" "service_worker": "background.js"
}, },
"permissions": ["sidePanel", "aiLanguageModelOriginTrial"], "permissions": ["sidePanel", "aiLanguageModelOriginTrial"],
"trial_tokens": ["A6hC1yvazc5QTqSESgEo3uwIUs1KBM4VB93yiTdtgFlFlYNJjf18zmzScpaCepaYpNLaMJ4dNkDps+vbrk7oEw8AAAB9eyJvcmlnaW4iOiAiY2hyb21lLWV4dGVuc2lvbjovL2lkZm1qYmJqY21qamtoYWlvZmltbWNtY29qYmlnbmpmIiwgImZlYXR1cmUiOiAiQUlQcm9tcHRBUElGb3JFeHRlbnNpb24iLCAiZXhwaXJ5IjogMTk4OTQwNzUwMH0="], "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvf0O/bR3JULoj6dOpG7sDif4BNVgootUIfSybh2a7jX47BglfZFNH/aRUgDjNtcTBPinXdGbljMVIudQ7w6LiwVq9b1Ht6ZXFVtHTKOsDWtVh/rVKE/AGue9eQ7xCncHFl4zLJUaDRUIRqe5zvjHtaMr8p92I3c/6k43LmTUp1QHz0NooDJRYKRPLS77YVDX8hZc2yopIH5NIY25Ned3wxZ/NWV70GZkYqFRN+UzvMS8bJUEY23L1AMSX7YQjMThY0BCZ/MBLo8UBLs8vN11EphMpLxnBhF2Zwwj2sCPR0jn0ev8HYCtKmGx8nzOl79oK24RFIsW8YWFB2fd28fBLwIDAQAB",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi99ZKuRYfZMQ80XryBYKNA4DJTHPMEiNkiF6TLqTXMp4Cb23I/DTblxlEELWyM1vDuXeFI7jqXDuM6YVHd7zTtA1hGbGgLm9w9+d763x2wCRbxud+dXIXW4IoD4CqXpCLscDD7Vrar/I5XbcmdA9jjlCXMGS2OKNRhYMjNpaVhFCi2jzWid+92DZSpPbdM9iBODGfwnFNp16tFX8/dDx3w23FneeOVHV3JjNIWO3uT60AhZWOtcQlERuMBJmEkKAgqE8T3ZjoZe4ALupfvDxI7khP29+gBXhgF/r6T0RAbB1LfxubhyLk/X7aC/sw3umCemqvc+knvKRBLHMVl1nHQIDAQAB", "trial_tokens": ["Aozzz6KfHYqh8q5x+Khse27nSp8YM7Tftv6XZhNO7lgYcP5uQxxBEpMfRhiFbYJV+yJl1fDNzvtao7FswtZGIgQAAAB4eyJvcmlnaW4iOiJjaHJvbWUtZXh0ZW5zaW9uOi8vYWhpaWZrb2RnbWlmcGNnbmRja3BwaW1lY25wa3BkbGwiLCJmZWF0dXJlIjoiQUlQcm9tcHRBUElGb3JFeHRlbnNpb24iLCJleHBpcnkiOjE3NjA0ODYzOTl9"],
"minimum_chrome_version": "131", "minimum_chrome_version": "131",
"side_panel": { "side_panel": {
"default_path": "sidepanel/index.html" "default_path": "sidepanel/index.html"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
{
"name": "Chrome Prompt API Example",
"private": true,
"version": "1.0.0",
"description": "",
"main": "background.js",
"scripts": {
"build": "rollup -c rollup.config.mjs"
},
"keywords": [],
"license": "Apache 2.0",
"devDependencies": {
"dompurify": "3.1.6",
"marked": "14.1.2",
"@rollup/plugin-commonjs": "26.0.1",
"@rollup/plugin-node-resolve": "15.2.3",
"rollup": "4.22.4",
"rollup-plugin-copy": "3.5.0"
}
}

View File

@@ -0,0 +1 @@
This extension does not collect, use or share any user data.

View File

@@ -0,0 +1,29 @@
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import copy from 'rollup-plugin-copy';
export default [
{
input: 'sidepanel/index.js',
output: {
dir: 'dist/sidepanel',
format: 'iife',
},
plugins: [
nodeResolve({
jsnext: true,
main: true,
browser: true
}),
commonjs(),
copy({
targets: [
{
src: ['manifest.json', 'background.js', 'sidepanel', 'images'],
dest: 'dist'
}
]
})
]
}
];

View File

@@ -4,7 +4,6 @@
<link rel="stylesheet" type="text/css" href="index.css" /> <link rel="stylesheet" type="text/css" href="index.css" />
</head> </head>
<body> <body>
<h1>Chrome built-in AI</h1>
<textarea <textarea
id="input-prompt" id="input-prompt"
placeholder='Type something, e.g. "Write a haiku about Chrome Extensions"' placeholder='Type something, e.g. "Write a haiku about Chrome Extensions"'
@@ -25,7 +24,7 @@
></label> ></label>
</div> </div>
<div> <div>
<input type="range" id="top-k" name="top-k" min="1" max="50" step="1" /> <input type="range" id="top-k" name="top-k" min="1" max="8" step="1" />
<label for="top-k">Top-k: <span id="label-top-k"></span></label> <label for="top-k">Top-k: <span id="label-top-k"></span></label>
</div> </div>
<button id="button-prompt" class="primary" disabled>Run</button> <button id="button-prompt" class="primary" disabled>Run</button>

View File

@@ -1,3 +1,6 @@
import DOMPurify from 'dompurify';
import { marked } from 'marked';
const inputPrompt = document.body.querySelector('#input-prompt'); const inputPrompt = document.body.querySelector('#input-prompt');
const buttonPrompt = document.body.querySelector('#button-prompt'); const buttonPrompt = document.body.querySelector('#button-prompt');
const buttonReset = document.body.querySelector('#button-reset'); const buttonReset = document.body.querySelector('#button-reset');
@@ -41,11 +44,19 @@ async function initDefaults() {
} }
const defaults = await chrome.aiOriginTrial.languageModel.capabilities(); const defaults = await chrome.aiOriginTrial.languageModel.capabilities();
console.log('Model default:', defaults); console.log('Model default:', defaults);
sliderTemperature.value = defaults.temperature; if (defaults.available !== 'readily') {
sliderTopK.value = defaults.topK; showResponse(
labelTopK.textContent = defaults.topK; `Model not yet available (current state: "${defaults.available}")`
labelTemperature.textContent = defaults.temperature; );
labelTemperature.value = defaults.temperature; return;
}
sliderTemperature.value = defaults.defaultTemperature;
// sliderTemperature.max = defaults.maxTemperature;
// Pending https://issues.chromium.org/issues/367771112.
sliderTopK.value = defaults.defaultTopK;
sliderTopK.max = defaults.maxTopK;
labelTopK.textContent = defaults.defaultTopK;
labelTemperature.textContent = defaults.defaultTemperature;
} }
initDefaults(); initDefaults();
@@ -101,15 +112,7 @@ function showLoading() {
function showResponse(response) { function showResponse(response) {
hide(elementLoading); hide(elementLoading);
show(elementResponse); show(elementResponse);
// Make sure to preserve line breaks in the response elementResponse.innerHTML = DOMPurify.sanitize(marked.parse(response));
elementResponse.textContent = '';
const paragraphs = response.split(/\r?\n/);
for (const paragraph of paragraphs) {
if (paragraph) {
elementResponse.appendChild(document.createTextNode(paragraph));
}
elementResponse.appendChild(document.createElement('BR'));
}
} }
function showError(error) { function showError(error) {