File size: 3,199 Bytes
714a774
 
 
 
c850f47
 
714a774
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c850f47
714a774
 
 
 
c850f47
 
714a774
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c850f47
 
 
 
 
714a774
 
c850f47
 
 
714a774
 
 
 
 
c850f47
 
 
 
714a774
 
 
 
 
 
 
 
 
 
 
 
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
"""
test_caption.py — verify STAGE 1 (object identification) in isolation.

Calls the caption Space and checks we get back a short object phrase (the dedup
key). Run `inspect_api.py` first and make sure the /chat_joycaption arg order
below matches; if it doesn't, fix it here AND in app.py's caption_object().

Consumes a little ZeroGPU quota (one call). Set HF_TOKEN so it's billed to you
and gets real quota; without a token you get the tiny anonymous allowance.

Usage:
    HF_TOKEN=hf_xxx python test_caption.py --image photo.jpg
    HF_TOKEN=hf_xxx python test_caption.py            # uses a synthetic test image
"""

import os
import sys
import argparse
import tempfile

from gradio_client import Client, handle_file

SPACE = os.getenv("CAPTION_SPACE", "fancyfeast/joy-caption-beta-one")
TOKEN = os.getenv("HF_TOKEN")

INSTRUCTION = (
    "Identify the single main physical object in this image as a short, generic "
    "noun phrase of 1 to 4 words (for example 'ceramic coffee mug' or 'wooden "
    "chair'). Ignore the background. Reply with ONLY the object name."
)


def make_test_image() -> str:
    """A trivial image so the test runs with zero setup. A real photo gives a more
    meaningful caption, but this is enough to prove the API call works."""
    from PIL import Image, ImageDraw
    img = Image.new("RGB", (512, 512), (232, 232, 236))
    ImageDraw.Draw(img).ellipse([150, 150, 362, 362], fill=(198, 92, 70))
    path = os.path.join(tempfile.gettempdir(), "piclets_test.png")
    img.save(path)
    return path


def main() -> None:
    ap = argparse.ArgumentParser()
    ap.add_argument("--image", help="path to a test photo (optional)")
    args = ap.parse_args()
    image_path = args.image or make_test_image()

    print(f"[caption] space = {SPACE}")
    print(f"[caption] image = {image_path}")
    if not TOKEN:
        print("[caption] WARNING: no HF_TOKEN — using the tiny anonymous ZeroGPU quota; may fail.")

    client = Client(SPACE, hf_token=TOKEN)

    # /chat_joycaption positional args (verify with inspect_api.py):
    #   (input_image, prompt, temperature, top_p, max_new_tokens, log_prompt)
    #     -> caption (a single string)
    # temperature=0 for deterministic, terse object names. Mirror in app.py
    # caption_object().
    result = client.predict(
        handle_file(image_path),
        INSTRUCTION,    # prompt
        0,              # temperature (deterministic)
        api_name="/chat_joycaption",
    )

    print("\n[caption] RAW RESULT (inspect this if anything looks off):")
    print(repr(result)[:1500])

    # beta-one returns the caption as a bare string (not a tuple).
    caption = result if isinstance(result, str) else (
        result[1] if isinstance(result, (list, tuple)) and len(result) > 1 else str(result)
    )
    phrase = " ".join(caption.strip().split()[:5])
    print(f"\n[caption] extracted object phrase: {phrase!r}")

    ok = bool(phrase) and len(phrase) < 80
    print("[caption] PASS" if ok else
          "[caption] FAIL — check RAW RESULT, then fix the arg order / result index "
          "here and in app.py caption_object().")
    sys.exit(0 if ok else 1)


if __name__ == "__main__":
    main()