Spaces:
Sleeping
Sleeping
Commit
Β·
a409078
1
Parent(s):
498e5e4
feat: add more sources for data
Browse files- README.md +30 -7
- data_upload/data_upload_page.py +10 -34
- data_upload/input_sources_utils/image_util.py +46 -0
- data_upload/input_sources_utils/pdf_util.py +22 -0
- data_upload/input_sources_utils/text_util.py +24 -0
- data_upload/input_sources_utils/website_util.py +56 -0
- requirements.txt +3 -0
- vectordb.py +19 -3
- weights/adapter_model.pt +3 -0
README.md
CHANGED
@@ -21,21 +21,24 @@ short_description: π§ Multimodal RAG that "weaves" together text and images
|
|
21 |
![GitHub](https://img.shields.io/github/license/NotShrirang/LoomRAG)
|
22 |
![GitHub last commit](https://img.shields.io/github/last-commit/NotShrirang/LoomRAG)
|
23 |
![GitHub repo size](https://img.shields.io/github/repo-size/NotShrirang/LoomRAG)
|
24 |
-
<a href="https://
|
25 |
|
26 |
-
This project implements a Multimodal Retrieval-Augmented Generation (RAG) system, named **LoomRAG**, that leverages OpenAI's CLIP model for neural cross-modal retrieval and semantic search. The system allows users to input text queries and retrieve both text and image responses seamlessly through vector embeddings. It also supports uploading images and PDFs for enhanced interaction and intelligent retrieval capabilities through a Streamlit-based interface.
|
27 |
|
28 |
Experience the project in action:
|
29 |
|
30 |
-
[![LoomRAG Streamlit App](https://img.shields.io/badge/Streamlit%20App-red?style=for-the-badge&logo=streamlit&labelColor=white)](https://
|
31 |
|
32 |
---
|
33 |
|
34 |
## πΈ Implementation Screenshots
|
35 |
|
36 |
-
| ![Screenshot
|
37 |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
38 |
-
|
|
|
|
|
|
|
|
39 |
|
40 |
---
|
41 |
|
@@ -46,6 +49,9 @@ Experience the project in action:
|
|
46 |
- π€ **Upload Options**: Allows users to upload images and PDFs for AI-powered processing and retrieval
|
47 |
- π§ **Embedding-Based Search**: Uses OpenAI's CLIP model to align text and image embeddings in a shared latent space
|
48 |
- π **Augmented Text Generation**: Enhances text results using LLMs for contextually rich outputs
|
|
|
|
|
|
|
49 |
|
50 |
---
|
51 |
|
@@ -63,10 +69,23 @@ Experience the project in action:
|
|
63 |
- The system performs a nearest neighbor search in the vector database to retrieve relevant text and images
|
64 |
|
65 |
3. **Response Generation**:
|
|
|
66 |
- For text results: Optionally refined or augmented using a language model
|
67 |
- For image results: Directly returned or enhanced with image captions
|
68 |
- For PDFs: Extracts text content and provides relevant sections
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
---
|
71 |
|
72 |
## π Installation
|
@@ -98,6 +117,9 @@ Experience the project in action:
|
|
98 |
- Access the interface in your browser to:
|
99 |
- Submit natural language queries
|
100 |
- Upload images or PDFs to retrieve contextually relevant results
|
|
|
|
|
|
|
101 |
|
102 |
2. **Example Queries**:
|
103 |
- **Text Query**: "sunset over mountains"
|
@@ -112,12 +134,13 @@ Experience the project in action:
|
|
112 |
- π **Vector Database**: It uses FAISS for efficient similarity search
|
113 |
- π€ **Model**: Uses OpenAI CLIP for neural embedding generation
|
114 |
- βοΈ **Augmentation**: Optional LLM-based augmentation for text responses
|
|
|
115 |
|
116 |
---
|
117 |
|
118 |
## πΊοΈ Roadmap
|
119 |
|
120 |
-
- [
|
121 |
- [ ] Adding support for audio and video modalities
|
122 |
- [ ] Improving the re-ranking system for better contextual relevance
|
123 |
- [ ] Enhanced PDF parsing with semantic section segmentation
|
@@ -132,7 +155,7 @@ Contributions are welcome! Please open an issue or submit a pull request for any
|
|
132 |
|
133 |
## π License
|
134 |
|
135 |
-
This project is licensed under the
|
136 |
|
137 |
---
|
138 |
|
|
|
21 |
![GitHub](https://img.shields.io/github/license/NotShrirang/LoomRAG)
|
22 |
![GitHub last commit](https://img.shields.io/github/last-commit/NotShrirang/LoomRAG)
|
23 |
![GitHub repo size](https://img.shields.io/github/repo-size/NotShrirang/LoomRAG)
|
24 |
+
<a href="https://huggingface.co/spaces/NotShrirang/LoomRAG"><img src="https://img.shields.io/badge/Streamlit%20App-red?style=flat-rounded-square&logo=streamlit&labelColor=white"/></a>
|
25 |
|
26 |
+
This project implements a Multimodal Retrieval-Augmented Generation (RAG) system, named **LoomRAG**, that leverages OpenAI's CLIP model for neural cross-modal retrieval and semantic search. The system allows users to input text queries and retrieve both text and image responses seamlessly through vector embeddings. It features a comprehensive annotation interface for creating custom datasets and supports CLIP model fine-tuning with configurable parameters for domain-specific applications. The system also supports uploading images and PDFs for enhanced interaction and intelligent retrieval capabilities through a Streamlit-based interface.
|
27 |
|
28 |
Experience the project in action:
|
29 |
|
30 |
+
[![LoomRAG Streamlit App](https://img.shields.io/badge/Streamlit%20App-red?style=for-the-badge&logo=streamlit&labelColor=white)](https://huggingface.co/spaces/NotShrirang/LoomRAG)
|
31 |
|
32 |
---
|
33 |
|
34 |
## πΈ Implementation Screenshots
|
35 |
|
36 |
+
| ![Screenshot 2025-01-01 184852](https://github.com/user-attachments/assets/ad79d0f0-d200-4a82-8c2f-0890a9fe8189) | ![Screenshot 2025-01-01 222334](https://github.com/user-attachments/assets/7307857d-a41f-4f60-8808-00d6db6e8e3e) |
|
37 |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
38 |
+
| Data Upload Page | Data Search / Retrieval |
|
39 |
+
| | |
|
40 |
+
| ![Screenshot 2025-01-01 222412](https://github.com/user-attachments/assets/e38273f4-426b-444d-80f0-501fa9563779) | ![Screenshot 2025-01-01 223948](https://github.com/user-attachments/assets/21724a92-ef79-44ae-83e6-25f8de29c45a) |
|
41 |
+
| Data Annotation Page | CLIP Fine-Tuning |
|
42 |
|
43 |
---
|
44 |
|
|
|
49 |
- π€ **Upload Options**: Allows users to upload images and PDFs for AI-powered processing and retrieval
|
50 |
- π§ **Embedding-Based Search**: Uses OpenAI's CLIP model to align text and image embeddings in a shared latent space
|
51 |
- π **Augmented Text Generation**: Enhances text results using LLMs for contextually rich outputs
|
52 |
+
- π·οΈ **Image Annotation**: Enables users to annotate uploaded images through an intuitive interface
|
53 |
+
- π― **CLIP Fine-Tuning**: Supports custom model training with configurable parameters including test dataset split size, learning rate, optimizer, and weight decay
|
54 |
+
- π¨ **Fine-Tuned Model Integration**: Seamlessly load and utilize fine-tuned CLIP models for enhanced search and retrieval
|
55 |
|
56 |
---
|
57 |
|
|
|
69 |
- The system performs a nearest neighbor search in the vector database to retrieve relevant text and images
|
70 |
|
71 |
3. **Response Generation**:
|
72 |
+
|
73 |
- For text results: Optionally refined or augmented using a language model
|
74 |
- For image results: Directly returned or enhanced with image captions
|
75 |
- For PDFs: Extracts text content and provides relevant sections
|
76 |
|
77 |
+
4. **Image Annotation**:
|
78 |
+
|
79 |
+
- Dedicated annotation page for managing uploaded images
|
80 |
+
- Support for creating and managing multiple datasets simultaneously
|
81 |
+
- Flexible annotation workflow for efficient data labeling
|
82 |
+
- Dataset organization and management capabilities
|
83 |
+
|
84 |
+
5. **Model Fine-Tuning**:
|
85 |
+
- Custom CLIP model training on annotated images
|
86 |
+
- Configurable training parameters for optimization
|
87 |
+
- Integration of fine-tuned models into the search pipeline
|
88 |
+
|
89 |
---
|
90 |
|
91 |
## π Installation
|
|
|
117 |
- Access the interface in your browser to:
|
118 |
- Submit natural language queries
|
119 |
- Upload images or PDFs to retrieve contextually relevant results
|
120 |
+
- Annotate uploaded images
|
121 |
+
- Fine-tune CLIP models with custom parameters
|
122 |
+
- Use fine-tuned models for improved search results
|
123 |
|
124 |
2. **Example Queries**:
|
125 |
- **Text Query**: "sunset over mountains"
|
|
|
134 |
- π **Vector Database**: It uses FAISS for efficient similarity search
|
135 |
- π€ **Model**: Uses OpenAI CLIP for neural embedding generation
|
136 |
- βοΈ **Augmentation**: Optional LLM-based augmentation for text responses
|
137 |
+
- ποΈ Fine-Tuning: Configurable parameters for model training and optimization
|
138 |
|
139 |
---
|
140 |
|
141 |
## πΊοΈ Roadmap
|
142 |
|
143 |
+
- [x] Fine-tuning CLIP for domain-specific datasets
|
144 |
- [ ] Adding support for audio and video modalities
|
145 |
- [ ] Improving the re-ranking system for better contextual relevance
|
146 |
- [ ] Enhanced PDF parsing with semantic section segmentation
|
|
|
155 |
|
156 |
## π License
|
157 |
|
158 |
+
This project is licensed under the Apache-2.0 License. See the [LICENSE](LICENSE) file for details.
|
159 |
|
160 |
---
|
161 |
|
data_upload/data_upload_page.py
CHANGED
@@ -1,44 +1,20 @@
|
|
1 |
import os
|
2 |
import streamlit as st
|
3 |
import sys
|
4 |
-
|
|
|
5 |
|
6 |
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
7 |
|
8 |
|
9 |
def data_upload(clip_model, preprocess, text_embedding_model):
|
10 |
st.title("Data Upload")
|
11 |
-
upload_choice = st.selectbox(options=["Upload Image", "Upload PDF"], label="Select Upload Type")
|
12 |
if upload_choice == "Upload Image":
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
with cols[4]:
|
21 |
-
if len(images) > 5:
|
22 |
-
st.info(f"and more {len(images) - 5} images...")
|
23 |
-
st.info(f"Total {len(images)} files selected.")
|
24 |
-
if st.button("Add Images"):
|
25 |
-
progress_bar = st.progress(0)
|
26 |
-
for image in images:
|
27 |
-
add_image_to_index(image, clip_model, preprocess)
|
28 |
-
progress_bar.progress((images.index(image) + 1) / len(images), f"{images.index(image) + 1}/{len(images)}")
|
29 |
-
st.success("Images Added to Database")
|
30 |
-
else:
|
31 |
-
st.subheader("Add PDF to Database")
|
32 |
-
st.warning("Please note that the images in the PDF will also be extracted and added to the database.")
|
33 |
-
pdfs = st.file_uploader("Upload PDF", type=["pdf"], accept_multiple_files=True)
|
34 |
-
if pdfs:
|
35 |
-
st.info(f"Total {len(pdfs)} files selected.")
|
36 |
-
if st.button("Add PDF"):
|
37 |
-
for pdf in pdfs:
|
38 |
-
add_pdf_to_index(
|
39 |
-
pdf=pdf,
|
40 |
-
clip_model=clip_model,
|
41 |
-
preprocess=preprocess,
|
42 |
-
text_embedding_model=text_embedding_model,
|
43 |
-
)
|
44 |
-
st.success("PDF Added to Database")
|
|
|
1 |
import os
|
2 |
import streamlit as st
|
3 |
import sys
|
4 |
+
|
5 |
+
from data_upload.input_sources_utils import image_util, pdf_util, website_util
|
6 |
|
7 |
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
8 |
|
9 |
|
10 |
def data_upload(clip_model, preprocess, text_embedding_model):
|
11 |
st.title("Data Upload")
|
12 |
+
upload_choice = st.selectbox(options=["Upload Image", "Add Image from URL / Link", "Upload PDF", "Website Link"], label="Select Upload Type")
|
13 |
if upload_choice == "Upload Image":
|
14 |
+
image_util.upload_image(clip_model, preprocess)
|
15 |
+
elif upload_choice == "Add Image from URL / Link":
|
16 |
+
image_util.image_from_url(clip_model, preprocess)
|
17 |
+
elif upload_choice == "Upload PDF":
|
18 |
+
pdf_util.upload_pdf(clip_model, preprocess, text_embedding_model)
|
19 |
+
elif upload_choice == "Website Link":
|
20 |
+
website_util.data_from_website(clip_model, preprocess, text_embedding_model)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data_upload/input_sources_utils/image_util.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import requests
|
3 |
+
import streamlit as st
|
4 |
+
import sys
|
5 |
+
from vectordb import add_image_to_index, add_pdf_to_index
|
6 |
+
|
7 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
8 |
+
|
9 |
+
def image_from_url(clip_model, preprocess):
|
10 |
+
st.title("Image from URL")
|
11 |
+
url = st.text_input("Enter Image URL")
|
12 |
+
correct_url = False
|
13 |
+
if url:
|
14 |
+
try:
|
15 |
+
st.image(url)
|
16 |
+
correct_url = True
|
17 |
+
except:
|
18 |
+
st.error("Invalid URL")
|
19 |
+
correct_url = False
|
20 |
+
if correct_url:
|
21 |
+
if st.button("Add Image"):
|
22 |
+
response = requests.get(url)
|
23 |
+
if response.status_code == 200:
|
24 |
+
add_image_to_index(response.content, clip_model, preprocess)
|
25 |
+
st.success("Image Added to Database")
|
26 |
+
else:
|
27 |
+
st.error("Invalid URL")
|
28 |
+
|
29 |
+
def upload_image(clip_model, preprocess):
|
30 |
+
st.subheader("Add Image to Database")
|
31 |
+
images = st.file_uploader("Upload Image", type=["jpg", "jpeg", "png"], accept_multiple_files=True)
|
32 |
+
if images:
|
33 |
+
cols = st.columns(5, vertical_alignment="center")
|
34 |
+
for count, image in enumerate(images[:4]):
|
35 |
+
with cols[count]:
|
36 |
+
st.image(image)
|
37 |
+
with cols[4]:
|
38 |
+
if len(images) > 5:
|
39 |
+
st.info(f"and more {len(images) - 5} images...")
|
40 |
+
st.info(f"Total {len(images)} files selected.")
|
41 |
+
if st.button("Add Images"):
|
42 |
+
progress_bar = st.progress(0)
|
43 |
+
for image in images:
|
44 |
+
add_image_to_index(image, clip_model, preprocess)
|
45 |
+
progress_bar.progress((images.index(image) + 1) / len(images), f"{images.index(image) + 1}/{len(images)}")
|
46 |
+
st.success("Images Added to Database")
|
data_upload/input_sources_utils/pdf_util.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import streamlit as st
|
3 |
+
import sys
|
4 |
+
from vectordb import add_image_to_index, add_pdf_to_index
|
5 |
+
|
6 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
7 |
+
|
8 |
+
def upload_pdf(clip_model, preprocess, text_embedding_model):
|
9 |
+
st.subheader("Add PDF to Database")
|
10 |
+
st.warning("Please note that the images in the PDF will also be extracted and added to the database.")
|
11 |
+
pdfs = st.file_uploader("Upload PDF", type=["pdf"], accept_multiple_files=True)
|
12 |
+
if pdfs:
|
13 |
+
st.info(f"Total {len(pdfs)} files selected.")
|
14 |
+
if st.button("Add PDF"):
|
15 |
+
for pdf in pdfs:
|
16 |
+
add_pdf_to_index(
|
17 |
+
pdf=pdf,
|
18 |
+
clip_model=clip_model,
|
19 |
+
preprocess=preprocess,
|
20 |
+
text_embedding_model=text_embedding_model,
|
21 |
+
)
|
22 |
+
st.success("PDF Added to Database")
|
data_upload/input_sources_utils/text_util.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import bs4
|
2 |
+
import os
|
3 |
+
from langchain_text_splitters import CharacterTextSplitter
|
4 |
+
import requests
|
5 |
+
import streamlit as st
|
6 |
+
import sys
|
7 |
+
from vectordb import add_image_to_index, add_pdf_to_index, update_vectordb
|
8 |
+
|
9 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
10 |
+
|
11 |
+
|
12 |
+
def process_text(text: str, text_embedding_model):
|
13 |
+
text_splitter = CharacterTextSplitter(
|
14 |
+
separator="\n",
|
15 |
+
chunk_size=1200,
|
16 |
+
chunk_overlap=200,
|
17 |
+
length_function=len,
|
18 |
+
is_separator_regex=False,
|
19 |
+
)
|
20 |
+
chunks = text_splitter.split_text(text)
|
21 |
+
text_embeddings = text_embedding_model.encode(chunks)
|
22 |
+
for chunk, embedding in zip(chunks, text_embeddings):
|
23 |
+
index = update_vectordb(index_path="text_index.index", embedding=embedding, text_content=chunk)
|
24 |
+
return index
|
data_upload/input_sources_utils/website_util.py
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import bs4
|
2 |
+
import os
|
3 |
+
import requests
|
4 |
+
import streamlit as st
|
5 |
+
import sys
|
6 |
+
from vectordb import add_image_to_index, add_pdf_to_index
|
7 |
+
from data_upload.input_sources_utils import text_util
|
8 |
+
|
9 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
10 |
+
|
11 |
+
|
12 |
+
def data_from_website(clip_model, preprocess, text_embedding_model):
|
13 |
+
st.title("Data from Website")
|
14 |
+
website_url = st.text_input("Enter Website URL")
|
15 |
+
if website_url:
|
16 |
+
st.write(f"URL: {website_url}")
|
17 |
+
if st.button("Extract and Add Data"):
|
18 |
+
response = requests.get(website_url)
|
19 |
+
if response.status_code == 200:
|
20 |
+
st.success("Data Extracted Successfully")
|
21 |
+
else:
|
22 |
+
st.error("Invalid URL")
|
23 |
+
|
24 |
+
soup = bs4.BeautifulSoup(response.content, features="lxml")
|
25 |
+
images = soup.find_all("img")
|
26 |
+
image_dict = []
|
27 |
+
if not images:
|
28 |
+
st.info("No Images Found!")
|
29 |
+
else:
|
30 |
+
st.info(f"Found {len(images)} Images")
|
31 |
+
progress_bar = st.progress(0, f"Extracting Images... | 0/{len(images)}")
|
32 |
+
cols = st.columns(5)
|
33 |
+
for count, image in enumerate(images):
|
34 |
+
try:
|
35 |
+
image_url = image["src"].replace("//", "https://")
|
36 |
+
response = requests.get(image_url)
|
37 |
+
if response.status_code == 200:
|
38 |
+
image_dict.append({"src": image_url, "content": response.content})
|
39 |
+
add_image_to_index(response.content, clip_model, preprocess)
|
40 |
+
len_image_dict = len(image_dict)
|
41 |
+
if len_image_dict <= 4:
|
42 |
+
with cols[len_image_dict - 1]:
|
43 |
+
st.image(image_url, caption=image_url, use_container_width=True)
|
44 |
+
elif len_image_dict == 5:
|
45 |
+
with cols[4]:
|
46 |
+
st.info(f"and more {len(images) - 4} images...")
|
47 |
+
except:
|
48 |
+
pass
|
49 |
+
progress_bar.progress((count + 1) / len(images), f"Extracting Images... | {count + 1}/{len(images)}")
|
50 |
+
progress_bar.empty()
|
51 |
+
|
52 |
+
main_content = soup.find('main')
|
53 |
+
sample_text = main_content.text.strip().replace(r'\n', '')
|
54 |
+
with st.spinner("Processing Text..."):
|
55 |
+
text_util.process_text(main_content.text, text_embedding_model)
|
56 |
+
st.success("Data Added to Database")
|
requirements.txt
CHANGED
@@ -6,6 +6,7 @@ annotated-types==0.7.0
|
|
6 |
anyio==4.7.0
|
7 |
async-timeout==4.0.3
|
8 |
attrs==24.3.0
|
|
|
9 |
blinker==1.9.0
|
10 |
cachetools==5.5.0
|
11 |
certifi==2024.12.14
|
@@ -47,6 +48,7 @@ langchain-core==0.3.28
|
|
47 |
langchain-experimental==0.3.4
|
48 |
langchain-text-splitters==0.3.4
|
49 |
langsmith==0.1.147
|
|
|
50 |
markdown-it-py==3.0.0
|
51 |
MarkupSafe==3.0.2
|
52 |
marshmallow==3.23.2
|
@@ -91,6 +93,7 @@ sentence-transformers==3.3.1
|
|
91 |
six==1.17.0
|
92 |
smmap==5.0.1
|
93 |
sniffio==1.3.1
|
|
|
94 |
SQLAlchemy==2.0.36
|
95 |
streamlit==1.41.1
|
96 |
streamlit-option-menu==0.4.0
|
|
|
6 |
anyio==4.7.0
|
7 |
async-timeout==4.0.3
|
8 |
attrs==24.3.0
|
9 |
+
beautifulsoup4==4.12.3
|
10 |
blinker==1.9.0
|
11 |
cachetools==5.5.0
|
12 |
certifi==2024.12.14
|
|
|
48 |
langchain-experimental==0.3.4
|
49 |
langchain-text-splitters==0.3.4
|
50 |
langsmith==0.1.147
|
51 |
+
lxml==5.1.0
|
52 |
markdown-it-py==3.0.0
|
53 |
MarkupSafe==3.0.2
|
54 |
marshmallow==3.23.2
|
|
|
93 |
six==1.17.0
|
94 |
smmap==5.0.1
|
95 |
sniffio==1.3.1
|
96 |
+
soupsieve==2.6
|
97 |
SQLAlchemy==2.0.36
|
98 |
streamlit==1.41.1
|
99 |
streamlit-option-menu==0.4.0
|
vectordb.py
CHANGED
@@ -57,7 +57,10 @@ def update_vectordb(index_path: str, embedding: torch.Tensor, image_path: str =
|
|
57 |
|
58 |
|
59 |
def add_image_to_index(image, model: clip.model.CLIP, preprocess):
|
60 |
-
|
|
|
|
|
|
|
61 |
image_name = image_name.replace(" ", "_")
|
62 |
os.makedirs("./images", exist_ok=True)
|
63 |
os.makedirs("./vectorstore", exist_ok=True)
|
@@ -65,7 +68,10 @@ def add_image_to_index(image, model: clip.model.CLIP, preprocess):
|
|
65 |
try:
|
66 |
f.write(image.read())
|
67 |
except:
|
68 |
-
|
|
|
|
|
|
|
69 |
f.write(image.read())
|
70 |
image = Image.open(f"./images/{image_name}")
|
71 |
with torch.no_grad():
|
@@ -106,7 +112,7 @@ def add_pdf_to_index(pdf, clip_model: clip.model.CLIP, preprocess, text_embeddin
|
|
106 |
pdf_texts.append(page_text)
|
107 |
if page_text != "" or page_text.strip() != "":
|
108 |
chunks = text_splitter.split_text(page_text)
|
109 |
-
text_embeddings
|
110 |
for i, chunk in enumerate(chunks):
|
111 |
update_vectordb(index_path="text_index.index", embedding=text_embeddings[i], text_content=chunk)
|
112 |
pdf_pages_data.append({f"page_number": page_num, "content": chunk, "type": "text"})
|
@@ -114,6 +120,16 @@ def add_pdf_to_index(pdf, clip_model: clip.model.CLIP, preprocess, text_embeddin
|
|
114 |
progress_bar.progress(percent_complete, f"Processing Page {page_num + 1}/{len(pdf_reader.pages)}")
|
115 |
return pdf_pages_data
|
116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
|
118 |
def search_image_index(text_input: str, index: faiss.IndexFlatL2, clip_model: clip.model.CLIP, k: int = 3):
|
119 |
with torch.no_grad():
|
|
|
57 |
|
58 |
|
59 |
def add_image_to_index(image, model: clip.model.CLIP, preprocess):
|
60 |
+
if hasattr(image, "name"):
|
61 |
+
image_name = image.name
|
62 |
+
else:
|
63 |
+
image_name = f"{time.time()}.png"
|
64 |
image_name = image_name.replace(" ", "_")
|
65 |
os.makedirs("./images", exist_ok=True)
|
66 |
os.makedirs("./vectorstore", exist_ok=True)
|
|
|
68 |
try:
|
69 |
f.write(image.read())
|
70 |
except:
|
71 |
+
if hasattr(image, "data"):
|
72 |
+
image = io.BytesIO(image.data)
|
73 |
+
else:
|
74 |
+
image = io.BytesIO(image)
|
75 |
f.write(image.read())
|
76 |
image = Image.open(f"./images/{image_name}")
|
77 |
with torch.no_grad():
|
|
|
112 |
pdf_texts.append(page_text)
|
113 |
if page_text != "" or page_text.strip() != "":
|
114 |
chunks = text_splitter.split_text(page_text)
|
115 |
+
text_embeddings = text_embedding_model.encode(chunks)
|
116 |
for i, chunk in enumerate(chunks):
|
117 |
update_vectordb(index_path="text_index.index", embedding=text_embeddings[i], text_content=chunk)
|
118 |
pdf_pages_data.append({f"page_number": page_num, "content": chunk, "type": "text"})
|
|
|
120 |
progress_bar.progress(percent_complete, f"Processing Page {page_num + 1}/{len(pdf_reader.pages)}")
|
121 |
return pdf_pages_data
|
122 |
|
123 |
+
def search_image_index_with_image(image_features, index: faiss.IndexFlatL2, clip_model: clip.model.CLIP, k: int = 3):
|
124 |
+
with torch.no_grad():
|
125 |
+
distances, indices = index.search(image_features.cpu().numpy(), k)
|
126 |
+
return indices
|
127 |
+
|
128 |
+
|
129 |
+
def search_text_index_with_image(text_embeddings, index: faiss.IndexFlatL2, text_embedding_model: SentenceTransformer, k: int = 3):
|
130 |
+
distances, indices = index.search(text_embeddings, k)
|
131 |
+
return indices
|
132 |
+
|
133 |
|
134 |
def search_image_index(text_input: str, index: faiss.IndexFlatL2, clip_model: clip.model.CLIP, k: int = 3):
|
135 |
with torch.no_grad():
|
weights/adapter_model.pt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:64a44152945986519fcaae3d8aa16d0000c4e2b7743992c5e5d35136c89e3dc1
|
3 |
+
size 7876804
|