dchubcloud commited on
Commit
170fbda
·
verified ·
1 Parent(s): c1493b0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -11
app.py CHANGED
@@ -2,16 +2,29 @@
2
 
3
  A live demo of the DC Hub Power Index (DCPI) that ALSO runs as an MCP server
4
  (launch(mcp_server=True)) so Hugging Face Agents / smolagents and any MCP client
5
- can query it. The complete DC Hub MCP — 47 tools across 21,000+ data-center
6
- facilities, real-time grid telemetry, fiber, gas, and 2,000+ M&A deals — lives at
7
- https://dchub.cloud/mcp. Connect that for the full dataset (10 calls/day free).
 
 
 
 
 
 
 
8
  """
 
 
 
 
9
  import requests
10
  import gradio as gr
11
 
12
  API = "https://dchub.cloud"
13
  FULL_MCP = "https://dchub.cloud/mcp"
14
  TIMEOUT = 20
 
 
15
 
16
 
17
  def _verdict(score):
@@ -59,7 +72,7 @@ def dcpi_score(market: str) -> str:
59
  f"- Excess-power headroom: {d.get('excess_power_score', '?')}/100 · "
60
  f"grid constraint: {d.get('constraint_score', '?')}/100\n\n"
61
  f"_Modeled estimate from public ISO/EIA/queue data · DC Hub (dchub.cloud) · CC-BY-4.0._\n\n"
62
- f"_Full grid headroom, interconnection queue, fiber + 47 tools: connect the DC Hub MCP → **{FULL_MCP}**._"
63
  )
64
  except Exception as e:
65
  return f"DC Hub lookup failed ({e}). Query the full live MCP at {FULL_MCP}."
@@ -95,16 +108,117 @@ def compare_markets(markets: str) -> str:
95
  return "\n".join(out)
96
 
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  INTRO = f"""# ⚡ DC Hub — Power Index (live)
99
  **Can you actually get power to build a data center here?** DC Hub scores 311
100
  U.S. + global markets on power availability — a 0-100 index with a
101
  **BUILD / CAUTION / AVOID** verdict, power cost, and modeled time-to-power. Live
102
  from [dchub.cloud](https://dchub.cloud).
103
 
104
- This Space is **also an MCP server** — point your Hugging Face Agent / MCP client
105
- at it, or connect the **full DC Hub MCP** (47 tools — 21,000+ facilities, real-time
106
- grid telemetry, fiber, gas, 2,000+ M&A deals) at **`{FULL_MCP}`** (10 calls/day
107
- free, no key needed).
108
  """
109
 
110
  with gr.Blocks(title="DC Hub — Power Index", theme=gr.themes.Soft()) as demo:
@@ -121,12 +235,46 @@ with gr.Blocks(title="DC Hub — Power Index", theme=gr.themes.Soft()) as demo:
121
  cout = gr.Markdown()
122
  gr.Button("Rank by power availability", variant="primary").click(
123
  compare_markets, cinp, cout)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  gr.Markdown(
125
  f"_Data: DC Hub (dchub.cloud), CC-BY-4.0 · the live infrastructure data "
126
  f"layer for AI agents · [connect the full MCP]({FULL_MCP}) · "
127
  f"[free key](https://dchub.cloud/signup)_")
128
 
129
  if __name__ == "__main__":
130
- # mcp_server=True exposes dcpi_score + compare_markets as MCP tools at
131
- # /gradio_api/mcp/sse — usable by HF Agents, smolagents, and any MCP client.
132
- demo.launch(mcp_server=True)
 
2
 
3
  A live demo of the DC Hub Power Index (DCPI) that ALSO runs as an MCP server
4
  (launch(mcp_server=True)) so Hugging Face Agents / smolagents and any MCP client
5
+ can query it. Seven tools: the two DCPI classics (dcpi_score, compare_markets)
6
+ plus five bridge tools (grid scoreboard, facility search, market ranking,
7
+ interconnection queue, hyperscaler deals) forwarded to DC Hub's canonical MCP
8
+ server. The complete DC Hub MCP — 74 tools across 21,900+ data-center
9
+ facilities (4,900+ verified), real-time grid telemetry, fiber, gas, and 1,400+
10
+ tracked deals — lives at https://dchub.cloud/mcp. Connect that for the full
11
+ dataset (10 calls/day free anonymous; free key via its claim_free_key tool).
12
+
13
+ Optional Space secret DCHUB_API_KEY (a dchub_ key) lifts the bridge tools to
14
+ full-tier responses; without it they ride the anonymous free tier.
15
  """
16
+ import json
17
+ import os
18
+ import uuid
19
+
20
  import requests
21
  import gradio as gr
22
 
23
  API = "https://dchub.cloud"
24
  FULL_MCP = "https://dchub.cloud/mcp"
25
  TIMEOUT = 20
26
+ API_KEY = (os.environ.get("DCHUB_API_KEY") or "").strip()
27
+ UA = "huggingface-space-dchub-bridge/1.0 (+https://dchub.cloud)"
28
 
29
 
30
  def _verdict(score):
 
72
  f"- Excess-power headroom: {d.get('excess_power_score', '?')}/100 · "
73
  f"grid constraint: {d.get('constraint_score', '?')}/100\n\n"
74
  f"_Modeled estimate from public ISO/EIA/queue data · DC Hub (dchub.cloud) · CC-BY-4.0._\n\n"
75
+ f"_Full grid headroom, interconnection queue, fiber + 74 tools: connect the DC Hub MCP → **{FULL_MCP}**._"
76
  )
77
  except Exception as e:
78
  return f"DC Hub lookup failed ({e}). Query the full live MCP at {FULL_MCP}."
 
108
  return "\n".join(out)
109
 
110
 
111
+ # ── Bridge tools: forwarded to the canonical DC Hub MCP server ──────────────
112
+ def _call_tool(name: str, arguments: dict) -> str:
113
+ """Single-shot JSON-RPC tools/call against the canonical DC Hub MCP server."""
114
+ headers = {
115
+ "Content-Type": "application/json",
116
+ "Accept": "application/json, text/event-stream",
117
+ "User-Agent": UA,
118
+ "X-MCP-Platform": "huggingface",
119
+ }
120
+ if API_KEY:
121
+ headers["X-API-Key"] = API_KEY
122
+ body = {
123
+ "jsonrpc": "2.0",
124
+ "id": str(uuid.uuid4()),
125
+ "method": "tools/call",
126
+ "params": {"name": name, "arguments": {k: v for k, v in arguments.items()
127
+ if v not in ("", None)}},
128
+ }
129
+ try:
130
+ r = requests.post(FULL_MCP, json=body, headers=headers, timeout=45)
131
+ text = r.text
132
+ if "data:" in text and text.lstrip().startswith("event:"):
133
+ for line in text.splitlines():
134
+ if line.startswith("data:"):
135
+ text = line[5:].strip()
136
+ break
137
+ payload = json.loads(text)
138
+ result = payload.get("result") or payload
139
+ content = result.get("content")
140
+ if isinstance(content, list):
141
+ out = "\n".join(c.get("text", "") for c in content if c.get("type") == "text")
142
+ else:
143
+ out = json.dumps(result, indent=2)
144
+ try:
145
+ return json.dumps(json.loads(out), indent=2)
146
+ except Exception:
147
+ return out
148
+ except Exception as e:
149
+ return json.dumps({"error": str(e)[:300],
150
+ "hint": f"DC Hub MCP unreachable — retry, or connect {FULL_MCP} directly"})
151
+
152
+
153
+ def grid_scoreboard() -> str:
154
+ """Live ranked scoreboard of power grids (7 US ISOs + Great Britain, EU zones,
155
+ Taiwan, Japan, South Korea, Brazil, and more): fuel mix, renewable share, and
156
+ demand right now. Greenest grids first. No parameters."""
157
+ return _call_tool("get_grid_scoreboard", {})
158
+
159
+
160
+ def search_facilities(query: str = "", country: str = "", state: str = "",
161
+ operator: str = "", min_capacity_mw: float = 0,
162
+ limit: int = 10) -> str:
163
+ """Search DC Hub's index of 21,900+ data-center facilities (4,900+ independently
164
+ verified) across 170+ countries.
165
+
166
+ Args:
167
+ query: Free-text search over facility name/operator/location.
168
+ country: ISO 3166-1 alpha-2 country code, e.g. US, GB, SG.
169
+ state: US state abbreviation, e.g. VA, TX.
170
+ operator: Operator/provider name, e.g. Equinix, Digital Realty.
171
+ min_capacity_mw: Minimum power capacity in megawatts.
172
+ limit: Max results (1-500).
173
+ """
174
+ return _call_tool("search_facilities", {
175
+ "query": query, "country": country, "state": state, "operator": operator,
176
+ "min_capacity_mw": min_capacity_mw or None, "limit": int(limit) or 10})
177
+
178
+
179
+ def rank_markets(criteria: str = "most_capacity", region: str = "us",
180
+ limit: int = 10) -> str:
181
+ """Rank data-center markets by a live criterion from the DC Hub Power Index.
182
+
183
+ Args:
184
+ criteria: One of cheapest_power, most_capacity, most_operators, fastest.
185
+ region: global, us, canada, eu, apac, or americas.
186
+ limit: Number of markets to return (1-50).
187
+ """
188
+ return _call_tool("rank_markets", {"criteria": criteria, "region": region,
189
+ "limit": int(limit) or 10})
190
+
191
+
192
+ def interconnection_queue(iso: str = "") -> str:
193
+ """US grid interconnection-queue intelligence — how much capacity is waiting to
194
+ connect, by ISO/RTO.
195
+
196
+ Args:
197
+ iso: Optional drill-down: ERCOT, PJM, MISO, CAISO, SPP, NYISO, or ISONE.
198
+ Empty = national overview.
199
+ """
200
+ return _call_tool("get_interconnection_queue", {"iso": iso})
201
+
202
+
203
+ def hyperscaler_deals(limit: int = 10) -> str:
204
+ """Recent hyperscaler / AI-capex deals from DC Hub's tracker of 1,400+ deals.
205
+
206
+ Args:
207
+ limit: Number of recent deals to return.
208
+ """
209
+ return _call_tool("hyperscaler_deals", {"limit": int(limit) or 10})
210
+
211
+
212
  INTRO = f"""# ⚡ DC Hub — Power Index (live)
213
  **Can you actually get power to build a data center here?** DC Hub scores 311
214
  U.S. + global markets on power availability — a 0-100 index with a
215
  **BUILD / CAUTION / AVOID** verdict, power cost, and modeled time-to-power. Live
216
  from [dchub.cloud](https://dchub.cloud).
217
 
218
+ This Space is **also an MCP server** with 7 tools — point your Hugging Face
219
+ Agent / MCP client at it, or connect the **full DC Hub MCP** (74 tools —
220
+ 21,900+ facilities, 4,900+ verified, real-time grid telemetry, fiber, gas,
221
+ 1,400+ tracked deals) at **`{FULL_MCP}`** (10 calls/day free, no key needed).
222
  """
223
 
224
  with gr.Blocks(title="DC Hub — Power Index", theme=gr.themes.Soft()) as demo:
 
235
  cout = gr.Markdown()
236
  gr.Button("Rank by power availability", variant="primary").click(
237
  compare_markets, cinp, cout)
238
+ with gr.Tab("Grid scoreboard"):
239
+ gout = gr.Code(language="json")
240
+ gr.Button("Live grid scoreboard (greenest first)", variant="primary").click(
241
+ grid_scoreboard, [], gout)
242
+ with gr.Tab("Search facilities"):
243
+ s_q = gr.Textbox(label="query", value="Ashburn")
244
+ s_c = gr.Textbox(label="country (ISO-2)", value="US")
245
+ s_s = gr.Textbox(label="state")
246
+ s_o = gr.Textbox(label="operator")
247
+ s_m = gr.Number(label="min capacity MW", value=0)
248
+ s_l = gr.Number(label="limit", value=10)
249
+ sout = gr.Code(language="json")
250
+ gr.Button("Search 21,900+ facilities", variant="primary").click(
251
+ search_facilities, [s_q, s_c, s_s, s_o, s_m, s_l], sout)
252
+ with gr.Tab("Rank markets"):
253
+ r_c = gr.Dropdown(["most_capacity", "cheapest_power", "most_operators",
254
+ "fastest"], value="most_capacity", label="criteria")
255
+ r_r = gr.Dropdown(["us", "global", "canada", "eu", "apac", "americas"],
256
+ value="us", label="region")
257
+ r_l = gr.Number(label="limit", value=10)
258
+ rout = gr.Code(language="json")
259
+ gr.Button("Rank markets", variant="primary").click(
260
+ rank_markets, [r_c, r_r, r_l], rout)
261
+ with gr.Tab("Interconnection queue"):
262
+ q_i = gr.Dropdown(["", "ERCOT", "PJM", "MISO", "CAISO", "SPP", "NYISO",
263
+ "ISONE"], value="", label="ISO (empty = national)")
264
+ qout = gr.Code(language="json")
265
+ gr.Button("Queue intelligence", variant="primary").click(
266
+ interconnection_queue, [q_i], qout)
267
+ with gr.Tab("Hyperscaler deals"):
268
+ d_l = gr.Number(label="limit", value=10)
269
+ dout = gr.Code(language="json")
270
+ gr.Button("Recent AI-capex deals", variant="primary").click(
271
+ hyperscaler_deals, [d_l], dout)
272
  gr.Markdown(
273
  f"_Data: DC Hub (dchub.cloud), CC-BY-4.0 · the live infrastructure data "
274
  f"layer for AI agents · [connect the full MCP]({FULL_MCP}) · "
275
  f"[free key](https://dchub.cloud/signup)_")
276
 
277
  if __name__ == "__main__":
278
+ # mcp_server=True exposes all 7 tools as MCP tools at /gradio_api/mcp/sse —
279
+ # usable by HF Agents, smolagents, and any MCP client.
280
+ demo.launch(mcp_server=True)