2222 "ai_foundry" : {
2323 "icon_svg" : '<rect x="6" y="10" width="36" height="28" rx="4" fill="#0078D4"/><rect x="12" y="16" width="10" height="8" rx="2" fill="white" opacity="0.9"/><rect x="26" y="16" width="10" height="8" rx="2" fill="white" opacity="0.9"/><rect x="12" y="27" width="24" height="5" rx="2" fill="white" opacity="0.6"/>' ,
2424 "color" : "#0078D4" , "bg" : "#E8F4FD" , "category" : "AI" ,
25- "azure_icon_key" : "azure_openai "
25+ "azure_icon_key" : "ai_foundry "
2626 },
2727 "ai_hub" : {
2828 "icon_svg" : '<rect x="6" y="10" width="36" height="28" rx="4" fill="#0078D4"/><circle cx="24" cy="24" r="8" fill="white" opacity="0.9"/><circle cx="24" cy="24" r="4" fill="#0078D4"/>' ,
5757 "fabric" : {
5858 "icon_svg" : '<polygon points="24,6 42,18 42,34 24,46 6,34 6,18" fill="#E8740C" opacity="0.9"/><text x="24" y="30" text-anchor="middle" font-size="14" fill="white" font-weight="700">F</text>' ,
5959 "color" : "#E8740C" , "bg" : "#FEF3E8" , "category" : "Data" ,
60- "azure_icon_key" : "managed_service_fabric "
60+ "azure_icon_key" : "microsoft_fabric "
6161 },
6262 "synapse" : {
6363 "icon_svg" : '<circle cx="24" cy="24" r="18" fill="#0078D4"/><path d="M15 24 L24 15 L33 24 L24 33 Z" fill="white" opacity="0.9"/>' ,
407407}
408408
409409
410+ _TYPE_ALIASES = {
411+ # Azure ARM resource names → canonical diagram type
412+ # Network
413+ "private_endpoints" : "pe" , "private_endpoint" : "pe" ,
414+ "virtual_networks" : "vnet" , "virtual_network" : "vnet" ,
415+ "network_security_groups" : "nsg" , "network_security_group" : "nsg" ,
416+ "bastion_hosts" : "bastion" , "bastion_host" : "bastion" ,
417+ "application_gateways" : "app_gateway" , "application_gateway" : "app_gateway" ,
418+ "front_doors" : "front_door" , "front_door_and_cdn_profiles" : "front_door" ,
419+ "virtual_network_gateways" : "vpn" , "vpn_gateways" : "vpn" ,
420+ "load_balancers" : "load_balancer" ,
421+ "nat_gateways" : "nat_gateway" ,
422+ "expressroute_circuits" : "expressroute" ,
423+ "firewalls" : "firewall" ,
424+ "cdn_profiles" : "cdn" ,
425+ # Data
426+ "data_factories" : "adf" , "data_factory" : "adf" ,
427+ "storage_accounts" : "storage" , "storage_account" : "storage" ,
428+ "data_lake" : "adls" , "adls_gen2" : "adls" , "data_lake_storage" : "adls" ,
429+ "fabric_capacities" : "fabric" , "fabric_capacity" : "fabric" , "microsoft_fabric" : "fabric" ,
430+ "synapse_workspaces" : "synapse" , "synapse_workspace" : "synapse" , "synapse_analytics" : "synapse" ,
431+ "cosmos" : "cosmos_db" , "cosmosdb" : "cosmos_db" , "documentdb" : "cosmos_db" ,
432+ "sql_databases" : "sql_database" , "sql_db" : "sql_database" ,
433+ "sql_servers" : "sql_server" ,
434+ "redis_caches" : "redis" , "redis_cache" : "redis" , "cache_redis" : "redis" ,
435+ "stream_analytics_jobs" : "stream_analytics" ,
436+ "databricks_workspaces" : "databricks" ,
437+ "data_explorer_clusters" : "data_explorer" , "azure_data_explorer" : "data_explorer" ,
438+ "postgresql_server" : "postgresql" , "postgresql_servers" : "postgresql" ,
439+ "mysql_server" : "mysql" , "mysql_servers" : "mysql" ,
440+ # AI
441+ "cognitive_services" : "ai_foundry" , "ai_services" : "ai_foundry" , "foundry" : "ai_foundry" ,
442+ "azure_openai" : "openai" ,
443+ "cognitive_search" : "search" , "search_services" : "search" , "search_service" : "search" ,
444+ "machine_learning" : "aml" , "ml" : "aml" , "machine_learning_workspaces" : "aml" ,
445+ "form_recognizers" : "document_intelligence" ,
446+ "ai_studio" : "ai_hub" , "foundry_project" : "ai_hub" ,
447+ # Security
448+ "key_vault" : "keyvault" , "key_vaults" : "keyvault" ,
449+ "sentinel" : "sentinel" , "azure_sentinel" : "sentinel" ,
450+ # Compute
451+ "virtual_machines" : "vm" , "virtual_machine" : "vm" ,
452+ "app_services" : "appservice" , "web_apps" : "appservice" , "web_app" : "appservice" ,
453+ "function_apps" : "function_app" , "functions" : "function_app" ,
454+ "kubernetes_services" : "aks" , "managed_clusters" : "aks" , "kubernetes" : "aks" ,
455+ "container_registries" : "acr" ,
456+ "container_apps_environments" : "container_apps" ,
457+ "spring_apps" : "spring_apps" , "azure_spring_apps" : "spring_apps" ,
458+ "static_apps" : "static_web_app" , "static_web_apps" : "static_web_app" ,
459+ # Integration
460+ "event_hubs" : "event_hub" ,
461+ "event_grid_topics" : "event_grid" , "event_grid_domains" : "event_grid" ,
462+ "api_management_services" : "apim" ,
463+ "service_bus_namespaces" : "service_bus" ,
464+ "logic_app" : "logic_apps" ,
465+ "notification_hubs" : "notification_hub" ,
466+ # Monitoring
467+ "log_analytics_workspaces" : "log_analytics" ,
468+ "application_insights" : "appinsights" , "app_insight" : "appinsights" ,
469+ # IoT
470+ "iot_hubs" : "iot_hub" ,
471+ # Management
472+ "backup_vaults" : "backup" , "backup_vault" : "backup" ,
473+ }
474+
410475def get_service_info (svc_type : str ) -> dict :
411476 t = svc_type .lower ().replace ("-" , "_" ).replace (" " , "_" )
477+ t = _TYPE_ALIASES .get (t , t )
412478 info = SERVICE_ICONS .get (t , SERVICE_ICONS ["default" ]).copy ()
413479 # Add official Azure icon data URI if available
414480 azure_key = info .get ("azure_icon_key" , t )
@@ -418,10 +484,14 @@ def get_service_info(svc_type: str) -> dict:
418484
419485
420486def generate_html (services : list , connections : list , title : str , vnet_info : str = "" , hierarchy : list = None ) -> str :
487+ def _norm (t ):
488+ t = t .lower ().replace ("-" , "_" ).replace (" " , "_" )
489+ return _TYPE_ALIASES .get (t , t )
490+
421491 nodes_js = json .dumps ([{
422492 "id" : svc ["id" ],
423493 "name" : svc ["name" ],
424- "type" : svc .get ("type" , "default" ),
494+ "type" : _norm ( svc .get ("type" , "default" ) ),
425495 "sku" : svc .get ("sku" , "" ),
426496 "private" : svc .get ("private" , False ),
427497 "details" : svc .get ("details" , []),
@@ -445,7 +515,7 @@ def generate_html(services: list, connections: list, title: str, vnet_info: str
445515 "dash" : CONNECTION_STYLES .get (conn .get ("type" , "default" ), CONNECTION_STYLES ["default" ])["dash" ],
446516 } for conn in connections ], ensure_ascii = False )
447517
448- pe_count = sum (1 for s in services if s .get ("type" , "default" ) == "pe" )
518+ pe_count = sum (1 for s in services if _norm ( s .get ("type" , "default" ) ) == "pe" )
449519 svc_count = len (services ) - pe_count
450520 generated_at = datetime .now ().strftime ("%Y-%m-%d %H:%M" )
451521 vnet_info_js = json .dumps (vnet_info , ensure_ascii = False )
0 commit comments