Spaces:
Sleeping
Sleeping
Update webui/run_app.py
Browse files- webui/run_app.py +111 -12
webui/run_app.py
CHANGED
|
@@ -113,7 +113,42 @@ async def get_system_status(key: str = "", request: Request = None):
|
|
| 113 |
}
|
| 114 |
except Exception:
|
| 115 |
return { "thread_string": "0/6", "key_info": { "status": "failed", "type": "free", "show_test_panel": False } }
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
# --- API TRÍCH XUẤT LOG DIAGNOSTICS ĐỂ ĐẨY LÊN TERMINAL UI TỪNG GIÂY ---
|
| 118 |
@app.get("/api/logs/{task_id}")
|
| 119 |
async def get_task_logs(task_id: str):
|
|
@@ -483,6 +518,39 @@ async def index_page():
|
|
| 483 |
const keyDetails = document.getElementById("keyDetails");
|
| 484 |
const adminPanel = document.getElementById("adminTestPanel");
|
| 485 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 486 |
if(data.key_info.status === "success") {{
|
| 487 |
if(data.key_info.type === "admin") {{
|
| 488 |
keyDetails.innerHTML = '<div class="text-emerald-600"><i class="fa-solid fa-crown text-base mr-1"></i> Core System Status: ACCESS GRANTED (ADMIN MASTER CONTROL)</div>';
|
|
@@ -495,10 +563,10 @@ async def index_page():
|
|
| 495 |
keyDetails.innerHTML = `
|
| 496 |
<div class="text-emerald-600 font-extrabold grid grid-cols-1 sm:grid-cols-2 gap-1 text-xs">
|
| 497 |
<div><i class="fa-solid fa-check-circle"></i> SECURE TOKEN AUTHENTICATED</div>
|
| 498 |
-
<div>🆔 TxID:
|
| 499 |
-
<div>💰 Paid Metric:
|
| 500 |
-
<div>📅 Registration:
|
| 501 |
-
<div>⏳ Termination:
|
| 502 |
</div>
|
| 503 |
`;
|
| 504 |
}}
|
|
@@ -510,6 +578,42 @@ async def index_page():
|
|
| 510 |
}}
|
| 511 |
setInterval(runSystemStatusSync, 1000);
|
| 512 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 513 |
function fetchLiveTerminalOutput() {{
|
| 514 |
if (!currentTaskId) return;
|
| 515 |
fetch("/api/logs/" + currentTaskId)
|
|
@@ -539,7 +643,7 @@ async def index_page():
|
|
| 539 |
const targetBtn = document.getElementById("mainSubmitBtn");
|
| 540 |
const iconObj = document.getElementById("btnIcon");
|
| 541 |
const textObj = document.getElementById("btnText");
|
| 542 |
-
const currentToken = document.getElementById("licenseKey").value;
|
| 543 |
|
| 544 |
if(runningStateActive) {{
|
| 545 |
if(confirm("Do you want to terminate the active rendering cycle immediately?")) {{
|
|
@@ -604,15 +708,10 @@ async def index_page():
|
|
| 604 |
textObj.innerText = "GENERATE PRODUCTION VIDEO";
|
| 605 |
iconObj.className = "fa-solid fa-play";
|
| 606 |
}}
|
| 607 |
-
|
| 608 |
-
function triggerVerificationHandshake() {{
|
| 609 |
-
runSystemStatusSync();
|
| 610 |
-
alert("Credentials verification payload synchronized.");
|
| 611 |
-
}}
|
| 612 |
</script>
|
| 613 |
</body>
|
| 614 |
</html>
|
| 615 |
-
|
| 616 |
return HTMLResponse(content=html_content)
|
| 617 |
|
| 618 |
if __name__ == "__main__":
|
|
|
|
| 113 |
}
|
| 114 |
except Exception:
|
| 115 |
return { "thread_string": "0/6", "key_info": { "status": "failed", "type": "free", "show_test_panel": False } }
|
| 116 |
+
# --- API CHUYÊN TRÁCH XỬ LÝ NÚT BẤM VALIDATE TOKEN (THÊM MỚI ĐỂ VÁ LỖI) ---
|
| 117 |
+
@app.post("/api/validate-key")
|
| 118 |
+
async def validate_user_key(request: Request):
|
| 119 |
+
try:
|
| 120 |
+
data = await request.json()
|
| 121 |
+
token = data.get("key", "").strip()
|
| 122 |
+
except Exception:
|
| 123 |
+
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid raw payload structure."})
|
| 124 |
+
|
| 125 |
+
device_id = request.client.host if request else "MOBILE_DEFAULT_NODE"
|
| 126 |
+
|
| 127 |
+
# Nếu để trống key, chặn ngay từ vòng gửi xe
|
| 128 |
+
if not token:
|
| 129 |
+
return JSONResponse(status_code=400, content={"status": "error", "message": "Access token cannot be empty!"})
|
| 130 |
+
|
| 131 |
+
# Gọi licensing_client để kiểm tra tính hợp lệ thực tế
|
| 132 |
+
is_valid, key_info = licensing_client.verify_and_get_license_info(token, device_id)
|
| 133 |
+
|
| 134 |
+
# NẾU KEY SAI/LỤI: Trả về trạng thái lỗi 401 Unauthorized để chặn đứng Frontend
|
| 135 |
+
if not is_valid:
|
| 136 |
+
return JSONResponse(
|
| 137 |
+
status_code=401,
|
| 138 |
+
content={
|
| 139 |
+
"status": "error",
|
| 140 |
+
"message": "Authentication Failed: Invalid or expired security token."
|
| 141 |
+
}
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
# NẾU KEY ĐÚNG: Trả về thành công và đồng bộ dữ liệu VIP
|
| 145 |
+
return {
|
| 146 |
+
"status": "success",
|
| 147 |
+
"message": "Credentials verification payload synchronized.",
|
| 148 |
+
"tier": key_info.get("tier", "FREE").lower(),
|
| 149 |
+
"days_left": key_info.get("days_left", 0)
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
# --- API TRÍCH XUẤT LOG DIAGNOSTICS ĐỂ ĐẨY LÊN TERMINAL UI TỪNG GIÂY ---
|
| 153 |
@app.get("/api/logs/{task_id}")
|
| 154 |
async def get_task_logs(task_id: str):
|
|
|
|
| 518 |
const keyDetails = document.getElementById("keyDetails");
|
| 519 |
const adminPanel = document.getElementById("adminTestPanel");
|
| 520 |
|
| 521 |
+
if(data.key_info.status === "success") {{
|
| 522 |
+
if(data.key_info.type === "admin") {{
|
| 523 |
+
keyDetails.innerHTML = '<div class="text-emerald-600"><i class="fa-solid fa-crown text-base mr-1"></i> Core System Status: ACCESS GRANTED (ADMIN MASTER CONTROL)</div>';
|
| 524 |
+
adminPanel.classList.remove("hidden");
|
| 525 |
+
|
| 526 |
+
<script>
|
| 527 |
+
let currentTaskId = null;
|
| 528 |
+
let logPollingTimer = null;
|
| 529 |
+
let runningStateActive = false;
|
| 530 |
+
|
| 531 |
+
const txtInput = document.getElementById("video_script");
|
| 532 |
+
const lblCounter = document.getElementById("charCounter");
|
| 533 |
+
|
| 534 |
+
function enforceInputConstraints() {{
|
| 535 |
+
if(txtInput.value.length > 1500) {{
|
| 536 |
+
txtInput.value = txtInput.value.substring(0, 1500);
|
| 537 |
+
}}
|
| 538 |
+
lblCounter.innerText = txtInput.value.length + " / 1500 Chars";
|
| 539 |
+
}}
|
| 540 |
+
txtInput.addEventListener("input", enforceInputConstraints);
|
| 541 |
+
txtInput.addEventListener("paste", () => {{ setTimeout(enforceInputConstraints, 10); }});
|
| 542 |
+
|
| 543 |
+
async function runSystemStatusSync() {{
|
| 544 |
+
const currentToken = document.getElementById("licenseKey").value.trim();
|
| 545 |
+
try {{
|
| 546 |
+
const response = await fetch("/api/system-status?key=" + encodeURIComponent(currentToken));
|
| 547 |
+
const data = await response.json();
|
| 548 |
+
|
| 549 |
+
document.getElementById("liveThreadMonitor").innerText = data.thread_string + " Running Threads";
|
| 550 |
+
|
| 551 |
+
const keyDetails = document.getElementById("keyDetails");
|
| 552 |
+
const adminPanel = document.getElementById("adminTestPanel");
|
| 553 |
+
|
| 554 |
if(data.key_info.status === "success") {{
|
| 555 |
if(data.key_info.type === "admin") {{
|
| 556 |
keyDetails.innerHTML = '<div class="text-emerald-600"><i class="fa-solid fa-crown text-base mr-1"></i> Core System Status: ACCESS GRANTED (ADMIN MASTER CONTROL)</div>';
|
|
|
|
| 563 |
keyDetails.innerHTML = `
|
| 564 |
<div class="text-emerald-600 font-extrabold grid grid-cols-1 sm:grid-cols-2 gap-1 text-xs">
|
| 565 |
<div><i class="fa-solid fa-check-circle"></i> SECURE TOKEN AUTHENTICATED</div>
|
| 566 |
+
<div>🆔 TxID: $${{data.key_info.tx_id}}</div>
|
| 567 |
+
<div>💰 Paid Metric: $${{data.key_info.amount}}</div>
|
| 568 |
+
<div>📅 Registration: $${{data.key_info.issued_date}}</div>
|
| 569 |
+
<div>⏳ Termination: $${{data.key_info.expiry_date}} ($${{data.key_info.days_left}} days remaining)</div>
|
| 570 |
</div>
|
| 571 |
`;
|
| 572 |
}}
|
|
|
|
| 578 |
}}
|
| 579 |
setInterval(runSystemStatusSync, 1000);
|
| 580 |
|
| 581 |
+
// --- HÀM XỬ LÝ CHECK SỰ KIỆN VALIDATE TOKEN KHI BẤM NÚT (SỬA LỖI NHẬP LỤI) ---
|
| 582 |
+
async function triggerVerificationHandshake() {{
|
| 583 |
+
const currentToken = document.getElementById("licenseKey").value.trim();
|
| 584 |
+
const keyDetails = document.getElementById("keyDetails");
|
| 585 |
+
|
| 586 |
+
if (!currentToken) {{
|
| 587 |
+
alert("❌ Please enter a token before validation!");
|
| 588 |
+
return;
|
| 589 |
+
}}
|
| 590 |
+
|
| 591 |
+
try {{
|
| 592 |
+
// Gọi trực tiếp đến API POST kiểm tra key chuyên dụng ở Backend
|
| 593 |
+
const response = await fetch("/api/validate-key", {{
|
| 594 |
+
method: "POST",
|
| 595 |
+
headers: {{ "Content-Type": "application/json" }},
|
| 596 |
+
body: JSON.stringify({{ key: currentToken }})
|
| 597 |
+
}});
|
| 598 |
+
|
| 599 |
+
const data = await response.json();
|
| 600 |
+
|
| 601 |
+
if (!response.ok) {{
|
| 602 |
+
// Nếu backend trả về 401 hoặc lỗi chặn, quăng lỗi xuống block catch bên dưới
|
| 603 |
+
throw new Error(data.message || "Invalid or expired security token.");
|
| 604 |
+
}}
|
| 605 |
+
|
| 606 |
+
// CHỈ BẮN THÔNG BÁO KHI KEY THỰC SỰ CHUẨN
|
| 607 |
+
alert("💚 " + data.message);
|
| 608 |
+
await runSystemStatusSync(); // Đồng bộ lại giao diện VIP/ADMIN ngay lập tức
|
| 609 |
+
|
| 610 |
+
}} catch (error) {{
|
| 611 |
+
// NẾU KEY SAI HOẶC BẤM LỤI: Báo lỗi đỏ và khóa quyền
|
| 612 |
+
alert("❌ " + error.message);
|
| 613 |
+
keyDetails.innerHTML = '<div><i class="fa-solid fa-circle-exclamation mr-1"></i> License Status: Authentication Failed (Token Rejected)</div>';
|
| 614 |
+
}}
|
| 615 |
+
}}
|
| 616 |
+
|
| 617 |
function fetchLiveTerminalOutput() {{
|
| 618 |
if (!currentTaskId) return;
|
| 619 |
fetch("/api/logs/" + currentTaskId)
|
|
|
|
| 643 |
const targetBtn = document.getElementById("mainSubmitBtn");
|
| 644 |
const iconObj = document.getElementById("btnIcon");
|
| 645 |
const textObj = document.getElementById("btnText");
|
| 646 |
+
const currentToken = document.getElementById("licenseKey").value.trim();
|
| 647 |
|
| 648 |
if(runningStateActive) {{
|
| 649 |
if(confirm("Do you want to terminate the active rendering cycle immediately?")) {{
|
|
|
|
| 708 |
textObj.innerText = "GENERATE PRODUCTION VIDEO";
|
| 709 |
iconObj.className = "fa-solid fa-play";
|
| 710 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 711 |
</script>
|
| 712 |
</body>
|
| 713 |
</html>
|
| 714 |
+
|
| 715 |
return HTMLResponse(content=html_content)
|
| 716 |
|
| 717 |
if __name__ == "__main__":
|