deepmap-mcp 0.2.0__tar.gz
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.
- deepmap_mcp-0.2.0/.gitignore +65 -0
- deepmap_mcp-0.2.0/PKG-INFO +111 -0
- deepmap_mcp-0.2.0/README_MCP.md +91 -0
- deepmap_mcp-0.2.0/pyproject.toml +37 -0
- deepmap_mcp-0.2.0/volcanosafe/__init__.py +2 -0
- deepmap_mcp-0.2.0/volcanosafe/__main__.py +4 -0
- deepmap_mcp-0.2.0/volcanosafe/api.py +376 -0
- deepmap_mcp-0.2.0/volcanosafe/mcp_server.py +543 -0
- deepmap_mcp-0.2.0/volcanosafe/risk_engine.py +587 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.eggs/
|
|
8
|
+
*.egg
|
|
9
|
+
|
|
10
|
+
# Virtual environment
|
|
11
|
+
venv/
|
|
12
|
+
.venv/
|
|
13
|
+
env/
|
|
14
|
+
|
|
15
|
+
# IDE
|
|
16
|
+
.vscode/
|
|
17
|
+
.idea/
|
|
18
|
+
*.swp
|
|
19
|
+
*.swo
|
|
20
|
+
|
|
21
|
+
# Data (862 MB -- regenerate with trainers/fetchers, NOT stored in git)
|
|
22
|
+
# Run: python overnight_trainer.py OR python -m data_pipeline.scheduler --once
|
|
23
|
+
data/
|
|
24
|
+
!data/README.md
|
|
25
|
+
*.h5
|
|
26
|
+
*.hdf5
|
|
27
|
+
*.segy
|
|
28
|
+
*.sgy
|
|
29
|
+
*.mseed
|
|
30
|
+
*.nc
|
|
31
|
+
*.db
|
|
32
|
+
|
|
33
|
+
# Output
|
|
34
|
+
outputs/
|
|
35
|
+
*.png
|
|
36
|
+
*.html
|
|
37
|
+
!demo_landing.html
|
|
38
|
+
!volcanosafe/landing.html
|
|
39
|
+
*.pdf
|
|
40
|
+
|
|
41
|
+
# Trained Models (TRADE SECRET - never commit weights)
|
|
42
|
+
models/
|
|
43
|
+
*.joblib
|
|
44
|
+
*.pkl
|
|
45
|
+
*.onnx
|
|
46
|
+
|
|
47
|
+
# Secrets
|
|
48
|
+
.env
|
|
49
|
+
*.key
|
|
50
|
+
credentials/
|
|
51
|
+
|
|
52
|
+
# IP-sensitive docs (keep local only)
|
|
53
|
+
IP_STRATEGY.md
|
|
54
|
+
IP_STRATEGY.docx
|
|
55
|
+
|
|
56
|
+
# Word temp files
|
|
57
|
+
~$*.docx
|
|
58
|
+
|
|
59
|
+
# OS
|
|
60
|
+
.DS_Store
|
|
61
|
+
Thumbs.db
|
|
62
|
+
|
|
63
|
+
# Claude
|
|
64
|
+
.claude/
|
|
65
|
+
.vercel
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deepmap-mcp
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: DeepMap AI MCP Server - Real-time volcano monitoring, earthquake prediction, seismic risk, and geophysical intelligence for Claude and MCP-compatible LLMs
|
|
5
|
+
Project-URL: Homepage, https://deepmap.ai
|
|
6
|
+
Project-URL: Documentation, https://api.volcanosafe.com/docs
|
|
7
|
+
Project-URL: Repository, https://deepmapai.com
|
|
8
|
+
Author-email: DeepMap AI <info@deepmapai.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: claude,deepmap,earthquake,geophysics,mcp,risk,safety,seismic,volcano
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: httpx>=0.25
|
|
18
|
+
Requires-Dist: mcp>=1.0
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# DeepMap AI MCP Server
|
|
22
|
+
|
|
23
|
+
Real-time volcano monitoring, earthquake prediction, and geophysical intelligence as a [Model Context Protocol](https://modelcontextprotocol.io/) server.
|
|
24
|
+
Gives Claude (and any MCP-compatible LLM) direct access to live volcanic risk scores,
|
|
25
|
+
earthquake predictions, seismic risk assessments, tidal forcing analysis,
|
|
26
|
+
flight disruption forecasts, tidal eruption windows, LiDAR fault detection, and travel advisories.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install deepmap-mcp
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Configure for Claude Desktop
|
|
35
|
+
|
|
36
|
+
Add the following to your `claude_desktop_config.json`:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"deepmap": {
|
|
42
|
+
"command": "python",
|
|
43
|
+
"args": ["-m", "volcanosafe.mcp_server"],
|
|
44
|
+
"env": {
|
|
45
|
+
"DEEPMAP_API_URL": "https://api.volcanosafe.com",
|
|
46
|
+
"DEEPMAP_API_KEY": "dm_live_..."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or run directly from the command line:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
deepmap-mcp
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Available Tools
|
|
60
|
+
|
|
61
|
+
### Volcano Tools
|
|
62
|
+
|
|
63
|
+
| Tool | Description |
|
|
64
|
+
|------|-------------|
|
|
65
|
+
| `volcano_risk` | Full real-time risk assessment with seismic data, tidal state, travel advisory, and flight impact |
|
|
66
|
+
| `volcano_quick` | Low-latency risk score without live seismic fetch -- ideal for batch or insurance queries |
|
|
67
|
+
| `volcano_flights` | Flight disruption risk for airports near a volcano |
|
|
68
|
+
| `volcano_tidal_forecast` | Tidal eruption risk window forecast based on Mf tidal cycle analysis |
|
|
69
|
+
| `volcano_advisory` | Plain-text travel advisory with insurance recommendation and monitoring agency status |
|
|
70
|
+
| `volcano_list` | List all monitored volcanoes with names, countries, coordinates, and last eruption dates |
|
|
71
|
+
| `volcano_batch` | Quick risk scores for multiple volcanoes at once (max 10 per request) |
|
|
72
|
+
|
|
73
|
+
### Earthquake Tools
|
|
74
|
+
|
|
75
|
+
| Tool | Description |
|
|
76
|
+
|------|-------------|
|
|
77
|
+
| `predict_earthquake` | ML earthquake risk prediction for a region using GradientBoosting trained on real USGS data. Returns risk score, confidence, and contributing features |
|
|
78
|
+
| `list_earthquake_regions` | List all supported earthquake monitoring regions with bounds, historical rate, and magnitude of completeness |
|
|
79
|
+
| `assess_current_earthquakes` | Current global seismic risk assessment across all monitored regions using live USGS data |
|
|
80
|
+
| `earthquake_alert_cycle` | Full alert cycle across all monitored regions with triggered alerts and recommended actions |
|
|
81
|
+
| `predict_seismic_risk` | Seismic hazard risk score (0-10) for any lat/lon combining Vs30 site classification, liquefaction probability, and amplification factor |
|
|
82
|
+
| `analyze_tidal_forcing` | Tidal stress forcing analysis on earthquake triggering using Schuster's test and Rayleigh statistics |
|
|
83
|
+
| `detect_fault_scarps` | LiDAR/3DEP slope-break fault scarp detection with strike, dip direction, and length estimates |
|
|
84
|
+
|
|
85
|
+
### Supported Earthquake Regions
|
|
86
|
+
|
|
87
|
+
| Region Key | Name |
|
|
88
|
+
|------------|------|
|
|
89
|
+
| `ucerf3` | Southern California (UCERF3) |
|
|
90
|
+
| `new_madrid` | New Madrid Seismic Zone |
|
|
91
|
+
| `cascadia` | Cascadia Subduction Zone |
|
|
92
|
+
| `wasatch` | Wasatch Front (Utah) |
|
|
93
|
+
| `oklahoma` | Oklahoma (Induced) |
|
|
94
|
+
| `trans_mexico` | Trans-Mexican Volcanic Belt |
|
|
95
|
+
|
|
96
|
+
## Environment Variables
|
|
97
|
+
|
|
98
|
+
| Variable | Default | Description |
|
|
99
|
+
|----------|---------|-------------|
|
|
100
|
+
| `DEEPMAP_API_URL` | `https://api.volcanosafe.com` | API base URL |
|
|
101
|
+
| `DEEPMAP_API_KEY` | *(empty)* | API key for authenticated access |
|
|
102
|
+
| `VOLCANOSAFE_BASE_URL` | *(fallback)* | Legacy env var, still supported |
|
|
103
|
+
| `VOLCANOSAFE_API_KEY` | *(fallback)* | Legacy env var, still supported |
|
|
104
|
+
|
|
105
|
+
## Documentation
|
|
106
|
+
|
|
107
|
+
Full API documentation: [https://api.volcanosafe.com/docs](https://api.volcanosafe.com/docs)
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# DeepMap AI MCP Server
|
|
2
|
+
|
|
3
|
+
Real-time volcano monitoring, earthquake prediction, and geophysical intelligence as a [Model Context Protocol](https://modelcontextprotocol.io/) server.
|
|
4
|
+
Gives Claude (and any MCP-compatible LLM) direct access to live volcanic risk scores,
|
|
5
|
+
earthquake predictions, seismic risk assessments, tidal forcing analysis,
|
|
6
|
+
flight disruption forecasts, tidal eruption windows, LiDAR fault detection, and travel advisories.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install deepmap-mcp
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Configure for Claude Desktop
|
|
15
|
+
|
|
16
|
+
Add the following to your `claude_desktop_config.json`:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"mcpServers": {
|
|
21
|
+
"deepmap": {
|
|
22
|
+
"command": "python",
|
|
23
|
+
"args": ["-m", "volcanosafe.mcp_server"],
|
|
24
|
+
"env": {
|
|
25
|
+
"DEEPMAP_API_URL": "https://api.volcanosafe.com",
|
|
26
|
+
"DEEPMAP_API_KEY": "dm_live_..."
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or run directly from the command line:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
deepmap-mcp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Available Tools
|
|
40
|
+
|
|
41
|
+
### Volcano Tools
|
|
42
|
+
|
|
43
|
+
| Tool | Description |
|
|
44
|
+
|------|-------------|
|
|
45
|
+
| `volcano_risk` | Full real-time risk assessment with seismic data, tidal state, travel advisory, and flight impact |
|
|
46
|
+
| `volcano_quick` | Low-latency risk score without live seismic fetch -- ideal for batch or insurance queries |
|
|
47
|
+
| `volcano_flights` | Flight disruption risk for airports near a volcano |
|
|
48
|
+
| `volcano_tidal_forecast` | Tidal eruption risk window forecast based on Mf tidal cycle analysis |
|
|
49
|
+
| `volcano_advisory` | Plain-text travel advisory with insurance recommendation and monitoring agency status |
|
|
50
|
+
| `volcano_list` | List all monitored volcanoes with names, countries, coordinates, and last eruption dates |
|
|
51
|
+
| `volcano_batch` | Quick risk scores for multiple volcanoes at once (max 10 per request) |
|
|
52
|
+
|
|
53
|
+
### Earthquake Tools
|
|
54
|
+
|
|
55
|
+
| Tool | Description |
|
|
56
|
+
|------|-------------|
|
|
57
|
+
| `predict_earthquake` | ML earthquake risk prediction for a region using GradientBoosting trained on real USGS data. Returns risk score, confidence, and contributing features |
|
|
58
|
+
| `list_earthquake_regions` | List all supported earthquake monitoring regions with bounds, historical rate, and magnitude of completeness |
|
|
59
|
+
| `assess_current_earthquakes` | Current global seismic risk assessment across all monitored regions using live USGS data |
|
|
60
|
+
| `earthquake_alert_cycle` | Full alert cycle across all monitored regions with triggered alerts and recommended actions |
|
|
61
|
+
| `predict_seismic_risk` | Seismic hazard risk score (0-10) for any lat/lon combining Vs30 site classification, liquefaction probability, and amplification factor |
|
|
62
|
+
| `analyze_tidal_forcing` | Tidal stress forcing analysis on earthquake triggering using Schuster's test and Rayleigh statistics |
|
|
63
|
+
| `detect_fault_scarps` | LiDAR/3DEP slope-break fault scarp detection with strike, dip direction, and length estimates |
|
|
64
|
+
|
|
65
|
+
### Supported Earthquake Regions
|
|
66
|
+
|
|
67
|
+
| Region Key | Name |
|
|
68
|
+
|------------|------|
|
|
69
|
+
| `ucerf3` | Southern California (UCERF3) |
|
|
70
|
+
| `new_madrid` | New Madrid Seismic Zone |
|
|
71
|
+
| `cascadia` | Cascadia Subduction Zone |
|
|
72
|
+
| `wasatch` | Wasatch Front (Utah) |
|
|
73
|
+
| `oklahoma` | Oklahoma (Induced) |
|
|
74
|
+
| `trans_mexico` | Trans-Mexican Volcanic Belt |
|
|
75
|
+
|
|
76
|
+
## Environment Variables
|
|
77
|
+
|
|
78
|
+
| Variable | Default | Description |
|
|
79
|
+
|----------|---------|-------------|
|
|
80
|
+
| `DEEPMAP_API_URL` | `https://api.volcanosafe.com` | API base URL |
|
|
81
|
+
| `DEEPMAP_API_KEY` | *(empty)* | API key for authenticated access |
|
|
82
|
+
| `VOLCANOSAFE_BASE_URL` | *(fallback)* | Legacy env var, still supported |
|
|
83
|
+
| `VOLCANOSAFE_API_KEY` | *(fallback)* | Legacy env var, still supported |
|
|
84
|
+
|
|
85
|
+
## Documentation
|
|
86
|
+
|
|
87
|
+
Full API documentation: [https://api.volcanosafe.com/docs](https://api.volcanosafe.com/docs)
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "deepmap-mcp"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "DeepMap AI MCP Server - Real-time volcano monitoring, earthquake prediction, seismic risk, and geophysical intelligence for Claude and MCP-compatible LLMs"
|
|
9
|
+
readme = "README_MCP.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "DeepMap AI", email = "info@deepmapai.com"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["volcano", "earthquake", "seismic", "mcp", "claude", "risk", "geophysics", "safety", "deepmap"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Scientific/Engineering :: GIS",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"mcp>=1.0",
|
|
25
|
+
"httpx>=0.25",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://deepmap.ai"
|
|
30
|
+
Documentation = "https://api.volcanosafe.com/docs"
|
|
31
|
+
Repository = "https://deepmapai.com"
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["volcanosafe"]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
deepmap-mcp = "volcanosafe.mcp_server:main"
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VolcanoSafe -- Standalone Tourism Risk API
|
|
3
|
+
=============================================
|
|
4
|
+
|
|
5
|
+
FastAPI server providing real-time volcano risk intelligence
|
|
6
|
+
for travel insurance, tour operators, and tourism apps.
|
|
7
|
+
|
|
8
|
+
Launch:
|
|
9
|
+
uvicorn volcanosafe.api:app --host 0.0.0.0 --port 8070
|
|
10
|
+
|
|
11
|
+
Endpoints:
|
|
12
|
+
GET / -> API info + pricing
|
|
13
|
+
GET /v1/volcanoes -> List all monitored volcanoes
|
|
14
|
+
GET /v1/risk/{volcano_id} -> Full risk assessment
|
|
15
|
+
GET /v1/quick/{volcano_id} -> Quick risk score (low latency)
|
|
16
|
+
GET /v1/flights/{volcano_id} -> Flight disruption risk
|
|
17
|
+
GET /v1/tidal/{volcano_id} -> 14-day tidal forecast
|
|
18
|
+
GET /v1/advisory/{volcano_id} -> Travel advisory text
|
|
19
|
+
GET /v1/batch -> Batch risk for multiple volcanoes
|
|
20
|
+
GET /health -> Health check
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import time
|
|
26
|
+
from datetime import datetime, timezone
|
|
27
|
+
from typing import List, Optional
|
|
28
|
+
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
from fastapi import FastAPI, HTTPException, Query
|
|
32
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
33
|
+
from fastapi.responses import FileResponse, JSONResponse, PlainTextResponse, Response
|
|
34
|
+
|
|
35
|
+
from volcanosafe.risk_engine import (
|
|
36
|
+
assess_volcano_risk,
|
|
37
|
+
compute_tidal_stress,
|
|
38
|
+
forecast_tidal_windows,
|
|
39
|
+
list_volcanoes,
|
|
40
|
+
VOLCANOES,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
app = FastAPI(
|
|
44
|
+
title="VolcanoSafe API",
|
|
45
|
+
description=(
|
|
46
|
+
"Real-time volcano risk intelligence for tourism, travel insurance, "
|
|
47
|
+
"and aviation. Combines seismic monitoring, tidal forcing analysis, "
|
|
48
|
+
"eruption history, and atmospheric dispersion modeling."
|
|
49
|
+
),
|
|
50
|
+
version="1.0.0",
|
|
51
|
+
contact={
|
|
52
|
+
"name": "DeepMap AI",
|
|
53
|
+
"email": "info@volcanosafe.com",
|
|
54
|
+
},
|
|
55
|
+
servers=[
|
|
56
|
+
{"url": "https://api.volcanosafe.com", "description": "Production"},
|
|
57
|
+
{"url": "http://localhost:8070", "description": "Local development"},
|
|
58
|
+
],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
app.add_middleware(
|
|
62
|
+
CORSMiddleware,
|
|
63
|
+
allow_origins=["*"],
|
|
64
|
+
allow_credentials=True,
|
|
65
|
+
allow_methods=["*"],
|
|
66
|
+
allow_headers=["*"],
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Request counter for usage tracking
|
|
70
|
+
_request_count = 0
|
|
71
|
+
_start_time = time.time()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# =====================================================================
|
|
75
|
+
# Landing / Info
|
|
76
|
+
# =====================================================================
|
|
77
|
+
|
|
78
|
+
@app.get("/", operation_id="getApiInfo", tags=["System"])
|
|
79
|
+
def root():
|
|
80
|
+
"""API information and pricing."""
|
|
81
|
+
global _request_count
|
|
82
|
+
_request_count += 1
|
|
83
|
+
return {
|
|
84
|
+
"name": "VolcanoSafe API",
|
|
85
|
+
"version": "1.0.0",
|
|
86
|
+
"description": "Real-time volcano risk intelligence for tourism and travel",
|
|
87
|
+
"volcanoes_monitored": len(VOLCANOES),
|
|
88
|
+
"data_sources": [
|
|
89
|
+
"USGS Earthquake Catalog (real-time)",
|
|
90
|
+
"Tidal forcing model (Mf p=0.000132, peer-reviewed methodology)",
|
|
91
|
+
"Smithsonian GVP eruption catalog",
|
|
92
|
+
"CENAPRED / INGV / USGS monitoring agencies",
|
|
93
|
+
],
|
|
94
|
+
"endpoints": {
|
|
95
|
+
"/v1/volcanoes": "List all monitored volcanoes",
|
|
96
|
+
"/v1/risk/{id}": "Full risk assessment with travel advisory",
|
|
97
|
+
"/v1/quick/{id}": "Quick risk score (optimized for high volume)",
|
|
98
|
+
"/v1/flights/{id}": "Airport disruption risk assessment",
|
|
99
|
+
"/v1/tidal/{id}": "14-day tidal eruption window forecast",
|
|
100
|
+
"/v1/advisory/{id}": "Plain-text travel advisory",
|
|
101
|
+
"/v1/batch?ids=popo,colima": "Batch assessment for multiple volcanoes",
|
|
102
|
+
},
|
|
103
|
+
"pricing": {
|
|
104
|
+
"free_tier": "100 requests/day, risk score only",
|
|
105
|
+
"starter": "$49/mo -- 10K requests, full assessment",
|
|
106
|
+
"professional": "$199/mo -- 100K requests, batch + webhooks",
|
|
107
|
+
"enterprise": "$999/mo -- unlimited, SLA, custom volcanoes",
|
|
108
|
+
"insurance_api": "$0.50-2.00/policy quote (volume pricing)",
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# =====================================================================
|
|
114
|
+
# Volcano List
|
|
115
|
+
# =====================================================================
|
|
116
|
+
|
|
117
|
+
@app.get("/v1/volcanoes", operation_id="listVolcanoes", tags=["Volcanoes"])
|
|
118
|
+
def get_volcanoes():
|
|
119
|
+
"""List all monitored volcanoes."""
|
|
120
|
+
global _request_count
|
|
121
|
+
_request_count += 1
|
|
122
|
+
return {
|
|
123
|
+
"count": len(VOLCANOES),
|
|
124
|
+
"volcanoes": list_volcanoes(),
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# =====================================================================
|
|
129
|
+
# Full Risk Assessment
|
|
130
|
+
# =====================================================================
|
|
131
|
+
|
|
132
|
+
@app.get("/v1/risk/{volcano_id}", operation_id="getVolcanoRisk", tags=["Risk Assessment"])
|
|
133
|
+
def get_risk(volcano_id: str, include_seismic: bool = True):
|
|
134
|
+
"""
|
|
135
|
+
Full risk assessment for a volcano.
|
|
136
|
+
|
|
137
|
+
Returns risk score (0-100), alert level (1-5), travel advisory,
|
|
138
|
+
seismic analysis, tidal state, 14-day forecast, and flight impact.
|
|
139
|
+
"""
|
|
140
|
+
global _request_count
|
|
141
|
+
_request_count += 1
|
|
142
|
+
|
|
143
|
+
result = assess_volcano_risk(volcano_id, include_seismic=include_seismic)
|
|
144
|
+
if "error" in result:
|
|
145
|
+
raise HTTPException(status_code=404, detail=result)
|
|
146
|
+
return result
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# =====================================================================
|
|
150
|
+
# Quick Risk Score (low latency)
|
|
151
|
+
# =====================================================================
|
|
152
|
+
|
|
153
|
+
@app.get("/v1/quick/{volcano_id}", operation_id="getQuickRisk", tags=["Risk Assessment"])
|
|
154
|
+
def get_quick_risk(volcano_id: str):
|
|
155
|
+
"""
|
|
156
|
+
Quick risk score -- optimized for high-volume insurance queries.
|
|
157
|
+
Skips real-time seismic fetch for faster response.
|
|
158
|
+
"""
|
|
159
|
+
global _request_count
|
|
160
|
+
_request_count += 1
|
|
161
|
+
|
|
162
|
+
result = assess_volcano_risk(volcano_id, include_seismic=False)
|
|
163
|
+
if "error" in result:
|
|
164
|
+
raise HTTPException(status_code=404, detail=result)
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
"volcano_id": volcano_id,
|
|
168
|
+
"risk_score": result["assessment"]["risk_score"],
|
|
169
|
+
"alert_level": result["assessment"]["alert_level"],
|
|
170
|
+
"alert_name": result["assessment"]["alert_name"],
|
|
171
|
+
"alert_color": result["assessment"]["alert_color"],
|
|
172
|
+
"headline": result["travel_advisory"]["headline"],
|
|
173
|
+
"insurance_advisory": result["travel_advisory"]["insurance_advisory"],
|
|
174
|
+
"tidal_risk": result["tidal_state"]["tidal_risk_label"],
|
|
175
|
+
"timestamp": result["assessment"]["timestamp"],
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# =====================================================================
|
|
180
|
+
# Flight Disruption Risk
|
|
181
|
+
# =====================================================================
|
|
182
|
+
|
|
183
|
+
@app.get("/v1/flights/{volcano_id}", operation_id="getFlightRisk", tags=["Aviation"])
|
|
184
|
+
def get_flight_risk(volcano_id: str):
|
|
185
|
+
"""Airport disruption risk from volcanic activity."""
|
|
186
|
+
global _request_count
|
|
187
|
+
_request_count += 1
|
|
188
|
+
|
|
189
|
+
result = assess_volcano_risk(volcano_id, include_seismic=False)
|
|
190
|
+
if "error" in result:
|
|
191
|
+
raise HTTPException(status_code=404, detail=result)
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
"volcano": result["volcano"],
|
|
195
|
+
"risk_score": result["assessment"]["risk_score"],
|
|
196
|
+
"alert_name": result["assessment"]["alert_name"],
|
|
197
|
+
"flight_impact": result["flight_impact"],
|
|
198
|
+
"recommendation": (
|
|
199
|
+
"Check with airline before travel"
|
|
200
|
+
if result["assessment"]["risk_score"] >= 40
|
|
201
|
+
else "No expected flight disruption"
|
|
202
|
+
),
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# =====================================================================
|
|
207
|
+
# Tidal Forecast
|
|
208
|
+
# =====================================================================
|
|
209
|
+
|
|
210
|
+
@app.get("/v1/tidal/{volcano_id}", operation_id="getTidalForecast", tags=["Tidal Forecast"])
|
|
211
|
+
def get_tidal_forecast(volcano_id: str, days: int = Query(default=14, ge=1, le=30)):
|
|
212
|
+
"""14-day tidal eruption risk window forecast."""
|
|
213
|
+
global _request_count
|
|
214
|
+
_request_count += 1
|
|
215
|
+
|
|
216
|
+
vid = volcano_id.lower().replace(" ", "_").replace("-", "_")
|
|
217
|
+
if vid not in VOLCANOES:
|
|
218
|
+
raise HTTPException(status_code=404, detail=f"Unknown volcano: {volcano_id}")
|
|
219
|
+
|
|
220
|
+
v = VOLCANOES[vid]
|
|
221
|
+
current = compute_tidal_stress(datetime.now(timezone.utc), v["lat"])
|
|
222
|
+
windows = forecast_tidal_windows(v["lat"], days_ahead=days)
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
"volcano": {"id": vid, "name": v["name"]},
|
|
226
|
+
"current_tidal_state": current,
|
|
227
|
+
"forecast_days": days,
|
|
228
|
+
"high_risk_windows": windows,
|
|
229
|
+
"methodology": "Based on Mf fortnightly tidal cycle (p=0.000132, Schuster test on 40,913 M5+ earthquakes)",
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# =====================================================================
|
|
234
|
+
# Travel Advisory
|
|
235
|
+
# =====================================================================
|
|
236
|
+
|
|
237
|
+
@app.get("/v1/advisory/{volcano_id}", operation_id="getTravelAdvisory", tags=["Travel Advisory"])
|
|
238
|
+
def get_advisory(volcano_id: str):
|
|
239
|
+
"""Plain-text travel advisory for a volcano."""
|
|
240
|
+
global _request_count
|
|
241
|
+
_request_count += 1
|
|
242
|
+
|
|
243
|
+
result = assess_volcano_risk(volcano_id, include_seismic=False)
|
|
244
|
+
if "error" in result:
|
|
245
|
+
raise HTTPException(status_code=404, detail=result)
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
"volcano": result["volcano"]["name"],
|
|
249
|
+
"country": result["volcano"]["country"],
|
|
250
|
+
**result["travel_advisory"],
|
|
251
|
+
"risk_score": result["assessment"]["risk_score"],
|
|
252
|
+
"alert_level": result["assessment"]["alert_name"],
|
|
253
|
+
"tourism_notes": result.get("tourism_notes", ""),
|
|
254
|
+
"monitoring_agency": result["monitoring"]["agency"],
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# =====================================================================
|
|
259
|
+
# Batch Assessment
|
|
260
|
+
# =====================================================================
|
|
261
|
+
|
|
262
|
+
@app.get("/v1/batch", operation_id="batchRiskScores", tags=["Volcanoes"])
|
|
263
|
+
def batch_risk(ids: str = Query(..., description="Comma-separated volcano IDs")):
|
|
264
|
+
"""Batch risk assessment for multiple volcanoes."""
|
|
265
|
+
global _request_count
|
|
266
|
+
_request_count += 1
|
|
267
|
+
|
|
268
|
+
volcano_ids = [v.strip() for v in ids.split(",")]
|
|
269
|
+
results = []
|
|
270
|
+
|
|
271
|
+
for vid in volcano_ids[:10]: # Max 10 per batch
|
|
272
|
+
result = assess_volcano_risk(vid, include_seismic=False)
|
|
273
|
+
if "error" not in result:
|
|
274
|
+
results.append({
|
|
275
|
+
"id": vid,
|
|
276
|
+
"name": result["volcano"]["name"],
|
|
277
|
+
"risk_score": result["assessment"]["risk_score"],
|
|
278
|
+
"alert_name": result["assessment"]["alert_name"],
|
|
279
|
+
"headline": result["travel_advisory"]["headline"],
|
|
280
|
+
})
|
|
281
|
+
else:
|
|
282
|
+
results.append({"id": vid, "error": result["error"]})
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
"count": len(results),
|
|
286
|
+
"assessments": results,
|
|
287
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# =====================================================================
|
|
292
|
+
# Health Check
|
|
293
|
+
# =====================================================================
|
|
294
|
+
|
|
295
|
+
@app.get("/health", operation_id="healthCheck", tags=["System"])
|
|
296
|
+
def health():
|
|
297
|
+
"""API health check."""
|
|
298
|
+
return {
|
|
299
|
+
"status": "healthy",
|
|
300
|
+
"uptime_seconds": round(time.time() - _start_time, 1),
|
|
301
|
+
"total_requests": _request_count,
|
|
302
|
+
"volcanoes_monitored": len(VOLCANOES),
|
|
303
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
# =====================================================================
|
|
308
|
+
# AI Plugin / ChatGPT GPT Actions Discovery
|
|
309
|
+
# =====================================================================
|
|
310
|
+
|
|
311
|
+
_PLUGIN_PATH = Path(__file__).parent / "ai-plugin.json"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
@app.get("/.well-known/ai-plugin.json", include_in_schema=False)
|
|
315
|
+
def plugin_manifest():
|
|
316
|
+
"""Serve the OpenAI ChatGPT plugin manifest for GPT Actions discovery."""
|
|
317
|
+
if not _PLUGIN_PATH.exists():
|
|
318
|
+
raise HTTPException(status_code=404, detail="Plugin manifest not found")
|
|
319
|
+
return FileResponse(_PLUGIN_PATH, media_type="application/json")
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
# =====================================================================
|
|
323
|
+
# SEO: robots.txt and sitemap.xml
|
|
324
|
+
# =====================================================================
|
|
325
|
+
|
|
326
|
+
@app.get("/robots.txt", include_in_schema=False)
|
|
327
|
+
def robots_txt():
|
|
328
|
+
"""Serve robots.txt for search engine crawlers."""
|
|
329
|
+
content = (
|
|
330
|
+
"User-agent: *\n"
|
|
331
|
+
"Allow: /\n"
|
|
332
|
+
"Allow: /docs\n"
|
|
333
|
+
"Allow: /openapi.json\n"
|
|
334
|
+
"Allow: /landing\n"
|
|
335
|
+
"Allow: /.well-known/ai-plugin.json\n"
|
|
336
|
+
"\n"
|
|
337
|
+
"Sitemap: https://api.volcanosafe.com/sitemap.xml\n"
|
|
338
|
+
)
|
|
339
|
+
return PlainTextResponse(content)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@app.get("/sitemap.xml", include_in_schema=False)
|
|
343
|
+
def sitemap_xml():
|
|
344
|
+
"""Serve sitemap.xml for search engines."""
|
|
345
|
+
urls = [
|
|
346
|
+
"https://api.volcanosafe.com/landing",
|
|
347
|
+
"https://api.volcanosafe.com/docs",
|
|
348
|
+
"https://api.volcanosafe.com/v1/volcanoes",
|
|
349
|
+
"https://api.volcanosafe.com/.well-known/ai-plugin.json",
|
|
350
|
+
]
|
|
351
|
+
xml_entries = "\n".join(
|
|
352
|
+
f" <url><loc>{u}</loc><changefreq>weekly</changefreq></url>"
|
|
353
|
+
for u in urls
|
|
354
|
+
)
|
|
355
|
+
xml = (
|
|
356
|
+
'<?xml version="1.0" encoding="UTF-8"?>\n'
|
|
357
|
+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
|
|
358
|
+
f"{xml_entries}\n"
|
|
359
|
+
"</urlset>"
|
|
360
|
+
)
|
|
361
|
+
return Response(content=xml, media_type="application/xml")
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
# =====================================================================
|
|
365
|
+
# Landing Page
|
|
366
|
+
# =====================================================================
|
|
367
|
+
|
|
368
|
+
_LANDING_PATH = Path(__file__).parent / "landing.html"
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
@app.get("/landing", include_in_schema=False)
|
|
372
|
+
def landing_page():
|
|
373
|
+
"""Serve the VolcanoSafe marketing landing page."""
|
|
374
|
+
if not _LANDING_PATH.exists():
|
|
375
|
+
raise HTTPException(status_code=404, detail="Landing page not found")
|
|
376
|
+
return FileResponse(_LANDING_PATH, media_type="text/html")
|