Spaces:
Build error
Build error
Farid Karimli
commited on
Commit
•
638bffe
1
Parent(s):
9a544d2
LLaMa parser fix
Browse files- code/.chainlit/config.toml +19 -16
- code/main.py +2 -0
- code/modules/config/config.yml +2 -2
- code/modules/config/constants.py +6 -3
- code/modules/dataloader/data_loader.py +29 -31
- code/modules/dataloader/helpers.py +22 -2
code/.chainlit/config.toml
CHANGED
@@ -23,7 +23,7 @@ allow_origins = ["*"]
|
|
23 |
unsafe_allow_html = false
|
24 |
|
25 |
# Process and display mathematical expressions. This can clash with "$" characters in messages.
|
26 |
-
latex =
|
27 |
|
28 |
# Automatically tag threads with the current chat profile (if a chat profile is used)
|
29 |
auto_tag_thread = true
|
@@ -85,31 +85,34 @@ custom_meta_image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/
|
|
85 |
# custom_build = "./public/build"
|
86 |
|
87 |
[UI.theme]
|
88 |
-
default = "
|
89 |
#layout = "wide"
|
90 |
#font_family = "Inter, sans-serif"
|
91 |
# Override default MUI light theme. (Check theme.ts)
|
92 |
[UI.theme.light]
|
93 |
-
background = "#FAFAFA"
|
94 |
-
paper = "#FFFFFF"
|
95 |
|
96 |
[UI.theme.light.primary]
|
97 |
-
main = "#
|
98 |
-
dark = "#
|
99 |
-
light = "#
|
100 |
[UI.theme.light.text]
|
101 |
-
primary = "#212121"
|
102 |
-
secondary = "#616161"
|
|
|
103 |
# Override default MUI dark theme. (Check theme.ts)
|
104 |
[UI.theme.dark]
|
105 |
-
background = "#
|
106 |
-
paper = "#
|
107 |
|
108 |
[UI.theme.dark.primary]
|
109 |
-
main = "#
|
110 |
-
dark = "#
|
111 |
-
light = "#
|
112 |
-
|
|
|
|
|
113 |
|
114 |
[meta]
|
115 |
-
generated_by = "1.1.
|
|
|
23 |
unsafe_allow_html = false
|
24 |
|
25 |
# Process and display mathematical expressions. This can clash with "$" characters in messages.
|
26 |
+
latex = true
|
27 |
|
28 |
# Automatically tag threads with the current chat profile (if a chat profile is used)
|
29 |
auto_tag_thread = true
|
|
|
85 |
# custom_build = "./public/build"
|
86 |
|
87 |
[UI.theme]
|
88 |
+
default = "dark"
|
89 |
#layout = "wide"
|
90 |
#font_family = "Inter, sans-serif"
|
91 |
# Override default MUI light theme. (Check theme.ts)
|
92 |
[UI.theme.light]
|
93 |
+
#background = "#FAFAFA"
|
94 |
+
#paper = "#FFFFFF"
|
95 |
|
96 |
[UI.theme.light.primary]
|
97 |
+
#main = "#F80061"
|
98 |
+
#dark = "#980039"
|
99 |
+
#light = "#FFE7EB"
|
100 |
[UI.theme.light.text]
|
101 |
+
#primary = "#212121"
|
102 |
+
#secondary = "#616161"
|
103 |
+
|
104 |
# Override default MUI dark theme. (Check theme.ts)
|
105 |
[UI.theme.dark]
|
106 |
+
#background = "#FAFAFA"
|
107 |
+
#paper = "#FFFFFF"
|
108 |
|
109 |
[UI.theme.dark.primary]
|
110 |
+
#main = "#F80061"
|
111 |
+
#dark = "#980039"
|
112 |
+
#light = "#FFE7EB"
|
113 |
+
[UI.theme.dark.text]
|
114 |
+
#primary = "#EEEEEE"
|
115 |
+
#secondary = "#BDBDBD"
|
116 |
|
117 |
[meta]
|
118 |
+
generated_by = "1.1.304"
|
code/main.py
CHANGED
@@ -173,4 +173,6 @@ async def main(message):
|
|
173 |
answer_with_sources, source_elements, sources_dict = get_sources(res, answer)
|
174 |
processor._process(message.content, answer, sources_dict)
|
175 |
|
|
|
|
|
176 |
await cl.Message(content=answer_with_sources, elements=source_elements).send()
|
|
|
173 |
answer_with_sources, source_elements, sources_dict = get_sources(res, answer)
|
174 |
processor._process(message.content, answer, sources_dict)
|
175 |
|
176 |
+
answer_with_sources = answer_with_sources.replace("$$", "$")
|
177 |
+
|
178 |
await cl.Message(content=answer_with_sources, elements=source_elements).send()
|
code/modules/config/config.yml
CHANGED
@@ -7,7 +7,7 @@ vectorstore:
|
|
7 |
data_path: '../storage/data' # str
|
8 |
url_file_path: '../storage/data/urls.txt' # str
|
9 |
expand_urls: True # bool
|
10 |
-
db_option : '
|
11 |
db_path : '../vectorstores' # str
|
12 |
model : 'sentence-transformers/all-MiniLM-L6-v2' # str [sentence-transformers/all-MiniLM-L6-v2, text-embedding-ada-002']
|
13 |
search_top_k : 3 # int
|
@@ -32,7 +32,7 @@ llm_params:
|
|
32 |
local_llm_params:
|
33 |
model: 'tiny-llama'
|
34 |
temperature: 0.7
|
35 |
-
pdf_reader: 'llama' # str [llama, pymupdf]
|
36 |
|
37 |
chat_logging:
|
38 |
log_chat: False # bool
|
|
|
7 |
data_path: '../storage/data' # str
|
8 |
url_file_path: '../storage/data/urls.txt' # str
|
9 |
expand_urls: True # bool
|
10 |
+
db_option : 'RAGatouille' # str [FAISS, Chroma, RAGatouille, RAPTOR]
|
11 |
db_path : '../vectorstores' # str
|
12 |
model : 'sentence-transformers/all-MiniLM-L6-v2' # str [sentence-transformers/all-MiniLM-L6-v2, text-embedding-ada-002']
|
13 |
search_top_k : 3 # int
|
|
|
32 |
local_llm_params:
|
33 |
model: 'tiny-llama'
|
34 |
temperature: 0.7
|
35 |
+
pdf_reader: 'llama' # str [llama, pymupdf, gpt]
|
36 |
|
37 |
chat_logging:
|
38 |
log_chat: False # bool
|
code/modules/config/constants.py
CHANGED
@@ -15,7 +15,9 @@ opening_message = f"Hey, What Can I Help You With?\n\nYou can me ask me question
|
|
15 |
# Prompt Templates
|
16 |
|
17 |
openai_prompt_template = """Use the following pieces of information to answer the user's question.
|
18 |
-
You are an intelligent chatbot designed to help students with questions regarding the course.
|
|
|
|
|
19 |
If you don't know the answer, just say that you don't know.
|
20 |
|
21 |
Context: {context}
|
@@ -26,8 +28,9 @@ Helpful answer:
|
|
26 |
"""
|
27 |
|
28 |
openai_prompt_template_with_history = """Use the following pieces of information to answer the user's question.
|
29 |
-
You are an intelligent chatbot designed to help students with questions regarding the course.
|
30 |
-
|
|
|
31 |
If you don't know the answer, just say that you don't know, don't try to make up an answer.
|
32 |
|
33 |
Use the history to answer the question if you can.
|
|
|
15 |
# Prompt Templates
|
16 |
|
17 |
openai_prompt_template = """Use the following pieces of information to answer the user's question.
|
18 |
+
You are an intelligent chatbot designed to help students with questions regarding the course.
|
19 |
+
Render math equations in LaTeX format between $ or $$ signs, stick to the parameter and variable icons found in your context.
|
20 |
+
Be sure to explain the parameters and variables in the equations.
|
21 |
If you don't know the answer, just say that you don't know.
|
22 |
|
23 |
Context: {context}
|
|
|
28 |
"""
|
29 |
|
30 |
openai_prompt_template_with_history = """Use the following pieces of information to answer the user's question.
|
31 |
+
You are an intelligent chatbot designed to help students with questions regarding the course.
|
32 |
+
Render math equations in LaTeX format between $ or $$ signs, stick to the parameter and variable icons found in your context.
|
33 |
+
Be sure to explain the parameters and variables in the equations.
|
34 |
If you don't know the answer, just say that you don't know, don't try to make up an answer.
|
35 |
|
36 |
Use the history to answer the question if you can.
|
code/modules/dataloader/data_loader.py
CHANGED
@@ -27,12 +27,10 @@ import tempfile
|
|
27 |
import PyPDF2
|
28 |
|
29 |
try:
|
30 |
-
from modules.dataloader.helpers import get_metadata
|
31 |
from modules.config.constants import OPENAI_API_KEY, LLAMA_CLOUD_API_KEY
|
32 |
-
|
33 |
-
|
34 |
except:
|
35 |
-
from dataloader.helpers import get_metadata
|
36 |
from config.constants import OPENAI_API_KEY, LLAMA_CLOUD_API_KEY
|
37 |
|
38 |
logger = logging.getLogger(__name__)
|
@@ -51,6 +49,7 @@ class PDFReader:
|
|
51 |
|
52 |
class LlamaParser:
|
53 |
def __init__(self):
|
|
|
54 |
self.GPT_API_KEY = OPENAI_API_KEY
|
55 |
self.LLAMA_CLOUD_API_KEY = LLAMA_CLOUD_API_KEY
|
56 |
self.parse_url = "https://api.cloud.llamaindex.ai/api/parsing/upload"
|
@@ -65,16 +64,30 @@ class LlamaParser:
|
|
65 |
language="en",
|
66 |
gpt4o_mode=False,
|
67 |
# gpt4o_api_key=OPENAI_API_KEY,
|
68 |
-
parsing_instruction="The provided documents are PDFs of lecture slides of deep learning material. They contain LaTeX equations, images, and text. The goal is to extract the text, images and equations from the slides
|
69 |
)
|
70 |
|
71 |
def parse(self, pdf_path):
|
72 |
pdf_name = os.path.basename(pdf_path)
|
73 |
|
|
|
|
|
|
|
|
|
74 |
documents = self.parser.load_data(pdf_path)
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
-
os.remove(pdf_path) # cleanup, just in case
|
78 |
return documents
|
79 |
|
80 |
def make_request(self, pdf_url):
|
@@ -186,18 +199,6 @@ class FileReader:
|
|
186 |
text += page.extract_text()
|
187 |
return text
|
188 |
|
189 |
-
@staticmethod
|
190 |
-
def download_pdf_from_url(pdf_url):
|
191 |
-
response = requests.get(pdf_url)
|
192 |
-
if response.status_code == 200:
|
193 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_file:
|
194 |
-
temp_file.write(response.content)
|
195 |
-
temp_file_path = temp_file.name
|
196 |
-
return temp_file_path
|
197 |
-
else:
|
198 |
-
self.logger.error(f"Failed to download PDF from URL: {pdf_url}")
|
199 |
-
return None
|
200 |
-
|
201 |
def read_pdf(self, temp_file_path: str):
|
202 |
if self.kind == "llama":
|
203 |
documents = self.pdf_reader.parse(temp_file_path) # asyncio.run(self.pdf_reader.parse(temp_file_path)) if using async
|
@@ -383,22 +384,17 @@ class ChunkProcessor:
|
|
383 |
)
|
384 |
self.document_chunks_full.extend(document_chunks)
|
385 |
|
|
|
386 |
self.document_data[file_path] = file_data
|
387 |
self.document_metadata[file_path] = file_metadata
|
388 |
|
389 |
def process_file(self, file_path, file_index, file_reader, addl_metadata):
|
390 |
file_name = os.path.basename(file_path)
|
391 |
-
storage_dir = os.path.join(os.getcwd(), self.config["vectorstore"]["data_path"])
|
392 |
-
local_path = os.path.join(storage_dir, file_name)
|
393 |
-
|
394 |
-
if not os.path.exists(local_path):
|
395 |
-
local_path = FileReader.download_pdf_from_url(pdf_url=file_path)
|
396 |
|
397 |
if file_name in self.document_data:
|
398 |
return
|
399 |
|
400 |
-
file_type = file_name.split(".")[-1]
|
401 |
-
self.logger.info(f"Reading file {file_index + 1}: {local_path}")
|
402 |
|
403 |
read_methods = {
|
404 |
"pdf": file_reader.read_pdf,
|
@@ -412,9 +408,10 @@ class ChunkProcessor:
|
|
412 |
return
|
413 |
|
414 |
try:
|
415 |
-
documents = read_methods[file_type](
|
|
|
416 |
self.process_documents(
|
417 |
-
documents,
|
418 |
)
|
419 |
except Exception as e:
|
420 |
self.logger.error(f"Error processing file {file_name}: {str(e)}")
|
@@ -500,10 +497,11 @@ if __name__ == "__main__":
|
|
500 |
data_loader = DataLoader(config, logger=logger)
|
501 |
document_chunks, document_names, documents, document_metadata = (
|
502 |
data_loader.get_chunks(
|
503 |
-
|
504 |
-
[
|
505 |
)
|
506 |
)
|
507 |
|
508 |
-
print(document_names)
|
509 |
print(len(document_chunks))
|
|
|
|
27 |
import PyPDF2
|
28 |
|
29 |
try:
|
30 |
+
from modules.dataloader.helpers import get_metadata, download_pdf_from_url
|
31 |
from modules.config.constants import OPENAI_API_KEY, LLAMA_CLOUD_API_KEY
|
|
|
|
|
32 |
except:
|
33 |
+
from dataloader.helpers import get_metadata, download_pdf_from_url
|
34 |
from config.constants import OPENAI_API_KEY, LLAMA_CLOUD_API_KEY
|
35 |
|
36 |
logger = logging.getLogger(__name__)
|
|
|
49 |
|
50 |
class LlamaParser:
|
51 |
def __init__(self):
|
52 |
+
print("Initializing LlamaParser")
|
53 |
self.GPT_API_KEY = OPENAI_API_KEY
|
54 |
self.LLAMA_CLOUD_API_KEY = LLAMA_CLOUD_API_KEY
|
55 |
self.parse_url = "https://api.cloud.llamaindex.ai/api/parsing/upload"
|
|
|
64 |
language="en",
|
65 |
gpt4o_mode=False,
|
66 |
# gpt4o_api_key=OPENAI_API_KEY,
|
67 |
+
parsing_instruction="The provided documents are PDFs of lecture slides of deep learning material. They contain LaTeX equations, images, and text. The goal is to extract the text, images and equations from the slides. The markdown should be clean and easy to read, and any math equation should be converted to LaTeX format, between $ signs. For images, if you can, give a description and a source."
|
68 |
)
|
69 |
|
70 |
def parse(self, pdf_path):
|
71 |
pdf_name = os.path.basename(pdf_path)
|
72 |
|
73 |
+
if not os.path.exists(pdf_path):
|
74 |
+
logger.warning(f"File {pdf_name} does not exist locally, installing temporarily...")
|
75 |
+
pdf_path = download_pdf_from_url(pdf_path)
|
76 |
+
|
77 |
documents = self.parser.load_data(pdf_path)
|
78 |
+
document = [document.to_langchain_format() for document in documents][0]
|
79 |
+
|
80 |
+
content = document.page_content
|
81 |
+
pages = content.split("\n---\n")
|
82 |
+
pages = [page.strip() for page in pages]
|
83 |
+
|
84 |
+
documents = [
|
85 |
+
Document(
|
86 |
+
page_content=page,
|
87 |
+
metadata={"source": pdf_path, "page": i}
|
88 |
+
) for i, page in enumerate(pages)
|
89 |
+
]
|
90 |
|
|
|
91 |
return documents
|
92 |
|
93 |
def make_request(self, pdf_url):
|
|
|
199 |
text += page.extract_text()
|
200 |
return text
|
201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
def read_pdf(self, temp_file_path: str):
|
203 |
if self.kind == "llama":
|
204 |
documents = self.pdf_reader.parse(temp_file_path) # asyncio.run(self.pdf_reader.parse(temp_file_path)) if using async
|
|
|
384 |
)
|
385 |
self.document_chunks_full.extend(document_chunks)
|
386 |
|
387 |
+
print(f"Processed {file_path}. File_data: {file_data}")
|
388 |
self.document_data[file_path] = file_data
|
389 |
self.document_metadata[file_path] = file_metadata
|
390 |
|
391 |
def process_file(self, file_path, file_index, file_reader, addl_metadata):
|
392 |
file_name = os.path.basename(file_path)
|
|
|
|
|
|
|
|
|
|
|
393 |
|
394 |
if file_name in self.document_data:
|
395 |
return
|
396 |
|
397 |
+
file_type = file_name.split(".")[-1]
|
|
|
398 |
|
399 |
read_methods = {
|
400 |
"pdf": file_reader.read_pdf,
|
|
|
408 |
return
|
409 |
|
410 |
try:
|
411 |
+
documents = read_methods[file_type](file_path)
|
412 |
+
|
413 |
self.process_documents(
|
414 |
+
documents, file_path, file_type, "file", addl_metadata
|
415 |
)
|
416 |
except Exception as e:
|
417 |
self.logger.error(f"Error processing file {file_name}: {str(e)}")
|
|
|
497 |
data_loader = DataLoader(config, logger=logger)
|
498 |
document_chunks, document_names, documents, document_metadata = (
|
499 |
data_loader.get_chunks(
|
500 |
+
["https://dl4ds.github.io/sp2024/static_files/lectures/05_loss_functions_v2.pdf"],
|
501 |
+
[],
|
502 |
)
|
503 |
)
|
504 |
|
505 |
+
print(document_names[:5])
|
506 |
print(len(document_chunks))
|
507 |
+
|
code/modules/dataloader/helpers.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
import requests
|
2 |
from bs4 import BeautifulSoup
|
3 |
-
from
|
4 |
-
|
5 |
|
6 |
def get_urls_from_file(file_path: str):
|
7 |
"""
|
@@ -106,3 +106,23 @@ def get_metadata(lectures_url, schedule_url):
|
|
106 |
continue
|
107 |
|
108 |
return lecture_metadata
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import requests
|
2 |
from bs4 import BeautifulSoup
|
3 |
+
from urllib.parse import urlparse
|
4 |
+
import tempfile
|
5 |
|
6 |
def get_urls_from_file(file_path: str):
|
7 |
"""
|
|
|
106 |
continue
|
107 |
|
108 |
return lecture_metadata
|
109 |
+
|
110 |
+
|
111 |
+
def download_pdf_from_url(pdf_url):
|
112 |
+
"""
|
113 |
+
Function to temporarily download a PDF file from a URL and return the local file path.
|
114 |
+
|
115 |
+
Args:
|
116 |
+
pdf_url (str): The URL of the PDF file to download.
|
117 |
+
|
118 |
+
Returns:
|
119 |
+
str: The local file path of the downloaded PDF file.
|
120 |
+
"""
|
121 |
+
response = requests.get(pdf_url)
|
122 |
+
if response.status_code == 200:
|
123 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_file:
|
124 |
+
temp_file.write(response.content)
|
125 |
+
temp_file_path = temp_file.name
|
126 |
+
return temp_file_path
|
127 |
+
else:
|
128 |
+
return None
|