wylum commited on
Commit
2156d4e
·
verified ·
1 Parent(s): 9c9f731

Delete app-single.py

Browse files
Files changed (1) hide show
  1. app-single.py +0 -438
app-single.py DELETED
@@ -1,438 +0,0 @@
1
- """
2
- This code uses the PyMuPDF package.
3
-
4
- PyMuPDF is AGPL licensed, please refer to:
5
- https://pymupdf.readthedocs.io/en/latest/about.html#license-and-copyright
6
- """
7
-
8
- """
9
- Code below is based on an implementation by Sunil Kumar Dash:
10
-
11
- MIT License
12
-
13
- Copyright (c) 2023 Sunil Kumar Dash
14
-
15
- Permission is hereby granted, free of charge, to any person obtaining a copy
16
- of this software and associated documentation files (the "Software"), to deal
17
- in the Software without restriction, including without limitation the rights
18
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
- copies of the Software, and to permit persons to whom the Software is
20
- furnished to do so, subject to the following conditions:
21
-
22
- The above copyright notice and this permission notice shall be included in all
23
- copies or substantial portions of the Software.
24
-
25
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
- SOFTWARE.
32
- """
33
-
34
- from huggingface_hub import InferenceClient
35
- from langchain_openai import AzureOpenAIEmbeddings
36
- #from langchain_community.chat_models import AzureChatOpenAI
37
- from langchain_openai import AzureChatOpenAI
38
-
39
-
40
-
41
-
42
-
43
- from typing import Any
44
- import gradio as gr
45
- from langchain_openai import OpenAIEmbeddings
46
- from langchain_community.vectorstores import Chroma
47
- import chromadb
48
- #to handle the tenant issue
49
- chromadb.api.client.SharedSystemClient.clear_system_cache()
50
-
51
- from langchain.chains import ConversationalRetrievalChain
52
- from langchain_openai import ChatOpenAI
53
-
54
- from langchain_community.document_loaders import PyMuPDFLoader
55
- from langchain.schema.document import Document
56
-
57
- from langchain.text_splitter import RecursiveCharacterTextSplitter
58
- from langchain.text_splitter import CharacterTextSplitter
59
- from langchain.memory import ConversationBufferMemory
60
- from langchain_community.llms import HuggingFaceEndpoint
61
- from langchain_community.embeddings import HuggingFaceEmbeddings
62
-
63
-
64
- # for hugging face llm
65
- from transformers import AutoTokenizer
66
- import transformers
67
- import torch
68
- import tqdm
69
- import accelerate
70
-
71
-
72
- import pymupdf
73
- from PIL import Image
74
- import os
75
- import re
76
- import uuid
77
-
78
- import os
79
- import wget
80
- import subprocess
81
- import urllib.request
82
- import requests
83
-
84
- from pathlib import Path
85
- from unidecode import unidecode
86
-
87
- api_key = os.getenv("OPENAI_API_KEY")
88
- user_agent = os.getenv("USER_AGENT")
89
-
90
- dr_link_url1 = os.getenv("DR_LINK_1")
91
- dr_link_url2 = os.getenv("DR_LINK_2")
92
- azure_endpt = os.getenv("AZURE_ENDPT")
93
-
94
-
95
- """
96
- enable_box = gr.Textbox(
97
- value=None, placeholder="Upload your OpenAI API key", interactive=True
98
- )
99
- disable_box = gr.Textbox(value="OpenAI API key is set", interactive=False)
100
- """
101
-
102
- def set_apikey(api_key: str):
103
- print("API Key set")
104
- app.OPENAI_API_KEY = api_key
105
- #return disable_box
106
-
107
- """
108
- def enable_api_box():
109
- return enable_box
110
- """
111
-
112
- def add_text(history, text: str):
113
- if not text:
114
- raise gr.Error("enter text")
115
- print("in add_text history="+str(history))
116
- print("in add_text text="+str(text))
117
-
118
- history = history + [(text, "")]
119
- return history
120
-
121
-
122
- class my_app:
123
- def __init__(self, OPENAI_API_KEY: str = None) -> None:
124
- print("init")
125
- self.OPENAI_API_KEY: str = api_key
126
- #self.chain = None
127
- #self.chat_history: list = []
128
- #self.N: int = 0
129
- self.count: int = 0
130
-
131
- def __call__(self, file: str) -> Any:
132
- print("call")
133
- #if self.count == 0:
134
- #vincent added
135
- #self.chain = None
136
- #self.chat_history: list = []
137
- #self.N: int = 0
138
- #self.count: int = 0
139
-
140
- #self.chain = self.build_chain(file)
141
- #self.count += 1
142
-
143
- #vincent added
144
-
145
- #else:
146
- #self.chain = self.build_chain(file)
147
- #self.count += 1
148
-
149
- #return self.chain
150
-
151
-
152
- def process_file2(file: str):
153
-
154
- loader = PyMuPDFLoader(file.name)
155
- documents = loader.load()
156
- pattern = r"/([^/]+)$"
157
- match = re.search(pattern, file.name)
158
- try:
159
- file_name = match.group(1)
160
- except:
161
- file_name = os.path.basename(file)
162
-
163
- return documents, file_name
164
-
165
- def create_collection_name(filepath):
166
- # Extract filename without extension
167
- collection_name = Path(filepath).stem
168
- # Fix potential issues from naming convention
169
- ## Remove space
170
- collection_name = collection_name.replace(" ","-")
171
- ## ASCII transliterations of Unicode text
172
- collection_name = unidecode(collection_name)
173
- ## Remove special characters
174
- #collection_name = re.findall("[\dA-Za-z]*", collection_name)[0]
175
- collection_name = re.sub('[^A-Za-z0-9]+', '-', collection_name)
176
- ## Limit length to 50 characters
177
- collection_name = collection_name[:50]
178
- ## Minimum length of 3 characters
179
- if len(collection_name) < 3:
180
- collection_name = collection_name + 'xyz'
181
- ## Enforce start and end as alphanumeric character
182
- if not collection_name[0].isalnum():
183
- collection_name = 'A' + collection_name[1:]
184
- if not collection_name[-1].isalnum():
185
- collection_name = collection_name[:-1] + 'Z'
186
- print('Filepath: ', filepath)
187
- print('Collection name: ', collection_name)
188
- return collection_name
189
-
190
- def build_qa_chain(collection_name, vector_db, file: str):
191
- print("in build_qa_chain="+file.name)
192
- documents, file_name = process_file2(file)
193
- # Load embeddings model
194
- #embeddings = OpenAIEmbeddings(openai_api_key=self.OPENAI_API_KEY)
195
-
196
- #vincent for old LLM
197
- """
198
- embeddings = AzureOpenAIEmbeddings(
199
- model="text-embedding-ada-002",
200
- # dimensions: Optional[int] = None, # Can specify dimensions with new text-embedding-3 models
201
- azure_endpoint=azure_endpt , # If not provided, will read env variable AZURE_OPENAI_ENDPOINT
202
- openai_api_key=api_key, # Can provide an API key directly. If missing read env variable AZURE_OPENAI_API_KEY
203
- #openai_api_version="2023-05-15", # If not provided, will read env variable AZURE_OPENAI_API_VERSION
204
- openai_api_version="2023-05-15", # If not provided, will read env variable AZURE_OPENAI_API_VERSION
205
- )
206
- """
207
-
208
- #vincent for new LLM
209
- embeddings = HuggingFaceEmbeddings()
210
-
211
-
212
- #vincent added to handle the tenant problem 20250211
213
- chromadb.api.client.SharedSystemClient.clear_system_cache()
214
- new_client = chromadb.EphemeralClient()
215
- memory = ConversationBufferMemory(
216
- memory_key="chat_history",
217
- output_key='answer',
218
- return_messages=True
219
- )
220
-
221
- # added by vincent
222
- text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=10)
223
- chunked_documents = text_splitter.split_documents(documents)
224
-
225
- #list_file_path = [x.name for x in list_file_obj if x is not None]
226
- list_file_path = file.name
227
- # Create collection_name for vector database
228
- # vincent fix InvalidCollectionException 20250212
229
- #collection_name = create_collection_name(list_file_path[0])
230
- collection_name = "pdf_docs_l_"+file.name[-10:]
231
-
232
- vector_db = Chroma.from_documents(
233
- documents=chunked_documents,
234
- embedding=embeddings,
235
- client=new_client,
236
- #collection_name=file_name,
237
- #persist_directory = "db_" + file_name,
238
- collection_name=collection_name,
239
- )
240
- """
241
- chain = ConversationalRetrievalChain.from_llm(
242
- ChatOpenAI(temperature=0.0, openai_api_key=self.OPENAI_API_KEY),
243
- retriever=pdfsearch.as_retriever(search_kwargs={"k": 1}),
244
- return_source_documents=True,
245
- )
246
- """
247
-
248
- #vincent added for old LLM
249
- """
250
- chain = ConversationalRetrievalChain.from_llm(
251
- #ChatOpenAI(temperature=0.0, openai_api_key=self.OPENAI_API_KEY),
252
-
253
- AzureChatOpenAI(
254
- temperature=0.0, openai_api_key=api_key, api_version="2024-08-01-preview",
255
- model_name="gpt-4o", azure_endpoint=azure_endpt),
256
- #vincent modified
257
- retriever=vector_db.as_retriever(),
258
- #retriever=pdfsearch.as_retriever(search_kwargs={"k": 1}),
259
- return_source_documents=True,
260
- chain_type="stuff",
261
- memory=memory,
262
- )
263
-
264
- """
265
- #vincent for new LLM
266
- llm_model = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
267
- #llm_model = "meta-llama/Llama-2-7b-chat-hf"
268
- llm = HuggingFaceEndpoint(
269
- repo_id=llm_model,
270
- task="text-generation", # Explicitly specify task
271
- # model_kwargs={"temperature": temperature, "max_new_tokens": 250, "top_k": top_k}
272
- temperature = 0.01,
273
- max_new_tokens = 250,
274
- top_k = 3,
275
- )
276
-
277
- chain = ConversationalRetrievalChain.from_llm(
278
- llm,
279
- retriever=vector_db.as_retriever(),
280
- chain_type="stuff",
281
- memory=memory,
282
- # combine_docs_chain_kwargs={"prompt": your_prompt})
283
- return_source_documents=True,
284
- #return_generated_question=False,
285
- verbose=False,
286
- )
287
-
288
- #vincent added 20250211
289
- app.count += 1
290
- return collection_name, vector_db, chain
291
-
292
-
293
- def get_response(collection_name, vector_db, qa_chain, history, query, file):
294
- #vincent added
295
- set_apikey(api_key)
296
- #print("in get_response count=" + str(app.count))
297
- if not file:
298
- raise gr.Error(message="Upload a PDF")
299
-
300
- formatted_chat_history = list(history)
301
- formatted_chat_history = formatted_chat_history[:len(formatted_chat_history)-1]
302
- print("in get_response query="+ query)
303
- #print("in get_response chat_history="+ str(app.chat_history))
304
- print("in get_response formatted_chat_history="+ str(formatted_chat_history))
305
- #print("in get_response history="+ str(history))
306
-
307
- chat_history_tuples = []
308
- for message in formatted_chat_history:
309
- chat_history_tuples.append((message[0], message[1]))
310
-
311
- #vincent added 20250211
312
- if app.count == 0:
313
- collection_name, vector_db, qa_chain = build_qa_chain(collection_name, vector_db, file)
314
- result = qa_chain.invoke(
315
- {"question": query, "chat_history": chat_history_tuples}, return_only_outputs=True
316
- #{"question": query, "chat_history": format_chat_history(query, history)}, return_only_outputs=True
317
- )
318
-
319
-
320
- #app.chat_history += [(query, result["answer"])]
321
- ##app.N = list(result["source_documents"][0])[1][1]["page"]
322
- for char in result["answer"]:
323
- history[-1][-1] += char
324
- yield collection_name, vector_db, qa_chain, history, ""
325
-
326
- #print("answer:"+ result["answer"])
327
-
328
-
329
- def render_file(file):
330
- #print("in render_file="+file.name+" count="+str(app.count))
331
- doc = pymupdf.open(file.name)
332
- # vincent: issue in N
333
- page = doc[N]
334
- # Render the page as a PNG image with a resolution of 150 DPI
335
- pix = page.get_pixmap(dpi=150)
336
- image = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
337
- return image
338
-
339
-
340
- def purge_chat_and_render_first(file):
341
- print("purge_chat_and_render_first")
342
- # Purges the previous chat session so that the bot has no concept of previous documents
343
- chat_history = []
344
- history = []
345
- #count = 0
346
-
347
- #vincent added 20250211
348
- #count = count + 1
349
- app.count = 0
350
-
351
- # Use PyMuPDF to render the first page of the uploaded document
352
- doc = pymupdf.open(file.name)
353
- page = doc[0]
354
- # Render the page as a PNG image with a resolution of 150 DPI
355
- pix = page.get_pixmap(dpi=150)
356
- image = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
357
- return image, []
358
-
359
- app = my_app()
360
-
361
- with gr.Blocks() as demo:
362
-
363
- vector_db = gr.State()
364
- qa_chain = gr.State()
365
- collection_name = gr.State()
366
- #N = gr.Number()
367
- #count = gr.Number()
368
-
369
- N = 0
370
- count = 0
371
-
372
- #chat_history = gr.State()
373
- #chat_history: list = []
374
- #chat_history = []
375
-
376
- with gr.Column():
377
- """
378
- with gr.Row():
379
-
380
- with gr.Column(scale=1):
381
- api_key = gr.Textbox(
382
- placeholder="Enter OpenAI API key and hit <RETURN>",
383
- show_label=False,
384
- interactive=True
385
- )
386
- """
387
- with gr.Row():
388
- with gr.Column(scale=2):
389
- with gr.Row():
390
- chatbot = gr.Chatbot(value=[], elem_id="chatbot")
391
- with gr.Row():
392
- txt = gr.Textbox(
393
- show_label=False,
394
- placeholder="Enter text and press submit",
395
- scale=2
396
- )
397
- submit_btn = gr.Button("submit", scale=1)
398
-
399
- with gr.Column(scale=1):
400
- with gr.Row():
401
- show_img = gr.Image(label="Upload PDF")
402
- with gr.Row():
403
- btn = gr.UploadButton("📁 upload a PDF", file_types=[".pdf"])
404
-
405
- """
406
- api_key.submit(
407
- fn=set_apikey,
408
- inputs=[api_key],
409
- outputs=[
410
- api_key,
411
- ],
412
- )
413
- """
414
-
415
- btn.upload(
416
- fn=purge_chat_and_render_first,
417
- inputs=[btn],
418
- outputs=[show_img, chatbot],
419
- )
420
-
421
- submit_btn.click(
422
- fn=add_text,
423
- inputs=[chatbot, txt],
424
- outputs=[
425
- chatbot,
426
- ],
427
- queue=False,
428
- ).success(
429
- fn=get_response, inputs=[collection_name,vector_db, qa_chain, chatbot, txt, btn], outputs=[collection_name,vector_db, qa_chain, chatbot, txt]
430
- ).success(
431
- fn=render_file, inputs=[btn], outputs=[show_img]
432
- )
433
-
434
- #demo.queue()
435
- #demo.launch(share=True, ssr_mode=False)
436
- #demo.launch()
437
- demo.queue().launch(share=True)
438
- #demo.launch(share=True)