diff --git a/frontend/src/components/EmotionalStats.tsx b/frontend/src/components/EmotionalStats.tsx index 5958528..5e8d356 100644 --- a/frontend/src/components/EmotionalStats.tsx +++ b/frontend/src/components/EmotionalStats.tsx @@ -1,18 +1,109 @@ +import { + BarChart, + Bar, + XAxis, + YAxis, + Tooltip, + CartesianGrid, + ResponsiveContainer, + Legend +} from "recharts"; + import type { ContentAnalysisResponse } from "../types/ApiTypes" import StatsStyling from "../styles/stats_styling"; const styles = StatsStyling; type EmotionalStatsProps = { - contentData: ContentAnalysisResponse; + contentData: ContentAnalysisResponse; } const EmotionalStats = ({contentData}: EmotionalStatsProps) => { + const rows = contentData.average_emotion_by_topic ?? []; + const emotionKeys = rows.length + ? Object.keys(rows[0]).filter((key) => key.startsWith("emotion_")) + : []; + + const colors = ["#2563eb", "#f59e0b", "#10b981", "#ef4444", "#8b5cf6", "#14b8a6"]; + + const chartData = rows.map((row) => { + const topic = String(row.topic); + return { + ...row, + topicLabel: topic.length > 20 ? `${topic.slice(0, 20)}...` : topic + }; + }); + + const strongestPerTopic = rows.map((row) => { + let maxKey = ""; + let maxValue = Number.NEGATIVE_INFINITY; + + emotionKeys.forEach((key) => { + const value = Number(row[key] ?? 0); + if (value > maxValue) { + maxValue = value; + maxKey = key; + } + }); + + return { + topic: String(row.topic), + count: Number(row.n ?? 0), + emotion: maxKey.replace("emotion_", "") || "unknown", + value: maxValue > Number.NEGATIVE_INFINITY ? maxValue : 0 + }; + }); + + if (!rows.length) { return ( -
-

lol

-
- ) +
+

Emotion by Topic

+

No topic emotion data available.

+
+ ); + } + + return ( +
+
+

Average Emotion by Topic

+

Mean emotion scores for each detected topic

+ + {/*
+ + + + + + + + {emotionKeys.map((key, index) => ( + + ))} + + +
*/} +
+ +
+ {strongestPerTopic.map((topic) => ( +
+

{topic.topic}

+

Top emotion: {topic.emotion}

+
{topic.value.toFixed(3)}
+
+ Based on {topic.count} events +
+
+ ))} +
+
+ ); } -export default EmotionalStats; \ No newline at end of file +export default EmotionalStats; diff --git a/frontend/src/types/ApiTypes.ts b/frontend/src/types/ApiTypes.ts index 85bc92a..c654c91 100644 --- a/frontend/src/types/ApiTypes.ts +++ b/frontend/src/types/ApiTypes.ts @@ -10,6 +10,12 @@ type FrequencyWord = { count: number; } +type AverageEmotionByTopic = { + topic: string; + n: number; + [emotion: string]: string | number; +} + type Vocab = { author: string; events: number; @@ -55,6 +61,7 @@ type TimeAnalysisResponse = { // Content Analysis type ContentAnalysisResponse = { word_frequencies: FrequencyWord[]; + average_emotion_by_topic: AverageEmotionByTopic[]; } // Summary @@ -84,8 +91,9 @@ export type { User, UserAnalysisResponse, FrequencyWord, + AverageEmotionByTopic, SummaryResponse, TimeAnalysisResponse, ContentAnalysisResponse, FilterResponse -} \ No newline at end of file +}