176 lines
6.3 KiB
Python
176 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
P4 rewrite with automation-safe approach:
|
||
- jsonData: use ability=['听觉抓取关键信息'], explanation='' (automation-compatible)
|
||
- 题目1/题目2: include full ability + explanation info in text
|
||
"""
|
||
import json, subprocess, sys, os, time
|
||
|
||
AT = "CMHSbUUjka3TrUsaxxEc297ongf"
|
||
TID = "tblVmeDtBDKsAEfz"
|
||
BASE = os.path.expanduser("~/.openclaw/workspace-xiaoyan")
|
||
CRED_FILE = os.path.expanduser("~/.openclaw/credentials/xiaoyan/config.json")
|
||
|
||
sys.path.insert(0, os.path.join(BASE, "scripts"))
|
||
import rewrite_p4_all as rw
|
||
|
||
RECORD_IDS = {
|
||
"021301": "recvjufKJO8d0O",
|
||
"021401": "recvjufM763ijb",
|
||
"021501": "recvjufM76lEsW",
|
||
"021601": "recvjufM76hNv5",
|
||
"021701": "recvjufM76eMKs",
|
||
"021801": "recvjufM76lRHQ",
|
||
"022101": "recvjufM76o6of",
|
||
"032501": "recvjufM76k4dx",
|
||
"032901": "recvjufM76frUP",
|
||
}
|
||
|
||
def get_token():
|
||
with open(CRED_FILE) as f:
|
||
cred = json.load(f)
|
||
app_id = cred["apps"][0]["appId"]
|
||
app_secret = cred["apps"][0]["appSecret"]
|
||
r = subprocess.run(["curl","-s","-X","POST",
|
||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||
"-H","Content-Type: application/json",
|
||
"-d",json.dumps({"app_id":app_id,"app_secret":app_secret})],
|
||
capture_output=True, text=True)
|
||
return json.loads(r.stdout)["tenant_access_token"]
|
||
|
||
def make_qtext_with_info(questions):
|
||
"""Generate 题目 text with dialogue, ability and explanation info"""
|
||
lines = []
|
||
for i, q in enumerate(questions, 1):
|
||
lines.append(f"{i}.")
|
||
lines.append(f"【描述】{q.get('questionDesc','')}")
|
||
lines.append(f"【听力文本】")
|
||
if 'dialogue' in q:
|
||
lines.append(q['dialogue'])
|
||
lines.append(f"【题目】")
|
||
lines.append(q['question'])
|
||
for j, opt in enumerate(q.get('options',[])):
|
||
marker = "(正确)" if j == q.get('answer',[-1])[0] else ""
|
||
lines.append(f"{chr(65+j)}. {opt}{marker}")
|
||
# Add ability info
|
||
ability = q.get('new_ability', q.get('ability', ['听力理解']))
|
||
lines.append(f"【能力标签】{'|'.join(ability) if isinstance(ability,list) else ability}")
|
||
# Add explanation
|
||
lines.append(f"【解析】{q.get('explanation','')}")
|
||
lines.append("")
|
||
return "\n".join(lines)
|
||
|
||
def sanitize_json(json_data):
|
||
"""Replace ability/explanation with automation-safe values"""
|
||
for qs in json_data.get("first", {}).get("questionSet", []):
|
||
qs["ability"] = ["听觉抓取关键信息"]
|
||
qs["explanation"] = ""
|
||
second = json_data.get("second", {})
|
||
if second and isinstance(second, dict) and "questionSet" in second:
|
||
for qs in second.get("questionSet", []):
|
||
qs["ability"] = ["听觉抓取关键信息"]
|
||
qs["explanation"] = ""
|
||
return json_data
|
||
|
||
def write_one(token, qsid, record_id, json_data, q1_text, q2_text):
|
||
"""Write one record and verify"""
|
||
json_str = json.dumps(json_data, ensure_ascii=False)
|
||
fields = {"jsonData": json_str, "题目1": q1_text, "题目2": q2_text}
|
||
payload = json.dumps({"fields": fields}, ensure_ascii=False)
|
||
|
||
tmp = f"/tmp/p4_safe_{record_id}.json"
|
||
with open(tmp, "w") as f:
|
||
f.write(payload)
|
||
|
||
r = subprocess.run(["curl","-s","-X","PUT",
|
||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{AT}/tables/{TID}/records/{record_id}",
|
||
"-H",f"Authorization: Bearer {token}",
|
||
"-H","Content-Type: application/json",
|
||
"-d",f"@{tmp}"],
|
||
capture_output=True, text=True, timeout=30)
|
||
os.remove(tmp)
|
||
|
||
resp = json.loads(r.stdout)
|
||
if resp.get("code") != 0:
|
||
return False, f"API error: {resp.get('msg','')}"
|
||
|
||
# Verify
|
||
r = subprocess.run(["curl","-s","-X","GET",
|
||
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{AT}/tables/{TID}/records/{record_id}",
|
||
"-H",f"Authorization: Bearer {token}"],
|
||
capture_output=True, text=True, timeout=30)
|
||
vdata = json.loads(r.stdout)
|
||
if vdata.get("code") != 0:
|
||
return False, f"Verify error: {vdata.get('msg','')}"
|
||
|
||
rec = vdata.get("data",{}).get("record",{})
|
||
jd = rec.get("fields",{}).get("jsonData","")
|
||
q1 = rec.get("fields",{}).get("题目1","") or ""
|
||
|
||
if not jd:
|
||
return False, "jsonData empty"
|
||
|
||
try:
|
||
parsed = json.loads(jd)
|
||
fqs = parsed.get("first",{}).get("questionSet",[])
|
||
if not fqs:
|
||
return False, "no first questions"
|
||
q0_question = fqs[0].get("question","")
|
||
q0_ability = fqs[0].get("ability","")
|
||
return True, f"Qs={len(fqs)}, q0='{q0_question[:30]}', ability={q0_ability}, Q1_len={len(q1)}"
|
||
except Exception as e:
|
||
return False, f"parse: {e}"
|
||
|
||
def main():
|
||
token = get_token()
|
||
print(f"Token: {token[:15]}...")
|
||
results = []
|
||
|
||
for qsid, record_id in RECORD_IDS.items():
|
||
data = rw.RECORD_DATA.get(qsid)
|
||
if not data:
|
||
continue
|
||
|
||
fb = data["first_block"]
|
||
sb = data["second_block"]
|
||
fqs = data["first_qs_list"]
|
||
sqs = data["second_qs_list"]
|
||
|
||
# Build jsonData - keep original dialogue but not in final jsonData
|
||
json_data = {"first": fb, "second": sb}
|
||
|
||
# Build Q1/Q2 text with full info
|
||
q1_text = make_qtext_with_info(fqs)
|
||
q2_text = make_qtext_with_info(sqs) if sqs else ""
|
||
|
||
# Clean dialogues from jsonData and sanitize
|
||
for q in fb["questionSet"]:
|
||
q.pop("dialogue", None)
|
||
q.pop("new_ability", None)
|
||
if sb and isinstance(sb, dict) and "questionSet" in sb:
|
||
for q in sb["questionSet"]:
|
||
q.pop("dialogue", None)
|
||
q.pop("new_ability", None)
|
||
|
||
json_data = sanitize_json(json_data)
|
||
|
||
print(f"\nWriting {qsid} ({record_id})...")
|
||
ok, msg = write_one(token, qsid, record_id, json_data, q1_text, q2_text)
|
||
status = "✅" if ok else "❌"
|
||
print(f" {status} {msg}")
|
||
results.append((qsid, ok, msg))
|
||
time.sleep(0.5)
|
||
|
||
success = sum(1 for r in results if r[1])
|
||
fails = sum(1 for r in results if not r[1])
|
||
print(f"\n{'='*60}")
|
||
print(f"FINAL: {success} succeeded, {fails} failed")
|
||
|
||
if fails:
|
||
for qsid, ok, msg in results:
|
||
if not ok:
|
||
print(f" ❌ {qsid}: {msg}")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|