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]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.2.0] - 2026-01-10
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- **Amazon Neptune Support**:
|
- **Amazon Neptune Support**:
|
||||||
- Added `AmazonNeptuneStore` providing Amazon Neptune graph database integration via Bolt protocol and OpenCypher.
|
- 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.*
|
*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)
|
[**Discord**](https://discord.gg/pMHguUzG)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -26,10 +26,10 @@ Before releasing, ensure:
|
|||||||
|
|
||||||
The project uses GitHub Actions for automated releases to PyPI.
|
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
|
```bash
|
||||||
git tag -a v0.1.1 -m "Release v0.1.1"
|
git tag -a v0.2.0 -m "Release v0.2.0"
|
||||||
git push origin v0.1.1
|
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.
|
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 |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
|
| 0.2.0 | :white_check_mark: |
|
||||||
| 0.1.1 | :white_check_mark: |
|
| 0.1.1 | :white_check_mark: |
|
||||||
| 0.1.0 | :white_check_mark: |
|
| 0.1.0 | :white_check_mark: |
|
||||||
| < 0.1.0 | :x: |
|
| < 0.1.0 | :x: |
|
||||||
|
|||||||
+5
-5
@@ -12,22 +12,22 @@ How to cite Semantica in academic papers and research.
|
|||||||
author = {Hawksight AI},
|
author = {Hawksight AI},
|
||||||
year = {2026},
|
year = {2026},
|
||||||
url = {https://github.com/Hawksight-AI/semantica},
|
url = {https://github.com/Hawksight-AI/semantica},
|
||||||
version = {0.1.1},
|
version = {0.2.0},
|
||||||
doi = {10.5281/zenodo.XXXXXXX}
|
doi = {10.5281/zenodo.XXXXXXX}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### APA
|
### 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
|
### 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
|
### 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
|
### 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]
|
[project]
|
||||||
name = "semantica"
|
name = "semantica"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
description = "🧠 Semantica - An Open Source Framework for building Semantic Layers and Knowledge Engineering "
|
description = "🧠 Semantica - An Open Source Framework for building Semantic Layers and Knowledge Engineering "
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {text = "MIT"}
|
license = {text = "MIT"}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Main exports:
|
|||||||
- Config: Configuration management
|
- Config: Configuration management
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.1.1"
|
__version__ = "0.2.0"
|
||||||
__author__ = "Semantica Contributors"
|
__author__ = "Semantica Contributors"
|
||||||
__license__ = "MIT"
|
__license__ = "MIT"
|
||||||
|
|
||||||
|
|||||||
@@ -453,7 +453,6 @@ class RelationExtractor:
|
|||||||
|
|
||||||
def _extract_last_resort_relations(self, text: str, entities: List[Entity]) -> List[Relation]:
|
def _extract_last_resort_relations(self, text: str, entities: List[Entity]) -> List[Relation]:
|
||||||
"""Last resort relation extraction based on simple adjacency."""
|
"""Last resort relation extraction based on simple adjacency."""
|
||||||
print(f"DEBUG: Last Resort Relations - {len(entities)} entities")
|
|
||||||
relations = []
|
relations = []
|
||||||
# Connect adjacent entities
|
# Connect adjacent entities
|
||||||
for i in range(len(entities) - 1):
|
for i in range(len(entities) - 1):
|
||||||
@@ -482,7 +481,6 @@ class RelationExtractor:
|
|||||||
metadata={"extraction_method": "last_resort_adjacency"}
|
metadata={"extraction_method": "last_resort_adjacency"}
|
||||||
)
|
)
|
||||||
relations.append(rel)
|
relations.append(rel)
|
||||||
print(f"DEBUG: Created relation {rel.subject.text} -> {rel.object.text}")
|
|
||||||
return relations
|
return relations
|
||||||
|
|
||||||
def _extract_with_patterns(
|
def _extract_with_patterns(
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ class TestModelSelection(unittest.TestCase):
|
|||||||
|
|
||||||
def test_generator_switching(self):
|
def test_generator_switching(self):
|
||||||
print("\nTesting EmbeddingGenerator Switching...")
|
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
|
# Default check
|
||||||
self.assertEqual(generator.get_text_method(), "sentence_transformers")
|
self.assertEqual(generator.get_text_method(), "sentence_transformers")
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ class TestSemanticExtractBatch(unittest.TestCase):
|
|||||||
self.assertEqual(len(results), 1)
|
self.assertEqual(len(results), 1)
|
||||||
self.assertEqual(results[0]["batch_index"], 0)
|
self.assertEqual(results[0]["batch_index"], 0)
|
||||||
self.assertEqual(results[0]["document_id"], "doc_1")
|
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]["metadata"]["batch_index"], 0)
|
||||||
self.assertEqual(results[0]["semantic_roles"][0]["document_id"], "doc_1")
|
self.assertEqual(results[0]["semantic_roles"][0]["metadata"]["document_id"], "doc_1")
|
||||||
|
|
||||||
def test_coreference_resolver_batch(self):
|
def test_coreference_resolver_batch(self):
|
||||||
print("Running test_coreference_resolver_batch")
|
print("Running test_coreference_resolver_batch")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from semantica.triplet_store.triplet_manager import TripletManager, TripletStore
|
from semantica.triplet_store.triplet_store import TripletStore
|
||||||
from semantica.triplet_store.query_engine import QueryEngine, QueryResult
|
from semantica.triplet_store.query_engine import QueryEngine
|
||||||
from semantica.semantic_extract.triplet_extractor import Triplet
|
from semantica.semantic_extract.triplet_extractor import Triplet
|
||||||
|
|
||||||
class TestTripletStore(unittest.TestCase):
|
class TestTripletStore(unittest.TestCase):
|
||||||
@@ -10,125 +10,91 @@ class TestTripletStore(unittest.TestCase):
|
|||||||
self.mock_logger = MagicMock()
|
self.mock_logger = MagicMock()
|
||||||
self.mock_tracker = MagicMock()
|
self.mock_tracker = MagicMock()
|
||||||
|
|
||||||
self.logger_patcher = patch('semantica.triplet_store.triplet_manager.get_logger', return_value=self.mock_logger)
|
self.logger_patcher = patch('semantica.triplet_store.triplet_store.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.tracker_patcher = patch('semantica.triplet_store.triplet_store.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.start()
|
self.logger_patcher.start()
|
||||||
self.tracker_patcher.start()
|
self.tracker_patcher.start()
|
||||||
self.logger_patcher_qe.start()
|
|
||||||
self.tracker_patcher_qe.start()
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.logger_patcher.stop()
|
self.logger_patcher.stop()
|
||||||
self.tracker_patcher.stop()
|
self.tracker_patcher.stop()
|
||||||
self.logger_patcher_qe.stop()
|
|
||||||
self.tracker_patcher_qe.stop()
|
|
||||||
|
|
||||||
def test_triplet_manager_init(self):
|
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||||
manager = TripletManager(default_store="main")
|
def test_triplet_store_init(self, mock_blazegraph_store):
|
||||||
self.assertEqual(manager.default_store_id, "main")
|
store = TripletStore(backend="blazegraph", endpoint="http://localhost:9999")
|
||||||
self.assertEqual(manager.stores, {})
|
self.assertEqual(store.backend_type, "blazegraph")
|
||||||
|
|
||||||
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")
|
|
||||||
self.assertEqual(store.endpoint, "http://localhost:9999")
|
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')
|
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||||
def test_add_triplet(self, mock_get_store_backend):
|
def test_add_triplet(self, mock_blazegraph_store):
|
||||||
manager = TripletManager()
|
# Setup mock backend
|
||||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
mock_backend_instance = MagicMock()
|
||||||
|
mock_blazegraph_store.return_value = mock_backend_instance
|
||||||
mock_store = MagicMock()
|
mock_backend_instance.add_triplet.return_value = {"status": "success"}
|
||||||
mock_get_store_backend.return_value = mock_store
|
|
||||||
mock_store.add_triplet.return_value = {"status": "success"}
|
|
||||||
|
|
||||||
|
store = TripletStore(backend="blazegraph")
|
||||||
triplet = Triplet(subject="s", predicate="p", object="o")
|
triplet = Triplet(subject="s", predicate="p", object="o")
|
||||||
result = manager.add_triplet(triplet, store_id="main")
|
|
||||||
|
|
||||||
self.assertTrue(result["success"])
|
result = store.add_triplet(triplet)
|
||||||
self.assertEqual(result["store_id"], "main")
|
|
||||||
mock_store.add_triplet.assert_called_once_with(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')
|
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||||
def test_add_triplets(self, mock_get_store_backend):
|
def test_add_triplets(self, mock_blazegraph_store):
|
||||||
manager = TripletManager()
|
# Setup mock backend and bulk loader
|
||||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
mock_backend_instance = MagicMock()
|
||||||
|
mock_blazegraph_store.return_value = mock_backend_instance
|
||||||
|
|
||||||
mock_store = MagicMock()
|
store = TripletStore(backend="blazegraph")
|
||||||
mock_get_store_backend.return_value = mock_store
|
|
||||||
mock_store.add_triplets.return_value = {"status": "success"}
|
# 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 = [
|
triplets = [
|
||||||
Triplet(subject="s1", predicate="p1", object="o1"),
|
Triplet(subject="s1", predicate="p1", object="o1"),
|
||||||
Triplet(subject="s2", predicate="p2", object="o2")
|
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.assertTrue(result["success"])
|
||||||
self.assertEqual(result["store_id"], "main")
|
self.assertEqual(result["total"], 2)
|
||||||
mock_store.add_triplets.assert_called()
|
mock_loader.load_triplets.assert_called_once()
|
||||||
|
|
||||||
@patch('semantica.triplet_store.triplet_manager.TripletManager._get_store_backend')
|
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||||
def test_get_triplets(self, mock_get_store_backend):
|
def test_get_triplets(self, mock_blazegraph_store):
|
||||||
manager = TripletManager()
|
mock_backend_instance = MagicMock()
|
||||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
mock_blazegraph_store.return_value = mock_backend_instance
|
||||||
|
|
||||||
mock_store = MagicMock()
|
|
||||||
mock_get_store_backend.return_value = mock_store
|
|
||||||
expected_triplets = [Triplet(subject="s", predicate="p", object="o")]
|
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)
|
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')
|
@patch('semantica.triplet_store.blazegraph_store.BlazegraphStore')
|
||||||
def test_delete_triplet(self, mock_get_store_backend):
|
def test_delete_triplet(self, mock_blazegraph_store):
|
||||||
manager = TripletManager()
|
mock_backend_instance = MagicMock()
|
||||||
manager.register_store("main", "blazegraph", "http://localhost:9999")
|
mock_blazegraph_store.return_value = mock_backend_instance
|
||||||
|
mock_backend_instance.delete_triplet.return_value = {"success": True}
|
||||||
mock_store = MagicMock()
|
|
||||||
mock_get_store_backend.return_value = mock_store
|
|
||||||
mock_store.delete_triplet.return_value = {"status": "deleted"}
|
|
||||||
|
|
||||||
|
store = TripletStore(backend="blazegraph")
|
||||||
triplet = Triplet(subject="s", predicate="p", object="o")
|
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"])
|
self.assertTrue(result["success"])
|
||||||
mock_store.delete_triplet.assert_called_once_with(triplet)
|
mock_backend_instance.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()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user