mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
57 KiB
57 KiB
In [ ]:
# Install Semantica and all required dependencies
%pip install -qU semantica networkx matplotlib plotly pandas faiss-cpu beautifulsoup4 groq sentence-transformers
In [ ]:
# Core imports will be added in cells where they're first used
import os
import json
In [ ]:
# Set up API keys
# Note: In production, use environment variables: export GROQ_API_KEY="your-key"
os.environ["GROQ_API_KEY"] = os.getenv("GROQ_API_KEY", "")
In [ ]:
# Create configuration dictionary
config_dict = {
"project_name": "GraphRAG_Complete",
# Embedding configuration
"embedding": {
"provider": "sentence_transformers",
"model": "all-MiniLM-L6-v2" # 384-dimensional embeddings
},
# Extraction configuration (for NER and relation extraction)
"extraction": {
"provider": "groq",
"model": "llama-3.1-8b-instant",
"temperature": 0.0 # Deterministic extraction
},
# Inference configuration (for answer generation)
"inference": {
"provider": "groq",
"model": "llama-3.3-70b-versatile"
},
# Vector store configuration
"vector_store": {
"provider": "faiss",
"dimension": 384 # Must match embedding dimension
},
# Knowledge graph configuration
"knowledge_graph": {
"backend": "networkx",
"merge_entities": True # Automatically merge duplicate entities
}
}
In [ ]:
from semantica.core import Semantica, ConfigManager
from semantica.vector_store import VectorStore
# Load configuration and initialize Semantica core
config = ConfigManager().load_from_dict(config_dict)
core = Semantica(config=config)
# Initialize vector store with matching dimension
vs = VectorStore(backend="faiss", dimension=384)
print("Configuration complete. Semantica initialized.")
print(f" - Embedding dimension: 384")
print(f" - Vector store backend: FAISS")
print(f" - Knowledge graph backend: NetworkX")
In [ ]:
# Define foundation data (ground truth)
foundation_data = {
"entities": [
{
"id": "hyaluronic_acid",
"name": "Hyaluronic Acid",
"type": "Ingredient",
"properties": {"role": "Humectant"}
},
{
"id": "retinol",
"name": "Retinol",
"type": "Ingredient",
"properties": {"role": "Anti-aging actives"}
},
{
"id": "niacinamide",
"name": "Niacinamide",
"type": "Ingredient",
"properties": {"role": "Barrier repair"}
}
],
"relationships": [
{
"source": "hyaluronic_acid",
"target": "niacinamide",
"type": "COMPLEMENTS",
"properties": {"benefit": "Hydration + Barrier"}
}
]
}
In [ ]:
# Save foundation data to JSON file
with open("skincare_base.json", "w") as f:
json.dump(foundation_data, f, indent=2)
print("Foundation data saved to skincare_base.json")
In [ ]:
from semantica.seed import SeedDataManager
# Initialize SeedDataManager
seed_manager = SeedDataManager()
# Register the seed data source
seed_manager.register_source("core_ontology", "json", "skincare_base.json")
# Create foundation graph from seed data
foundation_graph = seed_manager.create_foundation_graph()
print(f"Phase 0.1 Complete. Seeded {len(foundation_data['entities'])} primary nodes and {len(foundation_data['relationships'])} relationships.")
print(f" - Foundation graph created successfully")
print(f" - Seed data will be merged with extracted data in Phase 4")
In [ ]:
# Import ingestion and normalization modules
from semantica.ingest import FeedIngestor, WebIngestor, FileIngestor
from semantica.normalize import TextNormalizer
In [ ]:
from semantica.ingest import FeedIngestor, WebIngestor, FileIngestor
from semantica.normalize import TextNormalizer
# Initialize ingestion components
normalizer = TextNormalizer()
feed_ingestor = FeedIngestor()
web_ingestor = WebIngestor()
file_ingestor = FileIngestor()
# Container for all ingested content
all_content = []
print("Ingestion components initialized.")
In [ ]:
# Define feed URLs
feed_urls = [
"https://makeupandbeautyblog.com/feed",
"https://www.drbaileyskincare.com/blogs/blog.atom"
]
print("Ingesting from RSS/Atom feeds...")
for url in feed_urls:
try:
print(f" Processing: {url}")
feed_data = feed_ingestor.ingest_feed(url)
# Extract content from feed items (limit to 3 per feed to avoid rate limits)
for item in feed_data.items[:3]:
text = item.content or item.description or item.title
if text:
all_content.append(text)
print(f" Successfully ingested {min(3, len(feed_data.items))} items")
except Exception as e:
print(f" Warning: Failed to ingest {url}: {e}")
print(f"\nTotal feed items ingested: {len([c for c in all_content if c])}")
In [ ]:
# Define web URLs to ingest
web_urls = [
"https://en.wikipedia.org/wiki/Retinol"
]
print("Ingesting from web pages...")
for url in web_urls:
try:
print(f" Processing: {url}")
content = web_ingestor.ingest_url(url)
if content and content.text:
all_content.append(content.text)
print(f" Successfully ingested content ({len(content.text)} characters)")
except Exception as e:
print(f" Warning: Failed to ingest {url}: {e}")
print(f"\nTotal web pages ingested: {len([c for c in all_content if c])}")
In [ ]:
# Define local files to ingest
local_files = [
"expert_skincare_guide.txt",
"data/sample_graphrag_paper.txt"
]
print("Ingesting from local files...")
for file_path in local_files:
try:
if os.path.exists(file_path):
print(f" Processing: {file_path}")
file_obj = file_ingestor.ingest_file(file_path)
# Access content via the text property (automatically handles decoding)
if file_obj.text:
all_content.append(file_obj.text)
print(f" Successfully ingested {file_path}")
else:
print(f" Warning: No text content extracted from {file_path}")
else:
print(f" Warning: File not found: {file_path}")
except Exception as e:
print(f" Warning: Failed to ingest {file_path}: {e}")
print(f"\nTotal local files processed: {len([c for c in all_content if c])}")
In [ ]:
# Normalize all ingested content
print("Normalizing content...")
normalized_content = []
for text in all_content:
if text and len(text) > 50: # Filter out very short content
normalized_text = normalizer.normalize(text)
normalized_content.append(normalized_text)
print(f"\nPhase 1 Complete. Ingested {len(normalized_content)} documents from multiple sources.")
print(f" - Feed items: {len(feed_urls)} feeds processed")
print(f" - Web pages: {len(web_urls)} URLs processed")
print(f" - Local files: {len(local_files)} files processed")
print(f" - Total normalized documents: {len(normalized_content)}")
In [ ]:
# Import chunking module
from semantica.split import EntityAwareChunker
In [ ]:
from semantica.split import EntityAwareChunker
# Initialize EntityAwareChunker
# - chunk_size: Maximum characters per chunk (1000)
# - chunk_overlap: Characters to overlap between chunks (200) for context continuity
chunker = EntityAwareChunker(chunk_size=1000, chunk_overlap=200)
print("EntityAwareChunker initialized.")
print(f" - Chunk size: 1000 characters")
print(f" - Overlap: 200 characters")
In [ ]:
# Chunk all normalized documents
all_chunks = []
print("Chunking documents...")
for i, text in enumerate(normalized_content, 1):
if text:
chunks = chunker.chunk(text)
all_chunks.extend(chunks)
print(f" Document {i}: {len(chunks)} chunks created")
print(f"\nPhase 2 Complete. Generated {len(all_chunks)} semantic chunks.")
if all_chunks:
avg_size = sum(len(str(c.text)) for c in all_chunks) / len(all_chunks)
print(f" - Average chunk size: {avg_size:.0f} characters")
print(f" - Total chunks: {len(all_chunks)}")
In [ ]:
# Import semantic extraction modules
from semantica.semantic_extract import (
NERExtractor,
RelationExtractor,
TripletExtractor,
EventDetector,
CoreferenceResolver
)In [ ]:
from semantica.semantic_extract import NERExtractor, RelationExtractor
# Initialize Named Entity Recognition extractor
# Uses LLM method with Groq for high-quality entity extraction
ner = NERExtractor(
method="llm",
provider="groq",
model="llama-3.1-8b-instant"
)
# Initialize Relation Extraction extractor
# Extracts relationships between entities
rel_ext = RelationExtractor(
method="llm",
provider="groq",
model="llama-3.1-8b-instant"
)
# Initialize Triplet Extraction extractor
# Extracts RDF-style triplets (subject-predicate-object)
triplet_ext = TripletExtractor(
method="llm",
provider="groq",
model="llama-3.1-8b-instant"
)
# Initialize Event Detection extractor
# Detects events and their participants
event_detector = EventDetector()
# Initialize Coreference Resolution
# Links pronouns and references to entities
coref_resolver = CoreferenceResolver()
print("All extractors initialized successfully.")
print(" - NER Extractor: Ready")
print(" - Relation Extractor: Ready")
print(" - Triplet Extractor: Ready")
print(" - Event Detector: Ready")
print(" - Coreference Resolver: Ready")
In [ ]:
# Container for all extraction results
combined_results = {
"entities": [],
"relationships": [],
"triplets": [],
"events": []
}
print("Results container initialized.")
In [ ]:
# Process first 10 chunks to avoid rate limits
print("Extracting semantic information from chunks...")
print(f"Processing {min(10, len(all_chunks))} chunks...\n")
for i, chunk in enumerate(all_chunks[:10]):
txt = str(chunk.text)
if len(txt) < 50:
continue
print(f"Chunk {i+1}/{min(10, len(all_chunks))}:")
try:
# Step 1: Named Entity Recognition
print(f" Extracting entities...")
entities = ner.extract(txt)
for e in entities:
combined_results["entities"].append({
"name": e.text,
"type": e.label,
"id": e.text.lower().replace(' ', '_').replace('-', '_'),
"confidence": getattr(e, 'confidence', 0.8)
})
print(f" Found {len(entities)} entities")
# Step 2: Relation Extraction (requires entities)
if entities:
print(f" Extracting relationships...")
try:
relations = rel_ext.extract(txt, entities=entities)
for r in relations:
combined_results["relationships"].append({
"source": r.subject,
"target": r.object,
"type": r.predicate,
"confidence": getattr(r, 'confidence', 0.7)
})
print(f" Found {len(relations)} relationships")
except Exception as e:
print(f" Warning: Error extracting relationships: {e}")
else:
print(f" Skipping relationship extraction (no entities found)")
# Step 3: Triplet Extraction
print(f" Extracting triplets...")
try:
triplets = triplet_ext.extract_triplets(txt, entities=entities if entities else None)
for t in triplets:
combined_results["triplets"].append({
"subject": t.subject,
"predicate": t.predicate,
"object": t.object
})
print(f" Found {len(triplets)} triplets")
except Exception as e:
print(f" Warning: Error extracting triplets: {e}")
# Step 4: Event Detection
print(f" Detecting events...")
try:
events = event_detector.detect_events(txt)
for evt in events:
combined_results["events"].append({
"type": evt.event_type,
"text": evt.text,
"participants": evt.participants
})
print(f" Found {len(events)} events")
except Exception as e:
print(f" Warning: Error detecting events: {e}")
print() # Blank line between chunks
except Exception as e:
print(f" Warning: Error processing chunk: {e}\n")
continue
In [ ]:
# Display extraction summary
print("=" * 60)
print("Phase 3 Complete - Extraction Summary")
print("=" * 60)
print(f"Entities extracted: {len(combined_results['entities'])}")
print(f"Relationships extracted: {len(combined_results['relationships'])}")
print(f"Triplets extracted: {len(combined_results['triplets'])}")
print(f"Events detected: {len(combined_results['events'])}")
print("=" * 60)
# Show sample entities
if combined_results['entities']:
print("\nSample entities:")
for entity in combined_results['entities'][:5]:
print(f" - {entity['name']} ({entity['type']})")
# Show sample relationships
if combined_results['relationships']:
print("\nSample relationships:")
for rel in combined_results['relationships'][:5]:
print(f" - {rel['source']} --[{rel['type']}]--> {rel['target']}")
In [ ]:
from semantica.kg import GraphBuilder
# Initialize GraphBuilder with entity merging enabled
gb = GraphBuilder(merge_entities=True)
# Build knowledge graph from extraction results
print("Building knowledge graph...")
kg = gb.build(sources=[combined_results])
print(f"Initial graph statistics:")
print(f" - Entities: {len(kg.get('entities', []))}")
print(f" - Relationships: {len(kg.get('relationships', []))}")
print(f" - Metadata: {kg.get('metadata', {})}")
In [ ]:
from semantica.kg import EntityResolver
# Initialize EntityResolver
# similarity_threshold: Minimum similarity (0.85 = 85%) to consider entities as duplicates
resolver = EntityResolver(similarity_threshold=0.85)
print("Resolving entities (deduplication)...")
print(f" Method: Semantic similarity matching")
print(f" Threshold: 0.85 (85% similarity)")
# Resolve entities using semantic method
resolved_entities = resolver.resolve_entities(
kg.get('entities', []),
)
# Create final graph with resolved entities
kg_final = {
**kg,
'entities': resolved_entities
}
print(f"\nEntity resolution complete:")
print(f" - Original entities: {len(kg.get('entities', []))}")
print(f" - Resolved entities: {len(kg_final['entities'])}")
print(f" - Entities merged: {len(kg.get('entities', [])) - len(kg_final['entities'])}")
In [ ]:
from semantica.kg import GraphAnalyzer
# Initialize GraphAnalyzer
analyzer = GraphAnalyzer()
print("Analyzing graph structure...")
# Perform comprehensive graph analysis
analysis = analyzer.analyze_graph(kg_final)
# Extract metrics from nested structure
metrics = analysis.get('metrics', {})
connectivity = analysis.get('connectivity', {})
print(f"\nGraph structure metrics:")
print(f" - Graph density: {metrics.get('density', 0):.4f}")
print(f" - Connected components: {connectivity.get('connected_components', 0)}")
print(f" - Average degree: {metrics.get('avg_degree', 0):.2f}")
print(f" - Total nodes: {metrics.get('num_nodes', 0)}")
print(f" - Total edges: {metrics.get('num_edges', 0)}")
In [ ]:
from semantica.kg import CentralityCalculator
# Initialize CentralityCalculator
centrality_calc = CentralityCalculator()
print("Calculating centrality measures...")
# Calculate degree centrality (simplest and most common)
# This returns a dictionary containing 'centrality', 'rankings', etc.
result = centrality_calc.calculate_degree_centrality(kg_final)
if result and "rankings" in result:
# Use the pre-computed rankings (highest scores first)
top_entities = result["rankings"][:5]
print(f"\nTop 5 entities by degree centrality:")
for rank, item in enumerate(top_entities, 1):
# item['node'] is the entity ID, item['score'] is the normalized score
print(f" {rank}. {item['node']}: {item['score']:.4f}")
else:
print(" No centrality data available")In [ ]:
# Initialize CommunityDetector
from semantica.kg import CommunityDetector
community_detector = CommunityDetector()
print("Detecting communities...")
print(" Method: Louvain algorithm (greedy modularity optimization)")
# Detect communities using Louvain algorithm
result = community_detector.detect_communities(
kg_final,
method="louvain"
)
if result and "communities" in result:
communities = result["communities"]
print(f"\nCommunity detection results:")
print(f" - Total communities found: {len(communities)}")
# Show top 3 communities
sorted_communities = sorted(communities, key=len, reverse=True)
for i, community in enumerate(sorted_communities[:3], 1):
print(f" - Community {i}: {len(community)} entities")
# Show sample entities from this community
sample_entities = list(community)[:3]
print(f" Sample entities: {', '.join(sample_entities)}")
else:
print(" No communities detected")
In [ ]:
print("=" * 60)
print("Phase 4 Complete - Knowledge Graph Summary")
print("=" * 60)
# Extract metrics from nested structure (if not already extracted)
metrics = analysis.get('metrics', {})
connectivity = analysis.get('connectivity', {})
print(f"Final graph contains:")
print(f" - Entities: {len(kg_final['entities'])}")
print(f" - Relationships: {len(kg_final.get('relationships', []))}")
print(f" - Graph density: {metrics.get('density', 0):.4f}")
print(f" - Connected components: {connectivity.get('connected_components', 0)}")
print(f" - Communities: {len(communities) if communities else 0}")
print("=" * 60)
In [ ]:
# Prepare texts for embedding generation
print("Preparing texts for embedding...")
texts = [str(c.text) for c in all_chunks]
print(f" - Total chunks to embed: {len(texts)}")
print(f" - Embedding model: all-MiniLM-L6-v2")
print(f" - Expected dimension: 384")
In [ ]:
# Generate embeddings using the configured embedding generator
print("Generating embeddings...")
embeddings = core.embedding_generator.generate_embeddings(texts)
print(f"Embeddings generated successfully:")
print(f" - Total embeddings: {len(embeddings)}")
print(f" - Embedding dimension: {embeddings.shape[1] if len(embeddings) > 0 else 0}")
In [ ]:
# Create metadata for each vector
metadata_list = []
print("Preparing metadata...")
for i, chunk in enumerate(all_chunks):
metadata_list.append({
"text": str(chunk.text),
"chunk_id": i,
"source": "multi_source_ingestion",
"chunk_length": len(str(chunk.text))
})
print(f" - Metadata entries created: {len(metadata_list)}")
In [ ]:
# Store vectors in FAISS vector store
print("Storing vectors in vector store...")
vs.store_vectors(vectors=embeddings, metadata=metadata_list)
print(f"\nPhase 5 Complete. Vector store populated successfully.")
print(f" - Vectors stored: {len(embeddings)}")
print(f" - Vector store backend: FAISS")
print(f" - Embedding dimension: {embeddings.shape[1] if len(embeddings) > 0 else 0}")
print(f" - Ready for similarity search")
In [ ]:
# Import context and provider modules
from semantica.context import AgentContext, EntityLinker
from semantica.semantic_extract.providers import create_provider
In [ ]:
from semantica.context import AgentContext
# Initialize AgentContext with hybrid retrieval enabled
print("Initializing AgentContext for GraphRAG...")
ctx = AgentContext(
vector_store=vs, # Vector store for semantic search
knowledge_graph=kg_final, # Knowledge graph for relationship traversal
use_graph_expansion=True, # Enable graph traversal
max_expansion_hops=2, # Traverse up to 2 hops from initial entities
hybrid_alpha=0.6 # 60% weight on graph, 40% on vector
)
print("AgentContext initialized successfully.")
print(f" - Graph expansion: Enabled")
print(f" - Max expansion hops: 2")
print(f" - Hybrid alpha: 0.6 (60% graph, 40% vector)")
In [ ]:
# Initialize LLM provider for answer generation
llm_provider = create_provider("groq", model="llama-3.3-70b-versatile")
print("LLM provider initialized.")
print(f" - Provider: Groq")
print(f" - Model: llama-3.3-70b-versatile")
print(f" - Ready for answer generation")
In [ ]:
# Initialize EntityLinker
linker = EntityLinker(knowledge_graph=kg_final)
print("EntityLinker initialized.")
print(f" - Knowledge graph: Linked")
print(f" - Ready for entity resolution in queries")
In [ ]:
# Define the user query
user_query = "What ingredients synergize with Retinol to prevent irritation?"
print("=" * 70)
print("GRAPH RAG QUERY PROCESSING")
print("=" * 70)
print(f"Query: {user_query}\n")
In [ ]:
# Retrieve context using hybrid retrieval
print("Retrieving context using hybrid search...")
print(" - Vector search: Finding semantically similar chunks")
print(" - Graph traversal: Following entity relationships")
print(" - Max results: 5")
print(" - Graph expansion: Enabled (2 hops)\n")
context_results = ctx.retrieve(
user_query,
max_results=5,
use_graph=True, # Enable graph-based retrieval
expand_graph=True, # Expand to related entities
include_entities=True, # Include related entities in results
include_relationships=True # Include relationships in results
)
print(f"Retrieved {len(context_results)} context results.\n")
In [ ]:
if context_results:
print("=" * 70)
print("MULTI-HOP CONTEXT DISCOVERED")
print("=" * 70)
for i, res in enumerate(context_results, 1):
print(f"\nResult {i}:")
print(f" Content: {res.get('content', '')[:150]}...")
print(f" Relevance Score: {res.get('score', 0):.4f}")
# Display related entities (multi-hop connections)
if res.get('related_entities'):
print(f" Related Entities ({len(res['related_entities'])}):")
for entity in res['related_entities'][:3]:
entity_name = entity.get('name', entity.get('content', 'Unknown'))
print(f" - {entity_name}")
# Display related relationships
if res.get('related_relationships'):
print(f" Related Relationships: {len(res['related_relationships'])}")
print("\n" + "=" * 70)
else:
print("No relevant context found.")
print("This may indicate:")
print(" - The knowledge graph doesn't contain relevant information")
print(" - Try a different query")
print(" - Check if entities in the query exist in the graph")
In [ ]:
if context_results:
# Combine all retrieved context
context_text = "\n\n".join([r.get('content', '') for r in context_results])
# Create prompt for LLM
prompt = f"""Based on the following context from a knowledge graph, answer the user query accurately and comprehensively.
Context:
{context_text}
Query: {user_query}
Provide a detailed answer based on the context above:"""
print("=" * 70)
print("GENERATING FINAL ANSWER")
print("=" * 70)
print("Using LLM to synthesize answer from retrieved context...\n")
try:
final_answer = llm_provider.generate(prompt, temperature=0.3)
print(final_answer)
except Exception as e:
print(f"Warning: LLM generation failed: {e}")
print("\nHowever, we successfully retrieved relevant context using GraphRAG!")
print("The context above can be used to answer the query manually.")
In [ ]:
from semantica.visualization import KGVisualizer
import matplotlib.pyplot as plt
# Initialize KGVisualizer
viz = KGVisualizer()
print("Visualizing knowledge graph...")
print(" - Layout: Spring (force-directed)")
print(" - Title: GraphRAG Knowledge Graph")
try:
viz.visualize_network(
kg_final,
layout="spring",
title="GraphRAG Knowledge Graph",
output="static"
)
plt.show()
print("Graph visualization complete.")
except Exception as e:
print(f"Warning: Visualization error: {e}")
print("Graph structure:")
print(f" - Entities: {len(kg_final.get('entities', []))}")
print(f" - Relationships: {len(kg_final.get('relationships', []))}")
In [ ]:
from semantica.export import GraphExporter
# Initialize GraphExporter
exporter = GraphExporter()
print("\nExporting knowledge graph...")
# Export to JSON (human-readable, easy to process)
try:
exporter.export_knowledge_graph(kg_final, "graphrag_kg.json", format="json")
print(" Exported to JSON: graphrag_kg.json")
except Exception as e:
print(f" Warning: JSON export error: {e}")
# Export to GraphML (standard graph format)
try:
exporter.export_knowledge_graph(kg_final, "graphrag_kg.graphml", format="graphml")
print(" Exported to GraphML: graphrag_kg.graphml")
except Exception as e:
print(f" Warning: GraphML export error: {e}")
print("\nPhase 7 Complete. Graph visualized and exported.")