Add environment artifact: smoke_test.py
Browse files- smoke_test.py +85 -0
smoke_test.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Dependency, headless rendering and optional GPU checks; no model downloads."""
|
| 2 |
+
import argparse
|
| 3 |
+
import importlib
|
| 4 |
+
import importlib.metadata
|
| 5 |
+
import json
|
| 6 |
+
import os
|
| 7 |
+
import subprocess
|
| 8 |
+
import tempfile
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
os.environ.setdefault("PYOPENGL_PLATFORM", "osmesa")
|
| 12 |
+
os.environ.setdefault("HF_HUB_OFFLINE", "1")
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def main():
|
| 16 |
+
parser = argparse.ArgumentParser()
|
| 17 |
+
parser.add_argument("--gpu", action="store_true")
|
| 18 |
+
args = parser.parse_args()
|
| 19 |
+
modules = [
|
| 20 |
+
"torch", "torchaudio", "torchvision", "numpy", "scipy", "soundfile",
|
| 21 |
+
"datasets", "transformers", "huggingface_hub", "safetensors", "yaml",
|
| 22 |
+
"f5_tts.api", "vocos", "smplx", "chumpy", "pyrender", "trimesh",
|
| 23 |
+
"imageio", "imageio_ffmpeg", "whisper", "jiwer", "python_speech_features",
|
| 24 |
+
]
|
| 25 |
+
for name in modules:
|
| 26 |
+
importlib.import_module(name)
|
| 27 |
+
import numpy as np
|
| 28 |
+
import pyrender
|
| 29 |
+
import soundfile as sf
|
| 30 |
+
import torch
|
| 31 |
+
import torchaudio.functional as audio_fn
|
| 32 |
+
import trimesh
|
| 33 |
+
|
| 34 |
+
scene = pyrender.Scene(bg_color=[255, 255, 255, 255], ambient_light=[0.5, 0.5, 0.5])
|
| 35 |
+
material = pyrender.MetallicRoughnessMaterial(baseColorFactor=[0.55, 0.68, 0.82, 1.0])
|
| 36 |
+
scene.add(pyrender.Mesh.from_trimesh(trimesh.creation.icosphere(subdivisions=1), material=material))
|
| 37 |
+
pose = np.eye(4)
|
| 38 |
+
pose[2, 3] = 3.0
|
| 39 |
+
scene.add(pyrender.PerspectiveCamera(yfov=np.pi / 3), pose=pose)
|
| 40 |
+
scene.add(pyrender.DirectionalLight(color=np.ones(3), intensity=2), pose=pose)
|
| 41 |
+
renderer = pyrender.OffscreenRenderer(64, 64)
|
| 42 |
+
try:
|
| 43 |
+
color, depth = renderer.render(scene)
|
| 44 |
+
assert color.shape[:2] == (64, 64) and np.count_nonzero(depth) > 0
|
| 45 |
+
finally:
|
| 46 |
+
renderer.delete()
|
| 47 |
+
with tempfile.TemporaryDirectory() as temp:
|
| 48 |
+
wav = Path(temp) / "tone.wav"
|
| 49 |
+
sf.write(wav, np.zeros(24000, np.float32), 24000)
|
| 50 |
+
waveform, sr = sf.read(wav)
|
| 51 |
+
assert sr == 24000 and len(waveform) == 24000
|
| 52 |
+
video = Path(temp) / "test.mp4"
|
| 53 |
+
subprocess.run([
|
| 54 |
+
"ffmpeg", "-nostdin", "-v", "error", "-f", "lavfi", "-i",
|
| 55 |
+
"color=c=blue:s=64x64:r=30:d=1", "-i", str(wav),
|
| 56 |
+
"-c:v", "libx264", "-pix_fmt", "yuv420p", "-c:a", "aac",
|
| 57 |
+
"-t", "1", str(video),
|
| 58 |
+
], check=True)
|
| 59 |
+
subprocess.run(["ffmpeg", "-nostdin", "-v", "error", "-xerror", "-i", str(video), "-f", "null", "-"], check=True)
|
| 60 |
+
tools = {}
|
| 61 |
+
for name, command in {
|
| 62 |
+
"git": ["git", "--version"], "git-lfs": ["git", "lfs", "version"],
|
| 63 |
+
"font": ["fc-match", "-f", "%{file}", "sans"],
|
| 64 |
+
}.items():
|
| 65 |
+
tools[name] = subprocess.check_output(command, text=True).strip()
|
| 66 |
+
assert Path(tools["font"]).is_file()
|
| 67 |
+
result = {
|
| 68 |
+
"tools": tools,
|
| 69 |
+
"imports": modules, "osmesa": "passed", "h264_aac": "passed",
|
| 70 |
+
"torch": torch.__version__, "cuda_build": torch.version.cuda,
|
| 71 |
+
"gpu_test_requested": args.gpu,
|
| 72 |
+
}
|
| 73 |
+
if args.gpu:
|
| 74 |
+
assert torch.cuda.is_available(), "A CUDA-capable runtime is required for --gpu"
|
| 75 |
+
x = torch.randn(128, 128, device="cuda")
|
| 76 |
+
assert torch.isfinite(x @ x.T).all().item()
|
| 77 |
+
resampled = audio_fn.resample(torch.zeros(1, 2400, device="cuda"), 24000, 16000)
|
| 78 |
+
assert resampled.shape[-1] == 1600
|
| 79 |
+
torch.cuda.synchronize()
|
| 80 |
+
result["gpu"] = torch.cuda.get_device_name(0)
|
| 81 |
+
print(json.dumps(result, ensure_ascii=False), flush=True)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
if __name__ == "__main__":
|
| 85 |
+
main()
|