ForcePilot/backend/package/yuxi/channel/extensions/feishu/tools/drive.py
Kris 5e91bb9985 feat(feishu): 新增飞书渠道完整插件实现
新增飞书渠道插件,包含基础配置、事件处理、消息收发、工具调用、权限管理等完整功能模块,支持WebSocket长连接、卡片消息、流式响应、群管理、审批通知等能力
2026-05-21 10:46:42 +08:00

290 lines
9.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import logging
from yuxi.channel.extensions.feishu.client import get_client
logger = logging.getLogger(__name__)
FEISHU_DRIVE_TOOLS = [
{
"name": "feishu_drive_list",
"description": "列出飞书云盘文件和文件夹",
"parameters": {"folder_token": "文件夹 token可选默认根目录"},
},
{
"name": "feishu_drive_info",
"description": "获取飞书云盘文件信息",
"parameters": {"file_token": "文件 token"},
},
{
"name": "feishu_drive_create_folder",
"description": "创建飞书云盘文件夹",
"parameters": {"name": "文件夹名称", "folder_token": "父文件夹 token"},
},
{
"name": "feishu_drive_upload",
"description": "上传文件到飞书云盘",
"parameters": {"file_path": "本地文件路径", "parent_token": "目标文件夹 token可选"},
},
{
"name": "feishu_drive_download",
"description": "下载飞书云盘文件",
"parameters": {"file_token": "文件 token", "save_path": "本地保存路径(可选)"},
},
{
"name": "feishu_drive_delete",
"description": "删除飞书云盘文件或文件夹",
"parameters": {"file_token": "文件 token", "file_type": "文件类型file/folder默认 file"},
},
{
"name": "feishu_drive_move",
"description": "移动飞书云盘文件到指定文件夹",
"parameters": {"file_token": "文件 token", "target_folder_token": "目标文件夹 token"},
},
]
async def list_drive_files(
app_id: str,
app_secret: str,
domain: 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.drive.v1.ListFileRequest(
folder_token=folder_token if folder_token else None,
page_size=50,
)
resp = await client.drive.v1.file.list_async(req)
if resp.success() and resp.data:
files = getattr(resp.data, "files", []) or []
return {
"success": True,
"files": [
{
"token": getattr(f, "token", ""),
"name": getattr(f, "name", ""),
"type": getattr(f, "type", ""),
"parent_token": getattr(f, "parent_token", ""),
}
for f in files
],
"has_more": getattr(resp.data, "has_more", False),
}
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_drive_files error")
return {"success": False, "error": "Internal error"}
async def get_drive_file_info(
app_id: str,
app_secret: str,
domain: str,
file_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.drive.v1.GetFileRequest(file_token=file_token)
resp = await client.drive.v1.file.get_async(req)
if resp.success() and resp.data:
f = resp.data
return {
"success": True,
"file": {
"token": getattr(f, "token", ""),
"name": getattr(f, "name", ""),
"type": getattr(f, "type", ""),
"size": getattr(f, "size", 0),
"url": getattr(f, "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 get_drive_file_info error")
return {"success": False, "error": "Internal error"}
async def create_drive_folder(
app_id: str,
app_secret: str,
domain: str,
name: 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.drive.v1.CreateFolderFileRequest(
request_body=lark_oapi.drive.v1.CreateFolderFileRequestBody(
name=name,
folder_token=folder_token,
),
)
resp = await client.drive.v1.file.create_folder_async(req)
if resp.success() and resp.data:
return {
"success": True,
"token": getattr(resp.data, "token", ""),
"url": getattr(resp.data, "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_drive_folder error")
return {"success": False, "error": "Internal error"}
async def upload_drive_file(
app_id: str,
app_secret: str,
domain: str,
file_path: str,
parent_token: str = "",
file_name: str = "",
http_timeout_ms: int = 60000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
with open(file_path, "rb") as f:
req = lark_oapi.drive.v1.UploadAllMediaRequest(
request_body=lark_oapi.drive.v1.UploadAllMediaRequestBody(
file_name=file_name or file_path.rsplit("\\", 1)[-1].rsplit("/", 1)[-1],
parent_type="explorer",
parent_node=parent_token if parent_token else None,
size=str(len(f.read())),
file=f,
),
)
f.seek(0)
resp = await client.drive.v1.media.upload_all_async(req)
if resp.success() and resp.data:
return {
"success": True,
"file_token": getattr(resp.data, "file_token", ""),
"url": getattr(resp.data, "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 upload_drive_file error")
return {"success": False, "error": "Internal error"}
async def download_drive_file(
app_id: str,
app_secret: str,
domain: str,
file_token: str,
save_path: 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.drive.v1.DownloadMediaRequest(file_token=file_token)
resp = await client.drive.v1.media.download_async(req)
if resp.success():
result = {"success": True, "file_token": file_token}
if resp.file and save_path:
with open(save_path, "wb") as f:
f.write(resp.file.read())
result["saved_to"] = save_path
return result
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu download_drive_file error")
return {"success": False, "error": "Internal error"}
async def delete_drive_file(
app_id: str,
app_secret: str,
domain: str,
file_token: str,
file_type: str = "file",
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.drive.v1.DeleteFileRequest(
file_token=file_token,
type=file_type,
)
resp = await client.drive.v1.file.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_drive_file error")
return {"success": False, "error": "Internal error"}
async def move_drive_file(
app_id: str,
app_secret: str,
domain: str,
file_token: str,
target_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.drive.v1.MoveFileRequest(
file_token=file_token,
request_body=lark_oapi.drive.v1.MoveFileRequestBody(
target_parent_token=target_folder_token,
),
)
resp = await client.drive.v1.file.move_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 move_drive_file error")
return {"success": False, "error": "Internal error"}