BGarida commited on
Commit
50356ed
·
1 Parent(s): 392d2e2

Deploying PDF Version v12

Browse files
Files changed (1) hide show
  1. app.py +105 -108
app.py CHANGED
@@ -1,16 +1,6 @@
1
  import os
2
  import tempfile
3
-
4
- os.environ["CHAINLIT_CONFIG_DIR"] = tempfile.gettempdir()
5
-
6
  import logging
7
-
8
- logging.basicConfig(level=logging.DEBUG)
9
- logger = logging.getLogger(__name__)
10
-
11
- logger.debug("Starting application")
12
-
13
-
14
  from typing import List
15
 
16
  from langchain.embeddings import OpenAIEmbeddings
@@ -21,148 +11,155 @@ from langchain.document_loaders import PyPDFLoader
21
  from langchain.chat_models import ChatOpenAI
22
  from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
23
  from langchain.schema import Document
24
- from langchain.memory import ChatMessageHistory, ConversationBufferMemory
25
 
26
  import chainlit as cl
27
  from chainlit.types import AskFileResponse
28
 
29
- text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
 
 
 
 
 
30
 
31
- system_template = """Use the following pieces of context to answer the users question.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  If you don't know the answer, just say that you don't know, don't try to make up an answer.
33
  ALWAYS return a "SOURCES" part in your answer.
34
  The "SOURCES" part should be a reference to the source of the document from which you got your answer.
35
 
36
- And if the user greets with greetings like Hi, hello, How are you, etc reply accordingly as well.
37
 
38
  Example of your response should be:
39
 
40
  The answer is foo
41
  SOURCES: xyz
42
 
43
-
44
  Begin!
45
  ----------------
46
  {summaries}"""
 
 
47
  messages = [
48
  SystemMessagePromptTemplate.from_template(system_template),
49
- HumanMessagePromptTemplate.from_template("{question}"),
50
  ]
51
  prompt = ChatPromptTemplate.from_messages(messages)
52
- chain_type_kwargs = {"prompt": prompt}
53
-
54
-
55
- def process_file(file: AskFileResponse):
56
- import tempfile
57
 
58
- with tempfile.NamedTemporaryFile(mode="w", delete=False) as tempfile:
59
- with open(tempfile.name, "wb") as f:
60
- f.write(file.content)
61
-
62
- pypdf_loader = PyPDFLoader(tempfile.name)
63
- texts = pypdf_loader.load_and_split()
64
- texts = [text.page_content for text in texts]
65
- return texts
66
 
 
 
 
 
67
 
68
  @cl.on_chat_start
69
  async def start():
70
- await cl.Message("Welcome! Chat session started. You can now ask questions about the uploaded PDF.").send()
 
71
 
72
- files = None
 
 
 
 
 
73
 
74
- # Wait for the user to upload a file
75
- while files == None:
76
- files = await cl.AskFileMessage(
77
- content="Please upload a PDF file to begin!",
78
- accept=["application/pdf"],
79
- max_size_mb=20,
80
- timeout=180,
81
- ).send()
82
 
83
  file = files[0]
84
-
85
- msg = cl.Message(
86
- content=f"Processing `{file.name}`...", disable_human_feedback=True
87
- )
88
  await msg.send()
89
 
90
- # load the file
91
- texts = process_file(file)
92
-
93
- print(texts[0])
94
-
95
- # Create a metadata for each chunk
96
- metadatas = [{"source": f"{i}-pl"} for i in range(len(texts))]
97
-
98
- # Create a Chroma vector store
99
- embeddings = OpenAIEmbeddings()
100
- docsearch = await cl.make_async(Chroma.from_texts)(
101
- texts, embeddings, metadatas=metadatas
102
- )
103
-
104
- message_history = ChatMessageHistory()
105
-
106
- memory = ConversationBufferMemory(
107
- memory_key="chat_history",
108
- output_key="answer",
109
- chat_memory=message_history,
110
- return_messages=True,
111
- )
112
-
113
- # Create a chain that uses the Chroma vector store
114
- chain = ConversationalRetrievalChain.from_llm(
115
- ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0, streaming=True),
116
- chain_type="stuff",
117
- retriever=docsearch.as_retriever(),
118
- memory=memory,
119
- return_source_documents=True,
120
- )
121
-
122
- # Let the user know that the system is ready
123
- msg.content = f"Processing `{file.name}` done. You can now ask questions!"
124
- await msg.update()
125
-
126
- cl.user_session.set("chain", chain)
127
 
128
- logger.debug("Defining main function")
 
 
 
129
 
130
  @cl.on_message
131
  async def main(message: cl.Message):
132
- debug_info = f"""
133
- Debug Info:
134
- Message type: {type(message)}
135
- Message: {message}
136
- Message content: {message.content}
137
- Message dir: {dir(message)}
138
- """
139
- print(debug_info)
140
-
141
  try:
142
- chain = cl.user_session.get("chain") # type: ConversationalRetrievalChain
143
  cb = cl.AsyncLangchainCallbackHandler()
144
 
145
  res = await chain.acall(message.content, callbacks=[cb])
146
  answer = res["answer"]
147
- source_documents = res["source_documents"] # type: List[Document]
 
 
 
 
 
148
 
149
- text_elements = [] # type: List[cl.Text]
150
- if source_documents:
151
- for source_idx, source_doc in enumerate(source_documents):
152
- source_name = f"source_{source_idx}"
153
- text_elements.append(
154
- cl.Text(content=source_doc.page_content, name=source_name)
155
- )
156
-
157
- source_names = [text_el.name for text_el in text_elements]
158
- if source_names:
159
- answer += f"\nSources: {', '.join(source_names)}"
160
- else:
161
- answer += "\nNo sources found"
162
 
163
  await cl.Message(content=answer, elements=text_elements).send()
164
 
165
  except Exception as e:
166
- error_message = f"An error occurred: {str(e)}\n\n{debug_info}"
167
- print(error_message)
168
- await cl.Message(content=error_message).send()
 
 
 
 
 
1
  import os
2
  import tempfile
 
 
 
3
  import logging
 
 
 
 
 
 
 
4
  from typing import List
5
 
6
  from langchain.embeddings import OpenAIEmbeddings
 
11
  from langchain.chat_models import ChatOpenAI
12
  from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
13
  from langchain.schema import Document
14
+ from langchain.memory import ConversationBufferMemory
15
 
16
  import chainlit as cl
17
  from chainlit.types import AskFileResponse
18
 
19
+ # Configure logging
20
+ logging.basicConfig(level=logging.INFO)
21
+ logger = logging.getLogger(__name__)
22
+
23
+ # Set Chainlit config directory
24
+ os.environ["CHAINLIT_CONFIG_DIR"] = tempfile.gettempdir()
25
 
26
+ # App configuration
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" # Updated to use the most capable embedding model
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.
47
  The "SOURCES" part should be a reference to the source of the document from which you got your answer.
48
 
49
+ If the user greets with phrases like Hi, hello, How are you, etc., reply accordingly as well.
50
 
51
  Example of your response should be:
52
 
53
  The answer is foo
54
  SOURCES: xyz
55
 
 
56
  Begin!
57
  ----------------
58
  {summaries}"""
59
+
60
+ # Create prompt template
61
  messages = [
62
  SystemMessagePromptTemplate.from_template(system_template),
63
+ HumanMessagePromptTemplate.from_template("{question}")
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,
88
+ ).send()
89
 
90
+ if not files:
91
+ await cl.Message("No file uploaded. Please try again.").send()
92
+ return
 
 
 
 
 
93
 
94
  file = files[0]
95
+ msg = cl.Message(content=f"Processing `{file.name}`...", disable_human_feedback=True)
 
 
 
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",
107
+ output_key="answer",
108
+ return_messages=True,
109
+ )
110
+
111
+ chain = ConversationalRetrievalChain.from_llm(
112
+ ChatOpenAI(
113
+ model_name=APP_CONFIG["model_name"],
114
+ temperature=APP_CONFIG["temperature"],
115
+ max_tokens=APP_CONFIG["max_output_tokens"],
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:
130
+ error_msg = f"An error occurred while processing the file: {str(e)}"
131
+ logger.error(error_msg)
132
+ await cl.Message(content=error_msg).send()
133
 
134
  @cl.on_message
135
  async def main(message: cl.Message):
136
+ """Handle user messages and generate responses."""
 
 
 
 
 
 
 
 
137
  try:
138
+ chain = cl.user_session.get("chain")
139
  cb = cl.AsyncLangchainCallbackHandler()
140
 
141
  res = await chain.acall(message.content, callbacks=[cb])
142
  answer = res["answer"]
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]
151
+ if source_names:
152
+ answer += f"\nSources: {', '.join(source_names)}"
153
+ else:
154
+ answer += "\nNo sources found"
 
 
 
 
 
 
 
 
155
 
156
  await cl.Message(content=answer, elements=text_elements).send()
157
 
158
  except Exception as e:
159
+ error_msg = f"An error occurred: {str(e)}"
160
+ logger.error(error_msg)
161
+ await cl.Message(content=error_msg).send()
162
+
163
+ if __name__ == "__main__":
164
+ logger.info(f"Starting Chainlit application with model: {APP_CONFIG['model_name']} and embedding model: {APP_CONFIG['embedding_model']}")
165
+ cl.run()