BGarida commited on
Commit
f62f25d
·
1 Parent(s): 3c8c9ec

Deploying PDF Version v14

Browse files
Files changed (1) hide show
  1. app.py +38 -22
app.py CHANGED
@@ -1,8 +1,7 @@
1
  import os
2
  import tempfile
3
  import logging
4
- from typing import List
5
-
6
  from langchain.embeddings import OpenAIEmbeddings
7
  from langchain.text_splitter import RecursiveCharacterTextSplitter
8
  from langchain.vectorstores import Chroma
@@ -27,20 +26,22 @@ os.environ["CHAINLIT_CONFIG_DIR"] = tempfile.gettempdir()
27
  APP_CONFIG = {
28
  "model_name": "gpt-4o",
29
  "temperature": 0,
30
- "chunk_size": 4000,
31
  "chunk_overlap": 200,
32
- "max_file_size_mb": 50,
33
  "max_output_tokens": 4096,
34
  "embedding_model": "text-embedding-3-large"
35
  }
36
 
37
- # Initialize text splitter
38
  text_splitter = RecursiveCharacterTextSplitter(
39
- chunk_size=APP_CONFIG["chunk_size"],
40
- chunk_overlap=APP_CONFIG["chunk_overlap"]
 
 
41
  )
42
 
43
- # System template
44
  system_template = """You are GPT-4o, an advanced AI model with multimodal capabilities and high intelligence. Use the following pieces of context to answer the user's question.
45
  If you don't know the answer, just say that you don't know, don't try to make up an answer.
46
  ALWAYS return a "SOURCES" part in your answer.
@@ -64,24 +65,37 @@ messages = [
64
  ]
65
  prompt = ChatPromptTemplate.from_messages(messages)
66
 
67
- def process_file(file: AskFileResponse) -> List[str]:
68
- """Process uploaded PDF file and return list of text chunks."""
69
  with tempfile.NamedTemporaryFile(mode="wb", delete=False, suffix=".pdf") as temp_file:
70
  temp_file.write(file.content)
71
  temp_file_path = temp_file.name
72
 
73
  loader = PyPDFLoader(temp_file_path)
74
  pages = loader.load_and_split()
75
- texts = text_splitter.split_documents(pages)
76
- return [text.page_content for text in texts]
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  @cl.on_chat_start
79
  async def start():
80
  """Initialize chat session and process uploaded PDF."""
81
- await cl.Message(f"Welcome! Chat session started using {APP_CONFIG['model_name']} for text generation and {APP_CONFIG['embedding_model']} for embeddings. This combination provides state-of-the-art performance for both English and non-English tasks. You can now ask questions about the uploaded PDF.").send()
82
 
83
  files = await cl.AskFileMessage(
84
- content="Please upload a PDF file to begin!",
85
  accept=["application/pdf"],
86
  max_size_mb=APP_CONFIG["max_file_size_mb"],
87
  timeout=180,
@@ -96,11 +110,13 @@ async def start():
96
  await msg.send()
97
 
98
  try:
99
- texts = process_file(file)
100
- metadatas = [{"source": f"{i}-pl"} for i in range(len(texts))]
101
-
102
  embeddings = OpenAIEmbeddings(model=APP_CONFIG["embedding_model"])
103
- docsearch = await cl.make_async(Chroma.from_texts)(texts, embeddings, metadatas=metadatas)
 
 
 
104
 
105
  memory = ConversationBufferMemory(
106
  memory_key="chat_history",
@@ -116,14 +132,14 @@ async def start():
116
  streaming=True
117
  ),
118
  chain_type="stuff",
119
- retriever=docsearch.as_retriever(),
120
  memory=memory,
121
  return_source_documents=True,
122
  combine_docs_chain_kwargs={"prompt": prompt}
123
  )
124
 
125
  cl.user_session.set("chain", chain)
126
- msg.content = f"Processing `{file.name}` done. You can now ask questions!"
127
  await msg.update()
128
 
129
  except Exception as e:
@@ -143,8 +159,8 @@ async def main(message: cl.Message):
143
  source_documents = res["source_documents"]
144
 
145
  text_elements = []
146
- for source_idx, source_doc in enumerate(source_documents):
147
- source_name = f"source_{source_idx}"
148
  text_elements.append(cl.Text(content=source_doc.page_content, name=source_name))
149
 
150
  source_names = [text_el.name for text_el in text_elements]
 
1
  import os
2
  import tempfile
3
  import logging
4
+ from typing import List, Dict
 
5
  from langchain.embeddings import OpenAIEmbeddings
6
  from langchain.text_splitter import RecursiveCharacterTextSplitter
7
  from langchain.vectorstores import Chroma
 
26
  APP_CONFIG = {
27
  "model_name": "gpt-4o",
28
  "temperature": 0,
29
+ "chunk_size": 2000, # Increased for book-length content
30
  "chunk_overlap": 200,
31
+ "max_file_size_mb": 100, # Increased for larger books
32
  "max_output_tokens": 4096,
33
  "embedding_model": "text-embedding-3-large"
34
  }
35
 
36
+ # Initialize text splitter with more sophisticated settings
37
  text_splitter = RecursiveCharacterTextSplitter(
38
+ chunk_size=APP_CONFIG["chunk_size"],
39
+ chunk_overlap=APP_CONFIG["chunk_overlap"],
40
+ length_function=len,
41
+ separators=["\n\n", "\n", " ", ""] # Prioritize splitting on paragraph breaks
42
  )
43
 
44
+ # System template (unchanged)
45
  system_template = """You are GPT-4o, an advanced AI model with multimodal capabilities and high intelligence. Use the following pieces of context to answer the user's question.
46
  If you don't know the answer, just say that you don't know, don't try to make up an answer.
47
  ALWAYS return a "SOURCES" part in your answer.
 
65
  ]
66
  prompt = ChatPromptTemplate.from_messages(messages)
67
 
68
+ def process_file(file: AskFileResponse) -> List[Dict[str, str]]:
69
+ """Process uploaded PDF file and return list of text chunks with metadata."""
70
  with tempfile.NamedTemporaryFile(mode="wb", delete=False, suffix=".pdf") as temp_file:
71
  temp_file.write(file.content)
72
  temp_file_path = temp_file.name
73
 
74
  loader = PyPDFLoader(temp_file_path)
75
  pages = loader.load_and_split()
76
+
77
+ chunks_with_metadata = []
78
+ for i, page in enumerate(pages):
79
+ chunks = text_splitter.split_text(page.page_content)
80
+ for j, chunk in enumerate(chunks):
81
+ chunks_with_metadata.append({
82
+ "content": chunk,
83
+ "metadata": {
84
+ "page": i + 1,
85
+ "chunk": j + 1,
86
+ "source": f"page_{i+1}_chunk_{j+1}"
87
+ }
88
+ })
89
+
90
+ return chunks_with_metadata
91
 
92
  @cl.on_chat_start
93
  async def start():
94
  """Initialize chat session and process uploaded PDF."""
95
+ await cl.Message(f"Welcome! Chat session started using {APP_CONFIG['model_name']} for text generation and {APP_CONFIG['embedding_model']} for embeddings. This combination is optimized for processing and querying book-length content. You can now upload a PDF of a book to begin!").send()
96
 
97
  files = await cl.AskFileMessage(
98
+ content="Please upload a PDF file of a book to begin!",
99
  accept=["application/pdf"],
100
  max_size_mb=APP_CONFIG["max_file_size_mb"],
101
  timeout=180,
 
110
  await msg.send()
111
 
112
  try:
113
+ chunks_with_metadata = process_file(file)
114
+
 
115
  embeddings = OpenAIEmbeddings(model=APP_CONFIG["embedding_model"])
116
+ docsearch = await cl.make_async(Chroma.from_documents)(
117
+ [Document(page_content=chunk["content"], metadata=chunk["metadata"]) for chunk in chunks_with_metadata],
118
+ embeddings
119
+ )
120
 
121
  memory = ConversationBufferMemory(
122
  memory_key="chat_history",
 
132
  streaming=True
133
  ),
134
  chain_type="stuff",
135
+ retriever=docsearch.as_retriever(search_kwargs={"k": 3}), # Retrieve top 3 chunks
136
  memory=memory,
137
  return_source_documents=True,
138
  combine_docs_chain_kwargs={"prompt": prompt}
139
  )
140
 
141
  cl.user_session.set("chain", chain)
142
+ msg.content = f"Processing `{file.name}` done. You can now ask questions about the book!"
143
  await msg.update()
144
 
145
  except Exception as e:
 
159
  source_documents = res["source_documents"]
160
 
161
  text_elements = []
162
+ for source_doc in source_documents:
163
+ source_name = f"Page {source_doc.metadata['page']}, Chunk {source_doc.metadata['chunk']}"
164
  text_elements.append(cl.Text(content=source_doc.page_content, name=source_name))
165
 
166
  source_names = [text_el.name for text_el in text_elements]