|
|
|
|
|
import uuid |
|
from typing import Dict, List, Optional |
|
from models import GraphExport |
|
|
|
class Concept: |
|
def __init__( |
|
self, |
|
id: Optional[str] = None, |
|
label: str = "", |
|
description: str = "", |
|
tags: Optional[List[str]] = None |
|
): |
|
self.id = id or str(uuid.uuid4()) |
|
self.label = label |
|
self.description = description |
|
self.tags = tags or [] |
|
|
|
def to_dict(self): |
|
return { |
|
"id": self.id, |
|
"label": self.label, |
|
"description": self.description, |
|
"tags": self.tags |
|
} |
|
|
|
@staticmethod |
|
def from_dict(data): |
|
return Concept( |
|
id=data.get("id"), |
|
label=data.get("label", ""), |
|
description=data.get("description", ""), |
|
tags=data.get("tags", []) |
|
) |
|
|
|
class Edge: |
|
def __init__(self, source: str, target: str, relation: str = "related_to"): |
|
self.source = source |
|
self.target = target |
|
self.relation = relation |
|
|
|
def to_dict(self): |
|
return { |
|
"source": self.source, |
|
"target": self.target, |
|
"relation": self.relation |
|
} |
|
|
|
@staticmethod |
|
def from_dict(data): |
|
return Edge( |
|
source=data["source"], |
|
target=data["target"], |
|
relation=data.get("relation", "related_to") |
|
) |
|
|
|
|
|
class ConceptStore: |
|
def __init__(self): |
|
self.concepts: Dict[str, Concept] = {} |
|
self.edges: List[Edge] = [] |
|
|
|
def add(self, concept: Concept): |
|
self.concepts[concept.id] = concept |
|
|
|
def get(self, concept_id: str) -> Optional[dict]: |
|
concept = self.concepts.get(concept_id) |
|
return concept.to_dict() if concept else None |
|
|
|
def add_edge(self, edge: Edge): |
|
if not any( |
|
e.source == edge.source and |
|
e.target == edge.target and |
|
e.relation == edge.relation |
|
for e in self.edges |
|
): |
|
self.edges.append(edge) |
|
|
|
def find_by_label(self, label: str) -> Optional[Concept]: |
|
for c in self.concepts.values(): |
|
if c.label == label: |
|
return c |
|
return None |
|
|
|
def import_from_json(self, data: dict) -> dict: |
|
nodes = data.get("nodes", []) |
|
edges = data.get("edges", []) |
|
|
|
if not isinstance(nodes, list) or not isinstance(edges, list): |
|
raise ValueError("Invalid format: 'nodes' and 'edges' must be lists") |
|
|
|
imported_nodes = 0 |
|
imported_edges = 0 |
|
|
|
for c in nodes: |
|
try: |
|
concept = Concept.from_dict(c) |
|
self.add(concept) |
|
imported_nodes += 1 |
|
except Exception as e: |
|
print(f"Failed to import concept: {e}") |
|
|
|
for e in edges: |
|
try: |
|
edge = Edge.from_dict(e) |
|
self.add_edge(edge) |
|
imported_edges += 1 |
|
except Exception as e: |
|
print(f"Failed to import edge: {e}") |
|
|
|
return { |
|
"status": "ok", |
|
"imported_nodes": imported_nodes, |
|
"imported_edges": imported_edges |
|
} |
|
|
|
def export_as_json(self) -> GraphExport: |
|
return GraphExport( |
|
nodes=[c.to_dict() for c in self.concepts.values()], |
|
edges=[e.to_dict() for e in self.edges] |
|
) |
|
|
|
def all_concepts(self): |
|
return [c.to_dict() for c in self.concepts.values()] |
|
|
|
def all_edges(self): |
|
return [e.to_dict() for e in self.edges] |
|
|
|
def remove_concept(self, concept_id: str): |
|
if concept_id in self.concepts: |
|
del self.concepts[concept_id] |
|
self.edges = [e for e in self.edges if e.source != concept_id and e.target != concept_id] |
|
|
|
def remove_edge(self, source_id: str, target_id: str, relation: str): |
|
self.edges = [ |
|
e for e in self.edges |
|
if not (e.source == source_id and e.target == target_id and e.relation == relation) |
|
] |
|
|
|
def debug_print(self): |
|
print("Concepts:") |
|
for c in self.concepts.values(): |
|
print(c.to_dict()) |
|
print("\nEdges:") |
|
for e in self.edges: |
|
print(e.to_dict()) |
|
|