ai_member_xiaoyan/scripts/fill_speaking_expl.py

214 lines
18 KiB
Python

#!/usr/bin/env python3
"""Generate explanations for 171 empty speaking-P1 questions, then write back."""
import json, requests, time
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
APP_ID = "cli_a931175d41799cc7"
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
TABLE = "tblRGv7k4WH58Jgq"
def get_token():
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=10)
return r.json()["tenant_access_token"]
# ── Explanation generator ──
# Map ability → template function that takes (question_content, ability_list) → explanation
def gen_expl(q, abilities):
"""Generate a natural Chinese explanation for a speaking question."""
content = q.get('content', '') or q.get('question', '')
ab = abilities[0] if abilities else '通用问答'
# ── Pattern-based explanations ──
# 基础信息表达|个人信息问答
if '个人信息' in ab:
if 'name' in content.lower() or "what's your name" in content.lower():
return "本题考察基础个人信息表达能力。回答时直接说出自己的名字,如 'My name is Tom.' 注意使用完整的介绍句式,发音清晰。"
if 'old' in content.lower() and 'how' in content.lower():
return "本题考察年龄表达。回答时用 'I am ... years old.' 的句式,说清楚数字。也可以补充生日信息使回答更丰富。"
if 'from' in content.lower():
return "本题考察国籍与家乡表达。回答时用 'I am from ...''I come from ...' 的句式,可以说国家或城市名称。"
if 'live' in content.lower():
return "本题考察家庭生活信息表达。回答时用 'I live with my ...' 描述同住的家人。注意家庭成员词汇的准确使用。"
if 'hair' in content.lower() or 'look like' in content.lower() or 'wearing' in content.lower() or 'favourite clothes' in content.lower():
return "本题考察人物外貌与穿着描述能力。回答时使用 'He/She has...' 描述发型发色,用 'He/She is wearing...' 描述衣着,注意颜色和衣物词汇的准确使用。"
if 'schoolbag' in content.lower() or 'in your' in content.lower() and ('schoolbag' in content.lower() or 'desk' in content.lower() or 'classroom' in content.lower()):
return "本题考察物品列举与位置描述能力。回答时使用 'There is/are ... in my ...' 句式,逐一说出物品名称,注意单复数一致。"
if 'tall' in content.lower():
return "本题考察比较级描述能力。回答时使用 '... is taller than me.' 的句式,说出比你高的人的名字。注意比较级的正确使用。"
if 'dinosaur' in content.lower() or 'cloud' in content.lower() or 'moon' in content.lower():
return "本题考察想象与外观描述能力。回答时使用形容词描述事物的样子,如 'It is big and green.''It looks like ...',发挥想象力用英语表达。"
if 'pet' in content.lower() and ('love' in content.lower() or 'like' in content.lower()):
return "本题考察宠物喜好表达。回答时说出你喜欢的宠物,如 'I love dogs.' 并尝试说明喜欢的原因。注意动物名称词汇的准确使用。"
if 'toy' in content.lower() or 'toys' in content.lower():
return "本题考察个人物品表达。回答时列举你拥有的玩具,用 'I have ...' 句式。注意玩具词汇和复数形式的正确使用。"
if 'book' in content.lower() and 'where' in content.lower():
return "本题考察物品位置表达。回答时使用方位介词描述书的位置,如 'It is on the desk.''It is in my schoolbag.'"
if 'pen' in content.lower() and 'yours' in content.lower():
return "本题考察物品归属表达。肯定回答用 'Yes, it is mine.',否定回答用 'No, it is not mine.' 注意物主代词的区分。"
if 'goal' in content.lower():
return "本题考察目标与计划表达能力。回答时说出本学期的目标,如 'My goal is to read 10 English books.' 注意使用完整句子表达决心。"
if 'keep healthy' in content.lower() or 'health' in content.lower():
return "本题考察健康建议表达能力。回答时列举保持健康的方法,如 'We can eat vegetables and exercise every day.' 注意使用情态动词 can/should。"
# fallback for 个人信息
return f"本题考察基础个人信息表达能力。回答时需要围绕「{content[:20]}」这个主题用完整的英语句子进行描述或说明,注意信息清晰、表达自然。"
# 表达喜好与理由
if '喜好' in ab:
if 'favorite' in content.lower() or 'favourite' in content.lower():
return "本题考察喜好表达与理由说明能力。回答时先明确说出喜好选择,如 'My favorite ... is ...',然后用 'because''I like it because...' 说明理由。"
if 'like' in content.lower() and 'music' in content.lower():
return "本题考察音乐喜好表达。回答时说出你喜欢的音乐类型,如 'I like pop music.' 再说明原因如 'because it makes me happy.' 也可以举一首喜欢的歌为例。"
if 'like' in content.lower() and 'read' in content.lower():
return "本题考察阅读喜好表达。回答时说明你喜欢读什么类型的书,如 'I like story books.' 并补充阅读的感受或最喜欢的书籍。"
if 'like' in content.lower() and 'internet' in content.lower():
return "本题考察网络活动喜好表达。回答时说出你在网上喜欢做什么,如 'I like watching videos and playing games online.' 用 and 连接多项活动。"
if 'like' in content.lower() and 'cat' in content.lower():
return "本题考察原因解释能力。回答时用 'because' 引出原因,如 'I like cats because they are cute and soft.' 至少给出一个具体理由。"
if 'hobby' in content.lower():
return "本题考察爱好表达。回答时说出你的爱好,如 'My hobby is drawing.''I like playing football.' 可以补充做这个爱好的频率和感受。"
if 'think of' in content.lower() or 'think about' in content.lower():
return "本题考察观点表达能力。回答时用 'I think ...' 开头表达你的看法,然后简单说明原因。鼓励表达真实想法而不仅仅是正确回答。"
if 'plan' in content.lower() or 'going to' in content.lower():
return "本题考察未来计划表达能力。回答时用 'I plan to ...''I am going to ...' 的句式描述计划,注意将来时的正确使用。"
if 'want to' in content.lower() and 'do' in content.lower():
return "本题考察意愿与计划表达。回答时用 'I want to ...' 表达你想做的事,如果涉及周末计划可用 'I am going to ...'"
if 'dad' in content.lower() and ('unhappy' in content.lower() or 'say' in content.lower()):
return "本题考察家庭情感与沟通表达。回答时描述爸爸的言行或情绪,如 'He said I should finish my homework first.' 注意引述和描述的准确性。"
if 'happy' in content.lower() or 'glad' in content.lower():
return "本题考察积极情感表达能力。回答时用 'I am happy/glad that ...' 的句式表达喜悦,并具体说出让你开心的事情。"
if 'afraid' in content.lower():
return "本题考察恐惧情感表达能力。回答时用 'I am afraid of ...' 说出害怕的动物或事物,可以简单说明原因如 'because it is scary.'"
if 'need' in content.lower() or 'need to do' in content.lower():
return "本题考察需求表达能力。回答时用 'I need to ...''We need ...' 说明需要做的事情或物品。注意 need 后接动词原形或名词。"
if 'colour' in content.lower() or 'color' in content.lower():
return "本题考察颜色偏好表达。回答时说出你想要的颜色,如 'I want the picture in blue.''I like red best.' 可以补充为什么喜欢这个颜色。"
if 'whose' in content.lower():
return "本题考察物品归属判断与表达。回答时用 'I think it is ...'s.''It might be ...' 的句式表达推断。注意名词所有格的正确使用。"
if 'exam' in content.lower():
return "本题考察学习准备与计划表达。回答时列举考前需做的事,如 'I need to review my notes and do more practice.' 注意使用 need to 表达必要性。"
if 'wrong' in content.lower() and 'radio' in content.lower():
return "本题考察推断与猜测表达能力。回答时用 'Maybe it is ...''It might be ...' 表达对故障原因的推测。注意情态动词 might/maybe 的使用。"
return f"本题考察表达喜好与理由的能力。回答时先表明喜好态度或观点,再用 'because' 等连接词说明理由,注意使用完整的英语句子。"
# 互动应答|问答交流
if '互动应答' in ab or '问答交流' in ab:
if 'help' in content.lower() and 'say' in content.lower():
return "本题考察礼貌应答能力。回答时给出得体的感谢用语,如 'Thank you so much!''That's very kind of you.' 注意感谢的真诚性表达。"
if 'sorry' in content.lower() or 'lose' in content.lower() and 'book' in content.lower():
return "本题考察道歉表达与情境应对。回答时用诚恳的道歉语如 'I am so sorry. I will help you find it.' 同时给出弥补方案,体现责任感。"
if 'library' in content.lower() and 'should' in content.lower():
return "本题考察规则表达能力。回答时使用情态动词如 'We shouldn't talk loudly.''We must be quiet.' 表达图书馆的行为规范。"
if 'park' in content.lower() and ('must' in content.lower() or 'should' in content.lower()):
return "本题考察规则与义务表达能力。回答时用 'We must not ...' 表达禁止行为,如 'We must not pick flowers or litter.' 注意 must 的使用。"
if 'ill' in content.lower() or 'sad' in content.lower():
return "本题考察共情与关怀表达能力。回答时说出关怀的话语,如 'I hope you feel better soon.''Don't be sad, let me help you.' 体现同理心。"
if 'leave' in content.lower():
return "本题考察礼貌告别用语。回答时说出得体的道别方式,如 'Goodbye!''See you later!' 也可以说 'It was nice meeting you.'"
if 'friend comes' in content.lower() or 'friend came' in content.lower() or 'come to your home' in content.lower():
return "本题考察接待与欢迎表达能力。回答时说出欢迎用语,如 'Welcome! Come in, please.''I'm so glad you came!' 注意热情友好的语气。"
if 'introduce' in content.lower():
return "本题考察介绍他人的能力。回答时使用 'This is my friend ...' 的句式介绍朋友,可以说出对方的名字和一两个特点。"
if 'shop' in content.lower() or 'shopping' in content.lower():
return "本题考察购物场景交流能力。回答时模拟店员用语如 'Can I help you?''What would you like to buy?' 注意服务场景的礼貌表达。"
if 'swim' in content.lower() or 'sports' in content.lower():
return "本题考察能力询问与应答。肯定回答用 'Yes, I can swim.',否定回答用 'No, I can't swim.' 或补充 'But I can run fast.'"
if 'can you help' in content.lower():
return "本题考察请求帮助的表达与应答。回答时可以表示愿意帮助 'Sure, I will help you.' 或说明无法帮助的原因 'Sorry, my hands are full.'"
if 'say when' in content.lower() and 'can' in content.lower() and 'find' in content.lower():
return "本题考察失物求助表达。回答时说出寻找物品的请求语,如 'I can't find my pen. Can you help me?''Have you seen my pen?'"
if 'say when' in content.lower() and 'ruler' in content.lower():
return "本题考察借物请求表达。回答时说出礼貌的借物请求,如 'May I borrow your ruler, please?' 注意使用 May I 或 Can I 的礼貌表达。"
if 'draw' in content.lower() and 'together' in content.lower():
return "本题考察邀请与提议表达能力。回答时使用 'Let's draw together!''Shall we draw a picture?' 表达邀请,语气友好自然。"
if 'loud' in content.lower():
return "本题考察请求与协商表达能力。回答时礼貌地提出降低音量的请求,如 'Could you please turn it down?''It's a bit too loud.' 注意礼貌用语。"
if 'rabbit' in content.lower() and 'eat' in content.lower():
return "本题考察观察与描述应答。回答时描述兔子正在吃什么,如 'The rabbit is eating a carrot.' 注意现在进行时的正确使用。"
if 'see in the sky' in content.lower():
return "本题考察观察与描述应答。回答时描述天空中看到的事物,如 'I can see some birds and clouds.''I can see the sun.' 注意自然观察词汇。"
if 'page' in content.lower():
return "本题考察课堂指令应答能力。回答时说出应该翻到的页码,如 'Let's turn to page 10.''Please turn to page 10.'"
if 'animal' in content.lower() and 'look at' in content.lower():
return "本题考察选择与提议应答。回答时提出想看的动物,如 'Let's look at the elephants.''I want to see the monkeys.'"
if 'car' in content.lower() and 'faster' in content.lower():
return "本题考察比较与判断应答。回答时使用比较级说出哪辆车更快,如 'The red car is faster.' 注意比较级 -er 或 more 的使用。"
if 'gift' in content.lower() or 'present' in content.lower():
return "本题考察礼物相关表达能力。回答时描述想要的礼物或礼物送给谁,如 'I want a toy car for my birthday.''This gift is for my mum.'"
if 'picnic' in content.lower():
return "本题考察准备与计划描述能力。回答时列举野餐需要带的东西,如 'We need some sandwiches, fruit and drinks for the picnic.' 注意物品词汇的准确使用。"
return f"本题考察互动应答能力。回答时需要根据「{content[:20]}」的情境,给出得体的英文回应,注意使用礼貌用语和完整句子。"
# 信息交换|双向问答
if '信息交换' in ab:
if 'lunch' in content.lower() or 'eat' in content.lower():
return "本题考察饮食内容交流能力。回答时用 'Let's have ...' 提出午餐建议,或说出想吃的食物。注意食物名称词汇的准确使用,可以说明选择理由使交流更自然。"
return "本题考察信息交换与双向交流能力。回答时不仅给出自己的答案,还可以反问对方以延续对话,注意问答之间的自然过渡和对话的互动性。"
# 过去经历描述
if '过去经历' in ab or 'Past' in ab:
if 'see' in content.lower() and ('park' in content.lower() or 'weekend' in content.lower()):
return "本题考察过去经历描述能力。回答时使用过去时描述你在公园看到的事物,如 'I saw many beautiful flowers and some ducks in the pond.' 注意过去式动词的正确使用。"
if 'help' in content.lower():
return "本题考察过去行为描述能力。回答时说出你帮助了谁以及怎么帮的,如 'I helped my mum clean the house.' 注意 help 后接动词原形。"
if 'weekend' in content.lower():
return "本题考察过去活动描述能力。回答时描述周末发生的事情,用过去时讲述活动和感受,如 'Last weekend, I went to the zoo with my family.'"
return f"本题考察过去经历描述能力。回答时使用过去时态描述「{content[:20]}」相关经历,注意动词过去式的变化,包含时间、地点和感受。"
# Fallback
return f"本题考察英语口语应答能力。请围绕「{content[:30]}」用完整句子进行回答,注意发音清晰、语法正确、表达自然。"
# ── Main ──
def main():
token = get_token()
print("Token OK")
with open('/root/.openclaw/workspace-xiaoyan/tmp/empty_expl_data.json') as f:
records = json.load(f)
print(f"Processing {len(records)} records, 171 questions...")
updated = 0
for rec in records:
rid = rec['rid']
jd = rec['jd']
qsid = rec['qsid']
modified = False
for bn in ['first', 'second']:
block = jd.get(bn, {})
if not block:
continue
qs = block.get('questionSet', [])
for qi, q in enumerate(qs):
expl = q.get('explanation', '')
if expl == 'PATCH' or not expl or len(expl.strip()) < 5:
abilities = q.get('ability', [])
new_expl = gen_expl(q, abilities)
q['explanation'] = new_expl
modified = True
updated += 1
if modified:
# Write back
new_jd_str = json.dumps(jd, ensure_ascii=False)
r = requests.put(
f'https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE}/records/{rid}',
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'},
json={'fields': {'jsonData': new_jd_str}}, timeout=15)
code = r.json().get('code')
if code == 0:
print(f'{qsid} ({rid[:12]}...)')
else:
print(f'{qsid}: {r.json().get("msg")}')
time.sleep(0.25)
print(f'\nDone: {updated} explanations generated across {len(records)} records')
if __name__ == '__main__':
main()