vccs
Vue 3용 차트 컴포넌트 모음, Recharts에서 포팅
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Sovereign inference market observability + oracle for Routstr and centralized catalogs (OpenRouter, OrcaRouter).
Rust CLI + lightweight Axum dashboard. Listens on Nostr for provider discovery (RIP-02), polls model catalogs, normalizes prices to USD and sats, persists to SQLite, and serves a live price board.
License: MPL-2.0
# Requires Rust 1.86+
cargo run --release -- serve
# Dashboard
open http://127.0.0.1:8080/
First boot pulls the OpenRouter and OrcaRouter models catalogs (~650 quotes), Coinbase BTC/USD, and (unless disabled) connects to Nostr relays for Routstr kind 38421 node announcements.
tokenstats serve [OPTIONS]
Options:
--bind <ADDR> HTTP bind (default 127.0.0.1:8080) [env: TOKENSTATS_BIND]
--relay <URL> Nostr relays (repeatable / comma) [env: TOKENSTATS_RELAYS]
--node <URL> Seed Routstr-compatible endpoints [env: TOKENSTATS_NODES]
--allow-private-nodes Poll Nostr nodes on private IPs (trusted LAN only)
--db <PATH> SQLite path (default data/tokenstats.db) [env: TOKENSTATS_DB]
--no-nostr Skip Nostr listener
--no-poll Skip HTTP provider polling
--no-persist In-memory only (no SQLite)
-v, --verbose Debug (-v) / trace (-vv)
# Catalog + dashboard only (no Nostr)
cargo run -- serve --no-nostr
# Seed a known Routstr node
cargo run -- serve --node https://your-node.example.com
# Custom DB + bind
cargo run -- serve --bind 0.0.0.0:8080 --db ./tokenstats.db
| Feature | Description |
|---|---|
| Best Now | Cheapest blended price for popular families (Claude, Grok, DeepSeek, GPT, Gemini, …). Shows node under the price. |
| Blend ratio | Toggle 1:2 / 1:3 / 1:4 in:out workload (?ratio=3). |
| Presets | Cheapest Frontier · Fastest · Most Private · Local-first |
| Feed strip | Feed status + reasons, last cycle, per-source health, Routstr nodes OK + dormant, stale count, BTC rate age |
| Signals | Per-quote 24h reliability, p50 latency, age (stale highlighted), outlier tag; Quality pills: healthy only, hide stale / outliers |
| Capabilities | tools / reasoning / vision tags per model (dashed = inferred from OpenRouter / OrcaRouter for Routstr nodes); pills filter on them |
| Δ out | Price change vs previous catalog snapshot |
| Hover → copy | curl or OpenAI-compatible config JSON for that quote; compare opens the model across sources |
| Compare | /compare?model=…: one model's offers from every source side by side, cheapest first, with spread and cheapest healthy offer |
| Export CSV | Current filtered view → /export.csv?... |
| Nodes | Discovered RIP-02 endpoints + reliability (last hour; 24h/7d on hover) + p50/p95 latency |
Query params: ?source=openrouter&preset=frontier&ratio=4&model=deepseek
| Path | Description |
|---|---|
GET / | HTML dashboard (auto-refresh ~15s) |
GET /health | Liveness + feed status (ok/degraded/down/…) + counts + last_updated |
GET /api/quotes | JSON quotes (source, model, kind, preset, ratio, limit, max_age_secs, min_reliability, min_reliability_24h, max_latency_ms, exclude_stale, exclude_outliers, healthy, capabilities); each quote carries canonical_model and tools / reasoning / vision / input_modalities / max_output_tokens |
GET /api/nodes | Discovered nodes + status (healthy/failing/dormant/skipped) + failure_class + reliability (1h/24h/7d) + latency p50/p95 + last success/error (+ skip_reason when not polled) |
GET /api/summary | Aggregates + Best Now strip |
GET /api/compare | Same model across sources, grouped by canonical_model (model, ratio, limit groups, plus the quote filters): offers, min/median/max blend, spread_pct, cheapest, cheapest_healthy |
GET /compare | HTML compare view |
GET /export.csv | CSV of current filtered view |
Nostr (kind 38421) ──► store.nodes ──► poll /v1/models ──┐
├──► store.quotes ──► dashboard / API
OpenRouter + OrcaRouter /v1/models ─────────────────────┘
Coinbase BTC-USD ──► oracle (USD ↔ sats)
SQLite snapshot every 30s
| Module | Role |
|---|---|
src/nostr/ | RIP-02 discovery (also listens for legacy kind 40500) |
src/providers/ | Reference catalogs (OpenRouter, OrcaRouter) + Routstr-compatible /v1/models |
src/market/ | Popular families, blend, presets |
src/oracle/ | BTC/USD + dual-unit normalization |
src/store/ | In-memory quotes/nodes + poll reliability |
src/persist/ | SQLite restore + periodic save |
src/web/ | Axum routes + HTML |
d, u, mint, version tags). Models/pricing come from the node’s /v1/models, not the event body.Specs: Routstr/protocol
data/tokenstats.db (gitignored)--node seeds are trusted| Concern | Flag / env | Default |
|---|---|---|
| Bind | --bind / TOKENSTATS_BIND | 127.0.0.1:8080 |
| SQLite | --db / TOKENSTATS_DB | data/tokenstats.db |
| Poll interval | --poll-interval-secs | 60 |
| BTC interval | --btc-interval-secs | 60 |
| Persist interval | --persist-interval-secs | 30 |
| Node poll concurrency / timeout | --node-concurrency / --node-timeout-secs | 16 / 10 |
| Quote expiry | --quote-ttl-secs | 86400 |
| Node cap / expiry | --max-nodes / --node-ttl-secs | 512 / 604800 |
| Stale flag threshold | --stale-after-secs | 600 |
| Price ceiling (USD/1M) | --max-price-usd-per-1m | 1000 |
| Poll private Nostr-announced nodes | --allow-private-nodes | off (SSRF guard) |
| Disable Nostr | --no-nostr | off |
| Disable OpenRouter | --no-openrouter | off |
| Disable OrcaRouter | --no-orcarouter | off |
| Plausible analytics | --plausible-script / TOKENSTATS_PLAUSIBLE_SCRIPT | off (no third-party JS) |
| JSON logs | --log-json / TOKENSTATS_LOG_JSON | off |
See docs/USAGE.md for the full list. SIGINT / SIGTERM trigger graceful shutdown (HTTP drain + final DB snapshot).
CI publishes ghcr.io/johnzilla/tokenstats (:latest, :sha-<short>) for every green main; production pulls it.
# Production with Caddy HTTPS (set DOMAIN in .env — see deploy/env.example)
docker compose --profile proxy pull && docker compose --profile proxy up -d
# Local build instead (dev / forks); app on 127.0.0.1:8080
docker compose up -d --build
Full doctl + DNS + Caddy/Nginx guide: docs/DEPLOY.md.
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
cargo run -- serve --no-nostr -v
cargo build --release
CI runs fmt, clippy (warnings denied) and tests on Rust 1.99.1, plus cargo check on the 1.86 MSRV, for every PR and push to main.
Mozilla Public License 2.0 — see LICENSE.