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