360 lines
11 KiB
Python
360 lines
11 KiB
Python
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
|
|||
|
|
from yuxi.channel.extensions.feishu.client import get_client
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
FEISHU_DOC_TOOLS = [
|
|||
|
|
{
|
|||
|
|
"name": "feishu_doc_read",
|
|||
|
|
"description": "读取飞书文档内容",
|
|||
|
|
"parameters": {"doc_token": "文档 token"},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "feishu_doc_create",
|
|||
|
|
"description": "创建飞书文档",
|
|||
|
|
"parameters": {"title": "文档标题", "folder_token": "文件夹 token(可选)"},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "feishu_doc_append",
|
|||
|
|
"description": "追加内容到飞书文档",
|
|||
|
|
"parameters": {"doc_token": "文档 token", "content": "要追加的内容"},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "feishu_doc_list_blocks",
|
|||
|
|
"description": "列出文档的所有块",
|
|||
|
|
"parameters": {"doc_token": "文档 token"},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "feishu_doc_export",
|
|||
|
|
"description": "导出飞书文档为 PDF 或其他格式",
|
|||
|
|
"parameters": {"doc_token": "文档 token", "export_format": "导出格式(pdf/docx,默认 pdf)"},
|
|||
|
|
},
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def read_doc(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
req = lark_oapi.docx.v1.GetDocumentRequest(document_id=doc_token)
|
|||
|
|
resp = await client.docx.v1.document.get_async(req)
|
|||
|
|
|
|||
|
|
if resp.success() and resp.data:
|
|||
|
|
doc = resp.data.document
|
|||
|
|
return {
|
|||
|
|
"success": True,
|
|||
|
|
"title": getattr(doc, "title", ""),
|
|||
|
|
"document_id": getattr(doc, "document_id", ""),
|
|||
|
|
}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu read_doc error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def write_doc(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
content: str,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
blocks = [
|
|||
|
|
lark_oapi.docx.v1.Block(
|
|||
|
|
block_type=2,
|
|||
|
|
text=lark_oapi.docx.v1.Text(
|
|||
|
|
elements=[
|
|||
|
|
lark_oapi.docx.v1.TextElement(
|
|||
|
|
text_run=lark_oapi.docx.v1.TextRun(content=content),
|
|||
|
|
)
|
|||
|
|
]
|
|||
|
|
),
|
|||
|
|
)
|
|||
|
|
]
|
|||
|
|
req = lark_oapi.docx.v1.UpdateDocumentRequest(
|
|||
|
|
document_id=doc_token,
|
|||
|
|
request_body=lark_oapi.docx.v1.UpdateDocumentRequestBody(
|
|||
|
|
document_id=doc_token,
|
|||
|
|
blocks=blocks,
|
|||
|
|
),
|
|||
|
|
)
|
|||
|
|
resp = await client.docx.v1.document.update_async(req)
|
|||
|
|
|
|||
|
|
if resp.success():
|
|||
|
|
return {"success": True}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu write_doc error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def append_doc(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
content: str,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
return await write_doc(app_id, app_secret, domain, doc_token, content, http_timeout_ms)
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def create_doc(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
title: str,
|
|||
|
|
folder_token: str = "",
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
req = lark_oapi.docx.v1.CreateDocumentRequest(
|
|||
|
|
request_body=lark_oapi.docx.v1.CreateDocumentRequestBody(
|
|||
|
|
title=title,
|
|||
|
|
folder_token=folder_token if folder_token else None,
|
|||
|
|
),
|
|||
|
|
)
|
|||
|
|
resp = await client.docx.v1.document.create_async(req)
|
|||
|
|
|
|||
|
|
if resp.success() and resp.data:
|
|||
|
|
return {
|
|||
|
|
"success": True,
|
|||
|
|
"document_id": getattr(resp.data.document, "document_id", ""),
|
|||
|
|
"url": getattr(resp.data.document, "url", ""),
|
|||
|
|
}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu create_doc error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def list_doc_blocks(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
req = lark_oapi.docx.v1.ListDocumentBlockRequest(
|
|||
|
|
document_id=doc_token,
|
|||
|
|
page_size=500,
|
|||
|
|
)
|
|||
|
|
resp = await client.docx.v1.document_block.list_async(req)
|
|||
|
|
|
|||
|
|
if resp.success() and resp.data:
|
|||
|
|
items = getattr(resp.data, "items", []) or []
|
|||
|
|
return {
|
|||
|
|
"success": True,
|
|||
|
|
"blocks": [
|
|||
|
|
{
|
|||
|
|
"block_id": getattr(b, "block_id", ""),
|
|||
|
|
"block_type": getattr(b, "block_type", 0),
|
|||
|
|
"text": getattr(getattr(b, "text", None), "elements", []),
|
|||
|
|
}
|
|||
|
|
for b in items
|
|||
|
|
],
|
|||
|
|
}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu list_doc_blocks error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def get_doc_block(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
block_id: str,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
req = lark_oapi.docx.v1.GetDocumentBlockRequest(
|
|||
|
|
document_id=doc_token,
|
|||
|
|
block_id=block_id,
|
|||
|
|
)
|
|||
|
|
resp = await client.docx.v1.document_block.get_async(req)
|
|||
|
|
|
|||
|
|
if resp.success() and resp.data:
|
|||
|
|
block = resp.data.block
|
|||
|
|
return {
|
|||
|
|
"success": True,
|
|||
|
|
"block": {
|
|||
|
|
"block_id": getattr(block, "block_id", ""),
|
|||
|
|
"block_type": getattr(block, "block_type", 0),
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu get_doc_block error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def update_doc_block(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
block_id: str,
|
|||
|
|
content: str,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
req = lark_oapi.docx.v1.UpdateDocumentBlockRequest(
|
|||
|
|
document_id=doc_token,
|
|||
|
|
block_id=block_id,
|
|||
|
|
request_body=lark_oapi.docx.v1.UpdateDocumentBlockRequestBody(
|
|||
|
|
update_text_elements={
|
|||
|
|
"elements": [
|
|||
|
|
{"text_run": {"content": content}}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
),
|
|||
|
|
)
|
|||
|
|
resp = await client.docx.v1.document_block.update_async(req)
|
|||
|
|
|
|||
|
|
if resp.success():
|
|||
|
|
return {"success": True}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu update_doc_block error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def delete_doc_block(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
block_id: str,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
req = lark_oapi.docx.v1.DeleteDocumentBlockRequest(
|
|||
|
|
document_id=doc_token,
|
|||
|
|
block_id=block_id,
|
|||
|
|
)
|
|||
|
|
resp = await client.docx.v1.document_block.delete_async(req)
|
|||
|
|
|
|||
|
|
if resp.success():
|
|||
|
|
return {"success": True}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu delete_doc_block error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def create_doc_table(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
row_size: int,
|
|||
|
|
column_size: int,
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
header = "| " + " | ".join(f"列{i + 1}" for i in range(column_size)) + " |\n"
|
|||
|
|
sep = "| " + " | ".join("---" for _ in range(column_size)) + " |\n"
|
|||
|
|
rows = "".join("| " + " | ".join("" for _ in range(column_size)) + " |\n" for _ in range(row_size))
|
|||
|
|
table_md = header + sep + rows
|
|||
|
|
return await write_doc(app_id, app_secret, domain, doc_token, table_md, http_timeout_ms)
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def write_table_cells(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
table_block_id: str,
|
|||
|
|
values: list[list[str]],
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
text = "".join("| " + " | ".join(row) + " |\n" for row in values)
|
|||
|
|
return await update_doc_block(app_id, app_secret, domain, doc_token, table_block_id, text, http_timeout_ms)
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def export_doc(
|
|||
|
|
app_id: str,
|
|||
|
|
app_secret: str,
|
|||
|
|
domain: str,
|
|||
|
|
doc_token: str,
|
|||
|
|
export_format: str = "pdf",
|
|||
|
|
http_timeout_ms: int = 30000,
|
|||
|
|
) -> dict:
|
|||
|
|
try:
|
|||
|
|
client = get_client(app_id, app_secret, domain, http_timeout_ms)
|
|||
|
|
|
|||
|
|
import lark_oapi
|
|||
|
|
req = lark_oapi.docx.v1.GetDocumentExportRequest(
|
|||
|
|
document_id=doc_token,
|
|||
|
|
export_format=export_format,
|
|||
|
|
export_type="download",
|
|||
|
|
)
|
|||
|
|
resp = await client.docx.v1.document.export_async(req)
|
|||
|
|
|
|||
|
|
if resp.success():
|
|||
|
|
return {
|
|||
|
|
"success": True,
|
|||
|
|
"document_id": doc_token,
|
|||
|
|
"format": export_format,
|
|||
|
|
}
|
|||
|
|
else:
|
|||
|
|
return {"success": False, "error": getattr(resp, "msg", "")}
|
|||
|
|
except ImportError:
|
|||
|
|
return {"success": False, "error": "lark-oapi SDK not installed"}
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception("Feishu export_doc error")
|
|||
|
|
return {"success": False, "error": "Internal error"}
|