component-studio / scripts /verify_space.py
mantrakp's picture
Integrate isolated Astra refinement, learned rigging and native Kimodo animation
381de33 verified
Raw History Blame Contribute Delete
3.42 kB
"""Run real inference on an explicitly named deployed Space and verify its downloaded GLB/ZIP."""
import argparse
import json
import os
from pathlib import Path
import zipfile
import time
from gradio_client import Client, handle_file
from huggingface_hub import get_token
import trimesh
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--space', required=True, help='Hugging Face owner/space')
parser.add_argument('--image', type=Path)
parser.add_argument('--prompt', default='')
parser.add_argument('--animation-prompt', default='')
parser.add_argument('--animation-seconds', type=float, default=6)
parser.add_argument('--output-dir', type=Path, default=Path('outputs/hf-verification'))
args = parser.parse_args()
if not args.image and not args.prompt.strip():
parser.error('Supply --image, --prompt, or both')
args.output_dir.mkdir(parents=True, exist_ok=True)
client = Client(args.space, token=os.environ.get('HF_TOKEN') or get_token(),
download_files=args.output_dir.resolve())
job = client.submit(handle_file(str(args.image)) if args.image else None,
args.prompt, 8, 0, args.animation_prompt, args.animation_seconds, api_name='/generate')
previous = None
while not job.done():
update = job.status()
current = (update.code.name, tuple(p.desc for p in update.progress_data or []))
if current != previous:
print(json.dumps({'state': current[0], 'progress': current[1]}), flush=True)
previous = current
time.sleep(2)
model, reference, views, bundle, status, manifest, video = job.result()
(args.output_dir / f"{manifest['id']}.json").write_text(json.dumps(manifest, indent=2))
if args.animation_prompt:
import struct
raw = Path(model).read_bytes()
size, kind = struct.unpack_from('<II', raw, 12)
if kind != 0x4e4f534a:
raise RuntimeError('Animated GLB has no JSON chunk')
gltf = json.loads(raw[20:20 + size])
if not gltf.get('skins') or not gltf.get('animations'):
raise RuntimeError('Requested animation returned a static mesh')
if not video or not manifest.get('animation', {}).get('accepted'):
raise RuntimeError('Animation lacks video or failed its technical/visual review')
if manifest['status'] != 'complete':
raise RuntimeError('Space did not complete all stages')
scene = trimesh.load(model, force='scene', process=False)
if len(scene.geometry) != manifest['metrics']['components']:
raise RuntimeError('Downloaded component count differs from manifest')
for mesh in scene.geometry.values():
if not len(mesh.faces) or mesh.visual.kind != 'texture' or mesh.visual.material.baseColorTexture is None:
raise RuntimeError('Downloaded mesh has missing geometry or texture')
with zipfile.ZipFile(bundle) as archive:
embedded = json.loads(archive.read('manifest.json'))
if embedded['id'] != manifest['id'] or 'final.glb' not in archive.namelist():
raise RuntimeError('Download archive does not match the completed run')
print(json.dumps({'verified': True, 'run': manifest['id'], 'model': model, 'bundle': bundle,
'components': len(scene.geometry)}, indent=2))
if __name__ == '__main__':
main()