ponshu-room-lite/lib/models/schema/hidden_specs.dart

145 lines
4.4 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:hive/hive.dart';
import 'sake_taste_stats.dart';
part 'hidden_specs.g.dart';
@HiveType(typeId: 12)
class HiddenSpecs extends HiveObject {
@HiveField(0)
final String? description;
@HiveField(1)
final Map<String, int> tasteStats;
@HiveField(2)
final List<String> flavorTags;
@HiveField(3)
final double? sweetnessScore;
@HiveField(4)
final double? bodyScore;
// Future specs
@HiveField(5)
final String? type; // 特定名称
@HiveField(6)
final double? alcoholContent;
@HiveField(7)
final int? polishingRatio;
@HiveField(8)
final double? sakeMeterValue; // 日本酒度
@HiveField(9)
final String? riceVariety;
@HiveField(10)
final String? yeast;
@HiveField(11)
final String? manufacturingYearMonth;
@HiveField(12)
final String? qrCodeUrl;
// ✅ 6軸フレーバーチャートさけのわデータ
@HiveField(13)
final Map<String, double>? sakenowaFlavorChart; // {f1, f2, f3, f4, f5, f6}
@HiveField(14)
final int? sakenowaBrandId; // さけのわ銘柄IDマッチング用
// Helper getter to convert generic Map to typed SakeTasteStats
SakeTasteStats get sakeTasteStats {
if (tasteStats.isEmpty) {
return SakeTasteStats(aroma: 0, bitterness: 0, sweetness: 0, acidity: 0, body: 0);
}
return SakeTasteStats.fromMap(tasteStats);
}
/// ✅ アクティブな味覚データ取得6軸優先、フォールバックで5軸
/// さけのわデータがあればそれを使用、なければGemini解析結果
Map<String, double> get activeTasteData {
if (sakenowaFlavorChart != null && sakenowaFlavorChart!.isNotEmpty) {
// さけのわ6軸を五味5軸に変換して返す
final f1 = sakenowaFlavorChart!['f1'] ?? 0.5;
final f2 = sakenowaFlavorChart!['f2'] ?? 0.5;
final f3 = sakenowaFlavorChart!['f3'] ?? 0.5;
final f4 = sakenowaFlavorChart!['f4'] ?? 0.5;
final f5 = sakenowaFlavorChart!['f5'] ?? 0.5;
final f6 = sakenowaFlavorChart!['f6'] ?? 0.5;
return {
'aroma': f1, // 華やか → 香り
'sweetness': (f2 + f4) / 2, // 芳醇・穏やか → 甘み
'acidity': f5, // 軽快 → 酸味
'bitterness': f6, // ドライ → キレ
'body': f3, // 重厚 → コク
};
}
// フォールバック: Gemini五味チャート
return tasteStats.map((k, v) => MapEntry(k, v.toDouble() / 5));
}
/// ✅ 6軸フレーバーの有無を判定
bool get hasSakenowaFlavorChart =>
sakenowaFlavorChart != null && sakenowaFlavorChart!.isNotEmpty;
HiddenSpecs({
this.description,
this.tasteStats = const {},
this.flavorTags = const [],
this.sweetnessScore,
this.bodyScore,
this.type,
this.alcoholContent,
this.polishingRatio,
this.sakeMeterValue,
this.riceVariety,
this.yeast,
this.manufacturingYearMonth,
this.qrCodeUrl,
this.sakenowaFlavorChart, // ✅ 追加
this.sakenowaBrandId, // ✅ 追加
});
HiddenSpecs copyWith({
String? description,
Map<String, int>? tasteStats,
List<String>? flavorTags,
double? sweetnessScore,
double? bodyScore,
String? type,
double? alcoholContent,
int? polishingRatio,
double? sakeMeterValue,
String? riceVariety,
String? yeast,
String? manufacturingYearMonth,
String? qrCodeUrl,
Map<String, double>? sakenowaFlavorChart, // ✅ 追加
int? sakenowaBrandId, // ✅ 追加
}) {
return HiddenSpecs(
description: description ?? this.description,
tasteStats: tasteStats ?? this.tasteStats,
flavorTags: flavorTags ?? this.flavorTags,
sweetnessScore: sweetnessScore ?? this.sweetnessScore,
bodyScore: bodyScore ?? this.bodyScore,
type: type ?? this.type,
alcoholContent: alcoholContent ?? this.alcoholContent,
polishingRatio: polishingRatio ?? this.polishingRatio,
sakeMeterValue: sakeMeterValue ?? this.sakeMeterValue,
riceVariety: riceVariety ?? this.riceVariety,
yeast: yeast ?? this.yeast,
manufacturingYearMonth: manufacturingYearMonth ?? this.manufacturingYearMonth,
qrCodeUrl: qrCodeUrl ?? this.qrCodeUrl,
sakenowaFlavorChart: sakenowaFlavorChart ?? this.sakenowaFlavorChart, // ✅ 追加
sakenowaBrandId: sakenowaBrandId ?? this.sakenowaBrandId, // ✅ 追加
);
}
}