Files
hermes-skills/scripts/create_doc.py
T

141 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""Create a Feishu document and populate it with content blocks.
Usage: python3 scripts/create_doc.py <title> <markdown_file>
Reads Feishu credentials from ~/.hermes/.env (FEISHU_APP_ID, FEISHU_APP_SECRET).
Creates a docx document with the given title, then converts basic markdown
to Feishu doc blocks and adds them.
Currently supports: # H1, ## H2, ### H3, - bullet, blank line separator,
plain text paragraphs. For richer content, extend build_blocks().
"""
import json, os, re, requests, sys
def get_feishu_token():
"""Get tenant access token from Feishu Open API."""
env_path = os.path.expanduser("~/.hermes/.env")
creds = {}
with open(env_path) as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
creds[k.strip()] = v.strip().strip('"').strip("'")
aid = creds.get("FEISHU_APP_ID")
sec = creds.get("FEISHU_APP_SECRET")
if not aid or not sec:
sys.exit("FEISHU_APP_ID or FEISHU_APP_SECRET not found in .env")
r = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": aid, "app_secret": sec},
timeout=10,
)
return r.json()["tenant_access_token"], aid, sec
def text_element(content):
return [{"text_run": {"content": content}}]
def build_blocks(markdown_text):
"""Convert basic markdown to Feishu doc blocks."""
blocks = []
lines = markdown_text.strip().split("\n")
i = 0
while i < len(lines):
line = lines[i]
# Blank line → divider or skip
if not line.strip():
# Two blank lines → divider
if i + 1 < len(lines) and not lines[i + 1].strip():
blocks.append({"block_type": 22, "divider": {}})
i += 2
continue
i += 1
continue
# Heading 3
if line.startswith("### "):
blocks.append({"block_type": 5, "heading3": {"elements": text_element(line[4:])}})
# Heading 2
elif line.startswith("## "):
blocks.append({"block_type": 4, "heading2": {"elements": text_element(line[3:])}})
# Heading 1
elif line.startswith("# "):
blocks.append({"block_type": 3, "heading1": {"elements": text_element(line[2:])}})
# Bullet
elif line.startswith("- ") or line.startswith("* "):
blocks.append({"block_type": 12, "bullet": {"elements": text_element(line[2:])}})
# Plain text
else:
blocks.append({"block_type": 2, "text": {"elements": text_element(line)}})
i += 1
return blocks
def main():
if len(sys.argv) < 2:
print("Usage: python3 create_doc.py <title> [markdown_file]")
print(" If no markdown_file, reads from stdin.")
sys.exit(1)
title = sys.argv[1]
if len(sys.argv) >= 3:
with open(sys.argv[2], encoding="utf-8") as f:
markdown = f.read()
else:
markdown = sys.stdin.read()
token, _, _ = get_feishu_token()
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
# Step 1: Create document
print(f"Creating doc: {title}")
r = requests.post(
"https://open.feishu.cn/open-apis/docx/v1/documents",
headers=headers,
json={"title": title},
timeout=10,
)
result = r.json()
if result.get("code") != 0:
sys.exit(f"Create failed: {result.get('msg')}")
doc_id = result["data"]["document"]["document_id"]
print(f" doc_id: {doc_id}")
# Step 2: Build and add blocks
blocks = build_blocks(markdown)
if not blocks:
print(" No blocks to add (empty markdown)")
else:
batch_size = 50
for i in range(0, len(blocks), batch_size):
batch = blocks[i:i + batch_size]
r = requests.post(
f"https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks/{doc_id}/children",
headers=headers,
json={"children": batch},
timeout=15,
)
result = r.json()
if result.get("code") != 0:
sys.exit(f"Block add failed (batch {i//batch_size}): {result.get('msg')}")
print(f" Batch {i//batch_size + 1}: {len(batch)} blocks OK")
url = f"https://xiteng.feishu.cn/docx/{doc_id}"
print(f"\n{url}")
print(doc_id)
if __name__ == "__main__":
main()