Spaces:
Sleeping
Sleeping
#!/usr/bin/env python3 | |
import gradio as gr | |
import subprocess | |
from pathlib import Path | |
import torch | |
import os | |
import logging | |
import sys | |
import spaces | |
# Logging konfigurieren | |
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") | |
logger = logging.getLogger(__name__) | |
class InfinigenManager: | |
def __init__(self, base_dir="infinigen", output_dir="outputs", blender_version="4.3.2"): | |
"""Initialisiert den InfinigenManager mit Basisverzeichnis, Ausgabeverzeichnis und Blender-Version.""" | |
self.base_dir = Path(base_dir) | |
self.output_dir = Path(output_dir) | |
self.blender_version = blender_version | |
self.blender_bin = None | |
self.blender_python = None | |
self.initialized = False | |
logger.info("Initialisiere InfinigenManager...") | |
self._initialize() | |
def _run_command(self, command, error_msg="Fehler bei Befehlsausführung", timeout=None): | |
"""Führt Befehle einheitlich aus und behandelt Fehler.""" | |
try: | |
result = subprocess.run( | |
command, | |
shell=isinstance(command, str), | |
capture_output=True, | |
text=True, | |
check=True, | |
timeout=timeout | |
) | |
logger.debug(f"STDOUT: {result.stdout}") | |
return result | |
except subprocess.CalledProcessError as e: | |
logger.error(f"{error_msg}: {e.stderr}") | |
raise | |
except subprocess.TimeoutExpired as e: | |
logger.error(f"{error_msg} (Timeout): {e.stderr}") | |
raise | |
def _initialize(self): | |
"""Führt die zentrale Initialisierung durch.""" | |
try: | |
self._setup_blender() | |
self._setup_infinigen() | |
self._check_cuda() | |
self.initialized = True | |
logger.info("Initialisierung erfolgreich abgeschlossen.") | |
except Exception as e: | |
logger.error(f"Initialisierung fehlgeschlagen: {e}") | |
self.initialized = False | |
def _setup_blender(self): | |
"""Richtet Blender und dessen Python-Interpreter ein.""" | |
logger.info("Starte Blender-Setup...") | |
self.blender_bin = self._find_blender() or self._install_latest_blender() | |
self.blender_python = self._find_blender_python_with_grep() | |
if not self.blender_python: | |
raise RuntimeError("Blender Python-Interpreter nicht gefunden!") | |
logger.info(f"Blender Python gefunden: {self.blender_python}") | |
def _find_blender(self): | |
"""Sucht nach einer vorhandenen Blender-Installation.""" | |
blender_paths = [ | |
f"/home/user/blender-{self.blender_version}-linux-x64/blender", | |
"/usr/bin/blender" | |
] | |
for bin_path in blender_paths: | |
if os.path.exists(bin_path): | |
try: | |
version_result = self._run_command([bin_path, "-v"], "Kann Blender-Version nicht prüfen", timeout=10) | |
version = next((line.split()[1] for line in version_result.stdout.split("\n") | |
if "Blender" in line and "." in line), None) | |
logger.info(f"Vorhandene Blender-Version: {version or 'unbekannt'}") | |
if version and version >= self.blender_version: | |
return bin_path | |
except Exception as e: | |
logger.warning(f"Fehler bei Blender-Prüfung ({bin_path}): {e}") | |
return None | |
def _install_latest_blender(self): | |
"""Installiert Blender 4.3.2, falls nicht vorhanden.""" | |
logger.info("Installiere Blender 4.3.2...") | |
url = "https://download.blender.org/release/Blender4.3/blender-4.3.2-linux-x64.tar.xz" | |
tar_path = "blender-4.3.2-linux-x64.tar.xz" | |
blender_dir = Path(f"/home/user/blender-{self.blender_version}-linux-x64") | |
self._run_command(f"wget -q {url}", "Fehler beim Herunterladen von Blender", timeout=60) | |
self._run_command(f"tar -xvf {tar_path} -C /home/user", "Fehler beim Entpacken von Blender", timeout=60) | |
os.remove(tar_path) | |
return blender_dir / "blender" | |
def _find_blender_python_with_grep(self): | |
"""Sucht den Blender-Python-Pfad mit find.""" | |
base_path = Path(self.blender_bin).parent.parent | |
grep_cmd = f"find {base_path} -type f -path '*/python/bin/python3*' -executable" | |
try: | |
result = self._run_command(grep_cmd, "Fehler bei der Python-Suche mit find") | |
python_paths = result.stdout.strip().split("\n") | |
for path in python_paths: | |
if path: | |
version_result = self._run_command([path, "--version"], "Fehler bei Python-Version", timeout=5) | |
logger.info(f"Python-Version: {version_result.stdout.strip()}") | |
return path | |
logger.warning("Kein passender Python-Pfad in find-Ausgabe gefunden.") | |
return None | |
except Exception as e: | |
logger.error(f"Fehler bei der Suche nach Blender-Python: {e}") | |
return None | |
def _check_cuda(self): | |
"""Prüft die CUDA-Verfügbarkeit für GPU-Nutzung.""" | |
cuda_available = torch.cuda.is_available() | |
logger.info(f"CUDA {'verfügbar' if cuda_available else 'nicht verfügbar'}: {torch.cuda.get_device_name(0) if cuda_available else 'N/A'}") | |
def _setup_infinigen(self): | |
"""Richtet Infinigen ein, falls nicht installiert.""" | |
if not self.blender_python: | |
logger.error("Kann Infinigen nicht installieren: Blender Python fehlt.") | |
return | |
logger.info("Starte Infinigen-Setup...") | |
if not self.base_dir.exists(): | |
self._run_command(f"git clone https://github.com/princeton-vl/infinigen.git {self.base_dir}", | |
"Fehler beim Klonen von Infinigen", timeout=30) | |
# Installiere Infinigen mit Abhängigkeiten | |
self._run_command([ | |
self.blender_python, "-m", "pip", "install", "-e", f"{self.base_dir}[terrain,vis]", "--user" | |
], "Fehler bei der Installation von Infinigen", timeout=60) | |
# Überprüfe, ob das datagen-Modul verfügbar ist | |
if not self._is_datagen_available(): | |
raise RuntimeError("Das 'datagen'-Modul von Infinigen ist nicht verfügbar. Überprüfe die Installation.") | |
def _is_datagen_available(self): | |
"""Prüft, ob das 'datagen'-Modul von Infinigen verfügbar ist.""" | |
try: | |
self._run_command([self.blender_python, "-c", "import infinigen.datagen"], timeout=10) | |
return True | |
except Exception as e: | |
logger.error(f"Fehler beim Import von 'infinigen.datagen': {e}") | |
return False | |
def generate_scene(self, seed, configs=None, pipeline_configs=None): | |
"""Generiert eine Szene mit Infinigen auf der GPU.""" | |
if not self.initialized or not self.blender_python: | |
return "Fehler: Infinigen nicht initialisiert!" | |
logger.info(f"Generiere Szene mit Seed: {seed}") | |
self.output_dir.mkdir(exist_ok=True) | |
configs = configs or ["infinigen_examples/configs/desert.gin", "infinigen_examples/configs/simple.gin"] | |
pipeline_configs = pipeline_configs or [ | |
"infinigen_examples/configs/local_16GB.gin", | |
"infinigen_examples/configs/monocular.gin", | |
"infinigen_examples/configs/blender_gt.gin" | |
] | |
command = [ | |
self.blender_python, "-m", "infinigen.datagen.manage_jobs", | |
"--output_folder", str(self.output_dir), | |
"--num_scenes", "1", | |
"--specific_seed", str(int(seed)), | |
"--configs" | |
] + configs + ["--pipeline_configs"] + pipeline_configs | |
try: | |
self._run_command(command, "Fehler bei Szenengenerierung", timeout=300) | |
output_path = self.output_dir / "0000000000.png" | |
return str(output_path) if output_path.exists() else "Fehler: Bild nicht gefunden!" | |
except Exception as e: | |
return f"Fehler bei Szenengenerierung: {str(e)}" | |
# Manager initialisieren | |
logger.info("Starte Manager-Initialisierung...") | |
manager = InfinigenManager() | |
# Gradio-Oberfläche definieren | |
with gr.Blocks(title="Infinigen Demo") as demo: | |
gr.Markdown("## Infinigen Scene Generator") | |
seed_input = gr.Number(label="Seed", value=0, precision=0) | |
output_image = gr.Image(label="Generierte Szene") | |
generate_button = gr.Button("Szene generieren") | |
generate_button.click(fn=manager.generate_scene, inputs=[seed_input], outputs=[output_image]) | |
logger.info("Starte Gradio-Oberfläche...") | |
demo.launch() |