"""Attach modification notices and stage a platform release directory.""" import argparse import json import math import os import shutil import struct from pathlib import Path from scripts.integrity import sha256, verify_files from scripts.provenance import REVISION, model_identity, validate_model_structure, validate_roles from scripts.quantize import DIFFUSERS_COMMIT from scripts.report import load_records, summary_from MODIFICATION = ('Modified by ixim / iximbox: eligible linear weights converted from ' 'Qwen-Image-2.1 to SDNQ UINT4 with SVD rank 32. Built with Qwen. ' 'Non-commercial research/evaluation under the accompanying Qwen Research License.') GENERATION_CASES = ('portrait', 'english_text', 'chinese_text', 'composition', 'texture', 'rgba') EDIT_SEEDS = (1000042, 1000123) VRAM_CAP_BYTES = int(7.2 * 2**30) def add_safetensors_notice(path): path = Path(path) temp = path.with_name(path.name + '.notice-tmp') try: with path.open('rb') as source: prefix = source.read(8) if len(prefix) != 8: raise ValueError(f'Invalid safetensors prefix: {path}') length = struct.unpack(' 100_000_000: raise ValueError('Unexpected safetensors header size') header = json.loads(source.read(length)) metadata = header.setdefault('__metadata__', {}) if metadata.get('modification_notice') == MODIFICATION: return metadata.update(modification_notice=MODIFICATION, base_revision=REVISION) encoded = json.dumps(header, ensure_ascii=False, separators=(',', ':')).encode('utf-8') encoded += b' ' * ((8 - len(encoded) % 8) % 8) with temp.open('wb') as target: target.write(struct.pack(' VRAM_CAP_BYTES or row['peak_reserved_bytes'] > VRAM_CAP_BYTES: raise ValueError('8GB proof exceeded the allocator cap') return row def stage(model, evaluation, output, platform): model, evaluation, output = Path(model), Path(evaluation), Path(output) if output.exists(): raise FileExistsError(f'Refusing to overwrite release directory: {output}') summary = json.loads((evaluation / 'summary.json').read_text(encoding='utf-8')) if summary['pairs'] != 14 or summary['cases'] != 7 or summary['steps'] != 40 or not summary['warmup']: raise ValueError('Release requires the 14-pair, 40-step evaluation') identity = validate_evaluation(evaluation, model, summary) vram_row = validate_vram(evaluation, identity) conversion = json.loads((model / 'conversion.json').read_text(encoding='utf-8')) verify_files(model, conversion['weight_files']) for component in ('transformer', 'text_encoder'): quant = json.loads((model / component / 'config.json').read_text(encoding='utf-8'))['quantization_config'] if str(quant.get('quant_method', '')).lower() != 'sdnq' or quant.get('weights_dtype') != 'uint4': raise ValueError(f'{component} is not saved as SDNQ UINT4') if quant.get('use_quantized_matmul'): raise ValueError(f'{component} enables a non-portable matmul kernel') shutil.copytree(model, output, ignore=shutil.ignore_patterns('.cache', '__pycache__', '*.lock')) shutil.copytree(evaluation, output / 'evaluation', ignore=shutil.ignore_patterns('__pycache__')) for name in ('scripts', 'benchmarks', 'cards', 'tests'): shutil.copytree(name, output / name, ignore=shutil.ignore_patterns('__pycache__', '*.pyc')) shutil.copy2('README.md', output / 'REPRODUCE.md') for name in ('requirements.txt', 'PUBLISHING.md'): shutil.copy2(name, output / name) shutil.copy2('artifacts/download-verification.json', output / 'upstream-verification.json') from scripts.model_card import render card = Path(f'cards/{platform}.md').read_text(encoding='utf-8') rendered = render(evaluation, platform, summary, vram_row) for key, value in rendered.items(): card = card.replace('{{' + key + '}}', value) if '{{' in card: raise ValueError('Unrendered model card placeholder') (output / 'README.md').write_text(card, encoding='utf-8') if platform == 'modelscope': (output / 'configuration.json').write_text(json.dumps( {'framework': 'pytorch', 'task': 'text-to-image-synthesis'}, indent=2) + '\n', encoding='utf-8') manifest = [{'path': path.relative_to(output).as_posix(), 'size': path.stat().st_size, 'sha256': sha256(path)} for path in sorted(output.rglob('*')) if path.is_file()] (output / 'MANIFEST.json').write_text(json.dumps(manifest, indent=2), encoding='utf-8') print(f'Staged {platform}: {len(manifest)} files, {sum(item["size"] for item in manifest)/1e9:.3f} GB', flush=True) def validate_release(root): root = Path(root) rows = json.loads((root / 'MANIFEST.json').read_text(encoding='utf-8')) expected = {row['path'] for row in rows} | {'MANIFEST.json'} actual = {path.relative_to(root).as_posix() for path in root.rglob('*') if path.is_file()} if actual != expected: raise ValueError(f'Unexpected or missing release files: {sorted(actual ^ expected)[:12]}') verify_files(root, rows) summary = json.loads((root / 'evaluation/summary.json').read_text(encoding='utf-8')) validate_evaluation(root / 'evaluation', root, summary) validate_vram(root / 'evaluation', model_identity(root)) return rows def main(): parser = argparse.ArgumentParser() parser.add_argument('action', choices=['annotate', 'stage', 'check']) parser.add_argument('--model', default='models/int4') parser.add_argument('--evaluation', default='artifacts/eval') parser.add_argument('--output', default='release/huggingface') parser.add_argument('--platform', choices=['huggingface', 'modelscope'], default='huggingface') args = parser.parse_args() if args.action == 'annotate': annotate(args.model) elif args.action == 'stage': stage(args.model, args.evaluation, args.output, args.platform) else: print(f'Validated {len(validate_release(args.output))} files') if __name__ == '__main__': main()