64 lines
2.5 KiB
Python
64 lines
2.5 KiB
Python
import logging
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
import httpx
|
||
|
||
from app.core.config import get_settings
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class LightRAGWebhook:
|
||
"""封装与 LightRAG 的交互。
|
||
|
||
说明:当前 LightRAG(>=1.4.x) 的“文本入库”接口为 `/documents/text` / `/documents/texts`,
|
||
旧版项目里使用的 `/ingest` 已不存在(回档后代码仍在调用旧接口)。
|
||
"""
|
||
|
||
def __init__(self, base_url: Optional[str] = None):
|
||
settings = get_settings()
|
||
self.base_url = base_url or settings.lightrag_url.rstrip("/")
|
||
self.api_key = settings.lightrag_api_key
|
||
|
||
def _headers(self) -> dict:
|
||
headers: dict = {}
|
||
if self.api_key:
|
||
headers["X-API-Key"] = self.api_key
|
||
return headers
|
||
|
||
async def ingest_text(self, file_source: str, text: str) -> Optional[str]:
|
||
"""向 LightRAG 提交一段文本,触发后台索引。
|
||
|
||
返回 track_id(如果服务端返回),便于后续排查。
|
||
"""
|
||
if not text.strip():
|
||
logger.info("空文本,跳过推送到 LightRAG(file_source=%s)", file_source)
|
||
return None
|
||
payload = {"text": text, "file_source": file_source}
|
||
async with httpx.AsyncClient(timeout=60.0, headers=self._headers()) as client:
|
||
resp = await client.post(f"{self.base_url}/documents/text", json=payload)
|
||
resp.raise_for_status()
|
||
data = resp.json()
|
||
track_id = data.get("track_id") if isinstance(data, dict) else None
|
||
logger.info("LightRAG 入库请求已提交(file_source=%s, track_id=%s)", file_source, track_id)
|
||
return track_id
|
||
|
||
async def delete_documents(self, doc_ids: List[str]) -> Dict[str, Any]:
|
||
"""请求 LightRAG 删除文档(delete_document 为后台任务)。
|
||
|
||
返回服务端响应(通常包含 status: deletion_started/busy/not_allowed)。
|
||
"""
|
||
if not doc_ids:
|
||
return {"status": "not_allowed", "message": "doc_ids 为空", "doc_id": ""}
|
||
|
||
payload = {
|
||
"doc_ids": doc_ids,
|
||
"delete_file": False,
|
||
"delete_llm_cache": False,
|
||
}
|
||
async with httpx.AsyncClient(timeout=60.0, headers=self._headers()) as client:
|
||
resp = await client.request("DELETE", f"{self.base_url}/documents/delete_document", json=payload)
|
||
resp.raise_for_status()
|
||
data = resp.json()
|
||
return data if isinstance(data, dict) else {"raw": data}
|