File size: 4,088 Bytes
a6d9a38
 
 
 
 
 
 
4a85866
a6d9a38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a85866
a6d9a38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Plain-language question editing and handoff to an app builder."""

import html
import json

from bongard.data import DataError, strict_loads, validate_question

KIND_LABELS = {"choice": "Choose one option", "noul": "Yes or no", "score": "Rate on a scale"}


def label(key):
    text = key.replace("_", " ").strip()
    return text[:1].upper() + text[1:]


def text_value(value):
    return value if isinstance(value, str) else json.dumps(value, ensure_ascii=False)


def load_questions(text):
    try:
        questions = strict_loads(text or "")
    except (ValueError, DataError) as exc:
        raise DataError(f"The question JSON could not be read: {exc}") from None
    if not isinstance(questions, dict) or not 1 <= len(questions) <= 8:
        raise DataError("Include 1–8 questions in this request.")
    for key, question in questions.items():
        validate_question(question, key)
        if question["type"] == "choice" and not 2 <= len(question["criteria"]) <= 32:
            raise DataError("A choice question needs 2–32 answer options.")
    return questions


def question_preview(text):
    try:
        questions = load_questions(text)
    except DataError as exc:
        if (text or "").strip() == "{}":
            return '<div class="question-empty">Include at least one question in the JSON.</div>'
        return f'<div class="inline-error" role="alert">{html.escape(str(exc))}</div>'
    rows = []
    for question in questions.values():
        kind = question["type"]
        detail = KIND_LABELS[kind]
        if kind != "noul":
            count = len(question["criteria"])
            detail += f" · {count} {'options' if kind == 'choice' else 'levels'}"
        rows.append(
            f'<div class="question-summary"><span>{html.escape(detail)}</span>'
            f"<p>{html.escape(text_value(question.get('instructions')))}</p></div>"
        )
    return (
        f'<div class="question-list"><div class="questions-count">{len(questions)} questions · one request</div>'
        + "".join(rows)
        + "</div>"
    )


def handoff(state_text, questions_text, has_image=False, calibrated=True, rotations=False):
    questions = load_questions(questions_text)
    image = 'handle_file("your-photo.png")' if has_image else "None"
    code = (
        "# Install once: pip install gradio_client\n"
        "from gradio_client import Client, handle_file\n\n"
        'client = Client("AgentBull/bongard-mini")\n'
        f"state_text = {state_text!r}\n"
        f"questions_text = {json.dumps(questions, ensure_ascii=False)!r}\n\n"
        "_, _, response = client.predict(\n"
        f"    state_text, questions_text, {image}, {calibrated}, {rotations},\n"
        '    api_name="/decide",\n'
        ")\n"
        'print(response["answers"])\n'
    )
    prompt = (
        "Add Bongard-mini decision judgments to my app using the tested request below. "
        "For a prototype, call the public Hugging Face Space AgentBull/bongard-mini with "
        "the official Gradio client for my app's stack: gradio_client for Python or "
        "@gradio/client for JavaScript. Use the '/decide' endpoint. The arguments, in order, "
        "are state_text, questions_text "
        f"(JSON string), image (optional), calibrated={calibrated}, rotations={rotations}. The third return "
        "value (Python prediction[2], JavaScript result.data[2]) is the model response; "
        "use its 'answers' dictionary and preserve its full "
        "probability distributions. Handle response['error'] and waiting for a GPU. "
        "Keep credentials on the server and do not bake a Hugging Face token into the frontend. "
        "For deployment, use the downloadable model and public runtime at "
        "https://huggingface.co/AgentBull/bongard-mini and https://github.com/AgentBull/bongard.\n\n"
        f"Context:\n{state_text}\n\nQuestions:\n{json.dumps(questions, ensure_ascii=False, indent=2)}"
    )
    if has_image:
        prompt += "\n\nThis request also requires an image. Let the user attach it as image 1."
    return prompt, code