[recipes] Google Activity import: include Gemini answers from safeHtmlItem#455
[recipes] Google Activity import: include Gemini answers from safeHtmlItem#455araece wants to merge 1 commit into
Conversation
OB1 PR Gate✅ Folder structure — All files are in allowed directories Result: All 15 checks passed! Ready for human review. Post-Merge TasksThese don't block merge — they're reminders for admins after this PR lands.
|
6c5b5d6 to
4a70aea
Compare
Gemini Apps Takeout records are widely believed to contain only the
user prompts, and the importer read only `title`/`time` accordingly.
That is no longer true: most prompt records carry Gemini's answer as
HTML in a top-level `safeHtmlItem` field ([{"html": "<p>..."}]) -
verified against a real July 2026 export, where 1,161 of 1,640 records
included it (median ~420 chars, p90 ~3.7k).
Changes:
- extractGeminiAnswer() + dependency-free htmlToText(): strip the
safeHtmlItem HTML to plain text (tags removed, entities decoded,
list items kept), capped at 1,000 chars per answer
- groupByDay() appends "Gemini's answer: ..." beneath the prompt
title; records without safeHtmlItem (all other categories, and the
~30% of Gemini records lacking it) behave exactly as before
- summarization prompt: instructs the model to use answers for what
was learned/decided, but to attribute answer-only facts as
AI-generated rather than established truth
- transcript cap raised 6k -> 12k chars for Gemini Apps only (answers
need the room; ~$0.0005/day at gpt-4o-mini rates), other categories
unchanged
- README: document the safeHtmlItem discovery
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4a70aea to
b9a1b11
Compare
[recipes] Google Activity import: include Gemini's answers from
safeHtmlItemWhat
The Google Activity importer currently reads only
titleandtimefrom Takeout'sMyActivity.jsonrecords — which for Gemini Apps means it imports what the user asked,but never what Gemini answered.
It turns out the answers ARE in the export: most Gemini prompt records carry the response
as HTML in a top-level
safeHtmlItemfield:{ "title": "Prompted How does polarization work in sunglasses?", "time": "2026-03-02T09:15:00.000Z", "safeHtmlItem": [{ "html": "<p>Polarized lenses contain a <strong>filter</strong> ..." }] }Verified against a real export (July 2026): 1,161 of 1,640 Gemini records included it
(median ~420 chars, p90 ~3.7k, max ~86k). The widespread "Takeout exports prompts only"
belief appears to be outdated.
Changes
extractGeminiAnswer()+ dependency-freehtmlToText()— strips thesafeHtmlItemHTML to plain text (tags removed, entities decoded,
<li>→-bullets), capped at1,000 chars per answer.
groupByDay()appendsGemini's answer: …beneath the prompt title. Records withoutsafeHtmlItem— all other categories, and the ~30% of Gemini records lacking it — behaveexactly as before (the helper is a no-op for them).
what was learned/decided, but to attribute facts that appear only in an answer as
AI-generated ("Gemini answered/suggested …") rather than established truth.
Gemini Appsonly, so answers survive thetruncation (~3.4k tokens ≈ $0.0005/day at gpt-4o-mini rates). Other categories keep 6k.
Why it matters
Day summaries built from prompts alone can only say what the user was asking about.
With the answers included, they can capture what the user actually found out — which is
the part worth remembering in a personal knowledge base.
Requirements
Unchanged from the existing recipe: a working Open Brain setup, an OpenRouter API key,
Node.js 18+. No new services, dependencies, or secrets (
metadata.jsonbumped to 1.1.0,geminitag and description updated).Testing
Tested against my own Open Brain instance:
node --checkpasses.--dry-run --raw --verbose --categories "Gemini Apps") against syntheticrecords: answer extracted and appended, HTML/entities cleaned, answerless record
untouched, other categories unaffected.
1,640-record export.
Not in scope (possible follow-up)
Localized exports use different filenames/prefixes (German:
MeineAktivitäten.json,titles starting
Eingegebener Prompt:), whichfindMyActivityFiles()/the filters don'tmatch — non-English Takeout exports are currently invisible to this recipe. Happy to send
that separately if there's interest.
🤖 Generated with Claude Code