Lexiverse
Lexiverse - AI contextual reading engine for English learners. Your next article is your next review.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Find out how cooked you are before placements cook you.
Upload a resume PDF (or paste the text) and get a Cooked Score (0–100, higher = more cooked), a roast, real strengths and weaknesses, a 4-week survival plan and an Instagram-story share card.
kooked/
├── server/ Express 5 API (Node 20+, ESM): parsing, PII stripping, scoring, Gemini
└── client/ Vite + React + Tailwind v4 single page
The AI never decides the score. POST /api/roast runs these steps:
pdf-parse) or from the pasted JSON { text }. Input under 40 chars gets a friendly 400.cached: true with no AI call.<resume> tags and treated as data, which defends against prompt injection.
If it isn't a resume, there's no score: a separate AI call roasts the upload itself using only the short document label ("electricity bill") and first name, and the API returns { notResume: true, documentType, roast, shareLine }.server/src/lib/score.js computes the score with fixed rules and returns the reasons shown in the UI.server/src/ai/variety.js), uses the first name and 10th/12th marks as material, and always finds something to roast. Jokes stay in the roast; strengths, weaknesses and the plan stay factual.Each result also gets one animated reaction sticker from Noto Emoji (Google, CC BY 4.0), picked from client/src/reactions.js and avoiding the ones that browser saw recently.
Scoring rules (base 10, clamped to 3–98):
| Signal | Points |
|---|---|
| 0 internships / 1 internship | +20 / +6 |
| no projects / all basic / only 1 non-basic | +25 / +18 / +8 |
| CGPA missing / <6 / <7 / <8 | +4 / +15 / +10 / +4 |
| fewer than 4 skills | +8 |
| no DSA / CP | +6 |
| no GitHub and no portfolio | +8 |
| no achievements | +8 |
Requires Node 20+.
# terminal 1
cd server
cp .env.example .env # leave GEMINI_API_KEY empty for mock mode
npm install
npm run dev # http://localhost:3001; logs "(MOCK AI)" without a key
# terminal 2
cd client
cp .env.example .env # VITE_API_URL=http://localhost:3001
npm install
npm run dev # http://localhost:5173
Run the server tests with cd server && npm test. They cover scoring, stripPII, the API flow, and a check that nothing PII-like is sent to Gemini.
Sample resumes live in server/samples/: weak.* scores 88 and strong.* scores 16. Regenerate the PDFs with npm run samples.
curl -F resume=@server/samples/weak.pdf http://localhost:3001/api/roast
curl -H 'content-type: application/json' -d '{"text":"..."}' http://localhost:3001/api/roast
curl http://localhost:3001/api/health # { ok, mock }
curl http://localhost:3001/api/stats # { totalRoasts }
If GEMINI_API_KEY is empty or MOCK_AI=true, the server uses a regex extractor and a template roast (server/src/ai/mock.js). The whole app works offline. The scoring rules are the same in mock mode because they never depended on the AI. Only the facts come from the regex extractor instead of Gemini.
server/.env as GEMINI_API_KEY=..., and remove MOCK_AI=true if it's set.GEMINI_MODEL (default gemini-3.5-flash).(MOCK AI).If an AI call fails or returns malformed JSON, the server retries once. If the retry also fails, the API returns 502 "The oven exploded. Try again."
| Server | Default | |
|---|---|---|
GEMINI_API_KEY | – | empty = mock mode |
GEMINI_MODEL | gemini-3.5-flash | |
PORT | 3001 | |
CLIENT_ORIGIN | http://localhost:5173 | CORS allow-list (comma-separated) |
RATE_LIMIT_PER_HOUR | 10 | per IP, /api/roast only |
MOCK_AI | – | true forces mock mode |
| Client | |
|---|---|
VITE_API_URL | API base URL |
VITE_SITE_URL | watermark on the share card (defaults to the current host) |
Server → Render (Blueprint)
render.yaml sets up the kooked-api web service (root server, free plan, Singapore).CLIENT_ORIGIN=https://<your-vercel-domain>. Leave GEMINI_API_KEY empty to launch in mock mode; add it later under the service's Environment tab and the service restarts using Gemini.trust proxy is already set, so rate limiting sees real client IPs behind Render's proxy./api/stats on page load, which starts the wake-up while the visitor picks a file.Client → Vercel
client. Framework preset Vite (build npm run build, output dist).VITE_API_URL=https://<your-render-service>.onrender.com, VITE_SITE_URL=<your-domain>.Cost safety: in Google AI Studio or Google Cloud billing, set a budget alert and a spending cap on the project that owns the key. Each uncached roast is two small Gemini calls. The per-IP rate limit and the cache keep abuse in check.
server/src/lib/cache.js and server/src/lib/stats.js expose small async interfaces (get/set and increment/get). You can replace them with MongoDB-backed versions without touching the route.