Spaces:
Sleeping
Sleeping
| """ | |
| Builds the MVP import graph: | |
| - 20 pharma API nodes | |
| - 8 rare earth mineral nodes | |
| - edges weighted by India's monthly import volume (USD millions) | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| from typing import Any | |
| import networkx as nx | |
| BASE_DIR = Path(__file__).resolve().parent.parent | |
| APIS_FILE = BASE_DIR / "data" / "seed" / "apis.json" | |
| RARE_EARTHS_FILE = BASE_DIR / "data" / "seed" / "rare_earths.json" | |
| OUTPUT_FILE = BASE_DIR / "data" / "graph_imports.json" | |
| INDIA_NODE_ID = "india" | |
| PHARMA_NODE_LIMIT = 20 | |
| RARE_EARTH_NODE_LIMIT = 8 | |
| def _read_json(path: Path) -> list[dict[str, Any]]: | |
| with open(path, "r", encoding="utf-8") as file: | |
| return json.load(file) | |
| def _top_by_import_value(records: list[dict[str, Any]], limit: int) -> list[dict[str, Any]]: | |
| sorted_rows = sorted( | |
| records, | |
| key=lambda row: float(row.get("monthly_import_value_usd_millions", 0) or 0), | |
| reverse=True, | |
| ) | |
| return sorted_rows[:limit] | |
| def build_import_graph() -> nx.DiGraph: | |
| apis = _top_by_import_value(_read_json(APIS_FILE), PHARMA_NODE_LIMIT) | |
| rare_earths = _top_by_import_value(_read_json(RARE_EARTHS_FILE), RARE_EARTH_NODE_LIMIT) | |
| graph = nx.DiGraph(name="pharmashield_mvp_import_graph") | |
| graph.add_node(INDIA_NODE_ID, type="country", name="India") | |
| max_value = max( | |
| [float(item.get("monthly_import_value_usd_millions", 0) or 0) for item in apis + rare_earths] or [1.0] | |
| ) | |
| for api in apis: | |
| node_id = api["id"] | |
| value = float(api.get("monthly_import_value_usd_millions", 0) or 0) | |
| graph.add_node( | |
| node_id, | |
| type="pharma_api", | |
| name=api.get("name", node_id), | |
| sector="pharma", | |
| china_share=api.get("china_share"), | |
| primary_provinces=api.get("primary_provinces", []), | |
| monthly_import_value_usd_millions=value, | |
| ) | |
| graph.add_edge( | |
| node_id, | |
| INDIA_NODE_ID, | |
| edge_type="india_imports_api", | |
| import_volume_usd_millions=value, | |
| weight=round(value / max_value, 6), | |
| ) | |
| for mineral in rare_earths: | |
| node_id = mineral["id"] | |
| value = float(mineral.get("monthly_import_value_usd_millions", 0) or 0) | |
| graph.add_node( | |
| node_id, | |
| type="rare_earth", | |
| name=mineral.get("name", node_id), | |
| sector="rare_earth", | |
| china_share=mineral.get("china_share"), | |
| primary_provinces=mineral.get("primary_provinces", []), | |
| monthly_import_value_usd_millions=value, | |
| ) | |
| graph.add_edge( | |
| node_id, | |
| INDIA_NODE_ID, | |
| edge_type="india_imports_rare_earth", | |
| import_volume_usd_millions=value, | |
| weight=round(value / max_value, 6), | |
| ) | |
| return graph | |
| def graph_to_dict(graph: nx.DiGraph) -> dict[str, Any]: | |
| return { | |
| "nodes": [ | |
| {"id": node_id, **attrs} | |
| for node_id, attrs in graph.nodes(data=True) | |
| ], | |
| "edges": [ | |
| {"source": source, "target": target, **attrs} | |
| for source, target, attrs in graph.edges(data=True) | |
| ], | |
| } | |
| def save_graph(path: Path = OUTPUT_FILE) -> dict[str, Any]: | |
| graph = build_import_graph() | |
| payload = graph_to_dict(graph) | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| with open(path, "w", encoding="utf-8") as file: | |
| json.dump(payload, file, indent=2, ensure_ascii=False) | |
| return payload | |
| if __name__ == "__main__": | |
| result = save_graph() | |
| print( | |
| f"Built import graph with {len(result['nodes'])} nodes " | |
| f"and {len(result['edges'])} edges -> {OUTPUT_FILE}" | |
| ) | |