import gradio as gr
import os
import urllib.parse # 新增:用於處理網址編碼
# 獲取當前絕對路徑
BASE_DIR = os.path.abspath(os.getcwd())
SCENES = [
{
"name": "Office 0",
"thumb": "assets/office0.PNG",
"model": "assets/office0.ply",
"tracking_img": "assets/office0_tracking.PNG"
},
{
"name": "Office 2",
"thumb": "assets/office2.PNG",
"model": "assets/office2.ply",
"tracking_img": "assets/office2_tracking.PNG"
},
{
"name": "Room 0",
"thumb": "assets/room0.PNG",
"model": "assets/room0.ply",
"tracking_img": "assets/room0_tracking.PNG"
}
]
gallery_items = [(item["thumb"], item["name"]) for item in SCENES]
import urllib.parse # 確保有這一行
def load_scene(evt: gr.SelectData, request: gr.Request):
index = evt.index
scene = SCENES[index]
# 取得 Hugging Face Space 的 ID (例如: yfyangd/rgs-slam-demo)
space_id = os.environ.get("SPACE_ID")
# --- 關鍵修正邏輯 ---
if space_id:
# 【情境 A:在 Hugging Face Spaces 線上執行】
# 我們改用 Hugging Face 的 "resolve" 網址。
# 這是直接指向 Git 倉庫的原始檔案,速度快且通常不會被 CORS 擋住。
# 格式: https://huggingface.co/spaces/{SPACE_ID}/resolve/main/{相對路徑}
# 注意:這裡直接用 scene["model"] (例如 assets/office0.ply),不需要絕對路徑
file_url = f"https://huggingface.co/spaces/{space_id}/resolve/main/{scene['model']}"
# 有些 viewer 需要加上 download=true 才能正確觸發 header,但 antimatter 通常不用
print(f"🌍 Using HF Repo URL: {file_url}")
else:
# 【情境 B:在 本機 (Localhost) 執行】
# 保持原本的邏輯,使用 localhost 的連結
full_model_path = os.path.join(BASE_DIR, scene["model"])
if not os.path.exists(full_model_path):
return (
"
⚠️ File not found
",
None,
f"**⚠️ Error:** File not found: {full_model_path}"
)
# 處理 Windows 路徑
clean_path = full_model_path.replace("\\", "/")
base_url = "http://127.0.0.1:7860"
if request:
host = request.headers.get("host")
if "gradio.live" in host:
base_url = f"https://{host}"
else:
base_url = f"http://{host}"
file_url = f"{base_url}/file={clean_path}"
print(f"🏠 Using Local URL: {file_url}")
# --- 通用部分:編碼並生成 iframe ---
# 編碼 file_url (處理特殊字元)
encoded_file_url = urllib.parse.quote(file_url, safe=':/')
# 組合外部 Viewer 連結
viewer_url = f"https://antimatter15.com/splat/?url={encoded_file_url}"
html = f"""
"""
status_msg = f"**{scene['name']}** - Loaded via {'HF CDN' if space_id else 'Local Server'}"
return (
html,
scene["tracking_img"],
status_msg
)
# --- UI (保持不變) ---
with gr.Blocks(title="RGS-SLAM Demo") as demo:
gr.Markdown("# 🚀 RGS-SLAM Gaussian Splatting Viewer")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### 📂 Select Scene")
scene_gallery = gr.Gallery(
value=gallery_items,
label="Available Scenes",
columns=1,
height=400,
object_fit="contain",
allow_preview=False
)
with gr.Column(scale=3):
status = gr.Markdown("**👈 Select a scene to auto-load**")
with gr.Tab("🎯 3D Viewer"):
viewer_frame = gr.HTML(
value="Select a scene
"
)
with gr.Tab("📍 Camera Trajectory"):
trajectory_img = gr.Image(label="Camera Path", height=600)
scene_gallery.select(
fn=load_scene,
inputs=None,
outputs=[viewer_frame, trajectory_img, status]
)
if __name__ == "__main__":
# 判斷是否在 Hugging Face Spaces 上執行
# HF Spaces 會有名為 "SPACE_ID" 的環境變數
is_on_hf_spaces = "SPACE_ID" in os.environ
demo.launch(
share=not is_on_hf_spaces, # 如果在 HF Spaces 就 False,本地就 True
allowed_paths=[BASE_DIR]
)