Bidet AI — cloud variant vs local, side-by-side
G16 Claude review of Apex Claude Code's build report. Code verified against the report, compared to the personal local Bidet shipped today (GPU-mode + format-reorder), three concrete cross-pollination ideas at the bottom.
1. Verification — does the report match the code?
| Report claim | Code reality | |
|---|---|---|
"processor.py is now just CLEAN_PROMPT, everything else in the browser" | Confirmed. processor.py is 985 bytes; only clean_transcript() remains. AI / Business / Classroom tab prompts are seeded into IndexedDB on first page load. | ✓ |
"transcriber.py calls Groq API with OpenAI fallback" | Confirmed. Provider selection logic respects user-supplied keys first, falls back to env keys for dev only. | ✓ |
"llm.py is a BYOK adapter — Gemini / OpenAI / Anthropic" | Confirmed. generate() reads user_keys dict per-request, falls back to env. Gemini takes precedence, then OpenAI, then Anthropic. | ✓ |
| "Personal SPEAKER_CONTEXT scrubbed" | Confirmed. CLEAN_PROMPT no longer mentions Mark / Apex / TP3 / OMI / Jules / Cursor / Antigravity / colleague names. Generic now. | ✓ |
"Two stateless endpoints: /transcribe + /run-tab" | Confirmed in web/backend/main.py. Multipart audio + keys for transcribe, JSON body for run-tab. | ✓ |
"PWA + embeddable widget at /widget.js" | Confirmed. web/static/widget.js exists, data-groq-key + data-gemini-key attributes wire it up. | ✓ |
One thing the report glossed: there's no rate limit on either endpoint. Stateless + free-tier hosting + no auth means anyone with the URL can hit /run-tab with their own keys. That's fine — costs go to their key. But if someone proxies your endpoint and burns Groq credits via a stolen key, your hosting could rate-limit on Cloud Run free tier. Not blocking; flag for post-launch.
2. The two products, side-by-side
| Local — yours | Cloud — public | |
|---|---|---|
| Audience | Mark only — private, personal | Anyone who knows the URL — public, multi-user |
| Live at | bidetai.thebarnetts.info (Apex port 8955, Cloudflare tunnel) | bidetai.app (Cloudflare Pages frontend + Google Cloud Run backend, both free-tier targets, not yet deployed) |
| Repo | C:\Users\Breezy\honest-answers (private, on Apex) | github.com/MrB-Ed/bidetai-app (private GitHub repo) |
| Transcription | faster-whisper on Apex GPU (CUDA + float16). Free, offline, ~5-10× faster than CPU. Shipped today. | Groq Whisper API (BYOK). $-per-minute, cloud-only, even faster end-to-end (Groq's LPU is sub-second on most clips). |
| LLM | gemma3:4b local Ollama (Apex). Free, private, offline. Tier-2 gemma3:12b queued for evaluation. | BYOK — user picks Gemini / OpenAI / Anthropic. Costs land on user's key. Defaults to Gemini. |
| State | Apex filesystem dumps + TP3 Postgres ingest pipeline. Sessions persist across devices via TP3. | Browser IndexedDB only. No accounts, no server DB. Per-browser history; no cross-device sync. |
| Tabs | 3 fixed: clean / analysis / forai. Hardcoded in processor.py. | 2 always-on (Raw, Clean) + N user-defined. 3 default seed tabs (AI, Business Notes, Classroom Notes), all editable / deletable / replaceable. |
| For-AI format | Today's reorder: raw transcript at TOP wrapped in <transcript> + metadata header, then Decisions / Priority Signals / Open Questions / Action Items. | Same finding, slightly evolved: ## Brief anchor at top (one-line summary) + <transcript> block + four structured sections + ## How to use this footer that owns the recency slot. Cites Lost-in-the-Middle (Liu 2024) + Context Rot (Chroma 2025). |
| Auth | Server-side HTTP Basic via Cloudflare tunnel. PIN-protected widget on legacy.thebarnetts.info. | None. Friends bookmark URL, paste keys once into Settings, that's it. |
| TP3 ingest | Yes. Every clean + analysis lands in Postgres for Oracle context. | No. By design — multi-user app can't share data with one person's TP3. |
| Embeddable widget | Yes — widget on legacy.thebarnetts.info, gated by PIN. | Yes — /widget.js drop-in, gated by client-side key attributes. Simpler. |
| Speaker context | Built-in: Mark / Omi / Apex / TP3 / Jules / colleague names corrected automatically. | Stripped. Generic prompt. |
| Recording resilience | None of the cloud's resilience features (Wake Lock, IndexedDB pending-upload). Recording dies if browser tab backgrounds. | Wake Lock acquired on record start. Failed uploads cached in IndexedDB and re-offered on next page load. |
| Tier-1 fabrication patches (post-hoc quote verifier, short-input bypass, removed seed phrases) | Shipped 2026-04-26 AM in processor.py. Survives because the local pipeline still has structured prompts in Python. | Not present in cloud — cloud's tabs are user-supplied prompts; user owns the format. Trade-off: cloud's outputs are more flexible but less guarded against gemma-style hallucinations on weak models. |
3. The two pivots Apex Claude Code made — verdict
Pivot 1: Dropped chunked MediaRecorder rotation → single recorder + Wake Lock + IndexedDB
Correct call. The chunking gotcha is real (only chunk 0 has the WebM header; rotation produces unjoinable fragments) and the failure mode they hit on backgrounded tabs is documented in MDN. Wake Lock is the right primary defense; IndexedDB-on-failure is the right secondary defense. Local Bidet doesn't have this resilience — recording can die mid-dump if your browser tab loses focus. Worth borrowing.
Pivot 2: Dropped Supabase → browser-only IndexedDB
Correct call. Supabase's value (auth + RLS-gated rows) is wasted on BYOK. Why hold encrypted user keys server-side when the user can paste them into IndexedDB in 10 seconds? The browser-only architecture also makes the legal / privacy story trivial: there's no data on your server because there's no data on your server. Three PRs collapsed into one — that's a real time win, not a corner cut.
4. Three specific cross-pollination ideas (ranked by effort/value)
Borrow #1 (high value, low effort) Anchor-footer prompt pattern → backport to local processor.py
The cloud's AI tab format adds two things my local reorder didn't:
## Briefat the very top — one sentence summarizing what the dump is about. Acts as a "stop here if that's all you need" anchor.## How to use thisat the very bottom — explicit footer telling the receiving AI how to interpret the structured sections. Owns the recency slot, which transformer attention weights heavily.
Both are research-backed (Anthropic / OpenAI / Google all agree per the cloud's research subagent). My local format has the right top-anchor (raw transcript) but not the bottom-anchor. I'd estimate 5-10% follow-up accuracy improvement on long dumps. Recommended: backport to /home/g16/projects/honest-answers/processor.py on Apex (or C:\Users\Breezy\honest-answers\processor.py). 30-minute change, includes a rebuild of the local container.
Borrow #2 (medium value, medium effort) Wake Lock + IndexedDB pending-upload resilience → backport to local frontend
Local Bidet's recording widget on legacy.thebarnetts.info has no Wake Lock and no failed-upload retry. If your phone screen dims mid-dump, the recorder may quietly stop. If the upload to Apex fails (Tailscale dropped, Cloudflare tunnel hiccup), the audio is lost. Cloud version has both. Recommended: port the recorder.js logic from web/static/recorder.js in cloud → over to the local widget. ~1-2 hour port, mostly copy-paste with auth-shim adjustments.
Borrow #3 (high value, higher effort) User-defined tabs → make local Bidet's tabs configurable
Cloud lets users define their own tabs with their own prompts (e.g., "Legacy Soil action items," "Personal," "Class prep notes"). Local Bidet has 3 fixed tabs that you configured for yourself months ago. Why this matters: when you're brain-dumping about Legacy Soil v3 vs. about a Brian Daly contract conversation vs. about a class lesson plan, the optimal output structure is different. A configurable-tabs version of local would let you pick "Legacy Soil tab" or "Contract notes tab" before recording. Estimated: 3-4 hour project. Lower priority than #1 and #2 — but interesting next step if local Bidet becomes your daily driver.
5. What I would NOT borrow from cloud → local
- BYOK transcription / LLM. Local has gemma3:4b free + faster-whisper free, both private. Switching to BYOK Groq + Gemini = paying for what's already free + losing privacy. Wrong direction for personal use.
- Removing speaker context. Local's SPEAKER_CONTEXT (your name, projects, colleagues) is genuinely valuable for transcription accuracy on Mark-specific terms ("Omi," "Apex," "TP3," "Jules"). Cloud has to drop it because cloud is multi-user. Local should keep it.
- Browser-only state. Local Bidet's TP3 ingest pipeline is what makes Oracle work. Browser-only would kill that. Local must keep server-side state.
- No auth. Local lives at a public URL (legacy.thebarnetts.info) and contains private brain dumps. PIN gate stays.
6. What's left on the cloud variant before public launch
| # | Item | Effort | Blocker? |
|---|---|---|---|
| 1 | Manual browser smoke test (Settings modal, tabs editor, History reload) | 5 min | Yes — you should see it work end-to-end before deploying |
| 2 | Deploy frontend to Cloudflare Pages + backend to Google Cloud Run | 30 min if scripted, 1-2 hrs ad hoc | Yes for public launch; not blocking for friend-of-friend testing |
| 3 | Optional PR 3: hybrid free tier with $1/day global cap | 2-3 hrs | No — defer until friends without keys ask for it |
| 4 | Drag-to-reorder on tabs editor | 30 min | No — pure polish |
| 5 | Rate limiting on /run-tab for abuse protection | 1 hr | No, but worth before public-public launch |
7. Honest opinion
The work is solid. Apex Claude Code wrote a report that matches the code, made two good architectural pivots in real time, scrubbed personal context cleanly, set up Cloudflare email routing as a nice touch, and shipped a research-backed AI tab format that's actually a step ahead of what local has.
The cost transparency in the report is also good — Apex CC was honest that Cursor burned ~2 hours in a hung dispatch loop, and that PR 2 ended up being self-coded by Architect (Claude Opus) after Cursor's harness kept failing on automation issues. That kind of "what the receipts actually say" framing is healthy.
What I'd do tomorrow morning if I were you:
- Read Apex CC's build report first.
- Run the local smoke test (5 min):
cd C:\Users\Breezy\bidetai-app; uvicorn web.backend.main:app --port 8957 --reload, hitlocalhost:8957, paste keys, record 30 seconds, verify all 3 default tabs render. - If it works, backport the anchor-footer pattern (Borrow #1 above) to your local
processor.py. That's the single biggest value you can extract from this work back into your daily-driver. - Defer deploy decision until you've slept on it. Cloudflare Pages + Cloud Run free tier means there's no urgency cost.
G16 Claude review · 2026-04-27 · cross-references Apex Claude Code's 2026-04-26 build report. Code spot-checked at processor.py, transcriber.py, llm.py; full repo at github.com/MrB-Ed/bidetai-app.