138 lines
3.8 KiB
Dart
138 lines
3.8 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../models/sake_item.dart';
|
|
import '../models/schema/sake_taste_stats.dart';
|
|
|
|
final shukoDiagnosisServiceProvider = Provider((ref) => ShukoDiagnosisService());
|
|
|
|
class ShukoDiagnosisService {
|
|
ShukoProfile diagnose(List<SakeItem> items) {
|
|
if (items.isEmpty) {
|
|
return ShukoProfile.empty();
|
|
}
|
|
|
|
// 1. Calculate Average Stats
|
|
double totalAroma = 0;
|
|
double totalRichness = 0;
|
|
double totalSweetness = 0;
|
|
double totalAlcohol = 0;
|
|
double totalFruity = 0;
|
|
int count = 0;
|
|
|
|
for (var item in items) {
|
|
final stats = item.hiddenSpecs.sakeTasteStats;
|
|
totalAroma += stats.aroma;
|
|
totalRichness += stats.richness;
|
|
totalSweetness += stats.sweetness;
|
|
totalAlcohol += stats.alcoholFeeling;
|
|
totalFruity += stats.fruitiness;
|
|
count++;
|
|
}
|
|
|
|
if (count == 0) {
|
|
return ShukoProfile.empty();
|
|
}
|
|
|
|
final avgStats = SakeTasteStats(
|
|
aroma: totalAroma / count,
|
|
richness: totalRichness / count,
|
|
sweetness: totalSweetness / count,
|
|
alcoholFeeling: totalAlcohol / count,
|
|
fruitiness: totalFruity / count,
|
|
);
|
|
|
|
// 2. Determine Title based on dominant traits
|
|
final title = _determineTitle(avgStats);
|
|
|
|
return ShukoProfile(
|
|
title: title.title,
|
|
description: title.description,
|
|
avgStats: avgStats,
|
|
totalSakeCount: items.length,
|
|
analyzedCount: count,
|
|
);
|
|
}
|
|
|
|
ShukoTitle _determineTitle(SakeTasteStats stats) {
|
|
// Simple rule-based logic (can be expanded)
|
|
|
|
// High Alcohol + Dry (Low Sweetness)
|
|
if (stats.alcoholFeeling > 3.5 && stats.sweetness < 2.5) {
|
|
return const ShukoTitle(
|
|
title: '辛口サムライ',
|
|
description: 'キレのある辛口を好む、硬派な日本酒ファン。',
|
|
);
|
|
}
|
|
|
|
// High Fruitiness + High Sweetness
|
|
if (stats.fruitiness > 3.5 && stats.sweetness > 3.0) {
|
|
return const ShukoTitle(
|
|
title: 'フルーティーマスター',
|
|
description: '果実のような香りと甘みを愛する、華やかな飲み手。',
|
|
);
|
|
}
|
|
|
|
// High Richness
|
|
if (stats.richness > 3.8) {
|
|
return const ShukoTitle(
|
|
title: '旨口探求者',
|
|
description: 'お米本来の旨みやコクを重視する、通な舌の持ち主。',
|
|
);
|
|
}
|
|
|
|
// High Aroma
|
|
if (stats.aroma > 4.0) {
|
|
return const ShukoTitle(
|
|
title: '香りの貴族',
|
|
description: '吟醸香など、鼻に抜ける香りを何より楽しむタイプ。',
|
|
);
|
|
}
|
|
|
|
// Balanced (All around 3)
|
|
if (stats.aroma > 2.5 && stats.aroma < 3.5 &&
|
|
stats.sweetness > 2.5 && stats.sweetness < 3.5) {
|
|
return const ShukoTitle(
|
|
title: 'バランスの賢者',
|
|
description: '偏りなく様々な酒を楽しむ、オールラウンダー。',
|
|
);
|
|
}
|
|
|
|
// Default
|
|
return const ShukoTitle(
|
|
title: 'ポシマイ杜氏',
|
|
description: '自分だけの好みを探索中の、未来の巨匠。',
|
|
);
|
|
}
|
|
}
|
|
|
|
class ShukoProfile {
|
|
final String title;
|
|
final String description;
|
|
final SakeTasteStats avgStats;
|
|
final int totalSakeCount;
|
|
final int analyzedCount;
|
|
|
|
ShukoProfile({
|
|
required this.title,
|
|
required this.description,
|
|
required this.avgStats,
|
|
required this.totalSakeCount,
|
|
required this.analyzedCount,
|
|
});
|
|
|
|
factory ShukoProfile.empty() {
|
|
return ShukoProfile(
|
|
title: '旅の始まり',
|
|
description: 'まずは日本酒を記録して、\n自分の好みを発見しましょう。',
|
|
avgStats: SakeTasteStats(aroma: 0, richness: 0, sweetness: 0, alcoholFeeling: 0, fruitiness: 0),
|
|
totalSakeCount: 0,
|
|
analyzedCount: 0,
|
|
);
|
|
}
|
|
}
|
|
|
|
class ShukoTitle {
|
|
final String title;
|
|
final String description;
|
|
const ShukoTitle({required this.title, required this.description});
|
|
}
|