aiecs 1.2.1__py3-none-any.whl → 1.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aiecs might be problematic. Click here for more details.
- aiecs/__init__.py +1 -1
- aiecs/config/config.py +2 -1
- aiecs/llm/clients/vertex_client.py +5 -0
- aiecs/main.py +2 -2
- aiecs/scripts/tools_develop/README.md +111 -2
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +80 -21
- aiecs/scripts/tools_develop/verify_tools.py +347 -0
- aiecs/tools/__init__.py +94 -30
- aiecs/tools/apisource/__init__.py +106 -0
- aiecs/tools/apisource/intelligence/__init__.py +20 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +378 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +387 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +384 -0
- aiecs/tools/apisource/monitoring/__init__.py +12 -0
- aiecs/tools/apisource/monitoring/metrics.py +308 -0
- aiecs/tools/apisource/providers/__init__.py +114 -0
- aiecs/tools/apisource/providers/base.py +684 -0
- aiecs/tools/apisource/providers/census.py +412 -0
- aiecs/tools/apisource/providers/fred.py +575 -0
- aiecs/tools/apisource/providers/newsapi.py +402 -0
- aiecs/tools/apisource/providers/worldbank.py +346 -0
- aiecs/tools/apisource/reliability/__init__.py +14 -0
- aiecs/tools/apisource/reliability/error_handler.py +362 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +420 -0
- aiecs/tools/apisource/tool.py +814 -0
- aiecs/tools/apisource/utils/__init__.py +12 -0
- aiecs/tools/apisource/utils/validators.py +343 -0
- aiecs/tools/langchain_adapter.py +95 -17
- aiecs/tools/search_tool/__init__.py +102 -0
- aiecs/tools/search_tool/analyzers.py +583 -0
- aiecs/tools/search_tool/cache.py +280 -0
- aiecs/tools/search_tool/constants.py +127 -0
- aiecs/tools/search_tool/context.py +219 -0
- aiecs/tools/search_tool/core.py +773 -0
- aiecs/tools/search_tool/deduplicator.py +123 -0
- aiecs/tools/search_tool/error_handler.py +257 -0
- aiecs/tools/search_tool/metrics.py +375 -0
- aiecs/tools/search_tool/rate_limiter.py +177 -0
- aiecs/tools/search_tool/schemas.py +297 -0
- aiecs/tools/statistics/data_loader_tool.py +2 -2
- aiecs/tools/statistics/data_transformer_tool.py +1 -1
- aiecs/tools/task_tools/__init__.py +8 -8
- aiecs/tools/task_tools/report_tool.py +1 -1
- aiecs/tools/tool_executor/__init__.py +2 -0
- aiecs/tools/tool_executor/tool_executor.py +284 -14
- aiecs/utils/__init__.py +11 -0
- aiecs/utils/cache_provider.py +698 -0
- aiecs/utils/execution_utils.py +5 -5
- {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/METADATA +1 -1
- {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/RECORD +55 -23
- aiecs/tools/task_tools/search_tool.py +0 -1123
- {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/WHEEL +0 -0
- {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/entry_points.txt +0 -0
- {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"""
|
|
2
|
+
US Census Bureau API Provider
|
|
3
|
+
|
|
4
|
+
Provides access to US Census Bureau data including demographic,
|
|
5
|
+
economic, and geographic information.
|
|
6
|
+
|
|
7
|
+
API Documentation: https://www.census.gov/data/developers/guidance/api-user-guide.html
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
12
|
+
|
|
13
|
+
from aiecs.tools.apisource.providers.base import BaseAPIProvider, expose_operation
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
# Optional HTTP client
|
|
18
|
+
try:
|
|
19
|
+
import requests
|
|
20
|
+
REQUESTS_AVAILABLE = True
|
|
21
|
+
except ImportError:
|
|
22
|
+
REQUESTS_AVAILABLE = False
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class CensusProvider(BaseAPIProvider):
|
|
26
|
+
"""
|
|
27
|
+
US Census Bureau API provider for demographic and economic data.
|
|
28
|
+
|
|
29
|
+
Provides access to:
|
|
30
|
+
- American Community Survey (ACS) data
|
|
31
|
+
- Decennial Census
|
|
32
|
+
- Economic indicators
|
|
33
|
+
- Population estimates
|
|
34
|
+
- Geographic data
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
BASE_URL = "https://api.census.gov/data"
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def name(self) -> str:
|
|
41
|
+
return "census"
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def description(self) -> str:
|
|
45
|
+
return "US Census Bureau API for demographic, economic, and geographic data"
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def supported_operations(self) -> List[str]:
|
|
49
|
+
return [
|
|
50
|
+
'get_acs_data',
|
|
51
|
+
'get_population',
|
|
52
|
+
'get_economic_data',
|
|
53
|
+
'list_datasets',
|
|
54
|
+
'list_variables'
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
def validate_params(self, operation: str, params: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
|
|
58
|
+
"""Validate parameters for Census API operations"""
|
|
59
|
+
|
|
60
|
+
if operation == 'get_acs_data':
|
|
61
|
+
if 'variables' not in params:
|
|
62
|
+
return False, "Missing required parameter: variables"
|
|
63
|
+
if 'geography' not in params:
|
|
64
|
+
return False, "Missing required parameter: geography"
|
|
65
|
+
|
|
66
|
+
elif operation == 'get_population':
|
|
67
|
+
if 'geography' not in params:
|
|
68
|
+
return False, "Missing required parameter: geography"
|
|
69
|
+
|
|
70
|
+
elif operation == 'get_economic_data':
|
|
71
|
+
if 'variables' not in params:
|
|
72
|
+
return False, "Missing required parameter: variables"
|
|
73
|
+
|
|
74
|
+
return True, None
|
|
75
|
+
|
|
76
|
+
# Exposed operations for AI agent visibility
|
|
77
|
+
|
|
78
|
+
@expose_operation(
|
|
79
|
+
operation_name='get_acs_data',
|
|
80
|
+
description='Get American Community Survey (ACS) demographic and economic data'
|
|
81
|
+
)
|
|
82
|
+
def get_acs_data(
|
|
83
|
+
self,
|
|
84
|
+
variables: str,
|
|
85
|
+
geography: str,
|
|
86
|
+
year: Optional[int] = None
|
|
87
|
+
) -> Dict[str, Any]:
|
|
88
|
+
"""
|
|
89
|
+
Get ACS data.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
variables: Comma-separated variable codes (e.g., 'B01001_001E,B19013_001E')
|
|
93
|
+
geography: Geographic level (e.g., 'state:*', 'county:*', 'tract:*')
|
|
94
|
+
year: Year for data (default: latest available)
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Dictionary containing ACS data and metadata
|
|
98
|
+
"""
|
|
99
|
+
params = {
|
|
100
|
+
'variables': variables,
|
|
101
|
+
'geography': geography
|
|
102
|
+
}
|
|
103
|
+
if year:
|
|
104
|
+
params['year'] = year
|
|
105
|
+
|
|
106
|
+
return self.execute('get_acs_data', params)
|
|
107
|
+
|
|
108
|
+
@expose_operation(
|
|
109
|
+
operation_name='get_population',
|
|
110
|
+
description='Get population estimates and demographic data'
|
|
111
|
+
)
|
|
112
|
+
def get_population(
|
|
113
|
+
self,
|
|
114
|
+
geography: str,
|
|
115
|
+
year: Optional[int] = None
|
|
116
|
+
) -> Dict[str, Any]:
|
|
117
|
+
"""
|
|
118
|
+
Get population data.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
geography: Geographic level (e.g., 'state:06', 'county:*')
|
|
122
|
+
year: Year for data (default: latest available)
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Dictionary containing population data
|
|
126
|
+
"""
|
|
127
|
+
params = {'geography': geography}
|
|
128
|
+
if year:
|
|
129
|
+
params['year'] = year
|
|
130
|
+
|
|
131
|
+
return self.execute('get_population', params)
|
|
132
|
+
|
|
133
|
+
@expose_operation(
|
|
134
|
+
operation_name='get_economic_data',
|
|
135
|
+
description='Get economic indicators and business statistics'
|
|
136
|
+
)
|
|
137
|
+
def get_economic_data(
|
|
138
|
+
self,
|
|
139
|
+
variables: str,
|
|
140
|
+
geography: Optional[str] = None,
|
|
141
|
+
year: Optional[int] = None
|
|
142
|
+
) -> Dict[str, Any]:
|
|
143
|
+
"""
|
|
144
|
+
Get economic data.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
variables: Comma-separated variable codes
|
|
148
|
+
geography: Geographic level (optional)
|
|
149
|
+
year: Year for data (default: latest available)
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Dictionary containing economic data
|
|
153
|
+
"""
|
|
154
|
+
params = {'variables': variables}
|
|
155
|
+
if geography:
|
|
156
|
+
params['geography'] = geography
|
|
157
|
+
if year:
|
|
158
|
+
params['year'] = year
|
|
159
|
+
|
|
160
|
+
return self.execute('get_economic_data', params)
|
|
161
|
+
|
|
162
|
+
@expose_operation(
|
|
163
|
+
operation_name='list_datasets',
|
|
164
|
+
description='List all available Census datasets'
|
|
165
|
+
)
|
|
166
|
+
def list_datasets(self) -> Dict[str, Any]:
|
|
167
|
+
"""
|
|
168
|
+
List available datasets.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Dictionary containing list of datasets
|
|
172
|
+
"""
|
|
173
|
+
return self.execute('list_datasets', {})
|
|
174
|
+
|
|
175
|
+
@expose_operation(
|
|
176
|
+
operation_name='list_variables',
|
|
177
|
+
description='List available variables for a specific dataset'
|
|
178
|
+
)
|
|
179
|
+
def list_variables(
|
|
180
|
+
self,
|
|
181
|
+
dataset: Optional[str] = None,
|
|
182
|
+
year: Optional[int] = None
|
|
183
|
+
) -> Dict[str, Any]:
|
|
184
|
+
"""
|
|
185
|
+
List available variables.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
dataset: Dataset name (e.g., 'acs/acs5')
|
|
189
|
+
year: Year for dataset
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Dictionary containing list of variables
|
|
193
|
+
"""
|
|
194
|
+
params = {}
|
|
195
|
+
if dataset:
|
|
196
|
+
params['dataset'] = dataset
|
|
197
|
+
if year:
|
|
198
|
+
params['year'] = year
|
|
199
|
+
|
|
200
|
+
return self.execute('list_variables', params)
|
|
201
|
+
|
|
202
|
+
def fetch(self, operation: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
203
|
+
"""Fetch data from Census API"""
|
|
204
|
+
|
|
205
|
+
if not REQUESTS_AVAILABLE:
|
|
206
|
+
raise ImportError("requests library is required for Census provider")
|
|
207
|
+
|
|
208
|
+
# Census API may require a key for some datasets
|
|
209
|
+
api_key = self._get_api_key('CENSUS_API_KEY')
|
|
210
|
+
timeout = self.config.get('timeout', 30)
|
|
211
|
+
|
|
212
|
+
# Build endpoint based on operation
|
|
213
|
+
if operation == 'get_acs_data':
|
|
214
|
+
# American Community Survey 5-Year Data
|
|
215
|
+
year = params.get('year', '2021')
|
|
216
|
+
endpoint = f"{self.BASE_URL}/{year}/acs/acs5"
|
|
217
|
+
|
|
218
|
+
# Build query parameters
|
|
219
|
+
variables = params['variables']
|
|
220
|
+
if isinstance(variables, list):
|
|
221
|
+
variables = ','.join(variables)
|
|
222
|
+
|
|
223
|
+
geography = params['geography']
|
|
224
|
+
|
|
225
|
+
query_params = {
|
|
226
|
+
'get': variables,
|
|
227
|
+
'for': geography
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if api_key:
|
|
231
|
+
query_params['key'] = api_key
|
|
232
|
+
|
|
233
|
+
elif operation == 'get_population':
|
|
234
|
+
# Population Estimates
|
|
235
|
+
year = params.get('year', '2021')
|
|
236
|
+
endpoint = f"{self.BASE_URL}/{year}/pep/population"
|
|
237
|
+
|
|
238
|
+
geography = params['geography']
|
|
239
|
+
variables = params.get('variables', 'POP')
|
|
240
|
+
|
|
241
|
+
query_params = {
|
|
242
|
+
'get': variables,
|
|
243
|
+
'for': geography
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if api_key:
|
|
247
|
+
query_params['key'] = api_key
|
|
248
|
+
|
|
249
|
+
elif operation == 'get_economic_data':
|
|
250
|
+
# Economic Census or other economic data
|
|
251
|
+
year = params.get('year', '2017')
|
|
252
|
+
dataset = params.get('dataset', 'ecnbasic')
|
|
253
|
+
endpoint = f"{self.BASE_URL}/{year}/ecnbasic"
|
|
254
|
+
|
|
255
|
+
variables = params['variables']
|
|
256
|
+
if isinstance(variables, list):
|
|
257
|
+
variables = ','.join(variables)
|
|
258
|
+
|
|
259
|
+
geography = params.get('geography', 'state:*')
|
|
260
|
+
|
|
261
|
+
query_params = {
|
|
262
|
+
'get': variables,
|
|
263
|
+
'for': geography
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if api_key:
|
|
267
|
+
query_params['key'] = api_key
|
|
268
|
+
|
|
269
|
+
elif operation == 'list_datasets':
|
|
270
|
+
# List available datasets
|
|
271
|
+
endpoint = f"{self.BASE_URL}.json"
|
|
272
|
+
query_params = {}
|
|
273
|
+
|
|
274
|
+
elif operation == 'list_variables':
|
|
275
|
+
# List variables for a dataset
|
|
276
|
+
year = params.get('year', '2021')
|
|
277
|
+
dataset = params.get('dataset', 'acs/acs5')
|
|
278
|
+
endpoint = f"{self.BASE_URL}/{year}/{dataset}/variables.json"
|
|
279
|
+
query_params = {}
|
|
280
|
+
|
|
281
|
+
else:
|
|
282
|
+
raise ValueError(f"Unknown operation: {operation}")
|
|
283
|
+
|
|
284
|
+
# Make API request
|
|
285
|
+
try:
|
|
286
|
+
response = requests.get(
|
|
287
|
+
endpoint,
|
|
288
|
+
params=query_params,
|
|
289
|
+
timeout=timeout
|
|
290
|
+
)
|
|
291
|
+
response.raise_for_status()
|
|
292
|
+
|
|
293
|
+
data = response.json()
|
|
294
|
+
|
|
295
|
+
# Census API typically returns array of arrays
|
|
296
|
+
# First row is headers, subsequent rows are data
|
|
297
|
+
if operation in ['get_acs_data', 'get_population', 'get_economic_data']:
|
|
298
|
+
if isinstance(data, list) and len(data) > 1:
|
|
299
|
+
headers = data[0]
|
|
300
|
+
rows = data[1:]
|
|
301
|
+
|
|
302
|
+
# Convert to list of dictionaries
|
|
303
|
+
result_data = [
|
|
304
|
+
dict(zip(headers, row)) for row in rows
|
|
305
|
+
]
|
|
306
|
+
else:
|
|
307
|
+
result_data = data
|
|
308
|
+
else:
|
|
309
|
+
result_data = data
|
|
310
|
+
|
|
311
|
+
return self._format_response(
|
|
312
|
+
operation=operation,
|
|
313
|
+
data=result_data,
|
|
314
|
+
source=f"US Census Bureau - {endpoint}"
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
except requests.exceptions.RequestException as e:
|
|
318
|
+
self.logger.error(f"Census API request failed: {e}")
|
|
319
|
+
raise Exception(f"Census API request failed: {str(e)}")
|
|
320
|
+
|
|
321
|
+
def get_operation_schema(self, operation: str) -> Optional[Dict[str, Any]]:
|
|
322
|
+
"""Get detailed schema for Census API operations"""
|
|
323
|
+
|
|
324
|
+
schemas = {
|
|
325
|
+
'get_acs_data': {
|
|
326
|
+
'description': 'Get American Community Survey data',
|
|
327
|
+
'parameters': {
|
|
328
|
+
'variables': {
|
|
329
|
+
'type': 'string',
|
|
330
|
+
'required': True,
|
|
331
|
+
'description': 'Comma-separated variable codes',
|
|
332
|
+
'examples': ['B01001_001E', 'B19013_001E', 'B25077_001E']
|
|
333
|
+
},
|
|
334
|
+
'geography': {
|
|
335
|
+
'type': 'string',
|
|
336
|
+
'required': True,
|
|
337
|
+
'description': 'Geographic level specification',
|
|
338
|
+
'examples': ['state:*', 'county:*', 'state:06', 'county:037']
|
|
339
|
+
},
|
|
340
|
+
'year': {
|
|
341
|
+
'type': 'integer',
|
|
342
|
+
'required': False,
|
|
343
|
+
'description': 'Year for data',
|
|
344
|
+
'examples': [2020, 2021, 2022]
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
'get_population': {
|
|
349
|
+
'description': 'Get population estimates',
|
|
350
|
+
'parameters': {
|
|
351
|
+
'geography': {
|
|
352
|
+
'type': 'string',
|
|
353
|
+
'required': True,
|
|
354
|
+
'description': 'Geographic level specification',
|
|
355
|
+
'examples': ['state:*', 'state:06', 'county:*']
|
|
356
|
+
},
|
|
357
|
+
'year': {
|
|
358
|
+
'type': 'integer',
|
|
359
|
+
'required': False,
|
|
360
|
+
'description': 'Year for data',
|
|
361
|
+
'examples': [2020, 2021, 2022]
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
'get_economic_data': {
|
|
366
|
+
'description': 'Get economic indicators',
|
|
367
|
+
'parameters': {
|
|
368
|
+
'variables': {
|
|
369
|
+
'type': 'string',
|
|
370
|
+
'required': True,
|
|
371
|
+
'description': 'Comma-separated variable codes',
|
|
372
|
+
'examples': ['EMP', 'PAYANN', 'ESTAB']
|
|
373
|
+
},
|
|
374
|
+
'geography': {
|
|
375
|
+
'type': 'string',
|
|
376
|
+
'required': False,
|
|
377
|
+
'description': 'Geographic level specification',
|
|
378
|
+
'examples': ['state:*', 'county:*']
|
|
379
|
+
},
|
|
380
|
+
'year': {
|
|
381
|
+
'type': 'integer',
|
|
382
|
+
'required': False,
|
|
383
|
+
'description': 'Year for data',
|
|
384
|
+
'examples': [2020, 2021, 2022]
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
'list_datasets': {
|
|
389
|
+
'description': 'List all available datasets',
|
|
390
|
+
'parameters': {}
|
|
391
|
+
},
|
|
392
|
+
'list_variables': {
|
|
393
|
+
'description': 'List available variables',
|
|
394
|
+
'parameters': {
|
|
395
|
+
'dataset': {
|
|
396
|
+
'type': 'string',
|
|
397
|
+
'required': False,
|
|
398
|
+
'description': 'Dataset name',
|
|
399
|
+
'examples': ['acs/acs5', 'acs/acs1', 'pep/population']
|
|
400
|
+
},
|
|
401
|
+
'year': {
|
|
402
|
+
'type': 'integer',
|
|
403
|
+
'required': False,
|
|
404
|
+
'description': 'Year for dataset',
|
|
405
|
+
'examples': [2020, 2021, 2022]
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return schemas.get(operation)
|
|
412
|
+
|