File size: 3,327 Bytes
dfe210b
 
305fc2a
 
dfe210b
305fc2a
 
dfe210b
305fc2a
 
 
 
dfe210b
 
 
 
 
 
 
 
 
80c945e
dfe210b
 
 
 
 
80c945e
305fc2a
dfe210b
80c945e
 
305fc2a
 
 
 
dfe210b
 
305fc2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dfe210b
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env python3
# Copyright 2026 Everpaper. Licensed under the Apache License, Version 2.0 (see ../LICENSE).
"""Smoke test: load the bundle, embed the shipped fictional texts, generated test images and generated audio clips,
compare with the fp32 reference vectors and check that every query finds its own image / clip first.

    python3 smoke_test.py [--bundle ../model] [--compute ane] [--image-compute gpu] [--audio-compute gpu] [--text-only]
                          [--no-audio] [--cleanup-temp] [--reference ../tests/smoke-reference.json ...]

Exit code 0 = every cosine >= its threshold (0.999 texts, 0.998 images, 0.9995 / 0.995 audio clips), all values
finite, every query at rank 1. `--text-only` runs only the v1.0 text reference and loads neither the vision nor the
audio asset; `--no-audio` skips the audio reference. The first run of a new executable (here: your python binary)
specializes the assets for the Neural Engine: expect a few minutes. Later runs load in about a second.
"""
from __future__ import annotations

import argparse
import sys
from pathlib import Path

HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
from embeddinggemma2_coreai import remove_own_mpsgraph_temp_files, run_smoke  # noqa: E402


def main() -> int:
    ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    ap.add_argument("--bundle", default=str(HERE.parent / "model"))
    ap.add_argument("--reference", action="append", default=None,
                    help="reference file(s); default: tests/smoke-reference.json, image-smoke-reference.json and audio-smoke-reference.json")
    ap.add_argument("--compute", default="ane", choices=["ane", "gpu", "cpu", "default"])
    ap.add_argument("--image-compute", default=None, choices=["ane", "gpu", "cpu", "default"],
                    help="where the image encoder runs (default: same as --compute)")
    ap.add_argument("--audio-compute", default=None, choices=["ane", "gpu", "cpu", "default"],
                    help="where the audio encoder runs (default: same as --compute)")
    ap.add_argument("--text-only", action="store_true", help="only the text reference (the vision and audio assets are not loaded)")
    ap.add_argument("--no-audio", action="store_true", help="skip the audio reference (the audio asset is not loaded)")
    ap.add_argument("--cleanup-temp", action="store_true", help="remove this process's MPSGraph temp folders at exit")
    a = ap.parse_args()
    tests = HERE.parent / "tests"
    refs = a.reference or [str(tests / "smoke-reference.json")] + (
        [] if a.text_only else [str(tests / "image-smoke-reference.json")] + ([] if a.no_audio else [str(tests / "audio-smoke-reference.json")]))
    try:
        ok = run_smoke(a.bundle, refs, a.compute, a.image_compute, a.audio_compute)
    except ValueError as e:  # e.g. --audio-compute cpu (refused before anything is loaded): a message, not a traceback
        print(f"error: {e}", file=sys.stderr)
        return 2
    finally:
        if a.cleanup_temp:  # also after an error
            import gc

            gc.collect()
            n, b = remove_own_mpsgraph_temp_files()
            print(f"cleanup-temp: removed {n} MPSGraph temp folder(s), {b / 2**20:.1f} MB")
    return 0 if ok else 1


if __name__ == "__main__":
    sys.exit(main())