ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Speak with Impact.
A speaking practice partner. Record yourself answering an interview question, running a pitch, or rehearsing a speech — get specific, coach-style feedback on pace, filler words, pauses, clarity, and impact.README 전문 보기 ↗Speak with Impact.
A speaking practice partner. Record yourself answering an interview question, running a pitch, or rehearsing a speech — get specific, coach-style feedback on pace, filler words, pauses, clarity, and impact.
/) → sign up / log in (/signup, /login) → setup (/dashboard) → recording (live waveform via Web Audio) → feedback report → progress dashboard./dashboard, /practice, /progress, /report) require an account when Firebase is configured.users/{uid}/sessions. Falls back to localStorage (and skips the auth gate) when Firebase env vars are absent.app/api/analyze/route.ts (runs on Vercel, keys server-side): AssemblyAI transcription (word timestamps, disfluencies) → pace/filler/pause metrics → Gemini writes the coaching report as structured JSON (lib/gemini.ts). Falls back to a labeled sample analysis when keys are absent or the pipeline fails.npm install
npm run dev
The app works with zero configuration (localStorage + sample feedback). To enable the real backend:
firestore.rules and publish. (Or firebase deploy --only firestore:rules with the Firebase CLI.)cp .env.local.example .env.local and fill in the NEXT_PUBLIC_FIREBASE_* values.ASSEMBLYAI_API_KEY — assemblyai.com (free tier includes $50 credit, no card).GEMINI_API_KEY — aistudio.google.com → Get API key.FISH_AUDIO_API_KEY — fish.audio → API keys. Felix's voice: the "Hear Felix's feedback" button on every report and the landing page's sample. The free developer tier is enough. Optional: without it the button says so quietly and the written take stays. Pick a voice from the fish.audio library and put its id in FISH_AUDIO_VOICE_ID, then run npm run felix:voice once to write public/felix-hello.mp3, the landing page's sample, and commit it.AI_DAILY_CEILING_USD caps what all three of those can spend in a day, across every account. It is optional and defaults to $500/day — see Global spend ceiling.
Add them to .env.local. Restart the dev server after env changes.
Every report opens with Felix's take: thirty to sixty words on how the speaker came across, the one thing that worked, the one thing to fix, and what to do next, coached toward the goal they picked. The pieces:
lib/felixTake.ts — the prompt, the goal focus, the word cap, and the deterministic fallback built from the report when the model can't answer.POST /api/felix — writes the take with Gemini from the server's copy of the session (the client only sends a session id) and merges it onto the session doc as felix, so every later open reads it back for free. A fallback take is never stored.POST /api/voice — with { sessionId }, reads that stored take, synthesizes it with Fish Audio, and caches the MP3 on the session's felix/voice subdocument (server-only; no client rule reaches it). Replays cost a Firestore read, never a second synthesis.components/FelixCoach.tsx — the module (web and app variants), with play / pause / replay, the progress hairline, and the felix_feedback_* events on the existing cookieless analytics.Nothing plays until it is pressed, and the take is always on screen as text.
The client code is already wired (lib/appCheck.ts) and stays
inert until NEXT_PUBLIC_RECAPTCHA_SITE_KEY is set. Without it, a signed-in user
can talk to Firestore directly with their own token and skip every rate limit in
lib/verify.ts, which only guard the API routes.
App Check is enforced in two places, set up independently: on Firestore
(the console Enforce button, steps below) and on the paid API routes
/api/analyze + /api/speech (the client sends an X-Firebase-AppCheck header;
the server verifies it in lib/verify.ts, gated by
APPCHECK_ENFORCE, step 5). The API half matters because a valid ID token proves
who is calling but not that the call came from our client — without it a script
can drive paid AssemblyAI/Gemini spend from curl, up to the per-day quota.
elovox.app → copy both keys. Both get used, in different
places: the site key is public and ships in the bundle, the secret key stays
with Firebase.ReCaptchaEnterpriseProvider in lib/appCheck.ts.NEXT_PUBLIC_RECAPTCHA_SITE_KEY in Vercel and redeploy —
NEXT_PUBLIC_* bakes in at build time./api/analyze and /api/speech,
and the server verifies it — but only logs failures until you opt in, so
nothing breaks during rollout. Watch the server logs for
[app-check] unattested …; once they fall to ~zero (every live bundle is
sending the header), set APPCHECK_ENFORCE=true in Vercel and redeploy
to start returning 403 for unattested calls. Same ship-then-enforce order
as Firestore, and for the same reason: flipping it early would 403 real users
still on a bundle from before the header existed.For local development, set NEXT_PUBLIC_APPCHECK_DEBUG=true, copy the token the
SDK prints to the console, and register it under App Check → Apps → ⋯ → Manage
debug tokens. Never set that variable in production — a registered debug token
bypasses attestation for every visitor. A production build now ignores it and
logs an error if it's set, but keep it out of the production environment anyway.
.env.local in Vercel → Project → Settings → Environment Variables.*.vercel.app domain (and any custom domain).The /api/analyze route sets maxDuration = 120 for transcription polling; on the Vercel Hobby plan enable Fluid Compute (default on new projects) so the function isn't cut off early.
Freemium, enforced server-side — the browser decides what to draw, never what the server will do.
users/{uid}/usage/{date} and is written solely through the Admin SDK; firestore.rules denies every client write to it, so it can't be forged. See lib/quota.ts.MAX_DAILY_ATTEMPTS — one shared topic, so the scores are only comparable if everyone gets the same number of goes), and a fair-use ceiling of 120 analyses a day guards the paid transcription pipeline (PREMIUM_ANALYSES_PER_DAY in app/api/analyze/route.ts). Entitlement is a single bit at users/{uid}/profile/plan, written only by the Stripe webhook (app/api/stripe/webhook/route.ts) and read-only to the user.Every paid route re-checks entitlement server-side via isPremiumServer in lib/verify.ts. Billing cycles and trial lengths come from lib/pricing.ts, not from the Stripe dashboard.
AI_DAILY_CEILING_USD)The per-user and per-IP limits above bound one account and one address. AI_DAILY_CEILING_USD bounds the total: a cap, in whole US dollars of estimated upstream spend per UTC day, across every paid AI call the app makes (/api/analyze, /api/speech, /api/felix). Without it, a set of accounts each politely inside its own limit could run up a bill many times the day's revenue with every limiter reporting green.
lib/opsMetrics.ts are constants rounded 3-5x above real provider pricing, because a breaker that needs an accurate bill to fire is a breaker that never fires, and over-estimating trips it early.billingAlerts row that shows up in the admin Billing queue and the daily operator email, while nothing is being refused yet. That is the signal to raise the ceiling as real traffic grows, before anyone is turned away.503, retryable, the recording is kept), Felix falls back to a take written from the report. The answers never mention money and never distinguish the ceiling from the operator's pauseAnalyze switch.aiCostCents and the per-route call counts) are on /admin → Ops, so a page at 75% can be read as a trend before deciding whether to raise the number or go find the accounts.All rights reserved. Elovox is a commercial product; the source is published to be read, not reused. See LICENSE.
Live at elovox.app.