445 lines
9.7 KiB
Python
445 lines
9.7 KiB
Python
#!/usr/bin/env python3
|
||
"""Generate component configurations for the script sheet and write them back."""
|
||
|
||
import json
|
||
import subprocess
|
||
import sys
|
||
|
||
# Get bot token
|
||
def get_token():
|
||
result = subprocess.run(
|
||
["jq", "-r", ".apps[0].appSecret",
|
||
"/root/.openclaw/credentials/xiaoyan/config.json"],
|
||
capture_output=True, text=True
|
||
)
|
||
app_secret = result.stdout.strip()
|
||
|
||
import urllib.request
|
||
import urllib.parse
|
||
data = json.dumps({"app_id": "cli_a931175d41799cc7", "app_secret": app_secret}).encode()
|
||
req = urllib.request.Request(
|
||
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||
data=data,
|
||
headers={"Content-Type": "application/json"}
|
||
)
|
||
resp = json.loads(urllib.request.urlopen(req).read())
|
||
return resp["tenant_access_token"]
|
||
|
||
TOKEN = get_token()
|
||
SPREADSHEET_TOKEN = "Dk1fs7TJ4hWs5PtUvXlc1EaEnvb"
|
||
SHEET_ID = "fmqYrx"
|
||
|
||
# Component configurations for each row
|
||
# Format: {row_number: config_text}
|
||
|
||
CONFIGS = {
|
||
# Row 12: 图片无序多选 (1217101) - motorbike
|
||
12: """【任务标题】
|
||
在图片中寻找摩托车
|
||
|
||
【情境引入】
|
||
Ben: Whoa! Those are motorbikes!
|
||
User: Where? Let me take a look.
|
||
|
||
【互动内容】
|
||
Find the $motorbikes$ in the picture.(音频)
|
||
选项:
|
||
00
|
||
01
|
||
02
|
||
答案:
|
||
00
|
||
01
|
||
辅助信息:motorbike 指"摩托车"。
|
||
|
||
【互动反馈】
|
||
正确 Ben : That's right! Those are two motorbikes!
|
||
错误 Ben : Look again. Can you find the motorbikes?
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 30: 对话朗读 (1217102) - people
|
||
30: """【任务标题】
|
||
询问那些人是谁
|
||
|
||
【资源配置】
|
||
图片时机:无
|
||
|
||
【情境引入】
|
||
无
|
||
|
||
【互动内容】
|
||
Who are those people?(朗读)
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 46: 对话挖空 (1217103) - people
|
||
46: """【任务标题】
|
||
向镇长报告发现
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
User: Tom! We found two strange people.
|
||
|
||
【互动内容】
|
||
We found two strange ___.(音频)
|
||
选项1:people(正确)
|
||
选项2:animals
|
||
|
||
【互动反馈】
|
||
正确 Tom : Good! Tell me more about them.
|
||
错误 Tom : Animals? Are you sure about that?
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 53: 对话挖空 (1217104) - motorbike
|
||
53: """【任务标题】
|
||
描述可疑人员的特征
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Tom: Tell me more about them.
|
||
|
||
【互动内容】
|
||
They're on ___.(音频)
|
||
选项1:motorbikes(正确)
|
||
选项2:bicycles
|
||
|
||
【互动反馈】
|
||
正确 Tom : Good job! I'm coming right now!
|
||
错误 Tom : Bicycles? That doesn't sound right.
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 67: 对话朗读 (1217105) - people
|
||
67: """【任务标题】
|
||
盘问来人身份
|
||
|
||
【资源配置】
|
||
图片时机:无
|
||
|
||
【情境引入】
|
||
无
|
||
|
||
【互动内容】
|
||
Who are you people?(朗读)
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 81: 对话挖空 (1217106) - show
|
||
81: """【任务标题】
|
||
要求检查袋子
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Jay: The bag is a secret!
|
||
|
||
【互动内容】
|
||
You must ___ me what is in the bag!(音频)
|
||
选项1:show(正确)
|
||
选项2:tell
|
||
|
||
【互动反馈】
|
||
正确 Jay : No, no! We can't show you!
|
||
错误 Jay : Ha! We won't tell you, either!
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 96: 对话选择 (1217107) - motorbike
|
||
96: """【任务标题】
|
||
回应 Jay 的炫耀
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Jay: Let me show you how fast it is!
|
||
|
||
【互动内容】
|
||
要求:选择正确的回复
|
||
选项:(音频)
|
||
选项1:Your motorbike looks really old.(正确)
|
||
- 反馈: 无
|
||
选项2:Your motorbike looks so cool!
|
||
- 反馈 Jay : Thank you, kid! But let me show you more!
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 110: 对话朗读 (1217108) - Show...
|
||
110: """【任务标题】
|
||
要求 Jay 继续展示
|
||
|
||
【资源配置】
|
||
图片时机:无
|
||
|
||
【情境引入】
|
||
无
|
||
|
||
【互动内容】
|
||
Wow! Show me more!(朗读)
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 122: 对话组句 (1217109) - Show...
|
||
122: """【任务标题】
|
||
请 Lin 展示摩托车
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Lin: My motorbike never does that.
|
||
|
||
【互动内容】
|
||
题目:请 Lin 展示她的摩托车
|
||
(音频)
|
||
选项1:Cool
|
||
选项2:Show
|
||
选项3:me
|
||
选项4:your
|
||
选项5:motorbike
|
||
答案:Cool! Show me your motorbike!
|
||
辅助信息:Cool 作感叹词放句首;Show me 后接名词表示"给我看看..."。
|
||
|
||
【互动反馈】
|
||
正确 Lin : Hmph. Fine.
|
||
错误 Lin : What do you want me to show?
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 142: 对话选读 (1217110) - motorbike
|
||
142: """【任务标题】
|
||
评价谁的摩托车更好
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Jay: Hey kids! Which motorbike is better?
|
||
|
||
【互动内容】
|
||
要求:选择一个你想表达的观点
|
||
选项:
|
||
选项1:I think the red motorbike is better.
|
||
- 反馈 Jay : What? I don't agree!
|
||
选项2:I think the orange motorbike is better.
|
||
- 反馈 Lin : Hey! You're wrong!
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 161: 对话朗读 (1217111) - ... can/can't hold...
|
||
161: """【任务标题】
|
||
答应帮忙拿袋子
|
||
|
||
【资源配置】
|
||
图片时机:无
|
||
|
||
【情境引入】
|
||
无
|
||
|
||
【互动内容】
|
||
Okay! I can hold it.(朗读)
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 176: 对话选择 (1217112) - ... can/can't hold...
|
||
176: """【任务标题】
|
||
回应 Ben 的关心
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Ben: Are you okay?
|
||
|
||
【互动内容】
|
||
要求:选择正确的回复
|
||
选项:(音频)
|
||
选项1:Don't worry. I can hold it.(正确)
|
||
- 反馈: 无
|
||
选项2:Help! I can't hold it!
|
||
- 反馈 Ben : Oh no! Let me help you!
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 192: 对话组句 (1217113) - ... can/can't hold...
|
||
192: """【任务标题】
|
||
让 Ben 放心你能拿住
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Ben: Let's see what's inside.
|
||
|
||
【互动内容】
|
||
题目:告诉 Ben 你能拿住袋子,让他放心
|
||
(音频)
|
||
选项1:Don't
|
||
选项2:worry
|
||
选项3:I
|
||
选项4:can
|
||
选项5:hold
|
||
选项6:it
|
||
答案:Don't worry. I can hold it.
|
||
辅助信息:Don't worry 表示"别担心";can 后跟动词原形表示"能/会"。
|
||
|
||
【互动反馈】
|
||
正确 Ben : Ouch!
|
||
错误 Ben : What? Are you okay?
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 204: 对话朗读 (1217114) - ... can/can't hold...
|
||
204: """【任务标题】
|
||
呼救求助
|
||
|
||
【资源配置】
|
||
图片时机:无
|
||
|
||
【情境引入】
|
||
无
|
||
|
||
【互动内容】
|
||
I can't hold it!(朗读)
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 233: 阅读理解 (1217115) - motorbike/people/hold/show
|
||
233: """【任务标题】
|
||
向 Tom 描述事情的经过
|
||
|
||
【情境引入】
|
||
Tom: Can anybody tell me what happened here?
|
||
|
||
【互动内容】
|
||
问题1:Who came from out of town?
|
||
答案:These two people.
|
||
|
||
问题2:What did they ride?
|
||
答案:They ride motorbikes.
|
||
|
||
问题3:What did you ask them to do?
|
||
答案:Show us what's in their bags.
|
||
|
||
【后置对话】
|
||
无""",
|
||
|
||
# Row 245: 对话选读 (1217116) - ... can/can't hold...
|
||
245: """【任务标题】
|
||
为自己的失误道歉
|
||
|
||
【资源配置】
|
||
无
|
||
|
||
【情境引入】
|
||
Lin: And you opened the bags without asking.
|
||
|
||
【互动内容】
|
||
要求:选择一个你想表达的观点
|
||
选项:
|
||
选项1:Sorry, but I can't hold it.
|
||
- 反馈 Tom : It's okay. Everybody makes mistakes.
|
||
选项2:Sorry, I can't hold it anymore.
|
||
- 反馈 Tom : It's okay. Everybody makes mistakes.
|
||
|
||
【后置对话】
|
||
无""",
|
||
}
|
||
|
||
|
||
def write_to_sheet(row, config_text):
|
||
"""Write config to a single cell in the sheet."""
|
||
import urllib.request
|
||
|
||
range_str = f"{SHEET_ID}!H{row}:H{row}"
|
||
data = json.dumps({
|
||
"valueRange": {
|
||
"range": range_str,
|
||
"values": [[config_text]]
|
||
}
|
||
}).encode()
|
||
|
||
req = urllib.request.Request(
|
||
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values",
|
||
data=data,
|
||
headers={
|
||
"Authorization": f"Bearer {TOKEN}",
|
||
"Content-Type": "application/json"
|
||
},
|
||
method="PUT"
|
||
)
|
||
resp = json.loads(urllib.request.urlopen(req).read())
|
||
return resp.get("code") == 0
|
||
|
||
|
||
def verify_write(row, expected_prefix):
|
||
"""Verify what was written."""
|
||
import urllib.request
|
||
range_str = f"{SHEET_ID}!H{row}:H{row}"
|
||
url = f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{SPREADSHEET_TOKEN}/values/{range_str}?valueRenderOption=ToString"
|
||
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {TOKEN}"})
|
||
resp = json.loads(urllib.request.urlopen(req).read())
|
||
values = resp.get("data", {}).get("valueRange", {}).get("values", [])
|
||
if values and values[0] and values[0][0]:
|
||
actual = values[0][0]
|
||
if actual.startswith(expected_prefix):
|
||
return True, actual[:80]
|
||
else:
|
||
return False, actual[:80]
|
||
return False, "EMPTY"
|
||
|
||
|
||
def main():
|
||
success = 0
|
||
failed = []
|
||
|
||
for row, config in sorted(CONFIGS.items()):
|
||
try:
|
||
ok = write_to_sheet(row, config)
|
||
if ok:
|
||
prefix = config.strip()[:50].replace("\n", " ")
|
||
verified, preview = verify_write(row, prefix[:20])
|
||
if verified:
|
||
print(f"✓ Row {row}: Written and verified - {preview}...")
|
||
success += 1
|
||
else:
|
||
print(f"⚠ Row {row}: Write reported OK but verification failed: {preview}")
|
||
failed.append(row)
|
||
else:
|
||
print(f"✗ Row {row}: Write failed")
|
||
failed.append(row)
|
||
except Exception as e:
|
||
print(f"✗ Row {row}: Error - {e}")
|
||
failed.append(row)
|
||
|
||
print(f"\n=== Summary ===")
|
||
print(f"Success: {success}/{len(CONFIGS)}")
|
||
if failed:
|
||
print(f"Failed rows: {failed}")
|
||
return 0 if not failed else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|