vn6295337 Claude Opus 4.5 commited on
Commit
49cfe9c
·
1 Parent(s): 2570661

Fix qualitative data extraction to match actual API structure

Browse files

- News: read from metrics.news.items[] instead of metrics.news.results
- Sentiment: read from metrics.sentiment.items[] flat array with source field
instead of nested metrics.finnhub.news and metrics.reddit.posts paths
- Use datetime field instead of published_date for consistency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

frontend/src/components/MCPDataPanel.tsx CHANGED
@@ -152,6 +152,7 @@ export function MCPDataPanel({ metrics, rawData, companyName, ticker, exchange,
152
  }, [groupedMetrics])
153
 
154
  // Extract news articles from raw_data if available
 
155
  const newsArticles = React.useMemo(() => {
156
  if (!rawData) return []
157
 
@@ -162,26 +163,26 @@ export function MCPDataPanel({ metrics, rawData, companyName, ticker, exchange,
162
  source?: string
163
  }> = []
164
 
165
- // Navigate to metrics.news - the actual structure from API
166
  const metricsObj = rawData.metrics as Record<string, unknown> | undefined
167
  const newsData = metricsObj?.news as Record<string, unknown> | undefined
168
 
169
  if (newsData) {
170
- // Get results array (from Tavily/NYT/NewsAPI)
171
- const results = newsData.results as Array<Record<string, unknown>> | undefined
172
- if (results && Array.isArray(results) && results.length > 0) {
173
- for (const a of results) {
174
  articles.push({
175
  title: String(a.title || a.content || 'News article'),
176
- url: String(a.url || a.link || '#'),
177
- date: a.published_date ? String(a.published_date) : undefined,
178
  source: a.source ? String(a.source) : 'Tavily'
179
  })
180
  }
181
  }
182
  }
183
 
184
- // Fallback: check rawData.news directly
185
  if (articles.length === 0 && rawData.news && Array.isArray(rawData.news)) {
186
  for (const a of rawData.news.slice(0, 10)) {
187
  articles.push({
@@ -197,10 +198,11 @@ export function MCPDataPanel({ metrics, rawData, companyName, ticker, exchange,
197
  }, [rawData])
198
 
199
  // Extract sentiment items (individual news/posts from Finnhub and Reddit)
 
200
  const sentimentItems = React.useMemo(() => {
201
  if (!rawData) return []
202
 
203
- const items: Array<{
204
  title: string
205
  url: string
206
  date?: string
@@ -208,48 +210,27 @@ export function MCPDataPanel({ metrics, rawData, companyName, ticker, exchange,
208
  subreddit?: string
209
  }> = []
210
 
211
- // Navigate to metrics.sentiment
212
  const metricsObj = rawData.metrics as Record<string, unknown> | undefined
213
  const sentimentData = metricsObj?.sentiment as Record<string, unknown> | undefined
214
 
215
  if (!sentimentData) return []
216
 
217
- const sentMetrics = sentimentData.metrics as Record<string, unknown> | undefined
218
-
219
- // Finnhub news items
220
- if (sentMetrics?.finnhub) {
221
- const finnhub = sentMetrics.finnhub as Record<string, unknown>
222
- const news = finnhub.news as Array<Record<string, unknown>> | undefined
223
- if (news && Array.isArray(news)) {
224
- for (const n of news) {
225
- items.push({
226
- title: String(n.headline || n.title || 'Finnhub article'),
227
- url: String(n.url || '#'),
228
- date: n.datetime ? String(n.datetime) : undefined,
229
- source: 'Finnhub'
230
- })
231
- }
232
- }
233
- }
234
-
235
- // Reddit posts
236
- if (sentMetrics?.reddit) {
237
- const reddit = sentMetrics.reddit as Record<string, unknown>
238
- const posts = reddit.posts as Array<Record<string, unknown>> | undefined
239
- if (posts && Array.isArray(posts)) {
240
- for (const p of posts) {
241
- items.push({
242
- title: String(p.title || 'Reddit post'),
243
- url: String(p.url || p.permalink || '#'),
244
- date: p.created_utc ? new Date(Number(p.created_utc) * 1000).toISOString().split('T')[0] : undefined,
245
- source: 'Reddit',
246
- subreddit: p.subreddit ? String(p.subreddit) : undefined
247
- })
248
- }
249
- }
250
  }
251
 
252
- return items
253
  }, [rawData])
254
 
255
  // Build qualitative rows for table display (news + sentiment)
 
152
  }, [groupedMetrics])
153
 
154
  // Extract news articles from raw_data if available
155
+ // Actual structure: rawData.metrics.news.items[]
156
  const newsArticles = React.useMemo(() => {
157
  if (!rawData) return []
158
 
 
163
  source?: string
164
  }> = []
165
 
166
+ // Navigate to metrics.news.items - the actual structure from Research Service
167
  const metricsObj = rawData.metrics as Record<string, unknown> | undefined
168
  const newsData = metricsObj?.news as Record<string, unknown> | undefined
169
 
170
  if (newsData) {
171
+ // Get items array (flat list with source field)
172
+ const items = newsData.items as Array<Record<string, unknown>> | undefined
173
+ if (items && Array.isArray(items) && items.length > 0) {
174
+ for (const a of items) {
175
  articles.push({
176
  title: String(a.title || a.content || 'News article'),
177
+ url: String(a.url || '#'),
178
+ date: a.datetime ? String(a.datetime) : undefined,
179
  source: a.source ? String(a.source) : 'Tavily'
180
  })
181
  }
182
  }
183
  }
184
 
185
+ // Fallback: check rawData.news directly (legacy format)
186
  if (articles.length === 0 && rawData.news && Array.isArray(rawData.news)) {
187
  for (const a of rawData.news.slice(0, 10)) {
188
  articles.push({
 
198
  }, [rawData])
199
 
200
  // Extract sentiment items (individual news/posts from Finnhub and Reddit)
201
+ // Actual structure: rawData.metrics.sentiment.items[] with source field for filtering
202
  const sentimentItems = React.useMemo(() => {
203
  if (!rawData) return []
204
 
205
+ const results: Array<{
206
  title: string
207
  url: string
208
  date?: string
 
210
  subreddit?: string
211
  }> = []
212
 
213
+ // Navigate to metrics.sentiment.items - flat array with source field
214
  const metricsObj = rawData.metrics as Record<string, unknown> | undefined
215
  const sentimentData = metricsObj?.sentiment as Record<string, unknown> | undefined
216
 
217
  if (!sentimentData) return []
218
 
219
+ const items = sentimentData.items as Array<Record<string, unknown>> | undefined
220
+ if (!items || !Array.isArray(items)) return []
221
+
222
+ for (const item of items) {
223
+ const source = String(item.source || 'Unknown')
224
+ results.push({
225
+ title: String(item.title || item.content || `${source} item`),
226
+ url: String(item.url || '#'),
227
+ date: item.datetime ? String(item.datetime) : undefined,
228
+ source,
229
+ subreddit: item.subreddit ? String(item.subreddit) : undefined
230
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  }
232
 
233
+ return results
234
  }, [rawData])
235
 
236
  // Build qualitative rows for table display (news + sentiment)