Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -191,36 +191,40 @@ def home():
|
|
| 191 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
| 192 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 193 |
<style>
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
.
|
| 197 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
</style>
|
| 199 |
</head>
|
| 200 |
-
<body class="
|
| 201 |
|
| 202 |
-
<nav class="
|
| 203 |
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
|
| 204 |
<div class="flex items-center gap-4">
|
| 205 |
-
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Seal_of_Meghalaya.svg/150px-Seal_of_Meghalaya.svg.png" class="h-
|
| 206 |
<div>
|
| 207 |
<h2 class="text-[10px] md:text-xs font-bold text-slate-500 uppercase tracking-[0.2em]" data-translate="govt_title">GOVERNMENT OF MEGHALAYA</h2>
|
| 208 |
-
<h1 class="text-
|
| 209 |
-
<p class="text-[10px] font-bold flex items-center gap-
|
| 210 |
-
<span class="flex h-2 w-2
|
| 211 |
-
|
| 212 |
-
|
| 213 |
</span>
|
| 214 |
-
<span
|
| 215 |
</p>
|
| 216 |
</div>
|
| 217 |
</div>
|
| 218 |
|
| 219 |
<div class="flex flex-col items-end gap-2">
|
| 220 |
-
<select id="lang-select" onchange="changeLanguage()" class="bg-slate-
|
| 221 |
<option value="en">🇬🇧 English</option>
|
| 222 |
<option value="hi">🇮🇳 हिंदी</option>
|
| 223 |
-
<option value="as">🇮🇳 অসমীয়া</option>
|
| 224 |
<option value="kha">🌲 Khasi</option>
|
| 225 |
<option value="gar">⛰️ Garo</option>
|
| 226 |
</select>
|
|
@@ -230,36 +234,36 @@ def home():
|
|
| 230 |
|
| 231 |
<div class="container mx-auto mt-8 p-4 max-w-5xl flex-grow">
|
| 232 |
|
| 233 |
-
<div class="grid grid-cols-3 md:grid-cols-6 gap-
|
| 234 |
-
<button onclick="setTask('lungs', 'image')" id="btn-lungs" class="
|
| 235 |
-
<div class="
|
| 236 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_lungs">Lungs</span>
|
| 237 |
</button>
|
| 238 |
-
<button onclick="setTask('cough', 'audio')" id="btn-cough" class="
|
| 239 |
-
<div class="
|
| 240 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_cough">Cough</span>
|
| 241 |
</button>
|
| 242 |
-
<button onclick="setTask('fracture', 'image')" id="btn-fracture" class="
|
| 243 |
-
<div class="
|
| 244 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_bone">Fracture</span>
|
| 245 |
</button>
|
| 246 |
-
<button onclick="setTask('brain', 'image')" id="btn-brain" class="
|
| 247 |
-
<div class="
|
| 248 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_brain">Brain</span>
|
| 249 |
</button>
|
| 250 |
-
<button onclick="setTask('eye', 'image')" id="btn-eye" class="
|
| 251 |
-
<div class="
|
| 252 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_eye">Eye</span>
|
| 253 |
</button>
|
| 254 |
-
<button onclick="setTask('skin', 'image')" id="btn-skin" class="
|
| 255 |
-
<div class="
|
| 256 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_skin">Skin</span>
|
| 257 |
</button>
|
| 258 |
</div>
|
| 259 |
|
| 260 |
-
<div class="glass
|
| 261 |
|
| 262 |
-
<div id="scope-box" class="hidden bg-slate-50 border-b border-slate-100 p-3 text-center">
|
| 263 |
<p class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-2" data-translate="lbl_scope">Scope of Detection</p>
|
| 264 |
<div id="scope-tags" class="flex flex-wrap justify-center gap-2"></div>
|
| 265 |
</div>
|
|
@@ -267,36 +271,37 @@ def home():
|
|
| 267 |
<div class="p-8">
|
| 268 |
<h2 id="header-text" class="text-2xl font-bold text-slate-800 mb-8 text-center">Select a Category</h2>
|
| 269 |
|
| 270 |
-
<div id="inputs" class="opacity-50 pointer-events-none transition-all duration-
|
| 271 |
<div class="grid grid-cols-3 gap-4 mb-4">
|
| 272 |
<div class="col-span-2">
|
| 273 |
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1 block" data-translate="lbl_name">Patient Name</label>
|
| 274 |
-
<input type="text" id="p-name" class="w-full bg-white border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500
|
| 275 |
</div>
|
| 276 |
<div>
|
| 277 |
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1 block" data-translate="lbl_age">Age</label>
|
| 278 |
-
<input type="number" id="p-age" class="w-full bg-white border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500
|
| 279 |
</div>
|
| 280 |
</div>
|
| 281 |
|
| 282 |
-
<div onclick="document.getElementById('file-input').click()" class="border-2 border-dashed border-slate-300 rounded-2xl p-
|
| 283 |
<input type="file" id="file-input" class="hidden" onchange="showPreview(event)" onclick="this.value=null">
|
| 284 |
|
| 285 |
<div id="placeholder" class="group-hover:scale-105 transition-transform duration-300">
|
| 286 |
-
<div class="w-
|
| 287 |
-
<i id="upload-icon" class="fas fa-cloud-upload-alt text-
|
| 288 |
</div>
|
| 289 |
-
<p id="upload-text" class="text-slate-600 font-
|
|
|
|
| 290 |
</div>
|
| 291 |
|
| 292 |
<div class="relative z-10">
|
| 293 |
-
<img id="img-preview" class="hidden mx-auto max-h-64 rounded-
|
| 294 |
-
<audio id="audio-preview" controls class="hidden w-full mt-
|
| 295 |
</div>
|
| 296 |
</div>
|
| 297 |
</div>
|
| 298 |
|
| 299 |
-
<button id="run-btn" onclick="analyze()" class="hidden w-full max-w-md mx-auto bg-gradient-to-r from-blue-600 to-
|
| 300 |
<i class="fas fa-microscope text-xl"></i> <span class="text-lg" data-translate="btn_run">Run Diagnosis</span>
|
| 301 |
</button>
|
| 302 |
|
|
@@ -305,36 +310,38 @@ def home():
|
|
| 305 |
<div class="absolute inset-0 border-4 border-slate-100 rounded-full"></div>
|
| 306 |
<div class="absolute inset-0 border-4 border-blue-500 rounded-full border-t-transparent animate-spin"></div>
|
| 307 |
</div>
|
| 308 |
-
<p class="text-sm font-bold text-slate-600 animate-pulse" data-translate="txt_analyzing">Analyzing
|
| 309 |
</div>
|
| 310 |
|
| 311 |
-
<div id="result-box" class="hidden mt-
|
| 312 |
-
<div class="flex flex-col md:flex-row justify-between items-start gap-
|
| 313 |
<div>
|
| 314 |
<p class="text-xs font-bold text-slate-400 uppercase tracking-widest mb-1" data-translate="lbl_result">Analysis Result</p>
|
| 315 |
<h1 id="res-label" class="text-3xl md:text-4xl font-extrabold text-slate-800 tracking-tight">--</h1>
|
| 316 |
-
<p class="text-sm text-slate-500 mt-2 font-medium bg-slate-100 inline-block px-
|
| 317 |
<span data-translate="lbl_conf">AI Confidence</span>: <span id="res-conf" class="font-mono text-slate-800">--</span>
|
| 318 |
</p>
|
| 319 |
</div>
|
| 320 |
-
<span id="res-badge" class="px-
|
| 321 |
</div>
|
| 322 |
|
| 323 |
-
<div id="alert-box" class="hidden p-
|
| 324 |
-
<div class="p-
|
| 325 |
-
<i id="alert-icon" class="fas fa-info-circle text-2xl"></i>
|
| 326 |
</div>
|
| 327 |
<div class="flex-grow">
|
| 328 |
-
<strong class="block text-lg mb-1" data-translate="lbl_action">Action Required</strong>
|
| 329 |
-
<span id="alert-text" class="text-sm
|
| 330 |
</div>
|
| 331 |
-
|
| 332 |
-
|
|
|
|
|
|
|
| 333 |
</button>
|
| 334 |
</div>
|
| 335 |
|
| 336 |
-
<div class="mt-
|
| 337 |
-
<span class="flex items-center gap-
|
| 338 |
<span id="sync-msg" class="text-yellow-500 font-bold flex items-center gap-1"><i class="fas fa-sync fa-spin"></i> Pending...</span>
|
| 339 |
</div>
|
| 340 |
</div>
|
|
@@ -346,14 +353,14 @@ def home():
|
|
| 346 |
<h3 class="text-sm font-bold text-slate-500 uppercase tracking-widest flex items-center gap-2">
|
| 347 |
<i class="fas fa-history"></i> Recent Patients
|
| 348 |
</h3>
|
| 349 |
-
<button onclick="clearHistory()" class="text-[10px] font-bold text-red-500 hover:text-red-700 bg-red-50 hover:bg-red-100 px-
|
| 350 |
</div>
|
| 351 |
-
<div class="
|
| 352 |
<table class="w-full text-sm text-left">
|
| 353 |
-
<thead class="bg-slate-50 text-slate-500 font-bold uppercase text-[10px] tracking-wider">
|
| 354 |
<tr><th class="px-6 py-4">Time</th><th class="px-6 py-4">Patient</th><th class="px-6 py-4">Category</th><th class="px-6 py-4">Diagnosis</th><th class="px-6 py-4">Risk</th></tr>
|
| 355 |
</thead>
|
| 356 |
-
<tbody id="history-table" class="divide-y divide-slate-
|
| 357 |
</table>
|
| 358 |
</div>
|
| 359 |
</div>
|
|
@@ -384,13 +391,6 @@ def home():
|
|
| 384 |
txt_analyzing: "विश्लेषण कर रहा है...", lbl_result: "परिणाम", lbl_conf: "विश्वास",
|
| 385 |
lbl_action: "आवश्यक कार्रवाई", lbl_scope: "जांच का दायरा", lbl_sync: "सरकारी सिंक"
|
| 386 |
},
|
| 387 |
-
as: {
|
| 388 |
-
govt_title: "মেঘালয় চৰকাৰ", online_status: "অনলাইন ন'ড: শ্বিলং",
|
| 389 |
-
btn_lungs: "হাঁওফাঁও", btn_cough: "কাহ", btn_bone: "হাৰ ভঙা", btn_brain: "মগজু", btn_eye: "চকু", btn_skin: "ছাল",
|
| 390 |
-
lbl_name: "নাম", lbl_age: "বয়স", txt_upload: "আপলোড কৰক", btn_run: "পৰীক্ষা কৰক",
|
| 391 |
-
txt_analyzing: "বিশ্লেষণ...", lbl_result: "ফলাফল", lbl_conf: "নিশ্চয়তা",
|
| 392 |
-
lbl_action: "পদক্ষেপ", lbl_scope: "পৰিসৰ", lbl_sync: "ডাটাবেচ"
|
| 393 |
-
},
|
| 394 |
kha: {
|
| 395 |
govt_title: "SORKAR MEGHALAYA", online_status: "Online: Shillong",
|
| 396 |
btn_lungs: "Phopsa", btn_cough: "Jyrhoh", btn_bone: "Shyieng", btn_brain: "Jabieng", btn_eye: "Khmat", btn_skin: "Doh",
|
|
@@ -427,8 +427,13 @@ def home():
|
|
| 427 |
currTask = task; currType = type;
|
| 428 |
let t = TRANSLATIONS[currLang];
|
| 429 |
|
| 430 |
-
|
| 431 |
-
document.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 432 |
|
| 433 |
document.getElementById('header-text').innerHTML = `Upload <span class="uppercase text-blue-600">${t["btn_" + task]}</span>`;
|
| 434 |
|
|
@@ -436,7 +441,7 @@ def home():
|
|
| 436 |
scopeTags.innerHTML = "";
|
| 437 |
MODEL_SCOPES[task].forEach(d => {
|
| 438 |
let tag = document.createElement("span");
|
| 439 |
-
tag.className = "px-3 py-1 bg-
|
| 440 |
tag.innerText = d;
|
| 441 |
scopeTags.appendChild(tag);
|
| 442 |
});
|
|
@@ -449,7 +454,7 @@ def home():
|
|
| 449 |
if (type === 'audio') {
|
| 450 |
input.accept = ".wav, .mp3, audio/*";
|
| 451 |
icon.className = "fas fa-microphone-alt text-4xl text-teal-500 mb-2";
|
| 452 |
-
txt.innerHTML = "Tap to upload Audio<br><span class='text-xs text-slate-400'>.wav, .mp3
|
| 453 |
} else {
|
| 454 |
input.accept = "image/*";
|
| 455 |
icon.className = "fas fa-cloud-upload-alt text-4xl text-blue-400 mb-2";
|
|
@@ -534,7 +539,6 @@ def home():
|
|
| 534 |
btnDoc.classList.add('hidden');
|
| 535 |
}
|
| 536 |
|
| 537 |
-
// Sync Animation
|
| 538 |
setTimeout(() => {
|
| 539 |
document.getElementById('sync-msg').innerHTML = "<i class='fas fa-check-circle'></i> Synced to Govt Database";
|
| 540 |
document.getElementById('sync-msg').className = "text-green-600 font-bold flex items-center gap-1";
|
|
@@ -547,15 +551,20 @@ def home():
|
|
| 547 |
}
|
| 548 |
}
|
| 549 |
|
|
|
|
| 550 |
function findDoctor() {
|
| 551 |
if (navigator.geolocation) {
|
| 552 |
navigator.geolocation.getCurrentPosition((pos) => {
|
| 553 |
-
|
|
|
|
|
|
|
|
|
|
| 554 |
}, () => {
|
| 555 |
-
|
|
|
|
| 556 |
});
|
| 557 |
} else {
|
| 558 |
-
window.open('https://www.google.com/maps/search/
|
| 559 |
}
|
| 560 |
}
|
| 561 |
|
|
|
|
| 191 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
| 192 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 193 |
<style>
|
| 194 |
+
/* Custom Beautification */
|
| 195 |
+
body { background: #f0f4f8; background-image: radial-gradient(#e2e8f0 1px, transparent 1px); background-size: 20px 20px; }
|
| 196 |
+
.glass { background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.3); }
|
| 197 |
+
.soft-shadow { box-shadow: 0 10px 40px -10px rgba(0,0,0,0.08); }
|
| 198 |
+
.icon-btn { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); }
|
| 199 |
+
.icon-btn:hover { transform: translateY(-5px); box-shadow: 0 15px 30px -5px rgba(0,0,0,0.1); }
|
| 200 |
+
.icon-btn.active { ring: 2px solid #3b82f6; background-color: #eff6ff; transform: scale(0.98); }
|
| 201 |
+
@keyframes pulse-soft { 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); } 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); } }
|
| 202 |
+
.animate-pulse-soft { animation: pulse-soft 2s infinite; }
|
| 203 |
</style>
|
| 204 |
</head>
|
| 205 |
+
<body class="font-sans text-slate-800 min-h-screen flex flex-col">
|
| 206 |
|
| 207 |
+
<nav class="glass sticky top-0 z-50 border-b border-slate-200">
|
| 208 |
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
|
| 209 |
<div class="flex items-center gap-4">
|
| 210 |
+
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Seal_of_Meghalaya.svg/150px-Seal_of_Meghalaya.svg.png" class="h-14 drop-shadow-md">
|
| 211 |
<div>
|
| 212 |
<h2 class="text-[10px] md:text-xs font-bold text-slate-500 uppercase tracking-[0.2em]" data-translate="govt_title">GOVERNMENT OF MEGHALAYA</h2>
|
| 213 |
+
<h1 class="text-xl md:text-2xl font-extrabold text-slate-900 tracking-tight">MediScan <span class="text-blue-600">AI</span></h1>
|
| 214 |
+
<p class="text-[10px] font-bold text-green-600 flex items-center gap-1.5 mt-0.5">
|
| 215 |
+
<span class="relative flex h-2 w-2">
|
| 216 |
+
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
| 217 |
+
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
|
| 218 |
</span>
|
| 219 |
+
<span data-translate="online_status">Online Node: Shillong HQ</span>
|
| 220 |
</p>
|
| 221 |
</div>
|
| 222 |
</div>
|
| 223 |
|
| 224 |
<div class="flex flex-col items-end gap-2">
|
| 225 |
+
<select id="lang-select" onchange="changeLanguage()" class="bg-slate-100 border border-slate-200 text-slate-700 text-xs rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-1.5 shadow-sm outline-none">
|
| 226 |
<option value="en">🇬🇧 English</option>
|
| 227 |
<option value="hi">🇮🇳 हिंदी</option>
|
|
|
|
| 228 |
<option value="kha">🌲 Khasi</option>
|
| 229 |
<option value="gar">⛰️ Garo</option>
|
| 230 |
</select>
|
|
|
|
| 234 |
|
| 235 |
<div class="container mx-auto mt-8 p-4 max-w-5xl flex-grow">
|
| 236 |
|
| 237 |
+
<div class="grid grid-cols-3 md:grid-cols-6 gap-4 mb-8">
|
| 238 |
+
<button onclick="setTask('lungs', 'image')" id="btn-lungs" class="icon-btn bg-white rounded-2xl p-4 flex flex-col items-center justify-center gap-3 border border-slate-100">
|
| 239 |
+
<div class="w-12 h-12 rounded-full bg-blue-50 flex items-center justify-center text-blue-600 text-2xl"><i class="fas fa-lungs"></i></div>
|
| 240 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_lungs">Lungs</span>
|
| 241 |
</button>
|
| 242 |
+
<button onclick="setTask('cough', 'audio')" id="btn-cough" class="icon-btn bg-white rounded-2xl p-4 flex flex-col items-center justify-center gap-3 border border-slate-100">
|
| 243 |
+
<div class="w-12 h-12 rounded-full bg-teal-50 flex items-center justify-center text-teal-600 text-2xl"><i class="fas fa-head-side-cough"></i></div>
|
| 244 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_cough">Cough</span>
|
| 245 |
</button>
|
| 246 |
+
<button onclick="setTask('fracture', 'image')" id="btn-fracture" class="icon-btn bg-white rounded-2xl p-4 flex flex-col items-center justify-center gap-3 border border-slate-100">
|
| 247 |
+
<div class="w-12 h-12 rounded-full bg-slate-100 flex items-center justify-center text-slate-600 text-2xl"><i class="fas fa-bone"></i></div>
|
| 248 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_bone">Fracture</span>
|
| 249 |
</button>
|
| 250 |
+
<button onclick="setTask('brain', 'image')" id="btn-brain" class="icon-btn bg-white rounded-2xl p-4 flex flex-col items-center justify-center gap-3 border border-slate-100">
|
| 251 |
+
<div class="w-12 h-12 rounded-full bg-purple-50 flex items-center justify-center text-purple-600 text-2xl"><i class="fas fa-brain"></i></div>
|
| 252 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_brain">Brain</span>
|
| 253 |
</button>
|
| 254 |
+
<button onclick="setTask('eye', 'image')" id="btn-eye" class="icon-btn bg-white rounded-2xl p-4 flex flex-col items-center justify-center gap-3 border border-slate-100">
|
| 255 |
+
<div class="w-12 h-12 rounded-full bg-indigo-50 flex items-center justify-center text-indigo-600 text-2xl"><i class="fas fa-eye"></i></div>
|
| 256 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_eye">Eye</span>
|
| 257 |
</button>
|
| 258 |
+
<button onclick="setTask('skin', 'image')" id="btn-skin" class="icon-btn bg-white rounded-2xl p-4 flex flex-col items-center justify-center gap-3 border border-slate-100">
|
| 259 |
+
<div class="w-12 h-12 rounded-full bg-orange-50 flex items-center justify-center text-orange-600 text-2xl"><i class="fas fa-hand-dots"></i></div>
|
| 260 |
<span class="text-xs font-bold text-slate-600" data-translate="btn_skin">Skin</span>
|
| 261 |
</button>
|
| 262 |
</div>
|
| 263 |
|
| 264 |
+
<div class="glass rounded-3xl soft-shadow overflow-hidden relative">
|
| 265 |
|
| 266 |
+
<div id="scope-box" class="hidden bg-slate-50/50 border-b border-slate-100 p-3 text-center backdrop-blur-sm">
|
| 267 |
<p class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-2" data-translate="lbl_scope">Scope of Detection</p>
|
| 268 |
<div id="scope-tags" class="flex flex-wrap justify-center gap-2"></div>
|
| 269 |
</div>
|
|
|
|
| 271 |
<div class="p-8">
|
| 272 |
<h2 id="header-text" class="text-2xl font-bold text-slate-800 mb-8 text-center">Select a Category</h2>
|
| 273 |
|
| 274 |
+
<div id="inputs" class="opacity-50 pointer-events-none transition-all duration-500 mb-8 max-w-2xl mx-auto">
|
| 275 |
<div class="grid grid-cols-3 gap-4 mb-4">
|
| 276 |
<div class="col-span-2">
|
| 277 |
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1 block" data-translate="lbl_name">Patient Name</label>
|
| 278 |
+
<input type="text" id="p-name" class="w-full bg-white/80 border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none transition-all">
|
| 279 |
</div>
|
| 280 |
<div>
|
| 281 |
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1 block" data-translate="lbl_age">Age</label>
|
| 282 |
+
<input type="number" id="p-age" class="w-full bg-white/80 border border-slate-200 p-3 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none transition-all">
|
| 283 |
</div>
|
| 284 |
</div>
|
| 285 |
|
| 286 |
+
<div onclick="document.getElementById('file-input').click()" class="border-2 border-dashed border-slate-300 rounded-2xl p-10 text-center cursor-pointer hover:bg-blue-50/50 hover:border-blue-400 transition-all duration-300 group relative overflow-hidden bg-white/60">
|
| 287 |
<input type="file" id="file-input" class="hidden" onchange="showPreview(event)" onclick="this.value=null">
|
| 288 |
|
| 289 |
<div id="placeholder" class="group-hover:scale-105 transition-transform duration-300">
|
| 290 |
+
<div class="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4 text-blue-600 shadow-sm">
|
| 291 |
+
<i id="upload-icon" class="fas fa-cloud-upload-alt text-3xl"></i>
|
| 292 |
</div>
|
| 293 |
+
<p id="upload-text" class="text-slate-600 font-bold" data-translate="txt_upload">Tap to upload</p>
|
| 294 |
+
<p class="text-xs text-slate-400 mt-1">Supported: JPG, PNG, WAV, MP3</p>
|
| 295 |
</div>
|
| 296 |
|
| 297 |
<div class="relative z-10">
|
| 298 |
+
<img id="img-preview" class="hidden mx-auto max-h-64 rounded-xl shadow-lg object-contain bg-black/5">
|
| 299 |
+
<audio id="audio-preview" controls class="hidden w-full mt-4"></audio>
|
| 300 |
</div>
|
| 301 |
</div>
|
| 302 |
</div>
|
| 303 |
|
| 304 |
+
<button id="run-btn" onclick="analyze()" class="hidden w-full max-w-md mx-auto bg-gradient-to-r from-blue-600 to-indigo-700 hover:from-blue-700 hover:to-indigo-800 text-white font-bold py-4 rounded-xl shadow-lg shadow-blue-200 transition-all transform hover:scale-[1.02] flex items-center justify-center gap-3 animate-pulse-soft">
|
| 305 |
<i class="fas fa-microscope text-xl"></i> <span class="text-lg" data-translate="btn_run">Run Diagnosis</span>
|
| 306 |
</button>
|
| 307 |
|
|
|
|
| 310 |
<div class="absolute inset-0 border-4 border-slate-100 rounded-full"></div>
|
| 311 |
<div class="absolute inset-0 border-4 border-blue-500 rounded-full border-t-transparent animate-spin"></div>
|
| 312 |
</div>
|
| 313 |
+
<p class="text-sm font-bold text-slate-600 animate-pulse" data-translate="txt_analyzing">Analyzing data...</p>
|
| 314 |
</div>
|
| 315 |
|
| 316 |
+
<div id="result-box" class="hidden mt-10 border-t border-slate-100 pt-8">
|
| 317 |
+
<div class="flex flex-col md:flex-row justify-between items-start gap-6 mb-6">
|
| 318 |
<div>
|
| 319 |
<p class="text-xs font-bold text-slate-400 uppercase tracking-widest mb-1" data-translate="lbl_result">Analysis Result</p>
|
| 320 |
<h1 id="res-label" class="text-3xl md:text-4xl font-extrabold text-slate-800 tracking-tight">--</h1>
|
| 321 |
+
<p class="text-sm text-slate-500 mt-2 font-medium bg-slate-100/80 inline-block px-3 py-1 rounded-lg border border-slate-200">
|
| 322 |
<span data-translate="lbl_conf">AI Confidence</span>: <span id="res-conf" class="font-mono text-slate-800">--</span>
|
| 323 |
</p>
|
| 324 |
</div>
|
| 325 |
+
<span id="res-badge" class="px-5 py-2.5 rounded-xl text-sm font-bold uppercase shadow-sm tracking-wide">--</span>
|
| 326 |
</div>
|
| 327 |
|
| 328 |
+
<div id="alert-box" class="hidden p-6 rounded-2xl border border-l-4 shadow-sm flex flex-col md:flex-row items-start md:items-center gap-5 transition-all bg-white/80 backdrop-blur">
|
| 329 |
+
<div class="p-4 bg-slate-50 rounded-full shrink-0">
|
| 330 |
+
<i id="alert-icon" class="fas fa-info-circle text-2xl text-slate-600"></i>
|
| 331 |
</div>
|
| 332 |
<div class="flex-grow">
|
| 333 |
+
<strong class="block text-lg mb-1 text-slate-800" data-translate="lbl_action">Action Required</strong>
|
| 334 |
+
<span id="alert-text" class="text-sm text-slate-600 leading-relaxed">--</span>
|
| 335 |
</div>
|
| 336 |
+
|
| 337 |
+
<button id="doctor-btn" onclick="findDoctor()" class="hidden px-6 py-3 bg-white text-slate-800 font-bold text-sm rounded-xl shadow-md border border-slate-100 hover:bg-slate-50 hover:shadow-lg transition flex items-center gap-2 whitespace-nowrap">
|
| 338 |
+
<i class="fas fa-map-marker-alt text-red-500 text-lg"></i>
|
| 339 |
+
<span>Find Nearest Doctor</span>
|
| 340 |
</button>
|
| 341 |
</div>
|
| 342 |
|
| 343 |
+
<div class="mt-8 flex items-center justify-between text-[10px] text-slate-400 border-t border-slate-50 pt-4">
|
| 344 |
+
<span class="flex items-center gap-2"><i class="fas fa-database text-blue-400"></i> <span data-translate="lbl_sync">Ayushman Bharat Sync</span></span>
|
| 345 |
<span id="sync-msg" class="text-yellow-500 font-bold flex items-center gap-1"><i class="fas fa-sync fa-spin"></i> Pending...</span>
|
| 346 |
</div>
|
| 347 |
</div>
|
|
|
|
| 353 |
<h3 class="text-sm font-bold text-slate-500 uppercase tracking-widest flex items-center gap-2">
|
| 354 |
<i class="fas fa-history"></i> Recent Patients
|
| 355 |
</h3>
|
| 356 |
+
<button onclick="clearHistory()" class="text-[10px] font-bold text-red-500 hover:text-red-700 bg-red-50 hover:bg-red-100 px-4 py-2 rounded-lg transition-colors uppercase tracking-wide">Clear History</button>
|
| 357 |
</div>
|
| 358 |
+
<div class="glass rounded-xl shadow-sm overflow-hidden border border-slate-200/50">
|
| 359 |
<table class="w-full text-sm text-left">
|
| 360 |
+
<thead class="bg-slate-50/80 text-slate-500 font-bold uppercase text-[10px] tracking-wider">
|
| 361 |
<tr><th class="px-6 py-4">Time</th><th class="px-6 py-4">Patient</th><th class="px-6 py-4">Category</th><th class="px-6 py-4">Diagnosis</th><th class="px-6 py-4">Risk</th></tr>
|
| 362 |
</thead>
|
| 363 |
+
<tbody id="history-table" class="divide-y divide-slate-100"></tbody>
|
| 364 |
</table>
|
| 365 |
</div>
|
| 366 |
</div>
|
|
|
|
| 391 |
txt_analyzing: "विश्लेषण कर रहा है...", lbl_result: "परिणाम", lbl_conf: "विश्वास",
|
| 392 |
lbl_action: "आवश्यक कार्रवाई", lbl_scope: "जांच का दायरा", lbl_sync: "सरकारी सिंक"
|
| 393 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 394 |
kha: {
|
| 395 |
govt_title: "SORKAR MEGHALAYA", online_status: "Online: Shillong",
|
| 396 |
btn_lungs: "Phopsa", btn_cough: "Jyrhoh", btn_bone: "Shyieng", btn_brain: "Jabieng", btn_eye: "Khmat", btn_skin: "Doh",
|
|
|
|
| 427 |
currTask = task; currType = type;
|
| 428 |
let t = TRANSLATIONS[currLang];
|
| 429 |
|
| 430 |
+
// Icon animation
|
| 431 |
+
document.querySelectorAll('.icon-btn').forEach(b => {
|
| 432 |
+
b.classList.remove('active', 'border-blue-500', 'ring-2', 'ring-blue-200');
|
| 433 |
+
b.classList.add('border-slate-100');
|
| 434 |
+
});
|
| 435 |
+
let btn = document.getElementById('btn-'+task);
|
| 436 |
+
btn.classList.add('active', 'border-blue-500', 'ring-2', 'ring-blue-200');
|
| 437 |
|
| 438 |
document.getElementById('header-text').innerHTML = `Upload <span class="uppercase text-blue-600">${t["btn_" + task]}</span>`;
|
| 439 |
|
|
|
|
| 441 |
scopeTags.innerHTML = "";
|
| 442 |
MODEL_SCOPES[task].forEach(d => {
|
| 443 |
let tag = document.createElement("span");
|
| 444 |
+
tag.className = "px-3 py-1 bg-white text-slate-600 text-[10px] font-bold uppercase rounded-full border border-slate-200 tracking-wide shadow-sm";
|
| 445 |
tag.innerText = d;
|
| 446 |
scopeTags.appendChild(tag);
|
| 447 |
});
|
|
|
|
| 454 |
if (type === 'audio') {
|
| 455 |
input.accept = ".wav, .mp3, audio/*";
|
| 456 |
icon.className = "fas fa-microphone-alt text-4xl text-teal-500 mb-2";
|
| 457 |
+
txt.innerHTML = "Tap to upload Audio<br><span class='text-xs text-slate-400'>.wav, .mp3</span>";
|
| 458 |
} else {
|
| 459 |
input.accept = "image/*";
|
| 460 |
icon.className = "fas fa-cloud-upload-alt text-4xl text-blue-400 mb-2";
|
|
|
|
| 539 |
btnDoc.classList.add('hidden');
|
| 540 |
}
|
| 541 |
|
|
|
|
| 542 |
setTimeout(() => {
|
| 543 |
document.getElementById('sync-msg').innerHTML = "<i class='fas fa-check-circle'></i> Synced to Govt Database";
|
| 544 |
document.getElementById('sync-msg').className = "text-green-600 font-bold flex items-center gap-1";
|
|
|
|
| 551 |
}
|
| 552 |
}
|
| 553 |
|
| 554 |
+
// FIND NEAREST DOCTOR (Uses Geolocation)
|
| 555 |
function findDoctor() {
|
| 556 |
if (navigator.geolocation) {
|
| 557 |
navigator.geolocation.getCurrentPosition((pos) => {
|
| 558 |
+
let lat = pos.coords.latitude;
|
| 559 |
+
let lon = pos.coords.longitude;
|
| 560 |
+
// Search for "Hospital" or "Clinic" near user coordinates
|
| 561 |
+
window.open(`https://www.google.com/maps/search/hospital+clinic/@${lat},${lon},13z`, '_blank');
|
| 562 |
}, () => {
|
| 563 |
+
// Fallback if permission denied
|
| 564 |
+
window.open('https://www.google.com/maps/search/hospital+near+me', '_blank');
|
| 565 |
});
|
| 566 |
} else {
|
| 567 |
+
window.open('https://www.google.com/maps/search/hospital+near+me', '_blank');
|
| 568 |
}
|
| 569 |
}
|
| 570 |
|