Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LlamaIndex RAGPlayground #6

Merged
merged 13 commits into from
May 13, 2024
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
33 changes: 33 additions & 0 deletions LlamaIndex/RAGPlayground/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "Python 3",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bullseye",
"customizations": {
"codespaces": {
"openFiles": [
"README.md",
"rag\app.py"
]
},
"vscode": {
"settings": {},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance"
]
}
},
"updateContentCommand": "[ -f packages.txt ] && sudo apt update && sudo apt upgrade -y && sudo xargs apt install -y <packages.txt; [ -f requirements.txt ] && pip3 install --user -r requirements.txt; pip3 install --user streamlit; echo '✅ Packages installed and Requirements met'",
"postAttachCommand": {
"server": "streamlit run rag\app.py --server.enableCORS false --server.enableXsrfProtection false"
},
"portsAttributes": {
"8501": {
"label": "Application",
"onAutoForward": "openPreview"
}
},
"forwardPorts": [
8501
]
}
78 changes: 78 additions & 0 deletions LlamaIndex/RAGPlayground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
## RAG Playground Using LlamaIndex
[Demo](https://github.com/abhi2596/rag_demo/assets/80634226/08f6c7c4-65e3-49b4-bfb1-9a5db2cce248)

<video width="640" height="480" autoplay>
<source src="../../../../_static/RAG_LlamaIndex.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>

## Introduction

The RAG Playground is an application designed to facilitate question-answering tasks based on uploaded PDF documents. It leverages LLamaIndex for RAG functionalities and utilizes Streamlit for the user interface.

## Key Features

- **PDF Upload:** Easily upload PDF files to the application.
- **Questioning:** Ask questions about the uploaded PDF documents.
- **RAG Integration:** Utilize LLamaIndex for RAG capabilities.
- **Embeddings:** Convert text to embeddings using the BAAI/bge-small-en-v1.5 model.
- **Reranker:** Reorder search results based on relevance to queries.
- **Streamlit Optimization:** Enhance performance using `@st.experimental_fragment` and `@st.cache_resource`.

## Project Workflow

1. **PDF Processing:**
- Load PDF files and extract text using PDFReader.
- Load data into Documents in LLamaIndex.
2. **Chunking and Conversion:**
- Chunk text and convert it into nodes using `VectorStoreIndex.from_documents`.
- Convert text to embeddings using the BAAI/bge-small-en-v1.5 model.
3. **Search Optimization:**
- Implement a reranker to reorder search results based on query relevance.
- Display top-ranked results after reranking.
4. **Interface Optimization:**
- Build the user interface using Streamlit.
- Optimize Streamlit performance with `@st.experimental_fragment` and `@st.cache_resource`.

## Tech Stack Used

- LLamaIndex
- Streamlit
- BAAI/bge-small-en-v1.5 model

## Repository and Deployment
Github - https://github.com/abhi2596/UnifyAI_RAG_playground/tree/main
Streamlit App - https://unifyai-rag-playground.streamlit.app/

Instructions to run locally:

1. First create a virtual environment in python

```
python -m venv <virtual env name>
```
2. Activate it and install poetry

```
source <virtual env name>/Scripts/activate - Windows
source <virtual env name>/bin/activate - Linux/Unix
pip install poetry
```
3. Clone the repo

```
git clone https://github.com/abhi2596/UnifyAI_RAG_playground/tree/main
```
4. Run the following commands

```
poetry install
cd rag
streamlit run app.py
```

## Contributors

| Name | GitHub Profile |
|------|----------------|
| Abhijeet Chintakunta | [abhi2596](https://github.com/abhi2596) |
4,344 changes: 4,344 additions & 0 deletions LlamaIndex/RAGPlayground/poetry.lock

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions LlamaIndex/RAGPlayground/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[tool.poetry]
name = "rag"
version = "0.1.0"
description = ""
authors = ["abhi2596 <abhijeetchintakunta@gmail.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = ">=3.9,<3.9.7 || >3.9.7,<4.0"
streamlit = "^1.33.0"
llama-index = "^0.10.30"
llama-index-core = "^0.10.30"
llama-index-readers-file = "^0.1.19"
beautifulsoup4 = "^4.12.3"
html5lib = "^1.1"
unifyai = "^0.8.2"
pypdf2 = "^3.0.1"
llama-index-llms-openai-like = "^0.1.3"
fitz = "^0.0.1.dev2"
pymupdf = "^1.24.2"
sentence-transformers = "^2.2.2"
llama-index-embeddings-huggingface = "^0.2.0"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Empty file.
105 changes: 105 additions & 0 deletions LlamaIndex/RAGPlayground/rag/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import streamlit as st
from llama_index.core import VectorStoreIndex, Settings,Document
from llama_index.core.embeddings import resolve_embed_model
from llama_index.core.postprocessor import SentenceTransformerRerank
from unify_llm import Unify
from PyPDF2 import PdfReader
import unify
from llama_index.core.node_parser import SentenceSplitter

# load_dotenv()

# add dynamic routing
# look into caching again and also mp_fragment and load_llm and clear chat history
# app should be fast

def reset():
st.session_state.messages = []

st.title("Chat with Data")

api_key = st.sidebar.text_input("Unify AI Key",type="password")

def provider(model_name):
dynamic = st.toggle("Dynamic Routing")
if dynamic:
providers = ["lowest-input-cost","lowest-output-cost","lowest-itl","lowest-ttft","highest-tks-per-sec"]
provider_name = st.selectbox("Select a Provider",options=providers,index=1)
else:
provider_name = st.selectbox("Select a Provider",options=unify.list_providers(model_name))
return provider_name

@st.experimental_fragment
def mp_fragment():
model_name = st.selectbox("Select Model",options=unify.list_models(),index=7)
provider_name = provider(model_name)
return model_name,provider_name

def load_models(model_name,provider_name):
Settings.llm = Unify(model=f"{model_name}@{provider_name}",api_key=api_key)

@st.cache_resource
def rerank_model():
rerank = SentenceTransformerRerank(
model="cross-encoder/ms-marco-MiniLM-L-2-v2", top_n=3
)
return rerank

with st.sidebar:
model_name,provider_name = mp_fragment()
uploaded_file = st.file_uploader("Upload a PDF file", accept_multiple_files=False,on_change=reset)
st.sidebar.button("Clear Chat History",on_click=reset)


load_models(model_name,provider_name)

if uploaded_file is not None:
@st.cache_resource
def vector_store(uploaded_file):
reader = PdfReader(uploaded_file)
text_list = []
for page in reader.pages:
text_list.append(page.extract_text())
documents = [Document(text=t) for t in text_list]
Settings.embed_model = resolve_embed_model(embed_model="local:BAAI/bge-small-en-v1.5")
index = VectorStoreIndex.from_documents(documents)
return index

index = vector_store(uploaded_file)
chat_engine = index.as_chat_engine(chat_mode="context",verbose=True,similarity_top_k=10,node_postprocessors=[rerank_model()])

# Initialize chat history
if "messages" not in st.session_state:
st.session_state.messages = []

# Display chat messages from history on app rerun
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])

if len(st.session_state.messages) == 0:
with st.chat_message("assistant"):
initial = " Follow this steps before asking questions about your data \n 1. Enter Unify API key \n 2. Select a Model and Provider using the sidebar \n 3. Upload a PDF file which is not encrypted \n 4. Any changes to sidebar will reset chat"
st.markdown(initial)
st.session_state.messages.append({"role": "assistant", "content": initial})

# Accept user input
if prompt := st.chat_input():
# Add user message to chat history
if api_key == "" and uploaded_file is None:
st.warning("Please Enter a Unify API key and upload a file")
elif api_key is None:
st.warning("Please Enter a Unify API key")
elif uploaded_file is None:
st.warning("Upload a File")
else:
st.session_state.messages.append({"role": "user", "content": prompt})
# Display user message in chat message container
with st.chat_message("user"):
st.markdown(prompt)
# Display assistant response in chat message container
with st.chat_message("assistant"):
response = chat_engine.stream_chat(prompt)
response = st.write_stream(response.response_gen)
# response = st.write(response)
st.session_state.messages.append({"role": "assistant", "content": response})
26 changes: 26 additions & 0 deletions LlamaIndex/RAGPlayground/rag/unify_llm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from llama_index.llms.openai_like import OpenAILike
import os
from typing import Any,Optional

class Unify(OpenAILike):
def __init__(
self,
model: str,
api_key: Optional[str] = None,
api_base: str = "https://api.unify.ai/v0",
is_chat_model: bool = True,
**kwargs: Any,
) -> None:
api_key = api_key or os.environ.get("UNIFY_API_KEY", None)
super().__init__(
model=model,
api_key=api_key,
api_base=api_base,
is_chat_model=is_chat_model,
**kwargs,
)

@classmethod
def class_name(cls) -> str:
"""Get class name."""
return "UnifyLLM"
Empty file.
2 changes: 1 addition & 1 deletion LlamaIndex/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# LlamaIndex Projects
This folder contains various projects built using the LangChain Unify Integration. Please headover to the corresponding folder of the project for more details.
This folder contains various projects built using the LLamaIndex Unify Integration. Please headover to the corresponding folder of the project for more details.

## Introduction
Provide a brief introduction to your project here. Describe what your project demonstrates, the tech stack used, the motivation behind the project, and briefly explain the necessary concepts used. Feel free to break down this section into multiple subsections depending on your project.
Expand Down
Binary file added videos/RAG_LLamaIndex.mp4
Binary file not shown.