iajitpanday commited on
Commit
f18e345
·
verified ·
1 Parent(s): 226f896

Create gradio_app.py

Browse files
Files changed (1) hide show
  1. gradio_app.py +321 -0
gradio_app.py ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gradio interface for the RAG-based response system.
3
+ This will be deployed to your Hugging Face Space.
4
+ """
5
+
6
+ import gradio as gr
7
+ import os
8
+ import tempfile
9
+ import json
10
+ from pathlib import Path
11
+ import torch
12
+ from transformers import AutoTokenizer, AutoModel, pipeline
13
+ from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader
14
+ from langchain_community.vectorstores import FAISS
15
+ from langchain_community.embeddings import HuggingFaceEmbeddings
16
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
17
+
18
+ # Define paths
19
+ DOCUMENTS_DIR = Path("documents")
20
+ DOCUMENTS_DIR.mkdir(exist_ok=True)
21
+ VECTOR_DB_PATH = Path("vector_db")
22
+
23
+ # Initialize models
24
+ model_name = "sentence-transformers/all-MiniLM-L6-v2"
25
+ embeddings = HuggingFaceEmbeddings(model_name=model_name)
26
+
27
+ # Initialize vector store
28
+ if VECTOR_DB_PATH.exists():
29
+ try:
30
+ vector_db = FAISS.load_local(str(VECTOR_DB_PATH), embeddings)
31
+ print("Loaded existing vector database.")
32
+ except Exception as e:
33
+ print(f"Error loading vector database: {e}")
34
+ vector_db = None
35
+ else:
36
+ vector_db = None
37
+
38
+ # Define possible intents
39
+ POSSIBLE_INTENTS = [
40
+ "product_inquiry",
41
+ "technical_support",
42
+ "billing_question",
43
+ "general_information",
44
+ "appointment_scheduling",
45
+ "complaint",
46
+ "other"
47
+ ]
48
+
49
+ # Default responses for when RAG fails or no documents are available
50
+ DEFAULT_RESPONSES = {
51
+ "product_inquiry": "Thank you for your interest in our products. I'll gather the information and have someone contact you with more details.",
52
+ "technical_support": "I understand you're experiencing technical issues. Let me find the right person to help you resolve this.",
53
+ "billing_question": "Thank you for your billing inquiry. I'll connect you with our billing department for assistance.",
54
+ "general_information": "Thank you for reaching out. I'll make sure you get the information you need.",
55
+ "appointment_scheduling": "I'd be happy to help schedule an appointment for you. Let me find the next available slot.",
56
+ "complaint": "I'm sorry to hear about your experience. Your feedback is important to us, and we'll address this promptly.",
57
+ "other": "Thank you for your call. I'll make sure your message gets to the right person."
58
+ }
59
+
60
+ def load_pdf(file):
61
+ """Load a PDF document into the vector store"""
62
+ global vector_db
63
+
64
+ try:
65
+ # Save the uploaded file temporarily
66
+ temp_dir = tempfile.mkdtemp()
67
+ temp_path = os.path.join(temp_dir, file.name)
68
+
69
+ with open(temp_path, "wb") as f:
70
+ f.write(file.read())
71
+
72
+ # Save a copy to the documents directory
73
+ target_path = os.path.join(DOCUMENTS_DIR, file.name)
74
+ with open(target_path, "wb") as f:
75
+ with open(temp_path, "rb") as src:
76
+ f.write(src.read())
77
+
78
+ # Load and process the PDF
79
+ loader = PyPDFLoader(temp_path)
80
+ documents = loader.load()
81
+
82
+ # Split the documents
83
+ text_splitter = RecursiveCharacterTextSplitter(
84
+ chunk_size=1000,
85
+ chunk_overlap=200
86
+ )
87
+ chunks = text_splitter.split_documents(documents)
88
+
89
+ # Update or create vector store
90
+ if vector_db is None:
91
+ vector_db = FAISS.from_documents(chunks, embeddings)
92
+ vector_db.save_local(str(VECTOR_DB_PATH))
93
+ else:
94
+ vector_db.add_documents(chunks)
95
+ vector_db.save_local(str(VECTOR_DB_PATH))
96
+
97
+ return f"Successfully added {file.name} to the knowledge base with {len(chunks)} chunks."
98
+
99
+ except Exception as e:
100
+ return f"Error processing PDF: {str(e)}"
101
+
102
+ def load_website(url):
103
+ """Load a website into the vector store"""
104
+ global vector_db
105
+
106
+ try:
107
+ # Load content from website
108
+ loader = WebBaseLoader(url)
109
+ documents = loader.load()
110
+
111
+ # Save the URL reference
112
+ with open(os.path.join(DOCUMENTS_DIR, "websites.txt"), "a") as f:
113
+ f.write(f"{url}\n")
114
+
115
+ # Split the documents
116
+ text_splitter = RecursiveCharacterTextSplitter(
117
+ chunk_size=1000,
118
+ chunk_overlap=200
119
+ )
120
+ chunks = text_splitter.split_documents(documents)
121
+
122
+ # Update or create vector store
123
+ if vector_db is None:
124
+ vector_db = FAISS.from_documents(chunks, embeddings)
125
+ vector_db.save_local(str(VECTOR_DB_PATH))
126
+ else:
127
+ vector_db.add_documents(chunks)
128
+ vector_db.save_local(str(VECTOR_DB_PATH))
129
+
130
+ return f"Successfully added {url} to the knowledge base with {len(chunks)} chunks."
131
+
132
+ except Exception as e:
133
+ return f"Error processing website: {str(e)}"
134
+
135
+ def generate_response(query, intent=None):
136
+ """Generate a response based on the query and intent"""
137
+ global vector_db
138
+
139
+ # If no intent provided, use a default
140
+ if not intent or intent not in POSSIBLE_INTENTS:
141
+ intent = "general_information"
142
+
143
+ # If no vector database, return default response
144
+ if vector_db is None:
145
+ return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
146
+
147
+ try:
148
+ # Query the vector database
149
+ retrieved_docs = vector_db.similarity_search(query, k=3)
150
+
151
+ if not retrieved_docs:
152
+ return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
153
+
154
+ # Combine retrieved document chunks
155
+ context = "\n\n".join([doc.page_content for doc in retrieved_docs])
156
+
157
+ # Create prompt for the model
158
+ prompt = f"""
159
+ Based on the following context information and the user's query,
160
+ provide a helpful, professional, and concise response.
161
+
162
+ Context:
163
+ {context}
164
+
165
+ User query: {query}
166
+
167
+ Intent: {intent}
168
+
169
+ Response:
170
+ """
171
+
172
+ # Generate response using a pre-trained model
173
+ tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-base")
174
+ model = AutoModel.from_pretrained("google/flan-t5-base")
175
+
176
+ inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True)
177
+ outputs = model.generate(
178
+ inputs["input_ids"],
179
+ max_length=200,
180
+ num_beams=4,
181
+ early_stopping=True
182
+ )
183
+
184
+ response_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
185
+
186
+ # If model output is empty or too short, use retrieved text with a prefix
187
+ if len(response_text) < 20:
188
+ response_text = f"Based on the information I have: {context[:200]}..."
189
+
190
+ return response_text
191
+
192
+ except Exception as e:
193
+ print(f"Error generating response: {e}")
194
+ return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
195
+
196
+ def list_documents():
197
+ """List all documents in the knowledge base"""
198
+ files = list(DOCUMENTS_DIR.glob("*.pdf"))
199
+
200
+ # Add websites if available
201
+ website_file = DOCUMENTS_DIR / "websites.txt"
202
+ websites = []
203
+ if website_file.exists():
204
+ with open(website_file, "r") as f:
205
+ websites = [line.strip() for line in f if line.strip()]
206
+
207
+ return {
208
+ "PDFs": [f.name for f in files],
209
+ "Websites": websites
210
+ }
211
+
212
+ # Create the Gradio interface
213
+ with gr.Blocks(title="Call Assistant RAG System") as demo:
214
+ gr.Markdown("# Call Assistant RAG System")
215
+ gr.Markdown("Add documents and websites to the knowledge base, and test the response generation.")
216
+
217
+ with gr.Tab("Add Knowledge"):
218
+ with gr.Row():
219
+ with gr.Column():
220
+ pdf_input = gr.File(label="Upload PDF Document")
221
+ pdf_button = gr.Button("Add PDF to Knowledge Base")
222
+ pdf_output = gr.Textbox(label="PDF Upload Status")
223
+
224
+ pdf_button.click(
225
+ load_pdf,
226
+ inputs=[pdf_input],
227
+ outputs=[pdf_output]
228
+ )
229
+
230
+ with gr.Column():
231
+ url_input = gr.Textbox(label="Website URL")
232
+ url_button = gr.Button("Add Website to Knowledge Base")
233
+ url_output = gr.Textbox(label="Website Status")
234
+
235
+ url_button.click(
236
+ load_website,
237
+ inputs=[url_input],
238
+ outputs=[url_output]
239
+ )
240
+
241
+ with gr.Tab("Knowledge Base"):
242
+ list_button = gr.Button("List Documents in Knowledge Base")
243
+ knowledge_output = gr.JSON(label="Documents")
244
+
245
+ list_button.click(
246
+ list_documents,
247
+ inputs=[],
248
+ outputs=[knowledge_output]
249
+ )
250
+
251
+ with gr.Tab("Test Response Generation"):
252
+ with gr.Row():
253
+ query_input = gr.Textbox(label="Query / Transcription")
254
+ intent_input = gr.Dropdown(
255
+ choices=POSSIBLE_INTENTS,
256
+ label="Intent",
257
+ value="general_information"
258
+ )
259
+
260
+ test_button = gr.Button("Generate Response")
261
+ response_output = gr.Textbox(label="Generated Response")
262
+
263
+ test_button.click(
264
+ generate_response,
265
+ inputs=[query_input, intent_input],
266
+ outputs=[response_output]
267
+ )
268
+
269
+ with gr.Tab("API"):
270
+ gr.Markdown("""
271
+ ## API Documentation
272
+
273
+ This Gradio app exposes an API endpoint that can be used by your Twilio application.
274
+
275
+ ### Endpoint: `/api/predict`
276
+
277
+ **Method:** POST
278
+
279
+ **Input:**
280
+ ```json
281
+ {
282
+ "data": [
283
+ "user's transcribed query",
284
+ "detected intent"
285
+ ]
286
+ }
287
+ ```
288
+
289
+ **Output:**
290
+ ```json
291
+ {
292
+ "data": [
293
+ "generated response"
294
+ ],
295
+ "duration": 1.2345
296
+ }
297
+ ```
298
+
299
+ **Example Python code to call the API:**
300
+ ```python
301
+ import requests
302
+
303
+ response = requests.post(
304
+ "https://huggingface.co/spaces/iajitpanday/vBot-1.5/api/predict",
305
+ json={"data": ["How do I reset my password?", "technical_support"]}
306
+ )
307
+
308
+ result = response.json()
309
+ generated_response = result["data"][0]
310
+ ```
311
+ """)
312
+
313
+ # Define API function for Gradio Spaces
314
+ def api_response(query, intent=None):
315
+ """API function for Gradio Spaces"""
316
+ response = generate_response(query, intent)
317
+ return [response]
318
+
319
+ # Define the API
320
+ demo.queue()
321
+ demo.launch()