Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Voice-first expense capture for India. Say what you spent; a journal keeps the record honest and correctable.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Say what you spent. Check it. Done.
Voice-first expense capture. You speak an expense the way you'd text it to yourself — "250 lunch" — and it becomes a structured transaction, with every field showing whether it was heard, worked out, filled from a default, or left blank because it's genuinely unknown. A confident capture saves itself, with an Undo that's there for exactly as long as it takes you to notice something's wrong; anything less certain stops on a review card first.
Start with CONTEXT.md — the whole product, architecture and
current state in one file. Product thinking lives in
PRD-VaaniTrack.md, evidence in
RESEARCH.md, what the project runs on in
TechStack.md, and the build log in
EXECUTION.md.
npm install
Copy .env.local.example to .env.local and add a Groq
API key (free at console.groq.com):
GROQ_API_KEY=gsk_...
One key covers both stages — whisper-large-v3 for transcription, and
openai/gpt-oss-120b for turning the transcript into a transaction. That is
the only variable capture needs.
The rest of .env.local.example configures the observability layer and the
diagnostic portal. Leave them unset and the app behaves identically — capture
just runs unobserved, and /portal denies everyone. To turn them on you need a
Supabase project with the SQL in supabase/ applied in order
(schema.sql, then 002, 003, 004) and a captures storage bucket:
DATABASE_URL= # Supavisor TRANSACTION pooler, not the direct host
NEXT_PUBLIC_SUPABASE_URL=
SUPABASE_SECRET_KEY= # sb_secret_... — server only, bypasses RLS
PORTAL_PASSWORD= # unset means /portal denies everyone
SAVE_CAPTURES=1 # local .captures/ files; off unless set, and
# structurally off in production regardless
npm run dev
Open http://localhost:3000. The microphone works here because browsers
treat localhost as a secure origin.
npm run dev:tunnel
It prints a QR code — point your phone camera at it — plus the URL, and
writes the same code to phone-link.png in case your terminal mangles the
block characters.
────────────────────────────────────────────────────
Point your phone camera at this:
[ QR code ]
...or open: https://something-random.trycloudflare.com
...or open phone-link.png in this folder and scan it.
────────────────────────────────────────────────────
On the phone: tap Say what you spent, allow the microphone when asked, speak, tap again to finish. A line under the button reports what was captured and heard, so a failure says where it broke.
The phone does not need to be on the same Wi-Fi. Mobile data is fine.
The URL is public while the tunnel runs. It's random and unlisted, and it dies when you stop the process — but anyone who has it can reach your app and spend your Groq quota. Don't post it anywhere.
The microphone is the whole product, and browsers only expose getUserMedia in
a secure context — HTTPS with a certificate the browser trusts, or
localhost.
Serving HTTPS from your laptop with a self-signed certificate is not enough. Chrome does not treat an origin with a failed certificate as secure even after you tap through the warning. You get the page; you never get the microphone. That is the wall you hit if the page loads on your phone but the mic refuses to open.
The tunnel avoids it entirely: your phone talks to Cloudflare over a certificate it already trusts, and Cloudflare forwards to your machine. No certificate to install, no interstitial, no firewall rules.
npm run dev:phone
Issues a certificate for your current LAN IP and prints https://192.168.1.12:3000.
Keeps everything on your own network — but you'll hit the Chrome problem above
unless you install the mkcert root CA on the phone
(C:\Users\<you>\AppData\Local\mkcert\rootCA.pem). Use the tunnel unless you
specifically need to stay off the internet.
Two things that bite on this path:
npm run dev | http on localhost. Fine on this machine; mic won't work from a phone. |
npm run dev:tunnel | Public URL with a trusted certificate. Use this for phone testing. |
npm run dev:phone | https with a certificate for your LAN IP. Stays off the internet, but see the Chrome caveat above. |
npm run dev:https | https via Next's own cert (localhost only). Fallback. |
npm run build | Production build |
node --experimental-strip-types scripts/journal.test.ts | The data-layer test suite. No framework, no build step. |
node --env-file=.env.local --experimental-strip-types scripts/observe.smoke.ts | Writes one full pipeline's worth of rows to Supabase, reads them back, deletes them. |
start-vaanitrack.bat | Windows one-click: clears stale processes, checks deps and the key, builds, tunnels. |
speak
│
▼
level meter is there actually sound in this? (dBFS)
│ a take under −55 dBFS is refused on the device
▼
whisper-large-v3 audio → text
│ stock hallucinations rejected by denylist
▼
gpt-oss-120b text → transaction + provenance
│ (never invents; leaves blanks blank)
▼
confidence gate four conditions; all must hold to save silently
│ ┌───────────────────┴───────────────────┐
│ ▼ ▼
│ all four hold any condition fails
│ auto-saved, with Undo review card — you check it,
│ then Save
▼ │
journal ◄──────────────────────────────────────────────────┘
localStorage, mirrored to Postgres if configured
Every stage above writes a row describing what it did, so a wrong expense can
be traced to the stage that produced it rather than guessed at. /portal is
where that is read back.
Why the review step exists: currency amounts are the single worst thing
speech recognition does — 36.3% accuracy at baseline, the lowest of any numeric
category measured. The amount is also the one field that must never be wrong.
Showing every transaction before it commits is what makes that survivable.
See RESEARCH.md §1.1.
Provenance. Every field records where its value came from — said, inferred, default, or unknown. Values the system worked out rather than heard are marked with a dotted underline on the review card. A missing category stays blank rather than being guessed.
| Route | What it is |
|---|---|
/ | The public landing page. No capture, no overlays. |
/app | Capture. Today's transactions only. The PWA's install target. |
/journal | The record — all populated days, month subtotals, edit and delete. |
/signin, /signup | Stubbed auth screens. The account is a UI concept only — nothing syncs yet, and these never touch the anonymous device id capture relies on. |
/portal | Diagnostic portal. Every capture, its pipeline stages, and a heuristic naming the likely point of failure. Password-gated; denies everyone when PORTAL_PASSWORD is unset. |
/diag | General diagnostics. |
/diag/mic | Microphone signal test. Runs the same utterance through three getUserMedia configurations and prints the dBFS that actually arrived. Built because Android routes capture through the platform voice path on some handsets, and whether that path works is a property of the handset. |
This is a two-day demo, deliberately scoped.
/signin and /signup are real
screens, but the session is a UI concept only. localStorage on the device
that recorded it is still the working copy. When Supabase is configured,
transactions also mirror to Postgres keyed by an anonymous per-browser
device id — that is durability, not sync: a second device is a different id
and sees nothing. Clearing site data still resets the id and orphans the
mirrored rows./diag/mic.