Initial DocsMCP stack
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
"""Async docs-api client for the WebUI."""
|
||||
import os
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from httpx import AsyncClient, Timeout
|
||||
|
||||
|
||||
class DocsAPIClient:
|
||||
"""Small async HTTP client for the docs-api backend."""
|
||||
|
||||
def __init__(self, base_url: Optional[str] = None, api_key: Optional[str] = None):
|
||||
self.base_url = (base_url or os.environ.get("DOCS_API_URL", "http://docs-api:8787")).rstrip("/")
|
||||
self.api_key = api_key if api_key is not None else os.environ.get("WEBUI_API_KEY")
|
||||
self.headers = {"X-API-Key": self.api_key} if self.api_key else {}
|
||||
self._client: Optional[AsyncClient] = None
|
||||
|
||||
async def _get_client(self) -> AsyncClient:
|
||||
if self._client is None or self._client.is_closed:
|
||||
self._client = AsyncClient(
|
||||
base_url=self.base_url,
|
||||
headers=self.headers,
|
||||
timeout=Timeout(120.0),
|
||||
)
|
||||
return self._client
|
||||
|
||||
async def request(self, method: str, path: str, **kwargs: Any) -> Dict[str, Any]:
|
||||
client = await self._get_client()
|
||||
resp = await client.request(method, path, **kwargs)
|
||||
if resp.status_code >= 400:
|
||||
raise RuntimeError(f"{method} {path} failed: {resp.status_code} {resp.text}")
|
||||
if resp.headers.get("content-type", "").startswith("application/json"):
|
||||
data = resp.json()
|
||||
return data if isinstance(data, dict) else {"data": data}
|
||||
return {"data": resp.text}
|
||||
|
||||
async def get(self, path: str, **kwargs: Any) -> Dict[str, Any]:
|
||||
return await self.request("GET", path, **kwargs)
|
||||
|
||||
async def post(self, path: str, **kwargs: Any) -> Dict[str, Any]:
|
||||
return await self.request("POST", path, **kwargs)
|
||||
|
||||
async def delete(self, path: str, **kwargs: Any) -> Dict[str, Any]:
|
||||
return await self.request("DELETE", path, **kwargs)
|
||||
|
||||
async def health(self) -> Dict[str, Any]:
|
||||
try:
|
||||
return await self.get("/health")
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": str(e)}
|
||||
|
||||
async def upload_file(self, library_id: str, filename: str, content: bytes) -> Dict[str, Any]:
|
||||
files = {"file": (filename, content)}
|
||||
return await self.post(f"/api/v1/upload/{library_id}", files=files)
|
||||
|
||||
async def close(self) -> None:
|
||||
if self._client is not None and not self._client.is_closed:
|
||||
await self._client.aclose()
|
||||
|
||||
|
||||
_client_instance: Optional[DocsAPIClient] = None
|
||||
|
||||
|
||||
async def get_client() -> DocsAPIClient:
|
||||
global _client_instance
|
||||
if _client_instance is None:
|
||||
_client_instance = DocsAPIClient()
|
||||
return _client_instance
|
||||
|
||||
|
||||
async def close_client() -> None:
|
||||
if _client_instance is not None:
|
||||
await _client_instance.close()
|
||||
Reference in New Issue
Block a user