Open-Source Cold Email & Warmup Platform
Warmbly 是开源的冷邮件平台:温暖您的邮箱、发送活动、并对每条回复进行分流。可在我们的云端运行,也可自行托管整套系统。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Route your next tour to where your fans already are.
GigRoute is a taste-grounded tour planner for independent musicians, built on the Qloo Taste AI Insights API. Enter your artist (or a better-known artist you sound like) and a region. An agent then:
Every city and venue has a “Why this city / venue?” panel built from Qloo's query.affinity and query.explainability: the affinity score, the tags that match your sound, and the artists whose fans drove the result.
Try it in one click: the landing page has a “See a sample tour” button (Radiohead · UK). It always runs on built-in sample data, so it works instantly with no keys.
Requires Node 20 or 22 (see .nvmrc).
nvm use # optional, picks Node 22
npm ci
npm run dev # http://localhost:3000
With no environment variables, the app runs in mock mode: a deterministic mock LLM drives the agent against hand-written fixture data. No network calls are made to Qloo or to any LLM.
| Command | What it does |
|---|---|
npm run dev | Development server |
npm run build / npm start | Production build and server |
npm test | Vitest unit tests (all mocked, no network) |
npm run lint | ESLint |
npm run contract-check | Optional live contract check against Qloo (see below). |
The key lives only in your shell for the length of one command. It is never written to a file or committed:
QLOO_API_KEY=... npm run contract-check
The script (scripts/qloo-contract-check.ts) makes one real request per endpoint GigRoute uses (search, similar artists, fan hotspots, venues with explainability, brand and movie cross-domain, tags) and checks that the response has the fields the app reads. It prints one line per check, with counts and field names only. It never prints response data or the key (anything it prints is scrubbed of the key as a safeguard).
PASS GET /search (artist): 10 artists; fields: id, name, type, popularity, tags, explainability
PASS /v2/insights filter.type=urn:entity:place (venues in London) + explainability: 5 places; ...; explainability on 5/5
FAIL /v2/insights filter.type=urn:entity:movie (cross-domain): Qloo 403: entity type or endpoint not enabled for this key
/search failed, so the checks that need an artist ID didn't run.0 means everything passed; 1 means at least one check failed or was skipped. With no key set it calls nothing, prints a skip message and exits 0.Set these in .env.local for local development (it is gitignored) or in Vercel → Project → Settings → Environment Variables. Never commit real values.
| Variable | Required | Example (empty means unset) | Purpose |
|---|---|---|---|
QLOO_API_KEY | For live Qloo | QLOO_API_KEY= | Sent as the X-Api-Key header. If empty, mock mode is used. |
QLOO_BASE_URL | No | QLOO_BASE_URL= | Defaults to https://hackathon.api.qloo.com. |
QLOO_MOCK | No | QLOO_MOCK= | Set to 1 to force mock Qloo data even when a key is present. |
LLM_BASE_URL | No | LLM_BASE_URL= | Any OpenAI-compatible chat completions endpoint. Defaults to OpenAI. |
LLM_API_KEY | For a live LLM | LLM_API_KEY= | If empty, the deterministic MockLLM plans the tour. |
LLM_MODEL | With LLM_API_KEY | LLM_MODEL= | Model name for the endpoint above. Must support tool calling. |
NEBIUS_API_KEY | No | NEBIUS_API_KEY= | Enables Nebius Token Factory summary rewrite when non-empty. |
NEBIUS_BASE_URL | No | NEBIUS_BASE_URL= | Defaults to https://api.tokenfactory.nebius.com/v1/. |
NEBIUS_MODEL | No | NEBIUS_MODEL= | Defaults to nvidia/nemotron-3-super-120b-a12b. |
NEBIUS_TIMEOUT_MS | No | NEBIUS_TIMEOUT_MS= | Defaults to 20000. |
NEBIUS_REASONING | No | NEBIUS_REASONING= | Empty = reasoning off (reasoning_effort: none + chat_template_kwargs.enable_thinking: false). Set default to omit both fields. |
Going live: set QLOO_API_KEY (and leave QLOO_MOCK unset). That is the only change. The real client already sends the documented requests (see below). The LLM is independent: with no LLM key, the mock LLM drives the real Qloo client.
GigRoute includes an optional, non-blocking final step that passes the deterministic tour summary and the Qloo facts it was built from to NVIDIA Nemotron on the Nebius Token Factory for rewriting. Set NEBIUS_API_KEY to enable it. If it times out, throws an error, or the key is not set, GigRoute seamlessly falls back to the deterministic summary without failing the plan.
"engines": { "node": ">=20 <23" } from package.json and uses Node 22./api/plan is a streaming (SSE) route function; / and /plan are static.A build with QLOO_MOCK=1 and no LLM key is tested as part of CI-style verification (npm ci && npm run build && npm test && npm run lint).
All requests are GET with the X-Api-Key header. The parameters are built in lib/qloo/requests.ts, the same builders feed the mock, and the URLs are asserted in tests/params.test.ts.
| Purpose | Request |
|---|---|
| Resolve artist | GET /search?query=<name>&types=urn:entity:artist&take=10 |
| Tag lookup | GET /v2/tags?filter.query=<q>&filter.parents.types=urn:entity:artist&take=20 |
| Similar artists (co-bills) | GET /v2/insights?filter.type=urn:entity:artist&signal.interests.entities=<id>&take=6 |
| Fan hotspots | GET /v2/insights?filter.type=urn:entity:destination&signal.interests.entities=<ids>&feature.explainability=true&take=10[&filter.location.query=<region>] |
| Venues per city | GET /v2/insights?filter.type=urn:entity:place&signal.interests.entities=<ids>&filter.location.query=<city>&feature.explainability=true&take=5 |
| Merch cues | GET /v2/insights?filter.type=urn:entity:brand or urn:entity:movie &signal.interests.entities=<id>&take=5 |
take is clamped to the documented maximum of 50.results.entities[] (insights), results[] (search) and results.tags[] (tags). Each entity contributes entity_id, name, subtype, properties, location, tags, popularity, query.affinity and query.explainability["signal.interests.entities"].lib/qloo/fixtures/mock-data.json are hand-written fake data, not real API responses. They copy the documented response shapes. Entity IDs are prefixed mock-, and addresses are placeholders.filter.location.query filters them by name (for example UK or USA; United Kingdom, England, US and United States work too). Other regions (for example India or Germany) end with a message explaining the sample data's coverage, with links to try the UK, the USA or everywhere.QLOO_MOCK=1 or QLOO_API_KEY is empty. The demo preset (demo=1) always uses mock mode.lib/qloo: RealQlooClient and MockQlooClient behind one QlooClient interface, with shared request builders and normalizers.lib/agent: a tool-calling agent over any OpenAI-compatible LLM (or MockLLM). Tool results are folded into a typed Plan (lib/agent/plan.ts), and a snapshot of that plan streams to the browser over SSE after every step.app/plan: renders the streamed plan, with progress, skeletons, empty and error states, the explainability panels, and a Leaflet/OpenStreetMap route map.narrateTour, pitchEmail in lib/agent/plan.ts) are pure and deterministic. The MockLLM's closing summary, the per-stop “why” text, the per-venue pitch drafts and the exports all come from the same Qloo evidence (affinity, tags, explainability, similar artists). Pitch drafts are shown with a copy button only; GigRoute never sends email./plan?artist=…®ion=…&cities=…&stops=… encodes every input, so a shared link re-runs the same plan (deterministic in mock mode). The plan page can copy that link, download Markdown or JSON (gigroute-plan@1), or print a clean light-on-paper view. Nothing is stored on a server.next/og (app/opengraph-image.tsx, app/twitter-image.tsx); the icon is app/icon.svg. Set NEXT_PUBLIC_SITE_URL to change the absolute URL used in the meta tags (defaults to https://gigroute.vercel.app).filter.location.query locality matching is fuzzy on Qloo's side. Very broad or unusual regions may return no destinations.query.explainability keyed by signal, with per-entity scores normalized 0–1). If the live API differs, the panels fall back to affinity and tags.