Spaces:
Running
Running
Commit
·
04c1763
1
Parent(s):
304c700
update
Browse files
app.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import os
|
|
|
|
| 3 |
|
| 4 |
-
#
|
| 5 |
BASE_DIR = os.path.abspath(os.getcwd())
|
| 6 |
|
| 7 |
SCENES = [
|
|
@@ -28,57 +29,80 @@ SCENES = [
|
|
| 28 |
gallery_items = [(item["thumb"], item["name"]) for item in SCENES]
|
| 29 |
|
| 30 |
def load_scene(evt: gr.SelectData, request: gr.Request):
|
| 31 |
-
"""
|
| 32 |
-
載入選定的場景並生成自動播放的 iframe 連結
|
| 33 |
-
request: 用來獲取當前 Gradio 的網址 (localhost 或 share link)
|
| 34 |
-
"""
|
| 35 |
index = evt.index
|
| 36 |
scene = SCENES[index]
|
| 37 |
|
|
|
|
| 38 |
full_model_path = os.path.join(BASE_DIR, scene["model"])
|
| 39 |
|
| 40 |
if not os.path.exists(full_model_path):
|
| 41 |
return (
|
| 42 |
-
"<div style='text-align:center; padding:50px'>⚠️ File not found</div>",
|
| 43 |
None,
|
| 44 |
-
f"**⚠️ Error:** File not found: {
|
| 45 |
)
|
| 46 |
|
| 47 |
-
#
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
if request:
|
| 50 |
-
host = request.headers.get("host")
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
|
| 57 |
-
#
|
| 58 |
-
#
|
| 59 |
-
|
|
|
|
| 60 |
|
| 61 |
-
#
|
| 62 |
-
|
|
|
|
| 63 |
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
# 4. 生成 HTML
|
| 67 |
-
html = f"""
|
| 68 |
-
<iframe
|
| 69 |
-
src="{viewer_url}"
|
| 70 |
-
width="100%"
|
| 71 |
-
height="600px"
|
| 72 |
-
frameborder="0"
|
| 73 |
-
allow="camera; gpu"
|
| 74 |
-
style="border-radius: 8px; background: #000;"
|
| 75 |
-
></iframe>
|
| 76 |
-
"""
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
# 提示訊息
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
|
| 83 |
return (
|
| 84 |
html,
|
|
@@ -86,11 +110,9 @@ def load_scene(evt: gr.SelectData, request: gr.Request):
|
|
| 86 |
status_msg
|
| 87 |
)
|
| 88 |
|
| 89 |
-
# --- UI ---
|
| 90 |
with gr.Blocks(title="RGS-SLAM Demo") as demo:
|
| 91 |
-
|
| 92 |
gr.Markdown("# 🚀 RGS-SLAM Gaussian Splatting Viewer")
|
| 93 |
-
|
| 94 |
with gr.Row():
|
| 95 |
with gr.Column(scale=1):
|
| 96 |
gr.Markdown("### 📂 Select Scene")
|
|
@@ -102,26 +124,21 @@ with gr.Blocks(title="RGS-SLAM Demo") as demo:
|
|
| 102 |
object_fit="contain",
|
| 103 |
allow_preview=False
|
| 104 |
)
|
| 105 |
-
|
| 106 |
with gr.Column(scale=3):
|
| 107 |
status = gr.Markdown("**👈 Select a scene to auto-load**")
|
| 108 |
-
|
| 109 |
with gr.Tab("🎯 3D Viewer"):
|
| 110 |
-
# 初始狀態為空
|
| 111 |
viewer_frame = gr.HTML(
|
| 112 |
value="<div style='text-align: center; padding: 100px; color: #666;'>Select a scene</div>"
|
| 113 |
)
|
| 114 |
-
|
| 115 |
with gr.Tab("📍 Camera Trajectory"):
|
| 116 |
trajectory_img = gr.Image(label="Camera Path", height=600)
|
| 117 |
|
| 118 |
scene_gallery.select(
|
| 119 |
fn=load_scene,
|
| 120 |
-
inputs=None,
|
| 121 |
outputs=[viewer_frame, trajectory_img, status]
|
| 122 |
)
|
| 123 |
|
| 124 |
if __name__ == "__main__":
|
| 125 |
-
#
|
| 126 |
-
|
| 127 |
-
demo.launch(share=True, allowed_paths=[BASE_DIR])
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import os
|
| 3 |
+
import urllib.parse # 新增:用於處理網址編碼
|
| 4 |
|
| 5 |
+
# 獲取當前絕對路徑
|
| 6 |
BASE_DIR = os.path.abspath(os.getcwd())
|
| 7 |
|
| 8 |
SCENES = [
|
|
|
|
| 29 |
gallery_items = [(item["thumb"], item["name"]) for item in SCENES]
|
| 30 |
|
| 31 |
def load_scene(evt: gr.SelectData, request: gr.Request):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
index = evt.index
|
| 33 |
scene = SCENES[index]
|
| 34 |
|
| 35 |
+
# 組合絕對路徑
|
| 36 |
full_model_path = os.path.join(BASE_DIR, scene["model"])
|
| 37 |
|
| 38 |
if not os.path.exists(full_model_path):
|
| 39 |
return (
|
| 40 |
+
"<div style='text-align:center; padding:50px; color:red'>⚠️ File not found</div>",
|
| 41 |
None,
|
| 42 |
+
f"**⚠️ Error:** File not found: {full_model_path}"
|
| 43 |
)
|
| 44 |
|
| 45 |
+
# --- 關鍵修正開始 ---
|
| 46 |
+
|
| 47 |
+
# 1. 處理 Windows 路徑 (將 \ 轉為 /)
|
| 48 |
+
# Gradio 的 file路由需要正斜線,且不能有磁碟機代號之後的雙反斜線混亂
|
| 49 |
+
clean_path = full_model_path.replace("\\", "/")
|
| 50 |
+
|
| 51 |
+
# 2. 判斷網址 (這是最容易報錯的地方)
|
| 52 |
+
base_url = "http://127.0.0.1:7860" # 預設值
|
| 53 |
+
is_https = False
|
| 54 |
+
|
| 55 |
if request:
|
| 56 |
+
host = request.headers.get("host")
|
| 57 |
+
if "gradio.live" in host:
|
| 58 |
+
base_url = f"https://{host}"
|
| 59 |
+
is_https = True
|
| 60 |
+
else:
|
| 61 |
+
base_url = f"http://{host}"
|
| 62 |
|
| 63 |
+
# 3. 組合檔案連結並進行 URL 編碼
|
| 64 |
+
# 我們只對路徑部分進行編碼,避免空白變成無效字元
|
| 65 |
+
# 瀏覽器看到的連結會類似: https://xxx.gradio.live/file=D:/Path/To/File.ply
|
| 66 |
+
file_url = f"{base_url}/file={clean_path}"
|
| 67 |
|
| 68 |
+
# 對 file_url 再進行一次完整編碼,因為它將作為 ?url= 的參數傳遞給外部網站
|
| 69 |
+
# 外部網站讀取時會解碼一次
|
| 70 |
+
encoded_file_url = urllib.parse.quote(file_url, safe=':/')
|
| 71 |
|
| 72 |
+
# 4. 組合外部 Viewer 連結
|
| 73 |
+
viewer_url = f"https://antimatter15.com/splat/?url={encoded_file_url}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
+
print(f"🔗 Base URL: {base_url}")
|
| 76 |
+
print(f"📂 File URL: {file_url}")
|
| 77 |
+
print(f"🚀 Final Viewer URL: {viewer_url}")
|
| 78 |
+
|
| 79 |
+
# --- 關鍵修正結束 ---
|
| 80 |
+
|
| 81 |
# 提示訊息
|
| 82 |
+
if not is_https:
|
| 83 |
+
status_msg = f"""
|
| 84 |
+
### ⚠️ 警告:無法載入 (CORS Error)
|
| 85 |
+
偵測到您正在使用 **Localhost (http)**。
|
| 86 |
+
由於安全性限制,外部 Viewer (https) 無法讀取您的本機檔案。
|
| 87 |
+
|
| 88 |
+
**請解決:**
|
| 89 |
+
1. 查看終端機 (Terminal)。
|
| 90 |
+
2. 複製 **Running on public URL: https://xxxx.gradio.live** 的連結。
|
| 91 |
+
3. 用該連結開啟網頁,即可正常顯示。
|
| 92 |
+
"""
|
| 93 |
+
html = f"<div style='background:#333; color:white; padding:20px; border-radius:10px;'>{status_msg}</div>"
|
| 94 |
+
else:
|
| 95 |
+
status_msg = f"**{scene['name']}** Loaded successfully from {base_url}"
|
| 96 |
+
html = f"""
|
| 97 |
+
<iframe
|
| 98 |
+
src="{viewer_url}"
|
| 99 |
+
width="100%"
|
| 100 |
+
height="600px"
|
| 101 |
+
frameborder="0"
|
| 102 |
+
allow="camera; display-capture"
|
| 103 |
+
style="border-radius: 8px; background: #000;"
|
| 104 |
+
></iframe>
|
| 105 |
+
"""
|
| 106 |
|
| 107 |
return (
|
| 108 |
html,
|
|
|
|
| 110 |
status_msg
|
| 111 |
)
|
| 112 |
|
| 113 |
+
# --- UI (保持不變) ---
|
| 114 |
with gr.Blocks(title="RGS-SLAM Demo") as demo:
|
|
|
|
| 115 |
gr.Markdown("# 🚀 RGS-SLAM Gaussian Splatting Viewer")
|
|
|
|
| 116 |
with gr.Row():
|
| 117 |
with gr.Column(scale=1):
|
| 118 |
gr.Markdown("### 📂 Select Scene")
|
|
|
|
| 124 |
object_fit="contain",
|
| 125 |
allow_preview=False
|
| 126 |
)
|
|
|
|
| 127 |
with gr.Column(scale=3):
|
| 128 |
status = gr.Markdown("**👈 Select a scene to auto-load**")
|
|
|
|
| 129 |
with gr.Tab("🎯 3D Viewer"):
|
|
|
|
| 130 |
viewer_frame = gr.HTML(
|
| 131 |
value="<div style='text-align: center; padding: 100px; color: #666;'>Select a scene</div>"
|
| 132 |
)
|
|
|
|
| 133 |
with gr.Tab("📍 Camera Trajectory"):
|
| 134 |
trajectory_img = gr.Image(label="Camera Path", height=600)
|
| 135 |
|
| 136 |
scene_gallery.select(
|
| 137 |
fn=load_scene,
|
| 138 |
+
inputs=None,
|
| 139 |
outputs=[viewer_frame, trajectory_img, status]
|
| 140 |
)
|
| 141 |
|
| 142 |
if __name__ == "__main__":
|
| 143 |
+
# 這裡必須保留 share=True
|
| 144 |
+
demo.launch(share=True, allowed_paths=[BASE_DIR])
|
|
|