Codequestt commited on
Commit
979bf04
Β·
verified Β·
1 Parent(s): f4b4b2a

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +176 -0
  2. requirements.txt +9 -0
app.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+ import uuid
4
+ import zipfile
5
+ import io
6
+ from gtts import gTTS
7
+ from langchain_community.llms import OpenAI
8
+ from langchain_community.embeddings import HuggingFaceEmbeddings
9
+ from langchain_community.vectorstores import FAISS
10
+ from langchain.chains import RetrievalQA
11
+ from langchain_community.document_loaders import PyPDFLoader, DirectoryLoader
12
+ from langchain.text_splitter import CharacterTextSplitter
13
+ from langchain.memory import ConversationBufferMemory
14
+ from langchain.llms.base import LLM
15
+ from typing import Any, List, Mapping, Optional
16
+ from openai import OpenAI as OpenAIClient
17
+ import gradio as gr
18
+
19
+
20
+ API_KEY = os.getenv("NVIDIA_API_KEY") # Replace the hardcoded key
21
+
22
+ class LlamaLLM(LLM):
23
+ client: Any = None
24
+
25
+ def __init__(self):
26
+ super().__init__()
27
+ self.client = OpenAIClient(
28
+ base_url="https://integrate.api.nvidia.com/v1",
29
+ api_key=API_KEY
30
+ )
31
+
32
+ def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
33
+ completion = self.client.chat.completions.create(
34
+ model="meta/llama-3.3-70b-instruct",
35
+ messages=[{"role": "user", "content": prompt}],
36
+ temperature=0.2,
37
+ top_p=0.7,
38
+ max_tokens=1024,
39
+ )
40
+ return completion.choices[0].message.content
41
+
42
+ @property
43
+ def _llm_type(self) -> str:
44
+ return "Llama 3.3"
45
+
46
+ # Initialize components
47
+ llm = LlamaLLM()
48
+
49
+ def process_pdfs(zip_file):
50
+ """Process uploaded ZIP file containing PDFs"""
51
+ print("Processing ZIP file...")
52
+ with tempfile.TemporaryDirectory() as temp_dir:
53
+ print(f"Extracting ZIP to temporary directory: {temp_dir}")
54
+ with zipfile.ZipFile(zip_file.name, 'r') as zip_ref:
55
+ zip_ref.extractall(temp_dir)
56
+
57
+ print("Loading PDFs...")
58
+ loader = DirectoryLoader(temp_dir, glob="**/*.pdf", loader_cls=PyPDFLoader)
59
+ documents = loader.load()
60
+
61
+ if not documents:
62
+ raise ValueError("No PDF files found in the uploaded ZIP")
63
+
64
+ print(f"Loaded {len(documents)} documents.")
65
+ text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
66
+ texts = text_splitter.split_documents(documents)
67
+
68
+ print("Creating embeddings...")
69
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
70
+ vectorstore = FAISS.from_documents(texts, embeddings)
71
+
72
+ memory = ConversationBufferMemory()
73
+ qa_chain = RetrievalQA.from_chain_type(
74
+ llm=llm,
75
+ chain_type="stuff",
76
+ retriever=vectorstore.as_retriever(),
77
+ memory=memory,
78
+ )
79
+
80
+ print("PDF processing complete.")
81
+ return qa_chain, memory
82
+
83
+ def generate_audio(text: str) -> str:
84
+ """Generate audio from text using gTTS"""
85
+ try:
86
+ tts = gTTS(text=text, lang='en')
87
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
88
+ tts.save(temp_file.name)
89
+ return temp_file.name
90
+ except Exception as e:
91
+ print(f"Audio generation error: {e}")
92
+ return None
93
+
94
+ def chat_response(query, qa_chain, memory):
95
+ print(f"Generating response for query: {query}")
96
+ try:
97
+ raw_response = qa_chain.invoke(query)
98
+ print(f"Raw response: {raw_response}")
99
+
100
+ royal_prompt = f"""
101
+ Respond as a historical royal figure mentioned in the query.
102
+ Use first-person perspective and be gender-specific.
103
+ Respond in the query's language. Be authoritative but polite.
104
+ Use only context information. If unsure, respond as a monarch would.
105
+ Context: {raw_response}
106
+ Previous conversation: {memory.buffer}
107
+ Query: {query}
108
+ Royal Response:"""
109
+
110
+ final_response = llm._call(royal_prompt)
111
+ print(f"Final response: {final_response}")
112
+ memory.save_context({'input': query}, {'output': final_response})
113
+ return final_response, generate_audio(final_response)
114
+ except Exception as e:
115
+ print(f"Error in chat_response: {e}")
116
+ raise gr.Error(f"Error generating response: {e}")
117
+
118
+ with gr.Blocks() as demo:
119
+ gr.Markdown("# πŸ‘‘ Royal Document Assistant")
120
+ qa_chain = gr.State()
121
+ memory = gr.State()
122
+
123
+ with gr.Row():
124
+ with gr.Column():
125
+ zip_upload = gr.File(label="Upload ZIP of PDFs", type="filepath")
126
+ load_btn = gr.Button("Process Documents")
127
+ load_status = gr.Markdown()
128
+
129
+ with gr.Row(visible=False) as chat_row:
130
+ with gr.Column():
131
+ chat_input = gr.Textbox(label="Ask the Royal Assistant")
132
+ chat_output = gr.Textbox(label="Response", interactive=False)
133
+ audio_output = gr.Audio(label="Spoken Response", type="filepath")
134
+ submit_btn = gr.Button("Ask")
135
+
136
+ def load_docs(zip_file):
137
+ try:
138
+ chain, mem = process_pdfs(zip_file)
139
+ return (
140
+ gr.update(visible=True),
141
+ chain,
142
+ mem,
143
+ "βœ… Documents processed! You may now ask questions"
144
+ )
145
+ except Exception as e:
146
+ return (
147
+ gr.update(visible=False),
148
+ None,
149
+ None,
150
+ f"❌ Error processing documents: {str(e)}"
151
+ )
152
+
153
+ def ask_question(query, qa_chain, memory):
154
+ if not qa_chain or not memory:
155
+ raise gr.Error("Please process documents first!")
156
+ try:
157
+ response, audio = chat_response(query, qa_chain, memory)
158
+ return response, audio
159
+ except Exception as e:
160
+ print(f"Error in ask_question: {e}")
161
+ return f"Error: {str(e)}", None
162
+
163
+ load_btn.click(
164
+ load_docs,
165
+ inputs=zip_upload,
166
+ outputs=[chat_row, qa_chain, memory, load_status]
167
+ )
168
+
169
+ submit_btn.click(
170
+ ask_question,
171
+ inputs=[chat_input, qa_chain, memory],
172
+ outputs=[chat_output, audio_output]
173
+ )
174
+
175
+ if __name__ == "__main__":
176
+ demo.launch(share=True)
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ langchain
3
+ langchain_community
4
+ openai
5
+ gTTS
6
+ python-dotenv
7
+ faiss-cpu
8
+ sentence-transformers
9
+ pypdf