Files
Finlytic/FinlyticApp/lib/features/news/widgets/finbert_sentiment_tab.dart
T

118 lines
5.0 KiB
Dart

import 'package:flutter/material.dart';
import '../../../core/theme/app_theme.dart';
import '../../../core/widgets/glass_container.dart';
import '../../../core/widgets/status_badge.dart';
import '../models/news_article_model.dart';
class FinbertSentimentTab extends StatelessWidget {
final NewsArticleModel article;
const FinbertSentimentTab({super.key, required this.article});
@override
Widget build(BuildContext context) {
final finbert = article.finbertResult;
final double compoundScore = finbert?.score ?? article.sentimentScore;
final double confidenceScore = article.confidence;
final String label = (finbert?.label ?? article.sentiment).toUpperCase();
final double posRatio = finbert?.positiveProbability ?? (label == 'POSITIVE' ? 0.8 : 0.1);
final double neuRatio = finbert?.neutralProbability ?? (label == 'NEUTRAL' ? 0.8 : 0.1);
final double negRatio = finbert?.negativeProbability ?? (label == 'NEGATIVE' ? 0.8 : 0.1);
final String aiText = finbert?.summarySnippet ?? (article.summary.isNotEmpty ? article.summary : 'FinBERT Sentiment-Analyse verarbeitet.');
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(Icons.psychology, color: AppTheme.accentCyan, size: 24),
const SizedBox(width: 8),
const Text('FinBERT NLP Modell', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: Colors.white)),
],
),
StatusBadge.sentiment(label.isNotEmpty ? label : 'NEUTRAL', score: compoundScore),
],
),
const SizedBox(height: 16),
GlassContainer(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Sentiment Verteilung (Wahrscheinlichkeiten):', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 13, color: Colors.white)),
const SizedBox(height: 12),
_buildProbBar('Positiv', posRatio, AppTheme.primaryEmerald),
const SizedBox(height: 8),
_buildProbBar('Neutral', neuRatio, Colors.amber),
const SizedBox(height: 8),
_buildProbBar('Negativ', negRatio, AppTheme.accentRed),
],
),
),
const SizedBox(height: 16),
GlassContainer(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Konfidenz-Score:', style: TextStyle(color: Colors.white70, fontSize: 13)),
Text('${(confidenceScore * 100).toStringAsFixed(1)}%', style: TextStyle(color: AppTheme.accentCyan, fontWeight: FontWeight.bold, fontSize: 14)),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Compound Sentiment-Wert:', style: TextStyle(color: Colors.white70, fontSize: 13)),
Text(compoundScore.toStringAsFixed(2), style: TextStyle(color: compoundScore >= 0 ? AppTheme.primaryEmerald : AppTheme.accentRed, fontWeight: FontWeight.bold, fontSize: 14)),
],
),
],
),
),
const SizedBox(height: 16),
const Text('KI-Zusammenfassung & Relevanz:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: Colors.white)),
const SizedBox(height: 8),
Text(aiText, style: const TextStyle(color: Colors.white70, fontSize: 13, height: 1.4)),
],
),
);
}
Widget _buildProbBar(String label, double ratio, Color color) {
final pct = (ratio * 100).clamp(0.0, 100.0);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: TextStyle(color: AppTheme.textMuted, fontSize: 12)),
Text('${pct.toStringAsFixed(1)}%', style: TextStyle(color: color, fontWeight: FontWeight.bold, fontSize: 12)),
],
),
const SizedBox(height: 4),
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: ratio.clamp(0.0, 1.0),
backgroundColor: Colors.white.withValues(alpha: 0.08),
valueColor: AlwaysStoppedAnimation<Color>(color),
minHeight: 6,
),
),
],
);
}
}