new-term-radar
신규 AI 용어를 매일 추적, X·Hugging Face·GitHub 등에서 모델·제품·레포 이름을 빠르게 수집
Groville는 소규모 사업을 위한 AI 성장 에이전트로 사이트와 검색콘솔을 분석해 놓친 고객을 찾아 캠페인을 초안합니다
Groville is the AI growth agent for small business. It reads your site and Google Search Console, finds the customers you're missing, and drafts the campaign to win them. You approve every move.
마케팅HTML · TypeScriptGitHub @alphabassgui온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기BUILDING A UNIQUE SOLUTION TO A PROBLEM - shipping mvp
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗An AI growth agent for Nigerian SMEs. Groville reads a business's website (and Google Search Console), finds the single biggest customer/search gap, drafts the campaign to fix it, and — once the owner approves — runs it and measures what it earned.
Built by The ALPHAs for the NACOS National BuildX hackathon.
The one rule that defines the product (the "honesty boundary"): Groville only ever drafts. The owner reviews and approves. Nothing is ever published or sent automatically, and the Results screen only ever reports what was actually measured — never an invented number.
This is the combined (monorepo) for the whole app — both halves live here:
fullnacos_/
├── frontend/ # The dashboard the business owner uses (Next.js)
└── backend/ # The "brain": API + background workers (Flask)
Note on naming: some backend files/README say "Blom" — that's an older name. The product is Groville. Same app.
Sign up → Onboarding (add your website) → Groville ANALYSES the site
→ OPPORTUNITIES (the biggest gaps, ranked)
→ CAMPAIGN DRAFT (Groville writes the fix)
→ You REVIEW & APPROVE
→ Groville EXECUTES the approved action
→ RESULTS (what it earned) + what it learned
Under the hood:
[ Browser ] --cookie auth--> [ Frontend: Next.js :3000 ]
| (fetch, credentials: 'include')
v
[ Backend: Flask :5000 ]
/ | \
Firestore Redis + Celery Groq LLM
(database) (async jobs: (text drafts +
analyze / vision scoring)
execute /
GTM run)
|
Playwright Chromium
(PixelRAG: screenshots
→ WebP tiles for GTM)
Alongside the main loop, GTM / PixelRAG (section 5) runs as its own on-demand async job: it screenshots your site + competitors, scores your go-to-market, and drafts a recommendation — and the gaps it finds feed straight back into your Opportunities board.
Frontend — Next.js 16 (App Router) · TypeScript · Tailwind CSS · shadcn/ui · Framer Motion
Backend — Flask · Firebase / Firestore (database) · Redis + Celery (background jobs) · Groq (LLM)
Visual GTM (PixelRAG) — headless Playwright Chromium (full-page screenshots + vertical tiling → WebP) · Groq Vision LLM (multimodal scoring of your site vs competitors)
Auth — Flask session cookie (the frontend calls the API with credentials: 'include')
The full demo loop runs end to end on real data:
What is simulated (by design, and it's honest about it):
Most action executions run in dry-run mode — they do not make a real external change. A completed execution writes one honest signal (execution_success) that shows up on Results. Groville deliberately does not fabricate rich metrics (rankings, clicks, etc.) it can't truly measure — that's the honesty boundary in action.
Not in the MVP (future work):
This is the newest capability in the app. Everything below is live and merged (backend first, then the frontend surface in PR #20).
A vision-model audit of your go-to-market surface. Instead of only reading your HTML, Groville looks at your site the way a visitor does — it takes real screenshots, compares them against competitors' screenshots, and scores how clearly you sell. PixelRAG is the screenshot-and-tile engine; the GTM engine is the vision analysis on top of it.
A new GTM item in the dashboard sidebar (between Opportunities and Campaigns), route /gtm. Press Run GTM analysis (enabled once your business has a website), watch the ~90-second progress state, then read the result.
POST /api/gtm/run (202 + run_id) [routes/gtm_routes.py]
│ Celery task: run_gtm_analysis [task.py]
▼
1. PixelRAG renders + tiles YOUR site render_and_tile_page [services/pixelrag_service.py]
2. Discover up to 2 competitors (from GSC) discover_competitors [services/gtm_discovery_service.py]
3. PixelRAG renders + tiles each competitor
4. Vision LLM scores you vs them (4 pillars) analyze_gtm_tiles [agent/gtm_engine.py]
5. The gaps it finds are written as normal OPPORTUNITIES create_opportunity
6. An executive Markdown DOSSIER is drafted + saved [services/gtm_dossier_service.py]
7. Run marked `completed`; frontend polls GET /api/gtm/runs/<id> every 15s until done
The 4 GTM pillars (each scored 0–100, plus an overall): above the fold, pricing clarity, social proof, CRO friction.
The important integration point: GTM is not a silo. The opportunities the vision model finds are persisted through the same create_opportunity service the rest of the app uses, so a GTM run also populates your normal Opportunities board (the run records how many it created in opportunities_created_count). The screenshot tiles PixelRAG produces are written under backend/static/tiles/<business_id>/<run_id>/… and the frontend loads them through the existing /api/backend/* rewrite proxy (same first-party-cookie path every other API call uses) — no new auth surface. This alignment of the tile manifest shape, the opportunity store, and the dossier is what the recent "gtm-pixelrag-sync" work locked in.
gtm_scores (the 5 gauges) · blind_spots[] · user_manifest.tiles[] (your site capture) · competitors_analyzed[] (each with domain, url, and manifest.tiles) · dossier_path · opportunities_created_count.
Note: the vision model does reason about competitor strengths/weaknesses internally, but those are not persisted on the run document in this phase — only
domain,url, and tiles are. The frontend therefore does not render strength/weakness lists, and the dossier does not depend on them.
The dossier is a draft recommendation you read and act on. The UI labels it "Groville's draft recommendation — review before acting." It is never presented as sent, published, or auto-executed. Groville drafts; you approve.
Two different kinds of timeout matter, plus one model-lifecycle risk:
| Where | Setting | Default |
|---|---|---|
| PixelRAG page navigation | timeout_ms (Playwright goto, falls back networkidle → domcontentloaded) | 15 s |
| PixelRAG per-tile screenshot | screenshot_timeout_ms | 20 s |
Frontend per-request fetch (apiFetch + dossier fetch) | AbortController | 60 s |
| Frontend poll cadence / ceiling | every 15 s, up to 40 ticks (~10 min) before giving up | |
| Vision LLM request | Groq default request timeout (not overridden in code) | Groq default |
"Timeout of models" / model decommission risk: the vision model id is
GROQ_VISION_MODEL(defaultqwen/qwen3.8-27b). Groq rotates and retires models — the previous default (llama-3.2-11b-vision-preview) was decommissioned, which breaks a run with a model-not-found error until the env var is pointed at a current multimodal model. If GTM runs start failing at the vision step, check this first. (The text LLM used elsewhere isGROQ_MODEL.)
completed. If the browser OOMs, a screenshot times out, or the vision model hiccups, the pipeline keeps going and the run completes with empty tiles and/or flat 50 scores (the clamp default). This is intentional (a run shouldn't hard-crash the loop) — but it means a "completed" run can be visually empty. The UI degrades gracefully; just re-run for a clean capture.--disable-dev-shm-usage — the key OOM fix — plus --no-sandbox, --disable-gpu) and pages are closed/cleaned between captures. Heavy pages were the main source of screenshot timeouts; that's mitigated but not eliminated on the free tier.localhost:6379
Secrets are NOT in this repo (they're gitignored). Every teammate creates their own. There are two env files, one per app.
🔑 The golden rule: use
localhostEVERYWHERE, not127.0.0.1The login uses a session cookie. If the frontend talks to
127.0.0.1:5000but you open the app atlocalhost:3000(or vice-versa), the browser treats them as different sites and drops the cookie → you get logged out / 401 right after login. Keep itlocalhoston both sides, and in the GitHub callback URL too.
backend/.envThere is no example file for the backend, so create backend/.env yourself with these keys:
| Variable | What it is |
|---|---|
SECRET_KEY | Signs the Flask session cookie. Any long random string. |
FIREBASE_CREDENTIALS | Absolute path to your Firebase service account JSON file (get it from Felix). |
GROQ_API_KEY | Your Groq LLM API key. |
GROQ_MODEL | The text model id, e.g. openai/gpt-oss-20b. |
GROQ_VISION_MODEL | The vision model id for GTM / PixelRAG (default qwen/qwen3.8-27b). Point it at a current multimodal model — Groq retires these (see section 5 "Model & capture timeouts"). |
TOKEN_ENCRYPTION_KEY | Encrypts stored OAuth tokens (a Fernet key). |
GITHUB_CLIENT_ID | From your GitHub OAuth App. |
GITHUB_CLIENT_SECRET | From your GitHub OAuth App. |
GITHUB_REDIRECT_URI | http://localhost:5000/api/connections/github/callback — must exactly match the callback URL set on your OAuth app. |
FRONTEND_URL | http://localhost:3000 — where the GitHub callback sends the user back to. |
DEBUG | True locally (keeps the cookie non-Secure so it works over plain http). |
INSTAGRAM_* | Optional — only for the Instagram connection; not needed for the core demo. |
GitHub tip: use an OAuth App (not a GitHub App). OAuth App tokens don't expire and match the code's
scope=repoflow. A GitHub App's user tokens expire after 8 hours and cause a "Try again" / 401 on the Connections screen.
frontend/.envCopy frontend/env.example → frontend/.env and fill it in. (Next.js also reads .env.local if you prefer that name — either works; it's gitignored the same way.) Key values:
| Variable | What it is |
|---|---|
NEXT_PUBLIC_API_BASE | http://localhost:5000 — the Flask backend. Use localhost (see the golden rule). Leave blank to run the offline "Ada" demo with no real backend. |
BMONI_API_KEY | BMONI sandbox payments key. Ask William — never commit it. |
BMONI_BASE_URL | https://embedded-dev.bmoni.com (sandbox only). |
DEMO_FALLBACK_ACCOUNT | true — shows a labelled placeholder account if BMONI can't issue a real one, so the demo still runs. |
CRON_SECRET, BMONI_MERCHANT_PHONE, APP_PUBLIC_URL, NEXT_PUBLIC_SUPABASE_* | Optional — see the comments inside env.example. |
⚠️ Never commit
.env,.env.local, or the Firebase service account JSON. If you ever paste a key into a chat or a public place, rotate it.
You'll use up to 4 terminals. Quick guide:
cd backend
python -m venv venv
# Windows:
venv\Scripts\activate
# macOS / Linux:
source venv/bin/activate
pip install -r requirements.txt
Then create backend/.env (section 7a) and make sure FIREBASE_CREDENTIALS points at your real service account JSON.
Start Redis (Windows: start Memurai). It must be reachable at localhost:6379.
celery -A task worker --loglevel=info --pool=solo
--pool=solois REQUIRED on Windows — without it Celery crashes withWinError 5.
python app.py
Runs on http://localhost:5000.
cd frontend
npm install # required after every pull (deps like framer-motion)
npm run dev
Open http://localhost:3000. 🎉
All under cookie auth (credentials: 'include'). Business routes are under /api/business/<id>.
| Area | Endpoints |
|---|---|
| Auth | POST /api/auth/register · login · logout · GET /api/auth/me |
| Business | POST /api/business · PATCH/DELETE /api/business/<id> |
| Analyze (async) | POST .../analyze → then poll GET .../runs/latest |
| Opportunities | GET .../opportunities |
| Actions | GET .../actions · POST .../actions/<id>/approve · .../reject |
| Execution | GET .../executions/<id> (poll: queued → running → completed/failed) |
| Results | GET .../measurements · GET .../learnings |
| Connections | GitHub: /api/connections/github/connect · callback · repositories; Search Console: /api/connections/search-console/*; Instagram: /api/connections/instagram/* |
| GTM / PixelRAG (async) | POST /api/gtm/run (→ run_id) · GET /api/gtm/runs?business_id= · GET /api/gtm/runs/<id>?business_id= (poll) · GET /api/gtm/runs/<id>/dossier?business_id= (text/markdown) |
| Symptom | Fix |
|---|---|
| Logged out / 401 right after login | You're mixing localhost and 127.0.0.1. Use localhost everywhere (API base, browser URL, GitHub callback). |
Celery: WinError 5 | Start the worker with --pool=solo. |
| GitHub connection shows "Try again" / 401 | The OAuth token expired or the callback URL doesn't match. Use an OAuth App, set both the app's callback and GITHUB_REDIRECT_URI to http://localhost:5000/api/connections/github/callback, restart Flask, and reconnect. |
| "No connector available for action type: X" | Make sure the backend is on the latest main (the connector fallback is merged). |
| Analyze crashes: "Opportunity response must be a JSON object" | The small LLM occasionally returns malformed JSON. Just re-run analyze. |
| GTM run fails at the vision step (model-not-found) | The vision model was retired by Groq. Set GROQ_VISION_MODEL to a current multimodal model and restart (see section 5). |
| GTM run shows "Visual capture unavailable" / flat 50 scores | A soft-fail (Chromium OOM, screenshot timeout, or vision hiccup) — the run still completes. Re-run for a clean capture. Old runs may also have lost their tiles on a Render redeploy (ephemeral disk). |
| GTM screenshots keep timing out on big sites | Heavy pages on Render's free tier. Mitigated by memory-safe Chromium flags + WebP tiling, but not eliminated; re-run, or try on a non-free instance. |
| Instagram won't publish | Expected — publishing needs Meta app review; not in the MVP. |
main → open a PR → squash-merge → delete the branch..env, .env.local, or the Firebase service account JSON.npm run lint and npm run build (frontend) before opening a PR.The ALPHAs · NACOS National BuildX