chore: init monorepo snapshot
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
from openai import OpenAI
|
||||
|
||||
# os.environ["OPENAI_API_KEY"] = ""
|
||||
|
||||
|
||||
def openai_complete_if_cache(
|
||||
model="gpt-4o-mini", prompt=None, system_prompt=None, history_messages=[], **kwargs
|
||||
) -> str:
|
||||
openai_client = OpenAI()
|
||||
|
||||
messages = []
|
||||
if system_prompt:
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
messages.extend(history_messages)
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
|
||||
response = openai_client.chat.completions.create(
|
||||
model=model, messages=messages, **kwargs
|
||||
)
|
||||
return response.choices[0].message.content
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
description = ""
|
||||
prompt = f"""
|
||||
Given the following description of a dataset:
|
||||
|
||||
{description}
|
||||
|
||||
Please identify 5 potential users who would engage with this dataset. For each user, list 5 tasks they would perform with this dataset. Then, for each (user, task) combination, generate 5 questions that require a high-level understanding of the entire dataset.
|
||||
|
||||
Output the results in the following structure:
|
||||
- User 1: [user description]
|
||||
- Task 1: [task description]
|
||||
- Question 1:
|
||||
- Question 2:
|
||||
- Question 3:
|
||||
- Question 4:
|
||||
- Question 5:
|
||||
- Task 2: [task description]
|
||||
...
|
||||
- Task 5: [task description]
|
||||
- User 2: [user description]
|
||||
...
|
||||
- User 5: [user description]
|
||||
...
|
||||
"""
|
||||
|
||||
result = openai_complete_if_cache(model="gpt-4o-mini", prompt=prompt)
|
||||
|
||||
file_path = "./queries.txt"
|
||||
with open(file_path, "w") as file:
|
||||
file.write(result)
|
||||
|
||||
print(f"Queries written to {file_path}")
|
||||
@@ -0,0 +1,34 @@
|
||||
import pipmaster as pm
|
||||
|
||||
if not pm.is_installed("pyvis"):
|
||||
pm.install("pyvis")
|
||||
if not pm.is_installed("networkx"):
|
||||
pm.install("networkx")
|
||||
|
||||
import networkx as nx
|
||||
from pyvis.network import Network
|
||||
import random
|
||||
|
||||
# Load the GraphML file
|
||||
G = nx.read_graphml("./dickens/graph_chunk_entity_relation.graphml")
|
||||
|
||||
# Create a Pyvis network
|
||||
net = Network(height="100vh", notebook=True)
|
||||
|
||||
# Convert NetworkX graph to Pyvis network
|
||||
net.from_nx(G)
|
||||
|
||||
|
||||
# Add colors and title to nodes
|
||||
for node in net.nodes:
|
||||
node["color"] = "#{:06x}".format(random.randint(0, 0xFFFFFF))
|
||||
if "description" in node:
|
||||
node["title"] = node["description"]
|
||||
|
||||
# Add title to edges
|
||||
for edge in net.edges:
|
||||
if "description" in edge:
|
||||
edge["title"] = edge["description"]
|
||||
|
||||
# Save and display the network
|
||||
net.show("knowledge_graph.html")
|
||||
@@ -0,0 +1,186 @@
|
||||
import os
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
from neo4j import GraphDatabase
|
||||
|
||||
# Constants
|
||||
WORKING_DIR = "./dickens"
|
||||
BATCH_SIZE_NODES = 500
|
||||
BATCH_SIZE_EDGES = 100
|
||||
|
||||
# Neo4j connection credentials
|
||||
NEO4J_URI = "bolt://localhost:7687"
|
||||
NEO4J_USERNAME = "neo4j"
|
||||
NEO4J_PASSWORD = "your_password"
|
||||
|
||||
|
||||
def xml_to_json(xml_file):
|
||||
try:
|
||||
tree = ET.parse(xml_file)
|
||||
root = tree.getroot()
|
||||
|
||||
# Print the root element's tag and attributes to confirm the file has been correctly loaded
|
||||
print(f"Root element: {root.tag}")
|
||||
print(f"Root attributes: {root.attrib}")
|
||||
|
||||
data = {"nodes": [], "edges": []}
|
||||
|
||||
# Use namespace
|
||||
namespace = {"": "http://graphml.graphdrawing.org/xmlns"}
|
||||
|
||||
for node in root.findall(".//node", namespace):
|
||||
node_data = {
|
||||
"id": node.get("id").strip('"'),
|
||||
"entity_type": node.find("./data[@key='d1']", namespace).text.strip('"')
|
||||
if node.find("./data[@key='d1']", namespace) is not None
|
||||
else "",
|
||||
"description": node.find("./data[@key='d2']", namespace).text
|
||||
if node.find("./data[@key='d2']", namespace) is not None
|
||||
else "",
|
||||
"source_id": node.find("./data[@key='d3']", namespace).text
|
||||
if node.find("./data[@key='d3']", namespace) is not None
|
||||
else "",
|
||||
}
|
||||
data["nodes"].append(node_data)
|
||||
|
||||
for edge in root.findall(".//edge", namespace):
|
||||
edge_data = {
|
||||
"source": edge.get("source").strip('"'),
|
||||
"target": edge.get("target").strip('"'),
|
||||
"weight": float(edge.find("./data[@key='d5']", namespace).text)
|
||||
if edge.find("./data[@key='d5']", namespace) is not None
|
||||
else 0.0,
|
||||
"description": edge.find("./data[@key='d6']", namespace).text
|
||||
if edge.find("./data[@key='d6']", namespace) is not None
|
||||
else "",
|
||||
"keywords": edge.find("./data[@key='d9']", namespace).text
|
||||
if edge.find("./data[@key='d9']", namespace) is not None
|
||||
else "",
|
||||
"source_id": edge.find("./data[@key='d8']", namespace).text
|
||||
if edge.find("./data[@key='d8']", namespace) is not None
|
||||
else "",
|
||||
}
|
||||
data["edges"].append(edge_data)
|
||||
|
||||
# Print the number of nodes and edges found
|
||||
print(f"Found {len(data['nodes'])} nodes and {len(data['edges'])} edges")
|
||||
|
||||
return data
|
||||
except ET.ParseError as e:
|
||||
print(f"Error parsing XML file: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def convert_xml_to_json(xml_path, output_path):
|
||||
"""Converts XML file to JSON and saves the output."""
|
||||
if not os.path.exists(xml_path):
|
||||
print(f"Error: File not found - {xml_path}")
|
||||
return None
|
||||
|
||||
json_data = xml_to_json(xml_path)
|
||||
if json_data:
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(json_data, f, ensure_ascii=False, indent=2)
|
||||
print(f"JSON file created: {output_path}")
|
||||
return json_data
|
||||
else:
|
||||
print("Failed to create JSON data")
|
||||
return None
|
||||
|
||||
|
||||
def process_in_batches(tx, query, data, batch_size):
|
||||
"""Process data in batches and execute the given query."""
|
||||
for i in range(0, len(data), batch_size):
|
||||
batch = data[i : i + batch_size]
|
||||
tx.run(query, {"nodes": batch} if "nodes" in query else {"edges": batch})
|
||||
|
||||
|
||||
def main():
|
||||
# Paths
|
||||
xml_file = os.path.join(WORKING_DIR, "graph_chunk_entity_relation.graphml")
|
||||
json_file = os.path.join(WORKING_DIR, "graph_data.json")
|
||||
|
||||
# Convert XML to JSON
|
||||
json_data = convert_xml_to_json(xml_file, json_file)
|
||||
if json_data is None:
|
||||
return
|
||||
|
||||
# Load nodes and edges
|
||||
nodes = json_data.get("nodes", [])
|
||||
edges = json_data.get("edges", [])
|
||||
|
||||
# Neo4j queries
|
||||
create_nodes_query = """
|
||||
UNWIND $nodes AS node
|
||||
MERGE (e:Entity {id: node.id})
|
||||
SET e.entity_type = node.entity_type,
|
||||
e.description = node.description,
|
||||
e.source_id = node.source_id,
|
||||
e.displayName = node.id
|
||||
REMOVE e:Entity
|
||||
WITH e, node
|
||||
CALL apoc.create.addLabels(e, [node.id]) YIELD node AS labeledNode
|
||||
RETURN count(*)
|
||||
"""
|
||||
|
||||
create_edges_query = """
|
||||
UNWIND $edges AS edge
|
||||
MATCH (source {id: edge.source})
|
||||
MATCH (target {id: edge.target})
|
||||
WITH source, target, edge,
|
||||
CASE
|
||||
WHEN edge.keywords CONTAINS 'lead' THEN 'lead'
|
||||
WHEN edge.keywords CONTAINS 'participate' THEN 'participate'
|
||||
WHEN edge.keywords CONTAINS 'uses' THEN 'uses'
|
||||
WHEN edge.keywords CONTAINS 'located' THEN 'located'
|
||||
WHEN edge.keywords CONTAINS 'occurs' THEN 'occurs'
|
||||
ELSE REPLACE(SPLIT(edge.keywords, ',')[0], '\"', '')
|
||||
END AS relType
|
||||
CALL apoc.create.relationship(source, relType, {
|
||||
weight: edge.weight,
|
||||
description: edge.description,
|
||||
keywords: edge.keywords,
|
||||
source_id: edge.source_id
|
||||
}, target) YIELD rel
|
||||
RETURN count(*)
|
||||
"""
|
||||
|
||||
set_displayname_and_labels_query = """
|
||||
MATCH (n)
|
||||
SET n.displayName = n.id
|
||||
WITH n
|
||||
CALL apoc.create.setLabels(n, [n.entity_type]) YIELD node
|
||||
RETURN count(*)
|
||||
"""
|
||||
|
||||
# Create a Neo4j driver
|
||||
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USERNAME, NEO4J_PASSWORD))
|
||||
|
||||
try:
|
||||
# Execute queries in batches
|
||||
with driver.session() as session:
|
||||
# Insert nodes in batches
|
||||
session.execute_write(
|
||||
process_in_batches, create_nodes_query, nodes, BATCH_SIZE_NODES
|
||||
)
|
||||
|
||||
# Insert edges in batches
|
||||
session.execute_write(
|
||||
process_in_batches, create_edges_query, edges, BATCH_SIZE_EDGES
|
||||
)
|
||||
|
||||
# Set displayName and labels
|
||||
session.run(set_displayname_and_labels_query)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error occurred: {e}")
|
||||
|
||||
finally:
|
||||
driver.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,115 @@
|
||||
import os
|
||||
from lightrag import LightRAG
|
||||
from lightrag.llm.openai import gpt_4o_mini_complete
|
||||
#########
|
||||
# Uncomment the below two lines if running in a jupyter notebook to handle the async nature of rag.insert()
|
||||
# import nest_asyncio
|
||||
# nest_asyncio.apply()
|
||||
#########
|
||||
|
||||
WORKING_DIR = "./custom_kg"
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=gpt_4o_mini_complete, # Use gpt_4o_mini_complete LLM model
|
||||
# llm_model_func=gpt_4o_complete # Optionally, use a stronger model
|
||||
)
|
||||
|
||||
custom_kg = {
|
||||
"entities": [
|
||||
{
|
||||
"entity_name": "CompanyA",
|
||||
"entity_type": "Organization",
|
||||
"description": "A major technology company",
|
||||
"source_id": "Source1",
|
||||
},
|
||||
{
|
||||
"entity_name": "ProductX",
|
||||
"entity_type": "Product",
|
||||
"description": "A popular product developed by CompanyA",
|
||||
"source_id": "Source1",
|
||||
},
|
||||
{
|
||||
"entity_name": "PersonA",
|
||||
"entity_type": "Person",
|
||||
"description": "A renowned researcher in AI",
|
||||
"source_id": "Source2",
|
||||
},
|
||||
{
|
||||
"entity_name": "UniversityB",
|
||||
"entity_type": "Organization",
|
||||
"description": "A leading university specializing in technology and sciences",
|
||||
"source_id": "Source2",
|
||||
},
|
||||
{
|
||||
"entity_name": "CityC",
|
||||
"entity_type": "Location",
|
||||
"description": "A large metropolitan city known for its culture and economy",
|
||||
"source_id": "Source3",
|
||||
},
|
||||
{
|
||||
"entity_name": "EventY",
|
||||
"entity_type": "Event",
|
||||
"description": "An annual technology conference held in CityC",
|
||||
"source_id": "Source3",
|
||||
},
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"src_id": "CompanyA",
|
||||
"tgt_id": "ProductX",
|
||||
"description": "CompanyA develops ProductX",
|
||||
"keywords": "develop, produce",
|
||||
"weight": 1.0,
|
||||
"source_id": "Source1",
|
||||
},
|
||||
{
|
||||
"src_id": "PersonA",
|
||||
"tgt_id": "UniversityB",
|
||||
"description": "PersonA works at UniversityB",
|
||||
"keywords": "employment, affiliation",
|
||||
"weight": 0.9,
|
||||
"source_id": "Source2",
|
||||
},
|
||||
{
|
||||
"src_id": "CityC",
|
||||
"tgt_id": "EventY",
|
||||
"description": "EventY is hosted in CityC",
|
||||
"keywords": "host, location",
|
||||
"weight": 0.8,
|
||||
"source_id": "Source3",
|
||||
},
|
||||
],
|
||||
"chunks": [
|
||||
{
|
||||
"content": "ProductX, developed by CompanyA, has revolutionized the market with its cutting-edge features.",
|
||||
"source_id": "Source1",
|
||||
"source_chunk_index": 0,
|
||||
},
|
||||
{
|
||||
"content": "One outstanding feature of ProductX is its advanced AI capabilities.",
|
||||
"source_id": "Source1",
|
||||
"chunk_order_index": 1,
|
||||
},
|
||||
{
|
||||
"content": "PersonA is a prominent researcher at UniversityB, focusing on artificial intelligence and machine learning.",
|
||||
"source_id": "Source2",
|
||||
"source_chunk_index": 0,
|
||||
},
|
||||
{
|
||||
"content": "EventY, held in CityC, attracts technology enthusiasts and companies from around the globe.",
|
||||
"source_id": "Source3",
|
||||
"source_chunk_index": 0,
|
||||
},
|
||||
{
|
||||
"content": "None",
|
||||
"source_id": "UNKNOWN",
|
||||
"source_chunk_index": 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
rag.insert_custom_kg(custom_kg)
|
||||
@@ -0,0 +1,126 @@
|
||||
import os
|
||||
import asyncio
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
import numpy as np
|
||||
from dotenv import load_dotenv
|
||||
import logging
|
||||
from openai import AzureOpenAI
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
AZURE_OPENAI_API_VERSION = os.getenv("AZURE_OPENAI_API_VERSION")
|
||||
AZURE_OPENAI_DEPLOYMENT = os.getenv("AZURE_OPENAI_DEPLOYMENT")
|
||||
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
|
||||
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
|
||||
|
||||
AZURE_EMBEDDING_DEPLOYMENT = os.getenv("AZURE_EMBEDDING_DEPLOYMENT")
|
||||
AZURE_EMBEDDING_API_VERSION = os.getenv("AZURE_EMBEDDING_API_VERSION")
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
|
||||
if os.path.exists(WORKING_DIR):
|
||||
import shutil
|
||||
|
||||
shutil.rmtree(WORKING_DIR)
|
||||
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def llm_model_func(
|
||||
prompt, system_prompt=None, history_messages=[], keyword_extraction=False, **kwargs
|
||||
) -> str:
|
||||
client = AzureOpenAI(
|
||||
api_key=AZURE_OPENAI_API_KEY,
|
||||
api_version=AZURE_OPENAI_API_VERSION,
|
||||
azure_endpoint=AZURE_OPENAI_ENDPOINT,
|
||||
)
|
||||
|
||||
messages = []
|
||||
if system_prompt:
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
if history_messages:
|
||||
messages.extend(history_messages)
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
|
||||
chat_completion = client.chat.completions.create(
|
||||
model=AZURE_OPENAI_DEPLOYMENT, # model = "deployment_name".
|
||||
messages=messages,
|
||||
temperature=kwargs.get("temperature", 0),
|
||||
top_p=kwargs.get("top_p", 1),
|
||||
n=kwargs.get("n", 1),
|
||||
)
|
||||
return chat_completion.choices[0].message.content
|
||||
|
||||
|
||||
async def embedding_func(texts: list[str]) -> np.ndarray:
|
||||
client = AzureOpenAI(
|
||||
api_key=AZURE_OPENAI_API_KEY,
|
||||
api_version=AZURE_EMBEDDING_API_VERSION,
|
||||
azure_endpoint=AZURE_OPENAI_ENDPOINT,
|
||||
)
|
||||
embedding = client.embeddings.create(model=AZURE_EMBEDDING_DEPLOYMENT, input=texts)
|
||||
|
||||
embeddings = [item.embedding for item in embedding.data]
|
||||
return np.array(embeddings)
|
||||
|
||||
|
||||
async def test_funcs():
|
||||
result = await llm_model_func("How are you?")
|
||||
print("Resposta do llm_model_func: ", result)
|
||||
|
||||
result = await embedding_func(["How are you?"])
|
||||
print("Resultado do embedding_func: ", result.shape)
|
||||
print("Dimensão da embedding: ", result.shape[1])
|
||||
|
||||
|
||||
asyncio.run(test_funcs())
|
||||
|
||||
embedding_dimension = 3072
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=embedding_dimension,
|
||||
max_token_size=8192,
|
||||
func=embedding_func,
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
book1 = open("./book_1.txt", encoding="utf-8")
|
||||
book2 = open("./book_2.txt", encoding="utf-8")
|
||||
|
||||
rag.insert([book1.read(), book2.read()])
|
||||
|
||||
query_text = "What are the main themes?"
|
||||
|
||||
print("Result (Naive):")
|
||||
print(rag.query(query_text, param=QueryParam(mode="naive")))
|
||||
|
||||
print("\nResult (Local):")
|
||||
print(rag.query(query_text, param=QueryParam(mode="local")))
|
||||
|
||||
print("\nResult (Global):")
|
||||
print(rag.query(query_text, param=QueryParam(mode="global")))
|
||||
|
||||
print("\nResult (Hybrid):")
|
||||
print(rag.query(query_text, param=QueryParam(mode="hybrid")))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,217 @@
|
||||
import asyncio
|
||||
import os
|
||||
import inspect
|
||||
import logging
|
||||
import logging.config
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.ollama import ollama_model_complete, ollama_embed
|
||||
from lightrag.utils import EmbeddingFunc, logger, set_verbose_debug
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(dotenv_path=".env", override=False)
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
|
||||
|
||||
def configure_logging():
|
||||
"""Configure logging for the application"""
|
||||
|
||||
# Reset any existing handlers to ensure clean configuration
|
||||
for logger_name in ["uvicorn", "uvicorn.access", "uvicorn.error", "lightrag"]:
|
||||
logger_instance = logging.getLogger(logger_name)
|
||||
logger_instance.handlers = []
|
||||
logger_instance.filters = []
|
||||
|
||||
# Get log directory path from environment variable or use current directory
|
||||
log_dir = os.getenv("LOG_DIR", os.getcwd())
|
||||
log_file_path = os.path.abspath(os.path.join(log_dir, "lightrag_ollama_demo.log"))
|
||||
|
||||
print(f"\nLightRAG compatible demo log file: {log_file_path}\n")
|
||||
os.makedirs(os.path.dirname(log_file_path), exist_ok=True)
|
||||
|
||||
# Get log file max size and backup count from environment variables
|
||||
log_max_bytes = int(os.getenv("LOG_MAX_BYTES", 10485760)) # Default 10MB
|
||||
log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", 5)) # Default 5 backups
|
||||
|
||||
logging.config.dictConfig(
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "%(levelname)s: %(message)s",
|
||||
},
|
||||
"detailed": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"formatter": "default",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr",
|
||||
},
|
||||
"file": {
|
||||
"formatter": "detailed",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": log_file_path,
|
||||
"maxBytes": log_max_bytes,
|
||||
"backupCount": log_backup_count,
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"lightrag": {
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
# Set the logger level to INFO
|
||||
logger.setLevel(logging.INFO)
|
||||
# Enable verbose debug if needed
|
||||
set_verbose_debug(os.getenv("VERBOSE_DEBUG", "false").lower() == "true")
|
||||
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=ollama_model_complete,
|
||||
llm_model_name=os.getenv("LLM_MODEL", "qwen2.5-coder:7b"),
|
||||
summary_max_tokens=8192,
|
||||
llm_model_kwargs={
|
||||
"host": os.getenv("LLM_BINDING_HOST", "http://localhost:11434"),
|
||||
"options": {"num_ctx": 8192},
|
||||
"timeout": int(os.getenv("TIMEOUT", "300")),
|
||||
},
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=int(os.getenv("EMBEDDING_DIM", "1024")),
|
||||
max_token_size=int(os.getenv("MAX_EMBED_TOKENS", "8192")),
|
||||
func=lambda texts: ollama_embed(
|
||||
texts,
|
||||
embed_model=os.getenv("EMBEDDING_MODEL", "bge-m3:latest"),
|
||||
host=os.getenv("EMBEDDING_BINDING_HOST", "http://localhost:11434"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
async def print_stream(stream):
|
||||
async for chunk in stream:
|
||||
print(chunk, end="", flush=True)
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
# Clear old data files
|
||||
files_to_delete = [
|
||||
"graph_chunk_entity_relation.graphml",
|
||||
"kv_store_doc_status.json",
|
||||
"kv_store_full_docs.json",
|
||||
"kv_store_text_chunks.json",
|
||||
"vdb_chunks.json",
|
||||
"vdb_entities.json",
|
||||
"vdb_relationships.json",
|
||||
]
|
||||
|
||||
for file in files_to_delete:
|
||||
file_path = os.path.join(WORKING_DIR, file)
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
print(f"Deleting old file:: {file_path}")
|
||||
|
||||
# Initialize RAG instance
|
||||
rag = await initialize_rag()
|
||||
|
||||
# Test embedding function
|
||||
test_text = ["This is a test string for embedding."]
|
||||
embedding = await rag.embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
print("\n=======================")
|
||||
print("Test embedding function")
|
||||
print("========================")
|
||||
print(f"Test dict: {test_text}")
|
||||
print(f"Detected embedding dimension: {embedding_dim}\n\n")
|
||||
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
await rag.ainsert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print("\n=====================")
|
||||
print("Query mode: naive")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="naive", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform local search
|
||||
print("\n=====================")
|
||||
print("Query mode: local")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="local", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform global search
|
||||
print("\n=====================")
|
||||
print("Query mode: global")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="global", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform hybrid search
|
||||
print("\n=====================")
|
||||
print("Query mode: hybrid")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="hybrid", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
finally:
|
||||
if rag:
|
||||
await rag.llm_response_cache.index_done_callback()
|
||||
await rag.finalize_storages()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging before running the main function
|
||||
configure_logging()
|
||||
asyncio.run(main())
|
||||
print("\nDone!")
|
||||
@@ -0,0 +1,227 @@
|
||||
import os
|
||||
import asyncio
|
||||
import inspect
|
||||
import logging
|
||||
import logging.config
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.openai import openai_complete_if_cache
|
||||
from lightrag.llm.ollama import ollama_embed
|
||||
from lightrag.utils import EmbeddingFunc, logger, set_verbose_debug
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(dotenv_path=".env", override=False)
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
|
||||
|
||||
def configure_logging():
|
||||
"""Configure logging for the application"""
|
||||
|
||||
# Reset any existing handlers to ensure clean configuration
|
||||
for logger_name in ["uvicorn", "uvicorn.access", "uvicorn.error", "lightrag"]:
|
||||
logger_instance = logging.getLogger(logger_name)
|
||||
logger_instance.handlers = []
|
||||
logger_instance.filters = []
|
||||
|
||||
# Get log directory path from environment variable or use current directory
|
||||
log_dir = os.getenv("LOG_DIR", os.getcwd())
|
||||
log_file_path = os.path.abspath(
|
||||
os.path.join(log_dir, "lightrag_compatible_demo.log")
|
||||
)
|
||||
|
||||
print(f"\nLightRAG compatible demo log file: {log_file_path}\n")
|
||||
os.makedirs(os.path.dirname(log_dir), exist_ok=True)
|
||||
|
||||
# Get log file max size and backup count from environment variables
|
||||
log_max_bytes = int(os.getenv("LOG_MAX_BYTES", 10485760)) # Default 10MB
|
||||
log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", 5)) # Default 5 backups
|
||||
|
||||
logging.config.dictConfig(
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "%(levelname)s: %(message)s",
|
||||
},
|
||||
"detailed": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"formatter": "default",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr",
|
||||
},
|
||||
"file": {
|
||||
"formatter": "detailed",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": log_file_path,
|
||||
"maxBytes": log_max_bytes,
|
||||
"backupCount": log_backup_count,
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"lightrag": {
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
# Set the logger level to INFO
|
||||
logger.setLevel(logging.INFO)
|
||||
# Enable verbose debug if needed
|
||||
set_verbose_debug(os.getenv("VERBOSE_DEBUG", "false").lower() == "true")
|
||||
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def llm_model_func(
|
||||
prompt, system_prompt=None, history_messages=[], keyword_extraction=False, **kwargs
|
||||
) -> str:
|
||||
return await openai_complete_if_cache(
|
||||
os.getenv("LLM_MODEL", "deepseek-chat"),
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key=os.getenv("LLM_BINDING_API_KEY") or os.getenv("OPENAI_API_KEY"),
|
||||
base_url=os.getenv("LLM_BINDING_HOST", "https://api.deepseek.com"),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
async def print_stream(stream):
|
||||
async for chunk in stream:
|
||||
if chunk:
|
||||
print(chunk, end="", flush=True)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=int(os.getenv("EMBEDDING_DIM", "1024")),
|
||||
max_token_size=int(os.getenv("MAX_EMBED_TOKENS", "8192")),
|
||||
func=lambda texts: ollama_embed(
|
||||
texts,
|
||||
embed_model=os.getenv("EMBEDDING_MODEL", "bge-m3:latest"),
|
||||
host=os.getenv("EMBEDDING_BINDING_HOST", "http://localhost:11434"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
# Clear old data files
|
||||
files_to_delete = [
|
||||
"graph_chunk_entity_relation.graphml",
|
||||
"kv_store_doc_status.json",
|
||||
"kv_store_full_docs.json",
|
||||
"kv_store_text_chunks.json",
|
||||
"vdb_chunks.json",
|
||||
"vdb_entities.json",
|
||||
"vdb_relationships.json",
|
||||
]
|
||||
|
||||
for file in files_to_delete:
|
||||
file_path = os.path.join(WORKING_DIR, file)
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
print(f"Deleting old file:: {file_path}")
|
||||
|
||||
# Initialize RAG instance
|
||||
rag = await initialize_rag()
|
||||
|
||||
# Test embedding function
|
||||
test_text = ["This is a test string for embedding."]
|
||||
embedding = await rag.embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
print("\n=======================")
|
||||
print("Test embedding function")
|
||||
print("========================")
|
||||
print(f"Test dict: {test_text}")
|
||||
print(f"Detected embedding dimension: {embedding_dim}\n\n")
|
||||
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
await rag.ainsert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print("\n=====================")
|
||||
print("Query mode: naive")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="naive", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform local search
|
||||
print("\n=====================")
|
||||
print("Query mode: local")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="local", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform global search
|
||||
print("\n=====================")
|
||||
print("Query mode: global")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="global", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform hybrid search
|
||||
print("\n=====================")
|
||||
print("Query mode: hybrid")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="hybrid", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
finally:
|
||||
if rag:
|
||||
await rag.finalize_storages()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging before running the main function
|
||||
configure_logging()
|
||||
asyncio.run(main())
|
||||
print("\nDone!")
|
||||
@@ -0,0 +1,189 @@
|
||||
import os
|
||||
import asyncio
|
||||
import logging
|
||||
import logging.config
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.openai import gpt_4o_mini_complete, openai_embed
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
from lightrag.utils import logger, set_verbose_debug
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
|
||||
|
||||
def configure_logging():
|
||||
"""Configure logging for the application"""
|
||||
|
||||
# Reset any existing handlers to ensure clean configuration
|
||||
for logger_name in ["uvicorn", "uvicorn.access", "uvicorn.error", "lightrag"]:
|
||||
logger_instance = logging.getLogger(logger_name)
|
||||
logger_instance.handlers = []
|
||||
logger_instance.filters = []
|
||||
|
||||
# Get log directory path from environment variable or use current directory
|
||||
log_dir = os.getenv("LOG_DIR", os.getcwd())
|
||||
log_file_path = os.path.abspath(os.path.join(log_dir, "lightrag_demo.log"))
|
||||
|
||||
print(f"\nLightRAG demo log file: {log_file_path}\n")
|
||||
os.makedirs(os.path.dirname(log_dir), exist_ok=True)
|
||||
|
||||
# Get log file max size and backup count from environment variables
|
||||
log_max_bytes = int(os.getenv("LOG_MAX_BYTES", 10485760)) # Default 10MB
|
||||
log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", 5)) # Default 5 backups
|
||||
|
||||
logging.config.dictConfig(
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "%(levelname)s: %(message)s",
|
||||
},
|
||||
"detailed": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"formatter": "default",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr",
|
||||
},
|
||||
"file": {
|
||||
"formatter": "detailed",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": log_file_path,
|
||||
"maxBytes": log_max_bytes,
|
||||
"backupCount": log_backup_count,
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"lightrag": {
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
# Set the logger level to INFO
|
||||
logger.setLevel(logging.INFO)
|
||||
# Enable verbose debug if needed
|
||||
set_verbose_debug(os.getenv("VERBOSE_DEBUG", "false").lower() == "true")
|
||||
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
embedding_func=openai_embed,
|
||||
llm_model_func=gpt_4o_mini_complete,
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
async def main():
|
||||
# Check if OPENAI_API_KEY environment variable exists
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print(
|
||||
"Error: OPENAI_API_KEY environment variable is not set. Please set this variable before running the program."
|
||||
)
|
||||
print("You can set the environment variable by running:")
|
||||
print(" export OPENAI_API_KEY='your-openai-api-key'")
|
||||
return # Exit the async function
|
||||
|
||||
try:
|
||||
# Clear old data files
|
||||
files_to_delete = [
|
||||
"graph_chunk_entity_relation.graphml",
|
||||
"kv_store_doc_status.json",
|
||||
"kv_store_full_docs.json",
|
||||
"kv_store_text_chunks.json",
|
||||
"vdb_chunks.json",
|
||||
"vdb_entities.json",
|
||||
"vdb_relationships.json",
|
||||
]
|
||||
|
||||
for file in files_to_delete:
|
||||
file_path = os.path.join(WORKING_DIR, file)
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
print(f"Deleting old file:: {file_path}")
|
||||
|
||||
# Initialize RAG instance
|
||||
rag = await initialize_rag()
|
||||
|
||||
# Test embedding function
|
||||
test_text = ["This is a test string for embedding."]
|
||||
embedding = await rag.embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
print("\n=======================")
|
||||
print("Test embedding function")
|
||||
print("========================")
|
||||
print(f"Test dict: {test_text}")
|
||||
print(f"Detected embedding dimension: {embedding_dim}\n\n")
|
||||
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
await rag.ainsert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print("\n=====================")
|
||||
print("Query mode: naive")
|
||||
print("=====================")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform local search
|
||||
print("\n=====================")
|
||||
print("Query mode: local")
|
||||
print("=====================")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform global search
|
||||
print("\n=====================")
|
||||
print("Query mode: global")
|
||||
print("=====================")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="global"),
|
||||
)
|
||||
)
|
||||
|
||||
# Perform hybrid search
|
||||
print("\n=====================")
|
||||
print("Query mode: hybrid")
|
||||
print("=====================")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="hybrid"),
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
finally:
|
||||
if rag:
|
||||
await rag.finalize_storages()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging before running the main function
|
||||
configure_logging()
|
||||
asyncio.run(main())
|
||||
print("\nDone!")
|
||||
@@ -0,0 +1,107 @@
|
||||
import os
|
||||
import asyncio
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.openai import gpt_4o_mini_complete, openai_embed
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
import numpy as np
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
#########
|
||||
# Uncomment the below two lines if running in a jupyter notebook to handle the async nature of rag.insert()
|
||||
# import nest_asyncio
|
||||
# nest_asyncio.apply()
|
||||
#########
|
||||
WORKING_DIR = "./mongodb_test_dir"
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "sk-"
|
||||
os.environ["MONGO_URI"] = "mongodb://0.0.0.0:27017/?directConnection=true"
|
||||
os.environ["MONGO_DATABASE"] = "LightRAG"
|
||||
os.environ["MONGO_KG_COLLECTION"] = "MDB_KG"
|
||||
|
||||
# Embedding Configuration and Functions
|
||||
EMBEDDING_MODEL = os.environ.get("EMBEDDING_MODEL", "text-embedding-3-large")
|
||||
EMBEDDING_MAX_TOKEN_SIZE = int(os.environ.get("EMBEDDING_MAX_TOKEN_SIZE", 8192))
|
||||
|
||||
|
||||
async def embedding_func(texts: list[str]) -> np.ndarray:
|
||||
return await openai_embed(
|
||||
texts,
|
||||
model=EMBEDDING_MODEL,
|
||||
)
|
||||
|
||||
|
||||
async def get_embedding_dimension():
|
||||
test_text = ["This is a test sentence."]
|
||||
embedding = await embedding_func(test_text)
|
||||
return embedding.shape[1]
|
||||
|
||||
|
||||
async def create_embedding_function_instance():
|
||||
# Get embedding dimension
|
||||
embedding_dimension = await get_embedding_dimension()
|
||||
# Create embedding function instance
|
||||
return EmbeddingFunc(
|
||||
embedding_dim=embedding_dimension,
|
||||
max_token_size=EMBEDDING_MAX_TOKEN_SIZE,
|
||||
func=embedding_func,
|
||||
)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
embedding_func_instance = await create_embedding_function_instance()
|
||||
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=gpt_4o_mini_complete,
|
||||
embedding_func=embedding_func_instance,
|
||||
graph_storage="MongoGraphStorage",
|
||||
log_level="DEBUG",
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
# Initialize RAG instance
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform local search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform global search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="global")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform hybrid search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="hybrid")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,229 @@
|
||||
"""
|
||||
Example of directly using modal processors
|
||||
|
||||
This example demonstrates how to use LightRAG's modal processors directly without going through MinerU.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import argparse
|
||||
from lightrag.llm.openai import openai_complete_if_cache, openai_embed
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
from lightrag import LightRAG
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
from raganything.modalprocessors import (
|
||||
ImageModalProcessor,
|
||||
TableModalProcessor,
|
||||
EquationModalProcessor,
|
||||
)
|
||||
|
||||
WORKING_DIR = "./rag_storage"
|
||||
|
||||
|
||||
def get_llm_model_func(api_key: str, base_url: str = None):
|
||||
return (
|
||||
lambda prompt,
|
||||
system_prompt=None,
|
||||
history_messages=[],
|
||||
**kwargs: openai_complete_if_cache(
|
||||
"gpt-4o-mini",
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
**kwargs,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_vision_model_func(api_key: str, base_url: str = None):
|
||||
return (
|
||||
lambda prompt,
|
||||
system_prompt=None,
|
||||
history_messages=[],
|
||||
image_data=None,
|
||||
**kwargs: openai_complete_if_cache(
|
||||
"gpt-4o",
|
||||
"",
|
||||
system_prompt=None,
|
||||
history_messages=[],
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt} if system_prompt else None,
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "text": prompt},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/jpeg;base64,{image_data}"
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
if image_data
|
||||
else {"role": "user", "content": prompt},
|
||||
],
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
**kwargs,
|
||||
)
|
||||
if image_data
|
||||
else openai_complete_if_cache(
|
||||
"gpt-4o-mini",
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
**kwargs,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def process_image_example(lightrag: LightRAG, vision_model_func):
|
||||
"""Example of processing an image"""
|
||||
# Create image processor
|
||||
image_processor = ImageModalProcessor(
|
||||
lightrag=lightrag, modal_caption_func=vision_model_func
|
||||
)
|
||||
|
||||
# Prepare image content
|
||||
image_content = {
|
||||
"img_path": "image.jpg",
|
||||
"img_caption": ["Example image caption"],
|
||||
"img_footnote": ["Example image footnote"],
|
||||
}
|
||||
|
||||
# Process image
|
||||
description, entity_info = await image_processor.process_multimodal_content(
|
||||
modal_content=image_content,
|
||||
content_type="image",
|
||||
file_path="image_example.jpg",
|
||||
entity_name="Example Image",
|
||||
)
|
||||
|
||||
print("Image Processing Results:")
|
||||
print(f"Description: {description}")
|
||||
print(f"Entity Info: {entity_info}")
|
||||
|
||||
|
||||
async def process_table_example(lightrag: LightRAG, llm_model_func):
|
||||
"""Example of processing a table"""
|
||||
# Create table processor
|
||||
table_processor = TableModalProcessor(
|
||||
lightrag=lightrag, modal_caption_func=llm_model_func
|
||||
)
|
||||
|
||||
# Prepare table content
|
||||
table_content = {
|
||||
"table_body": """
|
||||
| Name | Age | Occupation |
|
||||
|------|-----|------------|
|
||||
| John | 25 | Engineer |
|
||||
| Mary | 30 | Designer |
|
||||
""",
|
||||
"table_caption": ["Employee Information Table"],
|
||||
"table_footnote": ["Data updated as of 2024"],
|
||||
}
|
||||
|
||||
# Process table
|
||||
description, entity_info = await table_processor.process_multimodal_content(
|
||||
modal_content=table_content,
|
||||
content_type="table",
|
||||
file_path="table_example.md",
|
||||
entity_name="Employee Table",
|
||||
)
|
||||
|
||||
print("\nTable Processing Results:")
|
||||
print(f"Description: {description}")
|
||||
print(f"Entity Info: {entity_info}")
|
||||
|
||||
|
||||
async def process_equation_example(lightrag: LightRAG, llm_model_func):
|
||||
"""Example of processing a mathematical equation"""
|
||||
# Create equation processor
|
||||
equation_processor = EquationModalProcessor(
|
||||
lightrag=lightrag, modal_caption_func=llm_model_func
|
||||
)
|
||||
|
||||
# Prepare equation content
|
||||
equation_content = {"text": "E = mc^2", "text_format": "LaTeX"}
|
||||
|
||||
# Process equation
|
||||
description, entity_info = await equation_processor.process_multimodal_content(
|
||||
modal_content=equation_content,
|
||||
content_type="equation",
|
||||
file_path="equation_example.txt",
|
||||
entity_name="Mass-Energy Equivalence",
|
||||
)
|
||||
|
||||
print("\nEquation Processing Results:")
|
||||
print(f"Description: {description}")
|
||||
print(f"Entity Info: {entity_info}")
|
||||
|
||||
|
||||
async def initialize_rag(api_key: str, base_url: str = None):
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=3072,
|
||||
max_token_size=8192,
|
||||
func=lambda texts: openai_embed(
|
||||
texts,
|
||||
model="text-embedding-3-large",
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
),
|
||||
),
|
||||
llm_model_func=lambda prompt,
|
||||
system_prompt=None,
|
||||
history_messages=[],
|
||||
**kwargs: openai_complete_if_cache(
|
||||
"gpt-4o-mini",
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
**kwargs,
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to run the example"""
|
||||
parser = argparse.ArgumentParser(description="Modal Processors Example")
|
||||
parser.add_argument("--api-key", required=True, help="OpenAI API key")
|
||||
parser.add_argument("--base-url", help="Optional base URL for API")
|
||||
parser.add_argument(
|
||||
"--working-dir", "-w", default=WORKING_DIR, help="Working directory path"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Run examples
|
||||
asyncio.run(main_async(args.api_key, args.base_url))
|
||||
|
||||
|
||||
async def main_async(api_key: str, base_url: str = None):
|
||||
# Initialize LightRAG
|
||||
lightrag = await initialize_rag(api_key, base_url)
|
||||
|
||||
# Get model functions
|
||||
llm_model_func = get_llm_model_func(api_key, base_url)
|
||||
vision_model_func = get_vision_model_func(api_key, base_url)
|
||||
|
||||
# Run examples
|
||||
await process_image_example(lightrag, vision_model_func)
|
||||
await process_table_example(lightrag, llm_model_func)
|
||||
await process_equation_example(lightrag, llm_model_func)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,286 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Example script demonstrating the integration of MinerU parser with RAGAnything
|
||||
|
||||
This example shows how to:
|
||||
1. Process parsed documents with RAGAnything
|
||||
2. Perform multimodal queries on the processed documents
|
||||
3. Handle different types of content (text, images, tables)
|
||||
"""
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import logging.config
|
||||
from pathlib import Path
|
||||
|
||||
# Add project root directory to Python path
|
||||
import sys
|
||||
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
|
||||
from lightrag.llm.openai import openai_complete_if_cache, openai_embed
|
||||
from lightrag.utils import EmbeddingFunc, logger, set_verbose_debug
|
||||
from raganything import RAGAnything, RAGAnythingConfig
|
||||
|
||||
|
||||
def configure_logging():
|
||||
"""Configure logging for the application"""
|
||||
# Get log directory path from environment variable or use current directory
|
||||
log_dir = os.getenv("LOG_DIR", os.getcwd())
|
||||
log_file_path = os.path.abspath(os.path.join(log_dir, "raganything_example.log"))
|
||||
|
||||
print(f"\nRAGAnything example log file: {log_file_path}\n")
|
||||
os.makedirs(os.path.dirname(log_dir), exist_ok=True)
|
||||
|
||||
# Get log file max size and backup count from environment variables
|
||||
log_max_bytes = int(os.getenv("LOG_MAX_BYTES", 10485760)) # Default 10MB
|
||||
log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", 5)) # Default 5 backups
|
||||
|
||||
logging.config.dictConfig(
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "%(levelname)s: %(message)s",
|
||||
},
|
||||
"detailed": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"formatter": "default",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr",
|
||||
},
|
||||
"file": {
|
||||
"formatter": "detailed",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": log_file_path,
|
||||
"maxBytes": log_max_bytes,
|
||||
"backupCount": log_backup_count,
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"lightrag": {
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
# Set the logger level to INFO
|
||||
logger.setLevel(logging.INFO)
|
||||
# Enable verbose debug if needed
|
||||
set_verbose_debug(os.getenv("VERBOSE", "false").lower() == "true")
|
||||
|
||||
|
||||
async def process_with_rag(
|
||||
file_path: str,
|
||||
output_dir: str,
|
||||
api_key: str,
|
||||
base_url: str = None,
|
||||
working_dir: str = None,
|
||||
):
|
||||
"""
|
||||
Process document with RAGAnything
|
||||
|
||||
Args:
|
||||
file_path: Path to the document
|
||||
output_dir: Output directory for RAG results
|
||||
api_key: OpenAI API key
|
||||
base_url: Optional base URL for API
|
||||
working_dir: Working directory for RAG storage
|
||||
"""
|
||||
try:
|
||||
# Create RAGAnything configuration
|
||||
config = RAGAnythingConfig(
|
||||
working_dir=working_dir or "./rag_storage",
|
||||
mineru_parse_method="auto",
|
||||
enable_image_processing=True,
|
||||
enable_table_processing=True,
|
||||
enable_equation_processing=True,
|
||||
)
|
||||
|
||||
# Define LLM model function
|
||||
def llm_model_func(prompt, system_prompt=None, history_messages=[], **kwargs):
|
||||
return openai_complete_if_cache(
|
||||
"gpt-4o-mini",
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# Define vision model function for image processing
|
||||
def vision_model_func(
|
||||
prompt, system_prompt=None, history_messages=[], image_data=None, **kwargs
|
||||
):
|
||||
if image_data:
|
||||
return openai_complete_if_cache(
|
||||
"gpt-4o",
|
||||
"",
|
||||
system_prompt=None,
|
||||
history_messages=[],
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt}
|
||||
if system_prompt
|
||||
else None,
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "text": prompt},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/jpeg;base64,{image_data}"
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
if image_data
|
||||
else {"role": "user", "content": prompt},
|
||||
],
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
**kwargs,
|
||||
)
|
||||
else:
|
||||
return llm_model_func(prompt, system_prompt, history_messages, **kwargs)
|
||||
|
||||
# Define embedding function
|
||||
embedding_func = EmbeddingFunc(
|
||||
embedding_dim=3072,
|
||||
max_token_size=8192,
|
||||
func=lambda texts: openai_embed(
|
||||
texts,
|
||||
model="text-embedding-3-large",
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
),
|
||||
)
|
||||
|
||||
# Initialize RAGAnything with new dataclass structure
|
||||
rag = RAGAnything(
|
||||
config=config,
|
||||
llm_model_func=llm_model_func,
|
||||
vision_model_func=vision_model_func,
|
||||
embedding_func=embedding_func,
|
||||
)
|
||||
|
||||
# Process document
|
||||
await rag.process_document_complete(
|
||||
file_path=file_path, output_dir=output_dir, parse_method="auto"
|
||||
)
|
||||
|
||||
# Example queries - demonstrating different query approaches
|
||||
logger.info("\nQuerying processed document:")
|
||||
|
||||
# 1. Pure text queries using aquery()
|
||||
text_queries = [
|
||||
"What is the main content of the document?",
|
||||
"What are the key topics discussed?",
|
||||
]
|
||||
|
||||
for query in text_queries:
|
||||
logger.info(f"\n[Text Query]: {query}")
|
||||
result = await rag.aquery(query, mode="hybrid")
|
||||
logger.info(f"Answer: {result}")
|
||||
|
||||
# 2. Multimodal query with specific multimodal content using aquery_with_multimodal()
|
||||
logger.info(
|
||||
"\n[Multimodal Query]: Analyzing performance data in context of document"
|
||||
)
|
||||
multimodal_result = await rag.aquery_with_multimodal(
|
||||
"Compare this performance data with any similar results mentioned in the document",
|
||||
multimodal_content=[
|
||||
{
|
||||
"type": "table",
|
||||
"table_data": """Method,Accuracy,Processing_Time
|
||||
RAGAnything,95.2%,120ms
|
||||
Traditional_RAG,87.3%,180ms
|
||||
Baseline,82.1%,200ms""",
|
||||
"table_caption": "Performance comparison results",
|
||||
}
|
||||
],
|
||||
mode="hybrid",
|
||||
)
|
||||
logger.info(f"Answer: {multimodal_result}")
|
||||
|
||||
# 3. Another multimodal query with equation content
|
||||
logger.info("\n[Multimodal Query]: Mathematical formula analysis")
|
||||
equation_result = await rag.aquery_with_multimodal(
|
||||
"Explain this formula and relate it to any mathematical concepts in the document",
|
||||
multimodal_content=[
|
||||
{
|
||||
"type": "equation",
|
||||
"latex": "F1 = 2 \\cdot \\frac{precision \\cdot recall}{precision + recall}",
|
||||
"equation_caption": "F1-score calculation formula",
|
||||
}
|
||||
],
|
||||
mode="hybrid",
|
||||
)
|
||||
logger.info(f"Answer: {equation_result}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing with RAG: {str(e)}")
|
||||
import traceback
|
||||
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to run the example"""
|
||||
parser = argparse.ArgumentParser(description="MinerU RAG Example")
|
||||
parser.add_argument("file_path", help="Path to the document to process")
|
||||
parser.add_argument(
|
||||
"--working_dir", "-w", default="./rag_storage", help="Working directory path"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", "-o", default="./output", help="Output directory path"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--api-key",
|
||||
default=os.getenv("OPENAI_API_KEY"),
|
||||
help="OpenAI API key (defaults to OPENAI_API_KEY env var)",
|
||||
)
|
||||
parser.add_argument("--base-url", help="Optional base URL for API")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Check if API key is provided
|
||||
if not args.api_key:
|
||||
logger.error("Error: OpenAI API key is required")
|
||||
logger.error("Set OPENAI_API_KEY environment variable or use --api-key option")
|
||||
return
|
||||
|
||||
# Create output directory if specified
|
||||
if args.output:
|
||||
os.makedirs(args.output, exist_ok=True)
|
||||
|
||||
# Process with RAG
|
||||
asyncio.run(
|
||||
process_with_rag(
|
||||
args.file_path, args.output, args.api_key, args.base_url, args.working_dir
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging first
|
||||
configure_logging()
|
||||
|
||||
print("RAGAnything Example")
|
||||
print("=" * 30)
|
||||
print("Processing document with multimodal RAG pipeline")
|
||||
print("=" * 30)
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,232 @@
|
||||
"""
|
||||
LightRAG Rerank Integration Example
|
||||
|
||||
This example demonstrates how to use rerank functionality with LightRAG
|
||||
to improve retrieval quality across different query modes.
|
||||
|
||||
Configuration Required:
|
||||
1. Set your OpenAI LLM API key and base URL with env vars
|
||||
LLM_MODEL
|
||||
LLM_BINDING_HOST
|
||||
LLM_BINDING_API_KEY
|
||||
2. Set your OpenAI embedding API key and base URL with env vars:
|
||||
EMBEDDING_MODEL
|
||||
EMBEDDING_DIM
|
||||
EMBEDDING_BINDING_HOST
|
||||
EMBEDDING_BINDING_API_KEY
|
||||
3. Set your vLLM deployed AI rerank model setting with env vars:
|
||||
RERANK_MODEL
|
||||
RERANK_BINDING_HOST
|
||||
RERANK_BINDING_API_KEY
|
||||
|
||||
Note: Rerank is controlled per query via the 'enable_rerank' parameter (default: True)
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.openai import openai_complete_if_cache, openai_embed
|
||||
from lightrag.utils import EmbeddingFunc, setup_logger
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
from functools import partial
|
||||
from lightrag.rerank import cohere_rerank
|
||||
|
||||
# Set up your working directory
|
||||
WORKING_DIR = "./test_rerank"
|
||||
setup_logger("test_rerank")
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def llm_model_func(
|
||||
prompt, system_prompt=None, history_messages=[], **kwargs
|
||||
) -> str:
|
||||
return await openai_complete_if_cache(
|
||||
os.getenv("LLM_MODEL"),
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key=os.getenv("LLM_BINDING_API_KEY"),
|
||||
base_url=os.getenv("LLM_BINDING_HOST"),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
async def embedding_func(texts: list[str]) -> np.ndarray:
|
||||
return await openai_embed(
|
||||
texts,
|
||||
model=os.getenv("EMBEDDING_MODEL"),
|
||||
api_key=os.getenv("EMBEDDING_BINDING_API_KEY"),
|
||||
base_url=os.getenv("EMBEDDING_BINDING_HOST"),
|
||||
)
|
||||
|
||||
|
||||
rerank_model_func = partial(
|
||||
cohere_rerank,
|
||||
model=os.getenv("RERANK_MODEL"),
|
||||
api_key=os.getenv("RERANK_BINDING_API_KEY"),
|
||||
base_url=os.getenv("RERANK_BINDING_HOST"),
|
||||
)
|
||||
|
||||
|
||||
async def create_rag_with_rerank():
|
||||
"""Create LightRAG instance with rerank configuration"""
|
||||
|
||||
# Get embedding dimension
|
||||
test_embedding = await embedding_func(["test"])
|
||||
embedding_dim = test_embedding.shape[1]
|
||||
print(f"Detected embedding dimension: {embedding_dim}")
|
||||
|
||||
# Method 1: Using custom rerank function
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=embedding_dim,
|
||||
max_token_size=8192,
|
||||
func=embedding_func,
|
||||
),
|
||||
# Rerank Configuration - provide the rerank function
|
||||
rerank_model_func=rerank_model_func,
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
async def test_rerank_with_different_settings():
|
||||
"""
|
||||
Test rerank functionality with different enable_rerank settings
|
||||
"""
|
||||
print("\n\n🚀 Setting up LightRAG with Rerank functionality...")
|
||||
|
||||
rag = await create_rag_with_rerank()
|
||||
|
||||
# Insert sample documents
|
||||
sample_docs = [
|
||||
"Reranking improves retrieval quality by re-ordering documents based on relevance.",
|
||||
"LightRAG is a powerful retrieval-augmented generation system with multiple query modes.",
|
||||
"Vector databases enable efficient similarity search in high-dimensional embedding spaces.",
|
||||
"Natural language processing has evolved with large language models and transformers.",
|
||||
"Machine learning algorithms can learn patterns from data without explicit programming.",
|
||||
]
|
||||
|
||||
print("📄 Inserting sample documents...")
|
||||
await rag.ainsert(sample_docs)
|
||||
|
||||
query = "How does reranking improve retrieval quality?"
|
||||
print(f"\n🔍 Testing query: '{query}'")
|
||||
print("=" * 80)
|
||||
|
||||
# Test with rerank enabled (default)
|
||||
print("\n📊 Testing with enable_rerank=True (default):")
|
||||
result_with_rerank = await rag.aquery(
|
||||
query,
|
||||
param=QueryParam(
|
||||
mode="naive",
|
||||
top_k=10,
|
||||
chunk_top_k=5,
|
||||
enable_rerank=True, # Explicitly enable rerank
|
||||
),
|
||||
)
|
||||
print(f" Result length: {len(result_with_rerank)} characters")
|
||||
print(f" Preview: {result_with_rerank[:100]}...")
|
||||
|
||||
# Test with rerank disabled
|
||||
print("\n📊 Testing with enable_rerank=False:")
|
||||
result_without_rerank = await rag.aquery(
|
||||
query,
|
||||
param=QueryParam(
|
||||
mode="naive",
|
||||
top_k=10,
|
||||
chunk_top_k=5,
|
||||
enable_rerank=False, # Disable rerank
|
||||
),
|
||||
)
|
||||
print(f" Result length: {len(result_without_rerank)} characters")
|
||||
print(f" Preview: {result_without_rerank[:100]}...")
|
||||
|
||||
# Test with default settings (enable_rerank defaults to True)
|
||||
print("\n📊 Testing with default settings (enable_rerank defaults to True):")
|
||||
result_default = await rag.aquery(
|
||||
query, param=QueryParam(mode="naive", top_k=10, chunk_top_k=5)
|
||||
)
|
||||
print(f" Result length: {len(result_default)} characters")
|
||||
print(f" Preview: {result_default[:100]}...")
|
||||
|
||||
|
||||
async def test_direct_rerank():
|
||||
"""Test rerank function directly"""
|
||||
print("\n🔧 Direct Rerank API Test")
|
||||
print("=" * 40)
|
||||
|
||||
documents = [
|
||||
"Vector search finds semantically similar documents",
|
||||
"LightRAG supports advanced reranking capabilities",
|
||||
"Reranking significantly improves retrieval quality",
|
||||
"Natural language processing with modern transformers",
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
]
|
||||
|
||||
query = "rerank improve quality"
|
||||
print(f"Query: '{query}'")
|
||||
print(f"Documents: {len(documents)}")
|
||||
|
||||
try:
|
||||
reranked_results = await rerank_model_func(
|
||||
query=query,
|
||||
documents=documents,
|
||||
top_n=4,
|
||||
)
|
||||
|
||||
print("\n✅ Rerank Results:")
|
||||
i = 0
|
||||
for result in reranked_results:
|
||||
index = result["index"]
|
||||
score = result["relevance_score"]
|
||||
content = documents[index]
|
||||
print(f" {index}. Score: {score:.4f} | {content}...")
|
||||
i += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Rerank failed: {e}")
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main example function"""
|
||||
print("🎯 LightRAG Rerank Integration Example")
|
||||
print("=" * 60)
|
||||
|
||||
try:
|
||||
# Test direct rerank
|
||||
await test_direct_rerank()
|
||||
|
||||
# Test rerank with different enable_rerank settings
|
||||
await test_rerank_with_different_settings()
|
||||
|
||||
print("\n✅ Example completed successfully!")
|
||||
print("\n💡 Key Points:")
|
||||
print(" ✓ Rerank is now controlled per query via 'enable_rerank' parameter")
|
||||
print(" ✓ Default value for enable_rerank is True")
|
||||
print(" ✓ Rerank function is configured at LightRAG initialization")
|
||||
print(" ✓ Per-query enable_rerank setting overrides default behavior")
|
||||
print(
|
||||
" ✓ If enable_rerank=True but no rerank model is configured, a warning is issued"
|
||||
)
|
||||
print(" ✓ Monitor API usage and costs when using rerank services")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ Example failed: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,114 @@
|
||||
"""
|
||||
Sometimes you need to switch a storage solution, but you want to save LLM token and time.
|
||||
This handy script helps you to copy the LLM caches from one storage solution to another.
|
||||
(Not all the storage impl are supported)
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from lightrag.kg.postgres_impl import PostgreSQLDB, PGKVStorage
|
||||
from lightrag.kg.json_kv_impl import JsonKVStorage
|
||||
from lightrag.namespace import NameSpace
|
||||
|
||||
load_dotenv()
|
||||
ROOT_DIR = os.environ.get("ROOT_DIR")
|
||||
WORKING_DIR = f"{ROOT_DIR}/dickens"
|
||||
|
||||
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.INFO)
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
# AGE
|
||||
os.environ["AGE_GRAPH_NAME"] = "chinese"
|
||||
|
||||
postgres_db = PostgreSQLDB(
|
||||
config={
|
||||
"host": "localhost",
|
||||
"port": 15432,
|
||||
"user": "rag",
|
||||
"password": "rag",
|
||||
"database": "r2",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def copy_from_postgres_to_json():
|
||||
await postgres_db.initdb()
|
||||
|
||||
from_llm_response_cache = PGKVStorage(
|
||||
namespace=NameSpace.KV_STORE_LLM_RESPONSE_CACHE,
|
||||
global_config={"embedding_batch_num": 6},
|
||||
embedding_func=None,
|
||||
db=postgres_db,
|
||||
)
|
||||
|
||||
to_llm_response_cache = JsonKVStorage(
|
||||
namespace=NameSpace.KV_STORE_LLM_RESPONSE_CACHE,
|
||||
global_config={"working_dir": WORKING_DIR},
|
||||
embedding_func=None,
|
||||
)
|
||||
|
||||
# Get all cache data using the new flattened structure
|
||||
all_data = await from_llm_response_cache.get_all()
|
||||
|
||||
# Convert flattened data to hierarchical structure for JsonKVStorage
|
||||
kv = {}
|
||||
for flattened_key, cache_entry in all_data.items():
|
||||
# Parse flattened key: {mode}:{cache_type}:{hash}
|
||||
parts = flattened_key.split(":", 2)
|
||||
if len(parts) == 3:
|
||||
mode, cache_type, hash_value = parts
|
||||
if mode not in kv:
|
||||
kv[mode] = {}
|
||||
kv[mode][hash_value] = cache_entry
|
||||
print(f"Copying {flattened_key} -> {mode}[{hash_value}]")
|
||||
else:
|
||||
print(f"Skipping invalid key format: {flattened_key}")
|
||||
|
||||
await to_llm_response_cache.upsert(kv)
|
||||
await to_llm_response_cache.index_done_callback()
|
||||
print("Mission accomplished!")
|
||||
|
||||
|
||||
async def copy_from_json_to_postgres():
|
||||
await postgres_db.initdb()
|
||||
|
||||
from_llm_response_cache = JsonKVStorage(
|
||||
namespace=NameSpace.KV_STORE_LLM_RESPONSE_CACHE,
|
||||
global_config={"working_dir": WORKING_DIR},
|
||||
embedding_func=None,
|
||||
)
|
||||
|
||||
to_llm_response_cache = PGKVStorage(
|
||||
namespace=NameSpace.KV_STORE_LLM_RESPONSE_CACHE,
|
||||
global_config={"embedding_batch_num": 6},
|
||||
embedding_func=None,
|
||||
db=postgres_db,
|
||||
)
|
||||
|
||||
# Get all cache data from JsonKVStorage (hierarchical structure)
|
||||
all_data = await from_llm_response_cache.get_all()
|
||||
|
||||
# Convert hierarchical data to flattened structure for PGKVStorage
|
||||
flattened_data = {}
|
||||
for mode, mode_data in all_data.items():
|
||||
print(f"Processing mode: {mode}")
|
||||
for hash_value, cache_entry in mode_data.items():
|
||||
# Determine cache_type from cache entry or use default
|
||||
cache_type = cache_entry.get("cache_type", "extract")
|
||||
# Create flattened key: {mode}:{cache_type}:{hash}
|
||||
flattened_key = f"{mode}:{cache_type}:{hash_value}"
|
||||
flattened_data[flattened_key] = cache_entry
|
||||
print(f"\tConverting {mode}[{hash_value}] -> {flattened_key}")
|
||||
|
||||
# Upsert the flattened data
|
||||
await to_llm_response_cache.upsert(flattened_data)
|
||||
print("Mission accomplished!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(copy_from_json_to_postgres())
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
LightRAG meets Amazon Bedrock ⛰️
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.bedrock import bedrock_complete, bedrock_embed
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
import asyncio
|
||||
import nest_asyncio
|
||||
|
||||
nest_asyncio.apply()
|
||||
|
||||
logging.getLogger("aiobotocore").setLevel(logging.WARNING)
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=bedrock_complete,
|
||||
llm_model_name="Anthropic Claude 3 Haiku // Amazon Bedrock",
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=1024, max_token_size=8192, func=bedrock_embed
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
for mode in ["naive", "local", "global", "hybrid"]:
|
||||
print("\n+-" + "-" * len(mode) + "-+")
|
||||
print(f"| {mode.capitalize()} |")
|
||||
print("+-" + "-" * len(mode) + "-+\n")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode=mode)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,357 @@
|
||||
import asyncio
|
||||
import os
|
||||
import inspect
|
||||
import logging
|
||||
import logging.config
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.utils import EmbeddingFunc, logger, set_verbose_debug
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
import requests
|
||||
import numpy as np
|
||||
from dotenv import load_dotenv
|
||||
|
||||
"""This code is a modified version of lightrag_openai_demo.py"""
|
||||
|
||||
# ideally, as always, env!
|
||||
load_dotenv(dotenv_path=".env", override=False)
|
||||
|
||||
|
||||
""" ----========= IMPORTANT CHANGE THIS! =========---- """
|
||||
cloudflare_api_key = "YOUR_API_KEY"
|
||||
account_id = "YOUR_ACCOUNT ID" # This is unique to your Cloudflare account
|
||||
|
||||
# Authomatically changes
|
||||
api_base_url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/"
|
||||
|
||||
|
||||
# choose an embedding model
|
||||
EMBEDDING_MODEL = "@cf/baai/bge-m3"
|
||||
# choose a generative model
|
||||
LLM_MODEL = "@cf/meta/llama-3.2-3b-instruct"
|
||||
|
||||
WORKING_DIR = "../dickens" # you can change output as desired
|
||||
|
||||
|
||||
# Cloudflare init
|
||||
class CloudflareWorker:
|
||||
def __init__(
|
||||
self,
|
||||
cloudflare_api_key: str,
|
||||
api_base_url: str,
|
||||
llm_model_name: str,
|
||||
embedding_model_name: str,
|
||||
max_tokens: int = 4080,
|
||||
max_response_tokens: int = 4080,
|
||||
):
|
||||
self.cloudflare_api_key = cloudflare_api_key
|
||||
self.api_base_url = api_base_url
|
||||
self.llm_model_name = llm_model_name
|
||||
self.embedding_model_name = embedding_model_name
|
||||
self.max_tokens = max_tokens
|
||||
self.max_response_tokens = max_response_tokens
|
||||
|
||||
async def _send_request(self, model_name: str, input_: dict, debug_log: str):
|
||||
headers = {"Authorization": f"Bearer {self.cloudflare_api_key}"}
|
||||
|
||||
print(f"""
|
||||
data sent to Cloudflare
|
||||
~~~~~~~~~~~
|
||||
{debug_log}
|
||||
""")
|
||||
|
||||
try:
|
||||
response_raw = requests.post(
|
||||
f"{self.api_base_url}{model_name}", headers=headers, json=input_
|
||||
).json()
|
||||
print(f"""
|
||||
Cloudflare worker responded with:
|
||||
~~~~~~~~~~~
|
||||
{str(response_raw)}
|
||||
""")
|
||||
result = response_raw.get("result", {})
|
||||
|
||||
if "data" in result: # Embedding case
|
||||
return np.array(result["data"])
|
||||
|
||||
if "response" in result: # LLM response
|
||||
return result["response"]
|
||||
|
||||
raise ValueError("Unexpected Cloudflare response format")
|
||||
|
||||
except Exception as e:
|
||||
print(f"""
|
||||
Cloudflare API returned:
|
||||
~~~~~~~~~
|
||||
Error: {e}
|
||||
""")
|
||||
input("Press Enter to continue...")
|
||||
return None
|
||||
|
||||
async def query(self, prompt, system_prompt: str = "", **kwargs) -> str:
|
||||
# since no caching is used and we don't want to mess with everything lightrag, pop the kwarg it is
|
||||
kwargs.pop("hashing_kv", None)
|
||||
|
||||
message = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
|
||||
input_ = {
|
||||
"messages": message,
|
||||
"max_tokens": self.max_tokens,
|
||||
"response_token_limit": self.max_response_tokens,
|
||||
}
|
||||
|
||||
return await self._send_request(
|
||||
self.llm_model_name,
|
||||
input_,
|
||||
debug_log=f"\n- model used {self.llm_model_name}\n- system prompt: {system_prompt}\n- query: {prompt}",
|
||||
)
|
||||
|
||||
async def embedding_chunk(self, texts: list[str]) -> np.ndarray:
|
||||
print(f"""
|
||||
TEXT inputted
|
||||
~~~~~
|
||||
{texts}
|
||||
""")
|
||||
|
||||
input_ = {
|
||||
"text": texts,
|
||||
"max_tokens": self.max_tokens,
|
||||
"response_token_limit": self.max_response_tokens,
|
||||
}
|
||||
|
||||
return await self._send_request(
|
||||
self.embedding_model_name,
|
||||
input_,
|
||||
debug_log=f"\n-llm model name {self.embedding_model_name}\n- texts: {texts}",
|
||||
)
|
||||
|
||||
|
||||
def configure_logging():
|
||||
"""Configure logging for the application"""
|
||||
|
||||
# Reset any existing handlers to ensure clean configuration
|
||||
for logger_name in ["uvicorn", "uvicorn.access", "uvicorn.error", "lightrag"]:
|
||||
logger_instance = logging.getLogger(logger_name)
|
||||
logger_instance.handlers = []
|
||||
logger_instance.filters = []
|
||||
|
||||
# Get log directory path from environment variable or use current directory
|
||||
log_dir = os.getenv("LOG_DIR", os.getcwd())
|
||||
log_file_path = os.path.abspath(
|
||||
os.path.join(log_dir, "lightrag_cloudflare_worker_demo.log")
|
||||
)
|
||||
|
||||
print(f"\nLightRAG compatible demo log file: {log_file_path}\n")
|
||||
os.makedirs(os.path.dirname(log_file_path), exist_ok=True)
|
||||
|
||||
# Get log file max size and backup count from environment variables
|
||||
log_max_bytes = int(os.getenv("LOG_MAX_BYTES", 10485760)) # Default 10MB
|
||||
log_backup_count = int(os.getenv("LOG_BACKUP_COUNT", 5)) # Default 5 backups
|
||||
|
||||
logging.config.dictConfig(
|
||||
{
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "%(levelname)s: %(message)s",
|
||||
},
|
||||
"detailed": {
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"formatter": "default",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr",
|
||||
},
|
||||
"file": {
|
||||
"formatter": "detailed",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": log_file_path,
|
||||
"maxBytes": log_max_bytes,
|
||||
"backupCount": log_backup_count,
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"lightrag": {
|
||||
"handlers": ["console", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
# Set the logger level to INFO
|
||||
logger.setLevel(logging.INFO)
|
||||
# Enable verbose debug if needed
|
||||
set_verbose_debug(os.getenv("VERBOSE_DEBUG", "false").lower() == "true")
|
||||
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
cloudflare_worker = CloudflareWorker(
|
||||
cloudflare_api_key=cloudflare_api_key,
|
||||
api_base_url=api_base_url,
|
||||
embedding_model_name=EMBEDDING_MODEL,
|
||||
llm_model_name=LLM_MODEL,
|
||||
)
|
||||
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
max_parallel_insert=2,
|
||||
llm_model_func=cloudflare_worker.query,
|
||||
llm_model_name=os.getenv("LLM_MODEL", LLM_MODEL),
|
||||
summary_max_tokens=4080,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=int(os.getenv("EMBEDDING_DIM", "1024")),
|
||||
max_token_size=int(os.getenv("MAX_EMBED_TOKENS", "2048")),
|
||||
func=lambda texts: cloudflare_worker.embedding_chunk(
|
||||
texts,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
async def print_stream(stream):
|
||||
async for chunk in stream:
|
||||
print(chunk, end="", flush=True)
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
# Clear old data files
|
||||
files_to_delete = [
|
||||
"graph_chunk_entity_relation.graphml",
|
||||
"kv_store_doc_status.json",
|
||||
"kv_store_full_docs.json",
|
||||
"kv_store_text_chunks.json",
|
||||
"vdb_chunks.json",
|
||||
"vdb_entities.json",
|
||||
"vdb_relationships.json",
|
||||
]
|
||||
|
||||
for file in files_to_delete:
|
||||
file_path = os.path.join(WORKING_DIR, file)
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
print(f"Deleting old file:: {file_path}")
|
||||
|
||||
# Initialize RAG instance
|
||||
rag = await initialize_rag()
|
||||
|
||||
# Test embedding function
|
||||
test_text = ["This is a test string for embedding."]
|
||||
embedding = await rag.embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
print("\n=======================")
|
||||
print("Test embedding function")
|
||||
print("========================")
|
||||
print(f"Test dict: {test_text}")
|
||||
print(f"Detected embedding dimension: {embedding_dim}\n\n")
|
||||
|
||||
# Locate the location of what is needed to be added to the knowledge
|
||||
# Can add several simultaneously by modifying code
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
await rag.ainsert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print("\n=====================")
|
||||
print("Query mode: naive")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="naive", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform local search
|
||||
print("\n=====================")
|
||||
print("Query mode: local")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="local", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform global search
|
||||
print("\n=====================")
|
||||
print("Query mode: global")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="global", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
# Perform hybrid search
|
||||
print("\n=====================")
|
||||
print("Query mode: hybrid")
|
||||
print("=====================")
|
||||
resp = await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="hybrid", stream=True),
|
||||
)
|
||||
if inspect.isasyncgen(resp):
|
||||
await print_stream(resp)
|
||||
else:
|
||||
print(resp)
|
||||
|
||||
""" FOR TESTING (if you want to test straight away, after building. Uncomment this part"""
|
||||
|
||||
"""
|
||||
print("\n" + "=" * 60)
|
||||
print("AI ASSISTANT READY!")
|
||||
print("Ask questions about (your uploaded) regulations")
|
||||
print("Type 'quit' to exit")
|
||||
print("=" * 60)
|
||||
|
||||
while True:
|
||||
question = input("\n🔥 Your question: ")
|
||||
|
||||
if question.lower() in ['quit', 'exit', 'bye']:
|
||||
break
|
||||
|
||||
print("\nThinking...")
|
||||
response = await rag.aquery(question, param=QueryParam(mode="hybrid"))
|
||||
print(f"\nAnswer: {response}")
|
||||
|
||||
"""
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
finally:
|
||||
if rag:
|
||||
await rag.llm_response_cache.index_done_callback()
|
||||
await rag.finalize_storages()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Configure logging before running the main function
|
||||
configure_logging()
|
||||
asyncio.run(main())
|
||||
print("\nDone!")
|
||||
@@ -0,0 +1,82 @@
|
||||
import os
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.hf import hf_model_complete, hf_embed
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
import asyncio
|
||||
import nest_asyncio
|
||||
|
||||
nest_asyncio.apply()
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=hf_model_complete,
|
||||
llm_model_name="meta-llama/Llama-3.1-8B-Instruct",
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=384,
|
||||
max_token_size=5000,
|
||||
func=lambda texts: hf_embed(
|
||||
texts,
|
||||
tokenizer=AutoTokenizer.from_pretrained(
|
||||
"sentence-transformers/all-MiniLM-L6-v2"
|
||||
),
|
||||
embed_model=AutoModel.from_pretrained(
|
||||
"sentence-transformers/all-MiniLM-L6-v2"
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform local search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform global search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="global")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform hybrid search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="hybrid")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,143 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
import nest_asyncio
|
||||
from llama_index.embeddings.openai import OpenAIEmbedding
|
||||
from llama_index.llms.openai import OpenAI
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
from lightrag.llm.llama_index_impl import (
|
||||
llama_index_complete_if_cache,
|
||||
llama_index_embed,
|
||||
)
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
|
||||
nest_asyncio.apply()
|
||||
|
||||
# Configure working directory
|
||||
WORKING_DIR = "./index_default"
|
||||
print(f"WORKING_DIR: {WORKING_DIR}")
|
||||
|
||||
# Model configuration
|
||||
LLM_MODEL = os.environ.get("LLM_MODEL", "gpt-4")
|
||||
print(f"LLM_MODEL: {LLM_MODEL}")
|
||||
EMBEDDING_MODEL = os.environ.get("EMBEDDING_MODEL", "text-embedding-3-large")
|
||||
print(f"EMBEDDING_MODEL: {EMBEDDING_MODEL}")
|
||||
EMBEDDING_MAX_TOKEN_SIZE = int(os.environ.get("EMBEDDING_MAX_TOKEN_SIZE", 8192))
|
||||
print(f"EMBEDDING_MAX_TOKEN_SIZE: {EMBEDDING_MAX_TOKEN_SIZE}")
|
||||
|
||||
# OpenAI configuration
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "your-api-key-here")
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
print(f"Creating working directory: {WORKING_DIR}")
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
# Initialize LLM function
|
||||
async def llm_model_func(prompt, system_prompt=None, history_messages=[], **kwargs):
|
||||
try:
|
||||
# Initialize OpenAI if not in kwargs
|
||||
if "llm_instance" not in kwargs:
|
||||
llm_instance = OpenAI(
|
||||
model=LLM_MODEL,
|
||||
api_key=OPENAI_API_KEY,
|
||||
temperature=0.7,
|
||||
)
|
||||
kwargs["llm_instance"] = llm_instance
|
||||
|
||||
response = await llama_index_complete_if_cache(
|
||||
kwargs["llm_instance"],
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
**kwargs,
|
||||
)
|
||||
return response
|
||||
except Exception as e:
|
||||
print(f"LLM request failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
# Initialize embedding function
|
||||
async def embedding_func(texts):
|
||||
try:
|
||||
embed_model = OpenAIEmbedding(
|
||||
model=EMBEDDING_MODEL,
|
||||
api_key=OPENAI_API_KEY,
|
||||
)
|
||||
return await llama_index_embed(texts, embed_model=embed_model)
|
||||
except Exception as e:
|
||||
print(f"Embedding failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
# Get embedding dimension
|
||||
async def get_embedding_dim():
|
||||
test_text = ["This is a test sentence."]
|
||||
embedding = await embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
print(f"embedding_dim={embedding_dim}")
|
||||
return embedding_dim
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
embedding_dimension = await get_embedding_dim()
|
||||
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=embedding_dimension,
|
||||
max_token_size=EMBEDDING_MAX_TOKEN_SIZE,
|
||||
func=embedding_func,
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
# Initialize RAG instance
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
# Insert example text
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
# Test different query modes
|
||||
print("\nNaive Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nLocal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nGlobal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="global")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nHybrid Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="hybrid")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,145 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
import nest_asyncio
|
||||
from llama_index.embeddings.litellm import LiteLLMEmbedding
|
||||
from llama_index.llms.litellm import LiteLLM
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
from lightrag.llm.llama_index_impl import (
|
||||
llama_index_complete_if_cache,
|
||||
llama_index_embed,
|
||||
)
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
|
||||
nest_asyncio.apply()
|
||||
|
||||
# Configure working directory
|
||||
WORKING_DIR = "./index_default"
|
||||
print(f"WORKING_DIR: {WORKING_DIR}")
|
||||
|
||||
# Model configuration
|
||||
LLM_MODEL = os.environ.get("LLM_MODEL", "gpt-4")
|
||||
print(f"LLM_MODEL: {LLM_MODEL}")
|
||||
EMBEDDING_MODEL = os.environ.get("EMBEDDING_MODEL", "text-embedding-3-large")
|
||||
print(f"EMBEDDING_MODEL: {EMBEDDING_MODEL}")
|
||||
EMBEDDING_MAX_TOKEN_SIZE = int(os.environ.get("EMBEDDING_MAX_TOKEN_SIZE", 8192))
|
||||
print(f"EMBEDDING_MAX_TOKEN_SIZE: {EMBEDDING_MAX_TOKEN_SIZE}")
|
||||
|
||||
# LiteLLM configuration
|
||||
LITELLM_URL = os.environ.get("LITELLM_URL", "http://localhost:4000")
|
||||
print(f"LITELLM_URL: {LITELLM_URL}")
|
||||
LITELLM_KEY = os.environ.get("LITELLM_KEY", "sk-1234")
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
# Initialize LLM function
|
||||
async def llm_model_func(prompt, system_prompt=None, history_messages=[], **kwargs):
|
||||
try:
|
||||
# Initialize LiteLLM if not in kwargs
|
||||
if "llm_instance" not in kwargs:
|
||||
llm_instance = LiteLLM(
|
||||
model=f"openai/{LLM_MODEL}", # Format: "provider/model_name"
|
||||
api_base=LITELLM_URL,
|
||||
api_key=LITELLM_KEY,
|
||||
temperature=0.7,
|
||||
)
|
||||
kwargs["llm_instance"] = llm_instance
|
||||
|
||||
response = await llama_index_complete_if_cache(
|
||||
kwargs["llm_instance"],
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
)
|
||||
return response
|
||||
except Exception as e:
|
||||
print(f"LLM request failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
# Initialize embedding function
|
||||
async def embedding_func(texts):
|
||||
try:
|
||||
embed_model = LiteLLMEmbedding(
|
||||
model_name=f"openai/{EMBEDDING_MODEL}",
|
||||
api_base=LITELLM_URL,
|
||||
api_key=LITELLM_KEY,
|
||||
)
|
||||
return await llama_index_embed(texts, embed_model=embed_model)
|
||||
except Exception as e:
|
||||
print(f"Embedding failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
# Get embedding dimension
|
||||
async def get_embedding_dim():
|
||||
test_text = ["This is a test sentence."]
|
||||
embedding = await embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
print(f"embedding_dim={embedding_dim}")
|
||||
return embedding_dim
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
embedding_dimension = await get_embedding_dim()
|
||||
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=embedding_dimension,
|
||||
max_token_size=EMBEDDING_MAX_TOKEN_SIZE,
|
||||
func=embedding_func,
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
# Initialize RAG instance
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
# Insert example text
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
# Test different query modes
|
||||
print("\nNaive Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nLocal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nGlobal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="global")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nHybrid Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="hybrid")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,156 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
import nest_asyncio
|
||||
from llama_index.embeddings.litellm import LiteLLMEmbedding
|
||||
from llama_index.llms.litellm import LiteLLM
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
from lightrag.llm.llama_index_impl import (
|
||||
llama_index_complete_if_cache,
|
||||
llama_index_embed,
|
||||
)
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
|
||||
nest_asyncio.apply()
|
||||
|
||||
# Configure working directory
|
||||
WORKING_DIR = "./index_default"
|
||||
print(f"WORKING_DIR: {WORKING_DIR}")
|
||||
|
||||
# Model configuration
|
||||
LLM_MODEL = os.environ.get("LLM_MODEL", "gemma-3-4b")
|
||||
print(f"LLM_MODEL: {LLM_MODEL}")
|
||||
EMBEDDING_MODEL = os.environ.get("EMBEDDING_MODEL", "arctic-embed")
|
||||
print(f"EMBEDDING_MODEL: {EMBEDDING_MODEL}")
|
||||
EMBEDDING_MAX_TOKEN_SIZE = int(os.environ.get("EMBEDDING_MAX_TOKEN_SIZE", 8192))
|
||||
print(f"EMBEDDING_MAX_TOKEN_SIZE: {EMBEDDING_MAX_TOKEN_SIZE}")
|
||||
|
||||
# LiteLLM configuration
|
||||
LITELLM_URL = os.environ.get("LITELLM_URL", "http://localhost:4000")
|
||||
print(f"LITELLM_URL: {LITELLM_URL}")
|
||||
LITELLM_KEY = os.environ.get("LITELLM_KEY", "sk-4JdvGFKqSA3S0k_5p0xufw")
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
# Initialize LLM function
|
||||
async def llm_model_func(prompt, system_prompt=None, history_messages=[], **kwargs):
|
||||
try:
|
||||
# Initialize LiteLLM if not in kwargs
|
||||
if "llm_instance" not in kwargs:
|
||||
llm_instance = LiteLLM(
|
||||
model=f"openai/{LLM_MODEL}", # Format: "provider/model_name"
|
||||
api_base=LITELLM_URL,
|
||||
api_key=LITELLM_KEY,
|
||||
temperature=0.7,
|
||||
)
|
||||
kwargs["llm_instance"] = llm_instance
|
||||
|
||||
chat_kwargs = {}
|
||||
chat_kwargs["litellm_params"] = {
|
||||
"metadata": {
|
||||
"opik": {
|
||||
"project_name": "lightrag_llamaindex_litellm_opik_demo",
|
||||
"tags": ["lightrag", "litellm"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = await llama_index_complete_if_cache(
|
||||
kwargs["llm_instance"],
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
chat_kwargs=chat_kwargs,
|
||||
)
|
||||
return response
|
||||
except Exception as e:
|
||||
print(f"LLM request failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
# Initialize embedding function
|
||||
async def embedding_func(texts):
|
||||
try:
|
||||
embed_model = LiteLLMEmbedding(
|
||||
model_name=f"openai/{EMBEDDING_MODEL}",
|
||||
api_base=LITELLM_URL,
|
||||
api_key=LITELLM_KEY,
|
||||
)
|
||||
return await llama_index_embed(texts, embed_model=embed_model)
|
||||
except Exception as e:
|
||||
print(f"Embedding failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
# Get embedding dimension
|
||||
async def get_embedding_dim():
|
||||
test_text = ["This is a test sentence."]
|
||||
embedding = await embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
print(f"embedding_dim={embedding_dim}")
|
||||
return embedding_dim
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
embedding_dimension = await get_embedding_dim()
|
||||
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=embedding_dimension,
|
||||
max_token_size=EMBEDDING_MAX_TOKEN_SIZE,
|
||||
func=embedding_func,
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
# Initialize RAG instance
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
# Insert example text
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
# Test different query modes
|
||||
print("\nNaive Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nLocal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nGlobal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="global")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nHybrid Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="hybrid")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,110 @@
|
||||
import os
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.lmdeploy import lmdeploy_model_if_cache
|
||||
from lightrag.llm.hf import hf_embed
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
from transformers import AutoModel, AutoTokenizer
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
import asyncio
|
||||
import nest_asyncio
|
||||
|
||||
nest_asyncio.apply()
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
|
||||
async def lmdeploy_model_complete(
|
||||
prompt=None,
|
||||
system_prompt=None,
|
||||
history_messages=[],
|
||||
keyword_extraction=False,
|
||||
**kwargs,
|
||||
) -> str:
|
||||
model_name = kwargs["hashing_kv"].global_config["llm_model_name"]
|
||||
return await lmdeploy_model_if_cache(
|
||||
model_name,
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
## please specify chat_template if your local path does not follow original HF file name,
|
||||
## or model_name is a pytorch model on huggingface.co,
|
||||
## you can refer to https://github.com/InternLM/lmdeploy/blob/main/lmdeploy/model.py
|
||||
## for a list of chat_template available in lmdeploy.
|
||||
chat_template="llama3",
|
||||
# model_format ='awq', # if you are using awq quantization model.
|
||||
# quant_policy=8, # if you want to use online kv cache, 4=kv int4, 8=kv int8.
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=lmdeploy_model_complete,
|
||||
llm_model_name="meta-llama/Llama-3.1-8B-Instruct", # please use definite path for local model
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=384,
|
||||
max_token_size=5000,
|
||||
func=lambda texts: hf_embed(
|
||||
texts,
|
||||
tokenizer=AutoTokenizer.from_pretrained(
|
||||
"sentence-transformers/all-MiniLM-L6-v2"
|
||||
),
|
||||
embed_model=AutoModel.from_pretrained(
|
||||
"sentence-transformers/all-MiniLM-L6-v2"
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
# Initialize RAG instance
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
# Insert example text
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
# Test different query modes
|
||||
print("\nNaive Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nLocal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nGlobal Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="global")
|
||||
)
|
||||
)
|
||||
|
||||
print("\nHybrid Search:")
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="hybrid")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,171 @@
|
||||
import os
|
||||
import asyncio
|
||||
import nest_asyncio
|
||||
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm import (
|
||||
openai_complete_if_cache,
|
||||
nvidia_openai_embed,
|
||||
)
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
import numpy as np
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
# for custom llm_model_func
|
||||
from lightrag.utils import locate_json_string_body_from_string
|
||||
|
||||
nest_asyncio.apply()
|
||||
|
||||
WORKING_DIR = "./dickens"
|
||||
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
|
||||
# some method to use your API key (choose one)
|
||||
# NVIDIA_OPENAI_API_KEY = os.getenv("NVIDIA_OPENAI_API_KEY")
|
||||
NVIDIA_OPENAI_API_KEY = "nvapi-xxxx" # your api key
|
||||
|
||||
# using pre-defined function for nvidia LLM API. OpenAI compatible
|
||||
# llm_model_func = nvidia_openai_complete
|
||||
|
||||
|
||||
# If you trying to make custom llm_model_func to use llm model on NVIDIA API like other example:
|
||||
async def llm_model_func(
|
||||
prompt, system_prompt=None, history_messages=[], keyword_extraction=False, **kwargs
|
||||
) -> str:
|
||||
result = await openai_complete_if_cache(
|
||||
"nvidia/llama-3.1-nemotron-70b-instruct",
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key=NVIDIA_OPENAI_API_KEY,
|
||||
base_url="https://integrate.api.nvidia.com/v1",
|
||||
**kwargs,
|
||||
)
|
||||
if keyword_extraction:
|
||||
return locate_json_string_body_from_string(result)
|
||||
return result
|
||||
|
||||
|
||||
# custom embedding
|
||||
nvidia_embed_model = "nvidia/nv-embedqa-e5-v5"
|
||||
|
||||
|
||||
async def indexing_embedding_func(texts: list[str]) -> np.ndarray:
|
||||
return await nvidia_openai_embed(
|
||||
texts,
|
||||
model=nvidia_embed_model, # maximum 512 token
|
||||
# model="nvidia/llama-3.2-nv-embedqa-1b-v1",
|
||||
api_key=NVIDIA_OPENAI_API_KEY,
|
||||
base_url="https://integrate.api.nvidia.com/v1",
|
||||
input_type="passage",
|
||||
trunc="END", # handling on server side if input token is longer than maximum token
|
||||
encode="float",
|
||||
)
|
||||
|
||||
|
||||
async def query_embedding_func(texts: list[str]) -> np.ndarray:
|
||||
return await nvidia_openai_embed(
|
||||
texts,
|
||||
model=nvidia_embed_model, # maximum 512 token
|
||||
# model="nvidia/llama-3.2-nv-embedqa-1b-v1",
|
||||
api_key=NVIDIA_OPENAI_API_KEY,
|
||||
base_url="https://integrate.api.nvidia.com/v1",
|
||||
input_type="query",
|
||||
trunc="END", # handling on server side if input token is longer than maximum token
|
||||
encode="float",
|
||||
)
|
||||
|
||||
|
||||
# dimension are same
|
||||
async def get_embedding_dim():
|
||||
test_text = ["This is a test sentence."]
|
||||
embedding = await indexing_embedding_func(test_text)
|
||||
embedding_dim = embedding.shape[1]
|
||||
return embedding_dim
|
||||
|
||||
|
||||
# function test
|
||||
async def test_funcs():
|
||||
result = await llm_model_func("How are you?")
|
||||
print("llm_model_func: ", result)
|
||||
|
||||
result = await indexing_embedding_func(["How are you?"])
|
||||
print("embedding_func: ", result)
|
||||
|
||||
|
||||
# asyncio.run(test_funcs())
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
embedding_dimension = await get_embedding_dim()
|
||||
print(f"Detected embedding dimension: {embedding_dimension}")
|
||||
|
||||
# lightRAG class during indexing
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
# llm_model_name="meta/llama3-70b-instruct", #un comment if
|
||||
embedding_func=EmbeddingFunc(
|
||||
embedding_dim=embedding_dimension,
|
||||
max_token_size=512, # maximum token size, somehow it's still exceed maximum number of token
|
||||
# so truncate (trunc) parameter on embedding_func will handle it and try to examine the tokenizer used in LightRAG
|
||||
# so you can adjust to be able to fit the NVIDIA model (future work)
|
||||
func=indexing_embedding_func,
|
||||
),
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
# Initialize RAG instance
|
||||
rag = await initialize_rag()
|
||||
|
||||
# reading file
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
await rag.ainsert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print("==============Naive===============")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform local search
|
||||
print("==============local===============")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform global search
|
||||
print("==============global===============")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="global"),
|
||||
)
|
||||
)
|
||||
|
||||
# Perform hybrid search
|
||||
print("==============hybrid===============")
|
||||
print(
|
||||
await rag.aquery(
|
||||
"What are the top themes in this story?",
|
||||
param=QueryParam(mode="hybrid"),
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,112 @@
|
||||
import os
|
||||
import asyncio
|
||||
from lightrag import LightRAG, QueryParam
|
||||
from lightrag.llm.ollama import ollama_embed, openai_complete_if_cache
|
||||
from lightrag.utils import EmbeddingFunc
|
||||
from lightrag.kg.shared_storage import initialize_pipeline_status
|
||||
|
||||
# WorkingDir
|
||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
WORKING_DIR = os.path.join(ROOT_DIR, "myKG")
|
||||
if not os.path.exists(WORKING_DIR):
|
||||
os.mkdir(WORKING_DIR)
|
||||
print(f"WorkingDir: {WORKING_DIR}")
|
||||
|
||||
# redis
|
||||
os.environ["REDIS_URI"] = "redis://localhost:6379"
|
||||
|
||||
# neo4j
|
||||
BATCH_SIZE_NODES = 500
|
||||
BATCH_SIZE_EDGES = 100
|
||||
os.environ["NEO4J_URI"] = "neo4j://localhost:7687"
|
||||
os.environ["NEO4J_USERNAME"] = "neo4j"
|
||||
os.environ["NEO4J_PASSWORD"] = "12345678"
|
||||
|
||||
# milvus
|
||||
os.environ["MILVUS_URI"] = "http://localhost:19530"
|
||||
os.environ["MILVUS_USER"] = "root"
|
||||
os.environ["MILVUS_PASSWORD"] = "Milvus"
|
||||
os.environ["MILVUS_DB_NAME"] = "lightrag"
|
||||
|
||||
|
||||
async def llm_model_func(
|
||||
prompt, system_prompt=None, history_messages=[], keyword_extraction=False, **kwargs
|
||||
) -> str:
|
||||
return await openai_complete_if_cache(
|
||||
"deepseek-chat",
|
||||
prompt,
|
||||
system_prompt=system_prompt,
|
||||
history_messages=history_messages,
|
||||
api_key="",
|
||||
base_url="",
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
embedding_func = EmbeddingFunc(
|
||||
embedding_dim=768,
|
||||
max_token_size=512,
|
||||
func=lambda texts: ollama_embed(
|
||||
texts, embed_model="shaw/dmeta-embedding-zh", host="http://117.50.173.35:11434"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def initialize_rag():
|
||||
rag = LightRAG(
|
||||
working_dir=WORKING_DIR,
|
||||
llm_model_func=llm_model_func,
|
||||
summary_max_tokens=10000,
|
||||
embedding_func=embedding_func,
|
||||
chunk_token_size=512,
|
||||
chunk_overlap_token_size=256,
|
||||
kv_storage="RedisKVStorage",
|
||||
graph_storage="Neo4JStorage",
|
||||
vector_storage="MilvusVectorDBStorage",
|
||||
doc_status_storage="RedisKVStorage",
|
||||
)
|
||||
|
||||
await rag.initialize_storages()
|
||||
await initialize_pipeline_status()
|
||||
|
||||
return rag
|
||||
|
||||
|
||||
def main():
|
||||
# Initialize RAG instance
|
||||
rag = asyncio.run(initialize_rag())
|
||||
|
||||
with open("./book.txt", "r", encoding="utf-8") as f:
|
||||
rag.insert(f.read())
|
||||
|
||||
# Perform naive search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="naive")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform local search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="local")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform global search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="global")
|
||||
)
|
||||
)
|
||||
|
||||
# Perform hybrid search
|
||||
print(
|
||||
rag.query(
|
||||
"What are the top themes in this story?", param=QueryParam(mode="hybrid")
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user