mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
chore: Prepare release v0.2.0
This commit is contained in:
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.2.0] - 2026-01-10
|
||||
|
||||
### Added
|
||||
- **Amazon Neptune Support**:
|
||||
- Added `AmazonNeptuneStore` providing Amazon Neptune graph database integration via Bolt protocol and OpenCypher.
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
*The missing fabric between raw data and AI engineering. A comprehensive open-source framework for building semantic layers and knowledge engineering systems that transform unstructured data into AI-ready knowledge — powering Knowledge Graph-Powered RAG (GraphRAG), AI Agents, Multi-Agent Systems, and AI applications with structured semantic knowledge.*
|
||||
|
||||
**100% Open Source** • **MIT Licensed** • **Latest Version: 0.1.1** • **Production Ready** • **Community Driven**
|
||||
**100% Open Source** • **MIT Licensed** • **Latest Version: 0.2.0** • **Production Ready** • **Community Driven**
|
||||
|
||||
[**Discord**](https://discord.gg/pMHguUzG)
|
||||
|
||||
|
||||
+3
-3
@@ -26,10 +26,10 @@ Before releasing, ensure:
|
||||
|
||||
The project uses GitHub Actions for automated releases to PyPI.
|
||||
|
||||
1. **Tag the commit**: Create a new git tag for the version (e.g., `v0.1.1`).
|
||||
1. **Tag the commit**: Create a new git tag for the version (e.g., `v0.2.0`).
|
||||
```bash
|
||||
git tag -a v0.1.1 -m "Release v0.1.1"
|
||||
git push origin v0.1.1
|
||||
git tag -a v0.2.0 -m "Release v0.2.0"
|
||||
git push origin v0.2.0
|
||||
```
|
||||
2. **GitHub Action**: The `Release` workflow will automatically trigger, build the package, create a GitHub Release, and publish to PyPI using Trusted Publishing.
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ We actively support the following versions of Semantica with security updates:
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.2.0 | :white_check_mark: |
|
||||
| 0.1.1 | :white_check_mark: |
|
||||
| 0.1.0 | :white_check_mark: |
|
||||
| < 0.1.0 | :x: |
|
||||
|
||||
+5
-5
@@ -12,22 +12,22 @@ How to cite Semantica in academic papers and research.
|
||||
author = {Hawksight AI},
|
||||
year = {2026},
|
||||
url = {https://github.com/Hawksight-AI/semantica},
|
||||
version = {0.1.1},
|
||||
version = {0.2.0},
|
||||
doi = {10.5281/zenodo.XXXXXXX}
|
||||
}
|
||||
```
|
||||
|
||||
### APA
|
||||
Hawksight AI. (2026). *Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering* (Version 0.1.1) [Computer software]. https://github.com/Hawksight-AI/semantica
|
||||
Hawksight AI. (2026). *Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering* (Version 0.2.0) [Computer software]. https://github.com/Hawksight-AI/semantica
|
||||
|
||||
### MLA
|
||||
Hawksight AI. *Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering*. Version 0.1.1, GitHub, 2026, https://github.com/Hawksight-AI/semantica.
|
||||
Hawksight AI. *Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering*. Version 0.2.0, GitHub, 2026, https://github.com/Hawksight-AI/semantica.
|
||||
|
||||
### Chicago
|
||||
Hawksight AI. *Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering*. Version 0.1.1. GitHub, 2026. https://github.com/Hawksight-AI/semantica.
|
||||
Hawksight AI. *Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering*. Version 0.2.0. GitHub, 2026. https://github.com/Hawksight-AI/semantica.
|
||||
|
||||
### IEEE
|
||||
Hawksight AI, "Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering," Version 0.1.1, GitHub, 2026. [Online]. Available: https://github.com/Hawksight-AI/semantica
|
||||
Hawksight AI, "Semantica: An Open Source Framework for Semantic Layers and Knowledge Engineering," Version 0.2.0, GitHub, 2026. [Online]. Available: https://github.com/Hawksight-AI/semantica
|
||||
|
||||
---
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "semantica"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
description = "🧠 Semantica - An Open Source Framework for building Semantic Layers and Knowledge Engineering "
|
||||
readme = "README.md"
|
||||
license = {text = "MIT"}
|
||||
|
||||
@@ -10,7 +10,7 @@ Main exports:
|
||||
- Config: Configuration management
|
||||
"""
|
||||
|
||||
__version__ = "0.1.1"
|
||||
__version__ = "0.2.0"
|
||||
__author__ = "Semantica Contributors"
|
||||
__license__ = "MIT"
|
||||
|
||||
|
||||
@@ -453,7 +453,6 @@ class RelationExtractor:
|
||||
|
||||
def _extract_last_resort_relations(self, text: str, entities: List[Entity]) -> List[Relation]:
|
||||
"""Last resort relation extraction based on simple adjacency."""
|
||||
print(f"DEBUG: Last Resort Relations - {len(entities)} entities")
|
||||
relations = []
|
||||
# Connect adjacent entities
|
||||
for i in range(len(entities) - 1):
|
||||
@@ -482,7 +481,6 @@ class RelationExtractor:
|
||||
metadata={"extraction_method": "last_resort_adjacency"}
|
||||
)
|
||||
relations.append(rel)
|
||||
print(f"DEBUG: Created relation {rel.subject.text} -> {rel.object.text}")
|
||||
return relations
|
||||
|
||||
def _extract_with_patterns(
|
||||
|
||||
@@ -32,7 +32,8 @@ class TestModelSelection(unittest.TestCase):
|
||||
|
||||
def test_generator_switching(self):
|
||||
print("\nTesting EmbeddingGenerator Switching...")
|
||||
generator = EmbeddingGenerator()
|
||||
# Initialize with explicit method to ensure consistent starting state for test
|
||||
generator = EmbeddingGenerator(text={"method": "sentence_transformers"})
|
||||
|
||||
# Default check
|
||||
self.assertEqual(generator.get_text_method(), "sentence_transformers")
|
||||
|
||||
@@ -92,8 +92,8 @@ class TestSemanticExtractBatch(unittest.TestCase):
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0]["batch_index"], 0)
|
||||
self.assertEqual(results[0]["document_id"], "doc_1")
|
||||
self.assertEqual(results[0]["semantic_roles"][0]["batch_index"], 0)
|
||||
self.assertEqual(results[0]["semantic_roles"][0]["document_id"], "doc_1")
|
||||
self.assertEqual(results[0]["semantic_roles"][0]["metadata"]["batch_index"], 0)
|
||||
self.assertEqual(results[0]["semantic_roles"][0]["metadata"]["document_id"], "doc_1")
|
||||
|
||||
def test_coreference_resolver_batch(self):
|
||||
print("Running test_coreference_resolver_batch")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
from semantica.triplet_store.triplet_manager import TripletManager, TripletStore
|
||||
from semantica.triplet_store.query_engine import QueryEngine, QueryResult
|
||||
from semantica.triplet_store.triplet_store import TripletStore
|
||||
from semantica.triplet_store.query_engine import QueryEngine
|
||||
from semantica.semantic_extract.triplet_extractor import Triplet
|
||||
|
||||
class TestTripletStore(unittest.TestCase):
|
||||
@@ -10,125 +10,91 @@ class TestTripletStore(unittest.TestCase):
|
||||
self.mock_logger = MagicMock()
|
||||
self.mock_tracker = MagicMock()
|
||||
|
||||
self.logger_patcher = patch('semantica.triplet_store.triplet_manager.get_logger', return_value=self.mock_logger)
|
||||
self.tracker_patcher = patch('semantica.triplet_store.triplet_manager.get_progress_tracker', return_value=self.mock_tracker)
|
||||
self.logger_patcher_qe = patch('semantica.triplet_store.query_engine.get_logger', return_value=self.mock_logger)
|
||||
self.tracker_patcher_qe = patch('semantica.triplet_store.query_engine.get_progress_tracker', return_value=self.mock_tracker)
|
||||
self.logger_patcher = patch('semantica.triplet_store.triplet_store.get_logger', return_value=self.mock_logger)
|
||||
self.tracker_patcher = patch('semantica.triplet_store.triplet_store.get_progress_tracker', return_value=self.mock_tracker)
|
||||
|
||||
self.logger_patcher.start()
|
||||
self.tracker_patcher.start()
|
||||
self.logger_patcher_qe.start()
|
||||
self.tracker_patcher_qe.start()
|
||||
|
||||
def tearDown(self):
|
||||
self.logger_patcher.stop()
|
||||
self.tracker_patcher.stop()
|
||||
self.logger_patcher_qe.stop()
|
||||
self.tracker_patcher_qe.stop()
|
||||
|
||||
def test_triplet_manager_init(self):
|
||||
manager = TripletManager(default_store="main")
|
||||
self.assertEqual(manager.default_store_id, "main")
|
||||
self.assertEqual(manager.stores, {})
|
||||
|
||||
def test_register_store(self):
|
||||
manager = TripletManager()
|
||||
store = manager.register_store("main", "blazegraph", "http://localhost:9999")
|
||||
self.assertIsInstance(store, TripletStore)
|
||||
self.assertEqual(store.store_id, "main")
|
||||
self.assertEqual(store.store_type, "blazegraph")
|
||||
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||
def test_triplet_store_init(self, mock_blazegraph_store):
|
||||
store = TripletStore(backend="blazegraph", endpoint="http://localhost:9999")
|
||||
self.assertEqual(store.backend_type, "blazegraph")
|
||||
self.assertEqual(store.endpoint, "http://localhost:9999")
|
||||
self.assertIn("main", manager.stores)
|
||||
mock_blazegraph_store.assert_called_once()
|
||||
|
||||
@patch('semantica.triplet_store.triplet_manager.TripletManager._get_store_backend')
|
||||
def test_add_triplet(self, mock_get_store_backend):
|
||||
manager = TripletManager()
|
||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
||||
|
||||
mock_store = MagicMock()
|
||||
mock_get_store_backend.return_value = mock_store
|
||||
mock_store.add_triplet.return_value = {"status": "success"}
|
||||
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||
def test_add_triplet(self, mock_blazegraph_store):
|
||||
# Setup mock backend
|
||||
mock_backend_instance = MagicMock()
|
||||
mock_blazegraph_store.return_value = mock_backend_instance
|
||||
mock_backend_instance.add_triplet.return_value = {"status": "success"}
|
||||
|
||||
store = TripletStore(backend="blazegraph")
|
||||
triplet = Triplet(subject="s", predicate="p", object="o")
|
||||
result = manager.add_triplet(triplet, store_id="main")
|
||||
|
||||
self.assertTrue(result["success"])
|
||||
self.assertEqual(result["store_id"], "main")
|
||||
mock_store.add_triplet.assert_called_once_with(triplet)
|
||||
result = store.add_triplet(triplet)
|
||||
|
||||
self.assertEqual(result, {"status": "success"})
|
||||
mock_backend_instance.add_triplet.assert_called_once_with(triplet)
|
||||
|
||||
@patch('semantica.triplet_store.triplet_manager.TripletManager._get_store_backend')
|
||||
def test_add_triplets(self, mock_get_store_backend):
|
||||
manager = TripletManager()
|
||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
||||
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||
def test_add_triplets(self, mock_blazegraph_store):
|
||||
# Setup mock backend and bulk loader
|
||||
mock_backend_instance = MagicMock()
|
||||
mock_blazegraph_store.return_value = mock_backend_instance
|
||||
|
||||
mock_store = MagicMock()
|
||||
mock_get_store_backend.return_value = mock_store
|
||||
mock_store.add_triplets.return_value = {"status": "success"}
|
||||
store = TripletStore(backend="blazegraph")
|
||||
|
||||
# Mock bulk loader
|
||||
mock_loader = MagicMock()
|
||||
store.bulk_loader = mock_loader
|
||||
mock_progress = MagicMock()
|
||||
mock_progress.metadata = {"success": True}
|
||||
mock_progress.total_triplets = 2
|
||||
mock_progress.loaded_triplets = 2
|
||||
mock_progress.failed_triplets = 0
|
||||
mock_progress.total_batches = 1
|
||||
mock_loader.load_triplets.return_value = mock_progress
|
||||
|
||||
triplets = [
|
||||
Triplet(subject="s1", predicate="p1", object="o1"),
|
||||
Triplet(subject="s2", predicate="p2", object="o2")
|
||||
]
|
||||
|
||||
result = manager.add_triplets(triplets, store_id="main", batch_size=2)
|
||||
result = store.add_triplets(triplets, batch_size=2)
|
||||
|
||||
self.assertTrue(result["success"])
|
||||
self.assertEqual(result["store_id"], "main")
|
||||
mock_store.add_triplets.assert_called()
|
||||
self.assertEqual(result["total"], 2)
|
||||
mock_loader.load_triplets.assert_called_once()
|
||||
|
||||
@patch('semantica.triplet_store.triplet_manager.TripletManager._get_store_backend')
|
||||
def test_get_triplets(self, mock_get_store_backend):
|
||||
manager = TripletManager()
|
||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
||||
|
||||
mock_store = MagicMock()
|
||||
mock_get_store_backend.return_value = mock_store
|
||||
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||
def test_get_triplets(self, mock_blazegraph_store):
|
||||
mock_backend_instance = MagicMock()
|
||||
mock_blazegraph_store.return_value = mock_backend_instance
|
||||
expected_triplets = [Triplet(subject="s", predicate="p", object="o")]
|
||||
mock_store.get_triplets.return_value = expected_triplets
|
||||
mock_backend_instance.get_triplets.return_value = expected_triplets
|
||||
|
||||
result = manager.get_triplets(subject="s", store_id="main")
|
||||
store = TripletStore(backend="blazegraph")
|
||||
result = store.get_triplets(subject="s")
|
||||
|
||||
self.assertEqual(result, expected_triplets)
|
||||
mock_store.get_triplets.assert_called_once_with("s", None, None)
|
||||
mock_backend_instance.get_triplets.assert_called_once_with(subject="s", predicate=None, object=None)
|
||||
|
||||
@patch('semantica.triplet_store.triplet_manager.TripletManager._get_store_backend')
|
||||
def test_delete_triplet(self, mock_get_store_backend):
|
||||
manager = TripletManager()
|
||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
||||
|
||||
mock_store = MagicMock()
|
||||
mock_get_store_backend.return_value = mock_store
|
||||
mock_store.delete_triplet.return_value = {"status": "deleted"}
|
||||
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||
def test_delete_triplet(self, mock_blazegraph_store):
|
||||
mock_backend_instance = MagicMock()
|
||||
mock_blazegraph_store.return_value = mock_backend_instance
|
||||
mock_backend_instance.delete_triplet.return_value = {"success": True}
|
||||
|
||||
store = TripletStore(backend="blazegraph")
|
||||
triplet = Triplet(subject="s", predicate="p", object="o")
|
||||
result = manager.delete_triplet(triplet, store_id="main")
|
||||
|
||||
result = store.delete_triplet(triplet)
|
||||
|
||||
self.assertTrue(result["success"])
|
||||
mock_store.delete_triplet.assert_called_once_with(triplet)
|
||||
|
||||
@patch('semantica.triplet_store.triplet_manager.TripletManager._get_store_backend')
|
||||
def test_update_triplet(self, mock_get_store_backend):
|
||||
manager = TripletManager()
|
||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
||||
|
||||
mock_store = MagicMock()
|
||||
mock_get_store_backend.return_value = mock_store
|
||||
mock_store.delete_triplet.return_value = {"status": "deleted"}
|
||||
mock_store.add_triplet.return_value = {"status": "added"}
|
||||
|
||||
old_triplet = Triplet(subject="s", predicate="p", object="o_old")
|
||||
new_triplet = Triplet(subject="s", predicate="p", object="o_new")
|
||||
|
||||
result = manager.update_triplet(old_triplet, new_triplet, store_id="main")
|
||||
|
||||
self.assertTrue(result["success"])
|
||||
mock_store.delete_triplet.assert_called_once_with(old_triplet)
|
||||
mock_store.add_triplet.assert_called_once_with(new_triplet)
|
||||
|
||||
def test_query_engine_init(self):
|
||||
engine = QueryEngine(enable_caching=True)
|
||||
self.assertTrue(engine.enable_caching)
|
||||
self.assertEqual(engine.query_cache, {})
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
mock_backend_instance.delete_triplet.assert_called_once_with(triplet)
|
||||
|
||||
Reference in New Issue
Block a user