ai_member_xiaoyan/scripts/fix_second_and_pic.py

125 lines
6.8 KiB
Python

#!/usr/bin/env python3
"""Task 1: Fix all structured empty seconds → "second": {}
Task 2: Add 图片描述 to 021601, 021801, 022001"""
import requests, json, time
APP_TOKEN = "CMHSbUUjka3TrUsaxxEc297ongf"
APP_ID = "cli_a931175d41799cc7"
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
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"]
token = get_token()
# List all tables in the bitable
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables",
headers={"Authorization": f"Bearer {token}"}, timeout=15)
tables = r.json().get("data", {}).get("items", [])
print(f"{len(tables)} 个表\n")
# ====== Task 1: Scan all tables for structured empty second blocks ======
fixes_second = [] # (table_id, table_name, qsid, rid)
for t in tables:
tid = t["table_id"]
tname = t["name"]
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records?page_size=200",
headers={"Authorization": f"Bearer {token}"}, timeout=15)
items = r.json().get("data", {}).get("items", [])
for it in items:
f = it["fields"]
qsid = f.get("题目集合 ID", "") or ""
jd_raw = f.get("jsonData", "")
if not jd_raw: continue
try:
jd = json.loads(jd_raw) if isinstance(jd_raw, str) else jd_raw
except:
continue
second = jd.get("second", None)
if not second or not isinstance(second, dict):
continue
# Check if structured empty: has type/questionSetID but empty questionSet
qs = second.get("questionSet", None)
if qs is not None and isinstance(qs, list) and len(qs) == 0:
# Has structure but no content → fix to {}
fixes_second.append((tid, tname, qsid, it["record_id"], second))
print(f"=== Task 1: 修复结构化空 second → {{}} ===")
print(f"发现 {len(fixes_second)} 条需要修复\n")
for tid, tname, qsid, rid, old_second in fixes_second:
# Fetch fresh record to get current jsonData
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records/{rid}",
headers={"Authorization": f"Bearer {token}"}, timeout=10)
rec = r.json()["data"]["record"]
jd = json.loads(rec["fields"]["jsonData"])
# Before
old_type = jd["second"].get("type", "?")
# Replace with empty object
jd["second"] = {}
new_jd = json.dumps(jd, ensure_ascii=False)
r = requests.put(
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records/{rid}",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={"fields": {"jsonData": new_jd}}, timeout=15)
code = r.json().get("code")
print(f" {'' if code==0 else ''} [{tname}] {qsid}: second({old_type}) → {{}}")
time.sleep(0.3)
# ====== Task 2: Add 图片描述 to 021601, 021801, 022001 ======
print(f"\n=== Task 2: 补充图片描述 ===")
pic_map = {
"021601": '[1-组图]:{"prompt_2":"黑白线条图:一个孩子在公园里焦急地四处张望,似乎在寻找丢失的玩具,背景有秋千、滑梯和大树,远处是公园的出口","prompt_3":"黑白线条图:一个小男孩正在爬滑梯的顶部,一个较大的孩子站在下面焦急地伸手示意他下来,表情紧张","prompt_4":"黑白线条图:公园入口处可以看到周围的商店、图书馆和警察亭,一位公园工作人员站在指示牌旁微笑着指路"}',
"021801": '[1-组图]:{"prompt_2":"黑白线条图:一个孩子躺在床上盖着被子,额头上放着湿毛巾,他的朋友坐在床边端来一杯水,床头柜上放着药瓶","prompt_3":"黑白线条图:两个同学坐在教室的课桌前,一个正在耐心地指着作业本给另一个讲解题目,旁边放着课本和铅笔","prompt_4":"黑白线条图:两个孩子并肩坐在草地上,一个孩子指着远方天空中的热气球,脸上带着鼓励和期待的表情","prompt_5":"黑白线条图:教室里,一个孩子帮忙扶住同学够高处的书本,另一个孩子在帮老师整理教具,气氛温馨互助"}',
"022001": '[1-组图]:{"prompt_2":"黑白线条图:学校走廊里,一个孩子脸上带着担忧的表情蹲在墙角,另一个孩子走过来蹲下身关切地询问","prompt_3":"黑白线条图:一位爷爷坐在沙发上拉着孩子的手认真地说话,表情温和而坚定,孩子脸上露出理解的神情","prompt_4":"黑白线条图:教室里,一个孩子站在讲台上自信地展示自己的画作,台下的同学们都在热烈鼓掌,孩子脸上带着自豪的笑容","prompt_5":"黑白线条图:书房里,一位家长蹲在孩子面前轻声解释着笔记本上的内容,墙上贴着学习计划表和各种鼓励标语"}',
}
# Speaking-P2 table
SP2_TABLE = "tblGoWYBmVI0IrvQ"
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{SP2_TABLE}/records?page_size=200",
headers={"Authorization": f"Bearer {token}"}, timeout=15)
for it in r.json()["data"]["items"]:
qsid = it["fields"].get("题目集合 ID", "")
if qsid not in pic_map: continue
rid = it["record_id"]
r = requests.put(
f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{SP2_TABLE}/records/{rid}",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json={"fields": {"图片描述": pic_map[qsid]}}, timeout=15)
code = r.json().get("code")
print(f" {'' if code==0 else ''} {qsid}: 图片描述已写入")
# ====== Verify ======
print(f"\n=== 验证 ===")
# Spot-check one from each table
for tid, tname, qsid, rid, _ in fixes_second[:3]: # first 3
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{tid}/records/{rid}",
headers={"Authorization": f"Bearer {token}"}, timeout=10)
jd = json.loads(r.json()["data"]["record"]["fields"]["jsonData"])
second = jd.get("second", None)
status = "{}" if second == {} else f"{json.dumps(second, ensure_ascii=False)[:50]}"
print(f" [{tname}] {qsid}: second={status}")
# Verify pic
for qsid in pic_map:
r = requests.get(f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{SP2_TABLE}/records?page_size=200",
headers={"Authorization": f"Bearer {token}"}, timeout=15)
for it in r.json()["data"]["items"]:
if it["fields"].get("题目集合 ID") == qsid:
pic = it["fields"].get("图片描述", "")
print(f" {qsid}: 图片描述={'' if pic else '❌空'}")
break
time.sleep(0.2)
print("\n全部完成")