FixPortal 发布 fixportal-observatory:面向 AI 用量与成本的 OSS 可观测性面板
FixPortal/fixportal-observatory
FixPortal 发布开源项目 fixportal-observatory,用 .NET 10 与 React 19 构建、PostgreSQL 存储,把账单支出、公开目录估算、订阅名义价值和缺失数据分开呈现。
OSS observability for AI usage and cost evidence, as of 2026-08-25. It keeps billed spend, public-list estimates, subscription notional values, and missing data distinct.
Observatory is a .NET 10 and React 19 dashboard with a PostgreSQL store. Provider sources, local CLI telemetry, and manual entries retain provenance so unlike evidence is never silently merged.
Read these first
- Provider setup — every source, access requirement, and known unavailable capability.
- Truth and pricing — source/scope/basis meanings and safe catalog refresh.
- Adding a provider — the compile-time adapter seam.
- Local producers — Codex, Copilot, Claude, Kimi, Gemini review, Antigravity, Grok, and PI sweeper setup.
- Postman collection — representative authenticated API requests.
- OSS qualification — validation evidence and remaining limitations.
Release v1.0.1 starts a fresh public Git history; earlier history is archived by the
maintainer. If you have an older checkout, preserve local work and clone again.
Local development
Quick start
Want to look around without installing anything? See the public demo.
Restore uses public feeds; no GitHub Packages token is required.
docker compose up --buildThis starts PostgreSQL, the API, provider/pricing ingest, and the frontend at http://localhost:4173. The compose seed populates synthetic sample data; it is labelled demo-seed and is not a representation of provider billing. Optional GitHub billing uses GITHUB_TOKEN plus GITHUB_BILLING_ORG; the token needs the broader access listed in provider setup.
For a manual run, install .NET SDK 10, Node ^22.22.2, ^24.15.0, or >=26.0.0, and PostgreSQL 16. The sweeper client needs Node 24 or later; see Local producers. The commands below reuse the Compose database and its local development credentials. Use 127.0.0.1, not localhost: Compose publishes the port on IPv4 only, and on Windows localhost tries ::1 first, adding about 2 seconds to every new connection. The same applies to a TEST_DB_CONNECTION pointed at this database.
docker compose up -d --wait db
$env:DB_CONNECTION = 'Host=127.0.0.1;Port=5433;Database=aiobservatory;Username=aiobs;Password=aiobs'
$env:OBSERVATORY_API_KEY = 'change-me'
dotnet restore AiObservatory.slnx
npm --prefix src/AiObservatory.Web ci
dotnet run --project src/AiObservatory.Api
The API applies pending EF Core migrations when it starts. In a separate shell, give the frontend the same local development key, then start it:
$env:VITE_API_KEY = 'change-me'
npm --prefix src/AiObservatory.Web run dev
For a manual run, start the ingest worker in another shell; it only activates sources whose required settings are present:
$env:DB_CONNECTION = 'Host=127.0.0.1;Port=5433;Database=aiobservatory;Username=aiobs;Password=aiobs'
dotnet run --project src/AiObservatory.Ingest
Optional settings
| Setting | Effect when unset |
|---|---|
Activity__ProjectOwners |
The Activity and GitHub tabs show every project and repository that was ingested. Set it to a comma-separated list of GitHub account names to narrow them to those owners. |
VITE_ATTRIBUTION_NAME, VITE_ATTRIBUTION_URL |
The footer shows only a link to this project. Set both to credit whoever runs your instance. |
BUDGET_ALERT_MESSAGE_ID_DOMAIN |
Budget alert Message-Id headers use the domain of your configured sender address, or observatory.local if no sender is configured. |
Use neutral placeholders such as <observatory-api-key> outside your secret store. See Provider setup for acquisition settings; public pricing catalogs require no credentials. Google Cloud SKU pricing remains unavailable until verified mappings exist, independently of the bundled Gemini Developer API rates.
Dashboard truth
The Overview above runs on the Compose demo seed. Note that provider estimate reads Not reported rather than zero, because the seed carries no provider-reported cost — the distinction the cards exist to preserve:
- Billed spend contains provider-reported financial or ledger evidence only.
- Estimated cost is API usage rated from an observed public catalog.
- Subscription notional value is a separate comparison, not spend.
- Missing money or tokens read
Not reported, never zero. - Source status shows configuration, freshness, failure, and unavailability separately from process liveness.
Supported acquisition includes OpenAI usage/costs, Anthropic usage/cost reports and optional Claude Code analytics, GitHub Copilot organization engagement, Google Cloud Billing BigQuery export, GitHub activity/billing, and eight local transcript collectors. The provider matrix is the authoritative capability list.
API
Requests use X-Observatory-Key when API keys are configured. The most useful entry points are:
| Method | Route | What it provides |
|---|---|---|
GET |
/api/aggregates |
Daily source-aware usage and cost aggregates |
GET |
/api/sources/status |
Source configuration, freshness, and sanitized status |
POST |
/api/events |
A provenance-labelled usage event |
GET |
/api/subscriptions |
Subscription ledger records |
GET |
/api/insights |
Generated insights |
Import the Postman collection, set base_url and api_key, and use its source-aware event examples. It is a representative collection, not an exhaustive API specification.
Bringing your own data
Observatory accepts private evidence through three supported paths, none of which requires publishing anything to this repository:
- Usage events.
POST /api/eventsaccepts a provenance-labelled snapshot (sourceId,sourceKind,usageScope,costBasis); the Postman collection carries source-aware examples. Events are source-scoped, so re-posting a corrected snapshot replaces its previous contribution. - Spend entries. The Spend page records manual ledger entries under the
manual-ledgersource; they behave like provider-billed rows in every total and reconciliation. - A private adapter. For recurring feeds — a custom expense source, an internal billing export — adding a provider describes the compile-time adapter seam. An adapter can live in your own fork or deployment; it never needs to be upstreamed.
Contributing
Run the focused local-producer check:
node --test clients/observatory-sweep.test.mjs
Run the solution checks before a pull request:
dotnet test --solution AiObservatory.slnx --configuration Release
Run the opt-in PostgreSQL repricing qualification workload separately; it reports the median of three 1,000-event pricing activations and does not enforce a machine-specific timing threshold:
dotnet run --project tests/AiObservatory.Data.Tests/AiObservatory.Data.Tests.csproj --configuration Release -- --explicit only --filter-method AiObservatory.Data.Tests.Pricing.PricingRepricingServiceTests.QualificationRepricesEveryEligibleEventAndItsAggregate --show-live-output on --output Detailed
npm --prefix src/AiObservatory.Web test -- --run
The repository is Apache-2.0 licensed. Keep provider changes source-aware and update the setup matrix with any new capability or limitation.
Troubleshooting
| Symptom | Cause and next step |
|---|---|
A provider is Not configured |
Supply the exact required settings and upstream access in Provider setup. |
| Google Cloud catalog stays unavailable | Cloud SKU mappings remain unavailable; Gemini Developer API list pricing and billed BigQuery export are independent. |
| Claude activity appears twice | Exclude local Claude telemetry when Claude Code Analytics covers the same activity. |
| A cost is missing | Required model dimensions may be unknown; Observatory intentionally returns no guessed fallback price. |
来源:GitHub · github.com

