"""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 '
Include at least one question in the JSON.
' return f'' 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'
{html.escape(detail)}' f"

{html.escape(text_value(question.get('instructions')))}

" ) return ( f'
{len(questions)} questions · one request
' + "".join(rows) + "
" ) 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