ai_member_xiaoyan/scripts/write_p4_safe.py

176 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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()