A lightweight proof-of-concept Cloud Function that pulls live legislative data from the OpenStates API v3, feeds the full bill text to Gemini 2.0 on Vertex AI, and returns an HTML page showing:
- a list of recent Virginia bills (or the bill you request by ID)
- the full bill text & token count
- a plain-language summary generated by Gemini
The goal is to demonstrate how you can combine public-sector open data with generative AI to build rapid legislative-tracking tools.
┌────────┐ HTTP request ┌──────────────────────┐
│Browser │ ───────────────────▶ │Cloud Function │
└────────┘ │ 1. Fetch bills from │
│ OpenStates v3 API │
│ 2. Download latest │
│ bill version HTML │
│ 3. Count tokens & │
│ summarise via │
│ Gemini-2.0 Flash │
│ 4. Render HTML │
└──────────────────────┘
- Node.js ≥ 18 (tested with v20)
- A Google Cloud project with Vertex AI and Cloud Functions Gen 2 enabled
- An OpenStates API key – get one at https://open.pluralpolicy.com/
git clone https://github.com/mattcollier/openstates-demo.git
cd openstates-demo
npm install
# set env vars
export OPENSTATES_API_KEY=xxxxxxxxxxxxxxxxxxxx
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
# run locally
npx @google-cloud/functions-framework --target=myHttpFunction --port=8080
# open http://localhost:8080/ → list of bills
# open http://localhost:8080/<billId> → summary for a specific bill
gcloud functions deploy myHttpFunction --gen2 --runtime=nodejs20 --region=us-central1 --entry-point=myHttpFunction --trigger-http --allow-unauthenticated --set-env-vars=OPENSTATES_API_KEY=YOUR_KEY
Variable | Purpose |
---|---|
OPENSTATES_API_KEY |
Auth for OpenStates v3 REST API |
GOOGLE_CLOUD_PROJECT |
Project used by Vertex AI (auto-set in Cloud Functions) |
GOOGLE_CLOUD_LOCATION (optional) |
Vertex AI region (default global ) |
VA_ID constant in index.js |
Jurisdiction to query (change for other states) |
.
├── index.js # Cloud Function entry point
├── ai.js # Gemini helper: summarise & count tokens
├── header.html # Optional page header (empty by default)
├── footer.html # Optional page footer (empty by default)
├── package.json
└── .gcloudignore
- Different state – replace the
VA_ID
value with another jurisdiction ID from the OpenStates docs. - Styling – add CSS/JS to
header.html
&footer.html
. - Summary prompt – tweak
ai.js → generateContent()
for longer/shorter abstracts, JSON output, etc.
- No paging — only the first 20 bills are fetched.
- Bills whose HTML exceeds Gemini’s context window will be truncated.
- Minimal error handling & no caching.
- Consider moving to Cloud Run if you need higher concurrency.
- OpenStates / Plural Policy for open legislative data.
- Google Vertex AI for the Gemini model.
- @digitalbazaar/http-client for fetch wrapper.
Apache-2.0 — see LICENSE
for details.