/** * Utility functions for analyzing analysis results and calculating statistics */ import type { AnalysisResult } from '../types/analysis.types.ts'; /** * Statistics about stance distribution */ export type StanceStats = { total: number; pro: number; con: number; proPercentage: number; conPercentage: number; }; /** * Topic frequency data */ export type TopicFrequency = { topic: string; count: number; proCount: number; conCount: number; }; /** * Time-based statistics */ export type TimeStats = { date: string; count: number; }; /** * Calculate stance distribution statistics */ export function calculateStanceStats(results: AnalysisResult[]): StanceStats { const total = results.length; const pro = results.filter((r) => r.predicted_stance === 'PRO').length; const con = results.filter((r) => r.predicted_stance === 'CON').length; return { total, pro, con, proPercentage: total > 0 ? (pro / total) * 100 : 0, conPercentage: total > 0 ? (con / total) * 100 : 0, }; } /** * Calculate topic frequency statistics */ export function calculateTopicFrequency( results: AnalysisResult[], limit: number = 10 ): TopicFrequency[] { const topicMap = new Map(); results.forEach((result) => { const topic = result.topic.trim(); if (!topic) return; const existing = topicMap.get(topic) || { count: 0, proCount: 0, conCount: 0 }; existing.count += 1; if (result.predicted_stance === 'PRO') { existing.proCount += 1; } else { existing.conCount += 1; } topicMap.set(topic, existing); }); return Array.from(topicMap.entries()) .map(([topic, stats]) => ({ topic, count: stats.count, proCount: stats.proCount, conCount: stats.conCount, })) .sort((a, b) => b.count - a.count) .slice(0, limit); } /** * Calculate time-based statistics (grouped by date) */ export function calculateTimeStats(results: AnalysisResult[]): TimeStats[] { const dateMap = new Map(); results.forEach((result) => { const date = new Date(result.created_at).toISOString().split('T')[0]; dateMap.set(date, (dateMap.get(date) || 0) + 1); }); return Array.from(dateMap.entries()) .map(([date, count]) => ({ date, count })) .sort((a, b) => a.date.localeCompare(b.date)); } /** * Get unique topics count */ export function getUniqueTopicsCount(results: AnalysisResult[]): number { const uniqueTopics = new Set(results.map((r) => r.topic.trim()).filter((t) => t)); return uniqueTopics.size; } /** * Get average argument length (in characters) */ export function getAverageArgumentLength(results: AnalysisResult[]): number { if (results.length === 0) return 0; const totalLength = results.reduce((sum, r) => sum + r.argument.length, 0); return Math.round(totalLength / results.length); } /** * Get most recent analysis date */ export function getMostRecentAnalysisDate(results: AnalysisResult[]): string | null { if (results.length === 0) return null; const dates = results.map((r) => new Date(r.created_at).getTime()); const mostRecent = new Date(Math.max(...dates)); return mostRecent.toISOString().split('T')[0]; } /** * Get oldest analysis date */ export function getOldestAnalysisDate(results: AnalysisResult[]): string | null { if (results.length === 0) return null; const dates = results.map((r) => new Date(r.created_at).getTime()); const oldest = new Date(Math.min(...dates)); return oldest.toISOString().split('T')[0]; }