proKBD commited on
Commit
19ee5bc
·
verified ·
1 Parent(s): 58961dd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +284 -266
app.py CHANGED
@@ -1,413 +1,431 @@
1
  """Streamlit frontend for the News Summarization application."""
2
 
3
  import streamlit as st
4
-
5
  import pandas as pd
6
  import json
7
-
8
  import os
9
  import plotly.express as px
10
  import altair as alt
11
- from utils import (
12
- analyze_company_data,
13
- TextToSpeechConverter,
14
- get_translator,
15
- NewsExtractor,
16
- SentimentAnalyzer,
17
- TextSummarizer
18
- )
19
 
20
- # Set page config
21
  st.set_page_config(
22
  page_title="News Summarization App",
23
  page_icon="📰",
24
  layout="wide"
25
  )
26
 
27
- # Show loading message
28
- with st.spinner("Initializing the application... Please wait while we load the models."):
29
- # Initialize components
30
  try:
31
- st.success("Application initialized successfully!")
32
- except Exception as e:
33
- st.error(f"Error initializing application: {str(e)}")
34
- st.info("Please try refreshing the page.")
35
-
36
- def process_company(company_name):
37
- """Process company data directly."""
38
- try:
39
- # Call the analysis function directly from utils
40
- data = analyze_company_data(company_name)
41
-
42
- # Generate Hindi audio from final analysis
43
- if data.get("final_sentiment_analysis"):
44
- # Get the translator
45
- translator = get_translator()
46
- if translator:
47
- try:
48
- # Create a more detailed Hindi explanation
49
- sentiment_explanation = f"""
50
- {company_name} के समाचारों का विश्लेषण:
51
-
52
- समग्र भावना: {data['final_sentiment_analysis']}
53
-
54
- भावनात्मक विश्लेषण:
55
- - सकारात्मक भावना: {data.get('comparative_sentiment_score', {}).get('sentiment_indices', {}).get('positivity_index', 0):.2f}
56
- - नकारात्मक भावना: {data.get('comparative_sentiment_score', {}).get('sentiment_indices', {}).get('negativity_index', 0):.2f}
57
- - भावनात्मक तीव्रता: {data.get('comparative_sentiment_score', {}).get('sentiment_indices', {}).get('emotional_intensity', 0):.2f}
58
-
59
- विश्वसनीयता स्कोर: {data.get('comparative_sentiment_score', {}).get('sentiment_indices', {}).get('confidence_score', 0):.2f}
60
- """
61
-
62
- # Generate Hindi audio
63
- tts_converter = TextToSpeechConverter()
64
- audio_path = tts_converter.generate_audio(
65
- sentiment_explanation,
66
- f'{company_name}_summary'
67
- )
68
- data['audio_path'] = audio_path
69
- except Exception as e:
70
- print(f"Error generating Hindi audio: {str(e)}")
71
- data['audio_path'] = None
72
- else:
73
- print("Translator not available")
74
- data['audio_path'] = None
75
 
76
- return data
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
  except Exception as e:
86
- st.error(f"Error processing company: {str(e)}")
87
- return {"articles": [], "comparative_sentiment_score": {}, "final_sentiment_analysis": "", "audio_path": None}
88
 
89
  def main():
90
  st.title("📰 News Summarization and Analysis")
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  st.sidebar.error("Please enter a valid company name (at least 2 characters)")
92
  else:
93
  with st.spinner("Analyzing news articles..."):
94
- try:
95
- # Process company data
96
- data = process_company(company)
97
-
98
- if not data["articles"]:
99
- st.error("No articles found for analysis.")
100
- return
101
-
102
  # Display Articles
103
  st.header("📑 News Articles")
104
- for idx, article in enumerate(data["articles"], 1):
105
  with st.expander(f"Article {idx}: {article['title']}"):
106
- # Display content with proper formatting
107
- if article.get("content"):
108
- st.markdown("**Content:**")
109
- st.write(article["content"])
110
- else:
111
- st.warning("No content available for this article")
112
-
113
- # Display summary if available
114
- if article.get("summary"):
115
- st.markdown("**Summary:**")
116
- st.write(article["summary"])
117
-
118
- # Display source
119
- if article.get("source"):
120
- st.markdown("**Source:**")
121
- st.write(article["source"])
122
 
123
  # Enhanced sentiment display
124
  if "sentiment" in article:
125
  sentiment_col1, sentiment_col2 = st.columns(2)
126
  with sentiment_col1:
127
- st.markdown("**Basic Sentiment:**")
128
- st.write(article["sentiment"])
129
- if "sentiment_score" in article:
130
- st.write(f"**Confidence Score:** {article['sentiment_score']*100:.1f}%")
131
 
132
  with sentiment_col2:
133
  # Display fine-grained sentiment if available
134
  if "fine_grained_sentiment" in article and article["fine_grained_sentiment"]:
135
- st.markdown("**Detailed Sentiment:**")
136
  fine_grained = article["fine_grained_sentiment"]
137
  if "category" in fine_grained:
138
- st.write(f"Category: {fine_grained['category']}")
139
  if "confidence" in fine_grained:
140
- st.write(f"Confidence: {fine_grained['confidence']*100:.1f}%")
141
 
142
  # Display sentiment indices if available
143
  if "sentiment_indices" in article and article["sentiment_indices"]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  st.markdown(f"> {target['context']}")
145
  st.markdown("---")
146
 
147
- # Display URL if available
148
  if "url" in article:
149
- st.markdown(f"**[Read More]({article['url']})**")
150
 
151
  # Display Comparative Analysis
152
  st.header("📊 Comparative Analysis")
153
- analysis = data.get("comparative_sentiment_score", {})
154
 
155
  # Sentiment Distribution
156
  if "sentiment_distribution" in analysis:
157
  st.subheader("Sentiment Distribution")
158
 
159
-
160
-
161
-
162
-
163
  sentiment_dist = analysis["sentiment_distribution"]
164
 
165
-
166
  try:
167
  # Extract basic sentiment data
168
  if isinstance(sentiment_dist, dict):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  else:
170
  percentages = {k: 0 for k in basic_dist}
171
 
172
- # Display as metrics
173
  st.write("**Sentiment Distribution:**")
174
 
175
  col1, col2, col3 = st.columns(3)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  f"{percentages.get('neutral', 0):.1f}%"
177
  )
178
 
179
- # Create visualization
180
-
181
-
182
  chart_data = pd.DataFrame({
183
  'Sentiment': ['Positive', 'Negative', 'Neutral'],
184
  'Count': [
185
- basic_dist.get('positive', 0),
186
  basic_dist.get('negative', 0),
187
  basic_dist.get('neutral', 0)
188
  ],
 
 
 
 
189
  ]
190
  })
191
 
192
-
193
-
194
-
195
-
196
-
197
  chart = alt.Chart(chart_data).mark_bar().encode(
198
- y='Sentiment',
199
- x='Count',
200
  color=alt.Color('Sentiment', scale=alt.Scale(
201
  domain=['Positive', 'Negative', 'Neutral'],
202
  range=['green', 'red', 'gray']
203
  )),
204
- tooltip=['Sentiment', 'Count', 'Percentage']
205
  ).properties(
206
  width=600,
207
  height=300
208
  )
209
 
210
-
211
  text = chart.mark_text(
212
  align='left',
213
  baseline='middle',
214
- dx=3
215
  ).encode(
216
  text='Percentage'
217
  )
218
 
219
-
220
  chart_with_text = (chart + text)
221
-
222
  st.altair_chart(chart_with_text, use_container_width=True)
223
 
224
  except Exception as e:
225
  st.error(f"Error creating visualization: {str(e)}")
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
 
239
  # Display sentiment indices if available
240
  if "sentiment_indices" in analysis and analysis["sentiment_indices"]:
241
  st.subheader("Sentiment Indices")
242
 
243
-
244
-
245
-
246
-
247
-
248
  indices = analysis["sentiment_indices"]
249
 
250
-
251
  try:
252
  if isinstance(indices, dict):
253
- # Display as metrics in columns
254
  cols = st.columns(3)
255
 
256
-
257
  display_names = {
258
  "positivity_index": "Positivity",
259
  "negativity_index": "Negativity",
 
 
 
260
  "esg_relevance": "ESG Relevance"
261
  }
262
 
263
-
264
  for i, (key, value) in enumerate(indices.items()):
265
  if isinstance(value, (int, float)):
266
  with cols[i % 3]:
267
  display_name = display_names.get(key, key.replace("_", " ").title())
268
  st.metric(display_name, f"{value:.2f}")
269
 
270
- # Create visualization
271
-
272
-
273
  chart_data = pd.DataFrame({
274
  'Index': [display_names.get(k, k.replace("_", " ").title()) for k in indices.keys()],
275
  'Value': [v if isinstance(v, (int, float)) else 0 for v in indices.values()]
276
  })
277
 
278
-
279
  chart = alt.Chart(chart_data).mark_bar().encode(
280
  x='Value',
281
  y='Index',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  - **Confidence**: Confidence in the sentiment analysis (0-1)
283
  - **ESG Relevance**: Relevance to Environmental, Social, and Governance topics (0-1)
284
  """)
285
-
286
-
287
-
288
  except Exception as e:
289
  st.error(f"Error creating indices visualization: {str(e)}")
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
 
298
- # Display Final Analysis
299
- st.header("📊 Final Analysis")
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
 
308
- # Display overall sentiment analysis with enhanced formatting
309
- if data.get("final_sentiment_analysis"):
310
- st.markdown("### Overall Sentiment Analysis")
311
- analysis_parts = data["final_sentiment_analysis"].split(". ")
312
- if len(analysis_parts) >= 2:
313
- # First sentence - Overall sentiment
314
- st.markdown(f"**{analysis_parts[0]}.**")
315
- # Second sentence - Key findings
316
- st.markdown(f"**{analysis_parts[1]}.**")
317
- # Third sentence - Additional insights (if available)
318
- if len(analysis_parts) > 2:
319
- st.markdown(f"**{analysis_parts[2]}.**")
320
- else:
321
- st.write(data["final_sentiment_analysis"])
322
-
323
- # Add sentiment strength indicator
324
- if data.get("ensemble_info"):
325
- ensemble_info = data["ensemble_info"]
326
- if "model_agreement" in ensemble_info:
327
- agreement = ensemble_info["model_agreement"]
328
- strength = "Strong" if agreement > 0.8 else "Moderate" if agreement > 0.6 else "Weak"
329
- st.markdown(f"**Sentiment Strength:** {strength} (Agreement: {agreement:.2f})")
330
 
331
- # Display ensemble model details
332
- if data.get("ensemble_info"):
333
- st.subheader("Ensemble Model Details")
334
- ensemble_info = data["ensemble_info"]
335
-
336
- # Create columns for model details
337
- model_cols = st.columns(3)
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
- with model_cols[0]:
348
- st.markdown("**Primary Model:**")
349
- if "models" in ensemble_info and "transformer" in ensemble_info["models"]:
350
- model = ensemble_info["models"]["transformer"]
351
- st.write(f"Sentiment: {model['sentiment']}")
352
- st.write(f"Score: {model['score']:.3f}")
353
-
354
- with model_cols[1]:
355
- st.markdown("**TextBlob Analysis:**")
356
- if "models" in ensemble_info and "textblob" in ensemble_info["models"]:
357
- model = ensemble_info["models"]["textblob"]
358
- st.write(f"Sentiment: {model['sentiment']}")
359
- st.write(f"Score: {model['score']:.3f}")
360
 
361
- with model_cols[2]:
362
- st.markdown("**VADER Analysis:**")
363
- if "models" in ensemble_info and "vader" in ensemble_info["models"]:
364
- model = ensemble_info["models"]["vader"]
365
- st.write(f"Sentiment: {model['sentiment']}")
366
- st.write(f"Score: {model['score']:.3f}")
 
 
 
 
367
 
368
- # Display ensemble agreement if available
369
- if "model_agreement" in ensemble_info:
370
- st.markdown(f"**Model Agreement:** {ensemble_info['model_agreement']:.3f}")
371
-
372
- # Display Hindi audio player
373
- st.subheader("🔊 Listen to Analysis (Hindi)")
374
- if data.get("audio_path") and os.path.exists(data["audio_path"]):
375
- st.audio(data["audio_path"])
376
- else:
377
- st.info("Generating Hindi audio summary...")
378
- with st.spinner("Please wait while we generate the Hindi audio summary..."):
379
- # Try to generate audio again
380
- translator = get_translator()
381
- if translator and data.get("final_sentiment_analysis"):
382
- try:
383
- # Translate final analysis to Hindi
384
- translated_analysis = translator.translate(
385
- data["final_sentiment_analysis"],
386
- dest='hi'
387
- ).text
388
 
389
- # Generate Hindi audio
390
- tts_converter = TextToSpeechConverter()
391
- audio_path = tts_converter.generate_audio(
392
- translated_analysis,
393
- f'{company}_summary'
394
- )
395
- if audio_path and os.path.exists(audio_path):
396
- st.audio(audio_path)
397
- else:
398
- st.error("Hindi audio summary not available")
399
- except Exception as e:
400
- st.error(f"Error generating Hindi audio: {str(e)}")
401
- else:
402
- st.error("Hindi audio summary not available")
403
 
404
  # Total Articles
405
  if "total_articles" in analysis:
406
  st.sidebar.info(f"Found {analysis['total_articles']} articles")
407
-
408
- except Exception as e:
409
- st.error(f"Error analyzing company data: {str(e)}")
410
- print(f"Error: {str(e)}")
411
 
412
  # Add a disclaimer
413
- st.sidebar.markdown("---")
 
 
 
 
 
 
1
  """Streamlit frontend for the News Summarization application."""
2
 
3
  import streamlit as st
4
+ import requests
5
  import pandas as pd
6
  import json
7
+ from config import API_BASE_URL
8
  import os
9
  import plotly.express as px
10
  import altair as alt
 
 
 
 
 
 
 
 
11
 
 
12
  st.set_page_config(
13
  page_title="News Summarization App",
14
  page_icon="📰",
15
  layout="wide"
16
  )
17
 
18
+ def analyze_company(company_name):
19
+ """Send analysis request to API."""
 
20
  try:
21
+ response = requests.post(
22
+ f"{API_BASE_URL}/api/analyze",
23
+ json={"name": company_name}
24
+ )
25
+ if response.status_code == 200:
26
+ data = response.json()
27
+ # Print the response data for debugging
28
+ print("API Response Data:")
29
+ print(json.dumps(data, indent=2))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ # Download audio file if available
32
+ if 'audio_url' in data:
33
+ audio_response = requests.get(f"{API_BASE_URL}{data['audio_url']}")
34
+ if audio_response.status_code == 200:
35
+ data['audio_content'] = audio_response.content
36
+ return data
37
+ else:
38
+ st.error(f"Error from API: {response.text}")
39
+ return {"articles": [], "comparative_sentiment_score": {}, "final_sentiment_analysis": "", "audio_url": None}
40
  except Exception as e:
41
+ st.error(f"Error analyzing company: {str(e)}")
42
+ return {"articles": [], "comparative_sentiment_score": {}, "final_sentiment_analysis": "", "audio_url": None}
43
 
44
  def main():
45
  st.title("📰 News Summarization and Analysis")
46
+
47
+ # Sidebar
48
+ st.sidebar.header("Settings")
49
+
50
+ # Replace dropdown with text input
51
+ company = st.sidebar.text_input(
52
+ "Enter Company Name",
53
+ placeholder="e.g., Tesla, Apple, Microsoft, or any other company",
54
+ help="Enter the name of any company you want to analyze"
55
+ )
56
+
57
+ if st.sidebar.button("Analyze") and company:
58
+ if len(company.strip()) < 2:
59
  st.sidebar.error("Please enter a valid company name (at least 2 characters)")
60
  else:
61
  with st.spinner("Analyzing news articles..."):
62
+ result = analyze_company(company)
63
+
64
+ if result and result.get("articles"):
 
 
 
 
 
65
  # Display Articles
66
  st.header("📑 News Articles")
67
+ for idx, article in enumerate(result["articles"], 1):
68
  with st.expander(f"Article {idx}: {article['title']}"):
69
+ st.write("**Content:**", article.get("content", "No content available"))
70
+ if "summary" in article:
71
+ st.write("**Summary:**", article["summary"])
72
+ st.write("**Source:**", article.get("source", "Unknown"))
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  # Enhanced sentiment display
75
  if "sentiment" in article:
76
  sentiment_col1, sentiment_col2 = st.columns(2)
77
  with sentiment_col1:
78
+ st.write("**Sentiment:**", article["sentiment"])
79
+ st.write("**Confidence Score:**", f"{article.get('sentiment_score', 0)*100:.1f}%")
 
 
80
 
81
  with sentiment_col2:
82
  # Display fine-grained sentiment if available
83
  if "fine_grained_sentiment" in article and article["fine_grained_sentiment"]:
 
84
  fine_grained = article["fine_grained_sentiment"]
85
  if "category" in fine_grained:
86
+ st.write("**Detailed Sentiment:**", fine_grained["category"])
87
  if "confidence" in fine_grained:
88
+ st.write("**Confidence:**", f"{fine_grained['confidence']*100:.1f}%")
89
 
90
  # Display sentiment indices if available
91
  if "sentiment_indices" in article and article["sentiment_indices"]:
92
+ st.markdown("**Sentiment Indices:**")
93
+ indices = article["sentiment_indices"]
94
+
95
+ # Create columns for displaying indices
96
+ idx_cols = st.columns(3)
97
+
98
+ # Display positivity and negativity in first column
99
+ with idx_cols[0]:
100
+ if "positivity_index" in indices:
101
+ st.markdown(f"**Positivity:** {indices['positivity_index']:.2f}")
102
+ if "negativity_index" in indices:
103
+ st.markdown(f"**Negativity:** {indices['negativity_index']:.2f}")
104
+
105
+ # Display emotional intensity and controversy in second column
106
+ with idx_cols[1]:
107
+ if "emotional_intensity" in indices:
108
+ st.markdown(f"**Emotional Intensity:** {indices['emotional_intensity']:.2f}")
109
+ if "controversy_score" in indices:
110
+ st.markdown(f"**Controversy:** {indices['controversy_score']:.2f}")
111
+
112
+ # Display confidence and ESG in third column
113
+ with idx_cols[2]:
114
+ if "confidence_score" in indices:
115
+ st.markdown(f"**Confidence:** {indices['confidence_score']:.2f}")
116
+ if "esg_relevance" in indices:
117
+ st.markdown(f"**ESG Relevance:** {indices['esg_relevance']:.2f}")
118
+
119
+ # Display entities if available
120
+ if "entities" in article and article["entities"]:
121
+ st.markdown("**Named Entities:**")
122
+ entities = article["entities"]
123
+
124
+ # Organizations
125
+ if "ORG" in entities and entities["ORG"]:
126
+ st.write("**Organizations:**", ", ".join(entities["ORG"]))
127
+
128
+ # People
129
+ if "PERSON" in entities and entities["PERSON"]:
130
+ st.write("**People:**", ", ".join(entities["PERSON"]))
131
+
132
+ # Locations
133
+ if "GPE" in entities and entities["GPE"]:
134
+ st.write("**Locations:**", ", ".join(entities["GPE"]))
135
+
136
+ # Money
137
+ if "MONEY" in entities and entities["MONEY"]:
138
+ st.write("**Financial Values:**", ", ".join(entities["MONEY"]))
139
+
140
+ # Display sentiment targets if available
141
+ if "sentiment_targets" in article and article["sentiment_targets"]:
142
+ st.markdown("**Sentiment Targets:**")
143
+ targets = article["sentiment_targets"]
144
+ for target in targets:
145
+ st.markdown(f"**{target['entity']}** ({target['type']}): {target['sentiment']} ({target['confidence']*100:.1f}%)")
146
  st.markdown(f"> {target['context']}")
147
  st.markdown("---")
148
 
 
149
  if "url" in article:
150
+ st.write("**[Read More](%s)**" % article["url"])
151
 
152
  # Display Comparative Analysis
153
  st.header("📊 Comparative Analysis")
154
+ analysis = result.get("comparative_sentiment_score", {})
155
 
156
  # Sentiment Distribution
157
  if "sentiment_distribution" in analysis:
158
  st.subheader("Sentiment Distribution")
159
 
160
+ # Debug: Print sentiment distribution data
161
+ print("Sentiment Distribution Data:")
162
+ print(json.dumps(analysis["sentiment_distribution"], indent=2))
163
+
164
  sentiment_dist = analysis["sentiment_distribution"]
165
 
166
+ # Create a very simple visualization that will definitely work
167
  try:
168
  # Extract basic sentiment data
169
  if isinstance(sentiment_dist, dict):
170
+ if "basic" in sentiment_dist and isinstance(sentiment_dist["basic"], dict):
171
+ basic_dist = sentiment_dist["basic"]
172
+ elif any(k in sentiment_dist for k in ['positive', 'negative', 'neutral']):
173
+ basic_dist = {k: v for k, v in sentiment_dist.items()
174
+ if k in ['positive', 'negative', 'neutral']}
175
+ else:
176
+ basic_dist = {'positive': 0, 'negative': 0, 'neutral': 1}
177
+ else:
178
+ basic_dist = {'positive': 0, 'negative': 0, 'neutral': 1}
179
+
180
+ # Calculate percentages
181
+ total_articles = sum(basic_dist.values())
182
+ if total_articles > 0:
183
+ percentages = {
184
+ k: (v / total_articles) * 100
185
+ for k, v in basic_dist.items()
186
+ }
187
  else:
188
  percentages = {k: 0 for k in basic_dist}
189
 
190
+ # Display as simple text and metrics
191
  st.write("**Sentiment Distribution:**")
192
 
193
  col1, col2, col3 = st.columns(3)
194
+ with col1:
195
+ st.metric(
196
+ "Positive",
197
+ basic_dist.get('positive', 0),
198
+ f"{percentages.get('positive', 0):.1f}%"
199
+ )
200
+ with col2:
201
+ st.metric(
202
+ "Negative",
203
+ basic_dist.get('negative', 0),
204
+ f"{percentages.get('negative', 0):.1f}%"
205
+ )
206
+ with col3:
207
+ st.metric(
208
+ "Neutral",
209
+ basic_dist.get('neutral', 0),
210
  f"{percentages.get('neutral', 0):.1f}%"
211
  )
212
 
213
+ # Create a simple bar chart using Altair
214
+
215
+ # Create a simple DataFrame with consistent capitalization and percentages
216
  chart_data = pd.DataFrame({
217
  'Sentiment': ['Positive', 'Negative', 'Neutral'],
218
  'Count': [
219
+ basic_dist.get('positive', 0), # Map lowercase keys to capitalized display
220
  basic_dist.get('negative', 0),
221
  basic_dist.get('neutral', 0)
222
  ],
223
+ 'Percentage': [
224
+ f"{percentages.get('positive', 0):.1f}%",
225
+ f"{percentages.get('negative', 0):.1f}%",
226
+ f"{percentages.get('neutral', 0):.1f}%"
227
  ]
228
  })
229
 
230
+ # Add debug output to see what's in the data
231
+ print("Chart Data for Sentiment Distribution:")
232
+ print(chart_data)
233
+
234
+ # Create a simple bar chart with percentages
235
  chart = alt.Chart(chart_data).mark_bar().encode(
236
+ y='Sentiment', # Changed from x to y for horizontal bars
237
+ x='Count', # Changed from y to x for horizontal bars
238
  color=alt.Color('Sentiment', scale=alt.Scale(
239
  domain=['Positive', 'Negative', 'Neutral'],
240
  range=['green', 'red', 'gray']
241
  )),
242
+ tooltip=['Sentiment', 'Count', 'Percentage'] # Add tooltip with percentage
243
  ).properties(
244
  width=600,
245
  height=300
246
  )
247
 
248
+ # Add text labels with percentages
249
  text = chart.mark_text(
250
  align='left',
251
  baseline='middle',
252
+ dx=3 # Nudge text to the right so it doesn't overlap with the bar
253
  ).encode(
254
  text='Percentage'
255
  )
256
 
257
+ # Combine the chart and text
258
  chart_with_text = (chart + text)
259
+
260
  st.altair_chart(chart_with_text, use_container_width=True)
261
 
262
  except Exception as e:
263
  st.error(f"Error creating visualization: {str(e)}")
264
+ st.write("Fallback to simple text display:")
265
+ if isinstance(sentiment_dist, dict):
266
+ if "basic" in sentiment_dist:
267
+ st.write(f"Positive: {sentiment_dist['basic'].get('positive', 0)}")
268
+ st.write(f"Negative: {sentiment_dist['basic'].get('negative', 0)}")
269
+ st.write(f"Neutral: {sentiment_dist['basic'].get('neutral', 0)}")
270
+ else:
271
+ st.write(f"Positive: {sentiment_dist.get('positive', 0)}")
272
+ st.write(f"Negative: {sentiment_dist.get('negative', 0)}")
273
+ st.write(f"Neutral: {sentiment_dist.get('neutral', 0)}")
274
+ else:
275
+ st.write("No valid sentiment data available")
276
 
277
  # Display sentiment indices if available
278
  if "sentiment_indices" in analysis and analysis["sentiment_indices"]:
279
  st.subheader("Sentiment Indices")
280
 
281
+ # Debug: Print sentiment indices
282
+ print("Sentiment Indices:")
283
+ print(json.dumps(analysis["sentiment_indices"], indent=2))
284
+
285
+ # Get the indices data
286
  indices = analysis["sentiment_indices"]
287
 
288
+ # Create a very simple visualization that will definitely work
289
  try:
290
  if isinstance(indices, dict):
291
+ # Display as simple metrics in columns
292
  cols = st.columns(3)
293
 
294
+ # Define display names and descriptions
295
  display_names = {
296
  "positivity_index": "Positivity",
297
  "negativity_index": "Negativity",
298
+ "emotional_intensity": "Emotional Intensity",
299
+ "controversy_score": "Controversy",
300
+ "confidence_score": "Confidence",
301
  "esg_relevance": "ESG Relevance"
302
  }
303
 
304
+ # Display each index as a metric
305
  for i, (key, value) in enumerate(indices.items()):
306
  if isinstance(value, (int, float)):
307
  with cols[i % 3]:
308
  display_name = display_names.get(key, key.replace("_", " ").title())
309
  st.metric(display_name, f"{value:.2f}")
310
 
311
+ # Create a simple bar chart using Altair
312
+
313
+ # Create a simple DataFrame
314
  chart_data = pd.DataFrame({
315
  'Index': [display_names.get(k, k.replace("_", " ").title()) for k in indices.keys()],
316
  'Value': [v if isinstance(v, (int, float)) else 0 for v in indices.values()]
317
  })
318
 
319
+ # Create a simple bar chart
320
  chart = alt.Chart(chart_data).mark_bar().encode(
321
  x='Value',
322
  y='Index',
323
+ color=alt.Color('Index')
324
+ ).properties(
325
+ width=600,
326
+ height=300
327
+ )
328
+
329
+ st.altair_chart(chart, use_container_width=True)
330
+
331
+ # Add descriptions
332
+ with st.expander("Sentiment Indices Explained"):
333
+ st.markdown("""
334
+ - **Positivity**: Measures the positive sentiment in the articles (0-1)
335
+ - **Negativity**: Measures the negative sentiment in the articles (0-1)
336
+ - **Emotional Intensity**: Measures the overall emotional content (0-1)
337
+ - **Controversy**: High when both positive and negative sentiments are strong (0-1)
338
  - **Confidence**: Confidence in the sentiment analysis (0-1)
339
  - **ESG Relevance**: Relevance to Environmental, Social, and Governance topics (0-1)
340
  """)
341
+ else:
342
+ st.warning("Sentiment indices data is not in the expected format.")
343
+ st.write("No valid sentiment indices available")
344
  except Exception as e:
345
  st.error(f"Error creating indices visualization: {str(e)}")
346
+ st.write("Fallback to simple text display:")
347
+ if isinstance(indices, dict):
348
+ for key, value in indices.items():
349
+ if isinstance(value, (int, float)):
350
+ st.write(f"{key.replace('_', ' ').title()}: {value:.2f}")
351
+ else:
352
+ st.write("No valid sentiment indices data available")
353
 
354
+ # Source Distribution
355
+ if "source_distribution" in analysis:
356
+ st.subheader("Source Distribution")
357
+ source_df = pd.DataFrame.from_dict(
358
+ analysis["source_distribution"],
359
+ orient='index',
360
+ columns=['Count']
361
+ )
362
+ st.bar_chart(source_df)
363
 
364
+ # Common Topics
365
+ if "common_topics" in analysis:
366
+ st.subheader("Common Topics")
367
+ st.write(", ".join(analysis["common_topics"]) if analysis["common_topics"] else "No common topics found")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
 
369
+ # Coverage Differences
370
+ if "coverage_differences" in analysis:
371
+ st.subheader("Coverage Analysis")
372
+ for diff in analysis["coverage_differences"]:
373
+ st.write("- " + diff)
374
+
375
+ # Display Final Sentiment and Audio
376
+ st.header("🎯 Final Analysis")
377
+ if "final_sentiment_analysis" in result:
378
+ st.write(result["final_sentiment_analysis"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
+ # Display sentiment indices in the sidebar if available
381
+ if "sentiment_indices" in analysis and analysis["sentiment_indices"]:
382
+ indices = analysis["sentiment_indices"]
383
+ # Verify we have valid data
384
+ if indices and any(isinstance(v, (int, float)) for v in indices.values()):
385
+ st.sidebar.markdown("### Sentiment Indices")
386
+ for idx_name, idx_value in indices.items():
387
+ if isinstance(idx_value, (int, float)):
388
+ formatted_name = " ".join(word.capitalize() for word in idx_name.replace("_", " ").split())
389
+ st.sidebar.metric(formatted_name, f"{idx_value:.2f}")
390
 
391
+ # Display ensemble model information if available
392
+ if "ensemble_info" in result:
393
+ with st.expander("Ensemble Model Details"):
394
+ ensemble = result["ensemble_info"]
395
+
396
+ # Model agreement
397
+ if "agreement" in ensemble:
398
+ st.metric("Model Agreement", f"{ensemble['agreement']*100:.1f}%")
399
+
400
+ # Individual model results
401
+ if "models" in ensemble:
402
+ st.subheader("Individual Model Results")
403
+ models_data = []
404
+ for model_name, model_info in ensemble["models"].items():
405
+ models_data.append({
406
+ "Model": model_name,
407
+ "Sentiment": model_info.get("sentiment", "N/A"),
408
+ "Confidence": f"{model_info.get('confidence', 0)*100:.1f}%"
409
+ })
 
410
 
411
+ if models_data:
412
+ st.table(pd.DataFrame(models_data))
413
+
414
+ # Audio Playback Section
415
+ st.subheader("🔊 Listen to Analysis (Hindi)")
416
+ if 'audio_content' in result:
417
+ st.audio(result['audio_content'], format='audio/mp3')
418
+ else:
419
+ st.warning("Hindi audio summary not available")
 
 
 
 
 
420
 
421
  # Total Articles
422
  if "total_articles" in analysis:
423
  st.sidebar.info(f"Found {analysis['total_articles']} articles")
 
 
 
 
424
 
425
  # Add a disclaimer
426
+ st.sidebar.markdown("---")
427
+ st.sidebar.markdown("### About")
428
+ st.sidebar.write("This app analyzes news articles and provides sentiment analysis for any company.")
429
+
430
+ if __name__ == "__main__":
431
+ main()