Spaces:
Running on Zero
Running on Zero
| """ | |
| AI 3D Generator - TripoSG + rembg (Fixed for HF Space) | |
| """ | |
| import os | |
| import sys | |
| import uuid | |
| import time | |
| import logging | |
| import tempfile | |
| from pathlib import Path | |
| from typing import List | |
| import gradio as gr | |
| import numpy as np | |
| import torch | |
| from PIL import Image | |
| import trimesh | |
| from rembg import remove | |
| # ZeroGPU support | |
| try: | |
| import spaces | |
| except ImportError: | |
| class spaces: | |
| def GPU(fn=None, duration=None): | |
| if fn is None: | |
| return lambda f: f | |
| return fn | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") | |
| logger = logging.getLogger(__name__) | |
| # Config | |
| MODEL_ID = "VAST-AI/TripoSG" | |
| TRIPOSG_REPO_URL = "https://github.com/VAST-AI-Research/TripoSG.git" | |
| TRIPOSG_CODE_DIR = "triposg_repo" | |
| OUTPUT_DIR = Path(tempfile.gettempdir()) / "triposg_output" | |
| OUTPUT_DIR.mkdir(parents=True, exist_ok=True) | |
| # Clone repo | |
| if not os.path.exists(TRIPOSG_CODE_DIR): | |
| logger.info("Cloning TripoSG...") | |
| os.system(f"git clone {TRIPOSG_REPO_URL} {TRIPOSG_CODE_DIR}") | |
| sys.path.insert(0, TRIPOSG_CODE_DIR) | |
| sys.path.insert(0, os.path.join(TRIPOSG_CODE_DIR, "scripts")) | |
| # Global | |
| triposg_pipeline = None | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| def load_models(): | |
| global triposg_pipeline | |
| if triposg_pipeline is not None: | |
| return | |
| logger.info("Loading TripoSG...") | |
| try: | |
| from huggingface_hub import snapshot_download | |
| from triposg.pipelines.pipeline_triposg import TripoSGPipeline | |
| model_path = snapshot_download(MODEL_ID) | |
| triposg_pipeline = TripoSGPipeline.from_pretrained(model_path).to(device, torch.float16 if device == "cuda" else torch.float32) | |
| logger.info("TripoSG loaded") | |
| except Exception as e: | |
| logger.error(f"Load failed: {e}") | |
| triposg_pipeline = None | |
| def remove_background(image: Image.Image) -> Image.Image: | |
| try: | |
| return remove(image) | |
| except Exception as e: | |
| logger.warning(f"rembg failed: {e}") | |
| return image | |
| # ================== 下面貼返你原本其他函數 ================== | |
| # 請你從原本 app.py copy 下面這些函數貼入去: | |
| # select_best_view, create_composite_view, extract_dimensions_from_prompt, repair_mesh, scale_mesh, segment_mesh_parts, export_mesh | |
| # (如果你冇,我可以提供最小版 placeholder) | |
| # ================== Main Pipeline ================== | |
| def generate_3d_model(input_images: list, text_prompt: str, num_faces: int = 50000, export_format: str = "glb", progress=gr.Progress()): | |
| load_models() | |
| if triposg_pipeline is None: | |
| raise gr.Error("Model load failed. Check logs.") | |
| # ... 你原本 generate 邏輯 ... | |
| # 暫時用 placeholder | |
| return None, None, "Pipeline running... (add your full logic here)" | |
| # ================== UI ================== | |
| with gr.Blocks(title="AI 3D Generator") as demo: | |
| gr.Markdown("# 🚀 TripoSG 3D Generator (rembg version)") | |
| with gr.Row(): | |
| with gr.Column(): | |
| input_images = gr.File(label="Upload Images", file_count="multiple", file_types=["image"]) | |
| text_prompt = gr.Textbox(label="Text Prompt (dimensions etc)", lines=3) | |
| num_faces = gr.Slider(5000, 90000, value=50000, step=5000, label="Target Faces") | |
| btn = gr.Button("Generate 3D Model", variant="primary") | |
| with gr.Column(): | |
| preview = gr.Model3D(label="3D Preview") | |
| download = gr.File(label="Download Model") | |
| status = gr.Textbox(label="Status", lines=8) | |
| btn.click( | |
| generate_3d_model, | |
| inputs=[input_images, text_prompt, num_faces], | |
| outputs=[preview, download, status] | |
| ) | |
| demo.queue(max_size=5) | |
| demo.launch(show_api=True) |