CoolFace
Apppublic

Minjin1050/mn-geocoding-api

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
index.html423 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="mn">3  <head>4    <meta charset="UTF-8" />5    <meta name="viewport" content="width=device-width, initial-scale=1.0" />6    <title>Geocoding API (Pro Version)</title>7    <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />8    <style>9      :root {10        --primary: #2563eb;11        --error: #dc2626;12        --success: #16a34a;13        --bg: #f8fafc;14      }15      body {16        font-family: sans-serif;17        background: var(--bg);18        margin: 0;19        padding: 20px;20      }21      .container {22        max-width: 1000px;23        margin: auto;24        background: white;25        padding: 25px;26        border-radius: 12px;27        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);28      }29 30      /* Tabs */31      .tabs {32        display: flex;33        gap: 5px;34        margin-bottom: 20px;35        border-bottom: 2px solid #e2e8f0;36      }37      .tab-btn {38        padding: 10px 20px;39        cursor: pointer;40        border: none;41        background: none;42        font-weight: bold;43        color: #64748b;44      }45      .tab-btn.active {46        color: var(--primary);47        border-bottom: 2px solid var(--primary);48      }49 50      .section {51        margin-bottom: 20px;52        padding: 15px;53        border: 1px solid #e2e8f0;54        border-radius: 8px;55      }56      .input-group {57        display: flex;58        gap: 10px;59        margin-bottom: 15px;60        flex-wrap: wrap;61      }62      input[type="text"],63      input[type="number"] {64        flex: 1;65        padding: 10px;66        border: 1px solid #cbd5e1;67        border-radius: 5px;68        min-width: 150px;69      }70      button {71        padding: 10px 20px;72        cursor: pointer;73        border: none;74        border-radius: 5px;75        background: var(--primary);76        color: white;77        font-weight: bold;78      }79 80      .hidden {81        display: none;82      }83      #mapContainer {84        height: 450px;85        border-radius: 8px;86        border: 1px solid #cbd5e1;87        margin-top: 15px;88      }89 90      /* Custom Marker Styles */91      .marker-pin {92        width: 30px;93        height: 30px;94        border-radius: 50% 50% 50% 0;95        position: absolute;96        transform: rotate(-45deg);97        left: 50%;98        top: 50%;99        margin: -15px 0 0 -15px;100        display: flex;101        align-items: center;102        justify-content: center;103        color: white;104        font-weight: bold;105        border: 2px solid white;106      }107      .marker-pin span {108        transform: rotate(45deg);109        display: inline-block;110      }111 112      table {113        width: 100%;114        border-collapse: collapse;115        margin-top: 15px;116        font-size: 13px;117      }118      th,119      td {120        border: 1px solid #e2e8f0;121        padding: 8px;122        text-align: left;123      }124      th {125        background: #f1f5f9;126      }127    </style>128  </head>129  <body>130    <div class="container">131      <h1>📍 Geocoding Enterprise</h1>132 133      <div class="tabs">134        <button class="tab-btn active" onclick="openTab(event, 'searchTab')">135          🔍 Хайлт & Файл136        </button>137        <button class="tab-btn" onclick="openTab(event, 'validateTab')">138          🧪 50м Шалгалт139        </button>140      </div>141 142      <div id="searchTab" class="tab-content">143        <div class="section">144          <h3>🔍 Ганцаарчилсан хайлт</h3>145          <div class="input-group">146            <input147              type="text"148              id="addressInput"149              placeholder="Хаяг оруулна уу..."150            />151            <button id="geocodeButton">Хөрвүүлэх</button>152          </div>153        </div>154 155        <div class="section">156          <h3>📁 Олноор боловсруулах (CSV / JSON)</h3>157          <input type="file" id="fileInput" accept=".csv, .json" />158          <button id="uploadButton">Файл илгээх</button>159          <div160            id="batchStatus"161            class="hidden"162            style="margin-top: 10px; color: var(--primary)"163          ></div>164        </div>165 166        <div id="downloadSection" class="section hidden">167          <button onclick="exportData('csv')">CSV татах</button>168          <button onclick="exportData('json')" style="background: #475569">169            JSON татах170          </button>171        </div>172      </div>173 174      <div id="validateTab" class="tab-content hidden">175        <div class="section">176          <h3>🧪 Моделийн таамаглалыг шалгах (50m)</h3>177          <div class="input-group">178            <input type="text" id="v_address" placeholder="Текст хаяг..." />179            <input180              type="number"181              id="v_lat"182              step="any"183              placeholder="Өргөрөг (Lat)"184            />185            <input186              type="number"187              id="v_lon"188              step="any"189              placeholder="Уртраг (Lon)"190            />191            <button192              onclick="validateAddress()"193              style="background: var(--success)"194            >195              Шалгах196            </button>197          </div>198          <p style="font-size: 12px; color: #64748b">199            * Мап дээр дарж координатыг шууд авч болно.200          </p>201        </div>202        <div id="valResults" class="section hidden">203          <button onclick="downloadValCsv(false)">Бүгдийг татах</button>204          <button205            onclick="downloadValCsv(true)"206            style="background: var(--error)"207          >208            Зөвхөн бурууг татах209          </button>210          <div id="valTableContainer"></div>211        </div>212      </div>213 214      <div id="mapContainer"></div>215    </div>216 217    <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>218    <script>219      const API_BASE_URL = "https://minjin1050-mn-geocoding-api.hf.space";      let map, markerGroup;220      let batchResults = [];221      let valHistory = [];222 223      document.addEventListener("DOMContentLoaded", () => {224        map = L.map("mapContainer").setView([47.918, 106.918], 13);225        L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(226          map227        );228        markerGroup = L.layerGroup().addTo(map);229 230        // Газрын зураг дээр дарахад координат авах (Validate tab-д)231        map.on("click", (e) => {232          document.getElementById("v_lat").value = e.latlng.lat.toFixed(6);233          document.getElementById("v_lon").value = e.latlng.lng.toFixed(6);234        });235      });236 237      function openTab(evt, tabName) {238        document239          .querySelectorAll(".tab-content")240          .forEach((t) => t.classList.add("hidden"));241        document242          .querySelectorAll(".tab-btn")243          .forEach((b) => b.classList.remove("active"));244        document.getElementById(tabName).classList.remove("hidden");245        evt.currentTarget.classList.add("active");246      }247 248      // --- CUSTOM MARKER ---249      function createMarker(latlng, num, color, title, desc) {250        const icon = L.divIcon({251          className: "custom-pin",252          html: `<div style="background-color: ${color};" class="marker-pin"><span>${num}</span></div>`,253          iconSize: [30, 30],254          iconAnchor: [15, 30],255        });256        return L.marker(latlng, { icon: icon }).bindPopup(257          `<b>${title}</b><br>${desc}`258        );259      }260 261      // --- TAB 1: SINGLE & BATCH ---262      document.getElementById("geocodeButton").onclick = async () => {263        const addr = document.getElementById("addressInput").value;264        const res = await fetch(`${API_BASE_URL}/geocode/single`, {265          method: "POST",266          headers: { "Content-Type": "application/json" },267          body: JSON.stringify({ address: addr }),268        }).then((r) => r.json());269 270        markerGroup.clearLayers();271        if (res.latitude !== 0) {272          const m = createMarker(273            [res.latitude, res.longitude],274            1,275            "#2563eb",276            "Олдсон",277            res.address278          );279          markerGroup.addLayer(m);280          map.setView([res.latitude, res.longitude], 15);281        } else alert("Хаяг олдсонгүй");282      };283 284      document.getElementById("uploadButton").onclick = async () => {285        const file = document.getElementById("fileInput").files[0];286        if (!file) return alert("Файл сонгоно уу!");287        const formData = new FormData();288        formData.append("file", file);289 290        document.getElementById("batchStatus").classList.remove("hidden");291        document.getElementById("batchStatus").innerText =292          "Боловсруулж байна...";293 294        try {295          const resp = await fetch(`${API_BASE_URL}/geocode/batch-file`, {296            method: "POST",297            body: formData,298          });299          batchResults = await resp.json();300          document.getElementById(301            "batchStatus"302          ).innerText = `Нийт ${batchResults.length} хаяг бэлэн боллоо.`;303          document.getElementById("downloadSection").classList.remove("hidden");304        } catch (e) {305          alert("Алдаа гарлаа");306        }307      };308 309      // --- TAB 2: VALIDATE ---310      async function validateAddress() {311        const addr = document.getElementById("v_address").value;312        const lat = parseFloat(document.getElementById("v_lat").value);313        const lon = parseFloat(document.getElementById("v_lon").value);314 315        if (!addr || isNaN(lat)) return alert("Мэдээлэл дутуу");316 317        const res = await fetch(`${API_BASE_URL}/geocode/validate`, {318          method: "POST",319          headers: { "Content-Type": "application/json" },320          body: JSON.stringify({ address: addr, user_lat: lat, user_lon: lon }),321        }).then((r) => r.json());322 323        if (res.status === "error") return alert(res.message);324        // ... (fetch хийсний дараах хэсэг)325          markerGroup.clearLayers(); // Хуучин пинүүдийг арилгах326 327// Хэрэглэгчийн цэг (Цэнхэр)328          const userMarker = createMarker([lat, lon], "U", "#2563eb", "Таны өгсөн", addr);329          markerGroup.addLayer(userMarker);330 331// Моделийн цэг (Ногоон/Улаан)332          const pLat = res.predicted_coords.lat;333          const pLon = res.predicted_coords.lon;334          const predMarker = createMarker([pLat, pLon], "M", res.is_correct ? "#16a34a" : "#dc2626", "Модел", res.predicted_address);335        markerGroup.addLayer(predMarker);336 337// Газрын зургийг хоёр цэг харагдахаар тааруулах338const bounds = L.latLngBounds([lat, lon], [pLat, pLon]);339map.fitBounds(bounds, {padding: [50, 50]});340        const index = valHistory.length + 1;341        const isCorrect = res.is_correct;342 343        valHistory.push({ ...res, id: index });344 345        // Мап дээр зурах346        const uM = createMarker(347          [lat, lon],348          index,349          "#2563eb",350          "Таны өгсөн",351          addr352        );353        const pM = createMarker(354          [res.predicted_coords.lat, res.predicted_coords.lon],355          index,356          isCorrect ? "#16a34a" : "#dc2626",357          "Модел",358          res.predicted_address359        );360 361        markerGroup.addLayer(uM);362        markerGroup.addLayer(pM);363        renderValTable();364        document.getElementById("valResults").classList.remove("hidden");365      }366 367      function renderValTable() {368        let h = `<table><tr><th>ID</th><th>Таамаглал</th><th>Зай(м)</th><th>Төлөв</th></tr>`;369        valHistory.forEach((v) => {370          h += `<tr><td>${v.id}</td><td>${v.predicted_address}</td><td>${371            v.distance_meters372          }</td><td style="color:${v.is_correct ? "green" : "red"}">${373            v.is_correct ? "Зөв" : "Буруу"374          }</td></tr>`;375        });376        document.getElementById("valTableContainer").innerHTML = h + `</table>`;377      }378 379      function downloadValCsv(onlyErr) {380        const data = onlyErr381          ? valHistory.filter((v) => !v.is_correct)382          : valHistory;383        let csv = "\ufeffID,Input,Predicted,Distance,Status\n";384        data.forEach(385          (v) =>386            (csv += `${v.id},"${v.input_address}","${v.predicted_address}",${387              v.distance_meters388            },${v.is_correct ? "Ok" : "Fail"}\n`)389        );390        const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });391        const a = document.createElement("a");392        a.href = URL.createObjectURL(blob);393        a.download = "validation.csv";394        a.click();395      }396 397      function exportData(type) {398        let content, name, mime;399        if (type === "json") {400          content = JSON.stringify(batchResults, null, 2);401          name = "results.json";402          mime = "application/json";403        } else {404          content =405            "Input,Matched,Lat,Lon\n" +406            batchResults407              .map(408                (r) =>409                  `"${r.input_address}","${r.address}",${r.latitude},${r.longitude}`410              )411              .join("\n");412          name = "results.csv";413          mime = "text/csv";414        }415        const a = document.createElement("a");416        a.href = URL.createObjectURL(new Blob([content], { type: mime }));417        a.download = name;418        a.click();419      }420    </script>421  </body>422</html>423