"""Rewrite the question texts of a gallery JSONL to the q2 wording (clearer criteria, same gold). usage: python scripts/make_q2.py in.jsonl out.jsonl """ import json, sys INSTR = { "screen": { "en": "What is the current screen state? Decide in this order: if an alert, dialog or action sheet is shown, pick its kind; otherwise, if a sheet is presented, pick sheet whatever it contains; otherwise describe the screen underneath. Banners and toasts do not change the answer.", "ja": "現在の画面状態はどれか?次の順で判断する。アラート・ダイアログ・アクションシートがあればその種類。なければ、シートが出ていれば中身に関係なくシート。それもなければ下の画面で答える。バナーやトーストは答えを変えない。", }, "has_error": { "en": "Is an error or failure message visible (alert, banner, toast, inline validation, or error screen), including an offline / no connection banner?", "ja": "エラーや失敗を示すメッセージ(ダイアログ・バナー・トースト・入力エラー・エラー画面)が表示されているか?オフライン・接続なしの表示も含む。", }, "primary_button": { "en": "Which is the primary action button? Answer with the button's action even if it is disabled or shows a progress spinner.", "ja": "最も目立つ操作ボタンはどれか?押せない状態や処理中の表示でも、そのボタンの操作で答える。", }, "has_modal": { "en": "Is a modal (alert, dialog, action sheet, or sheet) presented over the content? A sheet counts at any height.", "ja": "コンテンツの上にモーダル(アラート・ダイアログ・アクションシート・シート)が表示されているか?シートは高さに関係なく含む。", }, "has_destructive_action": { "en": "Is a destructive action (e.g. a red Delete/Discard button) visible? Cancel and Close do not count.", "ja": "破壊的な操作(赤い削除・破棄ボタンなど)が表示されているか?キャンセルや閉じるは含まない。", }, "is_empty": { "en": "Does the main content show an empty state (no items or no results)? Loading spinners, skeleton placeholders and empty input fields are not an empty state.", "ja": "メインコンテンツが空の状態(項目なし・結果なし)か?読み込み中の表示やスケルトン、未入力の入力欄は空の状態ではない。", }, } SCREEN_CRITERIA = { "loading": "The whole content is replaced by a loading spinner, progress or skeleton (a saving button does not count) / 画面全体が読み込み中", "offline": "The whole content is replaced by an offline / no connection screen (a banner does not count) / 画面全体がオフライン表示", "home": "A normal home/list screen; banners or toasts may be shown on it / 通常のホーム・一覧画面(バナーやトーストがあってもよい)", "form": "A full-screen data-entry form (checkout, profile, transfer ...), not inside a sheet / 全画面の入力フォーム", "sheet": "A sheet presented over the content, whatever it contains (form, filters ...) / シート(中身がフォームでもシート)", } def main(src, dst): n = 0 with open(src, encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as out: for line in f: if not line.strip(): continue r = json.loads(line) lang = "ja" if r["meta"].get("lang") == "ja" else "en" for qid, text in INSTR.items(): if qid in r["questions"]: r["questions"][qid]["instructions"] = text[lang] crit = r["questions"]["screen"]["criteria"] for k, v in SCREEN_CRITERIA.items(): if k in crit: crit[k] = v r["meta"]["question_version"] = "q2" out.write(json.dumps(r, ensure_ascii=False) + "\n") n += 1 print(f"{n} records -> {dst}") if __name__ == "__main__": main(sys.argv[1], sys.argv[2])