Zasha1 commited on
Commit
ecaceca
·
verified ·
1 Parent(s): 4455a91

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +295 -295
app.py CHANGED
@@ -1,295 +1,295 @@
1
- import speech_recognition as sr
2
- from sentiment_analysis import analyze_sentiment
3
- from product_recommender import ProductRecommender
4
- from objection_handler import ObjectionHandler
5
- from google_sheets import fetch_call_data, store_data_in_sheet
6
- from sentence_transformers import SentenceTransformer
7
- from env_setup import config
8
- import re
9
- import uuid
10
- from google.oauth2 import service_account
11
- from googleapiclient.discovery import build
12
- import pandas as pd
13
- import plotly.express as px
14
- import plotly.graph_objs as go
15
- import streamlit as st
16
-
17
- # Initialize components
18
- product_recommender = ProductRecommender(r"C:\Users\shaik\Downloads\Sales Calls Transcriptions - Sheet2.csv")
19
- objection_handler = ObjectionHandler(r"C:\Users\shaik\Downloads\Sales Calls Transcriptions - Sheet3.csv")
20
- model = SentenceTransformer('all-MiniLM-L6-v2')
21
-
22
- def generate_comprehensive_summary(chunks):
23
- """
24
- Generate a comprehensive summary from conversation chunks
25
- """
26
- # Extract full text from chunks
27
- full_text = " ".join([chunk[0] for chunk in chunks])
28
-
29
- # Perform basic analysis
30
- total_chunks = len(chunks)
31
- sentiments = [chunk[1] for chunk in chunks]
32
-
33
- # Determine overall conversation context
34
- context_keywords = {
35
- 'product_inquiry': ['dress', 'product', 'price', 'stock'],
36
- 'pricing': ['cost', 'price', 'budget'],
37
- 'negotiation': ['installment', 'payment', 'manage']
38
- }
39
-
40
- # Detect conversation themes
41
- themes = []
42
- for keyword_type, keywords in context_keywords.items():
43
- if any(keyword.lower() in full_text.lower() for keyword in keywords):
44
- themes.append(keyword_type)
45
-
46
- # Basic sentiment analysis
47
- positive_count = sentiments.count('POSITIVE')
48
- negative_count = sentiments.count('NEGATIVE')
49
- neutral_count = sentiments.count('NEUTRAL')
50
-
51
- # Key interaction highlights
52
- key_interactions = []
53
- for chunk in chunks:
54
- if any(keyword.lower() in chunk[0].lower() for keyword in ['price', 'dress', 'stock', 'installment']):
55
- key_interactions.append(chunk[0])
56
-
57
- # Construct summary
58
- summary = f"Conversation Summary:\n"
59
-
60
- # Context and themes
61
- if 'product_inquiry' in themes:
62
- summary += "• Customer initiated a product inquiry about items.\n"
63
-
64
- if 'pricing' in themes:
65
- summary += "• Price and budget considerations were discussed.\n"
66
-
67
- if 'negotiation' in themes:
68
- summary += "• Customer and seller explored flexible payment options.\n"
69
-
70
- # Sentiment insights
71
- summary += f"\nConversation Sentiment:\n"
72
- summary += f"• Positive Interactions: {positive_count}\n"
73
- summary += f"• Negative Interactions: {negative_count}\n"
74
- summary += f"• Neutral Interactions: {neutral_count}\n"
75
-
76
- # Key highlights
77
- summary += "\nKey Conversation Points:\n"
78
- for interaction in key_interactions[:3]: # Limit to top 3 key points
79
- summary += f"• {interaction}\n"
80
-
81
- # Conversation outcome
82
- if positive_count > negative_count:
83
- summary += "\nOutcome: Constructive and potentially successful interaction."
84
- elif negative_count > positive_count:
85
- summary += "\nOutcome: Interaction may require further follow-up."
86
- else:
87
- summary += "\nOutcome: Neutral interaction with potential for future engagement."
88
-
89
- return summary
90
-
91
- def is_valid_input(text):
92
- text = text.strip().lower()
93
- if len(text) < 3 or re.match(r'^[a-zA-Z\s]*$', text) is None:
94
- return False
95
- return True
96
-
97
- def is_relevant_sentiment(sentiment_score):
98
- return sentiment_score > 0.4
99
-
100
- def calculate_overall_sentiment(sentiment_scores):
101
- if sentiment_scores:
102
- average_sentiment = sum(sentiment_scores) / len(sentiment_scores)
103
- overall_sentiment = (
104
- "POSITIVE" if average_sentiment > 0 else
105
- "NEGATIVE" if average_sentiment < 0 else
106
- "NEUTRAL"
107
- )
108
- else:
109
- overall_sentiment = "NEUTRAL"
110
- return overall_sentiment
111
-
112
- def real_time_analysis():
113
- recognizer = sr.Recognizer()
114
- mic = sr.Microphone()
115
-
116
- st.info("Say 'stop' to end the process.")
117
-
118
- sentiment_scores = []
119
- transcribed_chunks = []
120
- total_text = ""
121
-
122
- try:
123
- while True:
124
- with mic as source:
125
- st.write("Listening...")
126
- recognizer.adjust_for_ambient_noise(source)
127
- audio = recognizer.listen(source)
128
-
129
- try:
130
- st.write("Recognizing...")
131
- text = recognizer.recognize_google(audio)
132
- st.write(f"*Recognized Text:* {text}")
133
-
134
- if 'stop' in text.lower():
135
- st.write("Stopping real-time analysis...")
136
- break
137
-
138
- # Append to the total conversation
139
- total_text += text + " "
140
- sentiment, score = analyze_sentiment(text)
141
- sentiment_scores.append(score)
142
-
143
- # Handle objection
144
- objection_response = handle_objection(text)
145
-
146
- # Get product recommendation
147
- recommendations = []
148
- if is_valid_input(text) and is_relevant_sentiment(score):
149
- query_embedding = model.encode([text])
150
- distances, indices = product_recommender.index.search(query_embedding, 1)
151
-
152
- if distances[0][0] < 1.5: # Similarity threshold
153
- recommendations = product_recommender.get_recommendations(text)
154
-
155
- transcribed_chunks.append((text, sentiment, score))
156
-
157
- st.write(f"*Sentiment:* {sentiment} (Score: {score})")
158
- st.write(f"*Objection Response:* {objection_response}")
159
-
160
- if recommendations:
161
- st.write("*Product Recommendations:*")
162
- for rec in recommendations:
163
- st.write(rec)
164
-
165
- except sr.UnknownValueError:
166
- st.error("Speech Recognition could not understand the audio.")
167
- except sr.RequestError as e:
168
- st.error(f"Error with the Speech Recognition service: {e}")
169
- except Exception as e:
170
- st.error(f"Error during processing: {e}")
171
-
172
- # After conversation ends, calculate and display overall sentiment and summary
173
- overall_sentiment = calculate_overall_sentiment(sentiment_scores)
174
- call_summary = generate_comprehensive_summary(transcribed_chunks)
175
-
176
- st.subheader("Conversation Summary:")
177
- st.write(total_text.strip())
178
- st.subheader("Overall Sentiment:")
179
- st.write(overall_sentiment)
180
-
181
- # Store data in Google Sheets
182
- store_data_in_sheet(
183
- config["google_sheet_id"],
184
- transcribed_chunks,
185
- call_summary,
186
- overall_sentiment
187
- )
188
- st.success("Conversation data stored successfully in Google Sheets!")
189
-
190
- except Exception as e:
191
- st.error(f"Error in real-time analysis: {e}")
192
-
193
- def handle_objection(text):
194
- query_embedding = model.encode([text])
195
- distances, indices = objection_handler.index.search(query_embedding, 1)
196
- if distances[0][0] < 1.5: # Adjust similarity threshold as needed
197
- responses = objection_handler.handle_objection(text)
198
- return "\n".join(responses) if responses else "No objection response found."
199
- return "No objection response found."
200
-
201
- # (Previous imports remain the same)
202
-
203
- def run_app():
204
- st.set_page_config(page_title="Sales Call Assistant", layout="wide")
205
- st.title("AI Sales Call Assistant")
206
-
207
- st.sidebar.title("Navigation")
208
- app_mode = st.sidebar.radio("Choose a mode:", ["Real-Time Call Analysis", "Dashboard"])
209
-
210
- if app_mode == "Real-Time Call Analysis":
211
- st.header("Real-Time Sales Call Analysis")
212
- if st.button("Start Listening"):
213
- real_time_analysis()
214
-
215
- elif app_mode == "Dashboard":
216
- st.header("Call Summaries and Sentiment Analysis")
217
- try:
218
- data = fetch_call_data(config["google_sheet_id"])
219
- if data.empty:
220
- st.warning("No data available in the Google Sheet.")
221
- else:
222
- # Sentiment Visualizations
223
- sentiment_counts = data['Sentiment'].value_counts()
224
-
225
- # Pie Chart
226
- col1, col2 = st.columns(2)
227
- with col1:
228
- st.subheader("Sentiment Distribution")
229
- fig_pie = px.pie(
230
- values=sentiment_counts.values,
231
- names=sentiment_counts.index,
232
- title='Call Sentiment Breakdown',
233
- color_discrete_map={
234
- 'POSITIVE': 'green',
235
- 'NEGATIVE': 'red',
236
- 'NEUTRAL': 'blue'
237
- }
238
- )
239
- st.plotly_chart(fig_pie)
240
-
241
- # Bar Chart
242
- with col2:
243
- st.subheader("Sentiment Counts")
244
- fig_bar = px.bar(
245
- x=sentiment_counts.index,
246
- y=sentiment_counts.values,
247
- title='Number of Calls by Sentiment',
248
- labels={'x': 'Sentiment', 'y': 'Number of Calls'},
249
- color=sentiment_counts.index,
250
- color_discrete_map={
251
- 'POSITIVE': 'green',
252
- 'NEGATIVE': 'red',
253
- 'NEUTRAL': 'blue'
254
- }
255
- )
256
- st.plotly_chart(fig_bar)
257
-
258
- # Existing Call Details Section
259
- st.subheader("All Calls")
260
- display_data = data.copy()
261
- display_data['Summary Preview'] = display_data['Summary'].str[:100] + '...'
262
- st.dataframe(display_data[['Call ID', 'Chunk', 'Sentiment', 'Summary Preview', 'Overall Sentiment']])
263
-
264
- # Dropdown to select Call ID
265
- unique_call_ids = data[data['Call ID'] != '']['Call ID'].unique()
266
- call_id = st.selectbox("Select a Call ID to view details:", unique_call_ids)
267
-
268
- # Display selected Call ID details
269
- call_details = data[data['Call ID'] == call_id]
270
- if not call_details.empty:
271
- st.subheader("Detailed Call Information")
272
- st.write(f"**Call ID:** {call_id}")
273
- st.write(f"**Overall Sentiment:** {call_details.iloc[0]['Overall Sentiment']}")
274
-
275
- # Expand summary section
276
- st.subheader("Full Call Summary")
277
- st.text_area("Summary:",
278
- value=call_details.iloc[0]['Summary'],
279
- height=200,
280
- disabled=True)
281
-
282
- # Show all chunks for the selected call
283
- st.subheader("Conversation Chunks")
284
- for _, row in call_details.iterrows():
285
- if pd.notna(row['Chunk']):
286
- st.write(f"**Chunk:** {row['Chunk']}")
287
- st.write(f"**Sentiment:** {row['Sentiment']}")
288
- st.write("---") # Separator between chunks
289
- else:
290
- st.error("No details available for the selected Call ID.")
291
- except Exception as e:
292
- st.error(f"Error loading dashboard: {e}")
293
-
294
- if __name__ == "__main__":
295
- run_app()
 
1
+ import speech_recognition as sr
2
+ from sentiment_analysis import analyze_sentiment
3
+ from product_recommender import ProductRecommender
4
+ from objection_handler import ObjectionHandler
5
+ from google_sheets import fetch_call_data, store_data_in_sheet
6
+ from sentence_transformers import SentenceTransformer
7
+ from env_setup import config
8
+ import re
9
+ import uuid
10
+ from google.oauth2 import service_account
11
+ from googleapiclient.discovery import build
12
+ import pandas as pd
13
+ import plotly.express as px
14
+ import plotly.graph_objs as go
15
+ import streamlit as st
16
+
17
+ # Initialize components
18
+ product_recommender = ProductRecommender(r"C:\Users\shaik\OneDrive\Desktop\Infosys\Project1 - Copy\modules\data\recommendations.csv")
19
+ objection_handler = ObjectionHandler(r"C:\Users\shaik\Downloads\Sales Calls Transcriptions - Sheet3.csv")
20
+ model = SentenceTransformer('all-MiniLM-L6-v2')
21
+
22
+ def generate_comprehensive_summary(chunks):
23
+ """
24
+ Generate a comprehensive summary from conversation chunks
25
+ """
26
+ # Extract full text from chunks
27
+ full_text = " ".join([chunk[0] for chunk in chunks])
28
+
29
+ # Perform basic analysis
30
+ total_chunks = len(chunks)
31
+ sentiments = [chunk[1] for chunk in chunks]
32
+
33
+ # Determine overall conversation context
34
+ context_keywords = {
35
+ 'product_inquiry': ['dress', 'product', 'price', 'stock'],
36
+ 'pricing': ['cost', 'price', 'budget'],
37
+ 'negotiation': ['installment', 'payment', 'manage']
38
+ }
39
+
40
+ # Detect conversation themes
41
+ themes = []
42
+ for keyword_type, keywords in context_keywords.items():
43
+ if any(keyword.lower() in full_text.lower() for keyword in keywords):
44
+ themes.append(keyword_type)
45
+
46
+ # Basic sentiment analysis
47
+ positive_count = sentiments.count('POSITIVE')
48
+ negative_count = sentiments.count('NEGATIVE')
49
+ neutral_count = sentiments.count('NEUTRAL')
50
+
51
+ # Key interaction highlights
52
+ key_interactions = []
53
+ for chunk in chunks:
54
+ if any(keyword.lower() in chunk[0].lower() for keyword in ['price', 'dress', 'stock', 'installment']):
55
+ key_interactions.append(chunk[0])
56
+
57
+ # Construct summary
58
+ summary = f"Conversation Summary:\n"
59
+
60
+ # Context and themes
61
+ if 'product_inquiry' in themes:
62
+ summary += "• Customer initiated a product inquiry about items.\n"
63
+
64
+ if 'pricing' in themes:
65
+ summary += "• Price and budget considerations were discussed.\n"
66
+
67
+ if 'negotiation' in themes:
68
+ summary += "• Customer and seller explored flexible payment options.\n"
69
+
70
+ # Sentiment insights
71
+ summary += f"\nConversation Sentiment:\n"
72
+ summary += f"• Positive Interactions: {positive_count}\n"
73
+ summary += f"• Negative Interactions: {negative_count}\n"
74
+ summary += f"• Neutral Interactions: {neutral_count}\n"
75
+
76
+ # Key highlights
77
+ summary += "\nKey Conversation Points:\n"
78
+ for interaction in key_interactions[:3]: # Limit to top 3 key points
79
+ summary += f"• {interaction}\n"
80
+
81
+ # Conversation outcome
82
+ if positive_count > negative_count:
83
+ summary += "\nOutcome: Constructive and potentially successful interaction."
84
+ elif negative_count > positive_count:
85
+ summary += "\nOutcome: Interaction may require further follow-up."
86
+ else:
87
+ summary += "\nOutcome: Neutral interaction with potential for future engagement."
88
+
89
+ return summary
90
+
91
+ def is_valid_input(text):
92
+ text = text.strip().lower()
93
+ if len(text) < 3 or re.match(r'^[a-zA-Z\s]*$', text) is None:
94
+ return False
95
+ return True
96
+
97
+ def is_relevant_sentiment(sentiment_score):
98
+ return sentiment_score > 0.4
99
+
100
+ def calculate_overall_sentiment(sentiment_scores):
101
+ if sentiment_scores:
102
+ average_sentiment = sum(sentiment_scores) / len(sentiment_scores)
103
+ overall_sentiment = (
104
+ "POSITIVE" if average_sentiment > 0 else
105
+ "NEGATIVE" if average_sentiment < 0 else
106
+ "NEUTRAL"
107
+ )
108
+ else:
109
+ overall_sentiment = "NEUTRAL"
110
+ return overall_sentiment
111
+
112
+ def real_time_analysis():
113
+ recognizer = sr.Recognizer()
114
+ mic = sr.Microphone()
115
+
116
+ st.info("Say 'stop' to end the process.")
117
+
118
+ sentiment_scores = []
119
+ transcribed_chunks = []
120
+ total_text = ""
121
+
122
+ try:
123
+ while True:
124
+ with mic as source:
125
+ st.write("Listening...")
126
+ recognizer.adjust_for_ambient_noise(source)
127
+ audio = recognizer.listen(source)
128
+
129
+ try:
130
+ st.write("Recognizing...")
131
+ text = recognizer.recognize_google(audio)
132
+ st.write(f"*Recognized Text:* {text}")
133
+
134
+ if 'stop' in text.lower():
135
+ st.write("Stopping real-time analysis...")
136
+ break
137
+
138
+ # Append to the total conversation
139
+ total_text += text + " "
140
+ sentiment, score = analyze_sentiment(text)
141
+ sentiment_scores.append(score)
142
+
143
+ # Handle objection
144
+ objection_response = handle_objection(text)
145
+
146
+ # Get product recommendation
147
+ recommendations = []
148
+ if is_valid_input(text) and is_relevant_sentiment(score):
149
+ query_embedding = model.encode([text])
150
+ distances, indices = product_recommender.index.search(query_embedding, 1)
151
+
152
+ if distances[0][0] < 1.5: # Similarity threshold
153
+ recommendations = product_recommender.get_recommendations(text)
154
+
155
+ transcribed_chunks.append((text, sentiment, score))
156
+
157
+ st.write(f"*Sentiment:* {sentiment} (Score: {score})")
158
+ st.write(f"*Objection Response:* {objection_response}")
159
+
160
+ if recommendations:
161
+ st.write("*Product Recommendations:*")
162
+ for rec in recommendations:
163
+ st.write(rec)
164
+
165
+ except sr.UnknownValueError:
166
+ st.error("Speech Recognition could not understand the audio.")
167
+ except sr.RequestError as e:
168
+ st.error(f"Error with the Speech Recognition service: {e}")
169
+ except Exception as e:
170
+ st.error(f"Error during processing: {e}")
171
+
172
+ # After conversation ends, calculate and display overall sentiment and summary
173
+ overall_sentiment = calculate_overall_sentiment(sentiment_scores)
174
+ call_summary = generate_comprehensive_summary(transcribed_chunks)
175
+
176
+ st.subheader("Conversation Summary:")
177
+ st.write(total_text.strip())
178
+ st.subheader("Overall Sentiment:")
179
+ st.write(overall_sentiment)
180
+
181
+ # Store data in Google Sheets
182
+ store_data_in_sheet(
183
+ config["google_sheet_id"],
184
+ transcribed_chunks,
185
+ call_summary,
186
+ overall_sentiment
187
+ )
188
+ st.success("Conversation data stored successfully in Google Sheets!")
189
+
190
+ except Exception as e:
191
+ st.error(f"Error in real-time analysis: {e}")
192
+
193
+ def handle_objection(text):
194
+ query_embedding = model.encode([text])
195
+ distances, indices = objection_handler.index.search(query_embedding, 1)
196
+ if distances[0][0] < 1.5: # Adjust similarity threshold as needed
197
+ responses = objection_handler.handle_objection(text)
198
+ return "\n".join(responses) if responses else "No objection response found."
199
+ return "No objection response found."
200
+
201
+ # (Previous imports remain the same)
202
+
203
+ def run_app():
204
+ st.set_page_config(page_title="Sales Call Assistant", layout="wide")
205
+ st.title("AI Sales Call Assistant")
206
+
207
+ st.sidebar.title("Navigation")
208
+ app_mode = st.sidebar.radio("Choose a mode:", ["Real-Time Call Analysis", "Dashboard"])
209
+
210
+ if app_mode == "Real-Time Call Analysis":
211
+ st.header("Real-Time Sales Call Analysis")
212
+ if st.button("Start Listening"):
213
+ real_time_analysis()
214
+
215
+ elif app_mode == "Dashboard":
216
+ st.header("Call Summaries and Sentiment Analysis")
217
+ try:
218
+ data = fetch_call_data(config["google_sheet_id"])
219
+ if data.empty:
220
+ st.warning("No data available in the Google Sheet.")
221
+ else:
222
+ # Sentiment Visualizations
223
+ sentiment_counts = data['Sentiment'].value_counts()
224
+
225
+ # Pie Chart
226
+ col1, col2 = st.columns(2)
227
+ with col1:
228
+ st.subheader("Sentiment Distribution")
229
+ fig_pie = px.pie(
230
+ values=sentiment_counts.values,
231
+ names=sentiment_counts.index,
232
+ title='Call Sentiment Breakdown',
233
+ color_discrete_map={
234
+ 'POSITIVE': 'green',
235
+ 'NEGATIVE': 'red',
236
+ 'NEUTRAL': 'blue'
237
+ }
238
+ )
239
+ st.plotly_chart(fig_pie)
240
+
241
+ # Bar Chart
242
+ with col2:
243
+ st.subheader("Sentiment Counts")
244
+ fig_bar = px.bar(
245
+ x=sentiment_counts.index,
246
+ y=sentiment_counts.values,
247
+ title='Number of Calls by Sentiment',
248
+ labels={'x': 'Sentiment', 'y': 'Number of Calls'},
249
+ color=sentiment_counts.index,
250
+ color_discrete_map={
251
+ 'POSITIVE': 'green',
252
+ 'NEGATIVE': 'red',
253
+ 'NEUTRAL': 'blue'
254
+ }
255
+ )
256
+ st.plotly_chart(fig_bar)
257
+
258
+ # Existing Call Details Section
259
+ st.subheader("All Calls")
260
+ display_data = data.copy()
261
+ display_data['Summary Preview'] = display_data['Summary'].str[:100] + '...'
262
+ st.dataframe(display_data[['Call ID', 'Chunk', 'Sentiment', 'Summary Preview', 'Overall Sentiment']])
263
+
264
+ # Dropdown to select Call ID
265
+ unique_call_ids = data[data['Call ID'] != '']['Call ID'].unique()
266
+ call_id = st.selectbox("Select a Call ID to view details:", unique_call_ids)
267
+
268
+ # Display selected Call ID details
269
+ call_details = data[data['Call ID'] == call_id]
270
+ if not call_details.empty:
271
+ st.subheader("Detailed Call Information")
272
+ st.write(f"**Call ID:** {call_id}")
273
+ st.write(f"**Overall Sentiment:** {call_details.iloc[0]['Overall Sentiment']}")
274
+
275
+ # Expand summary section
276
+ st.subheader("Full Call Summary")
277
+ st.text_area("Summary:",
278
+ value=call_details.iloc[0]['Summary'],
279
+ height=200,
280
+ disabled=True)
281
+
282
+ # Show all chunks for the selected call
283
+ st.subheader("Conversation Chunks")
284
+ for _, row in call_details.iterrows():
285
+ if pd.notna(row['Chunk']):
286
+ st.write(f"**Chunk:** {row['Chunk']}")
287
+ st.write(f"**Sentiment:** {row['Sentiment']}")
288
+ st.write("---") # Separator between chunks
289
+ else:
290
+ st.error("No details available for the selected Call ID.")
291
+ except Exception as e:
292
+ st.error(f"Error loading dashboard: {e}")
293
+
294
+ if __name__ == "__main__":
295
+ run_app()