lightrag-memgraph 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lightrag_memgraph-0.1.0/.gitignore +2 -0
- lightrag_memgraph-0.1.0/LICENSE +21 -0
- lightrag_memgraph-0.1.0/PKG-INFO +35 -0
- lightrag_memgraph-0.1.0/README.md +5 -0
- lightrag_memgraph-0.1.0/example.py +101 -0
- lightrag_memgraph-0.1.0/pyproject.toml +68 -0
- lightrag_memgraph-0.1.0/src/lightrag_memgraph/__init__.py +9 -0
- lightrag_memgraph-0.1.0/src/lightrag_memgraph/core.py +85 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Memgraph
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lightrag-memgraph
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LightRAG integration with Memgraph
|
|
5
|
+
Project-URL: Homepage, https://github.com/memgraph/ai-toolkit
|
|
6
|
+
Project-URL: Source, https://github.com/memgraph/ai-toolkit/tree/main/integrations/lightrag-memgraph
|
|
7
|
+
Project-URL: Issues, https://github.com/memgraph/ai-toolkit/issues
|
|
8
|
+
Author-email: Memgraph Tech Team <tech@memgraph.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: graph,integration,lightrag,memgraph,toolkit
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: lightrag-hku[api]==1.4.8.2
|
|
21
|
+
Requires-Dist: memgraph-toolbox>=0.1.6
|
|
22
|
+
Requires-Dist: numpy>=1.21.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: black>=22.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: isort>=5.0.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# Why?
|
|
32
|
+
|
|
33
|
+
* High-quality, slow and high-cost entity extraction.
|
|
34
|
+
* Connect extracted entities with existing domain-specific entities.
|
|
35
|
+
* Cost for your scale (e.g., $ per your document page).
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
import traceback
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from lightrag.llm.openai import gpt_4o_mini_complete, openai_embed
|
|
7
|
+
import shutil
|
|
8
|
+
|
|
9
|
+
from lightrag_memgraph import MemgraphLightRAGWrapper
|
|
10
|
+
from memgraph_toolbox.api.memgraph import Memgraph
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
14
|
+
WORKING_DIR = "./lightrag_storage.out"
|
|
15
|
+
if os.path.exists(WORKING_DIR):
|
|
16
|
+
shutil.rmtree(WORKING_DIR)
|
|
17
|
+
if not os.path.exists(WORKING_DIR):
|
|
18
|
+
os.mkdir(WORKING_DIR)
|
|
19
|
+
memgraph = Memgraph()
|
|
20
|
+
memgraph.query("MATCH (n) DETACH DELETE n;")
|
|
21
|
+
|
|
22
|
+
DUMMY_TEXTS = [
|
|
23
|
+
"""In the heart of the bustling city, a small bookstore stood as a
|
|
24
|
+
sanctuary for dreamers and thinkers alike. Its shelves, lined with
|
|
25
|
+
stories from every corner of the world, beckoned to those seeking
|
|
26
|
+
adventure, solace, or simply a quiet moment away from the noise.
|
|
27
|
+
The owner, an elderly gentleman with a gentle smile, greeted each
|
|
28
|
+
visitor as if they were an old friend. On rainy afternoons, the
|
|
29
|
+
soft patter of drops against the windows created a symphony that
|
|
30
|
+
mingled with the rustle of pages. Children gathered in the reading
|
|
31
|
+
nook, their imaginations ignited by tales of dragons and distant
|
|
32
|
+
lands. College students found refuge among the stacks, their minds
|
|
33
|
+
wandering as they prepared for exams. The bookstore was more than a
|
|
34
|
+
place to buy books; it was a haven where stories came alive,
|
|
35
|
+
friendships blossomed, and the magic of words wove its spell on all
|
|
36
|
+
who entered.""",
|
|
37
|
+
"""Beneath the golden canopy of autumn leaves, a
|
|
38
|
+
quiet park unfolded its charm to those who wandered its winding
|
|
39
|
+
paths. Joggers traced familiar routes, their breath visible in the
|
|
40
|
+
crisp morning air, while elderly couples strolled hand in hand,
|
|
41
|
+
reminiscing about days gone by. Children’s laughter echoed from the
|
|
42
|
+
playground, where swings soared and slides became mountains to
|
|
43
|
+
conquer. A painter sat on a weathered bench, capturing the fiery
|
|
44
|
+
hues of the season on her canvas, her brush dancing with
|
|
45
|
+
inspiration. Nearby, a group of friends gathered for a picnic,
|
|
46
|
+
sharing stories and homemade treats as squirrels darted hopefully
|
|
47
|
+
around their feet. The gentle breeze carried the scent of earth and
|
|
48
|
+
fallen leaves, inviting all to pause and savor the moment. In this
|
|
49
|
+
tranquil oasis, time seemed to slow, offering a gentle reminder of
|
|
50
|
+
nature’s beauty and the simple joys that color everyday life.""",
|
|
51
|
+
"""On the edge of a sleepy coastal village, a lighthouse stood
|
|
52
|
+
sentinel against the relentless waves. Its beacon, steadfast and
|
|
53
|
+
bright, guided fishermen safely home through fog and storm. The
|
|
54
|
+
keeper, a solitary figure with weathered hands, tended the light
|
|
55
|
+
with unwavering dedication, his days marked by the rhythm of tides
|
|
56
|
+
and the cries of gulls. Each evening, as the sun dipped below the
|
|
57
|
+
horizon, the village gathered on the shore to watch the sky ignite
|
|
58
|
+
in shades of orange and violet. Children chased the surf, their
|
|
59
|
+
laughter mingling with the roar of the sea. Local artisans
|
|
60
|
+
displayed their crafts at the market, their wares shaped by the
|
|
61
|
+
stories and traditions of generations. The lighthouse, a symbol of
|
|
62
|
+
hope and resilience, reminded all who saw it that even in the
|
|
63
|
+
darkest nights, a guiding light could be found, illuminating the
|
|
64
|
+
path home.""",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
async def main():
|
|
69
|
+
lightrag_wrapper = MemgraphLightRAGWrapper(disable_embeddings=True)
|
|
70
|
+
try:
|
|
71
|
+
await lightrag_wrapper.initialize(
|
|
72
|
+
working_dir=WORKING_DIR,
|
|
73
|
+
max_parallel_insert=8,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
total_time = 0.0
|
|
77
|
+
start_time = time.perf_counter()
|
|
78
|
+
await lightrag_wrapper.ainsert(
|
|
79
|
+
input=[text for text in DUMMY_TEXTS],
|
|
80
|
+
file_paths=[str(idx) for idx in range(len(DUMMY_TEXTS))],
|
|
81
|
+
)
|
|
82
|
+
end_time = time.perf_counter()
|
|
83
|
+
total_time += end_time - start_time
|
|
84
|
+
if len(DUMMY_TEXTS) > 0:
|
|
85
|
+
print(f"Average time per text: {total_time/len(DUMMY_TEXTS):.4f} seconds.")
|
|
86
|
+
|
|
87
|
+
rag = lightrag_wrapper.get_lightrag()
|
|
88
|
+
print(await rag.get_graph_labels())
|
|
89
|
+
kg_data = await rag.get_knowledge_graph(node_label="City", max_depth=3)
|
|
90
|
+
print("KNOWLEDGE GRAPH DATA:")
|
|
91
|
+
print(kg_data)
|
|
92
|
+
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"An error occurred: {e}")
|
|
95
|
+
print(traceback.format_exc())
|
|
96
|
+
finally:
|
|
97
|
+
await lightrag_wrapper.afinalize()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "lightrag-memgraph"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "LightRAG integration with Memgraph"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "Memgraph Tech Team", email = "tech@memgraph.com"},
|
|
10
|
+
]
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
keywords = ["memgraph", "graph", "integration", "toolkit", "lightrag"]
|
|
13
|
+
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
dependencies = [
|
|
25
|
+
"lightrag-hku[api]==1.4.8.2",
|
|
26
|
+
"memgraph-toolbox>=0.1.6",
|
|
27
|
+
"numpy>=1.21.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest>=7.0.0",
|
|
33
|
+
"pytest-asyncio>=0.21.0",
|
|
34
|
+
"black>=22.0.0",
|
|
35
|
+
"isort>=5.0.0",
|
|
36
|
+
"mypy>=1.0.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
"Homepage" = "https://github.com/memgraph/ai-toolkit"
|
|
41
|
+
"Source" = "https://github.com/memgraph/ai-toolkit/tree/main/integrations/lightrag-memgraph"
|
|
42
|
+
"Issues" = "https://github.com/memgraph/ai-toolkit/issues"
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
pythonpath = ["src"]
|
|
46
|
+
asyncio_mode = "strict"
|
|
47
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["hatchling", "build", "setuptools"]
|
|
51
|
+
build-backend = "hatchling.build"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.build.targets.wheel]
|
|
54
|
+
packages = ["src/lightrag_memgraph"]
|
|
55
|
+
|
|
56
|
+
[tool.black]
|
|
57
|
+
line-length = 88
|
|
58
|
+
target-version = ['py310']
|
|
59
|
+
|
|
60
|
+
[tool.isort]
|
|
61
|
+
profile = "black"
|
|
62
|
+
line_length = 88
|
|
63
|
+
|
|
64
|
+
[tool.mypy]
|
|
65
|
+
python_version = "3.10"
|
|
66
|
+
warn_return_any = true
|
|
67
|
+
warn_unused_configs = true
|
|
68
|
+
disallow_untyped_defs = true
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from lightrag import LightRAG
|
|
6
|
+
from lightrag.kg.shared_storage import initialize_pipeline_status
|
|
7
|
+
from lightrag.llm.openai import gpt_4o_mini_complete, openai_embed
|
|
8
|
+
from lightrag.utils import setup_logger
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
+
MEMGRAPH_URI = os.getenv("MEMGRAPH_URI", "bolt://localhost:7687")
|
|
14
|
+
os.environ["MEMGRAPH_URI"] = MEMGRAPH_URI
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DummyEmbed:
|
|
18
|
+
def __init__(self, dim: int = 1):
|
|
19
|
+
self.embedding_dim = dim
|
|
20
|
+
|
|
21
|
+
async def __call__(self, texts: list[str]) -> np.ndarray:
|
|
22
|
+
return np.ones((len(texts), self.embedding_dim), dtype=float)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MemgraphLightRAGWrapper:
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
log_level: str = "INFO",
|
|
29
|
+
disable_embeddings: bool = False,
|
|
30
|
+
):
|
|
31
|
+
self.log_level = log_level
|
|
32
|
+
self.disable_embeddings = disable_embeddings
|
|
33
|
+
self.rag: Optional[LightRAG] = None
|
|
34
|
+
|
|
35
|
+
# https://github.com/HKUDS/LightRAG/blob/main/lightrag/lightrag.py
|
|
36
|
+
# https://github.com/HKUDS/LightRAG/blob/main/lightrag/llm
|
|
37
|
+
async def initialize(self, **lightrag_kwargs) -> None:
|
|
38
|
+
setup_logger("lightrag", level=self.log_level)
|
|
39
|
+
logging.getLogger("nano-vectordb").setLevel(self.log_level)
|
|
40
|
+
logging.getLogger("pikepdf").setLevel(self.log_level)
|
|
41
|
+
if self.disable_embeddings:
|
|
42
|
+
lightrag_kwargs["embedding_func"] = DummyEmbed(dim=1)
|
|
43
|
+
lightrag_kwargs["vector_storage"] = "NanoVectorDBStorage"
|
|
44
|
+
if "working_dir" in lightrag_kwargs:
|
|
45
|
+
working_dir = lightrag_kwargs["working_dir"]
|
|
46
|
+
if not os.path.exists(working_dir):
|
|
47
|
+
os.mkdir(working_dir)
|
|
48
|
+
if "llm_model_func" not in lightrag_kwargs:
|
|
49
|
+
lightrag_kwargs["llm_model_func"] = gpt_4o_mini_complete
|
|
50
|
+
if "embedding_func" not in lightrag_kwargs:
|
|
51
|
+
lightrag_kwargs["embedding_func"] = openai_embed
|
|
52
|
+
if (
|
|
53
|
+
lightrag_kwargs["llm_model_func"] == gpt_4o_mini_complete
|
|
54
|
+
or lightrag_kwargs["embedding_func"] == openai_embed
|
|
55
|
+
):
|
|
56
|
+
openai_api_key = os.environ.get("OPENAI_API_KEY")
|
|
57
|
+
if not openai_api_key:
|
|
58
|
+
raise EnvironmentError(
|
|
59
|
+
"OPENAI_API_KEY environment variable is not set. Please set your OpenAI API key."
|
|
60
|
+
)
|
|
61
|
+
self.rag = LightRAG(graph_storage="MemgraphStorage", **lightrag_kwargs)
|
|
62
|
+
await self.rag.initialize_storages()
|
|
63
|
+
await initialize_pipeline_status()
|
|
64
|
+
|
|
65
|
+
def get_lightrag(self) -> LightRAG:
|
|
66
|
+
if self.rag is None:
|
|
67
|
+
raise RuntimeError("LightRAG not initialized. Call initialize() first.")
|
|
68
|
+
return self.rag
|
|
69
|
+
|
|
70
|
+
# https://github.com/HKUDS/LightRAG/blob/main/lightrag/lightrag.py
|
|
71
|
+
async def ainsert(self, **kwargs) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Example call: await lightrag_wrapper.ainsert(input=text, file_paths=[id])
|
|
74
|
+
|
|
75
|
+
If you want to inject info under each entity about the source input,
|
|
76
|
+
pass file_paths as a list of strings (ids don't work, not written under each entity).
|
|
77
|
+
"""
|
|
78
|
+
if self.rag is None:
|
|
79
|
+
raise RuntimeError("LightRAG not initialized. Call initialize() first.")
|
|
80
|
+
await self.rag.ainsert(**kwargs)
|
|
81
|
+
|
|
82
|
+
async def afinalize(self) -> None:
|
|
83
|
+
if self.rag is None:
|
|
84
|
+
raise RuntimeError("LightRAG not initialized. Call initialize() first.")
|
|
85
|
+
await self.rag.finalize_storages()
|