feat: add smart page creation endpoint with HybridRAG research
Add POST /wiki/pages/smart-create endpoint that combines research with content generation for the librarian agent: - Run HybridRAG search on topic (wiki + graph + web) - Use LLM (WikiPageWriter) to synthesize findings into wiki content - Create page with proper attribution and sources - Schedule background tasks for vector/graph indexing - Apply bidirectional entity linking (forward + backward links) New files: - src/services/entity_linking_utils.py - shared entity linking helper Modified: - src/models/wiki.py - WikiSmartCreateRequest/Response models - src/services/wiki_service.py - smart_create_page() method - src/routers/wiki.py - /pages/smart-create endpoint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+127
-2
@@ -13,7 +13,8 @@ import logging
|
||||
from src.models.wiki import (
|
||||
WikiPage, WikiPageList, WikiPageCreate, WikiPageUpdate, WikiPageMove,
|
||||
WikiOperationResponse, WikiSearchResponse,
|
||||
DossierList, WikiSearchResult
|
||||
DossierList, WikiSearchResult,
|
||||
WikiSmartCreateRequest, WikiSmartCreateResponse
|
||||
)
|
||||
from src.services.wiki_service import WikiService
|
||||
from src.services.graph_service import GraphService
|
||||
@@ -22,8 +23,15 @@ from src.clients.wikijs_client import WikiJSClient
|
||||
from src.clients.neo4j_client import Neo4jClient
|
||||
from src.clients.qdrant_client import QdrantClientWrapper
|
||||
from src.clients.ollama_client import OllamaClient
|
||||
from src.core.dependencies import WikiJSDep, Neo4jDep, QdrantDep, OllamaDep, verify_api_key
|
||||
from src.core.dependencies import (
|
||||
WikiJSDep, Neo4jDep, QdrantDep, OllamaDep, SearXNGDep,
|
||||
verify_api_key, get_settings, get_hybrid_rag_service, get_ingestion_service
|
||||
)
|
||||
from src.core.multi_tenancy import DEFAULT_USER
|
||||
from src.services.hybrid_rag_service import HybridRAGService
|
||||
from src.services.wiki_page_writer import WikiPageWriter
|
||||
from src.services.entity_linking_utils import apply_bidirectional_entity_linking
|
||||
from src.config import Settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -163,6 +171,123 @@ async def create_page(
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.post("/pages/smart-create", response_model=WikiSmartCreateResponse, status_code=201)
|
||||
async def smart_create_page(
|
||||
request: WikiSmartCreateRequest,
|
||||
background_tasks: BackgroundTasks,
|
||||
wiki_client: WikiJSDep,
|
||||
neo4j_client: Neo4jDep,
|
||||
qdrant_client: QdrantDep,
|
||||
ollama_client: OllamaDep,
|
||||
searxng_client: SearXNGDep,
|
||||
settings: Settings = Depends(get_settings),
|
||||
api_key: str = Depends(verify_api_key)
|
||||
):
|
||||
"""
|
||||
Create wiki page with intelligent research.
|
||||
|
||||
Combines HybridRAG search with LLM content generation to create
|
||||
rich, well-researched wiki pages in a single API call.
|
||||
|
||||
**Process:**
|
||||
1. Runs HybridRAG search on the topic (wiki + graph + web)
|
||||
2. Uses LLM to synthesize findings into structured wiki content
|
||||
3. Creates the page with proper attribution/sources
|
||||
4. Indexes into vectors + knowledge graph (background)
|
||||
5. Applies bidirectional entity linking (background)
|
||||
|
||||
**Example Request:**
|
||||
```json
|
||||
{
|
||||
"topic": "Docker orchestration patterns",
|
||||
"path": "/technology/containers/docker-orchestration",
|
||||
"tags": ["technology", "devops", "containers"],
|
||||
"user": "jpmschweitzer",
|
||||
"include_web_research": true,
|
||||
"include_wiki_search": true
|
||||
}
|
||||
```
|
||||
|
||||
**Returns:**
|
||||
- Created page with ID, path, content
|
||||
- Research summary (wiki/web/graph result counts)
|
||||
- Entity linking statistics (forward/backward links)
|
||||
"""
|
||||
try:
|
||||
user = request.user or DEFAULT_USER
|
||||
|
||||
# Build services
|
||||
wiki_service = WikiService(wiki_client)
|
||||
vector_service = VectorService(qdrant_client, wiki_client, ollama_client)
|
||||
graph_service = GraphService(neo4j_client, wiki_client)
|
||||
hybrid_rag_service = HybridRAGService(
|
||||
vector_service=vector_service,
|
||||
graph_service=graph_service,
|
||||
searxng_client=searxng_client,
|
||||
ollama_client=ollama_client,
|
||||
settings=settings
|
||||
)
|
||||
wiki_page_writer = WikiPageWriter(ollama_client=ollama_client)
|
||||
|
||||
# Step 1-5: Research + Generate + Create page
|
||||
page, research_data = await wiki_service.smart_create_page(
|
||||
topic=request.topic,
|
||||
user=user,
|
||||
path=request.path,
|
||||
tags=request.tags,
|
||||
hybrid_rag_service=hybrid_rag_service,
|
||||
wiki_page_writer=wiki_page_writer,
|
||||
include_web=request.include_web_research,
|
||||
include_wiki=request.include_wiki_search
|
||||
)
|
||||
|
||||
# Schedule graph and vector updates in background
|
||||
background_tasks.add_task(
|
||||
graph_service.update_from_page,
|
||||
page_id=page.id,
|
||||
user=user
|
||||
)
|
||||
background_tasks.add_task(
|
||||
vector_service.update_from_page,
|
||||
page_id=page.id,
|
||||
user=user
|
||||
)
|
||||
|
||||
# Schedule bidirectional entity linking in background
|
||||
async def run_entity_linking():
|
||||
ingestion_service = get_ingestion_service()
|
||||
return await apply_bidirectional_entity_linking(
|
||||
page_id=page.id,
|
||||
page_title=page.title,
|
||||
user=user,
|
||||
neo4j_client=neo4j_client,
|
||||
wiki_service=wiki_service,
|
||||
ingestion_service=ingestion_service
|
||||
)
|
||||
|
||||
background_tasks.add_task(run_entity_linking)
|
||||
|
||||
logger.info(
|
||||
f"Smart page created: id={page.id}, path={page.path}, "
|
||||
f"sources={research_data['sources_used']}"
|
||||
)
|
||||
|
||||
return WikiSmartCreateResponse(
|
||||
page=page,
|
||||
research_summary=research_data["research_summary"],
|
||||
sources_used=research_data["sources_used"],
|
||||
search_id=research_data["search_id"],
|
||||
entity_linking={"forward_links": 0, "backward_links": 0, "pages_updated": 0}
|
||||
# Note: entity_linking stats are 0 here as it runs in background
|
||||
)
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to smart create page: {e}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
|
||||
@router.put("/pages/{page_id}", response_model=WikiPage)
|
||||
async def update_page(
|
||||
page_id: int,
|
||||
|
||||
Reference in New Issue
Block a user