Spaces:
Sleeping
Sleeping
File size: 11,039 Bytes
b3eb597 ae6433b a570ee2 ae6433b ab778b5 6eb917c 66d546b 6eb917c 5983f67 1927724 e8c4d5a 8dc25fc 2b9db4b 8dc25fc e4d2335 7a1753e e4d2335 4e72933 e4d2335 2b4ed80 e4d2335 4e72933 e4d2335 bd2d8e4 c1344f9 60c5bda 1927724 de1281a 0b5158c 34a9249 fcacc9a 5766909 cd9a49e c246bae de1281a 5766909 4b843ed 0b5158c 4b843ed de1281a 9e4af49 60c5bda 34d2248 087006d 8cfbb65 087006d a570ee2 8cfbb65 a570ee2 087006d 8cfbb65 087006d a570ee2 8cfbb65 a570ee2 8cfbb65 a570ee2 8cfbb65 a570ee2 34a9249 60c5bda 087006d 2d3b7b6 90eec1e b3eb597 162880f b3eb597 8cfbb65 162880f 8cfbb65 ab778b5 0edf725 e68783d 0edf725 e68783d 0edf725 d0a4478 e68783d 9e4af49 0edf725 d0a4478 8cfbb65 60c5bda 34a9249 707b043 66d546b 60c5bda 7393b38 34a9249 5b7a6c6 7393b38 34a9249 7393b38 60c5bda 34a9249 60c5bda 34a9249 60c5bda 34a9249 60c5bda 34a9249 7393b38 60c5bda cdb1b12 60c5bda 2d3b7b6 60c5bda b3eb597 60c5bda | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | import gradio as gr
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import re
from io import BytesIO
import tempfile
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
import plotly.express as px
from PIL import Image
categories_keywords = {
"Application Status": ["application status", "application", "status", "submitted", "processing", "pending", "approval", "rejected", "accepted", "apply", "how to apply", "can I apply"],
"Follow-Ups": ['update', 'updates', 'any updates', 'any news', 'response from you', 'any reply'],
"Firki": ['firki'],
"Interviews": ['interview', 'set up interview', 'phone interview'],
"Volunteering": ["volunteer", "volunteering", "help out", "assist", "volunteer work", "volunteer opportunities"],
"Certificates": ["certificate", "certificates", "completion", "certification", "accreditation", "proof", "document", "certified"],
"Job Opportunities": ["job", "opportunity", "career", "vacancy", "position", "employment", "hiring", "recruitment", "internship", "post", "posts", "available", "teacher", "teaching", "opportunities", "looking for"],
"Surveys and Forms": ["survey", "form", "forms", "questionnaire", "feedback form", "response", "fill out", "submission"],
"Spam": ["spam", "unsubscribe", "remove", "stop", "junk", "block", "opt-out"],
"Rescheduling and Postponing": ["reschedule", "postpone", "delay", "change date", "new time", "rearrange", "shift", "adjust timing"],
"Contact and Communication Issues": ["contact", "communicate", "communication", "reach out", "phone", "email", "address", "details"],
"Email and Credentials Issues": ["email", "credentials", "login", "password", "gmail", "username", "verification", "reset"],
"Timing and Scheduling": ["timing", "schedule", "scheduling", "time", "appointment", "availability", "calendar", "book", "slot"],
"Salary and Benefits": ["salary", "benefits", "pay", "compensation", "wages", "earnings", "package", "remuneration", "incentives"],
"Technical Issues": ["technical", "issue", "problem", "error", "bug", "glitch", "fix", "troubleshoot", "support"],
"End of Conversation": ["bye", "thank you", "thanks", "goodbye", "end conversation", "ok", "ok thanks"],
"Feedback": ["feedback", "comments", "review", "opinion", "suggestion", "critique", "rating"],
"Event Inquiries": ["event", "webinar", "meeting", "conference", "session", "seminar", "workshop", "invitation"],
"Payment Issues": ["payment", "billing", "transaction", "charge", "fee", "invoice", "refund", "receipt"],
"Registration Issues": ["registration", "register", "sign up", "enroll", "join", "signup", "enrollment"],
"Service Requests": ["service", "support", "request", "assistance", "help", "aid", "maintenance"],
"Account Issues": ["account", "profile", "update", "activation", "deactivation", "reset", "account password"],
"Product Information": ["product", "service", "details", "info", "information", "specifications", "features"],
"Order Status": ["order", "status", "tracking", "shipment", "delivery", "purchase", "dispatch"],
"Miscellaneous": []
}
def categorize_question(question):
words = question.split()
# words to exclude from End Conversation
exclusion_words = {'is', 'please', 'not resolved', 'unresolved', 'problem', 'help', 'issue', 'webinar', 'office', 'leave', 'approved', 'notice', 'period', 'good morning', 'when', 'where', 'why', 'how', 'which', 'and when'}
# Categorization
for category, keywords in categories_keywords.items():
if any(keyword.lower() in question.lower() for keyword in keywords):
return category
# Secondary check for 'End of Conversation' category
if "end of conversation" in question.lower() and not any(exclusion_word in question.lower() for exclusion_word in exclusion_words):
return "End of Conversation"
return "Miscellaneous"
def preprocess_data(df):
df.rename(columns={'Question Asked': 'texts'}, inplace=True)
df['texts'] = df['texts'].astype(str).str.lower()
df['texts'] = df['texts'].apply(lambda text: re.sub(r'https?://\S+|www\.\S+', '', text))
def remove_emoji(string):
emoji_pattern = re.compile("["
u"\U0001F600-\U0001F64F"
u"\U0001F300-\U0001F5FF"
u"\U0001F680-\U0001F6FF"
u"\U0001F1E0-\U0001F1FF"
u"\U00002702-\U000027B0"
u"\U000024C2-\U0001F251"
"]+", flags=re.UNICODE)
return emoji_pattern.sub(r'', string)
df['texts'] = df['texts'].apply(remove_emoji)
custom_synonyms = {
'application': ['form'],
'apply': ['fill', 'applied'],
'work': ['job'],
'salary': ['stipend', 'pay', 'payment', 'paid'],
'test': ['online test', 'amcat test', 'exam', 'assessment'],
'pass': ['clear', 'selected', 'pass or not'],
'result': ['outcome', 'mark', 'marks'],
'thanks': ["thanks a lot to you", "thankyou so much", "thank you so much", "tysm", "thank you",
"okaythank", "thx", "ty", "thankyou", "thank", "thank u"],
'interview': ["pi"]
}
for original_word, synonym_list in custom_synonyms.items():
for synonym in synonym_list:
pattern = r"\b" + synonym + r"\b"
df['texts'] = df['texts'].str.replace(pattern, original_word, regex=True)
spam_list = ["click here", "free", "recharge", "limited", "discount", "money back guarantee", "aaj", "kal", "mein",
"how can i help you", "how can we help you", "how we can help you", "follow", "king", "contacting", "gar",
"kirke", "subscribe", "youtube", "jio", "insta", "make money", "b2b", "sent using truecaller"]
for spam_phrase in spam_list:
pattern = r"\b" + re.escape(spam_phrase) + r"\b"
df = df[~df['texts'].str.contains(pattern)]
def remove_punctuations(text):
return re.sub(r'[^\w\s]', '', text)
df['texts'] = df['texts'].apply(remove_punctuations)
df['texts'] = df['texts'].str.strip()
df = df[df['texts'] != '']
# Categorize
df['Category'] = df['texts'].apply(categorize_question)
return df
def cluster_data(df, num_clusters):
vectorizer = TfidfVectorizer(stop_words='english')
X = vectorizer.fit_transform(df['texts'])
kmeans = KMeans(n_clusters=num_clusters, random_state=0)
kmeans.fit(X)
df['Cluster'] = kmeans.labels_
return df, kmeans
def generate_wordcloud(df):
text = " ".join(df['texts'].tolist())
stopwords = set(STOPWORDS)
wordcloud = WordCloud(
width=800,
height=400,
background_color='white',
max_words=300,
collocations=False,
min_font_size=10,
max_font_size=200,
stopwords=stopwords,
prefer_horizontal=1.0,
scale=2,
relative_scaling=0.5,
random_state=42
).generate(text)
plt.figure(figsize=(15, 7))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
buf = BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
img = Image.open(buf)
return img
def generate_bar_chart(df, num_clusters_to_display):
# Exclude common words
common_words = {'i', 'you', 'thanks', 'thank', 'ok', 'okay', 'sure', 'done', 'to', 'for', 'and', 'but', 'so'}
top_categories = df['Category'].value_counts().index[:num_clusters_to_display]
df_top_categories = df[df['Category'].isin(top_categories)]
category_top_words = df_top_categories.groupby('Category', observed=False)['texts'].apply(lambda x: ' '.join(x)).reset_index()
category_top_words['top_word'] = category_top_words['texts'].apply(lambda x: ' '.join([word for word in pd.Series(x.split()).value_counts().index if word not in common_words][:3]))
category_sizes = df_top_categories['Category'].value_counts().reset_index()
category_sizes.columns = ['Category', 'Count']
category_sizes = category_sizes.merge(category_top_words[['Category', 'top_word']], on='Category')
fig = px.bar(category_sizes, x='Category', y='Count', text='top_word', title='Category Frequency with Top Words')
fig.update_traces(textposition='outside')
fig.update_layout(xaxis_title='Category', yaxis_title='Frequency', showlegend=False)
buf = BytesIO()
fig.write_image(buf, format='png')
buf.seek(0)
img = Image.open(buf)
return img
def main(file, num_clusters_to_display):
try:
df = pd.read_csv(file)
# Filter by 'Fallback Message shown'
df = df[df['Answer'] == 'Fallback Message shown']
df = preprocess_data(df)
# Clustering
num_clusters = 12
df, kmeans = cluster_data(df, num_clusters)
# Categorization
df['Category'] = df['texts'].apply(categorize_question)
df = df[df['Category'] != 'Miscellaneous']
# Sorting (ascending order)
category_sizes = df['Category'].value_counts().reset_index()
category_sizes.columns = ['Category', 'Count']
sorted_categories = category_sizes.sort_values(by='Count', ascending=False)['Category'].tolist()
sorted_categories_sm = category_sizes.sort_values(by='Count', ascending=True)['Category'].tolist()
# Display (according to input slider)
largest_categories = sorted_categories[:num_clusters_to_display]
smallest_categories = sorted_categories_sm[:num_clusters_to_display]
# Filtering (according to input slider)
filtered_df = df[df['Category'].isin(largest_categories)]
filtered_cloud_df = df[df['Category'].isin(smallest_categories)]
# Sort the output file by Category and Cluster
filtered_df = filtered_df.sort_values(by=['Category', 'Cluster'])
filtered_cloud_df = filtered_cloud_df.sort_values(by='Category')
wordcloud_img = generate_wordcloud(filtered_cloud_df)
bar_chart_img = generate_bar_chart(df, num_clusters_to_display)
with tempfile.NamedTemporaryFile(delete=False, suffix=".csv") as tmpfile:
filtered_df.to_csv(tmpfile.name, index=False)
csv_file_path = tmpfile.name
return csv_file_path, wordcloud_img, bar_chart_img
except Exception as e:
print(f"Error: {e}")
return str(e), None, None
interface = gr.Interface(
fn=main,
inputs=[
gr.File(label="Upload CSV File (.csv)"),
gr.Slider(label="Number of Categories to Display", minimum=1, maximum=15, step=1, value=5)
],
outputs=[
gr.File(label="Categorized Data CSV"),
gr.Image(label="Word Cloud"),
gr.Image(label="Bar Chart")
],
title="Unanswered User Queries Categorization",
)
interface.launch(share=True)
|