ponshu-room-lite/lib/services/shuko_diagnosis_service.dart

168 lines
4.9 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: '自分だけの好みを探索中の、未来の巨匠。',
);
}
// v1.1: Personalization Logic
String getGreeting(String? nickname) {
if (nickname == null || nickname.trim().isEmpty) {
return 'ようこそ!';
}
return 'ようこそ、$nicknameさん';
}
ShukoTitle personalizeTitle(ShukoTitle original, String? gender) {
if (gender == null) return original;
String suffix = '';
String newTitle = original.title;
// Simple customization logic
if (gender == 'female') {
if (newTitle.contains('サムライ')) newTitle = newTitle.replaceAll('サムライ', '麗人');
if (newTitle.contains('貴族')) newTitle = newTitle.replaceAll('貴族', 'プリンセス');
if (newTitle.contains('賢者')) newTitle = newTitle.replaceAll('賢者', 'ミューズ');
if (newTitle.contains('杜氏')) newTitle = newTitle.replaceAll('杜氏', '看板娘'); // Playful
} else if (gender == 'male') {
if (newTitle.contains('貴族')) newTitle = newTitle.replaceAll('貴族', '貴公子');
}
return ShukoTitle(
title: newTitle,
description: original.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});
}