File size: 4,153 Bytes
6fe13ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Drive the generated REST endpoints against a running app.

This layer exists because `test_pipelines.py` calls `WorkflowExecutor` directly
and therefore skips gradio's *output component* postprocessing — which is
exactly where an image port's value shape matters. A bare `data:` URI passes
the executor happily and then dies in the endpoint with

    OSError: [Errno 22] Invalid argument: '...\\data:image\\png;base64,...'

because gradio treats the URI as a filename. Only these tests catch that.

    python apps/05_workflow1111/app.py                 # in another shell
    python apps/05_workflow1111/test_api.py [url]      # default 127.0.0.1:7865

Pass `--local` to exercise only the endpoints that need no Hugging Face token.
"""

import os
import sys
import time
import warnings

warnings.filterwarnings("ignore")
import logging  # noqa: E402

logging.disable(logging.CRITICAL)

for _s in (sys.stdout, sys.stderr):
    try:
        _s.reconfigure(encoding="utf-8", errors="replace")
    except (AttributeError, ValueError):
        pass

from gradio_client import Client, handle_file  # noqa: E402

HERE = os.path.dirname(os.path.abspath(__file__))
SAMPLES = os.path.join(HERE, "samples")

args = [a for a in sys.argv[1:] if not a.startswith("--")]
LOCAL_ONLY = "--local" in sys.argv
URL = args[0] if args else "http://127.0.0.1:7865"


def sample(name):
    path = os.path.join(SAMPLES, name)
    if not os.path.exists(path):
        raise SystemExit(f"missing sample {name} — run make_samples.py first")
    return handle_file(path)


# (api_name, args, needs_token)
CASES = [
    ("/annotator_map", lambda: [sample("control.jpg")], False),
    ("/png_info", lambda: [sample("with_parameters.png")], False),
    ("/upscaled_local", lambda: [sample("extras.jpg")], True),   # also hits 2 Spaces
    ("/image", lambda: ["a red fox in a snowy pine forest", "", "Cinematic",
                        "enhance fine detail"], True),
    ("/edited_image", lambda: [sample("init_image.jpg"),
                               "make it a snowy winter scene"], True),
    ("/generated_prompt", lambda: ["a lighthouse in a storm"], True),
    ("/recovered_prompt", lambda: [sample("interrogate.jpg")], True),
    ("/detected_objects", lambda: [sample("detect.jpg")], True),
    ("/x_y_grid", lambda: ["a lone tree on a hill",
                           "at sunrise | in a storm | at night | in fog"], True),
]


def describe(value):
    if isinstance(value, (list, tuple)):
        return " | ".join(describe(v) for v in value)
    if isinstance(value, dict):
        value = value.get("path") or value.get("url") or str(value)
    if isinstance(value, str) and os.path.isfile(value):
        try:
            from PIL import Image
            with Image.open(value) as im:
                return f"image {im.width}×{im.height} {im.format}"
        except Exception:
            return f"file ({os.path.getsize(value) // 1024} KB)"
    text = str(value).replace("\n", " ")
    return f"text: {text[:64]}"


def main():
    client = Client(URL, verbose=False)
    available = set(client.view_api(return_format="dict",
                                    print_info=False)["named_endpoints"])
    print(f"\n{URL}{len(available)} endpoints\n")

    passed = failed = skipped = 0
    for name, build, needs_token in CASES:
        if name not in available:
            print(f"  skip  {name:20} (not exposed)")
            skipped += 1
            continue
        if LOCAL_ONLY and needs_token:
            skipped += 1
            continue
        t0 = time.time()
        try:
            result = client.predict(*build(), api_name=name)
        except Exception as e:
            failed += 1
            print(f"  FAIL  {name:20} ({time.time() - t0:6.1f}s)  "
                  f"{type(e).__name__}: {str(e)[:120]}")
        else:
            passed += 1
            print(f"  ok    {name:20} ({time.time() - t0:6.1f}s)  {describe(result)}")
        sys.stdout.flush()

    print(f"\n{'=' * 66}\n  {passed} passed, {failed} failed, {skipped} skipped\n{'=' * 66}")
    return 1 if failed else 0


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