hyperagents 1.2.3rc5.post3__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.
- agents/__init__.py +31 -0
- agents/background_monitor.py +453 -0
- agents/learning.py +460 -0
- agents/planner.py +421 -0
- agents/transcriber.py +341 -0
- civilization/__init__.py +51 -0
- civilization/api/__init__.py +7 -0
- civilization/api/civilization_api.py +361 -0
- civilization/graph/__init__.py +19 -0
- civilization/graph/knowledge_linker.py +348 -0
- civilization/graph/org_graph.py +348 -0
- civilization/graph/process_graph.py +386 -0
- civilization/ingestion/__init__.py +20 -0
- civilization/ingestion/chunker.py +273 -0
- civilization/ingestion/document_ingestor.py +358 -0
- civilization/ingestion/embedder.py +262 -0
- civilization/ingestion/extractor.py +224 -0
- civilization/interview/__init__.py +19 -0
- civilization/interview/gap_detector.py +380 -0
- civilization/interview/interviewer.py +323 -0
- civilization/interview/questioner.py +363 -0
- civilization/retrieval/__init__.py +17 -0
- civilization/retrieval/civilization_rag.py +316 -0
- civilization/retrieval/context_injector.py +342 -0
- civilization/retrieval/relevance_ranker.py +287 -0
- civilization/schema.py +299 -0
- civilization/store.py +177 -0
- civilization/sync/__init__.py +16 -0
- civilization/sync/confluence_sync.py +317 -0
- civilization/sync/gdrive_sync.py +262 -0
- civilization/sync/notion_sync.py +237 -0
- civilization/versioning/__init__.py +19 -0
- civilization/versioning/diff_engine.py +351 -0
- civilization/versioning/staleness_detector.py +303 -0
- civilization/versioning/version_manager.py +293 -0
- cli/__init__.py +1 -0
- cli/doctor.py +334 -0
- cli/hyperclaw.py +1357 -0
- cli/onboarding.py +469 -0
- core/__init__.py +1 -0
- core/connectors/__init__.py +119 -0
- core/connectors/infrastructure.py +772 -0
- core/connectors/messaging.py +586 -0
- core/connectors/productivity.py +764 -0
- core/connectors/smarthome.py +528 -0
- core/connectors/social.py +730 -0
- core/hyperrouter/__init__.py +23 -0
- core/hyperrouter/bandit.py +218 -0
- core/hyperrouter/fast_loop.py +68 -0
- core/hyperrouter/slow_loop.py +143 -0
- core/hyperstate/__init__.py +24 -0
- core/hyperstate/certifier.py +154 -0
- core/hyperstate/schema.py +160 -0
- core/hyperstate/state_manager.py +103 -0
- core/hyperstate/store.py +163 -0
- core/providers/__init__.py +121 -0
- core/providers/embeddings.py +389 -0
- core/providers/image.py +534 -0
- core/providers/llm.py +1935 -0
- core/providers/search.py +608 -0
- core/providers/voice.py +474 -0
- hyperagents-1.2.3rc5.post3.dist-info/METADATA +469 -0
- hyperagents-1.2.3rc5.post3.dist-info/RECORD +361 -0
- hyperagents-1.2.3rc5.post3.dist-info/WHEEL +5 -0
- hyperagents-1.2.3rc5.post3.dist-info/entry_points.txt +6 -0
- hyperagents-1.2.3rc5.post3.dist-info/licenses/LICENSE +21 -0
- hyperagents-1.2.3rc5.post3.dist-info/top_level.txt +13 -0
- hyperclaw/__init__.py +67 -0
- hyperclaw/__main__.py +220 -0
- hyperclaw/agent.py +775 -0
- hyperclaw/agent_coordinator.py +577 -0
- hyperclaw/anthropic_params.py +225 -0
- hyperclaw/api_utils.py +85 -0
- hyperclaw/approval_telegram.py +209 -0
- hyperclaw/approval_terminal.py +80 -0
- hyperclaw/attachments.py +177 -0
- hyperclaw/branding.py +55 -0
- hyperclaw/brief/__init__.py +11 -0
- hyperclaw/brief/cli.py +204 -0
- hyperclaw/brief/collect.py +146 -0
- hyperclaw/brief/compose.py +333 -0
- hyperclaw/brief/diff.py +110 -0
- hyperclaw/brief/errors.py +99 -0
- hyperclaw/brief/google.py +269 -0
- hyperclaw/brief/google_auth.py +294 -0
- hyperclaw/brief/links.py +124 -0
- hyperclaw/brief/service.py +424 -0
- hyperclaw/brief/store.py +205 -0
- hyperclaw/brief/tasks.py +200 -0
- hyperclaw/chat_scope.py +115 -0
- hyperclaw/cli_tui.py +497 -0
- hyperclaw/client_guard.py +717 -0
- hyperclaw/connection_check.py +113 -0
- hyperclaw/cost_guard.py +1728 -0
- hyperclaw/default_config/agents.yaml +534 -0
- hyperclaw/default_config/hyperclaw.yaml +27 -0
- hyperclaw/default_config/models.yaml +161 -0
- hyperclaw/deployment.py +39 -0
- hyperclaw/digest/__init__.py +9 -0
- hyperclaw/digest/cli.py +117 -0
- hyperclaw/digest/errors.py +100 -0
- hyperclaw/digest/gitlab.py +187 -0
- hyperclaw/digest/http.py +113 -0
- hyperclaw/digest/redact.py +32 -0
- hyperclaw/digest/service.py +271 -0
- hyperclaw/digest/slack.py +223 -0
- hyperclaw/digest/state.py +124 -0
- hyperclaw/digest/summarize.py +198 -0
- hyperclaw/digest/tokens.py +143 -0
- hyperclaw/distribution.py +46 -0
- hyperclaw/documents.py +351 -0
- hyperclaw/feeds.py +339 -0
- hyperclaw/google_workspace/__init__.py +5 -0
- hyperclaw/google_workspace/api.py +151 -0
- hyperclaw/google_workspace/auth.py +397 -0
- hyperclaw/google_workspace/calendar.py +157 -0
- hyperclaw/google_workspace/cli.py +72 -0
- hyperclaw/google_workspace/drive.py +236 -0
- hyperclaw/google_workspace/errors.py +58 -0
- hyperclaw/google_workspace/gmail.py +295 -0
- hyperclaw/google_workspace/meet.py +122 -0
- hyperclaw/google_workspace/tools.py +319 -0
- hyperclaw/hyperspeed.py +57 -0
- hyperclaw/integrations_layer.py +1427 -0
- hyperclaw/live_state.py +188 -0
- hyperclaw/managed_config.py +245 -0
- hyperclaw/media_hub.py +179 -0
- hyperclaw/memory_manager.py +584 -0
- hyperclaw/model_catalog.py +551 -0
- hyperclaw/model_policy.py +211 -0
- hyperclaw/model_router.py +595 -0
- hyperclaw/model_selector.py +72 -0
- hyperclaw/naming.py +284 -0
- hyperclaw/notices.py +65 -0
- hyperclaw/oai_stream.py +106 -0
- hyperclaw/orchestrator.py +591 -0
- hyperclaw/outbox.py +82 -0
- hyperclaw/persona.py +367 -0
- hyperclaw/prometheus.py +219 -0
- hyperclaw/prompt_assembly.py +157 -0
- hyperclaw/provider_setup.py +146 -0
- hyperclaw/providers.py +340 -0
- hyperclaw/qualification.py +341 -0
- hyperclaw/qualification_keys/hyper-d292fd127cef5a3e.pub +1 -0
- hyperclaw/qualification_records/anthropic--claude-sonnet-5-5.json +14 -0
- hyperclaw/reasoning_display.py +35 -0
- hyperclaw/scheduler.py +454 -0
- hyperclaw/server.py +847 -0
- hyperclaw/setup.py +627 -0
- hyperclaw/skills.py +717 -0
- hyperclaw/solomon.py +442 -0
- hyperclaw/swarm.py +533 -0
- hyperclaw/taint.py +832 -0
- hyperclaw/team/__init__.py +28 -0
- hyperclaw/team/dispatcher.py +431 -0
- hyperclaw/team/genesis.py +106 -0
- hyperclaw/team/lead.py +110 -0
- hyperclaw/team/model.py +135 -0
- hyperclaw/team/morning.py +238 -0
- hyperclaw/team/repos.py +66 -0
- hyperclaw/team/roster.py +264 -0
- hyperclaw/team/specialist.py +235 -0
- hyperclaw/team/status.py +163 -0
- hyperclaw/team/watchers.py +112 -0
- hyperclaw/teamsetup/__init__.py +17 -0
- hyperclaw/teamsetup/checks.py +208 -0
- hyperclaw/teamsetup/item.py +391 -0
- hyperclaw/teamsetup/oauth_loopback.py +84 -0
- hyperclaw/teamsetup/onboard.py +550 -0
- hyperclaw/teamsetup/profile.py +82 -0
- hyperclaw/teamsetup/secrets.py +313 -0
- hyperclaw/teamsetup/selfcheck.py +295 -0
- hyperclaw/teamsetup/service.py +495 -0
- hyperclaw/teamsetup/slack_oauth.py +442 -0
- hyperclaw/teamsetup/tty.py +62 -0
- hyperclaw/telegram_bot.py +1106 -0
- hyperclaw/telegram_intake.py +126 -0
- hyperclaw/telegram_pairing.py +360 -0
- hyperclaw/terminal_provider.py +323 -0
- hyperclaw/tools/__init__.py +1 -0
- hyperclaw/tools/approval.py +949 -0
- hyperclaw/tools/args.py +212 -0
- hyperclaw/tools/catalog.py +244 -0
- hyperclaw/tools/classify.py +266 -0
- hyperclaw/tools/effects.py +724 -0
- hyperclaw/tools/egress.py +210 -0
- hyperclaw/tools/envelope.py +188 -0
- hyperclaw/tools/guard.py +367 -0
- hyperclaw/tools/ledger.py +339 -0
- hyperclaw/tools/receipts.py +70 -0
- hyperclaw/tools/registry.py +318 -0
- hyperclaw/tools/service_guard.py +151 -0
- hyperclaw/tools/surfaces.py +54 -0
- hyperclaw/tools/workspace.py +87 -0
- hyperclaw/trading/__init__.py +77 -0
- hyperclaw/truth_guard.py +791 -0
- hyperclaw/tts.py +124 -0
- hyperclaw/tui.py +4255 -0
- hyperclaw/tui_bridge.py +938 -0
- hyperclaw/unattended.py +60 -0
- hyperclaw/updates/__init__.py +54 -0
- hyperclaw/updates/check.py +131 -0
- hyperclaw/updates/index.py +178 -0
- hyperclaw/updates/install.py +110 -0
- hyperclaw/updates/managed.py +161 -0
- hyperclaw/updates/manifest.py +138 -0
- hyperclaw/updates/notices.py +86 -0
- hyperclaw/updates/paths.py +53 -0
- hyperclaw/updates/release.py +146 -0
- hyperclaw/updates/upgrade.py +253 -0
- hyperclaw/updates/versioning.py +104 -0
- hyperclaw/userconfig.py +119 -0
- hyperclaw/xai.py +83 -0
- integrations/__init__.py +31 -0
- integrations/automation/__init__.py +1 -0
- integrations/automation/make.py +87 -0
- integrations/automation/zapier.py +87 -0
- integrations/base.py +476 -0
- integrations/communication/__init__.py +1 -0
- integrations/communication/twilio.py +279 -0
- integrations/communication/zoom.py +290 -0
- integrations/data/__init__.py +1 -0
- integrations/data/google_analytics.py +135 -0
- integrations/data/postgres.py +182 -0
- integrations/data/supabase_connector.py +202 -0
- integrations/data/weather_feeds.py +450 -0
- integrations/developer/__init__.py +9 -0
- integrations/developer/github.py +406 -0
- integrations/developer/gitlab.py +298 -0
- integrations/enterprise/__init__.py +13 -0
- integrations/enterprise/confluence.py +266 -0
- integrations/enterprise/hubspot.py +293 -0
- integrations/enterprise/jira.py +314 -0
- integrations/enterprise/salesforce.py +286 -0
- integrations/finance/__init__.py +1 -0
- integrations/finance/polymarket_client.py +247 -0
- integrations/finance/quickbooks.py +281 -0
- integrations/finance/stripe.py +261 -0
- integrations/gateway.py +238 -0
- integrations/messaging/__init__.py +32 -0
- integrations/messaging/discord.py +159 -0
- integrations/messaging/email.py +401 -0
- integrations/messaging/imessage.py +443 -0
- integrations/messaging/signal.py +175 -0
- integrations/messaging/slack.py +217 -0
- integrations/messaging/sms.py +175 -0
- integrations/messaging/teams.py +208 -0
- integrations/messaging/telegram.py +260 -0
- integrations/messaging/whatsapp.py +203 -0
- integrations/productivity/__init__.py +17 -0
- integrations/productivity/airtable.py +217 -0
- integrations/productivity/asana.py +248 -0
- integrations/productivity/google/__init__.py +19 -0
- integrations/productivity/google/base.py +89 -0
- integrations/productivity/google/calendar.py +272 -0
- integrations/productivity/google/docs.py +202 -0
- integrations/productivity/google/drive.py +268 -0
- integrations/productivity/google/gmail.py +279 -0
- integrations/productivity/google/meet.py +218 -0
- integrations/productivity/google/sheets.py +222 -0
- integrations/productivity/google/tasks.py +199 -0
- integrations/productivity/linear.py +279 -0
- integrations/productivity/microsoft/__init__.py +13 -0
- integrations/productivity/microsoft/base.py +93 -0
- integrations/productivity/microsoft/calendar.py +207 -0
- integrations/productivity/microsoft/onedrive.py +222 -0
- integrations/productivity/microsoft/outlook.py +241 -0
- integrations/productivity/microsoft/sharepoint.py +211 -0
- integrations/productivity/notion.py +243 -0
- integrations/productivity/todoist.py +250 -0
- integrations/productivity/trello.py +244 -0
- integrations/storage/__init__.py +1 -0
- integrations/storage/box.py +279 -0
- integrations/storage/dropbox.py +215 -0
- integrations/telegram_inbound.py +179 -0
- integrations/telegram_poller.py +151 -0
- memory/__init__.py +1 -0
- memory/causal_graph.py +125 -0
- memory/impact_tracker.py +88 -0
- memory/vector_memory.py +436 -0
- models/__init__.py +12 -0
- models/chatjimmy_client.py +210 -0
- models/claude_client.py +235 -0
- models/claude_code_subagent.py +192 -0
- models/openai_client.py +120 -0
- models/router.py +162 -0
- recursive/discovery_loop.py +118 -0
- recursive/optimization_loop.py +135 -0
- recursive/validation_loop.py +38 -0
- security/__init__.py +1 -0
- security/audit_logger.py +106 -0
- security/filesystem_guard.py +100 -0
- security/hypershield.py +99 -0
- security/network_guard.py +97 -0
- security/policy_engine.py +198 -0
- swarm/__init__.py +1 -0
- swarm/agents/__init__.py +0 -0
- swarm/agents/base.py +230 -0
- swarm/agents/business/__init__.py +0 -0
- swarm/agents/business/counsel.py +31 -0
- swarm/agents/business/herald.py +32 -0
- swarm/agents/business/ledger.py +26 -0
- swarm/agents/business/nexus.py +30 -0
- swarm/agents/business/ops.py +30 -0
- swarm/agents/business/pipeline.py +28 -0
- swarm/agents/business/revenue.py +30 -0
- swarm/agents/business/sovereign.py +31 -0
- swarm/agents/business/strategos.py +27 -0
- swarm/agents/business/talent.py +27 -0
- swarm/agents/business/venture.py +32 -0
- swarm/agents/comms/__init__.py +1 -0
- swarm/agents/comms/cipher.py +32 -0
- swarm/agents/comms/echo_comms.py +31 -0
- swarm/agents/comms/envoy.py +31 -0
- swarm/agents/comms/herald_scheduler.py +33 -0
- swarm/agents/comms/pulse.py +29 -0
- swarm/agents/creative/__init__.py +0 -0
- swarm/agents/creative/author.py +27 -0
- swarm/agents/creative/lens.py +25 -0
- swarm/agents/executive/__init__.py +1 -0
- swarm/agents/intelligence/__init__.py +1 -0
- swarm/agents/intelligence/arbiter.py +30 -0
- swarm/agents/intelligence/sentinel.py +30 -0
- swarm/agents/media/__init__.py +0 -0
- swarm/agents/personal/__init__.py +0 -0
- swarm/agents/personal/atlas.py +27 -0
- swarm/agents/personal/hearth.py +26 -0
- swarm/agents/personal/midas.py +27 -0
- swarm/agents/personal/navigator.py +27 -0
- swarm/agents/personal/nourish.py +31 -0
- swarm/agents/personal/vitals.py +33 -0
- swarm/agents/recursive/__init__.py +0 -0
- swarm/agents/recursive/alchemist.py +73 -0
- swarm/agents/recursive/calibrator.py +45 -0
- swarm/agents/recursive/scout.py +97 -0
- swarm/agents/scientific/__init__.py +0 -0
- swarm/agents/scientific/cosmos.py +36 -0
- swarm/agents/scientific/gaia.py +26 -0
- swarm/agents/scientific/medicus.py +33 -0
- swarm/agents/scientific/oracle_agent.py +39 -0
- swarm/agents/scientific/scribe.py +39 -0
- swarm/agents/talent/__init__.py +0 -0
- swarm/agents/talent/deal.py +28 -0
- swarm/agents/talent/roster.py +29 -0
- swarm/agents/talent/scout.py +29 -0
- swarm/agents/talent/stage.py +27 -0
- swarm/agents/tech/__init__.py +0 -0
- swarm/agents/tech/aegis.py +28 -0
- swarm/agents/tech/bridge.py +28 -0
- swarm/agents/tech/forge.py +28 -0
- swarm/agents/trading/__init__.py +1 -0
- swarm/agents/trading/global_prediction_engine.py +611 -0
- swarm/agents/trading/polymarket_trader.py +165 -0
- swarm/agents/trading/prediction_strategist.py +218 -0
- swarm/autogen_bridge.py +68 -0
- swarm/bid_protocol.py +196 -0
- swarm/dispatcher.py +527 -0
- swarm/nexus.py +181 -0
- swarm/registry.py +112 -0
- telegram_listener.py +403 -0
- ui/tui/app.py +214 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
"""Weather & Agricultural Data Feeds — Global data integration for prediction markets."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import asyncio
|
|
4
|
+
import httpx
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Dict, List, Optional, Any
|
|
7
|
+
from datetime import datetime, timedelta
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger("weather_feeds")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class WeatherIntelligence:
|
|
14
|
+
"""Global weather and agricultural data aggregation for prediction advantage."""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.session = None
|
|
18
|
+
|
|
19
|
+
# Multiple weather API endpoints for redundancy
|
|
20
|
+
self.apis = {
|
|
21
|
+
"openweather": {
|
|
22
|
+
"url": "https://api.openweathermap.org/data/2.5",
|
|
23
|
+
"key": None # Will need API key
|
|
24
|
+
},
|
|
25
|
+
"weatherapi": {
|
|
26
|
+
"url": "https://api.weatherapi.com/v1",
|
|
27
|
+
"key": None # Alternative source
|
|
28
|
+
},
|
|
29
|
+
"noaa": {
|
|
30
|
+
"url": "https://api.weather.gov", # US government, free
|
|
31
|
+
"key": None
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Critical agricultural regions for crop predictions
|
|
36
|
+
self.crop_regions = {
|
|
37
|
+
"corn_belt": {
|
|
38
|
+
"name": "US Corn Belt",
|
|
39
|
+
"coords": [(41.8781, -87.6298), (40.7589, -89.6465), (42.0308, -93.6319)],
|
|
40
|
+
"primary_crops": ["corn", "soybeans"],
|
|
41
|
+
"markets": ["corn prices", "soybean futures", "food inflation"]
|
|
42
|
+
},
|
|
43
|
+
"wheat_belt": {
|
|
44
|
+
"name": "Great Plains Wheat",
|
|
45
|
+
"coords": [(39.7392, -104.9903), (37.6872, -97.3301), (46.8083, -100.7837)],
|
|
46
|
+
"primary_crops": ["wheat", "barley"],
|
|
47
|
+
"markets": ["wheat prices", "grain exports", "food security"]
|
|
48
|
+
},
|
|
49
|
+
"ukraine_farming": {
|
|
50
|
+
"name": "Ukrainian Agricultural Region",
|
|
51
|
+
"coords": [(50.4501, 30.5234), (48.3794, 31.1656), (49.9935, 36.2304)],
|
|
52
|
+
"primary_crops": ["wheat", "corn", "sunflower"],
|
|
53
|
+
"markets": ["global grain supply", "food crisis", "ukraine conflict impact"]
|
|
54
|
+
},
|
|
55
|
+
"brazil_soy": {
|
|
56
|
+
"name": "Brazilian Soy Belt",
|
|
57
|
+
"coords": [(-15.7975, -47.8919), (-16.6869, -49.2648), (-14.2350, -51.9253)],
|
|
58
|
+
"primary_crops": ["soybeans", "corn", "cotton"],
|
|
59
|
+
"markets": ["soy exports", "deforestation", "brazil politics"]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async def __aenter__(self):
|
|
64
|
+
self.session = httpx.AsyncClient(timeout=30.0)
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
68
|
+
if self.session:
|
|
69
|
+
await self.session.aclose()
|
|
70
|
+
|
|
71
|
+
async def get_regional_weather_analysis(self, region: str) -> Dict:
|
|
72
|
+
"""Analyze weather conditions for agricultural regions."""
|
|
73
|
+
if region not in self.crop_regions:
|
|
74
|
+
return {"error": f"Unknown region: {region}"}
|
|
75
|
+
|
|
76
|
+
region_data = self.crop_regions[region]
|
|
77
|
+
weather_summary = []
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
# Sample multiple coordinates within region
|
|
81
|
+
for coord in region_data["coords"][:3]: # Limit to avoid rate limits
|
|
82
|
+
lat, lon = coord
|
|
83
|
+
weather = await self._get_location_weather(lat, lon)
|
|
84
|
+
if weather:
|
|
85
|
+
weather_summary.append(weather)
|
|
86
|
+
|
|
87
|
+
if not weather_summary:
|
|
88
|
+
return {"error": "No weather data available"}
|
|
89
|
+
|
|
90
|
+
# Aggregate regional conditions
|
|
91
|
+
analysis = self._analyze_agricultural_impact(weather_summary, region_data)
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
"region": region_data["name"],
|
|
95
|
+
"primary_crops": region_data["primary_crops"],
|
|
96
|
+
"affected_markets": region_data["markets"],
|
|
97
|
+
"weather_analysis": analysis,
|
|
98
|
+
"prediction_signals": self._generate_prediction_signals(analysis, region_data),
|
|
99
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(f"Error analyzing region {region}: {e}")
|
|
104
|
+
return {"error": str(e)}
|
|
105
|
+
|
|
106
|
+
async def _get_location_weather(self, lat: float, lon: float) -> Optional[Dict]:
|
|
107
|
+
"""Fetch weather data for specific coordinates."""
|
|
108
|
+
try:
|
|
109
|
+
# Using NOAA (free, US government data)
|
|
110
|
+
if -90 <= lat <= 90 and -180 <= lon <= 180:
|
|
111
|
+
# For US locations, use NOAA
|
|
112
|
+
if 25 <= lat <= 49 and -125 <= lon <= -66:
|
|
113
|
+
return await self._fetch_noaa_weather(lat, lon)
|
|
114
|
+
|
|
115
|
+
# Fallback: simulate weather data for demo
|
|
116
|
+
return self._generate_sample_weather(lat, lon)
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.error(f"Error fetching weather for {lat}, {lon}: {e}")
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
async def _fetch_noaa_weather(self, lat: float, lon: float) -> Optional[Dict]:
|
|
123
|
+
"""Fetch from NOAA API (US locations)."""
|
|
124
|
+
try:
|
|
125
|
+
# Get grid point
|
|
126
|
+
response = await self.session.get(
|
|
127
|
+
f"{self.apis['noaa']['url']}/points/{lat},{lon}"
|
|
128
|
+
)
|
|
129
|
+
response.raise_for_status()
|
|
130
|
+
|
|
131
|
+
data = response.json()
|
|
132
|
+
forecast_url = data["properties"]["forecast"]
|
|
133
|
+
|
|
134
|
+
# Get forecast
|
|
135
|
+
forecast_response = await self.session.get(forecast_url)
|
|
136
|
+
forecast_response.raise_for_status()
|
|
137
|
+
|
|
138
|
+
forecast_data = forecast_response.json()
|
|
139
|
+
periods = forecast_data["properties"]["periods"][:7] # 7 days
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
"source": "NOAA",
|
|
143
|
+
"lat": lat,
|
|
144
|
+
"lon": lon,
|
|
145
|
+
"forecast": periods,
|
|
146
|
+
"alerts": data.get("properties", {}).get("alerts", [])
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
except Exception as e:
|
|
150
|
+
logger.error(f"NOAA fetch error: {e}")
|
|
151
|
+
return self._generate_sample_weather(lat, lon)
|
|
152
|
+
|
|
153
|
+
def _generate_sample_weather(self, lat: float, lon: float) -> Dict:
|
|
154
|
+
"""Generate representative weather data for analysis."""
|
|
155
|
+
import random
|
|
156
|
+
|
|
157
|
+
# Seasonal adjustment based on month
|
|
158
|
+
month = datetime.now().month
|
|
159
|
+
|
|
160
|
+
if 3 <= month <= 5: # Spring
|
|
161
|
+
temp_base = 15
|
|
162
|
+
precip_chance = 0.4
|
|
163
|
+
elif 6 <= month <= 8: # Summer
|
|
164
|
+
temp_base = 25
|
|
165
|
+
precip_chance = 0.3
|
|
166
|
+
elif 9 <= month <= 11: # Fall
|
|
167
|
+
temp_base = 12
|
|
168
|
+
precip_chance = 0.5
|
|
169
|
+
else: # Winter
|
|
170
|
+
temp_base = 5
|
|
171
|
+
precip_chance = 0.4
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
"source": "simulated",
|
|
175
|
+
"lat": lat,
|
|
176
|
+
"lon": lon,
|
|
177
|
+
"current": {
|
|
178
|
+
"temperature": temp_base + random.uniform(-5, 10),
|
|
179
|
+
"humidity": random.uniform(40, 80),
|
|
180
|
+
"precipitation_mm": random.uniform(0, 20) if random.random() < precip_chance else 0,
|
|
181
|
+
"wind_speed": random.uniform(5, 25),
|
|
182
|
+
"pressure": random.uniform(1000, 1020)
|
|
183
|
+
},
|
|
184
|
+
"forecast_7day": {
|
|
185
|
+
"avg_temp": temp_base + random.uniform(-3, 8),
|
|
186
|
+
"total_precipitation": random.uniform(0, 50),
|
|
187
|
+
"extreme_weather_risk": random.choice(["low", "medium", "high"]),
|
|
188
|
+
"growing_conditions": random.choice(["poor", "fair", "good", "excellent"])
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
def _analyze_agricultural_impact(self, weather_data: List[Dict], region_info: Dict) -> Dict:
|
|
193
|
+
"""Analyze weather impact on agricultural production."""
|
|
194
|
+
if not weather_data:
|
|
195
|
+
return {}
|
|
196
|
+
|
|
197
|
+
# Aggregate weather metrics
|
|
198
|
+
temperatures = []
|
|
199
|
+
precipitation = []
|
|
200
|
+
extreme_risks = []
|
|
201
|
+
|
|
202
|
+
for location in weather_data:
|
|
203
|
+
if "current" in location:
|
|
204
|
+
temperatures.append(location["current"]["temperature"])
|
|
205
|
+
precipitation.append(location["current"]["precipitation_mm"])
|
|
206
|
+
|
|
207
|
+
if "forecast_7day" in location:
|
|
208
|
+
extreme_risks.append(location["forecast_7day"]["extreme_weather_risk"])
|
|
209
|
+
|
|
210
|
+
avg_temp = sum(temperatures) / len(temperatures) if temperatures else 15
|
|
211
|
+
total_precip = sum(precipitation) if precipitation else 0
|
|
212
|
+
|
|
213
|
+
# Assess agricultural conditions
|
|
214
|
+
analysis = {
|
|
215
|
+
"temperature_analysis": {
|
|
216
|
+
"average": avg_temp,
|
|
217
|
+
"status": self._assess_temperature_impact(avg_temp, region_info["primary_crops"])
|
|
218
|
+
},
|
|
219
|
+
"precipitation_analysis": {
|
|
220
|
+
"total_mm": total_precip,
|
|
221
|
+
"status": self._assess_precipitation_impact(total_precip, region_info["primary_crops"])
|
|
222
|
+
},
|
|
223
|
+
"overall_conditions": self._calculate_overall_conditions(avg_temp, total_precip),
|
|
224
|
+
"crop_stress_indicators": self._identify_stress_factors(avg_temp, total_precip, extreme_risks),
|
|
225
|
+
"market_impact_probability": self._estimate_market_impact(avg_temp, total_precip, extreme_risks)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return analysis
|
|
229
|
+
|
|
230
|
+
def _assess_temperature_impact(self, temp: float, crops: List[str]) -> str:
|
|
231
|
+
"""Assess temperature impact on specific crops."""
|
|
232
|
+
# Corn optimal: 20-30°C, Soybeans: 20-25°C, Wheat: 15-25°C
|
|
233
|
+
optimal_ranges = {
|
|
234
|
+
"corn": (20, 30),
|
|
235
|
+
"soybeans": (20, 25),
|
|
236
|
+
"wheat": (15, 25),
|
|
237
|
+
"cotton": (21, 27),
|
|
238
|
+
"barley": (15, 20)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
impacts = []
|
|
242
|
+
for crop in crops:
|
|
243
|
+
if crop in optimal_ranges:
|
|
244
|
+
min_temp, max_temp = optimal_ranges[crop]
|
|
245
|
+
if min_temp <= temp <= max_temp:
|
|
246
|
+
impacts.append("optimal")
|
|
247
|
+
elif temp < min_temp - 5 or temp > max_temp + 5:
|
|
248
|
+
impacts.append("stress")
|
|
249
|
+
else:
|
|
250
|
+
impacts.append("suboptimal")
|
|
251
|
+
else:
|
|
252
|
+
impacts.append("unknown")
|
|
253
|
+
|
|
254
|
+
if "stress" in impacts:
|
|
255
|
+
return "stress_conditions"
|
|
256
|
+
elif "optimal" in impacts:
|
|
257
|
+
return "favorable_conditions"
|
|
258
|
+
else:
|
|
259
|
+
return "neutral_conditions"
|
|
260
|
+
|
|
261
|
+
def _assess_precipitation_impact(self, precip: float, crops: List[str]) -> str:
|
|
262
|
+
"""Assess precipitation impact on crops."""
|
|
263
|
+
if precip < 5:
|
|
264
|
+
return "drought_risk"
|
|
265
|
+
elif precip > 40:
|
|
266
|
+
return "flood_risk"
|
|
267
|
+
elif 15 <= precip <= 25:
|
|
268
|
+
return "optimal_moisture"
|
|
269
|
+
else:
|
|
270
|
+
return "adequate_moisture"
|
|
271
|
+
|
|
272
|
+
def _calculate_overall_conditions(self, temp: float, precip: float) -> str:
|
|
273
|
+
"""Calculate overall agricultural conditions score."""
|
|
274
|
+
temp_score = 5 # Neutral baseline
|
|
275
|
+
precip_score = 5
|
|
276
|
+
|
|
277
|
+
# Temperature scoring (5 = optimal)
|
|
278
|
+
if 18 <= temp <= 27:
|
|
279
|
+
temp_score = 5
|
|
280
|
+
elif 15 <= temp < 18 or 27 < temp <= 32:
|
|
281
|
+
temp_score = 4
|
|
282
|
+
elif temp < 10 or temp > 35:
|
|
283
|
+
temp_score = 1
|
|
284
|
+
else:
|
|
285
|
+
temp_score = 3
|
|
286
|
+
|
|
287
|
+
# Precipitation scoring
|
|
288
|
+
if 15 <= precip <= 25:
|
|
289
|
+
precip_score = 5
|
|
290
|
+
elif 10 <= precip < 15 or 25 < precip <= 35:
|
|
291
|
+
precip_score = 4
|
|
292
|
+
elif precip < 5 or precip > 50:
|
|
293
|
+
precip_score = 1
|
|
294
|
+
else:
|
|
295
|
+
precip_score = 3
|
|
296
|
+
|
|
297
|
+
overall = (temp_score + precip_score) / 2
|
|
298
|
+
|
|
299
|
+
if overall >= 4.5:
|
|
300
|
+
return "excellent"
|
|
301
|
+
elif overall >= 3.5:
|
|
302
|
+
return "good"
|
|
303
|
+
elif overall >= 2.5:
|
|
304
|
+
return "fair"
|
|
305
|
+
else:
|
|
306
|
+
return "poor"
|
|
307
|
+
|
|
308
|
+
def _identify_stress_factors(self, temp: float, precip: float, extreme_risks: List[str]) -> List[str]:
|
|
309
|
+
"""Identify stress factors affecting crop production."""
|
|
310
|
+
stress_factors = []
|
|
311
|
+
|
|
312
|
+
if temp > 32:
|
|
313
|
+
stress_factors.append("heat_stress")
|
|
314
|
+
if temp < 10:
|
|
315
|
+
stress_factors.append("cold_stress")
|
|
316
|
+
if precip < 5:
|
|
317
|
+
stress_factors.append("drought_stress")
|
|
318
|
+
if precip > 40:
|
|
319
|
+
stress_factors.append("waterlog_stress")
|
|
320
|
+
if "high" in extreme_risks:
|
|
321
|
+
stress_factors.append("extreme_weather_risk")
|
|
322
|
+
|
|
323
|
+
return stress_factors
|
|
324
|
+
|
|
325
|
+
def _estimate_market_impact(self, temp: float, precip: float, extreme_risks: List[str]) -> float:
|
|
326
|
+
"""Estimate probability of significant market impact (0-1)."""
|
|
327
|
+
impact_score = 0.0
|
|
328
|
+
|
|
329
|
+
# Temperature extremes
|
|
330
|
+
if temp > 35 or temp < 5:
|
|
331
|
+
impact_score += 0.3
|
|
332
|
+
elif temp > 30 or temp < 10:
|
|
333
|
+
impact_score += 0.1
|
|
334
|
+
|
|
335
|
+
# Precipitation extremes
|
|
336
|
+
if precip > 50 or precip < 2:
|
|
337
|
+
impact_score += 0.3
|
|
338
|
+
elif precip > 35 or precip < 8:
|
|
339
|
+
impact_score += 0.1
|
|
340
|
+
|
|
341
|
+
# Extreme weather
|
|
342
|
+
high_risk_count = extreme_risks.count("high")
|
|
343
|
+
impact_score += high_risk_count * 0.2
|
|
344
|
+
|
|
345
|
+
return min(impact_score, 1.0) # Cap at 100%
|
|
346
|
+
|
|
347
|
+
def _generate_prediction_signals(self, analysis: Dict, region_info: Dict) -> List[Dict]:
|
|
348
|
+
"""Generate specific prediction market signals from weather analysis."""
|
|
349
|
+
signals = []
|
|
350
|
+
|
|
351
|
+
overall_conditions = analysis.get("overall_conditions", "fair")
|
|
352
|
+
market_impact_prob = analysis.get("market_impact_probability", 0.0)
|
|
353
|
+
stress_factors = analysis.get("crop_stress_indicators", [])
|
|
354
|
+
|
|
355
|
+
# Generate signals for each affected market
|
|
356
|
+
for market in region_info.get("affected_markets", []):
|
|
357
|
+
signal_strength = self._calculate_signal_strength(
|
|
358
|
+
overall_conditions, market_impact_prob, stress_factors, market
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
direction = self._determine_market_direction(
|
|
362
|
+
overall_conditions, stress_factors, market
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
if signal_strength > 0.3: # Only significant signals
|
|
366
|
+
signals.append({
|
|
367
|
+
"market_category": market,
|
|
368
|
+
"signal_strength": signal_strength,
|
|
369
|
+
"direction": direction,
|
|
370
|
+
"confidence": min(signal_strength * 0.8, 0.95),
|
|
371
|
+
"reasoning": self._explain_signal_reasoning(
|
|
372
|
+
overall_conditions, stress_factors, market, direction
|
|
373
|
+
)
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
return signals
|
|
377
|
+
|
|
378
|
+
def _calculate_signal_strength(self, conditions: str, impact_prob: float,
|
|
379
|
+
stress_factors: List[str], market: str) -> float:
|
|
380
|
+
"""Calculate signal strength for specific market."""
|
|
381
|
+
base_strength = {
|
|
382
|
+
"excellent": 0.2,
|
|
383
|
+
"good": 0.1,
|
|
384
|
+
"fair": 0.05,
|
|
385
|
+
"poor": 0.4
|
|
386
|
+
}.get(conditions, 0.05)
|
|
387
|
+
|
|
388
|
+
# Boost for high impact probability
|
|
389
|
+
impact_boost = impact_prob * 0.3
|
|
390
|
+
|
|
391
|
+
# Boost for stress factors
|
|
392
|
+
stress_boost = len(stress_factors) * 0.1
|
|
393
|
+
|
|
394
|
+
return min(base_strength + impact_boost + stress_boost, 1.0)
|
|
395
|
+
|
|
396
|
+
def _determine_market_direction(self, conditions: str, stress_factors: List[str],
|
|
397
|
+
market: str) -> str:
|
|
398
|
+
"""Determine expected market direction."""
|
|
399
|
+
if any(stress in stress_factors for stress in ["drought_stress", "heat_stress", "extreme_weather_risk"]):
|
|
400
|
+
if "price" in market.lower() or "inflation" in market.lower():
|
|
401
|
+
return "bullish" # Stress → higher prices
|
|
402
|
+
elif "supply" in market.lower():
|
|
403
|
+
return "bearish" # Stress → lower supply
|
|
404
|
+
|
|
405
|
+
if conditions in ["excellent", "good"]:
|
|
406
|
+
if "price" in market.lower():
|
|
407
|
+
return "bearish" # Good conditions → lower prices
|
|
408
|
+
elif "supply" in market.lower():
|
|
409
|
+
return "bullish" # Good conditions → higher supply
|
|
410
|
+
|
|
411
|
+
return "neutral"
|
|
412
|
+
|
|
413
|
+
def _explain_signal_reasoning(self, conditions: str, stress_factors: List[str],
|
|
414
|
+
market: str, direction: str) -> str:
|
|
415
|
+
"""Generate human-readable reasoning for signal."""
|
|
416
|
+
if direction == "bullish" and "price" in market.lower():
|
|
417
|
+
return f"Weather stress factors {stress_factors} likely to reduce crop yields, driving prices higher"
|
|
418
|
+
elif direction == "bearish" and "price" in market.lower():
|
|
419
|
+
return f"Favorable conditions ({conditions}) suggest good yields, likely suppressing prices"
|
|
420
|
+
elif direction == "bullish" and "supply" in market.lower():
|
|
421
|
+
return f"Good weather conditions ({conditions}) support strong crop production"
|
|
422
|
+
elif direction == "bearish" and "supply" in market.lower():
|
|
423
|
+
return f"Weather stress {stress_factors} threatens crop production levels"
|
|
424
|
+
else:
|
|
425
|
+
return f"Weather analysis ({conditions}) provides moderate signal for {market}"
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
async def test_weather_intelligence():
|
|
429
|
+
"""Test weather data integration."""
|
|
430
|
+
async with WeatherIntelligence() as weather:
|
|
431
|
+
# Test corn belt analysis
|
|
432
|
+
analysis = await weather.get_regional_weather_analysis("corn_belt")
|
|
433
|
+
|
|
434
|
+
print("=== CORN BELT WEATHER ANALYSIS ===")
|
|
435
|
+
print(f"Region: {analysis.get('region')}")
|
|
436
|
+
print(f"Crops: {analysis.get('primary_crops')}")
|
|
437
|
+
print(f"Overall Conditions: {analysis.get('weather_analysis', {}).get('overall_conditions')}")
|
|
438
|
+
|
|
439
|
+
signals = analysis.get('prediction_signals', [])
|
|
440
|
+
print(f"\n=== PREDICTION SIGNALS ({len(signals)} found) ===")
|
|
441
|
+
|
|
442
|
+
for signal in signals:
|
|
443
|
+
print(f"\nMarket: {signal['market_category']}")
|
|
444
|
+
print(f"Direction: {signal['direction']}")
|
|
445
|
+
print(f"Strength: {signal['signal_strength']:.2f}")
|
|
446
|
+
print(f"Reasoning: {signal['reasoning']}")
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
if __name__ == "__main__":
|
|
450
|
+
asyncio.run(test_weather_intelligence())
|