@@ -764,8 +794,8 @@
📦 ${model.filename}
Tạo lúc: ${new Date(model.created).toLocaleString('vi-VN')}
Kích thước: ${model.size_mb} MB
- ${model.info.train_accuracy ? `
Train Accuracy: ${(model.info.train_accuracy * 100).toFixed(2)}%
` : ''}
- ${model.info.test_accuracy ? `
Test Accuracy: ${(model.info.test_accuracy * 100).toFixed(2)}%
` : ''}
+ ${model.info && model.info.train_accuracy ? `
Train Accuracy: ${(model.info.train_accuracy * 100).toFixed(2)}%
` : ''}
+ ${model.info && model.info.test_accuracy ? `
Test Accuracy: ${(model.info.test_accuracy * 100).toFixed(2)}%
` : ''}
`;
container.appendChild(item);
@@ -1101,7 +1131,8 @@
'random_forest': '✓ Random Forest: Ổn định, không overfitting, phù hợp mọi kích thước dữ liệu',
'decision_tree': '✓ Decision Tree: Đơn giản nhất, nhanh nhất, dễ hiểu, phù hợp để test nhanh',
'svm': '✓ SVM: Chính xác cao với dữ liệu nhỏ, chậm với dữ liệu lớn',
- 'cnn': '✓ CNN PyTorch: Mạnh nhất với ảnh vệ tinh, tự học features, tương thích GPU tốt, cần pip install torch'
+ 'cnn': '✓ CNN PyTorch: Mạnh nhất với ảnh vệ tinh, tự học features, tương thích GPU tốt, cần pip install torch',
+ 'swin-unet': '✓ Swin-UNet: Kết hợp Transformer + U-Net, độ chính xác cao nhất, phù hợp dataset lớn, tốc độ training trung bình'
};
desc.textContent = descriptions[modelType];
@@ -1130,10 +1161,19 @@
document.getElementById('nEstimators').value = 50;
learningRateGroup.style.display = 'none';
useGpuGroup.style.display = ''; // Show GPU option for CNN
+ } else if (modelType === 'swin-unet') {
+ // Swin-UNet uses n_estimators as epochs and supports GPU
+ nEstimatorsGroup.style.display = '';
+ document.querySelector('#nEstimatorsGroup label').textContent = 'Epochs (số lần training):';
+ document.getElementById('nEstimators').value = 100;
+ learningRateGroup.style.display = ''; // Show learning rate for Swin-UNet
+ document.querySelector('#learningRateGroup label').textContent = 'Learning Rate (mặc định: 0.0005):';
+ document.getElementById('learningRate').value = 0.0005;
+ useGpuGroup.style.display = ''; // Show GPU option for Swin-UNet
}
- // Reset n_estimators label for non-CNN
- if (modelType !== 'cnn' && modelType !== 'decision_tree' && modelType !== 'svm') {
+ // Reset n_estimators label for non-CNN/non-Swin-UNet
+ if (modelType !== 'cnn' && modelType !== 'swin-unet' && modelType !== 'decision_tree' && modelType !== 'svm') {
document.querySelector('#nEstimatorsGroup label').textContent = 'N Estimators:';
}
}
@@ -1278,12 +1318,213 @@
}
}
+ // === PROVINCE SELECTION FUNCTIONS ===
+ let allProvinces = {};
+ let allProvincesMerged = {};
+ let currentProvinceName = '';
+ let currentProvinceMode = '63'; // '63' or '32'
+
+ // Load provinces list (both 63 and 32)
+ async function loadProvinces() {
+ try {
+ // Load 63 provinces
+ const response63 = await fetch(`${API_BASE}/provinces/by-region`);
+ allProvinces = await response63.json();
+
+ // Load 32 merged provinces
+ const response32 = await fetch(`${API_BASE}/provinces-32/by-region`);
+ allProvincesMerged = await response32.json();
+
+ // Default to 63 provinces
+ populateRegionButtons();
+ populateProvinceSelect();
+ } catch (error) {
+ console.error('Error loading provinces:', error);
+ document.getElementById('provinceSelect').innerHTML = '
';
+ }
+ }
+
+ // Switch between 63 and 32 province lists
+ function switchProvinceList(mode) {
+ currentProvinceMode = mode;
+
+ // Update button styles
+ const btn63 = document.getElementById('btn63Provinces');
+ const btn32 = document.getElementById('btn32Provinces');
+ const modeLabel = document.getElementById('provinceListMode');
+
+ if (mode === '63') {
+ btn63.style.background = '#667eea';
+ btn63.style.color = 'white';
+ btn32.style.background = '#f0f0f0';
+ btn32.style.color = '#333';
+ modeLabel.textContent = 'Danh sách: 63 tỉnh';
+ } else {
+ btn63.style.background = '#f0f0f0';
+ btn63.style.color = '#333';
+ btn32.style.background = '#667eea';
+ btn32.style.color = 'white';
+ modeLabel.textContent = 'Danh sách: 32 tỉnh (sau sáp nhập)';
+ }
+
+ // Update region filter buttons
+ populateRegionButtons();
+
+ // Reload province list
+ populateProvinceSelect();
+ }
+
+ // Populate province select dropdown
+ function populateProvinceSelect(filterRegion = 'all') {
+ const select = document.getElementById('provinceSelect');
+ select.innerHTML = '
';
+
+ // Choose which province list to use
+ const provinceData = currentProvinceMode === '63' ? allProvinces : allProvincesMerged;
+
+ // Get all regions dynamically from data
+ const regions = Object.keys(provinceData);
+
+ regions.forEach(region => {
+ if (filterRegion !== 'all' && filterRegion !== region) {
+ return;
+ }
+
+ const provinces = provinceData[region];
+ if (!provinces || provinces.length === 0) return;
+
+ const optgroup = document.createElement('optgroup');
+ optgroup.label = `${region} (${provinces.length} tỉnh)`;
+
+ provinces.forEach(province => {
+ const option = document.createElement('option');
+ option.value = province.name;
+
+ // For merged provinces, show additional info
+ if (currentProvinceMode === '32' && province.merged_from) {
+ option.textContent = `${province.name} (${province.merged_from.join(', ')})`;
+ } else {
+ option.textContent = `${province.name} - ${province.name_en || ''}`;
+ }
+
+ option.dataset.bbox = JSON.stringify(province.bbox);
+ optgroup.appendChild(option);
+ });
+
+ select.appendChild(optgroup);
+ });
+ }
+
+ // Handle province selection
+ function onProvinceSelect(event) {
+ const select = event.target;
+ const selectedOption = select.options[select.selectedIndex];
+
+ if (!selectedOption.value) {
+ currentProvinceName = '';
+ document.getElementById('provinceDisplay').textContent = '';
+ return;
+ }
+
+ const provinceName = selectedOption.value;
+ const bbox = JSON.parse(selectedOption.dataset.bbox);
+
+ currentProvinceName = provinceName;
+
+ // Update bbox inputs
+ document.getElementById('minLon').value = bbox[0];
+ document.getElementById('minLat').value = bbox[1];
+ document.getElementById('maxLon').value = bbox[2];
+ document.getElementById('maxLat').value = bbox[3];
+
+ // Update bbox display
+ document.getElementById('bboxDisplay').textContent =
+ `Lon: ${bbox[0]} → ${bbox[2]}, Lat: ${bbox[1]} → ${bbox[3]}`;
+ document.getElementById('provinceDisplay').textContent = `📍 ${provinceName}`;
+
+ // Draw rectangle on map
+ const bounds = [[bbox[1], bbox[0]], [bbox[3], bbox[2]]];
+
+ // Remove previous rectangle
+ if (currentRectangle) {
+ drawnItems.removeLayer(currentRectangle);
+ }
+
+ // Add new rectangle
+ currentRectangle = L.rectangle(bounds, {
+ color: '#667eea',
+ weight: 3,
+ fillOpacity: 0.2
+ });
+ drawnItems.addLayer(currentRectangle);
+
+ // Fit map to bounds
+ map.fitBounds(bounds, { padding: [50, 50] });
+
+ // Show success notification
+ showNotification('success', `Đã chọn tỉnh: ${provinceName}`);
+ }
+
+ // Populate region filter buttons
+ function populateRegionButtons() {
+ const container = document.getElementById('regionFilterContainer');
+
+ // Keep the "Tất cả" button
+ const allButton = container.querySelector('[data-region="all"]');
+ container.innerHTML = '';
+ container.appendChild(allButton);
+
+ // Get regions from current data
+ const provinceData = currentProvinceMode === '63' ? allProvinces : allProvincesMerged;
+ const regions = Object.keys(provinceData);
+
+ // Add button for each region
+ regions.forEach(region => {
+ const button = document.createElement('button');
+ button.type = 'button';
+ button.className = 'region-filter-btn';
+ button.dataset.region = region;
+ button.textContent = region;
+ button.style.cssText = 'padding: 8px 16px; background: #f0f0f0; color: #333; border: none; border-radius: 6px; cursor: pointer;';
+ container.appendChild(button);
+ });
+
+ // Re-setup event listeners
+ setupRegionFilters();
+ }
+
+ // Handle region filter
+ function setupRegionFilters() {
+ const filterButtons = document.querySelectorAll('.region-filter-btn');
+
+ filterButtons.forEach(btn => {
+ btn.addEventListener('click', function() {
+ // Update active button style
+ filterButtons.forEach(b => {
+ b.style.background = '#f0f0f0';
+ b.style.color = '#333';
+ b.style.fontWeight = 'normal';
+ });
+ this.style.background = '#667eea';
+ this.style.color = 'white';
+ this.style.fontWeight = '600';
+
+ // Filter provinces
+ const region = this.dataset.region;
+ populateProvinceSelect(region);
+ });
+ });
+ }
+
// Initialize map when page loads
document.addEventListener('DOMContentLoaded', function() {
initMap();
- initPredictionMap();
- loadPredictionsList(); // Load predictions list on page load
loadCacheInfo(); // Load cache info
+ loadProvinces(); // Load provinces list
+
+ // Add event listeners
+ document.getElementById('provinceSelect').addEventListener('change', onProvinceSelect);
+ setupRegionFilters();
// Add model type change listener
document.getElementById('modelType').addEventListener('change', updateModelTypeUI);
diff --git a/vietnam_provinces.py b/vietnam_provinces.py
new file mode 100644
index 0000000..0f42b7f
--- /dev/null
+++ b/vietnam_provinces.py
@@ -0,0 +1,376 @@
+"""
+Vietnam Provinces Boundaries
+Ranh giới các tỉnh thành Việt Nam với bbox coordinates
+"""
+
+VIETNAM_PROVINCES = {
+ "Toàn quốc": {
+ "bbox": [102.14, 8.18, 109.46, 23.39],
+ "name_en": "Vietnam (Full)",
+ "region": "Toàn quốc"
+ },
+
+ # Miền Bắc - Northern Region
+ "Hà Nội": {
+ "bbox": [105.35, 20.53, 105.92, 21.33],
+ "name_en": "Hanoi",
+ "region": "Miền Bắc"
+ },
+ "Hải Phòng": {
+ "bbox": [106.48, 20.70, 107.07, 21.09],
+ "name_en": "Hai Phong",
+ "region": "Miền Bắc"
+ },
+ "Quảng Ninh": {
+ "bbox": [106.48, 20.70, 108.26, 21.62],
+ "name_en": "Quang Ninh",
+ "region": "Miền Bắc"
+ },
+ "Lào Cai": {
+ "bbox": [103.22, 21.82, 104.45, 22.77],
+ "name_en": "Lao Cai",
+ "region": "Miền Bắc"
+ },
+ "Điện Biên": {
+ "bbox": [102.72, 21.09, 103.45, 22.21],
+ "name_en": "Dien Bien",
+ "region": "Miền Bắc"
+ },
+ "Lai Châu": {
+ "bbox": [102.72, 21.82, 103.72, 22.77],
+ "name_en": "Lai Chau",
+ "region": "Miền Bắc"
+ },
+ "Hà Giang": {
+ "bbox": [104.42, 22.33, 105.59, 23.39],
+ "name_en": "Ha Giang",
+ "region": "Miền Bắc"
+ },
+ "Cao Bằng": {
+ "bbox": [105.52, 22.24, 106.70, 23.04],
+ "name_en": "Cao Bang",
+ "region": "Miền Bắc"
+ },
+ "Bắc Kạn": {
+ "bbox": [105.48, 21.95, 106.15, 22.52],
+ "name_en": "Bac Kan",
+ "region": "Miền Bắc"
+ },
+ "Tuyên Quang": {
+ "bbox": [104.97, 21.65, 105.65, 22.42],
+ "name_en": "Tuyen Quang",
+ "region": "Miền Bắc"
+ },
+ "Thái Nguyên": {
+ "bbox": [105.48, 21.27, 106.15, 22.07],
+ "name_en": "Thai Nguyen",
+ "region": "Miền Bắc"
+ },
+ "Lạng Sơn": {
+ "bbox": [106.22, 21.40, 107.18, 22.41],
+ "name_en": "Lang Son",
+ "region": "Miền Bắc"
+ },
+ "Bắc Giang": {
+ "bbox": [105.97, 21.05, 106.70, 21.68],
+ "name_en": "Bac Giang",
+ "region": "Miền Bắc"
+ },
+ "Phú Thọ": {
+ "bbox": [104.83, 21.01, 105.48, 21.82],
+ "name_en": "Phu Tho",
+ "region": "Miền Bắc"
+ },
+ "Vĩnh Phúc": {
+ "bbox": [105.31, 21.14, 105.81, 21.61],
+ "name_en": "Vinh Phuc",
+ "region": "Miền Bắc"
+ },
+ "Bắc Ninh": {
+ "bbox": [105.83, 20.93, 106.26, 21.32],
+ "name_en": "Bac Ninh",
+ "region": "Miền Bắc"
+ },
+ "Hải Dương": {
+ "bbox": [106.14, 20.68, 106.70, 21.07],
+ "name_en": "Hai Duong",
+ "region": "Miền Bắc"
+ },
+ "Hưng Yên": {
+ "bbox": [105.83, 20.58, 106.26, 21.03],
+ "name_en": "Hung Yen",
+ "region": "Miền Bắc"
+ },
+ "Hà Nam": {
+ "bbox": [105.79, 20.33, 106.14, 20.73],
+ "name_en": "Ha Nam",
+ "region": "Miền Bắc"
+ },
+ "Nam Định": {
+ "bbox": [105.98, 20.04, 106.47, 20.64],
+ "name_en": "Nam Dinh",
+ "region": "Miền Bắc"
+ },
+ "Thái Bình": {
+ "bbox": [106.23, 20.27, 106.70, 20.76],
+ "name_en": "Thai Binh",
+ "region": "Miền Bắc"
+ },
+ "Ninh Bình": {
+ "bbox": [105.70, 20.05, 106.14, 20.50],
+ "name_en": "Ninh Binh",
+ "region": "Miền Bắc"
+ },
+ "Hòa Bình": {
+ "bbox": [104.83, 20.35, 105.74, 21.06],
+ "name_en": "Hoa Binh",
+ "region": "Miền Bắc"
+ },
+ "Sơn La": {
+ "bbox": [103.22, 20.66, 104.83, 21.82],
+ "name_en": "Son La",
+ "region": "Miền Bắc"
+ },
+ "Yên Bái": {
+ "bbox": [103.97, 21.35, 105.20, 22.21],
+ "name_en": "Yen Bai",
+ "region": "Miền Bắc"
+ },
+
+ # Miền Trung - Central Region
+ "Thanh Hóa": {
+ "bbox": [104.83, 19.33, 106.14, 20.66],
+ "name_en": "Thanh Hoa",
+ "region": "Miền Trung"
+ },
+ "Nghệ An": {
+ "bbox": [103.97, 18.34, 105.74, 19.89],
+ "name_en": "Nghe An",
+ "region": "Miền Trung"
+ },
+ "Hà Tĩnh": {
+ "bbox": [105.20, 17.98, 106.23, 18.78],
+ "name_en": "Ha Tinh",
+ "region": "Miền Trung"
+ },
+ "Quảng Bình": {
+ "bbox": [105.74, 16.97, 107.04, 18.06],
+ "name_en": "Quang Binh",
+ "region": "Miền Trung"
+ },
+ "Quảng Trị": {
+ "bbox": [106.48, 16.38, 107.54, 17.20],
+ "name_en": "Quang Tri",
+ "region": "Miền Trung"
+ },
+ "Thừa Thiên Huế": {
+ "bbox": [107.04, 16.01, 108.01, 16.95],
+ "name_en": "Thua Thien Hue",
+ "region": "Miền Trung"
+ },
+ "Đà Nẵng": {
+ "bbox": [107.77, 15.87, 108.33, 16.28],
+ "name_en": "Da Nang",
+ "region": "Miền Trung"
+ },
+ "Quảng Nam": {
+ "bbox": [107.04, 14.93, 108.70, 16.16],
+ "name_en": "Quang Nam",
+ "region": "Miền Trung"
+ },
+ "Quảng Ngãi": {
+ "bbox": [108.01, 14.66, 109.18, 15.53],
+ "name_en": "Quang Ngai",
+ "region": "Miền Trung"
+ },
+ "Bình Định": {
+ "bbox": [108.33, 13.76, 109.26, 14.72],
+ "name_en": "Binh Dinh",
+ "region": "Miền Trung"
+ },
+ "Phú Yên": {
+ "bbox": [108.70, 12.75, 109.46, 13.96],
+ "name_en": "Phu Yen",
+ "region": "Miền Trung"
+ },
+ "Khánh Hòa": {
+ "bbox": [108.70, 11.75, 109.46, 12.95],
+ "name_en": "Khanh Hoa",
+ "region": "Miền Trung"
+ },
+ "Ninh Thuận": {
+ "bbox": [108.33, 11.27, 109.18, 12.04],
+ "name_en": "Ninh Thuan",
+ "region": "Miền Trung"
+ },
+ "Bình Thuận": {
+ "bbox": [107.54, 10.49, 108.70, 11.75],
+ "name_en": "Binh Thuan",
+ "region": "Miền Trung"
+ },
+ "Kon Tum": {
+ "bbox": [107.54, 13.95, 108.70, 15.17],
+ "name_en": "Kon Tum",
+ "region": "Tây Nguyên"
+ },
+ "Gia Lai": {
+ "bbox": [107.54, 13.17, 108.70, 14.72],
+ "name_en": "Gia Lai",
+ "region": "Tây Nguyên"
+ },
+ "Đắk Lắk": {
+ "bbox": [107.54, 12.24, 108.70, 13.40],
+ "name_en": "Dak Lak",
+ "region": "Tây Nguyên"
+ },
+ "Đắk Nông": {
+ "bbox": [107.04, 11.75, 108.33, 12.75],
+ "name_en": "Dak Nong",
+ "region": "Tây Nguyên"
+ },
+ "Lâm Đồng": {
+ "bbox": [107.04, 10.99, 108.70, 12.52],
+ "name_en": "Lam Dong",
+ "region": "Tây Nguyên"
+ },
+
+ # Miền Nam - Southern Region
+ "Hồ Chí Minh": {
+ "bbox": [106.36, 10.35, 107.04, 11.16],
+ "name_en": "Ho Chi Minh City",
+ "region": "Miền Nam"
+ },
+ "Đồng Nai": {
+ "bbox": [106.70, 10.49, 107.54, 11.51],
+ "name_en": "Dong Nai",
+ "region": "Miền Nam"
+ },
+ "Bình Dương": {
+ "bbox": [106.36, 10.87, 106.96, 11.51],
+ "name_en": "Binh Duong",
+ "region": "Miền Nam"
+ },
+ "Bà Rịa - Vũng Tàu": {
+ "bbox": [107.04, 10.16, 107.77, 10.87],
+ "name_en": "Ba Ria - Vung Tau",
+ "region": "Miền Nam"
+ },
+ "Bình Phước": {
+ "bbox": [106.36, 11.16, 107.54, 12.24],
+ "name_en": "Binh Phuoc",
+ "region": "Miền Nam"
+ },
+ "Tây Ninh": {
+ "bbox": [105.74, 10.87, 106.70, 11.75],
+ "name_en": "Tay Ninh",
+ "region": "Miền Nam"
+ },
+ "Long An": {
+ "bbox": [105.74, 10.16, 106.70, 11.16],
+ "name_en": "Long An",
+ "region": "Miền Nam"
+ },
+ "Tiền Giang": {
+ "bbox": [105.74, 9.99, 106.70, 10.70],
+ "name_en": "Tien Giang",
+ "region": "Miền Nam"
+ },
+ "Bến Tre": {
+ "bbox": [105.98, 9.77, 106.70, 10.35],
+ "name_en": "Ben Tre",
+ "region": "Miền Nam"
+ },
+ "Đồng Tháp": {
+ "bbox": [105.20, 10.16, 105.98, 11.16],
+ "name_en": "Dong Thap",
+ "region": "Miền Nam"
+ },
+ "Vĩnh Long": {
+ "bbox": [105.74, 9.77, 106.36, 10.35],
+ "name_en": "Vinh Long",
+ "region": "Miền Nam"
+ },
+ "Trà Vinh": {
+ "bbox": [105.98, 9.33, 106.70, 10.04],
+ "name_en": "Tra Vinh",
+ "region": "Miền Nam"
+ },
+ "An Giang": {
+ "bbox": [104.83, 9.99, 105.74, 10.99],
+ "name_en": "An Giang",
+ "region": "Miền Nam"
+ },
+ "Kiên Giang": {
+ "bbox": [103.22, 8.68, 105.48, 10.52],
+ "name_en": "Kien Giang",
+ "region": "Miền Nam"
+ },
+ "Cần Thơ": {
+ "bbox": [105.48, 9.77, 106.14, 10.35],
+ "name_en": "Can Tho",
+ "region": "Miền Nam"
+ },
+ "Hậu Giang": {
+ "bbox": [105.31, 9.33, 105.98, 9.99],
+ "name_en": "Hau Giang",
+ "region": "Miền Nam"
+ },
+ "Sóc Trăng": {
+ "bbox": [105.48, 9.16, 106.23, 9.99],
+ "name_en": "Soc Trang",
+ "region": "Miền Nam"
+ },
+ "Bạc Liêu": {
+ "bbox": [105.31, 8.93, 105.98, 9.60],
+ "name_en": "Bac Lieu",
+ "region": "Miền Nam"
+ },
+ "Cà Mau": {
+ "bbox": [104.58, 8.18, 105.48, 9.60],
+ "name_en": "Ca Mau",
+ "region": "Miền Nam"
+ },
+}
+
+
+def get_all_provinces():
+ """Lấy danh sách tất cả các tỉnh thành"""
+ return list(VIETNAM_PROVINCES.keys())
+
+
+def get_provinces_by_region():
+ """Lấy danh sách tỉnh thành theo vùng miền"""
+ regions = {}
+ for province, data in VIETNAM_PROVINCES.items():
+ region = data["region"]
+ if region not in regions:
+ regions[region] = []
+ regions[region].append({
+ "name": province,
+ "name_en": data["name_en"],
+ "bbox": data["bbox"]
+ })
+ return regions
+
+
+def get_province_bbox(province_name):
+ """Lấy bbox của một tỉnh thành"""
+ if province_name in VIETNAM_PROVINCES:
+ return VIETNAM_PROVINCES[province_name]["bbox"]
+ return None
+
+
+def search_province(query):
+ """Tìm kiếm tỉnh thành theo tên"""
+ query = query.lower()
+ results = []
+ for province, data in VIETNAM_PROVINCES.items():
+ if (query in province.lower() or
+ query in data["name_en"].lower()):
+ results.append({
+ "name": province,
+ "name_en": data["name_en"],
+ "bbox": data["bbox"],
+ "region": data["region"]
+ })
+ return results
diff --git a/vietnam_provinces_merged.py b/vietnam_provinces_merged.py
new file mode 100644
index 0000000..fd09b9d
--- /dev/null
+++ b/vietnam_provinces_merged.py
@@ -0,0 +1,461 @@
+"""
+Vietnam Provinces After Administrative Merger (32 provinces)
+32 tỉnh thành Việt Nam sau sáp nhập theo Nghị quyết 1211/2023
+Bbox đã được mở rộng để bao phủ các tỉnh đã hợp nhất
+"""
+
+VIETNAM_PROVINCES_32 = {
+ # Thành phố trực thuộc TW (5)
+ "Hà Nội": {
+ "bbox": [105.35, 20.53, 105.92, 21.33],
+ "name_en": "Hanoi",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": None,
+ "area_km2": 3359
+ },
+
+ "Hải Phòng": {
+ "bbox": [106.14, 20.68, 107.07, 21.09], # Bao gồm cả Hải Dương
+ "name_en": "Hai Phong",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": ["Hải Phòng", "Hải Dương"],
+ "area_km2": 2914
+ },
+
+ "Đà Nẵng": {
+ "bbox": [107.04, 14.93, 108.70, 16.28], # Bao gồm cả Quảng Nam
+ "name_en": "Da Nang - Quang Nam",
+ "region": "Duyên hải Nam Trung Bộ",
+ "merged_from": ["Đà Nẵng", "Quảng Nam"],
+ "area_km2": 11065
+ },
+
+ "Hồ Chí Minh": {
+ "bbox": [106.36, 10.35, 107.04, 11.16],
+ "name_en": "Ho Chi Minh City",
+ "region": "Đông Nam Bộ",
+ "merged_from": None,
+ "area_km2": 2061
+ },
+
+ "Cần Thơ": {
+ "bbox": [105.48, 9.77, 106.14, 10.35],
+ "name_en": "Can Tho",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": None,
+ "area_km2": 1402
+ },
+
+ # Các tỉnh sau sáp nhập (27)
+
+ # Vùng núi phía Bắc
+ "Lào Cai": {
+ "bbox": [103.22, 21.82, 104.45, 22.77],
+ "name_en": "Lao Cai",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": None,
+ "area_km2": 6384
+ },
+
+ "Điện Biên": {
+ "bbox": [102.72, 21.09, 103.72, 22.21], # Bao gồm cả Lai Châu
+ "name_en": "Dien Bien - Lai Chau",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": ["Điện Biên", "Lai Châu"],
+ "area_km2": 15274
+ },
+
+ "Hà Giang": {
+ "bbox": [104.42, 22.33, 105.59, 23.39],
+ "name_en": "Ha Giang",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": None,
+ "area_km2": 7946
+ },
+
+ "Cao Bằng": {
+ "bbox": [105.48, 21.95, 106.70, 23.04], # Bao gồm cả Bắc Kạn
+ "name_en": "Cao Bang - Bac Kan",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": ["Cao Bằng", "Bắc Kạn"],
+ "area_km2": 11335
+ },
+
+ "Lạng Sơn": {
+ "bbox": [106.22, 21.40, 107.18, 22.41],
+ "name_en": "Lang Son",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": None,
+ "area_km2": 8327
+ },
+
+ "Tuyên Quang": {
+ "bbox": [104.97, 21.65, 105.65, 22.42],
+ "name_en": "Tuyen Quang",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": None,
+ "area_km2": 5868
+ },
+
+ "Yên Bái": {
+ "bbox": [103.97, 21.35, 105.20, 22.21],
+ "name_en": "Yen Bai",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": None,
+ "area_km2": 6899
+ },
+
+ "Thái Nguyên": {
+ "bbox": [105.48, 21.27, 106.15, 22.07],
+ "name_en": "Thai Nguyen",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": None,
+ "area_km2": 3534
+ },
+
+ "Phú Thọ": {
+ "bbox": [104.83, 21.01, 105.48, 21.82],
+ "name_en": "Phu Tho",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": None,
+ "area_km2": 3533
+ },
+
+ "Hòa Bình": {
+ "bbox": [103.22, 20.35, 105.74, 21.82], # Bao gồm cả Sơn La
+ "name_en": "Hoa Binh - Son La",
+ "region": "Vùng núi phía Bắc",
+ "merged_from": ["Hòa Bình", "Sơn La"],
+ "area_km2": 19210
+ },
+
+ # Đồng bằng Bắc Bộ
+ "Quảng Ninh": {
+ "bbox": [106.48, 20.70, 108.26, 21.62],
+ "name_en": "Quang Ninh",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": None,
+ "area_km2": 6102
+ },
+
+ "Bắc Ninh": {
+ "bbox": [105.83, 20.93, 106.70, 21.68], # Bao gồm cả Bắc Giang
+ "name_en": "Bac Ninh - Bac Giang",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": ["Bắc Ninh", "Bắc Giang"],
+ "area_km2": 4631
+ },
+
+ "Vĩnh Phúc": {
+ "bbox": [105.31, 21.14, 105.81, 21.61],
+ "name_en": "Vinh Phuc",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": None,
+ "area_km2": 1236
+ },
+
+ "Hưng Yên": {
+ "bbox": [105.83, 20.58, 106.26, 21.03],
+ "name_en": "Hung Yen",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": None,
+ "area_km2": 926
+ },
+
+ "Nam Định": {
+ "bbox": [105.79, 20.04, 106.47, 20.73], # Bao gồm cả Hà Nam
+ "name_en": "Nam Dinh - Ha Nam",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": ["Nam Định", "Hà Nam"],
+ "area_km2": 2442
+ },
+
+ "Thái Bình": {
+ "bbox": [106.23, 20.27, 106.70, 20.76],
+ "name_en": "Thai Binh",
+ "region": "Đồng bằng Bắc Bộ",
+ "merged_from": None,
+ "area_km2": 1570
+ },
+
+ # Bắc Trung Bộ
+ "Thanh Hóa": {
+ "bbox": [104.83, 19.33, 106.14, 20.66], # Bao gồm cả Ninh Bình
+ "name_en": "Thanh Hoa - Ninh Binh",
+ "region": "Bắc Trung Bộ",
+ "merged_from": ["Thanh Hóa", "Ninh Bình"],
+ "area_km2": 12490
+ },
+
+ "Nghệ An": {
+ "bbox": [103.97, 17.98, 106.23, 19.89], # Bao gồm cả Hà Tĩnh
+ "name_en": "Nghe An - Ha Tinh",
+ "region": "Bắc Trung Bộ",
+ "merged_from": ["Nghệ An", "Hà Tĩnh"],
+ "area_km2": 22793
+ },
+
+ "Quảng Bình": {
+ "bbox": [105.74, 16.97, 107.04, 18.06],
+ "name_en": "Quang Binh",
+ "region": "Bắc Trung Bộ",
+ "merged_from": None,
+ "area_km2": 8065
+ },
+
+ "Quảng Trị": {
+ "bbox": [106.48, 16.38, 107.54, 17.20],
+ "name_en": "Quang Tri",
+ "region": "Bắc Trung Bộ",
+ "merged_from": None,
+ "area_km2": 4746
+ },
+
+ "Thừa Thiên Huế": {
+ "bbox": [107.04, 16.01, 108.01, 16.95],
+ "name_en": "Thua Thien Hue",
+ "region": "Bắc Trung Bộ",
+ "merged_from": None,
+ "area_km2": 5033
+ },
+
+ # Duyên hải Nam Trung Bộ
+ "Quảng Ngãi": {
+ "bbox": [108.01, 14.66, 109.18, 15.53],
+ "name_en": "Quang Ngai",
+ "region": "Duyên hải Nam Trung Bộ",
+ "merged_from": None,
+ "area_km2": 5153
+ },
+
+ "Bình Định": {
+ "bbox": [108.33, 12.75, 109.46, 14.72], # Bao gồm cả Phú Yên
+ "name_en": "Binh Dinh - Phu Yen",
+ "region": "Duyên hải Nam Trung Bộ",
+ "merged_from": ["Bình Định", "Phú Yên"],
+ "area_km2": 11092
+ },
+
+ "Khánh Hòa": {
+ "bbox": [108.70, 11.75, 109.46, 12.95],
+ "name_en": "Khanh Hoa",
+ "region": "Duyên hải Nam Trung Bộ",
+ "merged_from": None,
+ "area_km2": 5218
+ },
+
+ "Bình Thuận": {
+ "bbox": [107.54, 10.49, 109.18, 12.04], # Bao gồm cả Ninh Thuận
+ "name_en": "Binh Thuan - Ninh Thuan",
+ "region": "Duyên hải Nam Trung Bộ",
+ "merged_from": ["Bình Thuận", "Ninh Thuận"],
+ "area_km2": 11234
+ },
+
+ # Tây Nguyên
+ "Gia Lai": {
+ "bbox": [107.54, 13.17, 108.70, 15.17], # Bao gồm cả Kon Tum
+ "name_en": "Gia Lai - Kon Tum",
+ "region": "Tây Nguyên",
+ "merged_from": ["Gia Lai", "Kon Tum"],
+ "area_km2": 25536
+ },
+
+ "Đắk Lắk": {
+ "bbox": [107.04, 11.75, 108.70, 13.40], # Bao gồm cả Đắk Nông
+ "name_en": "Dak Lak - Dak Nong",
+ "region": "Tây Nguyên",
+ "merged_from": ["Đắk Lắk", "Đắk Nông"],
+ "area_km2": 19850
+ },
+
+ "Lâm Đồng": {
+ "bbox": [107.04, 10.99, 108.70, 12.52],
+ "name_en": "Lam Dong",
+ "region": "Tây Nguyên",
+ "merged_from": None,
+ "area_km2": 9776
+ },
+
+ # Đông Nam Bộ
+ "Đồng Nai": {
+ "bbox": [106.36, 10.49, 107.54, 12.24], # Bao gồm cả Bình Phước
+ "name_en": "Dong Nai - Binh Phuoc",
+ "region": "Đông Nam Bộ",
+ "merged_from": ["Đồng Nai", "Bình Phước"],
+ "area_km2": 13317
+ },
+
+ "Bình Dương": {
+ "bbox": [106.36, 10.87, 106.96, 11.51],
+ "name_en": "Binh Duong",
+ "region": "Đông Nam Bộ",
+ "merged_from": None,
+ "area_km2": 2695
+ },
+
+ "Bà Rịa - Vũng Tàu": {
+ "bbox": [107.04, 10.16, 107.77, 10.87],
+ "name_en": "Ba Ria - Vung Tau",
+ "region": "Đông Nam Bộ",
+ "merged_from": None,
+ "area_km2": 1990
+ },
+
+ "Tây Ninh": {
+ "bbox": [105.74, 10.87, 106.70, 11.75],
+ "name_en": "Tay Ninh",
+ "region": "Đông Nam Bộ",
+ "merged_from": None,
+ "area_km2": 4040
+ },
+
+ # Đồng bằng sông Cửu Long
+ "Tiền Giang": {
+ "bbox": [105.74, 9.99, 106.70, 11.16], # Bao gồm cả Long An
+ "name_en": "Tien Giang - Long An",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": ["Tiền Giang", "Long An"],
+ "area_km2": 6935
+ },
+
+ "Bến Tre": {
+ "bbox": [105.98, 9.77, 106.70, 10.35],
+ "name_en": "Ben Tre",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": None,
+ "area_km2": 2360
+ },
+
+ "Vĩnh Long": {
+ "bbox": [105.74, 9.33, 106.70, 10.35], # Bao gồm cả Trà Vinh
+ "name_en": "Vinh Long - Tra Vinh",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": ["Vĩnh Long", "Trà Vinh"],
+ "area_km2": 4567
+ },
+
+ "Đồng Tháp": {
+ "bbox": [105.20, 10.16, 105.98, 11.16],
+ "name_en": "Dong Thap",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": None,
+ "area_km2": 3377
+ },
+
+ "An Giang": {
+ "bbox": [104.83, 9.99, 105.74, 10.99],
+ "name_en": "An Giang",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": None,
+ "area_km2": 3537
+ },
+
+ "Kiên Giang": {
+ "bbox": [103.22, 8.68, 105.48, 10.52],
+ "name_en": "Kien Giang",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": None,
+ "area_km2": 6348
+ },
+
+ "Sóc Trăng": {
+ "bbox": [105.31, 9.16, 106.23, 9.99], # Bao gồm cả Hậu Giang
+ "name_en": "Soc Trang - Hau Giang",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": ["Sóc Trăng", "Hậu Giang"],
+ "area_km2": 4750
+ },
+
+ "Bạc Liêu": {
+ "bbox": [105.31, 8.93, 105.98, 9.60],
+ "name_en": "Bac Lieu",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": None,
+ "area_km2": 2585
+ },
+
+ "Cà Mau": {
+ "bbox": [104.58, 8.18, 105.48, 9.60],
+ "name_en": "Ca Mau",
+ "region": "Đồng bằng sông Cửu Long",
+ "merged_from": None,
+ "area_km2": 5332
+ },
+}
+
+
+def get_all_provinces_32():
+ """Lấy danh sách tất cả 32 tỉnh thành sau sáp nhập"""
+ return list(VIETNAM_PROVINCES_32.keys())
+
+
+def get_provinces_by_region_32():
+ """Lấy danh sách 32 tỉnh thành theo vùng miền"""
+ regions = {}
+ for province, data in VIETNAM_PROVINCES_32.items():
+ region = data["region"]
+ if region not in regions:
+ regions[region] = []
+ regions[region].append({
+ "name": province,
+ "name_en": data["name_en"],
+ "bbox": data["bbox"],
+ "merged_from": data.get("merged_from"),
+ "area_km2": data.get("area_km2")
+ })
+ return regions
+
+
+def get_province_bbox_32(province_name):
+ """Lấy bbox của một tỉnh thành (32 tỉnh)"""
+ if province_name in VIETNAM_PROVINCES_32:
+ return VIETNAM_PROVINCES_32[province_name]["bbox"]
+ return None
+
+
+def get_merged_info(province_name):
+ """Lấy thông tin sáp nhập của tỉnh"""
+ if province_name in VIETNAM_PROVINCES_32:
+ data = VIETNAM_PROVINCES_32[province_name]
+ return {
+ "name": province_name,
+ "bbox": data["bbox"],
+ "merged_from": data.get("merged_from"),
+ "region": data["region"],
+ "area_km2": data.get("area_km2")
+ }
+ return None
+
+
+def search_province_32(query):
+ """Tìm kiếm tỉnh thành theo tên (32 tỉnh)"""
+ query = query.lower()
+ results = []
+ for province, data in VIETNAM_PROVINCES_32.items():
+ if (query in province.lower() or
+ query in data["name_en"].lower()):
+ results.append({
+ "name": province,
+ "name_en": data["name_en"],
+ "bbox": data["bbox"],
+ "region": data["region"],
+ "merged_from": data.get("merged_from"),
+ "area_km2": data.get("area_km2")
+ })
+ return results
+
+
+def get_provinces_statistics():
+ """Thống kê các tỉnh đã sáp nhập"""
+ total = len(VIETNAM_PROVINCES_32)
+ merged = len([p for p in VIETNAM_PROVINCES_32.values() if p.get("merged_from")])
+ original = total - merged
+
+ return {
+ "total_provinces": total,
+ "merged_provinces": merged,
+ "original_provinces": original,
+ "regions": list(set(p["region"] for p in VIETNAM_PROVINCES_32.values())),
+ "total_area_km2": sum(p.get("area_km2", 0) for p in VIETNAM_PROVINCES_32.values())
+ }