From 161baa6f08db3a91636f6ff56336fc8d1a22cb93 Mon Sep 17 00:00:00 2001 From: Yannick Stephan Date: Tue, 18 Feb 2025 17:11:17 +0100 Subject: [PATCH 1/6] pm bs4 when ollama --- lightrag/llm/ollama.py | 43 +----------------------------------------- lightrag/utils.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/lightrag/llm/ollama.py b/lightrag/llm/ollama.py index 296e263e..f62386e4 100644 --- a/lightrag/llm/ollama.py +++ b/lightrag/llm/ollama.py @@ -1,51 +1,10 @@ -""" -Ollama LLM Interface Module -========================== - -This module provides interfaces for interacting with Ollama's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - ollama - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.ollama_interface import ollama_model_complete, ollama_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - import sys if sys.version_info < (3, 9): from typing import AsyncIterator else: from collections.abc import AsyncIterator + import pipmaster as pm # Pipmaster for dynamic library install # install specific modules diff --git a/lightrag/utils.py b/lightrag/utils.py index e5d29824..680adf7a 100644 --- a/lightrag/utils.py +++ b/lightrag/utils.py @@ -13,13 +13,19 @@ from functools import wraps from hashlib import md5 from typing import Any, Callable import xml.etree.ElementTree as ET -import bs4 - import numpy as np import tiktoken from lightrag.prompt import PROMPTS +import pipmaster as pm # Pipmaster for dynamic library install + +# install specific modules +if not pm.is_installed("bs4"): + pm.install("bs4") + +import bs4 + VERBOSE_DEBUG = os.getenv("VERBOSE", "false").lower() == "true" From 24ae083284d5979f71942a7c363555e5a18abb97 Mon Sep 17 00:00:00 2001 From: Yannick Stephan Date: Tue, 18 Feb 2025 19:38:04 +0100 Subject: [PATCH 2/6] removed never used method --- lightrag/llm/ollama.py | 18 ++++++++---------- lightrag/utils.py | 36 ------------------------------------ 2 files changed, 8 insertions(+), 46 deletions(-) diff --git a/lightrag/llm/ollama.py b/lightrag/llm/ollama.py index f62386e4..0e663201 100644 --- a/lightrag/llm/ollama.py +++ b/lightrag/llm/ollama.py @@ -13,7 +13,9 @@ if not pm.is_installed("ollama"): if not pm.is_installed("tenacity"): pm.install("tenacity") + import ollama + from tenacity import ( retry, stop_after_attempt, @@ -26,7 +28,7 @@ from lightrag.exceptions import ( APITimeoutError, ) from lightrag.api import __api_version__ -from lightrag.utils import extract_reasoning + import numpy as np from typing import Union @@ -38,7 +40,7 @@ from typing import Union (RateLimitError, APIConnectionError, APITimeoutError) ), ) -async def ollama_model_if_cache( +async def _ollama_model_if_cache( model, prompt, system_prompt=None, @@ -46,7 +48,7 @@ async def ollama_model_if_cache( **kwargs, ) -> Union[str, AsyncIterator[str]]: stream = True if kwargs.get("stream") else False - reasoning_tag = kwargs.pop("reasoning_tag", None) + kwargs.pop("max_tokens", None) # kwargs.pop("response_format", None) # allow json host = kwargs.pop("host", None) @@ -84,11 +86,7 @@ async def ollama_model_if_cache( response and can simply be trimmed. """ - return ( - model_response - if reasoning_tag is None - else extract_reasoning(model_response, reasoning_tag).response_content - ) + return model_response async def ollama_model_complete( @@ -98,7 +96,7 @@ async def ollama_model_complete( if keyword_extraction: kwargs["format"] = "json" model_name = kwargs["hashing_kv"].global_config["llm_model_name"] - return await ollama_model_if_cache( + return await _ollama_model_if_cache( model_name, prompt, system_prompt=system_prompt, @@ -131,4 +129,4 @@ async def ollama_embed(texts: list[str], embed_model, **kwargs) -> np.ndarray: kwargs["headers"] = headers ollama_client = ollama.Client(**kwargs) data = ollama_client.embed(model=embed_model, input=texts) - return data["embeddings"] + return data["embeddings"] \ No newline at end of file diff --git a/lightrag/utils.py b/lightrag/utils.py index 680adf7a..3ca93f85 100644 --- a/lightrag/utils.py +++ b/lightrag/utils.py @@ -18,13 +18,7 @@ import tiktoken from lightrag.prompt import PROMPTS -import pipmaster as pm # Pipmaster for dynamic library install -# install specific modules -if not pm.is_installed("bs4"): - pm.install("bs4") - -import bs4 VERBOSE_DEBUG = os.getenv("VERBOSE", "false").lower() == "true" @@ -90,12 +84,6 @@ class EmbeddingFunc: return await self.func(*args, **kwargs) -@dataclass -class ReasoningResponse: - reasoning_content: str | None - response_content: str - tag: str - def locate_json_string_body_from_string(content: str) -> str | None: """Locate the JSON string body from a string""" @@ -728,27 +716,3 @@ def get_conversation_turns( return "\n".join(formatted_turns) - -def extract_reasoning(response: str, tag: str) -> ReasoningResponse: - """Extract the reasoning section and the following section from the LLM response. - - Args: - response: LLM response - tag: Tag to extract - Returns: - ReasoningResponse: Reasoning section and following section - - """ - soup = bs4.BeautifulSoup(response, "html.parser") - - reasoning_section = soup.find(tag) - if reasoning_section is None: - return ReasoningResponse(None, response, tag) - reasoning_content = reasoning_section.get_text().strip() - - after_reasoning_section = reasoning_section.next_sibling - if after_reasoning_section is None: - return ReasoningResponse(reasoning_content, "", tag) - after_reasoning_content = after_reasoning_section.get_text().strip() - - return ReasoningResponse(reasoning_content, after_reasoning_content, tag) From 2524e02428c5a10662a6068425f03b4ffd5d0779 Mon Sep 17 00:00:00 2001 From: Yannick Stephan Date: Tue, 18 Feb 2025 19:58:03 +0100 Subject: [PATCH 3/6] remove tqdm and cleaned readme and ollama --- README.md | 10 ----- lightrag/api/requirements.txt | 1 - lightrag/kg/faiss_impl.py | 12 +----- lightrag/kg/milvus_impl.py | 11 +---- lightrag/kg/mongo_impl.py | 12 +----- lightrag/kg/nano_vector_db_impl.py | 11 +---- lightrag/kg/postgres_impl.py | 11 +---- lightrag/kg/qdrant_impl.py | 11 +---- lightrag/kg/redis_impl.py | 4 +- lightrag/kg/tidb_impl.py | 12 +----- lightrag/llm/ollama.py | 6 +-- lightrag/operate.py | 60 +++++++-------------------- lightrag/utils.py | 3 -- reproduce/Step_3.py | 3 +- reproduce/Step_3_openai_compatible.py | 3 +- requirements.txt | 1 - 16 files changed, 30 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index 6b0f86fe..eaa058ad 100644 --- a/README.md +++ b/README.md @@ -344,16 +344,6 @@ rag = LightRAG( ), ) ``` -#### Fully functional example - -There fully functional example `examples/lightrag_ollama_demo.py` that utilizes `gemma2:2b` model, runs only 4 requests in parallel and set context size to 32k. - -#### Using "Thinking" Models (e.g., DeepSeek) - -To return only the model's response, you can pass `reasoning_tag` in `llm_model_kwargs`. - -For example, for DeepSeek models, `reasoning_tag` should be set to `think`. - #### Low RAM GPUs In order to run this experiment on low RAM GPU you should select small model and tune context window (increasing context increase memory consumption). For example, running this ollama example on repurposed mining GPU with 6Gb of RAM required to set context size to 26k while using `gemma2:2b`. It was able to find 197 entities and 19 relations on `book.txt`. diff --git a/lightrag/api/requirements.txt b/lightrag/api/requirements.txt index 068a84b9..d0d00e29 100644 --- a/lightrag/api/requirements.txt +++ b/lightrag/api/requirements.txt @@ -7,5 +7,4 @@ python-multipart tenacity tiktoken torch -tqdm uvicorn diff --git a/lightrag/kg/faiss_impl.py b/lightrag/kg/faiss_impl.py index 2b67e2fa..75abf389 100644 --- a/lightrag/kg/faiss_impl.py +++ b/lightrag/kg/faiss_impl.py @@ -22,7 +22,6 @@ if not pm.is_installed("faiss"): try: import faiss - from tqdm.asyncio import tqdm as tqdm_async except ImportError as e: raise ImportError( "`faiss` library is not installed. Please install it via pip: `pip install faiss`." @@ -109,16 +108,7 @@ class FaissVectorDBStorage(BaseVectorStorage): for i in range(0, len(contents), self._max_batch_size) ] - pbar = tqdm_async( - total=len(batches), desc="Generating embeddings", unit="batch" - ) - - async def wrapped_task(batch): - result = await self.embedding_func(batch) - pbar.update(1) - return result - - embedding_tasks = [wrapped_task(batch) for batch in batches] + embedding_tasks = [self.embedding_func(batch) for batch in batches] embeddings_list = await asyncio.gather(*embedding_tasks) # Flatten the list of arrays diff --git a/lightrag/kg/milvus_impl.py b/lightrag/kg/milvus_impl.py index 3e8f1ba5..edefe0b1 100644 --- a/lightrag/kg/milvus_impl.py +++ b/lightrag/kg/milvus_impl.py @@ -1,7 +1,6 @@ import asyncio import os from typing import Any, final -from tqdm.asyncio import tqdm as tqdm_async from dataclasses import dataclass import numpy as np from lightrag.utils import logger @@ -94,15 +93,7 @@ class MilvusVectorDBStorage(BaseVectorStorage): for i in range(0, len(contents), self._max_batch_size) ] - async def wrapped_task(batch): - result = await self.embedding_func(batch) - pbar.update(1) - return result - - embedding_tasks = [wrapped_task(batch) for batch in batches] - pbar = tqdm_async( - total=len(embedding_tasks), desc="Generating embeddings", unit="batch" - ) + embedding_tasks = [self.embedding_func(batch) for batch in batches] embeddings_list = await asyncio.gather(*embedding_tasks) embeddings = np.concatenate(embeddings_list) diff --git a/lightrag/kg/mongo_impl.py b/lightrag/kg/mongo_impl.py index 8cfc84b9..2210e9f4 100644 --- a/lightrag/kg/mongo_impl.py +++ b/lightrag/kg/mongo_impl.py @@ -2,7 +2,6 @@ import os from dataclasses import dataclass import numpy as np import configparser -from tqdm.asyncio import tqdm as tqdm_async import asyncio from typing import Any, List, Union, final @@ -854,17 +853,8 @@ class MongoVectorDBStorage(BaseVectorStorage): for i in range(0, len(contents), self._max_batch_size) ] - async def wrapped_task(batch): - result = await self.embedding_func(batch) - pbar.update(1) - return result - - embedding_tasks = [wrapped_task(batch) for batch in batches] - pbar = tqdm_async( - total=len(embedding_tasks), desc="Generating embeddings", unit="batch" - ) + embedding_tasks = [self.embedding_func(batch) for batch in batches] embeddings_list = await asyncio.gather(*embedding_tasks) - embeddings = np.concatenate(embeddings_list) for i, d in enumerate(list_data): d["vector"] = np.array(embeddings[i], dtype=np.float32).tolist() diff --git a/lightrag/kg/nano_vector_db_impl.py b/lightrag/kg/nano_vector_db_impl.py index 16955d8a..b246790b 100644 --- a/lightrag/kg/nano_vector_db_impl.py +++ b/lightrag/kg/nano_vector_db_impl.py @@ -1,7 +1,6 @@ import asyncio import os from typing import Any, final -from tqdm.asyncio import tqdm as tqdm_async from dataclasses import dataclass import numpy as np @@ -71,15 +70,7 @@ class NanoVectorDBStorage(BaseVectorStorage): for i in range(0, len(contents), self._max_batch_size) ] - async def wrapped_task(batch): - result = await self.embedding_func(batch) - pbar.update(1) - return result - - embedding_tasks = [wrapped_task(batch) for batch in batches] - pbar = tqdm_async( - total=len(embedding_tasks), desc="Generating embeddings", unit="batch" - ) + embedding_tasks = [self.embedding_func(batch) for batch in batches] embeddings_list = await asyncio.gather(*embedding_tasks) embeddings = np.concatenate(embeddings_list) diff --git a/lightrag/kg/postgres_impl.py b/lightrag/kg/postgres_impl.py index f7866e42..70900c93 100644 --- a/lightrag/kg/postgres_impl.py +++ b/lightrag/kg/postgres_impl.py @@ -41,7 +41,6 @@ if not pm.is_installed("asyncpg"): try: import asyncpg - from tqdm.asyncio import tqdm as tqdm_async except ImportError as e: raise ImportError( @@ -380,15 +379,7 @@ class PGVectorStorage(BaseVectorStorage): for i in range(0, len(contents), self._max_batch_size) ] - async def wrapped_task(batch): - result = await self.embedding_func(batch) - pbar.update(1) - return result - - embedding_tasks = [wrapped_task(batch) for batch in batches] - pbar = tqdm_async( - total=len(embedding_tasks), desc="Generating embeddings", unit="batch" - ) + embedding_tasks = [self.embedding_func(batch) for batch in batches] embeddings_list = await asyncio.gather(*embedding_tasks) embeddings = np.concatenate(embeddings_list) diff --git a/lightrag/kg/qdrant_impl.py b/lightrag/kg/qdrant_impl.py index 0610346f..f9edc510 100644 --- a/lightrag/kg/qdrant_impl.py +++ b/lightrag/kg/qdrant_impl.py @@ -1,7 +1,6 @@ import asyncio import os from typing import Any, final -from tqdm.asyncio import tqdm as tqdm_async from dataclasses import dataclass import numpy as np import hashlib @@ -110,15 +109,7 @@ class QdrantVectorDBStorage(BaseVectorStorage): for i in range(0, len(contents), self._max_batch_size) ] - async def wrapped_task(batch): - result = await self.embedding_func(batch) - pbar.update(1) - return result - - embedding_tasks = [wrapped_task(batch) for batch in batches] - pbar = tqdm_async( - total=len(embedding_tasks), desc="Generating embeddings", unit="batch" - ) + embedding_tasks = [self.embedding_func(batch) for batch in batches] embeddings_list = await asyncio.gather(*embedding_tasks) embeddings = np.concatenate(embeddings_list) diff --git a/lightrag/kg/redis_impl.py b/lightrag/kg/redis_impl.py index 056fbc9e..4bff6c62 100644 --- a/lightrag/kg/redis_impl.py +++ b/lightrag/kg/redis_impl.py @@ -1,6 +1,5 @@ import os from typing import Any, final -from tqdm.asyncio import tqdm as tqdm_async from dataclasses import dataclass import pipmaster as pm import configparser @@ -51,7 +50,8 @@ class RedisKVStorage(BaseKVStorage): async def upsert(self, data: dict[str, dict[str, Any]]) -> None: pipe = self._redis.pipeline() - for k, v in tqdm_async(data.items(), desc="Upserting"): + + for k, v in data.items(): pipe.set(f"{self.namespace}:{k}", json.dumps(v)) await pipe.execute() diff --git a/lightrag/kg/tidb_impl.py b/lightrag/kg/tidb_impl.py index 110a404a..e8e7800d 100644 --- a/lightrag/kg/tidb_impl.py +++ b/lightrag/kg/tidb_impl.py @@ -7,7 +7,6 @@ import numpy as np from lightrag.types import KnowledgeGraph -from tqdm import tqdm from ..base import BaseGraphStorage, BaseKVStorage, BaseVectorStorage from ..namespace import NameSpace, is_namespace @@ -270,15 +269,8 @@ class TiDBVectorDBStorage(BaseVectorStorage): for i in range(0, len(contents), self._max_batch_size) ] embedding_tasks = [self.embedding_func(batch) for batch in batches] - embeddings_list = [] - for f in tqdm( - asyncio.as_completed(embedding_tasks), - total=len(embedding_tasks), - desc="Generating embeddings", - unit="batch", - ): - embeddings = await f - embeddings_list.append(embeddings) + embeddings_list = await asyncio.gather(*embedding_tasks) + embeddings = np.concatenate(embeddings_list) for i, d in enumerate(list_data): d["content_vector"] = embeddings[i] diff --git a/lightrag/llm/ollama.py b/lightrag/llm/ollama.py index 0e663201..e6fd5da7 100644 --- a/lightrag/llm/ollama.py +++ b/lightrag/llm/ollama.py @@ -4,7 +4,7 @@ if sys.version_info < (3, 9): from typing import AsyncIterator else: from collections.abc import AsyncIterator - + import pipmaster as pm # Pipmaster for dynamic library install # install specific modules @@ -48,7 +48,7 @@ async def _ollama_model_if_cache( **kwargs, ) -> Union[str, AsyncIterator[str]]: stream = True if kwargs.get("stream") else False - + kwargs.pop("max_tokens", None) # kwargs.pop("response_format", None) # allow json host = kwargs.pop("host", None) @@ -129,4 +129,4 @@ async def ollama_embed(texts: list[str], embed_model, **kwargs) -> np.ndarray: kwargs["headers"] = headers ollama_client = ollama.Client(**kwargs) data = ollama_client.embed(model=embed_model, input=texts) - return data["embeddings"] \ No newline at end of file + return data["embeddings"] diff --git a/lightrag/operate.py b/lightrag/operate.py index 13293f25..3ada34ab 100644 --- a/lightrag/operate.py +++ b/lightrag/operate.py @@ -3,7 +3,6 @@ from __future__ import annotations import asyncio import json import re -from tqdm.asyncio import tqdm as tqdm_async from typing import Any, AsyncIterator from collections import Counter, defaultdict from .utils import ( @@ -500,16 +499,8 @@ async def extract_entities( ) return dict(maybe_nodes), dict(maybe_edges) - results = [] - for result in tqdm_async( - asyncio.as_completed([_process_single_content(c) for c in ordered_chunks]), - total=len(ordered_chunks), - desc="Level 2 - Extracting entities and relationships", - unit="chunk", - position=1, - leave=False, - ): - results.append(await result) + tasks = [_process_single_content(c) for c in ordered_chunks] + results = await asyncio.gather(*tasks) maybe_nodes = defaultdict(list) maybe_edges = defaultdict(list) @@ -518,41 +509,20 @@ async def extract_entities( maybe_nodes[k].extend(v) for k, v in m_edges.items(): maybe_edges[tuple(sorted(k))].extend(v) - logger.debug("Inserting entities into storage...") - all_entities_data = [] - for result in tqdm_async( - asyncio.as_completed( - [ - _merge_nodes_then_upsert(k, v, knowledge_graph_inst, global_config) - for k, v in maybe_nodes.items() - ] - ), - total=len(maybe_nodes), - desc="Level 3 - Inserting entities", - unit="entity", - position=2, - leave=False, - ): - all_entities_data.append(await result) - logger.debug("Inserting relationships into storage...") - all_relationships_data = [] - for result in tqdm_async( - asyncio.as_completed( - [ - _merge_edges_then_upsert( - k[0], k[1], v, knowledge_graph_inst, global_config - ) - for k, v in maybe_edges.items() - ] - ), - total=len(maybe_edges), - desc="Level 3 - Inserting relationships", - unit="relationship", - position=3, - leave=False, - ): - all_relationships_data.append(await result) + all_entities_data = await asyncio.gather( + *[ + _merge_nodes_then_upsert(k, v, knowledge_graph_inst, global_config) + for k, v in maybe_nodes.items() + ] + ) + + all_relationships_data = await asyncio.gather( + *[ + _merge_edges_then_upsert(k[0], k[1], v, knowledge_graph_inst, global_config) + for k, v in maybe_edges.items() + ] + ) if not len(all_entities_data) and not len(all_relationships_data): logger.warning( diff --git a/lightrag/utils.py b/lightrag/utils.py index 3ca93f85..d932f149 100644 --- a/lightrag/utils.py +++ b/lightrag/utils.py @@ -19,7 +19,6 @@ import tiktoken from lightrag.prompt import PROMPTS - VERBOSE_DEBUG = os.getenv("VERBOSE", "false").lower() == "true" @@ -84,7 +83,6 @@ class EmbeddingFunc: return await self.func(*args, **kwargs) - def locate_json_string_body_from_string(content: str) -> str | None: """Locate the JSON string body from a string""" try: @@ -715,4 +713,3 @@ def get_conversation_turns( ) return "\n".join(formatted_turns) - diff --git a/reproduce/Step_3.py b/reproduce/Step_3.py index 2c5d699c..f9ee3257 100644 --- a/reproduce/Step_3.py +++ b/reproduce/Step_3.py @@ -2,7 +2,6 @@ import re import json import asyncio from lightrag import LightRAG, QueryParam -from tqdm import tqdm def extract_queries(file_path): @@ -44,7 +43,7 @@ def run_queries_and_save_to_json( result_file.write("[\n") first_entry = True - for query_text in tqdm(queries, desc="Processing queries", unit="query"): + for query_text in queries: result, error = loop.run_until_complete( process_query(query_text, rag_instance, query_param) ) diff --git a/reproduce/Step_3_openai_compatible.py b/reproduce/Step_3_openai_compatible.py index 05e7d685..e4833adf 100644 --- a/reproduce/Step_3_openai_compatible.py +++ b/reproduce/Step_3_openai_compatible.py @@ -3,7 +3,6 @@ import re import json import asyncio from lightrag import LightRAG, QueryParam -from tqdm import tqdm from lightrag.llm.openai import openai_complete_if_cache, openai_embed from lightrag.utils import EmbeddingFunc import numpy as np @@ -76,7 +75,7 @@ def run_queries_and_save_to_json( result_file.write("[\n") first_entry = True - for query_text in tqdm(queries, desc="Processing queries", unit="query"): + for query_text in queries: result, error = loop.run_until_complete( process_query(query_text, rag_instance, query_param) ) diff --git a/requirements.txt b/requirements.txt index c5ccac23..b784daa9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,6 @@ tenacity # LLM packages tiktoken -tqdm xxhash # Extra libraries are installed when needed using pipmaster From ea41d08b9fbd5eade74ce04ffe0a870ad73278f0 Mon Sep 17 00:00:00 2001 From: Yannick Stephan Date: Tue, 18 Feb 2025 20:05:51 +0100 Subject: [PATCH 4/6] removed torch from requirement lightrag server --- README.md | 3 +++ lightrag/api/requirements.txt | 1 - lightrag/llm/hf.py | 49 +++++------------------------------ 3 files changed, 9 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index eaa058ad..e675efc7 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,9 @@ rag = LightRAG( Using Hugging Face Models * If you want to use Hugging Face models, you only need to set LightRAG as follows: + +See lightrag_hf_demo.py + ```python from lightrag.llm import hf_model_complete, hf_embed from transformers import AutoModel, AutoTokenizer diff --git a/lightrag/api/requirements.txt b/lightrag/api/requirements.txt index d0d00e29..0e7dfc90 100644 --- a/lightrag/api/requirements.txt +++ b/lightrag/api/requirements.txt @@ -6,5 +6,4 @@ python-dotenv python-multipart tenacity tiktoken -torch uvicorn diff --git a/lightrag/llm/hf.py b/lightrag/llm/hf.py index 075fc357..d678c611 100644 --- a/lightrag/llm/hf.py +++ b/lightrag/llm/hf.py @@ -1,47 +1,7 @@ -""" -Hugging face LLM Interface Module -========================== - -This module provides interfaces for interacting with Hugging face's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - transformers - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.hf import hf_model_complete, hf_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - import copy import os +from functools import lru_cache + import pipmaster as pm # Pipmaster for dynamic library install # install specific modules @@ -51,9 +11,12 @@ if not pm.is_installed("torch"): pm.install("torch") if not pm.is_installed("tenacity"): pm.install("tenacity") +if not pm.is_installed("numpy"): + pm.install("numpy") +if not pm.is_installed("tenacity"): + pm.install("tenacity") from transformers import AutoTokenizer, AutoModelForCausalLM -from functools import lru_cache from tenacity import ( retry, stop_after_attempt, From 011227e426f2306a7087d9ac420a28873dfbc6be Mon Sep 17 00:00:00 2001 From: Yannick Stephan Date: Tue, 18 Feb 2025 20:27:59 +0100 Subject: [PATCH 5/6] cleanup no required install --- README.md | 2 +- lightrag/api/requirements.txt | 2 +- lightrag/kg/milvus_impl.py | 6 +++++- lightrag/kg/networkx_impl.py | 28 +++++++++------------------- lightrag/kg/oracle_impl.py | 6 ++++-- requirements.txt | 6 ------ 6 files changed, 20 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index e675efc7..84bde9ce 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,7 @@ rag = LightRAG( * If you want to use Hugging Face models, you only need to set LightRAG as follows: -See lightrag_hf_demo.py +See `lightrag_hf_demo.py` ```python from lightrag.llm import hf_model_complete, hf_embed diff --git a/lightrag/api/requirements.txt b/lightrag/api/requirements.txt index 0e7dfc90..4e2991b7 100644 --- a/lightrag/api/requirements.txt +++ b/lightrag/api/requirements.txt @@ -1,9 +1,9 @@ +aiofiles ascii_colors fastapi numpy pipmaster python-dotenv -python-multipart tenacity tiktoken uvicorn diff --git a/lightrag/kg/milvus_impl.py b/lightrag/kg/milvus_impl.py index edefe0b1..b1746514 100644 --- a/lightrag/kg/milvus_impl.py +++ b/lightrag/kg/milvus_impl.py @@ -6,12 +6,16 @@ import numpy as np from lightrag.utils import logger from ..base import BaseVectorStorage import pipmaster as pm -import configparser + + +if not pm.is_installed("configparser"): + pm.install("configparser") if not pm.is_installed("pymilvus"): pm.install("pymilvus") try: + import configparser from pymilvus import MilvusClient except ImportError as e: raise ImportError( diff --git a/lightrag/kg/networkx_impl.py b/lightrag/kg/networkx_impl.py index 04bb3bd7..ac321d24 100644 --- a/lightrag/kg/networkx_impl.py +++ b/lightrag/kg/networkx_impl.py @@ -1,7 +1,6 @@ -import html import os from dataclasses import dataclass -from typing import Any, cast, final +from typing import Any, final import numpy as np @@ -14,8 +13,16 @@ from lightrag.utils import ( from lightrag.base import ( BaseGraphStorage, ) +import pipmaster as pm + +if not pm.is_installed("graspologic"): + pm.install("graspologic") + +if not pm.is_installed("networkx"): + pm.install("networkx") try: + from graspologic import embed import networkx as nx except ImportError as e: raise ImportError( @@ -39,21 +46,6 @@ class NetworkXStorage(BaseGraphStorage): ) nx.write_graphml(graph, file_name) - @staticmethod - def stable_largest_connected_component(graph: nx.Graph) -> nx.Graph: - """Refer to https://github.com/microsoft/graphrag/index/graph/utils/stable_lcc.py - Return the largest connected component of the graph, with nodes and edges sorted in a stable way. - """ - from graspologic.utils import largest_connected_component - - graph = graph.copy() - graph = cast(nx.Graph, largest_connected_component(graph)) - node_mapping = { - node: html.unescape(node.upper().strip()) for node in graph.nodes() - } # type: ignore - graph = nx.relabel_nodes(graph, node_mapping) - return NetworkXStorage._stabilize_graph(graph) - @staticmethod def _stabilize_graph(graph: nx.Graph) -> nx.Graph: """Refer to https://github.com/microsoft/graphrag/index/graph/utils/stable_lcc.py @@ -153,8 +145,6 @@ class NetworkXStorage(BaseGraphStorage): # @TODO: NOT USED async def _node2vec_embed(self): - from graspologic import embed - embeddings, nodes = embed.node2vec_embed( self._graph, **self.global_config["node2vec_params"], diff --git a/lightrag/kg/oracle_impl.py b/lightrag/kg/oracle_impl.py index 0b21f620..1bb12ccf 100644 --- a/lightrag/kg/oracle_impl.py +++ b/lightrag/kg/oracle_impl.py @@ -20,10 +20,14 @@ from ..utils import logger import pipmaster as pm +if not pm.is_installed("graspologic"): + pm.install("graspologic") + if not pm.is_installed("oracledb"): pm.install("oracledb") try: + from graspologic import embed import oracledb except ImportError as e: @@ -452,8 +456,6 @@ class OracleGraphStorage(BaseGraphStorage): async def _node2vec_embed(self): """为节点生成向量""" - from graspologic import embed - embeddings, nodes = embed.node2vec_embed( self._graph, **self.config["node2vec_params"], diff --git a/requirements.txt b/requirements.txt index b784daa9..26f5655d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,6 @@ -accelerate -aiofiles aiohttp configparser -# File manipulation libraries -docling -graspologic - # database packages networkx From 55cd900e8e5b918bb174316e23a319494cdc5da7 Mon Sep 17 00:00:00 2001 From: Yannick Stephan Date: Tue, 18 Feb 2025 21:12:06 +0100 Subject: [PATCH 6/6] clean comments and unused libs --- lightrag/llm/azure_openai.py | 43 ------------- lightrag/llm/bedrock.py | 43 ------------- lightrag/llm/jina.py | 40 ------------ lightrag/llm/lmdeploy.py | 42 ------------- lightrag/llm/lollms.py | 63 ------------------- lightrag/llm/nvidia_openai.py | 44 +------------ lightrag/llm/openai.py | 42 ------------- lightrag/llm/siliconcloud.py | 40 ------------ lightrag/llm/zhipu.py | 42 ------------- lightrag/prompt.py | 3 +- .../lightrag_visualizer/graph_visualizer.py | 7 --- requirements.txt | 2 - .../test_lightrag_ollama_chat.py | 0 13 files changed, 3 insertions(+), 408 deletions(-) rename test_lightrag_ollama_chat.py => tests/test_lightrag_ollama_chat.py (100%) diff --git a/lightrag/llm/azure_openai.py b/lightrag/llm/azure_openai.py index 4d15a674..84e45cfb 100644 --- a/lightrag/llm/azure_openai.py +++ b/lightrag/llm/azure_openai.py @@ -1,46 +1,3 @@ -""" -Azure OpenAI LLM Interface Module -========================== - -This module provides interfaces for interacting with aure openai's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - openai - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.azure_openai import azure_openai_model_complete, azure_openai_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - - import os import pipmaster as pm # Pipmaster for dynamic library install diff --git a/lightrag/llm/bedrock.py b/lightrag/llm/bedrock.py index f3b2143c..615d3453 100644 --- a/lightrag/llm/bedrock.py +++ b/lightrag/llm/bedrock.py @@ -1,46 +1,3 @@ -""" -Bedrock LLM Interface Module -========================== - -This module provides interfaces for interacting with Bedrock's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - aioboto3, tenacity - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.bebrock import bebrock_model_complete, bebrock_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - - import copy import os import json diff --git a/lightrag/llm/jina.py b/lightrag/llm/jina.py index 62404dde..c3484b39 100644 --- a/lightrag/llm/jina.py +++ b/lightrag/llm/jina.py @@ -1,43 +1,3 @@ -""" -Jina Embedding Interface Module -========================== - -This module provides interfaces for interacting with jina system, -including embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added embedding generation - -Dependencies: - - tenacity - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.jina import jina_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - import os import pipmaster as pm # Pipmaster for dynamic library install diff --git a/lightrag/llm/lmdeploy.py b/lightrag/llm/lmdeploy.py index 99d1c807..acf51c23 100644 --- a/lightrag/llm/lmdeploy.py +++ b/lightrag/llm/lmdeploy.py @@ -1,45 +1,3 @@ -""" -LMDeploy LLM Interface Module -========================== - -This module provides interfaces for interacting with LMDeploy's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - tenacity - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.lmdeploy import lmdeploy_model_complete, lmdeploy_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - import pipmaster as pm # Pipmaster for dynamic library install # install specific modules diff --git a/lightrag/llm/lollms.py b/lightrag/llm/lollms.py index 00dd1da9..93d7e155 100644 --- a/lightrag/llm/lollms.py +++ b/lightrag/llm/lollms.py @@ -1,66 +1,3 @@ -""" -LoLLMs (Lord of Large Language Models) Interface Module -===================================================== - -This module provides the official interface for interacting with LoLLMs (Lord of Large Language and multimodal Systems), -a unified framework for AI model interaction and deployment. - -LoLLMs is designed as a "one tool to rule them all" solution, providing seamless integration -with various AI models while maintaining high performance and user-friendly interfaces. - -Author: ParisNeo -Created: 2024-01-24 -License: Apache 2.0 - -Copyright (c) 2024 ParisNeo - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -Version: 2.0.0 - -Change Log: -- 2.0.0 (2024-01-24): - * Added async support for model inference - * Implemented streaming capabilities - * Added embedding generation functionality - * Enhanced parameter handling - * Improved error handling and timeout management - -Dependencies: - - aiohttp - - numpy - - Python >= 3.10 - -Features: - - Async text generation with streaming support - - Embedding generation - - Configurable model parameters - - System prompt and chat history support - - Timeout handling - - API key authentication - -Usage: - from llm_interfaces.lollms import lollms_model_complete, lollms_embed - -Project Repository: https://github.com/ParisNeo/lollms -Documentation: https://github.com/ParisNeo/lollms/docs -""" - -__version__ = "1.0.0" -__author__ = "ParisNeo" -__status__ = "Production" -__project_url__ = "https://github.com/ParisNeo/lollms" -__doc_url__ = "https://github.com/ParisNeo/lollms/docs" import sys if sys.version_info < (3, 9): diff --git a/lightrag/llm/nvidia_openai.py b/lightrag/llm/nvidia_openai.py index f298039d..e711c4ac 100644 --- a/lightrag/llm/nvidia_openai.py +++ b/lightrag/llm/nvidia_openai.py @@ -1,46 +1,3 @@ -""" -OpenAI LLM Interface Module -========================== - -This module provides interfaces for interacting with openai's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - openai - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.nvidia_openai import nvidia_openai_model_complete, nvidia_openai_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - - import sys import os @@ -48,6 +5,7 @@ if sys.version_info < (3, 9): pass else: pass + import pipmaster as pm # Pipmaster for dynamic library install # install specific modules diff --git a/lightrag/llm/openai.py b/lightrag/llm/openai.py index aaaaf406..70aa0ceb 100644 --- a/lightrag/llm/openai.py +++ b/lightrag/llm/openai.py @@ -1,45 +1,3 @@ -""" -OpenAI LLM Interface Module -========================== - -This module provides interfaces for interacting with openai's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - openai - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.openai import openai_model_complete, openai_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - from ..utils import verbose_debug, VERBOSE_DEBUG import sys import os diff --git a/lightrag/llm/siliconcloud.py b/lightrag/llm/siliconcloud.py index 4aaaf7e7..41adb96e 100644 --- a/lightrag/llm/siliconcloud.py +++ b/lightrag/llm/siliconcloud.py @@ -1,43 +1,3 @@ -""" -SiliconCloud Embedding Interface Module -========================== - -This module provides interfaces for interacting with SiliconCloud system, -including embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added embedding generation - -Dependencies: - - tenacity - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.siliconcloud import siliconcloud_model_complete, siliconcloud_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - import sys if sys.version_info < (3, 9): diff --git a/lightrag/llm/zhipu.py b/lightrag/llm/zhipu.py index 5a73f41d..dede42dc 100644 --- a/lightrag/llm/zhipu.py +++ b/lightrag/llm/zhipu.py @@ -1,45 +1,3 @@ -""" -Zhipu LLM Interface Module -========================== - -This module provides interfaces for interacting with LMDeploy's language models, -including text generation and embedding capabilities. - -Author: Lightrag team -Created: 2024-01-24 -License: MIT License - -Copyright (c) 2024 Lightrag - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -Version: 1.0.0 - -Change Log: -- 1.0.0 (2024-01-24): Initial release - * Added async chat completion support - * Added embedding generation - * Added stream response capability - -Dependencies: - - tenacity - - numpy - - pipmaster - - Python >= 3.10 - -Usage: - from llm_interfaces.zhipu import zhipu_model_complete, zhipu_embed -""" - -__version__ = "1.0.0" -__author__ = "lightrag Team" -__status__ = "Production" - import sys import re import json diff --git a/lightrag/prompt.py b/lightrag/prompt.py index f4f5e38a..a25ab672 100644 --- a/lightrag/prompt.py +++ b/lightrag/prompt.py @@ -1,8 +1,9 @@ from __future__ import annotations +from typing import Any GRAPH_FIELD_SEP = "" -PROMPTS = {} +PROMPTS: dict[str, Any] = {} PROMPTS["DEFAULT_LANGUAGE"] = "English" PROMPTS["DEFAULT_TUPLE_DELIMITER"] = "<|>" diff --git a/lightrag/tools/lightrag_visualizer/graph_visualizer.py b/lightrag/tools/lightrag_visualizer/graph_visualizer.py index ad449f91..8a6f0976 100644 --- a/lightrag/tools/lightrag_visualizer/graph_visualizer.py +++ b/lightrag/tools/lightrag_visualizer/graph_visualizer.py @@ -1,10 +1,3 @@ -""" -3D GraphML Viewer using Dear ImGui and ModernGL -Author: ParisNeo, ArnoChen -Description: An interactive 3D GraphML viewer using imgui_bundle and ModernGL -Version: 2.0 -""" - from typing import Optional, Tuple, Dict, List import numpy as np import networkx as nx diff --git a/requirements.txt b/requirements.txt index 26f5655d..03d93aa3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,9 +13,7 @@ python-dotenv setuptools tenacity - # LLM packages tiktoken -xxhash # Extra libraries are installed when needed using pipmaster diff --git a/test_lightrag_ollama_chat.py b/tests/test_lightrag_ollama_chat.py similarity index 100% rename from test_lightrag_ollama_chat.py rename to tests/test_lightrag_ollama_chat.py