chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:37:47 +08:00
commit 7653f56fed
1422 changed files with 359026 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
<a target="_blank" href="https://lightning.ai/akshay-ddods/studios/rag-using-llama-3-3-by-meta-ai">
<img src="https://pl-bolts-doc-images.s3.us-east-2.amazonaws.com/app-2/studio-badge.svg" alt="Open In Studio"/>
</a>
# LLama3.3-RAG application
This project leverages a locally Llama 3.3 to build a RAG application to **chat with your docs** and Streamlit to build the UI.
## Demo
Watch the demo video:
[![Watch the video](https://github.com/patchy631/ai-engineering-hub/blob/main/document-chat-rag/resources/thumbnail.png)](https://www.youtube.com/watch?v=ZgNJMWipirk)
## Installation and setup
**Setup Ollama**:
```bash
# setup ollama on linux
curl -fsSL https://ollama.com/install.sh | sh
# pull llama 3.3:70B
ollama pull llama3.3
```
**Setup Qdrant VectorDB**
```bash
docker run -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage:z \
qdrant/qdrant
```
**Install Dependencies**:
Ensure you have Python 3.11 or later installed.
```bash
pip install streamlit ollama llama-index-vector-stores-qdrant
```
---
## 📬 Stay Updated with Our Newsletter!
**Get a FREE Data Science eBook** 📖 with 150+ essential lessons in Data Science when you subscribe to our newsletter! Stay in the loop with the latest tutorials, insights, and exclusive resources. [Subscribe now!](https://join.dailydoseofds.com)
[![Daily Dose of Data Science Newsletter](https://github.com/patchy631/ai-engineering/blob/main/resources/join_ddods.png)](https://join.dailydoseofds.com)
---
## Contribution
Contributions are welcome! Please fork the repository and submit a pull request with your improvements.
+170
View File
@@ -0,0 +1,170 @@
# Adapted from https://docs.streamlit.io/knowledge-base/tutorials/build-conversational-apps#build-a-simple-chatbot-gui-with-streaming
import os
import base64
import gc
import random
import tempfile
import time
import uuid
from IPython.display import Markdown, display
from llama_index.core import Settings
from llama_index.llms.ollama import Ollama
from llama_index.core import PromptTemplate
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.core import VectorStoreIndex, ServiceContext, SimpleDirectoryReader
import streamlit as st
if "id" not in st.session_state:
st.session_state.id = uuid.uuid4()
st.session_state.file_cache = {}
session_id = st.session_state.id
client = None
@st.cache_resource
def load_llm():
llm = Ollama(model="llama3.3", request_timeout=120.0)
return llm
def reset_chat():
st.session_state.messages = []
st.session_state.context = None
gc.collect()
def display_pdf(file):
# Opening file from file path
st.markdown("### PDF Preview")
base64_pdf = base64.b64encode(file.read()).decode("utf-8")
# Embedding PDF in HTML
pdf_display = f"""<iframe src="data:application/pdf;base64,{base64_pdf}" width="400" height="100%" type="application/pdf"
style="height:100vh; width:100%"
>
</iframe>"""
# Displaying File
st.markdown(pdf_display, unsafe_allow_html=True)
with st.sidebar:
st.header(f"Add your documents!")
uploaded_file = st.file_uploader("Choose your `.pdf` file", type="pdf")
if uploaded_file:
try:
with tempfile.TemporaryDirectory() as temp_dir:
file_path = os.path.join(temp_dir, uploaded_file.name)
with open(file_path, "wb") as f:
f.write(uploaded_file.getvalue())
file_key = f"{session_id}-{uploaded_file.name}"
st.write("Indexing your document...")
if file_key not in st.session_state.get('file_cache', {}):
if os.path.exists(temp_dir):
loader = SimpleDirectoryReader(
input_dir = temp_dir,
required_exts=[".pdf"],
recursive=True
)
else:
st.error('Could not find the file you uploaded, please check again...')
st.stop()
docs = loader.load_data()
# setup llm & embedding model
llm=load_llm()
embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-large-en-v1.5", trust_remote_code=True)
# Creating an index over loaded data
Settings.embed_model = embed_model
index = VectorStoreIndex.from_documents(docs, show_progress=True)
# Create the query engine, where we use a cohere reranker on the fetched nodes
Settings.llm = llm
query_engine = index.as_query_engine(streaming=True)
# ====== Customise prompt template ======
qa_prompt_tmpl_str = (
"Context information is below.\n"
"---------------------\n"
"{context_str}\n"
"---------------------\n"
"Given the context information above I want you to think step by step to answer the query in a crisp manner, incase case you don't know the answer say 'I don't know!'.\n"
"Query: {query_str}\n"
"Answer: "
)
qa_prompt_tmpl = PromptTemplate(qa_prompt_tmpl_str)
query_engine.update_prompts(
{"response_synthesizer:text_qa_template": qa_prompt_tmpl}
)
st.session_state.file_cache[file_key] = query_engine
else:
query_engine = st.session_state.file_cache[file_key]
# Inform the user that the file is processed and Display the PDF uploaded
st.success("Ready to Chat!")
display_pdf(uploaded_file)
except Exception as e:
st.error(f"An error occurred: {e}")
st.stop()
col1, col2 = st.columns([6, 1])
with col1:
st.header(f"Chat with Docs using Llama-3.3")
with col2:
st.button("Clear ↺", on_click=reset_chat)
# Initialize chat history
if "messages" not in st.session_state:
reset_chat()
# 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"])
# Accept user input
if prompt := st.chat_input("What's up?"):
# Add user message to chat history
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"):
message_placeholder = st.empty()
full_response = ""
# Simulate stream of response with milliseconds delay
streaming_response = query_engine.query(prompt)
for chunk in streaming_response.response_gen:
full_response += chunk
message_placeholder.markdown(full_response + "")
# full_response = query_engine.query(prompt)
message_placeholder.markdown(full_response)
# st.session_state.context = ctx
# Add assistant response to chat history
st.session_state.messages.append({"role": "assistant", "content": full_response})
Binary file not shown.
@@ -0,0 +1,363 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# RAG using Meta AI Llama-3\n",
"\n",
"\n",
"<img src=\"./resources/rag_architecture.png\" width=800px>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"from dotenv import load_dotenv\n",
"from IPython.display import Markdown, display\n",
"\n",
"from llama_index.core import Settings\n",
"from llama_index.llms.ollama import Ollama\n",
"from llama_index.core import PromptTemplate\n",
"from llama_index.embeddings.huggingface import HuggingFaceEmbedding\n",
"from llama_index.core import VectorStoreIndex, ServiceContext, SimpleDirectoryReader\n",
"\n",
"from llama_index.vector_stores.qdrant import QdrantVectorStore\n",
"from llama_index.core import Settings\n",
"import qdrant_client"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# allows nested access to the event loop\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# add your documents in this directory, you can drag & drop\n",
"input_dir_path = '/teamspace/studios/this_studio/test-dir'"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"collection_name=\"chat_with_docs\"\n",
"\n",
"client = qdrant_client.QdrantClient(\n",
" host=\"localhost\",\n",
" port=6333\n",
")\n",
"\n",
"def create_index(documents):\n",
" vector_store = QdrantVectorStore(client=client, collection_name=collection_name)\n",
" storage_context = StorageContext.from_defaults(vector_store=vector_store)\n",
" index = VectorStoreIndex.from_documents(\n",
" documents,\n",
" storage_context=storage_context,\n",
" )\n",
" return index"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7b4ba9e36b4e47b982be21b95b24a181",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"config.json: 0%| | 0.00/779 [00:00<?, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "bf2ebc67bf4a4caf8c6292b80f869b7c",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"model.safetensors: 0%| | 0.00/1.34G [00:00<?, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "8e41ff80db1a44a1ac3dc99fc477a819",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"tokenizer_config.json: 0%| | 0.00/366 [00:00<?, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "17460d4930c241c8a7af9208b82d1310",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"vocab.txt: 0%| | 0.00/232k [00:00<?, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "1418bcfbba844062a80299a82f04d21d",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"tokenizer.json: 0%| | 0.00/711k [00:00<?, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f73ccdc9f6be4b9e9e5d69d3de936ec1",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"special_tokens_map.json: 0%| | 0.00/125 [00:00<?, ?B/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\n",
"# setup llm & embedding model\n",
"llm=Ollama(model=\"llama3.3\", request_timeout=120.0)\n",
"# embed_model = HuggingFaceEmbedding( model_name=\"Snowflake/snowflake-arctic-embed-m\", trust_remote_code=True)\n",
"embed_model = HuggingFaceEmbedding( model_name=\"BAAI/bge-large-en-v1.5\", trust_remote_code=True)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b9f486b6a1da4f15bb0e43469fa8c420",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Parsing nodes: 0%| | 0/17 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "363a055481fb4d808da9551727ee5307",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Generating embeddings: 0%| | 0/26 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# load data\n",
"loader = SimpleDirectoryReader(\n",
" input_dir = input_dir_path,\n",
" required_exts=[\".pdf\"],\n",
" recursive=True\n",
" )\n",
"docs = loader.load_data()\n",
"\n",
"# Creating an index over loaded data\n",
"Settings.embed_model = embed_model\n",
"try:\n",
" index = create_index(docs)\n",
" print('Using Qdrant collection')\n",
"except:\n",
" index = VectorStoreIndex.from_documents(docs, show_progress=True)\n",
"\n",
"# Create the query engine, where we use a cohere reranker on the fetched nodes\n",
"Settings.llm = llm\n",
"query_engine = index.as_query_engine()\n",
"\n",
"# ====== Customise prompt template ======\n",
"qa_prompt_tmpl_str = (\n",
"\"Context information is below.\\n\"\n",
"\"---------------------\\n\"\n",
"\"{context_str}\\n\"\n",
"\"---------------------\\n\"\n",
"\"Given the context information above I want you to think step by step to answer the query in a crisp manner, incase case you don't know the answer say 'I don't know!'.\\n\"\n",
"\"Query: {query_str}\\n\"\n",
"\"Answer: \"\n",
")\n",
"qa_prompt_tmpl = PromptTemplate(qa_prompt_tmpl_str)\n",
"\n",
"query_engine.update_prompts(\n",
" {\"response_synthesizer:text_qa_template\": qa_prompt_tmpl}\n",
")\n",
"\n",
"# Generate the response\n",
"response = query_engine.query(\"What exactly is DSPy?\",)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"DSPy is a framework for programmatically solving advanced tasks with language and retrieval models through composing and declaring modules. It aims to replace brittle \"prompt engineering\" tricks with composable modules and automatic optimizers, allowing developers to define signatures that specify what a language model (LM) needs to do declaratively."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display(Markdown(str(response)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ❗️❗️ Make sure you clear GPU memory by clicking on Restart button above, if you want to use Streamlit from here"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
"To disable this warning, you can either:\n",
"\t- Avoid using `tokenizers` before the fork if possible\n",
"\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Sat Dec 7 08:31:49 2024 \n",
"+---------------------------------------------------------------------------------------+\n",
"| NVIDIA-SMI 535.216.03 Driver Version: 535.216.03 CUDA Version: 12.2 |\n",
"|-----------------------------------------+----------------------+----------------------+\n",
"| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
"| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
"| | | MIG M. |\n",
"|=========================================+======================+======================|\n",
"| 0 NVIDIA L4 Off | 00000000:35:00.0 Off | 0 |\n",
"| N/A 36C P0 31W / 72W | 19895MiB / 23034MiB | 0% Default |\n",
"| | | N/A |\n",
"+-----------------------------------------+----------------------+----------------------+\n",
" \n",
"+---------------------------------------------------------------------------------------+\n",
"| Processes: |\n",
"| GPU GI CI PID Type Process name GPU Memory |\n",
"| ID ID Usage |\n",
"|=======================================================================================|\n",
"+---------------------------------------------------------------------------------------+\n"
]
}
],
"source": [
"# check GPU usage\n",
"\n",
"!nvidia-smi"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
+193
View File
@@ -0,0 +1,193 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# RAG using Meta AI Llama-3.2\n",
"\n",
"\n",
"<img src=\"./resources/rag_architecture.png\" width=800px>"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import nest_asyncio\n",
"from IPython.display import Markdown, display\n",
"\n",
"from llama_index.core import Settings\n",
"from llama_index.llms.ollama import Ollama\n",
"from llama_index.core import PromptTemplate\n",
"from llama_index.embeddings.huggingface import HuggingFaceEmbedding\n",
"from llama_index.core import VectorStoreIndex, ServiceContext, SimpleDirectoryReader, StorageContext\n",
"from llama_index.core.postprocessor import SentenceTransformerRerank\n",
"from llama_index.vector_stores.qdrant import QdrantVectorStore\n",
"from llama_index.core import Settings\n",
"import qdrant_client"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# allows nested access to the event loop\n",
"nest_asyncio.apply()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# add your documents in this directory, you can drag & drop\n",
"input_dir_path = './docs'"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"collection_name=\"chat_with_docs\"\n",
"\n",
"client = qdrant_client.QdrantClient(\n",
" host=\"localhost\",\n",
" port=6333\n",
")\n",
"\n",
"def create_index(documents):\n",
" vector_store = QdrantVectorStore(client=client, collection_name=collection_name)\n",
" storage_context = StorageContext.from_defaults(vector_store=vector_store)\n",
" index = VectorStoreIndex.from_documents(\n",
" documents,\n",
" storage_context=storage_context,\n",
" )\n",
" return index"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"\n",
"# setup llm & embedding model and reranker\n",
"llm=Ollama(model=\"llama3.2:1b\", request_timeout=120.0)\n",
"embed_model = HuggingFaceEmbedding( model_name=\"BAAI/bge-large-en-v1.5\", trust_remote_code=True)\n",
"rerank = SentenceTransformerRerank(\n",
" model=\"cross-encoder/ms-marco-MiniLM-L-2-v2\", top_n=3\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Parsing nodes: 100%|██████████| 32/32 [00:00<00:00, 369.47it/s]\n",
"Generating embeddings: 100%|██████████| 45/45 [00:25<00:00, 1.77it/s]\n"
]
}
],
"source": [
"# load data\n",
"loader = SimpleDirectoryReader(\n",
" input_dir = input_dir_path,\n",
" required_exts=[\".pdf\"],\n",
" recursive=True\n",
" )\n",
"docs = loader.load_data()\n",
"\n",
"# Creating an index over loaded data\n",
"Settings.embed_model = embed_model\n",
"try:\n",
" index = create_index(docs)\n",
" print('Using Qdrant collection')\n",
"except:\n",
" index = VectorStoreIndex.from_documents(docs, show_progress=True)\n",
"\n",
"# Create the query engine, where we use a cohere reranker on the fetched nodes\n",
"Settings.llm = llm\n",
"query_engine = index.as_query_engine(\n",
" similarity_top_k=10, node_postprocessors=[rerank]\n",
")\n",
"\n",
"# ====== Customise prompt template ======\n",
"qa_prompt_tmpl_str = (\n",
"\"Context information is below.\\n\"\n",
"\"---------------------\\n\"\n",
"\"{context_str}\\n\"\n",
"\"---------------------\\n\"\n",
"\"Given the context information above I want you to think step by step to answer the query in a crisp manner, incase case you don't know the answer say 'I don't know!'.\\n\"\n",
"\"Query: {query_str}\\n\"\n",
"\"Answer: \"\n",
")\n",
"qa_prompt_tmpl = PromptTemplate(qa_prompt_tmpl_str)\n",
"\n",
"query_engine.update_prompts(\n",
" {\"response_synthesizer:text_qa_template\": qa_prompt_tmpl}\n",
")\n",
"\n",
"# Generate the response\n",
"response = query_engine.query(\"What exactly is DSPy?\",)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"DSPy stands for \"Deep Semantic Prompting and Parameterized Yield\". It is a programming model developed by Stanford Natural Language Processing Group that translates prompting techniques into parameterized declarative modules, which can be used to build complex natural language processing (NLP) systems. Specifically, DSPy allows users to define natural language signatures, or prompts, using a shorthand notation, and then uses these signatures to abstract and automate the task of prompting large language models, such as those used in transformer-based architectures like GPT-3.5."
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"display(Markdown(str(response)))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.15"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB