Coverage for src/qdrant_loader_mcp_server/search/enhanced/kg/models.py: 95%

73 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-08 06:06 +0000

1from __future__ import annotations 

2 

3import uuid 

4from dataclasses import dataclass, field 

5from enum import Enum 

6from typing import Any 

7 

8 

9class NodeType(Enum): 

10 DOCUMENT = "document" 

11 SECTION = "section" 

12 ENTITY = "entity" 

13 TOPIC = "topic" 

14 CONCEPT = "concept" 

15 

16 

17class RelationshipType(Enum): 

18 CONTAINS = "contains" 

19 PART_OF = "part_of" 

20 SIBLING = "sibling" 

21 MENTIONS = "mentions" 

22 DISCUSSES = "discusses" 

23 RELATES_TO = "relates_to" 

24 SIMILAR_TO = "similar_to" 

25 REFERENCES = "references" 

26 CITES = "cites" 

27 BUILDS_ON = "builds_on" 

28 CONTRADICTS = "contradicts" 

29 CO_OCCURS = "co_occurs" 

30 CATEGORIZED_AS = "categorized_as" 

31 

32 

33@dataclass 

34class GraphNode: 

35 node_type: NodeType 

36 title: str 

37 id: str | None = None 

38 content: str | None = None 

39 metadata: dict[str, Any] = field(default_factory=dict) 

40 

41 centrality_score: float = 0.0 

42 authority_score: float = 0.0 

43 hub_score: float = 0.0 

44 

45 entities: list[str] = field(default_factory=list) 

46 topics: list[str] = field(default_factory=list) 

47 concepts: list[str] = field(default_factory=list) 

48 keywords: list[str] = field(default_factory=list) 

49 

50 def __post_init__(self): 

51 if self.id is None or self.id == "": 

52 # Deterministic UUIDv5 id derived from stable inputs (node_type + title) 

53 # Fixed namespace ensures stable generation across runs/processes 

54 node_namespace = uuid.UUID("8f5b3e78-9b8c-4f07-b54e-27f7ac1d5a11") 

55 name = f"{self.node_type.value}::{self.title}" 

56 deterministic_uuid = uuid.uuid5(node_namespace, name) 

57 self.id = f"{self.node_type.value}_{deterministic_uuid}" 

58 

59 

60@dataclass 

61class GraphEdge: 

62 source_id: str 

63 target_id: str 

64 relationship_type: RelationshipType 

65 weight: float = 1.0 

66 metadata: dict[str, Any] = field(default_factory=dict) 

67 evidence: list[str] = field(default_factory=list) 

68 confidence: float = 1.0 

69 

70 def __post_init__(self): 

71 self.weight = max(0.0, min(1.0, self.weight)) 

72 self.confidence = max(0.0, min(1.0, self.confidence)) 

73 

74 

75class TraversalStrategy(Enum): 

76 BREADTH_FIRST = "breadth_first" 

77 DEPTH_FIRST = "depth_first" 

78 WEIGHTED = "weighted" 

79 CENTRALITY = "centrality" 

80 SEMANTIC = "semantic" 

81 HIERARCHICAL = "hierarchical" 

82 

83 

84@dataclass 

85class TraversalResult: 

86 path: list[str] 

87 nodes: list[GraphNode] 

88 edges: list[GraphEdge] 

89 total_weight: float 

90 semantic_score: float 

91 hop_count: int 

92 reasoning_path: list[str]