Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ env/
venv/
ENV/
.env
*.env
.venv
*.log
.DS_Store
Expand Down
5 changes: 3 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ def agent_chat():
request_data = request.get_json()
question = request_data.get('question', '')
location_context = request_data.get('location_context', None)
time_frame = request_data.get('time_frame', None)

if not question:
return jsonify({
Expand Down Expand Up @@ -446,8 +447,8 @@ def agent_chat():
traceback.print_exc()
# Fall through to normal chat

# Normal chat flow
response = call_adk_agent(question)
# Normal chat flow - pass context to agent
response = call_adk_agent(question, location_context=location_context, time_frame=time_frame)

return jsonify({
'success': True,
Expand Down
61 changes: 61 additions & 0 deletions docs/ANALYTICS_AGENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Analytics Agent Documentation

## Overview

The **Analytics Agent** is a specialized sub-agent that performs cross-dataset analysis on air quality and infectious disease data using Python code execution. It can handle complex analytical queries that span multiple data sources.

## Capabilities

### Data Sources
1. **Historical Air Quality** - EPA Historical Air Quality dataset (PM2.5, AQI)
2. **Live Air Quality** - Real-time AirNow API data
3. **Infectious Disease** - CDC BEAM disease surveillance data

### Analysis Types
- Cross-dataset correlations
- Temporal pattern analysis
- Geographic comparisons
- Trend analysis and forecasting
- Statistical modeling
- Data visualization

## Architecture

### Tools
The agent has access to three data retrieval tools:
- `get_air_quality()` - Historical EPA data
- `get_live_air_quality()` - Current air quality readings
- `get_infectious_disease_data()` - CDC disease data

### Code Execution
Uses `VertexAiCodeExecutor` to:
- Execute Python code in a stateful environment
- Run data analysis and visualizations
- Maintain state across multiple code executions

## Example Queries

### Cross-Dataset Analysis
```
"Analyze the correlation between air quality and respiratory diseases in California"
```

### Temporal Analysis
```
"Show me trends in air quality vs disease rates over the past year"
```

### Geographic Comparison
```
"Compare air quality and disease patterns across different states"
```

## Files Created

1. `multi_tool_agent_bquery_tools/agents/analytics_agent.py` - Main agent definition
2. `multi_tool_agent_bquery_tools/agents/analytics_prompts.py` - Instruction prompts
3. `multi_tool_agent_bquery_tools/agent.py` - Updated to include analytics agent

## Integration

The analytics agent is automatically integrated into the root agent's sub-agents list and will be routed to when users ask analytical questions spanning multiple datasets.
25 changes: 0 additions & 25 deletions multi_tool_agent_bquery_tools/.env

This file was deleted.

171 changes: 128 additions & 43 deletions multi_tool_agent_bquery_tools/agent.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# ./agent.py
# -*- coding: utf-8 -*-
import os
import asyncio
from datetime import datetime
from google.adk.agents import Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
Expand All @@ -16,53 +18,126 @@
from .agents.psa_video import create_psa_video_agents
from .tools.health_tools import get_health_faq

# Try to import analytics agent, use None if it fails
try:
from .agents.analytics_agent import analytics_agent
except Exception as e:
print(f"[WARNING] Analytics agent not available: {e}")
analytics_agent = None

# === Model configuration ===
GEMINI_MODEL = "gemini-2.0-flash"

def get_current_time_context():
"""Generate current time context for the agent"""
now = datetime.now()
current_time = now.strftime("%A, %B %d, %Y at %I:%M %p")
current_date = now.strftime("%Y-%m-%d")
current_year = now.year

return f"""
CURRENT TIME CONTEXT:
- Current Date & Time: {current_time}
- Current Date (ISO): {current_date}
- Current Year: {current_year}

IMPORTANT: Always reference the current time when providing health advice, especially for:
- Seasonal health recommendations
- Time-sensitive health alerts
- Current weather conditions affecting health
- Recent data trends and patterns
"""

def create_root_agent_with_context(location_context=None, time_frame=None):
"""Create the root agent with dynamic context including current time, location, and time frame"""

# Get current time context
time_context = get_current_time_context()

# Build location context if provided
location_info = ""
if location_context:
location_parts = []
if location_context.get('city'):
location_parts.append(f"City: {location_context['city']}")
if location_context.get('state'):
location_parts.append(f"State: {location_context['state']}")
if location_context.get('county'):
location_parts.append(f"County: {location_context['county']}")
if location_context.get('zipCode'):
location_parts.append(f"ZIP Code: {location_context['zipCode']}")
if location_context.get('formattedAddress'):
location_parts.append(f"Address: {location_context['formattedAddress']}")

if location_parts:
location_info = f"""
USER LOCATION CONTEXT:
- {', '.join(location_parts)}
- Coordinates: {location_context.get('coordinates', {}).get('lat', 'N/A')}, {location_context.get('coordinates', {}).get('lng', 'N/A')}
"""

# Build time frame context if provided
time_frame_info = ""
if time_frame:
time_frame_info = f"""
DATA TIME FRAME CONTEXT:
- Start Date: {time_frame.get('start_date', 'Not specified')}
- End Date: {time_frame.get('end_date', 'Not specified')}
- Analysis Period: {time_frame.get('period', 'Not specified')}
"""

# Combine all context
global_context = f"{time_context}{location_info}{time_frame_info}"

return Agent(
name="community_health_assistant",
model=GEMINI_MODEL,
description="Main community health assistant that routes queries to specialized sub-agents.",
global_instruction=global_context,
instruction=(
"You are a friendly Community Health & Wellness Assistant. "
"When a user greets you, respond warmly with this menu:\n\n"
"\"Welcome to the Community Health & Wellness Assistant!\n\n"
"I can help you with:\n"
"1. [LIVE AIR QUALITY] Check current air quality via the AirNow API\n"
"2. [HISTORICAL AIR QUALITY] View past PM2.5 data from EPA BigQuery\n"
"3. [DISEASES] Infectious Disease Tracking - County-level CDC data\n"
"4. [CLINICS] Find nearby clinics or doctors using Google Search\n"
"5. [HEALTH] General wellness, hygiene, and preventive care advice\n"
"6. [ANALYTICS] Cross-dataset analysis across air quality and disease data\n"
"7. [PSA VIDEOS] Generate and share public health announcement videos\n\n"
"What would you like to know about today?\"\n\n"
"Routing Rules:\n"
"- Mentions of 'live', 'today', 'current', or 'now' → live_air_quality_agent.\n"
"- Questions mentioning years, months, or historical data → air_quality_agent.\n"
"- Mentions of infections, outbreaks, or diseases → infectious_diseases_agent.\n"
"- If the user describes symptoms or feeling unwell "
"(e.g., 'I have a rash', 'I feel dizzy', 'my tooth hurts', 'I cut my hand', "
"'my child is sick'), route to clinic_finder_agent."
"- General health, hygiene, prevention, wellness, or safety advice → health_faq_agent.\n"
"- Analytical questions spanning multiple datasets, correlations, trends, or complex analysis → analytics_agent.\n"
"- Requests to create PSA videos, announcements, or post to social media → PSA video agents.\n\n"
"Process:\n"
"1. If clinic_finder_agent provides a search phrase (e.g., 'dermatologist near San Jose'), "
"use google_search with that phrase.\n"
"2. Summarize the top 3–5 results clearly with clinic names and addresses.\n\n"
"After any response (from you or a sub-agent), always end with: "
"'Is there anything else I can help you with today?'"
),
sub_agents=[
air_quality_agent,
live_air_quality_agent,
infectious_diseases_agent,
clinic_finder_agent,
health_faq_agent,
] + ([analytics_agent] if analytics_agent else []) + psa_agents # Add PSA video agents (ActionLine, VeoPrompt, Twitter)
)

# === Create PSA Video Agents ===
psa_agents = create_psa_video_agents(model=GEMINI_MODEL, tools_module=None)

# === Root Agent Definition ===
root_agent = Agent(
name="community_health_assistant",
model=GEMINI_MODEL,
description="Main community health assistant that routes queries to specialized sub-agents.",
instruction=(
"You are a friendly Community Health & Wellness Assistant. "
"When a user greets you, respond warmly with this menu:\n\n"
"\"Welcome to the Community Health & Wellness Assistant!\n\n"
"I can help you with:\n"
"1. [LIVE AIR QUALITY] Check current air quality via the AirNow API\n"
"2. [HISTORICAL AIR QUALITY] View past PM2.5 data from EPA BigQuery\n"
"3. [DISEASES] Infectious Disease Tracking - County-level CDC data\n"
"4. [CLINICS] Find nearby clinics or doctors using Google Search\n"
"5. [HEALTH] General wellness, hygiene, and preventive care advice\n"
"6. [PSA VIDEOS] Generate and share public health announcement videos\n\n"
"What would you like to know about today?\"\n\n"
"Routing Rules:\n"
"- Mentions of 'live', 'today', 'current', or 'now' → live_air_quality_agent.\n"
"- Questions mentioning years, months, or historical data → air_quality_agent.\n"
"- Mentions of infections, outbreaks, or diseases → infectious_diseases_agent.\n"
"- If the user describes symptoms or feeling unwell "
"(e.g., 'I have a rash', 'I feel dizzy', 'my tooth hurts', 'I cut my hand', "
"'my child is sick'), route to clinic_finder_agent."
"- General health, hygiene, prevention, wellness, or safety advice → health_faq_agent.\n"
"- Requests to create PSA videos, announcements, or post to social media → PSA video agents.\n\n"
"Process:\n"
"1. If clinic_finder_agent provides a search phrase (e.g., 'dermatologist near San Jose'), "
"use google_search with that phrase.\n"
"2. Summarize the top 3–5 results clearly with clinic names and addresses.\n\n"
"After any response (from you or a sub-agent), always end with: "
"'Is there anything else I can help you with today?'"
),
sub_agents=[
air_quality_agent,
live_air_quality_agent,
infectious_diseases_agent,
clinic_finder_agent,
health_faq_agent,
] + psa_agents, # Add PSA video agents (ActionLine, VeoPrompt, Twitter)
)
# === Default Root Agent (for backward compatibility) ===
root_agent = create_root_agent_with_context()

# === Runner & Session Setup ===
APP_NAME = "community_health_app"
Expand All @@ -85,11 +160,21 @@ def _initialize_session_and_runner():
)
_runner = Runner(agent=root_agent, app_name=APP_NAME, session_service=_session_service)

def call_agent(query: str) -> str:
def call_agent(query: str, location_context=None, time_frame=None) -> str:
"""Helper function to call the agent with a query and return the response."""
_initialize_session_and_runner()

# Create agent with context if provided
if location_context or time_frame:
agent_with_context = create_root_agent_with_context(location_context, time_frame)
# Create a new runner with the context-aware agent
context_runner = Runner(agent=agent_with_context, app_name=APP_NAME, session_service=_session_service)
runner_to_use = context_runner
else:
runner_to_use = _runner

content = types.Content(role="user", parts=[types.Part(text=query)])
events = _runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content)
events = runner_to_use.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content)

for event in events:
if event.is_final_response():
Expand Down
41 changes: 41 additions & 0 deletions multi_tool_agent_bquery_tools/agents/analytics_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import os
from google.adk.agents import Agent
from .analytics_prompts import return_instructions_analytics

# Import tools from other agents to get data
from ..tools.air_quality_tool import get_air_quality
from ..tools.live_air_quality_tool import get_live_air_quality
from ..tools.disease_tools import get_infectious_disease_data

GEMINI_MODEL = "gemini-2.0-flash"

# Try to use VertexAI code executor, fall back to None if not available
# (Agent will still work without code executor for basic data retrieval)
code_executor = None
try:
# Check if running with Google AI Studio (no VertexAI needed)
use_vertex_ai = os.getenv('GOOGLE_GENAI_USE_VERTEXAI', '').lower() == 'true'

if use_vertex_ai:
from google.adk.code_executors import VertexAiCodeExecutor
code_executor = VertexAiCodeExecutor(
optimize_data_file=True,
stateful=True,
)
print("[OK] Analytics agent using VertexAI code executor")
else:
print("[INFO] Running with Google AI Studio - code executor disabled")
print("[INFO] Analytics agent will work without code execution (data retrieval only)")
except Exception as e:
print(f"[WARNING] VertexAI code executor not available: {e}")
print("[INFO] Analytics agent will work without code execution (data retrieval only)")
code_executor = None

analytics_agent = Agent(
name="analytics_agent",
model=GEMINI_MODEL,
description="Analytics agent that performs cross-dataset analysis across air quality and disease data. Provides statistical analysis, correlations, and insights.",
instruction=return_instructions_analytics(),
code_executor=code_executor,
tools=[get_air_quality, get_live_air_quality, get_infectious_disease_data],
)
Loading