Summarizer requires a user gesture

219 views
Skip to first unread message

Raymond Camden

unread,
Sep 4, 2025, 1:15:52 PMSep 4
to Chrome Built-in AI Early Preview Program Discussions
I'm testing a demo where I can drag/drop an electronic comic book into the web app and the prompt API is used to analyze the pictures inside. This works (well, mostly). For each image, I generate a summary string. 

I then wanted to use the summary API to summarize the summaries. 

let availability = await Summarizer.availability();
console.log('summarizer availability', availability);
let summarizer = await Summarizer.create({
format:'plain-text',
length:'long',
monitor(m) {
     m.addEventListener('downloadprogress', (e) => {
      console.log(`Downloading summarizer: ${e.loaded * 100}%`);
    });
  }
});

I get `downloadable` for status. But when create is run, I get:

Uncaught (in promise) NotAllowedError: Requires a user gesture when availability is "downloading" or "downloadable".

There was an earlier user gesture, afaik, earlier when I dropped the comic book onto the web page. As a test, I also interacted with the page while the initial process (analyze images) was working. What else can I do here?

Roland Bouman

unread,
Sep 4, 2025, 6:06:10 PMSep 4
to Chrome Built-in AI Early Preview Program Discussions, Raymond Camden
I ran into similar situations. 

Unfortunately, if the Summarizer (with those options) isn't already in the status "available", then you won't be able to escape this.

If I understand correctly,

navigator.userActivation.isActive

must be true for the create call to succeed. 

So you could check explicitly for userActivation, but this will only help you predict whether the call to create will fail - I can't help directly not help to create a situation where it will succeed.

What should work, is check for user activation directly before the call to create(), and when you find isActive is not true, exit the current workflow and pop up a modal dialog to inform the user the action is taking a little longer.
The dialog should have a "Ok" button which would close the dialog, and then inside the click event handler for that button you could you try to create the Summarizer.

(Once you created the Summarizer, you can cache it somewhere for later, repeated use)

I think that in theory, it's possible that before the call to availability, the userActivation could be true, while it might not necessarily be true anymore when availability resolves, even if it returns the status available.
(This is based on my understanding that userActivation uses a timeout-mechanism)

Raymond Camden

unread,
Sep 4, 2025, 6:27:33 PMSep 4
to Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Ugh, that sounds... crazy. :) I mean, I only start my process after a user click, so how could it _not_ be active?

I'm running into this in a second demo as well, with Rewriter. :\
--
===========================================================================
Raymond Camden

Email : raymon...@gmail.com
Blog : www.raymondcamden.com
Twitter: raymondcamden

François Beaufort

unread,
Sep 5, 2025, 9:35:17 AMSep 5
to Raymond Camden, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Thanks for reporting those issues!

Raymond, can you share your demo URL so that I can try to reproduce locally?
Which Chrome version did you use by the way?

--
You received this message because you are subscribed to the Google Groups "Chrome Built-in AI Early Preview Program Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chrome-ai-dev-previe...@chromium.org.
To view this discussion visit https://groups.google.com/a/chromium.org/d/msgid/chrome-ai-dev-preview-discuss/CAK2avF9wRjPNf39ER9ZQgqxUGWXAPhP3HsQ1_PpK1uGYE%3DFeKg%40mail.gmail.com.

Raymond Camden

unread,
Sep 5, 2025, 9:43:02 AMSep 5
to François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
I can share - but keep in mind this is a WIP and a bit ugly. Also, if you need a comic book file, send me a direct email. 


Use console of course. 

François Beaufort

unread,
Sep 5, 2025, 10:29:44 AMSep 5
to Raymond Camden, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
I nuked my Chrome Canary user data dir to simulate a fresh install, enabled the Prompt API flag, dropped a cbz file into https://cfjedimaster.github.io/ai-testingzone/comic_web_ai/index.html and waited for the AI model to be downloaded. Note that I had to wait a bit to get from 90% to 100% as expected since it's uncompression time.
After that, I had to refresh the page, dropped the cbz file again, and it said "Starting work on AI Summary." Note that I had another error which doesn't seem to related:

zip.min.js:1 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'size')
    at new Mt (zip.min.js:1:21728)
    at getBlob (app.js:94:12)
    at doAISummary (app.js:193:34)
    at handleAISupport (app.js:180:9)


In other words, I could not reproduce the "NotAllowedError: Requires a user gesture when availability is "downloading" or "downloadable"."  error sadly. 

There's one issue I've noticed though in this code.
You checked the previously set "status" variable after "await LanguageModel.create()". You should check "await LanguageModel.availability()" again after since  "await LanguageModel.create()" will actually trigger model download if status is 'downloadable'.

image.png

François Beaufort

unread,
Sep 5, 2025, 10:38:35 AMSep 5
to Raymond Camden, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Something like that:

let status = await LanguageModel.availability();
if (status === "unavailable") {
  $aiSummary.innerHTML = "<p>AI support is unavailable, sorry.</p>";
  return;
}

session = await LanguageModel.create(...);

status = await LanguageModel.availability();
console.log("status", status);
if (status === "downloadable" || status == "downloading") {
  $aiSummary.innerHTML =
    "<p>AI support is enabled, but must be downloaded. Please stand by.</p>";
  return;
} else doAISummary(pages, reader, binreader);

Raymond Camden

unread,
Sep 5, 2025, 10:39:55 AMSep 5
to François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Thanks - I noticed some issues with my download support (I'm using similar code in another demo) - will hack at it.

Raymond Camden

unread,
Sep 9, 2025, 2:43:36 PMSep 9
to François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Ok, I got things better. :) I now create the summarizer at the same time as the prompt, and it removed the gesture issue. In general it's working... except that when I remove my page limit to scan the entire comic, it tends to crap out about 20 or so pages in. No error, nothing in console just... it stops. It doesn't seem to slow down at any time - it does a page ever 3 seconds or so, but somewhere in the 20s (page range wise) it just comes to a halt. I've done a few tests now on the same Batman comic, and it dies on page 24 or 25 consistently. 

I fized the issue with CBZ files and I'm seeing the same - a silent error at page 24.


On Fri, Sep 5, 2025 at 9:39 AM Raymond Camden <raymon...@gmail.com> wrote:
Thanks - I noticed some issues with my download support (I'm using similar code in another demo) - will hack at it.




Thomas Steiner

unread,
Sep 10, 2025, 12:50:00 PMSep 10
to Raymond Camden, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Did you compare what you have…

(await Summarizer.create()).inputQuota

…vs. what you got:

await (await Summarizer.create()).measureInputUsage('Your comic book text')

It smells like a quota exceeding issue to me. 


--
You received this message because you are subscribed to the Google Groups "Chrome Built-in AI Early Preview Program Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chrome-ai-dev-previe...@chromium.org.


--
Thomas Steiner, PhD—Developer Relations Engineer (blog.tomayac.comtoot.cafe/@tomayac)

Google Spain, S.L.U.
Torre Picasso, Pl. Pablo Ruiz Picasso, 1, Tetuán, 28020 Madrid, Spain

CIF: B63272603
Inscrita en el Registro Mercantil de Madrid, sección 8, Hoja M­-435397 Tomo 24227 Folio 25

----- BEGIN PGP SIGNATURE -----
Version: GnuPG v2.4.8 (GNU/Linux)

iFy0uwAntT0bE3xtRa5AfeCheCkthAtTh3reSabiGbl0ck
0fjumBl3DCharaCTersAttH3b0ttom.xKcd.cOm/1181.
----- END PGP SIGNATURE -----

Raymond Camden

unread,
Sep 10, 2025, 12:56:03 PMSep 10
to Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
I'll try - but wouldn't that throw an error of some sort?
Twitter: raymondcamden

Thomas Steiner

unread,
Sep 10, 2025, 12:59:41 PMSep 10
to Raymond Camden, Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
On Wed, Sep 10, 2025 at 6:55 PM Raymond Camden <raymon...@gmail.com> wrote:
I'll try - but wouldn't that throw an error of some sort?

It should, yes. Just curious what your measuring experiments reveal. Be sure to measure with the exact type of Summarizer you're creating (my quick and dirty example was just using the defaults). If it turns out that you're sending more than you can, then this is something that should go in a bug report. 

Raymond Camden

unread,
Sep 10, 2025, 1:59:14 PMSep 10
to Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Oh shoot, I am so sorry. I should have been clearer. My process is:

Use the Prompt API to describe each page, store the result
Send those descriptions to the Summarizer API

My issue is in the loop for the first part. If there are similar APIs there, I can try. 

Thomas Steiner

unread,
Sep 10, 2025, 2:01:36 PMSep 10
to Raymond Camden, Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Can you email me the failing comic book so I can try?

Raymond Camden

unread,
Sep 10, 2025, 2:01:54 PMSep 10
to Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Aha, so I added this in my loop:

  console.log(`${session.inputUsage}/${session.inputQuota}`);

And it's going over the max when near where it dies. So - I guess an easy solution would be to kill and recreate the session, but maybe intelligently like when it's about 80% "full".

Raymond Camden

unread,
Sep 10, 2025, 2:08:07 PMSep 10
to Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
My first attempt, which feels kinda lame, didn't work:

console.log(`${session.inputUsage}/${session.inputQuota}`);
if(session.inputUsage/session.inputQuota > .75) {
  console.log('need to nuke the session, getting close to full');
  session = await session.clone();
}

I can see the clone message, but the new session has the same input usage. Is the problem that I'm essentially cloning over an existing variable?

Raymond Camden

unread,
Sep 10, 2025, 2:15:08 PMSep 10
to Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
I think I got it!

I now start with a clone:

async function doAISummary(pages, reader, binreader) {
$aiSummary.innerHTML = "<p>Starting work on AI Summary.</p>";
summaries = [];
let newSession = await session.clone();

and use newSession in my code:

if(newSession.inputUsage/newSession.inputQuota > .75) {

  console.log('need to nuke the session, getting close to full');
  newSession = await session.clone();
}
let response = await newSession.prompt([{

And it can do ALL the pages! Woot!

So Thomas, would the lack of an error by the Prompt API be something I should report?

Thomas Steiner

unread,
Sep 12, 2025, 9:52:10 AMSep 12
to Raymond Camden, Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Thank you, Ray! If you can reproduce it, definitely please file a bug. In my quick testing, it threw immediately: 

const session = await LanguageModel.create();
let prompt = '';
while(await session.measureInputUsage(prompt) < session.inputQuota) {
  prompt += Date.now();
}
await session.prompt(prompt).catch(err => console.error(err));
// QuotaExceededError: The input is too large.

But glad that you've found a solution independent from a potential bug already. Cloning a main session is a best practice recommendation indeed.

Cheers,
Tom

Raymond Camden

unread,
Sep 12, 2025, 9:57:35 AMSep 12
to Thomas Steiner, François Beaufort, Roland Bouman, Chrome Built-in AI Early Preview Program Discussions
Will do later today. Blogging about this Totally Practical and Will Definitely Get Me a Job in AI demo in a few hours.
Reply all
Reply to author
Forward
0 new messages