File size: 3,956 Bytes
e379257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Rewrite the question texts of a gallery JSONL to the q3 wording.



q3 = q2 wording (scripts/make_q2.py, kept unchanged so q2 artifacts stay reproducible)

     + loading overlay / spinner is NOT a modal (has_modal, screen instructions + criteria)

     + primary_button: loading overlay without actionable button -> none;

       destructive row inside a settings list is not the primary button.

Gold is NOT touched here (see scripts/fix_settings_gold.py).



usage: python scripts/make_q3.py in.jsonl out.jsonl

"""
import json, os, sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from make_q2 import INSTR as Q2_INSTR, SCREEN_CRITERIA as Q2_SCREEN_CRITERIA

# Sentences appended to the q2 instructions (per language).
INSTR_APPEND = {
    "screen": {
        "en": "A full-screen or inline loading overlay or spinner is not a modal (not a dialog or sheet).",
        "ja": "全画面またはインラインのローディングオーバーレイやスピナーはモーダル(ダイアログやシート)ではありません。",
    },
    "has_modal": {
        "en": "A full-screen or inline loading overlay or spinner is NOT a modal: answer no for it.",
        "ja": "全画面またはインラインのローディングオーバーレイやスピナーはモーダルではありません。その場合は「いいえ」と答えてください。",
    },
    "primary_button": {
        "en": "A loading overlay with no actionable button means none. A destructive row inside a settings list (e.g. Delete Account) is not the primary button.",
        "ja": "操作できるボタンのないローディングオーバーレイは「none」です。設定画面のリスト内にある破壊的な行(アカウント削除など)は主要ボタンではありません。",
    },
}
# (en, ja) appended to the bilingual "en / ja" screen criteria.
CRITERIA_APPEND = {
    "loading": ("A full-screen loading overlay or spinner is loading, not a modal or sheet.",
                "全画面のローディングオーバーレイやスピナーもこれ(モーダルやシートではない)"),
    "sheet": ("A loading overlay or spinner is not a sheet.",
              "ローディングオーバーレイやスピナーはシートではない"),
}


def q3_instr(qid, lang):
    base = Q2_INSTR[qid][lang]
    add = INSTR_APPEND.get(qid, {}).get(lang)
    if not add:
        return base
    return base + ("" if lang == "ja" else " ") + add


def q3_criterion(key):
    base = Q2_SCREEN_CRITERIA[key]
    if key not in CRITERIA_APPEND:
        return base
    en, ja = base.rsplit(" / ", 1)
    add_en, add_ja = CRITERIA_APPEND[key]
    return f"{en}. {add_en} / {ja}。{add_ja}"


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 in Q2_INSTR:
                if qid in r["questions"]:
                    r["questions"][qid]["instructions"] = q3_instr(qid, lang)
            crit = r["questions"]["screen"]["criteria"]
            for k in Q2_SCREEN_CRITERIA:
                if k in crit:
                    crit[k] = q3_criterion(k)
            r["meta"]["question_version"] = "q3"
            out.write(json.dumps(r, ensure_ascii=False) + "\n")
            n += 1
    print(f"{n} records -> {dst}")


if __name__ == "__main__":
    if len(sys.argv) == 2 and sys.argv[1] == "--show":
        for q in INSTR_APPEND:
            for l in ("en", "ja"):
                print(f"[{q}/{l}] {q3_instr(q, l)}")
        for k in CRITERIA_APPEND:
            print(f"[criteria/{k}] {q3_criterion(k)}")
    else:
        main(sys.argv[1], sys.argv[2])