feat(feishu): add feishu directory and calendar tool modules
新增飞书通讯录用户搜索以及日历相关的工具接口,包括查询日历列表、获取日历事件、查询日历事件列表的功能,适配飞书开放SDK的调用逻辑,统一处理了参数校验和异常情况。
This commit is contained in:
parent
69b7139863
commit
21c52c87ad
168
backend/package/yuxi/channels/adapters/feishu/tools/calendar.py
Normal file
168
backend/package/yuxi/channels/adapters/feishu/tools/calendar.py
Normal file
@ -0,0 +1,168 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from ._validate import validate_params
|
||||
|
||||
try:
|
||||
import lark_oapi
|
||||
|
||||
HAS_LARK_SDK = True
|
||||
except ImportError:
|
||||
HAS_LARK_SDK = False
|
||||
lark_oapi = None # type: ignore
|
||||
|
||||
|
||||
@validate_params
|
||||
async def list_calendar_events(
|
||||
client: Any,
|
||||
calendar_id: str = "primary",
|
||||
start_time: str = "",
|
||||
end_time: str = "",
|
||||
page_size: int = 50,
|
||||
page_token: str = "",
|
||||
) -> dict[str, Any]:
|
||||
if not HAS_LARK_SDK or not client:
|
||||
return {"events": [], "has_more": False, "page_token": ""}
|
||||
|
||||
try:
|
||||
builder = (
|
||||
lark_oapi.api.calendar.v4.ListCalendarEventRequest.builder()
|
||||
.calendar_id(calendar_id)
|
||||
.page_size(min(page_size, 100))
|
||||
)
|
||||
if start_time:
|
||||
builder.start_time(start_time)
|
||||
if end_time:
|
||||
builder.end_time(end_time)
|
||||
if page_token:
|
||||
builder.page_token(page_token)
|
||||
|
||||
request = builder.build()
|
||||
resp = await client.calendar.v4.calendar_event.list(request)
|
||||
if not resp.success():
|
||||
raise RuntimeError(f"\u67e5\u8be2\u65e5\u5386\u4e8b\u4ef6\u5931\u8d25: {resp.msg}")
|
||||
|
||||
data = resp.data if hasattr(resp, "data") else {}
|
||||
items = data.get("items", [])
|
||||
events = []
|
||||
for item in items:
|
||||
events.append(
|
||||
{
|
||||
"event_id": item.get("event_id", ""),
|
||||
"summary": item.get("summary", ""),
|
||||
"description": item.get("description", ""),
|
||||
"start_time": _format_event_time(item.get("start_time")),
|
||||
"end_time": _format_event_time(item.get("end_time")),
|
||||
"location": item.get("location", ""),
|
||||
"organizer": _get_display_name(item.get("organizer")),
|
||||
"status": item.get("status", ""),
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"events": events,
|
||||
"has_more": data.get("has_more", False),
|
||||
"page_token": data.get("page_token", ""),
|
||||
"sync_token": data.get("sync_token", ""),
|
||||
}
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"\u67e5\u8be2\u65e5\u5386\u4e8b\u4ef6\u5931\u8d25: {e}") from e
|
||||
|
||||
|
||||
@validate_params
|
||||
async def get_calendar_event(
|
||||
client: Any,
|
||||
calendar_id: str,
|
||||
event_id: str,
|
||||
) -> dict[str, Any]:
|
||||
if not HAS_LARK_SDK or not client:
|
||||
raise RuntimeError("SDK \u4e0d\u53ef\u7528")
|
||||
|
||||
try:
|
||||
request = (
|
||||
lark_oapi.api.calendar.v4.GetCalendarEventRequest.builder()
|
||||
.calendar_id(calendar_id)
|
||||
.event_id(event_id)
|
||||
.build()
|
||||
)
|
||||
resp = await client.calendar.v4.calendar_event.get(request)
|
||||
if not resp.success():
|
||||
raise RuntimeError(f"\u83b7\u53d6\u65e5\u5386\u4e8b\u4ef6\u5931\u8d25: {resp.msg}")
|
||||
|
||||
data = resp.data if hasattr(resp, "data") else {}
|
||||
item = data.get("event", data)
|
||||
return {
|
||||
"event_id": item.get("event_id", ""),
|
||||
"summary": item.get("summary", ""),
|
||||
"description": item.get("description", ""),
|
||||
"start_time": _format_event_time(item.get("start_time")),
|
||||
"end_time": _format_event_time(item.get("end_time")),
|
||||
"location": item.get("location", ""),
|
||||
"organizer": _get_display_name(item.get("organizer")),
|
||||
"attendees": [
|
||||
_get_display_name(a) for a in (item.get("attendees") or [])
|
||||
],
|
||||
"status": item.get("status", ""),
|
||||
}
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"\u83b7\u53d6\u65e5\u5386\u4e8b\u4ef6\u5931\u8d25: {e}") from e
|
||||
|
||||
|
||||
@validate_params
|
||||
async def list_calendars(
|
||||
client: Any,
|
||||
page_size: int = 50,
|
||||
page_token: str = "",
|
||||
) -> dict[str, Any]:
|
||||
if not HAS_LARK_SDK or not client:
|
||||
return {"calendars": [], "has_more": False, "page_token": ""}
|
||||
|
||||
try:
|
||||
builder = (
|
||||
lark_oapi.api.calendar.v4.ListCalendarRequest.builder()
|
||||
.page_size(min(page_size, 100))
|
||||
)
|
||||
if page_token:
|
||||
builder.page_token(page_token)
|
||||
|
||||
request = builder.build()
|
||||
resp = await client.calendar.v4.calendar.list(request)
|
||||
if not resp.success():
|
||||
raise RuntimeError(f"\u67e5\u8be2\u65e5\u5386\u5217\u8868\u5931\u8d25: {resp.msg}")
|
||||
|
||||
data = resp.data if hasattr(resp, "data") else {}
|
||||
items = data.get("calendar_list", [])
|
||||
calendars = []
|
||||
for item in items:
|
||||
calendars.append(
|
||||
{
|
||||
"calendar_id": item.get("calendar_id", ""),
|
||||
"summary": item.get("summary", ""),
|
||||
"description": item.get("description", ""),
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"calendars": calendars,
|
||||
"has_more": data.get("has_more", False),
|
||||
"page_token": data.get("page_token", ""),
|
||||
}
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"\u67e5\u8be2\u65e5\u5386\u5217\u8868\u5931\u8d25: {e}") from e
|
||||
|
||||
|
||||
def _format_event_time(ts: Any) -> str:
|
||||
if ts is None:
|
||||
return ""
|
||||
if isinstance(ts, dict):
|
||||
return ts.get("date_time") or ts.get("date") or ""
|
||||
return str(ts)
|
||||
|
||||
|
||||
def _get_display_name(obj: Any) -> str:
|
||||
if obj is None:
|
||||
return ""
|
||||
if isinstance(obj, dict):
|
||||
return obj.get("display_name") or obj.get("name") or ""
|
||||
return str(obj)
|
||||
@ -0,0 +1,59 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from ._validate import validate_params
|
||||
|
||||
try:
|
||||
import lark_oapi
|
||||
|
||||
HAS_LARK_SDK = True
|
||||
except ImportError:
|
||||
HAS_LARK_SDK = False
|
||||
lark_oapi = None # type: ignore
|
||||
|
||||
|
||||
@validate_params
|
||||
async def search_users(
|
||||
client: Any,
|
||||
query: str,
|
||||
page_size: int = 20,
|
||||
page_token: str = "",
|
||||
) -> dict[str, Any]:
|
||||
if not HAS_LARK_SDK or not client:
|
||||
return {"users": [], "has_more": False, "page_token": ""}
|
||||
|
||||
try:
|
||||
request = (
|
||||
lark_oapi.api.contact.v3.SearchUserRequest.builder()
|
||||
.query(query)
|
||||
.page_size(min(page_size, 100))
|
||||
.page_token(page_token)
|
||||
.build()
|
||||
)
|
||||
resp = await client.contact.v3.user.search(request)
|
||||
if not resp.success():
|
||||
raise RuntimeError(f"搜索用户失败: {resp.msg}")
|
||||
|
||||
data = resp.data if hasattr(resp, "data") else {}
|
||||
items = data.get("items", [])
|
||||
users = [
|
||||
{
|
||||
"open_id": item.get("open_id", ""),
|
||||
"user_id": item.get("user_id", ""),
|
||||
"name": item.get("name", ""),
|
||||
"email": item.get("email", ""),
|
||||
"avatar_url": (
|
||||
item.get("avatar", {}).get("avatar_240", "") if isinstance(item.get("avatar"), dict) else ""
|
||||
),
|
||||
}
|
||||
for item in items
|
||||
]
|
||||
|
||||
return {
|
||||
"users": users,
|
||||
"has_more": data.get("has_more", False),
|
||||
"page_token": data.get("page_token", ""),
|
||||
}
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"搜索用户失败: {e}") from e
|
||||
Loading…
Reference in New Issue
Block a user