Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -13,221 +13,118 @@ st.set_page_config(
|
|
13 |
# Custom CSS styling
|
14 |
st.markdown("""
|
15 |
<style>
|
16 |
-
.analysis-
|
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 |
-
.
|
23 |
-
|
24 |
-
.
|
25 |
-
|
26 |
-
|
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
|
45 |
with st.spinner("🚀 Loading AI models..."):
|
46 |
device = 0 if torch.cuda.is_available() else -1
|
47 |
|
48 |
-
|
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
|
71 |
|
72 |
def analyze_review(text, models):
|
73 |
-
"""
|
74 |
-
|
75 |
|
76 |
-
#
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
main_topic = topic_result['labels'][0]
|
81 |
-
topic_confidence = topic_result['scores'][0]
|
82 |
|
83 |
-
#
|
84 |
-
|
85 |
-
|
86 |
-
sentiment_label = "positive" if sentiment_result['label'] in ['POSITIVE', 'positive'] else "negative"
|
87 |
-
sentiment_score = sentiment_result['score']
|
88 |
|
89 |
-
#
|
90 |
-
|
91 |
-
prompt = f"""Review: {text}
|
92 |
Topic: {main_topic}
|
93 |
-
Sentiment: {
|
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 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
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
|
120 |
-
st.markdown("---")
|
121 |
|
122 |
-
#
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
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
|
151 |
-
|
152 |
-
|
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 |
-
#
|
193 |
-
st.markdown("
|
|
|
194 |
|
|
|
195 |
col1, col2 = st.columns(2)
|
196 |
with col1:
|
197 |
-
|
198 |
-
|
199 |
-
st.markdown(f'<div class="analysis-card positive">{format_text(result["response"])}</div>',
|
200 |
-
unsafe_allow_html=True)
|
201 |
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
unsafe_allow_html=True)
|
208 |
|
209 |
-
# Download
|
210 |
st.download_button(
|
211 |
-
label="Download
|
212 |
-
data=f""
|
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 |
-
|
230 |
-
|
231 |
|
232 |
if __name__ == "__main__":
|
233 |
main()
|
|
|
13 |
# Custom CSS styling
|
14 |
st.markdown("""
|
15 |
<style>
|
16 |
+
.analysis-section {
|
17 |
padding: 1.5rem;
|
|
|
|
|
18 |
margin: 1rem 0;
|
19 |
}
|
20 |
+
.response-box {
|
21 |
+
background-color: #F8FAFC;
|
22 |
+
padding: 1.5rem;
|
23 |
+
border-radius: 0.5rem;
|
24 |
+
margin: 1rem 0;
|
|
|
|
|
25 |
}
|
26 |
</style>
|
27 |
""", unsafe_allow_html=True)
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
@st.cache_resource
|
30 |
def load_models():
|
31 |
+
"""Load ML models"""
|
32 |
with st.spinner("🚀 Loading AI models..."):
|
33 |
device = 0 if torch.cuda.is_available() else -1
|
34 |
|
35 |
+
classifier = pipeline(
|
|
|
36 |
"zero-shot-classification",
|
37 |
model="MoritzLaurer/deberta-v3-base-zeroshot-v1",
|
38 |
device=device,
|
39 |
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
40 |
)
|
41 |
|
|
|
42 |
sentiment_analyzer = pipeline(
|
43 |
"sentiment-analysis",
|
44 |
model="cardiffnlp/twitter-roberta-base-sentiment-latest",
|
45 |
device=device
|
46 |
)
|
47 |
|
|
|
48 |
response_generator = pipeline(
|
49 |
"text2text-generation",
|
50 |
model="Leo66277/custom-response-generator",
|
51 |
device=device
|
52 |
)
|
53 |
|
54 |
+
return classifier, sentiment_analyzer, response_generator
|
55 |
|
56 |
def analyze_review(text, models):
|
57 |
+
"""Analysis pipeline"""
|
58 |
+
classifier, sentiment_analyzer, response_generator = models
|
59 |
|
60 |
+
# Topic classification
|
61 |
+
topics = ["customer service", "mobile app", "credit card", "account security"]
|
62 |
+
topic_result = classifier(text, topics, multi_label=False)
|
63 |
+
main_topic = topic_result['labels'][0]
|
|
|
|
|
64 |
|
65 |
+
# Sentiment analysis
|
66 |
+
sentiment_result = sentiment_analyzer(text)[0]
|
67 |
+
sentiment = "positive" if sentiment_result['label'] in ['POSITIVE', 'positive'] else "negative"
|
|
|
|
|
68 |
|
69 |
+
# Generate response
|
70 |
+
prompt = f"""Review: {text}
|
|
|
71 |
Topic: {main_topic}
|
72 |
+
Sentiment: {sentiment}
|
73 |
Generate response:"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
|
75 |
+
response = response_generator(
|
76 |
+
prompt,
|
77 |
+
max_length=300,
|
78 |
+
num_return_sequences=1,
|
79 |
+
do_sample=True,
|
80 |
+
temperature=0.7
|
81 |
+
)[0]['generated_text'].strip()
|
82 |
+
|
83 |
+
return main_topic, sentiment, response
|
|
|
|
|
|
|
84 |
|
|
|
85 |
def main():
|
86 |
+
st.title("🏦 Bank Review Analysis")
|
|
|
87 |
|
88 |
+
# Main input
|
89 |
+
review = st.text_area(
|
90 |
+
"Enter customer review",
|
91 |
+
height=150,
|
92 |
+
placeholder="Paste your bank review here..."
|
93 |
+
)
|
|
|
94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
# Load models
|
96 |
models = load_models()
|
97 |
+
|
98 |
+
if st.button("Analyze Review"):
|
99 |
+
if review.strip():
|
100 |
+
topic, sentiment, response = analyze_review(review, models)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
|
102 |
+
# Display results
|
103 |
+
st.markdown("---")
|
104 |
+
st.markdown("### Analysis Results")
|
105 |
|
106 |
+
# Results columns
|
107 |
col1, col2 = st.columns(2)
|
108 |
with col1:
|
109 |
+
st.markdown(f"**Detected Topic:** {topic}")
|
110 |
+
st.markdown(f"**Sentiment:** {sentiment.capitalize()}")
|
|
|
|
|
111 |
|
112 |
+
# Response section
|
113 |
+
st.markdown("---")
|
114 |
+
st.markdown("### Suggested Response")
|
115 |
+
st.markdown(f'<div class="response-box">{textwrap.fill(response, width=80)}</div>',
|
116 |
+
unsafe_allow_html=True)
|
|
|
117 |
|
118 |
+
# Download button
|
119 |
st.download_button(
|
120 |
+
label="Download Report",
|
121 |
+
data=f"Topic: {topic}\nSentiment: {sentiment}\n\nResponse:\n{response}",
|
122 |
+
file_name="review_analysis.txt",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
mime="text/plain"
|
124 |
)
|
125 |
+
|
126 |
+
else:
|
127 |
+
st.warning("Please enter a review to analyze")
|
128 |
|
129 |
if __name__ == "__main__":
|
130 |
main()
|