""" Graph models for Library Desk Neo4j operations. Provides models for knowledge graph nodes, relationships, and queries. """ from pydantic import BaseModel, Field from typing import List, Dict, Any, Optional from datetime import datetime class GraphNode(BaseModel): """Graph node representation.""" id: str = Field(..., description="Node ID") labels: List[str] = Field(..., description="Node labels") properties: Dict[str, Any] = Field(default_factory=dict, description="Node properties") class GraphRelationship(BaseModel): """Graph relationship representation.""" id: str = Field(..., description="Relationship ID") type: str = Field(..., description="Relationship type") start_node: str = Field(..., description="Start node ID") end_node: str = Field(..., description="End node ID") properties: Dict[str, Any] = Field(default_factory=dict, description="Relationship properties") class GraphNodeDetail(BaseModel): """Detailed node with relationships.""" node: GraphNode = Field(..., description="Node data") relationships: List[GraphRelationship] = Field( default_factory=list, description="Connected relationships" ) related_nodes: List[GraphNode] = Field( default_factory=list, description="Connected nodes" ) class CypherQueryRequest(BaseModel): """Request to execute a Cypher query.""" query: str = Field(..., description="Cypher query to execute") parameters: Dict[str, Any] = Field( default_factory=dict, description="Query parameters" ) user: str = Field( default="jpmschweitzer", description="User for filtering (automatically scopes query)" ) class CypherQueryResponse(BaseModel): """Response from Cypher query execution.""" results: List[Dict[str, Any]] = Field(..., description="Query results") count: int = Field(..., description="Number of results") query_time_ms: float = Field(..., description="Query execution time in milliseconds") class UpdateFromPageRequest(BaseModel): """Request to update graph from a wiki page.""" page_id: int = Field(..., description="Wiki page ID to process") user: str = Field( default="jpmschweitzer", description="User identifier for namespace scoping" ) force_refresh: bool = Field( default=False, description="Force re-extraction even if page hasn't changed" ) class EntityMention(BaseModel): """Extracted entity mention.""" text: str = Field(..., description="Entity text") type: str = Field(..., description="Entity type (Person, Project, Concept, etc.)") confidence: float = Field(default=1.0, description="Extraction confidence (0-1)") class GraphUpdateSummary(BaseModel): """Summary of graph update operation.""" page_id: int = Field(..., description="Page ID processed") page_title: str = Field(..., description="Page title") nodes_created: int = Field(default=0, description="New nodes created") nodes_updated: int = Field(default=0, description="Existing nodes updated") relationships_created: int = Field(default=0, description="New relationships created") entities_extracted: List[EntityMention] = Field( default_factory=list, description="Entities extracted from page" ) processing_time_ms: float = Field(..., description="Processing time in milliseconds") success: bool = Field(default=True, description="Whether update succeeded") error_message: Optional[str] = Field(default=None, description="Error message if failed") class NodeListResponse(BaseModel): """Response for node listing.""" nodes: List[GraphNode] = Field(..., description="List of nodes") total: int = Field(..., description="Total number of nodes") user: str = Field(..., description="User filter applied") class MindMapNode(BaseModel): """Mind map node for visualization.""" id: str = Field(..., description="Node ID") label: str = Field(..., description="Node label/name") type: str = Field(..., description="Node type") size: int = Field(default=10, description="Visual size") color: Optional[str] = Field(default=None, description="Node color") class MindMapLink(BaseModel): """Mind map link for visualization.""" source: str = Field(..., description="Source node ID") target: str = Field(..., description="Target node ID") type: str = Field(..., description="Relationship type") strength: float = Field(default=1.0, description="Link strength") class MindMapResponse(BaseModel): """Mind map data for D3.js or similar visualization.""" nodes: List[MindMapNode] = Field(..., description="Graph nodes") links: List[MindMapLink] = Field(..., description="Graph edges") center_node: str = Field(..., description="Central node ID") depth: int = Field(..., description="Traversal depth")