ai_member_xiaoyan/skills/biaoshu/scripts/biaoshu_number.py

158 lines
4.9 KiB
Python

#!/usr/bin/env python3
"""
标数脚本 — 飞书剧本表格互动行自动编号
用法:
python3 biaoshu_number.py <wiki_url> [--prefix PREFIX]
示例:
python3 biaoshu_number.py "https://makee-interactive.feishu.cn/wiki/P9bvw6nXziqzWZkxDmMcOZN4ndc"
python3 biaoshu_number.py "https://makee-interactive.feishu.cn/wiki/xxx" --prefix 12186
"""
import json
import sys
import requests
# ========== 配置 ==========
APP_ID = "cli_a931175d41799cc7"
APP_SECRET = "Iw2vEfbjT6GtV0GhbxbZqfQ4nAPtbR14"
SHEET_MAX_ROWS = 250
def get_tenant_token() -> str:
r = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET},
)
return r.json()["tenant_access_token"]
def get_doc_blocks(token: str, obj_token: str) -> list:
r = requests.get(
f"https://open.feishu.cn/open-apis/docx/v1/documents/{obj_token}/blocks",
headers={"Authorization": f"Bearer {token}"},
)
return r.json().get("data", {}).get("items", [])
def find_embedded_sheet(blocks: list) -> tuple:
"""Find block_type=30 (embedded sheet), return (spreadsheet_token, sheet_id)"""
for block in blocks:
if block.get("block_type") == 30:
st = block.get("sheet", {}).get("token", "")
parts = st.split("_")
if len(parts) == 2:
return parts[0], parts[1]
return None, None
def read_sheet(token: str, spreadsheet_token: str, sheet_id: str) -> list:
r = requests.get(
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}"
f"/values/{sheet_id}!A1:B{SHEET_MAX_ROWS}?valueRenderOption=ToString",
headers={"Authorization": f"Bearer {token}"},
)
return r.json()["data"]["valueRange"]["values"]
def write_cell(token: str, spreadsheet_token: str, sheet_id: str, row: int, value: str) -> bool:
body = {
"valueRange": {
"range": f"{sheet_id}!B{row}:B{row}",
"values": [[value]],
}
}
r = requests.put(
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}/values",
headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
json=body,
)
return r.json().get("code") == 0
def verify_sheet(token: str, spreadsheet_token: str, sheet_id: str) -> list:
r = requests.get(
f"https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{spreadsheet_token}"
f"/values/{sheet_id}!A1:B{SHEET_MAX_ROWS}?valueRenderOption=ToString",
headers={"Authorization": f"Bearer {token}"},
)
return r.json()["data"]["valueRange"]["values"]
def parse_wiki_url(url: str) -> str:
"""Extract obj_token from wiki URL"""
# https://xxx.feishu.cn/wiki/P9bvw6nXziqzWZkxDmMcOZN4ndc?...
from urllib.parse import urlparse
path = urlparse(url).path
parts = path.strip("/").split("/")
return parts[-1] if parts else url
def main():
if len(sys.argv) < 2:
print("Usage: python3 biaoshu_number.py <wiki_url> [--prefix PREFIX]")
sys.exit(1)
wiki_url = sys.argv[1]
prefix = "12185"
if len(sys.argv) >= 4 and sys.argv[2] == "--prefix":
prefix = sys.argv[3]
obj_token = parse_wiki_url(wiki_url)
print(f"📄 文档 token: {obj_token}")
print(f"🔢 ID 前缀: {prefix}")
token = get_tenant_token()
print("✅ Token 获取成功")
blocks = get_doc_blocks(token, obj_token)
spreadsheet_token, sheet_id = find_embedded_sheet(blocks)
if not spreadsheet_token:
print("❌ 未找到内嵌 Sheet!")
sys.exit(1)
print(f"📊 Sheet: {spreadsheet_token} / {sheet_id}")
rows = read_sheet(token, spreadsheet_token, sheet_id)
print(f"📖 读取 {len(rows)}")
# Identify interaction rows (A列 not empty, not 'TL')
interactions = []
for i, r in enumerate(rows[1:], start=2):
a = (r[0] or "").strip() if len(r) > 0 else ""
if a and a != "TL":
interactions.append((i, a))
print(f"🎯 识别到 {len(interactions)} 个互动行")
# Write IDs
ok = 0
fail = 0
for idx, (row_num, a_type) in enumerate(interactions, start=1):
new_id = f"{prefix}{idx:02d}"
if write_cell(token, spreadsheet_token, sheet_id, row_num, new_id):
ok += 1
print(f" ✅ Row {row_num:3d} ({a_type}) → {new_id}")
else:
fail += 1
print(f" ❌ Row {row_num:3d} ({a_type}) → 写入失败")
print(f"\n📊 结果: {ok} 成功 / {fail} 失败")
# Verify
print("\n🔍 验证...")
updated = verify_sheet(token, spreadsheet_token, sheet_id)
for i, r in enumerate(updated[1:], start=2):
a = (r[0] or "").strip() if len(r) > 0 else ""
b = (r[1] or "").strip() if len(r) > 1 else ""
if b:
status = "" if b.startswith(prefix) else "⚠️"
print(f" {status} Row {i}: {a}{b}")
if __name__ == "__main__":
main()