bhagyabonam commited on
Commit
cc9bba2
·
verified ·
1 Parent(s): ef26e0a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -71
app.py CHANGED
@@ -14,16 +14,11 @@ import matplotlib.pyplot as plt
14
  from huggingface_hub import login
15
  import os
16
  from dotenv import load_dotenv
17
- import threading
18
-
19
 
20
  SPREADSHEET_ID = "1CsBub3Jlwyo7WHMQty6SDnBShIZMjl5XTVSoOKrxZhc"
21
  RANGE_NAME = 'Sheet1!A1:E'
22
  SERVICE_ACCOUNT_FILE = r"C:\Users\bhagy\AI\credentials.json"
23
-
24
-
25
- csv_file_path = r"C:\Users\bhagy\Downloads\900_products_dataset.csv"
26
-
27
 
28
  class CustomEmbeddingFunction:
29
  def __init__(self, model_name="sentence-transformers/all-MiniLM-L6-v2"):
@@ -37,14 +32,8 @@ class CustomEmbeddingFunction:
37
  embeddings = outputs.last_hidden_state.mean(dim=1).squeeze().numpy()
38
  return embeddings
39
 
40
-
41
- sentiment_pipeline = pipeline("sentiment-analysis")
42
- # persist_directory = "chromadb_storage"
43
- # chroma_client = PersistentClient(path=persist_directory)
44
  persist_directory = "chromadb_storage"
45
- os.makedirs(persist_directory, exist_ok=True) # Ensure the directory exists
46
  chroma_client = PersistentClient(path=persist_directory)
47
-
48
  collection_name = "crm_data"
49
 
50
  try:
@@ -92,7 +81,7 @@ hf_token= os.getenv("HUGGINGFACE_TOKEN")
92
  login(token=hf_token)
93
  if not hf_token:
94
  raise ValueError("Hugging Face API key not found! Please set the HUGGINGFACE_TOKEN variable.")
95
- print(f"API Key Loaded: {hf_token[:5]}****")
96
 
97
  model_name = "tabularisai/multilingual-sentiment-analysis"
98
  model = AutoModelForSequenceClassification.from_pretrained(model_name)
@@ -110,8 +99,6 @@ def analyze_sentiment(text):
110
  result = sentiment_analyzer(processed_text)[0]
111
 
112
  print(f"Sentiment Analysis Result: {result}")
113
-
114
-
115
  sentiment_map = {
116
  'Very Negative': "NEGATIVE",
117
  'Negative': "NEGATIVE",
@@ -134,17 +121,13 @@ def load_csv(file_path):
134
  if data is not None:
135
  st.session_state.crm_data = data
136
  print("CRM data loaded successfully!")
137
- return data
138
- else:
139
- st.error("Failed to load CRM data: File is empty or invalid.")
140
  except Exception as e:
141
- st.error(f"Error loading CSV: {e}")
142
  print(f"Error loading CSV: {e}")
143
  return None
144
 
145
  data = load_csv(csv_file_path)
146
 
147
-
148
  def process_crm_data(data):
149
  try:
150
  chunks = [str(row) for row in data.to_dict(orient="records")]
@@ -186,8 +169,6 @@ def query_crm_data_with_context(prompt, top_k=3):
186
  st.error(f"Error querying CRM data: {e}")
187
  return ["Error in querying recommendations."]
188
 
189
-
190
-
191
  sentence_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
192
  faiss_index = faiss.IndexFlatL2(384)
193
 
@@ -202,13 +183,8 @@ def load_objection_responses(csv_file_path):
202
 
203
  objection_response_pairs = load_objection_responses(r"C:\Users\bhagy\OneDrive\Desktop\INFOSYS PROJECT\objections_responses.csv")
204
  objections = list(objection_response_pairs.keys())
205
- # objection_embeddings = sentence_model.encode(objections)
206
- # faiss_index.add(np.array(objection_embeddings, dtype="float32"))
207
-
208
  objection_embeddings = sentence_model.encode(objections)
209
- objection_embeddings = objection_embeddings.reshape(-1, 384) # Reshape to 2D array
210
- faiss_index.add(objection_embeddings.astype("float32"))
211
-
212
 
213
  def find_closest_objection(query):
214
  query_embedding = sentence_model.encode([query])
@@ -300,7 +276,7 @@ def generate_comprehensive_summary(chunks):
300
  summary += f"• Neutral Interactions: {neutral_count}\n"
301
 
302
  summary += "\nKey Conversation Points:\n"
303
- for interaction in key_interactions[:3]: # Limit to top 3 key points
304
  summary += f"• {interaction}\n"
305
 
306
  if positive_count > negative_count:
@@ -325,8 +301,8 @@ def show_help():
325
 
326
  st.header("1. Introduction to the AI Assistant")
327
  st.write("""
328
- - **What It Does**: The assistant analyzes live sales calls in real-time. It detects sentiment shifts, provides product recommendations, and suggests dynamic question handling techniques.
329
- - **Key Features**:
330
  - Real-time speech-to-text conversion and sentiment analysis.
331
  - Product recommendations based on customer context.
332
  - Dynamic question prompt generator.
@@ -336,58 +312,58 @@ def show_help():
336
 
337
  st.header("2. Getting Started")
338
  st.write("""
339
- - **How to Start a Call**: To start a sales call, Click on Start Listening. Once connected, initiate the call, and the assistant will begin analyzing.
340
- - **What to Expect**: During the call, the assistant will provide real-time feedback, such as sentiment scores, product recommendations, and objection handling tips.
341
  """)
342
 
343
  st.header("3. Using the Assistant During Sales Calls")
344
  st.write("""
345
- - **Speech-to-Text Instructions**: Speak clearly into your microphone for the assistant to accurately capture and analyze your speech.
346
- - **Real-time Feedback**: The assistant will display real-time feedback on the sentiment of the conversation, suggest responses for objections, and provide product recommendations.
347
  """)
348
 
349
 
350
  st.header("4. Understanding the Interface")
351
  st.write("""
352
- - **Tabs Navigation**: The interface has different tabs:
353
- - **Call Summary**: After the call, review the summary, which highlights conversation key points.
354
- - **Sentiment Analysis**: See how the sentiment changed throughout the conversation.
355
- - **Product Recommendations**: View the recommended products based on customer intent and conversation context.
356
  """)
357
 
358
 
359
  st.header("5. FAQs and Troubleshooting")
360
  st.write("""
361
- - **Sentiment Detection Accuracy**: If the assistant's sentiment analysis isn't accurate, ensure you speak clearly and avoid background noise.
362
- - **Speech Recognition Issues**: Rephrase unclear statements and ensure the microphone is working well.
363
- - **Context Handling**: If the assistant misses some context, remind it of the product or the customer’s intent.
364
  """)
365
 
366
 
367
  st.header("6. Support and Contact Information")
368
  st.write("""
369
- - **Live Chat Support**: Chat with us in real-time by clicking the support icon in the bottom right.
370
- - **Email and Phone Support**: You can also reach us at [email protected] or call us at +1-800-555-1234.
371
- - **Feedback**: Please provide feedback to help us improve the assistant.
372
  """)
373
 
374
  st.header("7. Advanced Features")
375
  st.write("""
376
- - **Integration with CRM and Google Sheets**: Sync with CRM systems and Google Sheets to enhance product recommendations.
377
- - **Customization Options**: Customize the assistant’s tone, product categories, and question prompts through the settings tab.
378
  """)
379
 
380
  st.header("8. Privacy and Security")
381
  st.write("""
382
- - **Data Privacy**: All conversations are anonymized for analysis purposes. We ensure compliance with privacy regulations.
383
- - **Security Protocols**: All data is encrypted and stored securely.
384
  """)
385
 
386
 
387
  st.header("9. Updates and New Features")
388
  st.write("""
389
- - **Changelog**: We release regular updates to improve performance. Please refer to the changelog for new features and improvements.
390
- - **How to Update**: If an update is available, follow the instructions in the settings tab to install the latest version.
391
  """)
392
  def calculate_overall_sentiment(sentiment_scores):
393
  if sentiment_scores:
@@ -418,14 +394,14 @@ def process_real_time_audio():
418
 
419
 
420
  st.write("Transcribing audio...")
421
- transcribed_text = recognizer.recognize_sphinx(audio)
422
  st.write(f"You said: {transcribed_text}")
423
 
424
  if 'stop' in transcribed_text.lower():
425
  st.warning("Stopping the speech recognition process.")
426
  break
427
 
428
- st.markdown("### **Sentiment Analysis**")
429
  sentiment_label, sentiment_score = analyze_sentiment(transcribed_text)
430
  st.write(f"Sentiment: {sentiment_label}")
431
  st.write(f"Sentiment Score: {sentiment_score}")
@@ -434,15 +410,15 @@ def process_real_time_audio():
434
  response = None
435
 
436
  add_to_sentiment_history(transcribed_text, sentiment_label, sentiment_score, closest_objection, response)
437
- st.markdown("### **Recommendations**")
438
  recommendations = query_crm_data_with_context(transcribed_text)
439
  for i, rec in enumerate(recommendations, start=1):
440
  if isinstance(rec, dict) and 'Product' in rec and 'Recommendations' in rec:
441
- st.markdown(f"- **{rec['Product']}**: {rec['Recommendations']}")
442
  else:
443
  st.markdown(f"- {rec}")
444
 
445
- st.markdown("### **Objection Handling**")
446
  closest_objection, response = find_closest_objection(transcribed_text)
447
  st.write(f"Objection: {closest_objection}")
448
  st.write(f" Response: {response}")
@@ -460,8 +436,6 @@ def process_real_time_audio():
460
  except Exception as e:
461
  st.error(f"Error: {e}")
462
  break
463
- speech_thread = threading.Thread(target=recognize_speech, daemon=True)
464
- speech_thread.start()
465
 
466
  def generate_sentiment_pie_chart(sentiment_history):
467
  if not sentiment_history:
@@ -490,7 +464,7 @@ def generate_sentiment_pie_chart(sentiment_history):
490
  ax.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90, colors=colors,textprops={'fontsize':12, 'color':'white'})
491
  fig.patch.set_facecolor('none')
492
  ax.axis('equal')
493
- st.markdown("### *Sentiment Distribution*")
494
  st.pyplot(fig)
495
 
496
  def generate_post_call_summary(sentiment_history, recommendations=[]):
@@ -503,7 +477,6 @@ def generate_post_call_summary(sentiment_history, recommendations=[]):
503
  summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
504
  combined_text = " ".join([item["Text"] for item in sentiment_history])
505
 
506
- # summary = summarizer(combined_text, max_length=100, min_length=30, do_sample=False)[0]["summary_text"]
507
  scores = [item["Score"] for item in sentiment_history]
508
 
509
  st.markdown("## Summary of the Call")
@@ -511,7 +484,7 @@ def generate_post_call_summary(sentiment_history, recommendations=[]):
511
  summary = generate_comprehensive_summary(chunks)
512
  st.write(summary)
513
 
514
- st.markdown("### **Overall Sentiment for the Call**")
515
  sentiment_scores = [entry["Score"] for entry in sentiment_history]
516
  overall_sentiment = calculate_overall_sentiment(sentiment_scores)
517
  st.write(f"Overall Sentiment: {overall_sentiment}")
@@ -522,7 +495,7 @@ def generate_post_call_summary(sentiment_history, recommendations=[]):
522
  plt.figure(figsize=(10, 6))
523
  plt.bar(range(len(sentiment_scores)), sentiment_scores, color=colors)
524
  plt.axhline(0, color='black', linestyle='--', linewidth=1, label='Neutral')
525
- st.markdown("### **Sentiment Trend Bar Chart**")
526
  plt.title("Sentiment Trend Throughout the Call")
527
  plt.xlabel("Segment")
528
  plt.ylabel("Sentiment Score")
@@ -533,7 +506,7 @@ def generate_post_call_summary(sentiment_history, recommendations=[]):
533
  with col2:
534
  generate_sentiment_pie_chart(sentiment_history)
535
 
536
- st.markdown("### **Future Insights**")
537
 
538
 
539
  if overall_sentiment == "Negative":
@@ -545,28 +518,26 @@ def generate_post_call_summary(sentiment_history, recommendations=[]):
545
 
546
 
547
  if recommendations:
548
- st.write("### **Product Recommendations**")
549
  for rec in recommendations:
550
  st.write(f"- {rec}")
551
 
552
  if sentiment_history:
553
- st.write("### **Sentiment Breakdown by Segment**")
554
  for idx, entry in enumerate(sentiment_history, 1):
555
  st.write(f"Segment {idx}: Sentiment = {entry['Sentiment']}, Score = {entry['Score']:.2f}")
556
 
557
- # Main
558
  def main():
559
  st.title("🤖 RealTime AI-Powered Sales Assistant For Enhanced Conversation")
560
  st.markdown(
561
  "An intelligent assistant to analyze speech, handle objections, and recommend products in real-time."
562
  )
563
 
564
- # Tabs for navigation
565
- tabs = st.tabs(["🎙️ Real-Time Audio", "📊 Text Search ", "📋 Visualization","🕘 Query History","❓Help","💬 Feedback"])
566
 
567
 
568
  with tabs[0]:
569
- st.header("🎙️ Real-Time Audio Analysis")
570
  st.write(
571
  "Use this feature to analyze live speech, perform sentiment analysis, and get product recommendations."
572
  )
@@ -610,7 +581,6 @@ def main():
610
  st.dataframe(st.session_state["crm_history"])
611
 
612
  with tabs[4]:
613
- # st.subheader("❓Help")
614
  show_help()
615
 
616
  with tabs[5]:
@@ -623,7 +593,6 @@ def main():
623
  st.session_state["app_feedback"].append(feedback)
624
  st.success("Thank you for your feedback!")
625
 
626
- # Display previous feedback
627
  if st.session_state["app_feedback"]:
628
  st.write("### Previous Feedback:")
629
  for idx, feedback_entry in enumerate(st.session_state["app_feedback"], 1):
 
14
  from huggingface_hub import login
15
  import os
16
  from dotenv import load_dotenv
 
 
17
 
18
  SPREADSHEET_ID = "1CsBub3Jlwyo7WHMQty6SDnBShIZMjl5XTVSoOKrxZhc"
19
  RANGE_NAME = 'Sheet1!A1:E'
20
  SERVICE_ACCOUNT_FILE = r"C:\Users\bhagy\AI\credentials.json"
21
+ csv_file_path = r"C:\Users\bhagy\OneDrive\Desktop\INFOSYS PROJECT\900_products_dataset.csv"
 
 
 
22
 
23
  class CustomEmbeddingFunction:
24
  def __init__(self, model_name="sentence-transformers/all-MiniLM-L6-v2"):
 
32
  embeddings = outputs.last_hidden_state.mean(dim=1).squeeze().numpy()
33
  return embeddings
34
 
 
 
 
 
35
  persist_directory = "chromadb_storage"
 
36
  chroma_client = PersistentClient(path=persist_directory)
 
37
  collection_name = "crm_data"
38
 
39
  try:
 
81
  login(token=hf_token)
82
  if not hf_token:
83
  raise ValueError("Hugging Face API key not found! Please set the HUGGINGFACE_TOKEN variable.")
84
+ print(f"API Key Loaded: {hf_token[:5]}")
85
 
86
  model_name = "tabularisai/multilingual-sentiment-analysis"
87
  model = AutoModelForSequenceClassification.from_pretrained(model_name)
 
99
  result = sentiment_analyzer(processed_text)[0]
100
 
101
  print(f"Sentiment Analysis Result: {result}")
 
 
102
  sentiment_map = {
103
  'Very Negative': "NEGATIVE",
104
  'Negative': "NEGATIVE",
 
121
  if data is not None:
122
  st.session_state.crm_data = data
123
  print("CRM data loaded successfully!")
124
+ return data
 
 
125
  except Exception as e:
 
126
  print(f"Error loading CSV: {e}")
127
  return None
128
 
129
  data = load_csv(csv_file_path)
130
 
 
131
  def process_crm_data(data):
132
  try:
133
  chunks = [str(row) for row in data.to_dict(orient="records")]
 
169
  st.error(f"Error querying CRM data: {e}")
170
  return ["Error in querying recommendations."]
171
 
 
 
172
  sentence_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
173
  faiss_index = faiss.IndexFlatL2(384)
174
 
 
183
 
184
  objection_response_pairs = load_objection_responses(r"C:\Users\bhagy\OneDrive\Desktop\INFOSYS PROJECT\objections_responses.csv")
185
  objections = list(objection_response_pairs.keys())
 
 
 
186
  objection_embeddings = sentence_model.encode(objections)
187
+ faiss_index.add(np.array(objection_embeddings, dtype="float32"))
 
 
188
 
189
  def find_closest_objection(query):
190
  query_embedding = sentence_model.encode([query])
 
276
  summary += f"• Neutral Interactions: {neutral_count}\n"
277
 
278
  summary += "\nKey Conversation Points:\n"
279
+ for interaction in key_interactions[:3]:
280
  summary += f"• {interaction}\n"
281
 
282
  if positive_count > negative_count:
 
301
 
302
  st.header("1. Introduction to the AI Assistant")
303
  st.write("""
304
+ - *What It Does*: The assistant analyzes live sales calls in real-time. It detects sentiment shifts, provides product recommendations, and suggests dynamic question handling techniques.
305
+ - *Key Features*:
306
  - Real-time speech-to-text conversion and sentiment analysis.
307
  - Product recommendations based on customer context.
308
  - Dynamic question prompt generator.
 
312
 
313
  st.header("2. Getting Started")
314
  st.write("""
315
+ - *How to Start a Call*: To start a sales call, Click on Start Listening. Once connected, initiate the call, and the assistant will begin analyzing.
316
+ - *What to Expect*: During the call, the assistant will provide real-time feedback, such as sentiment scores, product recommendations, and objection handling tips.
317
  """)
318
 
319
  st.header("3. Using the Assistant During Sales Calls")
320
  st.write("""
321
+ - *Speech-to-Text Instructions*: Speak clearly into your microphone for the assistant to accurately capture and analyze your speech.
322
+ - *Real-time Feedback*: The assistant will display real-time feedback on the sentiment of the conversation, suggest responses for objections, and provide product recommendations.
323
  """)
324
 
325
 
326
  st.header("4. Understanding the Interface")
327
  st.write("""
328
+ - *Tabs Navigation*: The interface has different tabs:
329
+ - *Call Summary*: After the call, review the summary, which highlights conversation key points.
330
+ - *Sentiment Analysis*: See how the sentiment changed throughout the conversation.
331
+ - *Product Recommendations*: View the recommended products based on customer intent and conversation context.
332
  """)
333
 
334
 
335
  st.header("5. FAQs and Troubleshooting")
336
  st.write("""
337
+ - *Sentiment Detection Accuracy*: If the assistant's sentiment analysis isn't accurate, ensure you speak clearly and avoid background noise.
338
+ - *Speech Recognition Issues*: Rephrase unclear statements and ensure the microphone is working well.
339
+ - *Context Handling*: If the assistant misses some context, remind it of the product or the customer’s intent.
340
  """)
341
 
342
 
343
  st.header("6. Support and Contact Information")
344
  st.write("""
345
+ - *Live Chat Support*: Chat with us in real-time by clicking the support icon in the bottom right.
346
+ - *Email and Phone Support*: You can also reach us at [email protected] or call us at +1-800-555-1234.
347
+ - *Feedback*: Please provide feedback to help us improve the assistant.
348
  """)
349
 
350
  st.header("7. Advanced Features")
351
  st.write("""
352
+ - *Integration with CRM and Google Sheets*: Sync with CRM systems and Google Sheets to enhance product recommendations.
353
+ - *Customization Options*: Customize the assistant’s tone, product categories, and question prompts through the settings tab.
354
  """)
355
 
356
  st.header("8. Privacy and Security")
357
  st.write("""
358
+ - *Data Privacy*: All conversations are anonymized for analysis purposes. We ensure compliance with privacy regulations.
359
+ - *Security Protocols*: All data is encrypted and stored securely.
360
  """)
361
 
362
 
363
  st.header("9. Updates and New Features")
364
  st.write("""
365
+ - *Changelog*: We release regular updates to improve performance. Please refer to the changelog for new features and improvements.
366
+ - *How to Update*: If an update is available, follow the instructions in the settings tab to install the latest version.
367
  """)
368
  def calculate_overall_sentiment(sentiment_scores):
369
  if sentiment_scores:
 
394
 
395
 
396
  st.write("Transcribing audio...")
397
+ transcribed_text = recognizer.recognize_google(audio)
398
  st.write(f"You said: {transcribed_text}")
399
 
400
  if 'stop' in transcribed_text.lower():
401
  st.warning("Stopping the speech recognition process.")
402
  break
403
 
404
+ st.markdown("### *Sentiment Analysis*")
405
  sentiment_label, sentiment_score = analyze_sentiment(transcribed_text)
406
  st.write(f"Sentiment: {sentiment_label}")
407
  st.write(f"Sentiment Score: {sentiment_score}")
 
410
  response = None
411
 
412
  add_to_sentiment_history(transcribed_text, sentiment_label, sentiment_score, closest_objection, response)
413
+ st.markdown("### *Recommendations*")
414
  recommendations = query_crm_data_with_context(transcribed_text)
415
  for i, rec in enumerate(recommendations, start=1):
416
  if isinstance(rec, dict) and 'Product' in rec and 'Recommendations' in rec:
417
+ st.markdown(f"- *{rec['Product']}*: {rec['Recommendations']}")
418
  else:
419
  st.markdown(f"- {rec}")
420
 
421
+ st.markdown("### *Objection Handling*")
422
  closest_objection, response = find_closest_objection(transcribed_text)
423
  st.write(f"Objection: {closest_objection}")
424
  st.write(f" Response: {response}")
 
436
  except Exception as e:
437
  st.error(f"Error: {e}")
438
  break
 
 
439
 
440
  def generate_sentiment_pie_chart(sentiment_history):
441
  if not sentiment_history:
 
464
  ax.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90, colors=colors,textprops={'fontsize':12, 'color':'white'})
465
  fig.patch.set_facecolor('none')
466
  ax.axis('equal')
467
+ st.markdown("### Sentiment Distribution")
468
  st.pyplot(fig)
469
 
470
  def generate_post_call_summary(sentiment_history, recommendations=[]):
 
477
  summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
478
  combined_text = " ".join([item["Text"] for item in sentiment_history])
479
 
 
480
  scores = [item["Score"] for item in sentiment_history]
481
 
482
  st.markdown("## Summary of the Call")
 
484
  summary = generate_comprehensive_summary(chunks)
485
  st.write(summary)
486
 
487
+ st.markdown("### *Overall Sentiment for the Call*")
488
  sentiment_scores = [entry["Score"] for entry in sentiment_history]
489
  overall_sentiment = calculate_overall_sentiment(sentiment_scores)
490
  st.write(f"Overall Sentiment: {overall_sentiment}")
 
495
  plt.figure(figsize=(10, 6))
496
  plt.bar(range(len(sentiment_scores)), sentiment_scores, color=colors)
497
  plt.axhline(0, color='black', linestyle='--', linewidth=1, label='Neutral')
498
+ st.markdown("### *Sentiment Trend Bar Chart*")
499
  plt.title("Sentiment Trend Throughout the Call")
500
  plt.xlabel("Segment")
501
  plt.ylabel("Sentiment Score")
 
506
  with col2:
507
  generate_sentiment_pie_chart(sentiment_history)
508
 
509
+ st.markdown("### *Future Insights*")
510
 
511
 
512
  if overall_sentiment == "Negative":
 
518
 
519
 
520
  if recommendations:
521
+ st.write("### *Product Recommendations*")
522
  for rec in recommendations:
523
  st.write(f"- {rec}")
524
 
525
  if sentiment_history:
526
+ st.write("### *Sentiment Breakdown by Segment*")
527
  for idx, entry in enumerate(sentiment_history, 1):
528
  st.write(f"Segment {idx}: Sentiment = {entry['Sentiment']}, Score = {entry['Score']:.2f}")
529
 
 
530
  def main():
531
  st.title("🤖 RealTime AI-Powered Sales Assistant For Enhanced Conversation")
532
  st.markdown(
533
  "An intelligent assistant to analyze speech, handle objections, and recommend products in real-time."
534
  )
535
 
536
+ tabs = st.tabs(["🎙 Real-Time Audio", "📊 Text Search ", "📋 Visualization","🕘 Query History","❓Help","💬 Feedback"])
 
537
 
538
 
539
  with tabs[0]:
540
+ st.header("🎙 Real-Time Audio Analysis")
541
  st.write(
542
  "Use this feature to analyze live speech, perform sentiment analysis, and get product recommendations."
543
  )
 
581
  st.dataframe(st.session_state["crm_history"])
582
 
583
  with tabs[4]:
 
584
  show_help()
585
 
586
  with tabs[5]:
 
593
  st.session_state["app_feedback"].append(feedback)
594
  st.success("Thank you for your feedback!")
595
 
 
596
  if st.session_state["app_feedback"]:
597
  st.write("### Previous Feedback:")
598
  for idx, feedback_entry in enumerate(st.session_state["app_feedback"], 1):