Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,30 +1,233 @@
|
|
1 |
import streamlit as st
|
|
|
2 |
from transformers import pipeline
|
|
|
3 |
|
4 |
-
#
|
5 |
-
|
|
|
|
|
|
|
|
|
6 |
|
7 |
-
#
|
8 |
-
st.
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
-
#
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
max_label = result['label']
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import streamlit as st
|
2 |
+
import torch
|
3 |
from transformers import pipeline
|
4 |
+
import textwrap
|
5 |
|
6 |
+
# Page configuration
|
7 |
+
st.set_page_config(
|
8 |
+
page_title="Bank Review Analyzer",
|
9 |
+
page_icon="🏦",
|
10 |
+
layout="centered"
|
11 |
+
)
|
12 |
|
13 |
+
# Custom CSS styling
|
14 |
+
st.markdown("""
|
15 |
+
<style>
|
16 |
+
.analysis-card {
|
17 |
+
padding: 1.5rem;
|
18 |
+
border-radius: 0.5rem;
|
19 |
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
20 |
+
margin: 1rem 0;
|
21 |
+
}
|
22 |
+
.positive { border-left: 0.5rem solid #10B981 !important; }
|
23 |
+
.negative { border-left: 0.5rem solid #EF4444 !important; }
|
24 |
+
.step-indicator {
|
25 |
+
font-size: 1.2rem;
|
26 |
+
font-weight: 600;
|
27 |
+
color: #6B7280;
|
28 |
+
margin: 1.5rem 0;
|
29 |
+
}
|
30 |
+
</style>
|
31 |
+
""", unsafe_allow_html=True)
|
32 |
|
33 |
+
# Response templates
|
34 |
+
response_templates = {
|
35 |
+
"billing": {
|
36 |
+
"positive": "Thank you for your positive feedback on our billing services. We're delighted to hear about your experience...",
|
37 |
+
"negative": "We sincerely apologize for the issues with our billing services. Your concerns are important to us..."
|
38 |
+
},
|
39 |
+
# Add other template categories...
|
40 |
+
}
|
41 |
|
42 |
+
@st.cache_resource
|
43 |
+
def load_models():
|
44 |
+
"""Load all required ML models"""
|
45 |
+
with st.spinner("🚀 Loading AI models..."):
|
46 |
+
device = 0 if torch.cuda.is_available() else -1
|
47 |
+
|
48 |
+
# Zero-shot classification model
|
49 |
+
topic_classifier = pipeline(
|
50 |
+
"zero-shot-classification",
|
51 |
+
model="MoritzLaurer/deberta-v3-base-zeroshot-v1",
|
52 |
+
device=device,
|
53 |
+
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
54 |
+
)
|
55 |
+
|
56 |
+
# Sentiment analysis model
|
57 |
+
sentiment_analyzer = pipeline(
|
58 |
+
"sentiment-analysis",
|
59 |
+
model="cardiffnlp/twitter-roberta-base-sentiment-latest",
|
60 |
+
device=device
|
61 |
+
)
|
62 |
+
|
63 |
+
# Response generation model
|
64 |
+
response_generator = pipeline(
|
65 |
+
"text2text-generation",
|
66 |
+
model="Leo66277/custom-response-generator",
|
67 |
+
device=device
|
68 |
+
)
|
69 |
+
|
70 |
+
return topic_classifier, sentiment_analyzer, response_generator
|
71 |
|
72 |
+
def analyze_review(text, models):
|
73 |
+
"""Full analysis pipeline"""
|
74 |
+
topic_classifier, sentiment_analyzer, response_generator = models
|
75 |
+
|
76 |
+
# Step 1: Topic classification
|
77 |
+
with st.spinner("🔍 Analyzing review topic..."):
|
78 |
+
topic_labels = list(response_templates.keys())
|
79 |
+
topic_result = topic_classifier(text, topic_labels, multi_label=False)
|
80 |
+
main_topic = topic_result['labels'][0]
|
81 |
+
topic_confidence = topic_result['scores'][0]
|
82 |
+
|
83 |
+
# Step 2: Sentiment analysis
|
84 |
+
with st.spinner("💡 Detecting sentiment..."):
|
85 |
+
sentiment_result = sentiment_analyzer(text)[0]
|
86 |
+
sentiment_label = "positive" if sentiment_result['label'] in ['POSITIVE', 'positive'] else "negative"
|
87 |
+
sentiment_score = sentiment_result['score']
|
88 |
+
|
89 |
+
# Step 3: Generate response
|
90 |
+
with st.spinner("✍️ Generating professional response..."):
|
91 |
+
prompt = f"""Review: {text}
|
92 |
+
Topic: {main_topic}
|
93 |
+
Sentiment: {sentiment_label}
|
94 |
+
Generate response:"""
|
95 |
+
|
96 |
+
generated_response = response_generator(
|
97 |
+
prompt,
|
98 |
+
max_length=300,
|
99 |
+
num_return_sequences=1,
|
100 |
+
do_sample=True,
|
101 |
+
temperature=0.7
|
102 |
+
)[0]['generated_text'].strip()
|
103 |
+
|
104 |
+
return {
|
105 |
+
"topic": main_topic,
|
106 |
+
"topic_confidence": f"{topic_confidence:.1%}",
|
107 |
+
"sentiment": sentiment_label,
|
108 |
+
"sentiment_score": f"{sentiment_score:.1%}",
|
109 |
+
"response": generated_response,
|
110 |
+
"template_response": response_templates.get(main_topic, {}).get(sentiment_label)
|
111 |
+
}
|
112 |
|
113 |
+
def format_text(text, line_width=80):
|
114 |
+
"""Text formatting"""
|
115 |
+
return "\n".join(textwrap.wrap(text, width=line_width))
|
|
|
116 |
|
117 |
+
# Main interface
|
118 |
+
def main():
|
119 |
+
st.title("🏦 Bank Review Analysis System")
|
120 |
+
st.markdown("---")
|
121 |
+
|
122 |
+
# Sidebar configuration
|
123 |
+
with st.sidebar:
|
124 |
+
st.header("Settings")
|
125 |
+
show_details = st.checkbox("Show analysis details", True)
|
126 |
+
show_template = st.checkbox("Show template response", True)
|
127 |
+
st.markdown("---")
|
128 |
+
st.caption("Version: 1.0 | Developer: Leo66277")
|
129 |
+
|
130 |
+
# Main input area
|
131 |
+
with st.form(key="analysis_form"):
|
132 |
+
col1, col2 = st.columns([3, 1])
|
133 |
+
with col1:
|
134 |
+
review_text = st.text_area(
|
135 |
+
"Enter customer review",
|
136 |
+
placeholder="Paste your bank review here...",
|
137 |
+
height=150
|
138 |
+
)
|
139 |
+
with col2:
|
140 |
+
st.markdown("### Example Reviews")
|
141 |
+
st.caption("▶️ Difficulty logging into mobile banking")
|
142 |
+
st.caption("▶️ Unreasonable credit card annual fee")
|
143 |
+
st.caption("▶️ Excellent counter service attitude")
|
144 |
+
|
145 |
+
submitted = st.form_submit_button("Start Analysis", type="primary")
|
146 |
+
|
147 |
+
# Load models
|
148 |
+
models = load_models()
|
149 |
+
|
150 |
+
if submitted and review_text.strip():
|
151 |
+
# Perform analysis
|
152 |
+
result = analyze_review(review_text, models)
|
153 |
+
|
154 |
+
# Display results
|
155 |
+
with st.container():
|
156 |
+
st.markdown("## Analysis Results")
|
157 |
+
|
158 |
+
# Sentiment indicators
|
159 |
+
sentiment_icon = "✅" if result['sentiment'] == "positive" else "⚠️"
|
160 |
+
|
161 |
+
# Main metrics card
|
162 |
+
with st.expander("Key Metrics", expanded=True):
|
163 |
+
cols = st.columns(4)
|
164 |
+
cols[0].metric("Detected Topic", result['topic'])
|
165 |
+
cols[1].metric("Topic Confidence", result['topic_confidence'])
|
166 |
+
cols[2].metric("Sentiment", f"{sentiment_icon} {result['sentiment'].capitalize()}")
|
167 |
+
cols[3].metric("Sentiment Strength", result['sentiment_score'])
|
168 |
+
|
169 |
+
# Detailed analysis
|
170 |
+
if show_details:
|
171 |
+
with st.expander("Detailed Analysis", expanded=False):
|
172 |
+
tab1, tab2, tab3 = st.tabs(["Original Review", "Topic Distribution", "Sentiment Analysis"])
|
173 |
+
|
174 |
+
with tab1:
|
175 |
+
st.code(format_text(review_text), language="text")
|
176 |
+
|
177 |
+
with tab2:
|
178 |
+
st.caption("Topic Probability Distribution")
|
179 |
+
topic_data = {
|
180 |
+
'Topic': result['topic_distribution']['labels'],
|
181 |
+
'Confidence': result['topic_distribution']['scores']
|
182 |
+
}
|
183 |
+
st.bar_chart(topic_data, x='Topic', y='Confidence')
|
184 |
+
|
185 |
+
with tab3:
|
186 |
+
st.caption("Sentiment Analysis Raw Results")
|
187 |
+
st.json({
|
188 |
+
"label": result['sentiment'],
|
189 |
+
"score": float(result['sentiment_score'].strip('%'))/100
|
190 |
+
})
|
191 |
+
|
192 |
+
# Response generation
|
193 |
+
st.markdown("## 💬 Response Suggestions")
|
194 |
+
|
195 |
+
col1, col2 = st.columns(2)
|
196 |
+
with col1:
|
197 |
+
with st.container(border=True):
|
198 |
+
st.markdown("### 🚀 AI Generated Response")
|
199 |
+
st.markdown(f'<div class="analysis-card positive">{format_text(result["response"])}</div>',
|
200 |
+
unsafe_allow_html=True)
|
201 |
+
|
202 |
+
if show_template and result['template_response']:
|
203 |
+
with col2:
|
204 |
+
with st.container(border=True):
|
205 |
+
st.markdown("### 📋 Template Response")
|
206 |
+
st.markdown(f'<div class="analysis-card">{format_text(result["template_response"])}</div>',
|
207 |
+
unsafe_allow_html=True)
|
208 |
+
|
209 |
+
# Download report
|
210 |
+
st.download_button(
|
211 |
+
label="Download Full Report",
|
212 |
+
data=f"""Analysis Report
|
213 |
+
|
214 |
+
Original Review:
|
215 |
+
{review_text}
|
216 |
+
|
217 |
+
Topic Analysis: {result['topic']} ({result['topic_confidence']})
|
218 |
+
Sentiment Analysis: {result['sentiment'].capitalize()} ({result['sentiment_score']})
|
219 |
+
|
220 |
+
AI Generated Response:
|
221 |
+
{result['response']}
|
222 |
+
|
223 |
+
{"Template Response: " + result['template_response'] if result['template_response'] else ""}
|
224 |
+
""",
|
225 |
+
file_name="bank_review_analysis.txt",
|
226 |
+
mime="text/plain"
|
227 |
+
)
|
228 |
+
|
229 |
+
elif submitted:
|
230 |
+
st.warning("⚠️ Please enter valid review content")
|
231 |
+
|
232 |
+
if __name__ == "__main__":
|
233 |
+
main()
|