1167644824
Check Cross-Plugin Imports / check (push) Has been cancelled
All built-in plugins should be auto-activated. The is_core flag was only set on some plugins, leaving Mail, DMS, Calendar, Automation, Unified Search etc. inactive by default.
131 lines
4.5 KiB
Python
131 lines
4.5 KiB
Python
"""Unified Search plugin class and manifest."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from app.plugins.base import BasePlugin
|
|
from app.plugins.manifest import PluginManifest, PluginRouteDef, FrontendPageRoute
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class UnifiedSearchPlugin(BasePlugin):
|
|
"""Hybrid full-text and semantic search across all CRM entities."""
|
|
|
|
manifest = PluginManifest(
|
|
name="unified_search",
|
|
version="1.0.0",
|
|
display_name="Unified Search",
|
|
description=(
|
|
"Hybrid full-text (PostgreSQL FTS) and semantic (pgvector) search "
|
|
"with KI query understanding and RRF rank fusion across all CRM data."
|
|
),
|
|
dependencies=[],
|
|
routes=[
|
|
PluginRouteDef(
|
|
path="/api/v1/search",
|
|
module="app.plugins.builtins.unified_search.routes",
|
|
router_attr="router",
|
|
),
|
|
],
|
|
events=[
|
|
"mail.synced",
|
|
"file.uploaded",
|
|
"contact.created",
|
|
"contact.updated",
|
|
"calendar.entry.created",
|
|
],
|
|
migrations=["0001_initial.sql", "0002_embeddings.sql", "0003_add_deleted_at.sql"],
|
|
permissions=["search:read", "search:admin"],
|
|
is_core=True,
|
|
page_routes=[
|
|
FrontendPageRoute(path='/search', component='@/pages/GlobalSearchResults', protected=True),
|
|
],
|
|
author="LeoCRM Team",
|
|
min_app_version="1.0.0",
|
|
contract_version="1.0.0",
|
|
)
|
|
|
|
async def on_activate(self, db, service_container, event_bus) -> None:
|
|
"""Register search providers on activation."""
|
|
await super().on_activate(db, service_container, event_bus)
|
|
try:
|
|
from app.plugins.builtins.unified_search.provider_registry import (
|
|
auto_register_providers,
|
|
)
|
|
await auto_register_providers(db)
|
|
logger.info("Unified Search providers auto-registered")
|
|
except Exception:
|
|
logger.exception("Failed to auto-register search providers")
|
|
|
|
async def on_deactivate(self, db, service_container, event_bus) -> None:
|
|
"""Clear provider registry on deactivation."""
|
|
# Contract abmelden
|
|
from app.plugins.builtins.contracts import get_contract_registry
|
|
get_contract_registry().unregister(self.manifest.name)
|
|
from app.plugins.builtins.unified_search.provider_registry import (
|
|
get_search_registry,
|
|
)
|
|
registry = get_search_registry()
|
|
registry.clear()
|
|
await super().on_deactivate(db, service_container, event_bus)
|
|
|
|
# ─── Event Handlers ───
|
|
|
|
async def on_mail_synced(self, payload: dict[str, Any]) -> None:
|
|
"""Enqueue embedding jobs for synced mails."""
|
|
from app.core.jobs import enqueue_job
|
|
|
|
mail_ids = payload.get("mail_ids", [])
|
|
if mail_ids:
|
|
await enqueue_job("index_mails", mail_ids)
|
|
|
|
async def on_file_uploaded(self, payload: dict[str, Any]) -> None:
|
|
"""Enqueue file indexing job."""
|
|
from app.core.jobs import enqueue_job
|
|
|
|
file_id = payload.get("file_id")
|
|
if file_id:
|
|
await enqueue_job("index_file", file_id)
|
|
|
|
async def on_contact_created(self, payload: dict[str, Any]) -> None:
|
|
from app.core.jobs import enqueue_job
|
|
|
|
contact_id = payload.get("contact_id")
|
|
if contact_id:
|
|
await enqueue_job("index_contact", contact_id)
|
|
|
|
async def on_contact_updated(self, payload: dict[str, Any]) -> None:
|
|
from app.core.jobs import enqueue_job
|
|
|
|
contact_id = payload.get("contact_id")
|
|
if contact_id:
|
|
await enqueue_job("index_contact", contact_id)
|
|
|
|
async def on_calendar_entry_created(self, payload: dict[str, Any]) -> None:
|
|
from app.core.jobs import enqueue_job
|
|
|
|
entry_id = payload.get("entry_id")
|
|
if entry_id:
|
|
await enqueue_job("index_event", entry_id)
|
|
|
|
def get_notification_types(self) -> list[dict[str, Any]]:
|
|
return [
|
|
{
|
|
"type_key": "search_error",
|
|
"category": "search",
|
|
"label": "Suchfehler",
|
|
"description": "Fehler bei der Suchausführung",
|
|
"is_enabled_by_default": True,
|
|
},
|
|
{
|
|
"type_key": "search_reindex_complete",
|
|
"category": "search",
|
|
"label": "Reindex abgeschlossen",
|
|
"description": "Neuindizierung abgeschlossen",
|
|
"is_enabled_by_default": False,
|
|
},
|
|
]
|