mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
40 KiB
40 KiB
In [ ]:
%pip install -qU semantica networkx matplotlib plotly pandas faiss-cpu beautifulsoup4 groq sentence-transformers scikit-learn
In [ ]:
In [ ]:
import os
os.environ["GROQ_API_KEY"] = os.getenv("GROQ_API_KEY", "")
# Configuration constants
EMBEDDING_DIMENSION = 384
EMBEDDING_MODEL = "all-MiniLM-L6-v2"
CHUNK_SIZE = 500
CHUNK_OVERLAP = 50
TEMPORAL_GRANULARITY = "minute"
In [ ]:
from semantica.ingest import StreamIngestor, WebIngestor, FileIngestor
import os
from contextlib import redirect_stderr
from io import StringIO
os.makedirs("data", exist_ok=True)
all_documents = []
# ============================================================================
# REAL DATA SOURCE 1: CSV Transaction Data
# ============================================================================
# Ingest transaction data from CSV file with comprehensive fraud indicators
print("📊 Ingesting transaction data from CSV...")
csv_path = "data/transactions.csv"
file_ingestor = FileIngestor()
try:
csv_documents = file_ingestor.ingest(csv_path)
for doc in csv_documents:
if not hasattr(doc, 'metadata'):
doc.metadata = {}
doc.metadata['source'] = 'Transaction CSV'
doc.metadata['data_type'] = 'transaction'
all_documents.append(doc)
print(f" ✅ Loaded {len(csv_documents)} documents from CSV")
except Exception as e:
print(f" ⚠️ CSV ingestion failed: {e}")
# ============================================================================
# REAL DATA SOURCE 2: JSON Account & Fraud Pattern Data
# ============================================================================
# Ingest account metadata, device information, and fraud patterns from JSON
print("📊 Ingesting account and fraud pattern data from JSON...")
json_path = "data/accounts.json"
try:
json_documents = file_ingestor.ingest(json_path)
for doc in json_documents:
if not hasattr(doc, 'metadata'):
doc.metadata = {}
doc.metadata['source'] = 'Account JSON'
doc.metadata['data_type'] = 'account_metadata'
all_documents.append(doc)
print(f" ✅ Loaded {len(json_documents)} documents from JSON")
except Exception as e:
print(f" ⚠️ JSON ingestion failed: {e}")
# ============================================================================
# REAL DATA SOURCE 3: External Payment Processor API (Example)
# ============================================================================
# In production, you would use real APIs like:
# - Stripe API: https://api.stripe.com/v1/charges
# - PayPal API: https://api.paypal.com/v1/payments
# - Square API: https://connect.squareup.com/v2/payments
#
# For demonstration, we'll use a mock API endpoint that returns transaction data
# In production, replace with actual API endpoints and authentication
print("📊 Attempting to ingest from payment processor API...")
payment_apis = [
"https://api.stripe.com/v1/charges", # Stripe (requires API key)
"https://api.paypal.com/v1/payments", # PayPal (requires OAuth)
# Add your actual API endpoints here
]
web_ingestor = WebIngestor()
api_success = False
for api_url in payment_apis:
try:
with redirect_stderr(StringIO()):
api_documents = web_ingestor.ingest(api_url, method="url")
if api_documents:
for doc in api_documents:
if not hasattr(doc, 'metadata'):
doc.metadata = {}
doc.metadata['source'] = f'Payment API ({api_url.split("//")[1].split("/")[0]})'
doc.metadata['data_type'] = 'api_transaction'
all_documents.append(doc)
print(f" ✅ Loaded {len(api_documents)} documents from {api_url}")
api_success = True
break
except Exception:
continue
if not api_success:
print(" ℹ️ API endpoints require authentication. Using local data sources.")
# ============================================================================
# REAL DATA SOURCE 4: Stream Ingestion (Kafka/RabbitMQ)
# ============================================================================
# For real-time fraud detection, ingest from message streams
# Example Kafka configuration:
# stream_config = {
# "bootstrap_servers": "localhost:9092",
# "topic": "transactions",
# "group_id": "fraud_detection"
# }
# stream_ingestor = StreamIngestor()
# stream_documents = stream_ingestor.ingest(stream_config, method="kafka")
print("📊 Stream ingestion (Kafka/RabbitMQ) - Configure in production")
# ============================================================================
# PUBLIC FRAUD DETECTION DATASETS (References)
# ============================================================================
# For additional training and testing, consider these public datasets:
#
# 1. Credit Card Fraud Detection (Kaggle)
# URL: https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud
# - 284,807 transactions, 492 fraudulent (0.172% fraud rate)
# - Download and ingest: file_ingestor.ingest("creditcard.csv")
#
# 2. IEEE-CIS Fraud Detection (Kaggle)
# URL: https://www.kaggle.com/competitions/ieee-fraud-detection
# - 590,540 transactions, ~3.5% fraudulent
# - 431 features (400 numerical, 31 categorical)
#
# 3. PaySim Synthetic Financial Dataset
# URL: https://www.kaggle.com/datasets/ealaxi/paysim1
# - 6,000,000 mobile money transactions
# - ~0.14% fraud rate
#
# 4. UCI Credit Card Dataset
# URL: https://archive.ics.uci.edu/ml/datasets/default+of+credit+card+clients
# - 30,000 credit card clients
# - 23 features including payment history
#
# To use these datasets:
# 1. Download the dataset files
# 2. Place them in the data/ directory
# 3. Use FileIngestor to load: file_ingestor.ingest("data/dataset.csv")
# ============================================================================
# Fallback: Generate sample data if no sources available
# ============================================================================
if not all_documents:
print("⚠️ No data sources found. Generating sample transaction data...")
tx_data = """
2024-01-01 10:00:00 - Transaction $1000 from Account A123 to Account B456
2024-01-01 10:01:00 - Transaction $5000 from Account A123 to Account C789
2024-01-01 10:02:00 - Transaction $10000 from Account A123 to Account D012 (unusual pattern)
2024-01-01 10:03:00 - Multiple rapid transactions from Account A123 (suspicious)
2024-01-01 10:04:00 - Transaction $2000 from Account B456 to Account E789
2024-01-01 10:05:00 - Large transaction $50000 from Account A123 to Account F012 (fraud alert)
2024-01-01 10:06:00 - Transaction $1500 from Account C789 to Account G345
2024-01-01 10:07:00 - Unusual device login from Account A123 (suspicious activity)
"""
with open("data/transactions.txt", "w") as f:
f.write(tx_data)
file_ingestor = FileIngestor()
all_documents = file_ingestor.ingest("data/transactions.txt")
documents = all_documents
print(f"\n✅ Total ingested: {len(documents)} documents from {len(set(doc.metadata.get('source', 'unknown') for doc in documents))} sources")
In [ ]:
from semantica.parse import DocumentParser
parser = DocumentParser()
print(f"Parsing {len(documents)} documents...")
parsed_documents = []
for i, doc in enumerate(documents, 1):
try:
parsed = parser.parse(
doc.content if hasattr(doc, 'content') else str(doc),
content_type="text"
)
parsed_documents.append(parsed)
except Exception:
parsed_documents.append(doc)
if i % 50 == 0 or i == len(documents):
print(f" Parsed {i}/{len(documents)} documents...")
documents = parsed_documents
In [ ]:
from semantica.normalize import TextNormalizer
from semantica.split import TextSplitter
normalizer = TextNormalizer()
# Use sentence chunking for transaction logs
splitter = TextSplitter(method="sentence", chunk_size=CHUNK_SIZE, chunk_overlap=CHUNK_OVERLAP)
print(f"Normalizing {len(documents)} documents...")
normalized_documents = []
for i, doc in enumerate(documents, 1):
normalized_text = normalizer.normalize(
doc.content if hasattr(doc, 'content') else str(doc),
clean_html=True,
normalize_entities=True,
normalize_numbers=True,
remove_extra_whitespace=True,
lowercase=False
)
normalized_documents.append(normalized_text)
if i % 50 == 0 or i == len(documents):
print(f" Normalized {i}/{len(documents)} documents...")
print(f"Chunking {len(normalized_documents)} documents...")
chunked_documents = []
for i, doc_text in enumerate(normalized_documents, 1):
try:
with redirect_stderr(StringIO()):
chunks = splitter.split(doc_text)
chunked_documents.extend(chunks)
except Exception:
simple_splitter = TextSplitter(method="recursive", chunk_size=CHUNK_SIZE, chunk_overlap=CHUNK_OVERLAP)
chunks = simple_splitter.split(doc_text)
chunked_documents.extend(chunks)
if i % 50 == 0 or i == len(normalized_documents):
print(f" Chunked {i}/{len(normalized_documents)} documents ({len(chunked_documents)} chunks so far)")
print(f"Created {len(chunked_documents)} chunks from {len(normalized_documents)} documents")
In [ ]:
from semantica.semantic_extract import NERExtractor
entity_extractor = NERExtractor(
method="llm",
provider="groq",
llm_model="llama-3.1-8b-instant",
temperature=0.0
)
all_entities = []
print(f"Extracting entities from {len(chunked_documents)} chunks...")
for i, chunk in enumerate(chunked_documents, 1):
chunk_text = chunk.text if hasattr(chunk, 'text') else str(chunk)
try:
entities = entity_extractor.extract_entities(
chunk_text,
entity_types=["Transaction", "Account", "Device", "Pattern", "Anomaly"]
)
all_entities.extend(entities)
except Exception:
continue
if i % 20 == 0 or i == len(chunked_documents):
print(f" Processed {i}/{len(chunked_documents)} chunks ({len(all_entities)} entities found)")
transactions = [e for e in all_entities if e.label == "Transaction" or "transaction" in e.label.lower()]
accounts = [e for e in all_entities if e.label == "Account" or "account" in e.label.lower()]
anomalies = [e for e in all_entities if e.label in ["Anomaly", "Pattern"] or "anomaly" in e.label.lower() or "pattern" in e.label.lower()]
print(f"Extracted {len(transactions)} transactions, {len(accounts)} accounts, {len(anomalies)} anomalies/patterns")
In [ ]:
from semantica.semantic_extract import RelationExtractor
relation_extractor = RelationExtractor(
method="llm",
provider="groq",
llm_model="llama-3.1-8b-instant",
temperature=0.0
)
all_relationships = []
print(f"Extracting relationships from {len(chunked_documents)} chunks...")
for i, chunk in enumerate(chunked_documents, 1):
chunk_text = chunk.text if hasattr(chunk, 'text') else str(chunk)
try:
relationships = relation_extractor.extract_relations(
chunk_text,
entities=all_entities,
relation_types=["from", "to", "triggers", "detects", "associated_with", "causes"]
)
all_relationships.extend(relationships)
except Exception:
continue
if i % 20 == 0 or i == len(chunked_documents):
print(f" Processed {i}/{len(chunked_documents)} chunks ({len(all_relationships)} relationships found)")
print(f"Extracted {len(all_relationships)} relationships")
In [ ]:
from semantica.conflicts import ConflictDetector, ConflictResolver
from semantica.conflicts.methods import detect_conflicts
# Use logical conflict detection for fraud rules
# expert_review strategy flags conflicts for manual review by fraud analysts
conflict_detector = ConflictDetector()
conflict_resolver = ConflictResolver()
# Convert all entities to dictionaries for conflict detection
print(f"Converting {len(all_entities)} entities to dictionaries...")
entity_dicts = []
for e in all_entities:
entity_dict = {
"id": e.text if hasattr(e, 'text') else str(e),
"name": e.text if hasattr(e, 'text') else str(e),
"text": e.text if hasattr(e, 'text') else str(e),
"type": e.label if hasattr(e, 'label') else "ENTITY",
"label": e.label if hasattr(e, 'label') else "ENTITY",
"confidence": getattr(e, 'confidence', 1.0),
"metadata": getattr(e, 'metadata', {})
}
entity_dicts.append(entity_dict)
# Convert all relationships to dictionaries for conflict detection
print(f"Converting {len(all_relationships)} relationships to dictionaries...")
relationship_dicts = []
for r in all_relationships:
# Handle different relationship object formats
if hasattr(r, 'subject') and hasattr(r, 'predicate') and hasattr(r, 'object'):
# Relation object format: subject, predicate, object
source = r.subject.text if hasattr(r.subject, 'text') else str(r.subject)
target = r.object.text if hasattr(r.object, 'text') else str(r.object)
rel_type = r.predicate if isinstance(r.predicate, str) else str(r.predicate)
elif hasattr(r, 'source') and hasattr(r, 'target'):
# Alternative format: source, target, type/label
source = r.source.text if hasattr(r.source, 'text') else str(r.source)
target = r.target.text if hasattr(r.target, 'text') else str(r.target)
rel_type = getattr(r, 'label', getattr(r, 'type', 'RELATED_TO'))
else:
# Fallback: try to extract from dict-like object
source = getattr(r, 'source_id', getattr(r, 'source', 'UNKNOWN'))
target = getattr(r, 'target_id', getattr(r, 'target', 'UNKNOWN'))
rel_type = getattr(r, 'type', getattr(r, 'label', 'RELATED_TO'))
relationship_dict = {
"id": f"{source}_{rel_type}_{target}",
"source_id": source,
"target_id": target,
"type": rel_type,
"confidence": getattr(r, 'confidence', 1.0),
"metadata": getattr(r, 'metadata', {})
}
relationship_dicts.append(relationship_dict)
print(f"Detecting logical conflicts in {len(entity_dicts)} entities and {len(relationship_dicts)} relationships...")
# Detect logical conflicts (e.g., conflicting fraud indicators)
# Use the standalone function from methods module which accepts method as keyword argument
conflicts = detect_conflicts(entity_dicts, method="logical")
# Also detect relationship conflicts
relationship_conflicts = conflict_detector.detect_relationship_conflicts(relationship_dicts)
all_conflicts = conflicts + relationship_conflicts
print(f"Detected {len(conflicts)} entity conflicts and {len(relationship_conflicts)} relationship conflicts (total: {len(all_conflicts)} conflicts)")
if all_conflicts:
print(f"Resolving conflicts using expert_review strategy...")
resolved = conflict_resolver.resolve_conflicts(
all_conflicts,
strategy="expert_review" # Manual review by fraud analysts
)
print(f"Resolved {len(resolved)} conflicts (flagged for expert review)")
else:
print("No conflicts detected")
In [ ]:
from semantica.kg import GraphBuilder
graph_builder = GraphBuilder(
merge_entities=True,
resolve_conflicts=True,
entity_resolution_strategy="fuzzy",
enable_temporal=True,
temporal_granularity=TEMPORAL_GRANULARITY
)
print(f"Building knowledge graph from {len(all_entities)} entities and {len(all_relationships)} relationships...")
# GraphBuilder handles Entity and Relationship objects directly
kg = graph_builder.build({
"entities": all_entities,
"relationships": all_relationships
})
entities_count = len(kg.get('entities', []))
relationships_count = len(kg.get('relationships', []))
print(f"Graph: {entities_count} entities, {relationships_count} relationships")
In [ ]:
from semantica.embeddings import EmbeddingGenerator
embedding_gen = EmbeddingGenerator(
provider="sentence_transformers",
model=EMBEDDING_MODEL
)
print(f"Generating embeddings for {len(transactions)} transactions and {len(accounts)} accounts...")
transaction_texts = [t.text for t in transactions]
transaction_embeddings = embedding_gen.generate_embeddings(transaction_texts)
account_texts = [a.text for a in accounts]
account_embeddings = embedding_gen.generate_embeddings(account_texts)
print(f"Generated {len(transaction_embeddings)} transaction embeddings and {len(account_embeddings)} account embeddings")
In [ ]:
from semantica.vector_store import VectorStore
vector_store = VectorStore(backend="faiss", dimension=EMBEDDING_DIMENSION)
print(f"Storing {len(transaction_embeddings)} transaction vectors and {len(account_embeddings)} account vectors...")
transaction_ids = vector_store.store_vectors(
vectors=transaction_embeddings,
metadata=[{"type": "transaction", "name": t.text, "label": t.label} for t in transactions]
)
account_ids = vector_store.store_vectors(
vectors=account_embeddings,
metadata=[{"type": "account", "name": a.text, "label": a.label} for a in accounts]
)
print(f"Stored {len(transaction_ids)} transaction vectors and {len(account_ids)} account vectors")
In [ ]:
from semantica.kg import TemporalGraphQuery
temporal_query = TemporalGraphQuery(
enable_temporal_reasoning=True,
temporal_granularity=TEMPORAL_GRANULARITY
)
query_results = temporal_query.query_at_time(
kg,
query={"type": "Transaction"},
at_time="2024-01-01 10:05:00"
)
evolution = temporal_query.analyze_evolution(kg)
pattern_results = temporal_query.query_temporal_pattern(kg, pattern="sequence")
print(f"Temporal queries: {len(query_results.get('entities', []))} transactions at query time")
print(f"Temporal patterns detected: {pattern_results.get('num_patterns', 0)}")
In [ ]:
from semantica.kg import TemporalPatternDetector
pattern_detector = TemporalPatternDetector()
# Detect temporal fraud patterns (using sequence pattern detection)
fraud_patterns = pattern_detector.detect_temporal_patterns(kg, pattern_type="sequence")
# Detect sequence patterns (rapid transactions, unusual timing)
sequence_patterns = pattern_detector.detect_temporal_patterns(kg, pattern_type="sequence")
print(f"Detected {len(fraud_patterns)} fraud patterns")
print(f"Detected {len(sequence_patterns)} sequence patterns")
In [ ]:
from semantica.reasoning import Reasoner
from semantica.kg import ConnectivityAnalyzer
reasoner = Reasoner()
reasoner.add_rule("IF Account from Transaction AND Transaction amount > 10000 AND Transaction count > 3 THEN Account triggers Anomaly")
reasoner.add_rule("IF Transaction from Account AND Account triggers Anomaly THEN Transaction associated_with Pattern")
inferred_facts = reasoner.infer_facts(kg)
# Use Semantica's built-in analyze_connectivity for path finding
accounts = [e for e in kg.get('entities', []) if e.get('type') == 'Account']
anomalies = [e for e in kg.get('entities', []) if e.get('type') == 'Anomaly']
fraud_paths = []
if accounts and anomalies:
account_id = accounts[0].get('id') or accounts[0].get('text') or accounts[0].get('name')
anomaly_id = anomalies[0].get('id') or anomalies[0].get('text') or anomalies[0].get('name')
if account_id and anomaly_id:
path_result = analyze_connectivity(kg, method="paths", source=account_id, target=anomaly_id)
if path_result.get('exists'):
fraud_paths = [path_result]
print(f"Inferred {len(inferred_facts)} facts")
print(f"Found {len(fraud_paths)} fraud paths")In [ ]:
from semantica.kg import GraphAnalyzer, CommunityDetector
graph_analyzer = GraphAnalyzer()
community_detector = CommunityDetector()
analysis = graph_analyzer.analyze_graph(kg)
communities = community_detector.detect_communities(kg, method="louvain")
connectivity = graph_analyzer.analyze_connectivity(kg)
# Detect suspicious account communities
suspicious_communities = []
for community in communities:
community_accounts = [e for e in kg.get("entities", [])
if e.get("id") in community and e.get("type") == "Account"]
if len(community_accounts) > 0:
# Check if community has suspicious patterns
suspicious_communities.append({
"community_id": len(suspicious_communities),
"account_count": len(community_accounts)
})
print(f"Graph analytics:")
print(f" - Communities: {len(communities)}")
print(f" - Connected components: {len(connectivity.get('components', []))}")
print(f" - Graph density: {analysis.get('density', 0):.3f}")
print(f" - Suspicious communities: {len(suspicious_communities)}")
In [ ]:
from semantica.context import AgentContext, ContextGraph, ContextRetriever
from semantica.llms import Groq
# Initialize AgentContext with knowledge graph for GraphRAG
context = AgentContext(
vector_store=vector_store,
knowledge_graph=kg,
hybrid_alpha=0.7, # 70% graph, 30% vector
use_graph_expansion=True
)
# Build context graph using ContextGraph directly
print("Building context graph from knowledge graph...")
context_graph = ContextGraph()
# Convert KG entities and relationships to context graph format
kg_entities = kg.get('entities', [])[:50]
kg_relationships = kg.get('relationships', [])[:100]
# Build context graph from entities and relationships
graph_result = context_graph.build_from_entities_and_relationships(
entities=kg_entities,
relationships=kg_relationships
)
print(f"Context graph built: {len(context_graph.nodes)} nodes, {len(context_graph.edges)} edges")
# Store transaction data in context graph for better retrieval
print("\nStoring transaction data in context graph...")
for i, entity in enumerate(kg.get('entities', [])[:20]): # Store sample entities
entity_text = f"{entity.get('text', entity.get('name', ''))} is a {entity.get('type', 'Entity')}"
context.store(
content=entity_text,
metadata={"type": entity.get('type'), "source": "fraud_detection"},
entities=[entity],
extract_entities=False, # Already extracted
link_entities=True
)
# Get context graph statistics
stats = context.stats()
print(f"\nContext Graph Statistics:")
print(f" - Total memories: {stats.get('total_memories', 0)}")
print(f" - Graph nodes: {stats.get('graph_nodes', 0)}")
print(f" - Graph edges: {stats.get('graph_edges', 0)}")
# Initialize Groq LLM for reasoning
llm = Groq(
model="llama-3.1-8b-instant",
api_key=os.getenv("GROQ_API_KEY")
)
# Query with multi-hop reasoning using Groq LLM and context graph
queries = [
"What accounts have suspicious transaction patterns?",
"Which accounts show signs of fraud based on device changes?",
"What are the relationships between fraudulent transactions and accounts?"
]
print("\n" + "=" * 80)
print("GraphRAG with Multi-Hop Reasoning (Groq LLM + Context Graph)")
print("=" * 80)
for query in queries:
print(f"\n{'='*80}")
print(f"Query: {query}")
print(f"{'='*80}\n")
# Use query_with_reasoning for better responses with context graph
result = context.query_with_reasoning(
query=query,
llm_provider=llm,
max_results=15,
max_hops=3, # Multi-hop reasoning through context graph
min_score=0.2
)
print(f"Generated Response:\n{result.get('response', 'No response')}\n")
if result.get('reasoning_path'):
print(f"Reasoning Path:\n{result.get('reasoning_path')}\n")
print(f"Confidence: {result.get('confidence', 0):.3f}")
print(f"Sources Used: {result.get('num_sources', 0)}")
print(f"Reasoning Paths: {result.get('num_reasoning_paths', 0)}")
print()In [ ]:
from semantica.visualization import TemporalVisualizer
from datetime import datetime, timedelta
# Prepare temporal KG with timestamps for interactive visualization
# Extract timestamps from entities (if they have temporal metadata)
timestamps = {}
entities = kg.get('entities', [])
relationships = kg.get('relationships', [])
# Build timestamps map from entity metadata or relationships
for entity in entities:
entity_id = entity.get('id') or entity.get('text') or entity.get('name', '')
if entity_id:
# Extract timestamp from entity metadata if available
entity_times = []
if 'timestamp' in entity:
entity_times.append(entity['timestamp'])
elif 'temporal' in entity:
entity_times.extend(entity.get('temporal', []))
else:
# Use relationships to infer timestamps
for rel in relationships:
if rel.get('source') == entity_id or rel.get('target') == entity_id:
if 'timestamp' in rel:
entity_times.append(rel['timestamp'])
if entity_times:
timestamps[entity_id] = sorted(list(set(entity_times)))
# If no timestamps found, create synthetic timestamps based on entity order
if not timestamps:
base_time = datetime(2024, 1, 1, 10, 0, 0)
for i, entity in enumerate(entities[:50]): # Limit to first 50 for performance
entity_id = entity.get('id') or entity.get('text') or entity.get('name', '')
if entity_id:
# Assign timestamps in sequence
entity_time = base_time + timedelta(minutes=i)
timestamps[entity_id] = [entity_time.strftime("%Y-%m-%d %H:%M:%S")]
# Create temporal KG structure
temporal_kg = {
"entities": entities[:50], # Limit for performance
"relationships": relationships[:100], # Limit for performance
"timestamps": timestamps
}
# Initialize TemporalVisualizer
temporal_viz = TemporalVisualizer()
print("Generating interactive temporal dashboard...")
# Create interactive temporal dashboard
dashboard_fig = temporal_viz.visualize_temporal_dashboard(
temporal_kg,
output="interactive",
title="Fraud Detection - Temporal Knowledge Graph Dashboard"
)
# Display the interactive figure
if dashboard_fig:
dashboard_fig.show()
print("\n✅ Interactive temporal dashboard displayed above")
else:
print("⚠️ Dashboard generation failed")
print("\nGenerating interactive network evolution animation...")
# Create interactive network evolution animation
evolution_fig = temporal_viz.visualize_network_evolution(
temporal_kg,
output="interactive",
title="Fraud Detection - Network Evolution Over Time"
)
# Display the interactive animation
if evolution_fig:
evolution_fig.show()
print("\n✅ Interactive network evolution animation displayed above")
else:
print("⚠️ Network evolution visualization failed")In [ ]:
from semantica.export import GraphExporter, CSVExporter
# Export to JSON and GraphML using GraphExporter
graph_exporter = GraphExporter()
graph_exporter.export(kg, output_path="fraud_detection_kg.json", format="json")
graph_exporter.export(kg, output_path="fraud_detection_kg.graphml", format="graphml")
# Export to CSV using CSVExporter
csv_exporter = CSVExporter()
csv_exporter.export_knowledge_graph(kg, "fraud_detection_alerts")
# Creates: fraud_detection_alerts_entities.csv, fraud_detection_alerts_relationships.csv
print("✅ Exported fraud detection knowledge graph:")
print(" - JSON: fraud_detection_kg.json")
print(" - GraphML: fraud_detection_kg.graphml")
print(" - CSV entities: fraud_detection_alerts_entities.csv")
print(" - CSV relationships: fraud_detection_alerts_relationships.csv")