ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Illustrated, narrated books with a reading buddy ("Page") you can interrupt at any time. It's built for people who find it hard to focus on a page and for second-language readers.
The demo book is chapters 1–2 of Alice's Adventures in Wonderland (public domain, from Project Gutenberg): 28 scenes, about 43 minutes of narration per voice across both versions.
The book is split into two phases:
1. Offline build (scripts/build-book.ts, run once on a laptop). Everything about the book is generated ahead of time and committed under public/books/<id>/:
simple: a Simple-English rewrite, paragraph-for-paragraphsummary: a one-line summaryglossary: 3–6 tricky wordsimagePrompt: a description of one key momentffmpeg.book.json, which embeds the default voice's timings. Each extra voice gets tracks/<voice>.json plus audio/<voice>/*.mp3.2. Runtime (Next.js on Vercel). The page loads static assets. Only the interactive parts call OpenAI, through API routes:
| Route | Purpose |
|---|---|
POST /api/ask | The tutor. It receives the current scene and what was just heard, crossing scene boundaries if needed, plus the story-so-far summaries and recent chat. It returns {reply, action}, where action is one of: resume, reread_sentence, reread_scene, goto_scene, switch_simple, switch_original, stay_paused. One fast gpt-4.1-mini call with a strict JSON schema (see trade-offs). |
GET /api/tts?text&voice | Speaks tutor replies. The <audio> element plays it directly, so the voice starts as soon as the first bytes arrive. POST is also accepted. |
POST /api/transcribe | Push-to-talk audio → text. |
POST /api/define | Tap-a-word definition, example sentence and translation. |
The client player (components/Player.tsx) is a small state machine:
idle → playing ⇄ paused → listening → thinking → speaking → (do the tutor's action) → playing…
Safeguards on the tutor's voice:
All models come from one vendor (OpenAI) and can be changed with environment variables.
| Job | When | Model (default) | Why this model |
|---|---|---|---|
| Scene enrichment: simple rewrite, summary, glossary, image prompt | Build | gpt-4.1-mini (OPENAI_MODEL) | Cheap and fast, strong at following instructions, and supports strict JSON-schema output. Writing at an A2–B1 level doesn't need a frontier model. |
| Illustrations | Build | gpt-image-2 (OPENAI_IMAGE_MODEL, script default gpt-image-1) | Best character consistency and painterly style in our tests. Slow (about 1 min per image), which is fine offline. |
| Narration | Build | gpt-4o-mini-tts, voices fable / coral / ash | Takes style instructions ("warm storyteller, give characters a little voice") and costs far less than premium TTS. |
| Word timing alignment | Build | whisper-1 | The only OpenAI transcription model that returns word-level timestamps. |
| Tutor ("Page") | Runtime | gpt-4.1-mini with chat completions (OPENAI_MODEL) | Low latency matters most: the listener has paused mid-story. Strict JSON output with a fixed action list keeps answers short and on-script. No reasoning model needed for vocabulary and plot questions. |
| Tutor voice | Runtime | gpt-4o-mini-tts, voice chosen by the listener (default coral) | Streams; the first audio arrives in about 1 s. |
| Mic input | Runtime | gpt-4o-mini-transcribe (OPENAI_STT_MODEL) | More accurate than Whisper for short, noisy questions. No timestamps needed. |
| Tap-a-word | Runtime | gpt-4.1-mini | One small JSON call. The result is cached per word and language in the browser. |
These are measured on the demo book (28 scenes, about 4.2k words of original text and 3.4k words of Simple English). Costs are approximate list prices at build time; check OpenAI's pricing page before relying on them.
| Asset | Volume | Wall-clock time | Approx. cost |
|---|---|---|---|
| Scene enrichment (LLM) | 28 calls | about 1 min (sequential) | < $0.10 |
Illustrations (gpt-image-2, 1536×1024, medium) | 28 images (+2 tests) | about 15–20 min (4 at a time, about 1 min each) | about $2–3 |
| Narration, one voice, both versions | about 43 min of audio, 56 files | about 8–10 min | about $0.65 |
Word timings (whisper-1, including retries) | about 43 min per voice | included above | about $0.30 per voice |
| First full build (1 voice) | about 25 min | about $3–4 | |
| Each extra narrator voice | about 46 min of audio | about 10–12 min | about $1–1.5 |
Disk footprint:
Rule of thumb: a full ~300-page novel is about 25× this sample. That's roughly 700 scenes, about $50–75 of images, and about $15–20 of audio per voice. Image generation dominates both time and cost.
| Action | Latency (measured) | Approx. cost |
|---|---|---|
Tutor answer (gpt-4.1-mini) | 1.3–2 s to text | < $0.001 |
| Total time from asking to hearing Page's voice | about 2.4 s | |
| Tutor voice (streamed) | about 1 s to first audio | about $0.001–0.003 |
| Voice question → text | about 0.5–1 s | < $0.001 |
| Tap-a-word definition | about 1 s, then instant from cache | < $0.001 |
Narration playback is free at runtime because it's pre-generated.
app/
page.tsx Landing page
read/[book]/page.tsx Reader page (static, one per book in lib/books.ts)
api/ask/route.ts Tutor: context assembly → LLM → {reply, action}
api/tts/route.ts Streaming TTS (voice allowlist)
api/transcribe/route.ts Mic audio → text
api/define/route.ts Tap-a-word dictionary
layout.tsx, globals.css Fonts (Literata + Atkinson Hyperlegible), theme, pan/zoom + caption animations
components/
Player.tsx State machine: narration, tutor, actions, scene-boundary logic, voices, persistence
Stage.tsx Illustration with Ken Burns pan/zoom, crossfade, chapter title card
Transcript.tsx Karaoke read-along, sentence ▸ markers, Cinema captions (chunked)
TutorPanel.tsx Chat, quick-ask chips, mic + text input, glossary
WordPopover.tsx Definition / translation / "Read from here"
icons.tsx
lib/
book.ts Types + timing helpers (tokenAt, sentenceRange, captionRange, …), voice list
books.ts Book registry (imports book.json)
openai.ts Client + model/voice env defaults
scripts/
build-book.ts Offline generator (text → scenes → images, audio, timings)
public/books/alice/
book.json Scenes, text, glossary, default-voice timings
tracks/<voice>.json Timings for extra narrator voices
img/*.webp Illustrations + thumbnails
audio/[<voice>/]*.mp3 Narration (default voice at top level)
.cache/ Build cache (LLM outputs, raw word timings); git-ignored
The app chains text LLM → image model → TTS → speech-to-text alignment rather than asking one multimodal model to "turn this chapter into an illustrated audiobook".
Why chaining fits:
What chaining costs:
Realtime speech-to-speech models (one model listening and talking) would make Page feel more conversational: barge-in and lower latency. But it's harder to keep a voice model grounded in exact book state and to return structured actions reliably. It's the natural next step for the tutor only (see the roadmap).
gpt-4.1-mini):
needs_research, and play a spoken filler ("Good question, let me check…") while it works.Next.js + Vercel, single app: no separate backend, queue or database. Deploy is git push.
One vendor (OpenAI): one key and one bill, the simplest possible demo. Alternatives may be better per stage:
The model defaults in lib/openai.ts are a single point to change.
Browser state only: reading position, voice and language live in localStorage. There are no accounts, and the chat history is lost on reload.
/api/ask; the voice has watchdogs but the text answer doesn't.The API routes are public and unauthenticated, and they spend money on your OpenAI key.
| Risk | Where | Current mitigation | Next step |
|---|---|---|---|
Cost abuse / denial of wallet. Anyone can script calls to /api/ask, /api/tts, /api/transcribe, /api/define. | All routes | Input length caps (question 1k chars, TTS 1.2k, audio 10 MB, 30 s of recording). A spending limit on the OpenAI dashboard. Each call is cheap (fractions of a cent), but nothing limits how many calls one client can make. | Per-IP and per-session rate limits (e.g. Upstash Ratelimit / Vercel KV), Vercel BotID or Turnstile, auth for heavy features, daily budget caps per user |
| Prompt injection by the listener ("ignore your instructions…", role-play, extracting the system prompt) | /api/ask, /api/define | Structured JSON output with a fixed action enum, so the model can only trigger 7 harmless client actions. sceneIndex is clamped client-side, and replies are rendered as text, not HTML. | Output moderation, keep untrusted input clearly delimited, refuse off-topic requests server-side, log and red-team |
| Adding tools to the tutor later (web search, code execution, agents) | /api/ask | Not applicable today: the tutor has no tools, so injected instructions can only change its words or pick one of the 7 actions | If tools are added: keep public traffic tool-less, or restrict to allowlisted domains with no network/sandbox. Cap tool calls, time and spend per request. Treat web results as untrusted (indirect prompt injection). |
| Indirect injection from book content (once users upload books, the text could contain "SYSTEM: …") | Build-time LLM, tutor context | N/A (the only book is trusted public-domain text) | Treat uploaded text as data: delimit it, strip control-like patterns, never give the build pipeline tools, validate every LLM output against its schema |
| Unsafe or inappropriate generations (images, Simple-English text, tutor answers) | Build + /api/ask | Provider safety filters; the content is a children's classic | Moderation on generated text and images before publishing, human review for public books, age-appropriate system prompts |
| Voice/TTS misuse (making the app speak arbitrary text) | GET /api/tts?text= | Voice allowlist, 1.2k-char cap |
unpdf) as a stretch. Detect chapters and paragraphs deterministically; use an LLM only to clean up odd cases.gpt-image-1-mini or Flux schnell, about 2–5 s) and show the text with a soft placeholder image until the art lands.sentenceRange, captionRange, alignment);npm install
echo 'OPENAI_API_KEY=sk-...' > .env.local
npm run dev # http://localhost:3000
Needs ffmpeg and ffprobe installed locally.
OPENAI_IMAGE_MODEL=gpt-image-2 npm run build:book # CHAPTERS=2 by default, + EXTRA_VOICES=coral,ash
CHAPTERS=1 MAX_SCENES=2 EXTRA_VOICES= npm run build:book # quick test
DRY=1 npm run build:book # just print the scene split
Every generated file is reused on re-runs. Delete a file in public/books/alice/ or .cache/alice/ to regenerate it.
OPENAI_API_KEY.| Variable | Default | Used by |
|---|---|---|
OPENAI_API_KEY | (required) | everything |
OPENAI_MODEL | gpt-4.1-mini | book build, /api/ask, /api/define |
OPENAI_TTS_MODEL | gpt-4o-mini-tts | build narration, /api/tts |
OPENAI_TUTOR_VOICE | coral | /api/tts fallback voice |
OPENAI_STT_MODEL | gpt-4o-mini-transcribe | /api/transcribe |
OPENAI_IMAGE_MODEL | gpt-image-1 | build (we used gpt-image-2) |
OPENAI_VOICE / EXTRA_VOICES | fable / coral,ash | build: default and extra narrator voices |
Only speak text the tutor produced: sign/HMAC the reply ID from /api/ask, or return audio from /api/ask itself |
| Secrets | OPENAI_API_KEY | Server-side only; .env* is git-ignored | Use project-scoped keys with only the needed model permissions, rotate them, and use separate keys per environment |
| Copyright | Uploaded books | Demo uses public-domain text | Restrict uploads to public-domain or user-owned content, keep each user's uploads private, add terms of use and a takedown process |