Fix Feishu wiki child node retrieval
This commit is contained in:
@@ -80,9 +80,17 @@ def _feishu_get(path: str, params: dict | None = None, config: FeishuRetrievalCo
|
|||||||
url = f"{FEISHU_OPEN_API}{path}"
|
url = f"{FEISHU_OPEN_API}{path}"
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
|
|
||||||
|
try:
|
||||||
resp = httpx.get(url, headers=headers, params=params, timeout=config.timeout_seconds)
|
resp = httpx.get(url, headers=headers, params=params, timeout=config.timeout_seconds)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
|
except httpx.HTTPStatusError as exc:
|
||||||
|
raise ExternalServiceError(
|
||||||
|
f"飞书HTTP请求失败 [{path}]:{exc.response.status_code} {_response_error_detail(exc.response)}",
|
||||||
|
provider="feishu",
|
||||||
|
) from exc
|
||||||
|
except httpx.HTTPError as exc:
|
||||||
|
raise ExternalServiceError(f"飞书网络请求失败 [{path}]:{exc}", provider="feishu") from exc
|
||||||
|
|
||||||
if data.get("code") != 0:
|
if data.get("code") != 0:
|
||||||
raise ExternalServiceError(
|
raise ExternalServiceError(
|
||||||
@@ -100,9 +108,17 @@ def _feishu_post(path: str, payload: dict | None = None, config: FeishuRetrieval
|
|||||||
url = f"{FEISHU_OPEN_API}{path}"
|
url = f"{FEISHU_OPEN_API}{path}"
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
|
|
||||||
|
try:
|
||||||
resp = httpx.post(url, headers=headers, json=payload, timeout=config.timeout_seconds)
|
resp = httpx.post(url, headers=headers, json=payload, timeout=config.timeout_seconds)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
|
except httpx.HTTPStatusError as exc:
|
||||||
|
raise ExternalServiceError(
|
||||||
|
f"飞书HTTP请求失败 [{path}]:{exc.response.status_code} {_response_error_detail(exc.response)}",
|
||||||
|
provider="feishu",
|
||||||
|
) from exc
|
||||||
|
except httpx.HTTPError as exc:
|
||||||
|
raise ExternalServiceError(f"飞书网络请求失败 [{path}]:{exc}", provider="feishu") from exc
|
||||||
|
|
||||||
if data.get("code") != 0:
|
if data.get("code") != 0:
|
||||||
raise ExternalServiceError(
|
raise ExternalServiceError(
|
||||||
@@ -112,6 +128,15 @@ def _feishu_post(path: str, payload: dict | None = None, config: FeishuRetrieval
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def _response_error_detail(response: httpx.Response) -> str:
|
||||||
|
try:
|
||||||
|
body = response.json()
|
||||||
|
except ValueError:
|
||||||
|
return response.text[:200]
|
||||||
|
message = body.get("msg") or body.get("message") or body.get("error") or body
|
||||||
|
return str(message)[:300]
|
||||||
|
|
||||||
|
|
||||||
def _extract_text(elements: list[dict]) -> str:
|
def _extract_text(elements: list[dict]) -> str:
|
||||||
"""从 elements 列表中提取纯文本"""
|
"""从 elements 列表中提取纯文本"""
|
||||||
texts = []
|
texts = []
|
||||||
@@ -208,8 +233,16 @@ def _get_wiki_node_info(node_token: str, config: FeishuRetrievalConfig) -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _get_wiki_children(node_token: str, config: FeishuRetrievalConfig, page_size: int = 50) -> list[dict]:
|
def _get_wiki_children(
|
||||||
|
space_id: str,
|
||||||
|
node_token: str,
|
||||||
|
config: FeishuRetrievalConfig,
|
||||||
|
page_size: int = 50,
|
||||||
|
) -> list[dict]:
|
||||||
"""获取 Wiki 节点的子节点列表"""
|
"""获取 Wiki 节点的子节点列表"""
|
||||||
|
if not space_id:
|
||||||
|
raise ExternalServiceError("飞书知识库缺少 SpaceID,无法读取子节点", provider="feishu")
|
||||||
|
|
||||||
all_children = []
|
all_children = []
|
||||||
page_token = ""
|
page_token = ""
|
||||||
while True:
|
while True:
|
||||||
@@ -220,7 +253,7 @@ def _get_wiki_children(node_token: str, config: FeishuRetrievalConfig, page_size
|
|||||||
if page_token:
|
if page_token:
|
||||||
params["page_token"] = page_token
|
params["page_token"] = page_token
|
||||||
|
|
||||||
data = _feishu_get("/open-apis/wiki/v2/spaces/nodes/get_child_nodes", params=params, config=config)
|
data = _feishu_get(f"/open-apis/wiki/v2/spaces/{space_id}/nodes", params=params, config=config)
|
||||||
children = data.get("data", {}).get("items", [])
|
children = data.get("data", {}).get("items", [])
|
||||||
all_children.extend(children)
|
all_children.extend(children)
|
||||||
|
|
||||||
@@ -231,7 +264,7 @@ def _get_wiki_children(node_token: str, config: FeishuRetrievalConfig, page_size
|
|||||||
return all_children
|
return all_children
|
||||||
|
|
||||||
|
|
||||||
def _get_space_node_tree(space_id: str) -> list[dict]:
|
def _get_space_node_tree(space_id: str, config: FeishuRetrievalConfig | None = None) -> list[dict]:
|
||||||
"""获取知识空间下所有根节点"""
|
"""获取知识空间下所有根节点"""
|
||||||
all_nodes = []
|
all_nodes = []
|
||||||
page_token = ""
|
page_token = ""
|
||||||
@@ -243,7 +276,7 @@ def _get_space_node_tree(space_id: str) -> list[dict]:
|
|||||||
if page_token:
|
if page_token:
|
||||||
params["page_token"] = page_token
|
params["page_token"] = page_token
|
||||||
|
|
||||||
data = _feishu_get("/open-apis/wiki/v2/spaces/nodes", params=params)
|
data = _feishu_get(f"/open-apis/wiki/v2/spaces/{space_id}/nodes", params=params, config=config)
|
||||||
items = data.get("data", {}).get("items", [])
|
items = data.get("data", {}).get("items", [])
|
||||||
all_nodes.extend(items)
|
all_nodes.extend(items)
|
||||||
|
|
||||||
@@ -398,7 +431,7 @@ class FeishuKnowledgeService:
|
|||||||
return [(title, content, source_url)]
|
return [(title, content, source_url)]
|
||||||
|
|
||||||
# 如果节点是文件夹,获取子节点
|
# 如果节点是文件夹,获取子节点
|
||||||
children = cls._get_wiki_children_with_cache(node_id, config)
|
children = cls._get_wiki_children_with_cache(space_id, node_id, config)
|
||||||
|
|
||||||
documents = []
|
documents = []
|
||||||
for child in children:
|
for child in children:
|
||||||
@@ -457,9 +490,14 @@ class FeishuKnowledgeService:
|
|||||||
return content
|
return content
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_wiki_children_with_cache(cls, node_token: str, config: FeishuRetrievalConfig) -> list[dict]:
|
def _get_wiki_children_with_cache(
|
||||||
|
cls,
|
||||||
|
space_id: str,
|
||||||
|
node_token: str,
|
||||||
|
config: FeishuRetrievalConfig,
|
||||||
|
) -> list[dict]:
|
||||||
"""带缓存获取子节点"""
|
"""带缓存获取子节点"""
|
||||||
cache_key = f"{config.app_id}:children:{node_token}"
|
cache_key = f"{config.app_id}:children:{space_id}:{node_token}"
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
|
||||||
if cache_key in cls._content_cache:
|
if cache_key in cls._content_cache:
|
||||||
@@ -467,7 +505,7 @@ class FeishuKnowledgeService:
|
|||||||
if now - ts < cls._CACHE_TTL:
|
if now - ts < cls._CACHE_TTL:
|
||||||
return eval(cached_data) # noqa: S307
|
return eval(cached_data) # noqa: S307
|
||||||
|
|
||||||
children = _get_wiki_children(node_token, config)
|
children = _get_wiki_children(space_id, node_token, config)
|
||||||
cls._content_cache[cache_key] = (str(children), now)
|
cls._content_cache[cache_key] = (str(children), now)
|
||||||
return children
|
return children
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user