iajitpanday commited on
Commit
56a5b15
·
verified ·
1 Parent(s): 662c0ec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -213
app.py CHANGED
@@ -3,33 +3,12 @@ import os
3
  import tempfile
4
  import json
5
  import requests
6
- import base64
7
  from pathlib import Path
8
  from transformers import pipeline
9
- from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader
10
- from langchain_community.vectorstores import FAISS
11
- from langchain_community.embeddings import HuggingFaceEmbeddings
12
- from langchain.text_splitter import RecursiveCharacterTextSplitter
13
 
14
- # Define paths
15
  DOCUMENTS_DIR = Path("documents")
16
  DOCUMENTS_DIR.mkdir(exist_ok=True)
17
- VECTOR_DB_PATH = Path("vector_db")
18
-
19
- # Initialize models
20
- model_name = "sentence-transformers/all-MiniLM-L6-v2"
21
- embeddings = HuggingFaceEmbeddings(model_name=model_name)
22
-
23
- # Initialize vector store
24
- if VECTOR_DB_PATH.exists():
25
- try:
26
- vector_db = FAISS.load_local(str(VECTOR_DB_PATH), embeddings)
27
- print("Loaded existing vector database.")
28
- except Exception as e:
29
- print(f"Error loading vector database: {e}")
30
- vector_db = None
31
- else:
32
- vector_db = None
33
 
34
  # Define possible intents
35
  POSSIBLE_INTENTS = [
@@ -42,7 +21,7 @@ POSSIBLE_INTENTS = [
42
  "other"
43
  ]
44
 
45
- # Default responses for when RAG fails or no documents are available
46
  DEFAULT_RESPONSES = {
47
  "product_inquiry": "Thank you for your interest in our products. I'll gather the information and have someone contact you with more details.",
48
  "technical_support": "I understand you're experiencing technical issues. Let me find the right person to help you resolve this.",
@@ -53,6 +32,9 @@ DEFAULT_RESPONSES = {
53
  "other": "Thank you for your call. I'll make sure your message gets to the right person."
54
  }
55
 
 
 
 
56
  # Create a classifier
57
  try:
58
  classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
@@ -81,9 +63,7 @@ def classify_intent(text):
81
  return "other", 0.0
82
 
83
  def load_pdf(file):
84
- """Load a PDF document into the vector store"""
85
- global vector_db
86
-
87
  try:
88
  # Save the uploaded file temporarily
89
  temp_dir = tempfile.mkdtemp()
@@ -98,101 +78,40 @@ def load_pdf(file):
98
  with open(temp_path, "rb") as src:
99
  f.write(src.read())
100
 
101
- # Load and process the PDF
102
- loader = PyPDFLoader(temp_path)
103
- documents = loader.load()
104
-
105
- # Split the documents
106
- text_splitter = RecursiveCharacterTextSplitter(
107
- chunk_size=1000,
108
- chunk_overlap=200
109
- )
110
- chunks = text_splitter.split_documents(documents)
111
-
112
- # Update or create vector store
113
- if vector_db is None:
114
- vector_db = FAISS.from_documents(chunks, embeddings)
115
- vector_db.save_local(str(VECTOR_DB_PATH))
116
- else:
117
- vector_db.add_documents(chunks)
118
- vector_db.save_local(str(VECTOR_DB_PATH))
119
 
120
- return f"Successfully added {file.name} to the knowledge base with {len(chunks)} chunks."
121
 
122
  except Exception as e:
123
  return f"Error processing PDF: {str(e)}"
124
 
125
  def load_website(url):
126
- """Load a website into the vector store"""
127
- global vector_db
128
-
129
  try:
130
- # Load content from website
131
- loader = WebBaseLoader(url)
132
- documents = loader.load()
133
 
134
  # Save the URL reference
135
  with open(os.path.join(DOCUMENTS_DIR, "websites.txt"), "a") as f:
136
  f.write(f"{url}\n")
137
 
138
- # Split the documents
139
- text_splitter = RecursiveCharacterTextSplitter(
140
- chunk_size=1000,
141
- chunk_overlap=200
142
- )
143
- chunks = text_splitter.split_documents(documents)
144
-
145
- # Update or create vector store
146
- if vector_db is None:
147
- vector_db = FAISS.from_documents(chunks, embeddings)
148
- vector_db.save_local(str(VECTOR_DB_PATH))
149
- else:
150
- vector_db.add_documents(chunks)
151
- vector_db.save_local(str(VECTOR_DB_PATH))
152
-
153
- return f"Successfully added {url} to the knowledge base with {len(chunks)} chunks."
154
 
155
  except Exception as e:
156
  return f"Error processing website: {str(e)}"
157
 
158
  def generate_response(query, intent=None):
159
  """Generate a response based on the query and intent"""
160
- global vector_db
161
-
162
  # If no intent provided, use a default
163
  if not intent or intent not in POSSIBLE_INTENTS:
164
  intent = "general_information"
165
 
166
- # If no vector database, return default response
167
- if vector_db is None:
168
- return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
169
-
170
- try:
171
- # Query the vector database
172
- retrieved_docs = vector_db.similarity_search(query, k=3)
173
-
174
- if not retrieved_docs:
175
- return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
176
-
177
- # Combine retrieved document chunks
178
- context = "\n\n".join([doc.page_content for doc in retrieved_docs])
179
-
180
- # Simple response generation by combining context with templates
181
- if len(context) > 10:
182
- if intent == "product_inquiry":
183
- return f"Based on the information I have: {context[:300]}... Would you like to know more specific details?"
184
- elif intent == "technical_support":
185
- return f"I found some information that might help with your issue: {context[:300]}... Is there a specific part you'd like me to explain further?"
186
- elif intent == "billing_question":
187
- return f"Regarding your billing question: {context[:300]}... Would you like me to connect you with our billing department for more details?"
188
- else:
189
- return f"Here's what I found that might help answer your question: {context[:300]}... Is there anything specific you'd like me to clarify?"
190
- else:
191
- return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
192
-
193
- except Exception as e:
194
- print(f"Error generating response: {e}")
195
- return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
196
 
197
  def list_documents():
198
  """List all documents in the knowledge base"""
@@ -210,77 +129,23 @@ def list_documents():
210
  "Websites": websites
211
  }
212
 
213
- # Special handler for Twilio
214
- def handle_twilio_request(data):
215
- """Process Twilio request data"""
216
- try:
217
- # Extract relevant information from Twilio data
218
- if "SpeechResult" in data:
219
- # This is a speech transcription
220
- query = data.get("SpeechResult", "")
221
- intent, _ = classify_intent(query)
222
- response = generate_response(query, intent)
223
-
224
- # Create TwiML response
225
- twiml = f"""<?xml version="1.0" encoding="UTF-8"?>
226
- <Response>
227
- <Say>{response}</Say>
228
- <Pause length="1"/>
229
- <Say>Is there anything else I can help you with today?</Say>
230
- <Gather input="speech" action="https://huggingface.co/spaces/iajitpanday/vBot-1.5/api/twilio/followup" method="POST" speechTimeout="auto" speechModel="phone_call"/>
231
- <Say>Thank you for calling. Have a great day!</Say>
232
- </Response>
233
- """
234
- return twiml
235
-
236
- elif "TranscriptionText" in data:
237
- # This is a transcription callback
238
- query = data.get("TranscriptionText", "")
239
- intent, _ = classify_intent(query)
240
- response = generate_response(query, intent)
241
-
242
- # Create SMS response using Twilio API
243
- # Note: This requires Twilio credentials which we're avoiding
244
- return f"Response would be sent via SMS: {response}"
245
-
246
- elif "CallStatus" in data and data.get("CallStatus") == "ringing":
247
- # Initial call handling
248
- twiml = """<?xml version="1.0" encoding="UTF-8"?>
249
- <Response>
250
- <Say>Hello! Thank you for calling. How can I help you today?</Say>
251
- <Gather input="speech" action="https://huggingface.co/spaces/iajitpanday/vBot-1.5/api/twilio/speech" method="POST" speechTimeout="auto" speechModel="phone_call"/>
252
- <Say>I didn't hear anything. Please call back when you're ready.</Say>
253
- </Response>
254
- """
255
- return twiml
256
-
257
- else:
258
- # Follow-up or fallback
259
- twiml = """<?xml version="1.0" encoding="UTF-8"?>
260
- <Response>
261
- <Say>Thank you for your call. I've recorded your message and will process it shortly.</Say>
262
- </Response>
263
- """
264
- return twiml
265
-
266
- except Exception as e:
267
- print(f"Error processing Twilio request: {e}")
268
- # Return a generic TwiML response
269
- twiml = """<?xml version="1.0" encoding="UTF-8"?>
270
- <Response>
271
- <Say>I'm sorry, I encountered an error processing your request. Please try again later.</Say>
272
- </Response>
273
- """
274
- return twiml
275
 
276
- # API endpoints for Twilio
277
- def twilio_speech_handler(query):
278
- """API endpoint for Twilio speech processing"""
279
- # Process the query
280
- intent, _ = classify_intent(query)
281
- response = generate_response(query, intent)
282
 
283
- # Create TwiML response
284
  twiml = f"""<?xml version="1.0" encoding="UTF-8"?>
285
  <Response>
286
  <Say>{response}</Say>
@@ -292,9 +157,9 @@ def twilio_speech_handler(query):
292
  """
293
  return twiml
294
 
295
- def twilio_followup_handler(query):
296
- """API endpoint for Twilio follow-up handling"""
297
- if any(word in query.lower() for word in ["yes", "yeah", "sure", "please", "correct"]):
298
  twiml = """<?xml version="1.0" encoding="UTF-8"?>
299
  <Response>
300
  <Say>Great! How else can I help you today?</Say>
@@ -310,20 +175,9 @@ def twilio_followup_handler(query):
310
  """
311
  return twiml
312
 
313
- def twilio_call_handler():
314
- """API endpoint for initial Twilio call handling"""
315
- twiml = """<?xml version="1.0" encoding="UTF-8"?>
316
- <Response>
317
- <Say>Hello! Thank you for calling. How can I help you today?</Say>
318
- <Gather input="speech" action="https://huggingface.co/spaces/iajitpanday/vBot-1.5/api/twilio/speech" method="POST" speechTimeout="auto" speechModel="phone_call"/>
319
- <Say>I didn't hear anything. Please call back when you're ready.</Say>
320
- </Response>
321
- """
322
- return twiml
323
-
324
  # Create Gradio interface
325
- with gr.Blocks(title="Call Assistant RAG System") as demo:
326
- gr.Markdown("# Call Assistant RAG System")
327
  gr.Markdown("Add documents and websites to the knowledge base, and test the response generation.")
328
 
329
  with gr.Tab("Add Knowledge"):
@@ -382,52 +236,35 @@ with gr.Blocks(title="Call Assistant RAG System") as demo:
382
  gr.Markdown("""
383
  ## Twilio Integration Instructions
384
 
385
- This Gradio app provides API endpoints for Twilio integration. Follow these steps to set up:
386
 
387
  1. Log into your Twilio account
388
  2. Go to Phone Numbers → Manage → Active numbers
389
  3. Select your number (+19704064410)
390
- 4. For "A Call Comes In", select "Webhook" and enter:
391
  - URL: `https://huggingface.co/spaces/iajitpanday/vBot-1.5/api/twilio/call`
392
  - Method: HTTP POST
393
 
394
- The system will automatically:
395
  - Answer incoming calls
396
  - Process speech input
397
  - Generate responses using your knowledge base
398
  - Handle follow-up questions
399
  """)
400
-
401
- gr.Markdown("""
402
- ## API Documentation
403
-
404
- This app exposes several API endpoints for Twilio integration:
405
-
406
- 1. `/api/twilio/call` - Initial call handling
407
- 2. `/api/twilio/speech` - Processes speech input
408
- 3. `/api/twilio/followup` - Handles follow-up responses
409
-
410
- All endpoints return TwiML responses that Twilio can understand.
411
- """)
412
-
413
- # Define API functions (these are needed for Gradio API endpoints)
414
- def api_response(query, intent=None):
415
- """Standard API function for response generation"""
416
- response = generate_response(query, intent)
417
- return [response]
418
 
 
419
  def api_twilio_call():
420
- """API function for initial Twilio call handling"""
421
  return twilio_call_handler()
422
 
423
- def api_twilio_speech(speech_result=None):
424
- """API function for Twilio speech processing"""
425
- return twilio_speech_handler(speech_result)
426
 
427
- def api_twilio_followup(speech_result=None):
428
- """API function for Twilio follow-up handling"""
429
- return twilio_followup_handler(speech_result)
430
 
431
- # Mount these functions as API endpoints
432
  demo.queue()
433
  demo.launch()
 
3
  import tempfile
4
  import json
5
  import requests
 
6
  from pathlib import Path
7
  from transformers import pipeline
 
 
 
 
8
 
9
+ # Create necessary directories
10
  DOCUMENTS_DIR = Path("documents")
11
  DOCUMENTS_DIR.mkdir(exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  # Define possible intents
14
  POSSIBLE_INTENTS = [
 
21
  "other"
22
  ]
23
 
24
+ # Default responses
25
  DEFAULT_RESPONSES = {
26
  "product_inquiry": "Thank you for your interest in our products. I'll gather the information and have someone contact you with more details.",
27
  "technical_support": "I understand you're experiencing technical issues. Let me find the right person to help you resolve this.",
 
32
  "other": "Thank you for your call. I'll make sure your message gets to the right person."
33
  }
34
 
35
+ # Simple document storage (in-memory for this example)
36
+ knowledge_base = []
37
+
38
  # Create a classifier
39
  try:
40
  classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
 
63
  return "other", 0.0
64
 
65
  def load_pdf(file):
66
+ """Load a PDF document into the knowledge base"""
 
 
67
  try:
68
  # Save the uploaded file temporarily
69
  temp_dir = tempfile.mkdtemp()
 
78
  with open(temp_path, "rb") as src:
79
  f.write(src.read())
80
 
81
+ # In a real implementation, we would extract text and add to vector store
82
+ # For this simplified version, we'll just store the file name
83
+ knowledge_base.append({"type": "pdf", "name": file.name, "path": target_path})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
+ return f"Successfully added {file.name} to the knowledge base."
86
 
87
  except Exception as e:
88
  return f"Error processing PDF: {str(e)}"
89
 
90
  def load_website(url):
91
+ """Load a website into the knowledge base"""
 
 
92
  try:
93
+ # In a real implementation, we would fetch and process the website
94
+ # For this simplified version, we'll just store the URL
95
+ knowledge_base.append({"type": "website", "url": url})
96
 
97
  # Save the URL reference
98
  with open(os.path.join(DOCUMENTS_DIR, "websites.txt"), "a") as f:
99
  f.write(f"{url}\n")
100
 
101
+ return f"Successfully added {url} to the knowledge base."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  except Exception as e:
104
  return f"Error processing website: {str(e)}"
105
 
106
  def generate_response(query, intent=None):
107
  """Generate a response based on the query and intent"""
 
 
108
  # If no intent provided, use a default
109
  if not intent or intent not in POSSIBLE_INTENTS:
110
  intent = "general_information"
111
 
112
+ # For this simplified version, we'll just use the default responses
113
+ # In a real implementation, we would search the knowledge base
114
+ return DEFAULT_RESPONSES.get(intent, DEFAULT_RESPONSES["other"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  def list_documents():
117
  """List all documents in the knowledge base"""
 
129
  "Websites": websites
130
  }
131
 
132
+ # Twilio voice handlers
133
+ def twilio_call_handler():
134
+ """Handle incoming Twilio calls"""
135
+ twiml = """<?xml version="1.0" encoding="UTF-8"?>
136
+ <Response>
137
+ <Say>Hello! Thank you for calling. How can I help you today?</Say>
138
+ <Gather input="speech" action="https://huggingface.co/spaces/iajitpanday/vBot-1.5/api/twilio/speech" method="POST" speechTimeout="auto" speechModel="phone_call"/>
139
+ <Say>I didn't hear anything. Please call back when you're ready.</Say>
140
+ </Response>
141
+ """
142
+ return twiml
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
+ def twilio_speech_handler(speech_result=""):
145
+ """Process speech from Twilio"""
146
+ intent, _ = classify_intent(speech_result)
147
+ response = generate_response(speech_result, intent)
 
 
148
 
 
149
  twiml = f"""<?xml version="1.0" encoding="UTF-8"?>
150
  <Response>
151
  <Say>{response}</Say>
 
157
  """
158
  return twiml
159
 
160
+ def twilio_followup_handler(speech_result=""):
161
+ """Handle follow-up responses"""
162
+ if any(word in speech_result.lower() for word in ["yes", "yeah", "sure", "please", "correct"]):
163
  twiml = """<?xml version="1.0" encoding="UTF-8"?>
164
  <Response>
165
  <Say>Great! How else can I help you today?</Say>
 
175
  """
176
  return twiml
177
 
 
 
 
 
 
 
 
 
 
 
 
178
  # Create Gradio interface
179
+ with gr.Blocks(title="Call Assistant System") as demo:
180
+ gr.Markdown("# Call Assistant System")
181
  gr.Markdown("Add documents and websites to the knowledge base, and test the response generation.")
182
 
183
  with gr.Tab("Add Knowledge"):
 
236
  gr.Markdown("""
237
  ## Twilio Integration Instructions
238
 
239
+ This app provides API endpoints for Twilio voice integration. Follow these steps to set up:
240
 
241
  1. Log into your Twilio account
242
  2. Go to Phone Numbers → Manage → Active numbers
243
  3. Select your number (+19704064410)
244
+ 4. For "A Call Comes In", set "Webhook" to:
245
  - URL: `https://huggingface.co/spaces/iajitpanday/vBot-1.5/api/twilio/call`
246
  - Method: HTTP POST
247
 
248
+ The system will:
249
  - Answer incoming calls
250
  - Process speech input
251
  - Generate responses using your knowledge base
252
  - Handle follow-up questions
253
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
+ # API endpoints for Twilio
256
  def api_twilio_call():
257
+ """API endpoint for call handling"""
258
  return twilio_call_handler()
259
 
260
+ def api_twilio_speech(SpeechResult=""):
261
+ """API endpoint for speech processing"""
262
+ return twilio_speech_handler(SpeechResult)
263
 
264
+ def api_twilio_followup(SpeechResult=""):
265
+ """API endpoint for follow-up handling"""
266
+ return twilio_followup_handler(SpeechResult)
267
 
268
+ # Launch the interface
269
  demo.queue()
270
  demo.launch()