An educational AI-powered environmental investigation system that uses real OpenAQ air-quality data, Google ADK, Gemini, and Streamlit to investigate pollution patterns, visualize station observations, and explain possible contributing factors while enforcing strict AI security boundaries.
The application maintains strict boundaries of responsibility:
| Component | Role | Architectural Rule |
|---|---|---|
| OpenAQ API v3 | Environmental Data Provider | Real station measurements; bounded queries (β€5 stations, β€48 hrs, β€500 obs). |
| Python | Deterministic Computation | Zero LLM arithmetic. Means, medians, peaks, and % shifts calculated in pure Python/Pandas. |
| Google ADK | Agent Orchestration | Coordinates tools, models, instructions, and workflows using google.adk. |
| Gemini | Qualitative Interpretation | Interprets pre-calculated structured evidence; separates facts from hypotheses. |
| Security Layer | Multi-Tier Defense | Prompt-injection detection, secret isolation, and deterministic output validation. |
| Streamlit | Visual Dashboard | PM2.5 intensity map, KPI cards, interactive time-series, and AI investigation UI. |
| Google Cloud Run | Serverless Hosting | Containerized scale-to-zero deployment (min-instances=0) within free-tier limits. |
Security is foundational, not an afterthought:
- Prompt Injection Resistance (Lab 5A): Untrusted external data and user queries are pre-scanned. Injections like
"Ignore all previous instructions..."are blocked before reaching the LLM. - Secret Isolation (Lab 5B): API keys (
OPENAQ_API_KEY,GOOGLE_API_KEY) reside exclusively in environment variables and are never injected into prompts, LLM context, or outputs. - Deterministic Output Validation (Lab 5C):
- Station Reference Check: Rejects fictitious stations not present in the retrieved evidence.
- Numeric Claim Verification: Rejects hallucinated numbers (e.g.
"PM2.5 was 999 Β΅g/mΒ³") if they do not match computed metrics within tolerance. - Causality Enforcement: Rejects definitive causal assertions (e.g.
"Traffic caused the increase"); requires proper hypothesis framing ("may have contributed to").
C4C/
βββ notebooks/
β βββ secure_ai_sustainability.ipynb # Master educational walkthrough (Labs 0-7)
β βββ extension.ipynb # Extension activity: context enrichment + Agent Runtime deployment
βββ clean_air_agent/
β βββ __init__.py # Package entry point (exports root_agent, runner)
β βββ agent.py # Google ADK Root Agent definition
β βββ schemas.py # Pydantic data models
β βββ tools/
β β βββ __init__.py
β β βββ openaq.py # OpenAQ API v3 client with bounds & offline fallback
β β βββ analytics.py # Pure deterministic analytics engine
β βββ security/
β βββ __init__.py
β βββ validators.py # Deterministic security & output validation
βββ app/
β βββ streamlit_app.py # Interactive Streamlit dashboard & guardrailing sandbox
βββ scripts/
β βββ setup_venv.sh # macOS/Linux setup script
β βββ setup_venv_windows.ps1 # Windows PowerShell setup script
βββ tests/
β βββ test_openaq.py # Data retrieval & constraint tests
β βββ test_analytics.py # Deterministic math tests
β βββ test_security.py # Security acceptance tests
β βββ test_agent.py # ADK agent workflow tests
βββ .env.example # Environment variables template
βββ .gitignore # Secrets & cache ignore rules
βββ pytest.ini # Pytest configuration
βββ requirements.txt # Python dependencies
βββ Dockerfile # Production Cloud Run container
βββ README.md
- Python 3.10+ (tested on Python 3.14.6)
- OpenAQ API Key (obtain free here)
- Google Gemini API Key (obtain free from Google AI Studio)
cd /path/to/C4C./scripts/setup_venv.shcp .env.example .envcd C:\path\to\C4Cpowershell -ExecutionPolicy Bypass -File .\scripts\setup_venv_windows.ps1Copy-Item .env.example .envEdit .env with your API keys:
OPENAQ_API_KEY=your_openaq_key_here
GOOGLE_API_KEY=your_gemini_key_here
GEMINI_MODEL=gemini-2.5-flash(Note: If API keys are omitted, the application runs with high-fidelity realistic Delhi monitoring station data for offline sandbox exploration.)
Run the test suite to verify data ingestion, analytics, and security validators:
pytest -vLaunch the interactive environmental investigation dashboard:
streamlit run app/streamlit_app.py --server.port 8051 --server.address 0.0.0.0Open your browser at http://localhost:8501. Features include:
- Filters: Select station regions (Delhi / Anand Vihar, Pusa, Mandir Marg) or custom coordinates.
- PM2.5 Intensity Map: PyDeck map with scaled station markers and tooltips.
- Key Metrics: Real-time average, peak concentration, and diurnal trends.
- AI Investigator: Ask natural language questions and receive structured 4-part reports.
- Live Guardrailing Sandbox: Interactive panel to test prompt injection and secret defenses in real-time.
You can also run or debug the ADK agent directly using the ADK CLI:
adk run clean_air_agent "Investigate air quality around Anand Vihar"adk webOpen the master educational walkthrough:
source .venv/bin/activatejupyter lab notebooks/secure_ai_sustainability.ipynbFollow Labs 0 through 7 cell-by-cell.
Open the extension activity after the main build:
jupyter lab notebooks/extension.ipynbIf VS Code shows an error such as:
Running cells with 'Python 3.14.6' requires the ipykernel package.
it is using the global Homebrew Python instead of this project's virtual environment. Run:
./scripts/setup_venv.shThen select the notebook kernel named:
Clean Air Agent (.venv)
- Serverless scale-to-zero (
min-instances = 0) to prevent unexpected idle costs. - Containerized with non-root security standards.
Run this command from the repository root. The source deployment uses this
repository's Dockerfile, whose container command starts Streamlit at /.
gcloud run deploy clean-air-investigator-portal \
--source . \
--region us-central1 \
--port 8080 \
--allow-unauthenticated \
--min-instances 0 \
--max-instances 2 \
--set-env-vars GEMINI_MODEL=gemini-2.5-flash,OPENAQ_API_KEY=$OPENAQ_API_KEY,GOOGLE_API_KEY=$GOOGLE_API_KEYAfter deployment, open the URL printed by this command. The service name must
be clean-air-investigator-portal; a URL for adk-default-service-name is the
ADK API service and is not the Streamlit portal.
This command creates an API-only service backed by Uvicorn/FastAPI. Its root
path may return 404; use /docs for its API documentation. Do not use this
command to deploy the Streamlit portal.
adk deploy cloud_run \
--project=$GOOGLE_CLOUD_PROJECT \
--region=us-central1 \
clean_air_agent- Workshop Activity Map: Hyper-local pollution framing, data exploration, Google AI interpretation, prototype build, extension, and demo.
- LAB 0 β Setup: Virtual environment, dependencies,
.env, and minimal ADK agent check. - LAB 1 β Real Data: OpenAQ API v3 ingestion, location discovery, normalization, time-series.
- LAB 2 β Analytics: Pure Python deterministic statistics, peak detection, rate-of-change jumps.
- LAB 2B β Spatial Map: Discrete station PM2.5 intensity visualization with scientific disclaimers.
- LAB 3 β ADK Agent: Setting up
clean_air_investigatorroot agent with custom Python tools. - LAB 4 β AI Investigation: Structured 4-part reporting (Observed, Pattern, Possible Factors, Further Investigation).
- LAB 5 β Guardrailing a System:
- 5A: Prompt-injection resistance & untrusted boundary.
- 5B: Secret isolation & credential protection.
- 5C: Deterministic output validation (hallucinated stations, fake numbers, unqualified causality).
- LAB 6 β Streamlit Dashboard: End-to-end interactive dashboard and live guardrailing sandbox.
- LAB 7 β Google Cloud Run: Containerization, scale-to-zero serverless deployment, and cost controls.
- Extension Notebook: Weather, satellite, traffic, and low-cost sensor enrichment paths, plus Google Agent Runtime deployment for the ADK agent.
| Criteria | Where it appears |
|---|---|
| Understand the Problem | Workshop Activity Map and hyper-local pollution primer in the main notebook |
| Explore the Data | Labs 1, 2, and 2B |
| Use Google AI | Labs 3 and 4 with Google ADK and Gemini |
| Build | Lab 6 Streamlit dashboard and agent prototype |
| Extend | notebooks/extension.ipynb, including Google Agent Runtime deployment |
| Demo | Participant Demo Checklist in Lab 7 |