feat: add Paperless-ngx document storage integration
- Add /documents router with webhook, upload, search, health endpoints - Create DocumentSyncService for indexing documents to vectors/graph - Add PaperlessClient for REST API integration - Configure dependency injection for Paperless client - Add document models for webhook payloads and responses - Event-driven architecture via Paperless workflow webhooks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ from src.clients.wikijs_client import WikiJSClient
|
||||
from src.clients.searxng_client import SearXNGClient
|
||||
from src.clients.ollama_client import OllamaClient
|
||||
from src.clients.content_extractor import ContentExtractor
|
||||
from src.clients.paperless_client import PaperlessClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -155,6 +156,28 @@ def get_content_extractor() -> ContentExtractor:
|
||||
return extractor
|
||||
|
||||
|
||||
@lru_cache
|
||||
def get_paperless_client() -> PaperlessClient:
|
||||
"""
|
||||
Get Paperless-ngx client singleton.
|
||||
|
||||
Returns:
|
||||
Initialized Paperless-ngx REST API client
|
||||
|
||||
Note: Returns None-like client if paperless_token is not configured
|
||||
"""
|
||||
settings = get_settings()
|
||||
if not settings.paperless_token:
|
||||
logger.warning("Paperless token not configured - document storage disabled")
|
||||
client = PaperlessClient(
|
||||
base_url=settings.paperless_url,
|
||||
token=settings.paperless_token,
|
||||
timeout=settings.paperless_timeout
|
||||
)
|
||||
logger.debug(f"Created Paperless client: {settings.paperless_url}")
|
||||
return client
|
||||
|
||||
|
||||
# Type aliases for FastAPI endpoint dependencies
|
||||
# Usage: def my_endpoint(neo4j: Neo4jDep):
|
||||
Neo4jDep = Annotated[Neo4jClient, Depends(get_neo4j_client)]
|
||||
@@ -164,6 +187,7 @@ SearXNGDep = Annotated[SearXNGClient, Depends(get_searxng_client)]
|
||||
OllamaDep = Annotated[OllamaClient, Depends(get_ollama_client)]
|
||||
RedisDep = Annotated[aioredis.Redis, Depends(get_redis_client)]
|
||||
ContentExtractorDep = Annotated[ContentExtractor, Depends(get_content_extractor)]
|
||||
PaperlessDep = Annotated[PaperlessClient, Depends(get_paperless_client)]
|
||||
|
||||
|
||||
# Lifecycle management functions
|
||||
@@ -202,6 +226,21 @@ async def startup_clients():
|
||||
logger.error(f"✗ Ollama health check failed: {e}")
|
||||
pass
|
||||
|
||||
# Check Paperless availability
|
||||
settings = get_settings()
|
||||
if settings.paperless_token:
|
||||
try:
|
||||
paperless = get_paperless_client()
|
||||
is_healthy = await paperless.health_check()
|
||||
if is_healthy:
|
||||
logger.info(f"✓ Paperless-ngx ready: {settings.paperless_url}")
|
||||
else:
|
||||
logger.warning("✗ Paperless-ngx not responding")
|
||||
except Exception as e:
|
||||
logger.error(f"✗ Paperless health check failed: {e}")
|
||||
else:
|
||||
logger.info("○ Paperless-ngx not configured (document storage disabled)")
|
||||
|
||||
# Qdrant, Wiki.js, SearXNG are lazy-initialized
|
||||
logger.info("Service clients startup complete")
|
||||
|
||||
@@ -230,7 +269,8 @@ async def shutdown_clients():
|
||||
clients_to_close = [
|
||||
("Wiki.js", get_wikijs_client()),
|
||||
("SearXNG", get_searxng_client()),
|
||||
("Ollama", get_ollama_client())
|
||||
("Ollama", get_ollama_client()),
|
||||
("Paperless", get_paperless_client()),
|
||||
]
|
||||
|
||||
for name, client in clients_to_close:
|
||||
@@ -312,6 +352,18 @@ async def check_service_health() -> dict:
|
||||
logger.error(f"Ollama health check failed: {e}")
|
||||
health["ollama"] = False
|
||||
|
||||
# Paperless-ngx
|
||||
settings = get_settings()
|
||||
if settings.paperless_token:
|
||||
try:
|
||||
paperless = get_paperless_client()
|
||||
health["paperless"] = await paperless.health_check()
|
||||
except Exception as e:
|
||||
logger.error(f"Paperless health check failed: {e}")
|
||||
health["paperless"] = False
|
||||
else:
|
||||
health["paperless"] = None # Not configured
|
||||
|
||||
return health
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user