Skip to main content
Glama
custom_http.py5.01 kB
"""Generic HTTP API processor wrapper for custom document processing services.""" import logging from collections.abc import Awaitable, Callable from typing import Any, Optional import httpx from .base import DocumentProcessor, ProcessingResult, ProcessorError logger = logging.getLogger(__name__) class CustomHTTPProcessor(DocumentProcessor): """Generic HTTP API processor wrapper. Allows integration with any custom document processing API that follows a simple request/response pattern. This makes it easy to integrate your own text extraction services without writing a full processor. Expected API Contract: - POST request with file as multipart/form-data - Response: {"text": "extracted text", "metadata": {...}} Example: processor = CustomHTTPProcessor( name="my_ocr", api_url="https://my-ocr-service.com/process", api_key="secret", supported_types={"application/pdf", "image/jpeg"}, ) result = await processor.process(pdf_bytes, "application/pdf") """ def __init__( self, api_url: str, api_key: Optional[str] = None, timeout: int = 60, supported_types: Optional[set[str]] = None, name: str = "custom", ): """Initialize custom HTTP processor. Args: api_url: Your API endpoint (should accept POST with multipart/form-data) api_key: Optional API key for authentication (sent as Bearer token) timeout: Request timeout in seconds (default: 60) supported_types: MIME types your API supports name: Unique name for this processor (default: "custom") """ self.api_url = api_url self.api_key = api_key self.timeout = timeout self._name = name self._supported_types = supported_types or set() logger.info(f"Initialized CustomHTTPProcessor: {name} -> {api_url}") @property def name(self) -> str: return self._name @property def supported_mime_types(self) -> set[str]: return self._supported_types async def process( self, content: bytes, content_type: str, filename: Optional[str] = None, options: Optional[dict[str, Any]] = None, progress_callback: Optional[ Callable[[float, Optional[float], Optional[str]], Awaitable[None]] ] = None, ) -> ProcessingResult: """Process via custom HTTP API. Args: content: Document bytes content_type: MIME type filename: Optional filename options: Custom options (passed as form data to API) Returns: ProcessingResult with extracted text and metadata Raises: ProcessorError: If API call fails """ options = options or {} # Prepare request files = {"file": (filename or "document", content, content_type)} headers = {} if self.api_key: headers["Authorization"] = f"Bearer {self.api_key}" try: async with httpx.AsyncClient(timeout=self.timeout) as client: response = await client.post( self.api_url, files=files, headers=headers, data=options, # Pass options as form data ) response.raise_for_status() # Parse response result = response.json() text = result.get("text", "") metadata = result.get("metadata", {}) logger.debug( f"Custom processor '{self.name}' extracted {len(text)} characters" ) return ProcessingResult( text=text, metadata=metadata, processor=self.name, success=True, ) except httpx.HTTPError as e: logger.error(f"Custom processor '{self.name}' HTTP error: {e}") raise ProcessorError(f"API call failed: {str(e)}") from e except Exception as e: logger.error(f"Custom processor '{self.name}' failed: {e}") raise ProcessorError(f"Processing failed: {str(e)}") from e async def health_check(self) -> bool: """Check if custom API is available. Returns: True if API responds with status < 500 """ try: async with httpx.AsyncClient(timeout=5) as client: # Try GET request to check availability response = await client.get( self.api_url, headers={"User-Agent": "nextcloud-mcp-server"}, ) return response.status_code < 500 except Exception as e: logger.warning(f"Custom processor '{self.name}' health check failed: {e}") return False

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/No-Smoke/nextcloud-mcp-comprehensive'

If you have feedback or need assistance with the MCP directory API, please join our Discord server