Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bootstraprag/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ def create(project_name, framework, template, observability):
'rag-with-controllable-agents',
'rag-with-llama-parse',
'rag-with-adjacent-context',
'rag-with-sub-question-query-engine',
'rag-with-recursive-retriever',
'rag-with-citation',
'agents-with-introspection',
'llama-deploy-with-simplemq',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### Recursive Retrieve Agents
In LlamaIndex, the Recursive Retriever is a specialized component designed to enhance information retrieval by navigating through interconnected nodes within a document or across multiple documents. Unlike traditional retrieval methods that fetch information based solely on direct relevance, the Recursive Retriever delves deeper into the relationships between data points, allowing for a more comprehensive extraction of pertinent information.

### How to run?
`pip install -r requirements.txt`
`python main.py`

### How to expose as API?
`python api_server.py`
- Method: POST
- API: http://localhost:8000/api/v1/chat-completion
- Body:
```json
{
"query": "explain mlops architecture"
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(self, agent_names: List[str], data_dir: str = 'data'):
self.document_data = {}
self.agents = {}
self.query_engine = None
self.client: qdrant_client.QdrantClient = None

# Load environment variables
load_dotenv(find_dotenv())
Expand Down Expand Up @@ -60,6 +61,7 @@ def _setup_vector_store(self):
url=os.environ['DB_URL'],
api_key=os.environ['DB_API_KEY']
)
self.client = client
self.vector_store = QdrantVectorStore(
client=client,
collection_name=os.environ['COLLECTION_NAME']
Expand Down Expand Up @@ -91,11 +93,16 @@ def _create_query_engine_tools(self, agent_name: str, vector_index: VectorStoreI
def _build_agents(self):
"""Build agents with their respective tools."""
for agent_name in self.agent_names:
# Build indices
vector_index = VectorStoreIndex.from_documents(
self.document_data[agent_name],
storage_context=self.storage_context
)

if not self.client.collection_exists(collection_name=os.environ.get("COLLECTION_NAME")):
# Build indices
vector_index = VectorStoreIndex.from_documents(
self.document_data[agent_name],
storage_context=self.storage_context
)
else:
vector_index = VectorStoreIndex.from_vector_store(vector_store=self.vector_store)

summary_index = SummaryIndex.from_documents(
self.document_data[agent_name],
storage_context=self.storage_context
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
### Recursive Retrieve Agents
In LlamaIndex, the Recursive Retriever is a specialized component designed to enhance information retrieval by navigating through interconnected nodes within a document or across multiple documents. Unlike traditional retrieval methods that fetch information based solely on direct relevance, the Recursive Retriever delves deeper into the relationships between data points, allowing for a more comprehensive extraction of pertinent information.

### How to run?
`pip install -r requirements.txt`
`python main.py`

### How to expose as API?
`python api_server.py`
- Method: POST
- API: http://localhost:8000/api/v1/chat-completion
- Body:
```json
{
"query": "explain mlops architecture"
}
```

#### How to spin observability
- run `docker compose -f docker-compose-langfuse.yml up`
- launch langfuse in browser `http://localhost:3000`
- click on `signup`
- create `organization` & `project`
- once done create your `public` and `private` api keys
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- click on `signup`
- create `organization` & `project`
- once done create your `public` and `private` api keys
-

#### Instructions to run the code
- Navigate to the root of the project and run the below command
- `pip install -r requirements.txt`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
DB_URL='http://localhost:6333'
DB_API_KEY='th3s3cr3tk3y'
COLLECTION_NAME='SUB_QUESTION_COLLECTION'

OPENAI_API_KEY='sk-proj-'
OPENAI_EMBED_MODEL='gpt-4o'

# use this incase you are prefering to experiment with local models.
OLLAMA_BASE_URL='http://localhost:11434'
OLLAMA_LLM_MODEL='llama3.1'
OLLAMA_EMBED_MODEL='nomic-embed-text:latest'

CHUNK_SIZE=128
CHUNK_OVERLAP=20

# logger can be controlled usiing env
CRITICAL = 50
FATAL = 50
ERROR = 40
WARNING = 30
WARN = 30
INFO = 20
DEBUG = 10
NOTSET = 0

LIT_SERVER_PORT=8000
LIT_SERVER_WORKERS_PER_DEVICE=4

IS_EVALUATION_NEEDED=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from dotenv import load_dotenv, find_dotenv
from sub_question_query_engine import SubQuestionQueryEngineAgent
import litserve as lit
import os


class SubQuestionQueryAPI(lit.LitAPI):
def __init__(self):
load_dotenv(find_dotenv())
self.engine = None

def setup(self, device):
self.engine = SubQuestionQueryEngineAgent()

def decode_request(self, request, **kwargs):
return request['query']

def predict(self, x, **kwargs):
return self.engine.query(x)

def encode_response(self, output, **kwargs):
return {'Agent': output}


if __name__ == "__main__":
lit_api = SubQuestionQueryAPI()
server = lit.LitServer(lit_api=lit_api, api_path='/api/v1/chat-completion',
workers_per_device=int(os.environ.get('LIT_SERVER_WORKERS_PER_DEVICE')))
server.run(port=os.environ.get('LIT_SERVER_PORT'))
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from sub_question_query_engine import SubQuestionQueryEngineAgent


def print_welcome_message():
print("\n=== Orthodontics Query System ===")
print("Type your question and press Enter")
print("Type 'quit' to exit the program")
print("================================\n")


if __name__ == "__main__":
# Initialize the engine
engine = SubQuestionQueryEngineAgent()

# Load and index documents
print("Initializing the system... Please wait...")
engine.load_and_index_documents()

# Display welcome message
print_welcome_message()

while True:
try:
# Get user input
user_question = input("\nEnter your question: ").strip()

# Check for quit command
if user_question.lower() == 'quit':
print("\nThank you for using the system. Goodbye!")
break

# Skip empty questions
if not user_question:
print("Please enter a valid question.")
continue

# Execute query and print response
print("\nProcessing your question...\n")
response = engine.query(user_question)
print("\nResponse:", response)
print("\n" + "-" * 50) # Separator line

except Exception as e:
print(f"\nAn error occurred: {str(e)}")
print("Please try again with a different question.")
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### Sub Question Query Engine
The Sub-Question Query Engine in LlamaIndex is designed to handle complex queries that require information from multiple data sources. It operates by decomposing a complex query into several sub-questions, each directed to the most relevant data source. After obtaining responses to these sub-questions, it synthesizes them into a comprehensive final answer.

### How to run?
`pip install -r requirements.txt`
`python main.py`

### How to expose as API?
`python api_server.py`
- Method: POST
- API: http://localhost:8000/api/v1/chat-completion
- Body:
```json
{
"query": "Explain vertical plane in orthodontics"
}
```
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
llamaindex
llamaindex
llama-index-llms-ollama
llama-index-llms-openai
llama-index-agent-openai
llama-index-vector-stores-qdrant
qdrant-client
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext
from llama_index.core.tools import QueryEngineTool, ToolMetadata
from llama_index.core.query_engine import SubQuestionQueryEngine
from llama_index.core.callbacks import CallbackManager, LlamaDebugHandler
from llama_index.core import Settings
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
from llama_index.vector_stores.qdrant import QdrantVectorStore
from dotenv import load_dotenv, find_dotenv
import qdrant_client
import os


class SubQuestionQueryEngineAgent:
def __init__(self):
# Load environment variables
load_dotenv(find_dotenv())

# Initialize debug handler and settings
self._setup_settings()

# Initialize Qdrant clients
self.client = qdrant_client.QdrantClient(
url=os.environ['DB_URL'],
api_key=os.environ['DB_API_KEY']
)
self.aclient = qdrant_client.AsyncQdrantClient(
url=os.environ['DB_URL'],
api_key=os.environ['DB_API_KEY']
)

# Initialize query engine
self.query_engine = None

def _setup_settings(self):
"""Configure LlamaIndex settings"""
llama_debug = LlamaDebugHandler(print_trace_on_end=True)
callback_manager = CallbackManager([llama_debug])

Settings.callback_manager = callback_manager
Settings.llm = OpenAI(
model=os.environ.get("OPENAI_EMBED_MODEL"),
temperature=0.0
)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.chunk_size = int(os.environ.get("CHUNK_SIZE"))
Settings.chunk_overlap = int(os.environ.get("CHUNK_OVERLAP"))

def load_and_index_documents(self, input_dir="data"):
"""Load documents and create vector store index"""
# Load documents
orthodontics_docs = SimpleDirectoryReader(input_dir=input_dir).load_data(
show_progress=True
)

# Setup vector store and index
vector_store = QdrantVectorStore(
client=self.client,
aclient=self.aclient,
collection_name=os.environ.get("COLLECTION_NAME")
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
if not self.client.collection_exists(collection_name=os.environ.get("COLLECTION_NAME")):
vector_query_engine = VectorStoreIndex.from_documents(
documents=orthodontics_docs,
storage_context=storage_context
).as_query_engine()
else:
vector_query_engine = VectorStoreIndex.from_vector_store(
vector_store=vector_store).as_query_engine()

# Setup query engine tools
query_engine_tools = [
QueryEngineTool(
query_engine=vector_query_engine,
metadata=ToolMetadata(
name="orthodontics_tool",
description="guide on the orthodontics",
),
),
]

# Initialize SubQuestionQueryEngine
self.query_engine = SubQuestionQueryEngine.from_defaults(
query_engine_tools=query_engine_tools
)

def query(self, question: str):
"""Execute a query and return the response"""
if self.query_engine is None:
raise ValueError("Query engine not initialized. Call load_and_index_documents first.")

return self.query_engine.query(question)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
DB_URL='http://localhost:6333'
DB_API_KEY='th3s3cr3tk3y'
COLLECTION_NAME='SUB_QUESTION_COLLECTION'

OPENAI_API_KEY='sk-proj-'
OPENAI_EMBED_MODEL='gpt-4o'

# use this incase you are prefering to experiment with local models.
OLLAMA_BASE_URL='http://localhost:11434'
OLLAMA_LLM_MODEL='llama3.1'
OLLAMA_EMBED_MODEL='nomic-embed-text:latest'

CHUNK_SIZE=128
CHUNK_OVERLAP=20

# Langfuse Observability Details
LANGFUSE_PUBLIC_KEY='pk-lf-'
LANGFUSE_SECRET_KEY='sk-lf-'
LANGFUSE_HOST='http://localhost:3000'

# logger can be controlled usiing env
CRITICAL = 50
FATAL = 50
ERROR = 40
WARNING = 30
WARN = 30
INFO = 20
DEBUG = 10
NOTSET = 0

LIT_SERVER_PORT=8000
LIT_SERVER_WORKERS_PER_DEVICE=4

IS_EVALUATION_NEEDED=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from dotenv import load_dotenv, find_dotenv
from sub_question_query_engine import SubQuestionQueryEngineAgent
import litserve as lit
import os


class SubQuestionQueryAPI(lit.LitAPI):
def __init__(self):
load_dotenv(find_dotenv())
self.engine = None

def setup(self, device):
self.engine = SubQuestionQueryEngineAgent()

def decode_request(self, request, **kwargs):
return request['query']

def predict(self, x, **kwargs):
return self.engine.query(x)

def encode_response(self, output, **kwargs):
return {'Agent': output}


if __name__ == "__main__":
lit_api = SubQuestionQueryAPI()
server = lit.LitServer(lit_api=lit_api, api_path='/api/v1/chat-completion',
workers_per_device=int(os.environ.get('LIT_SERVER_WORKERS_PER_DEVICE')))
server.run(port=os.environ.get('LIT_SERVER_PORT'))
Binary file not shown.
Loading