// さけのわAPI データモデル // API Documentation: https://muro.sakenowa.com/sakenowa-data/api/ /// 銘柄データ class SakenowaBrand { final int id; final String name; final int breweryId; const SakenowaBrand({ required this.id, required this.name, required this.breweryId, }); factory SakenowaBrand.fromJson(Map json) { return SakenowaBrand( id: json['id'] as int, name: json['name'] as String, breweryId: json['breweryId'] as int, ); } } /// 蔵元データ class SakenowaBrewery { final int id; final String name; final int areaId; const SakenowaBrewery({ required this.id, required this.name, required this.areaId, }); factory SakenowaBrewery.fromJson(Map json) { return SakenowaBrewery( id: json['id'] as int, name: json['name'] as String, areaId: json['areaId'] as int, ); } } /// 地域データ class SakenowaArea { final int id; final String name; const SakenowaArea({ required this.id, required this.name, }); factory SakenowaArea.fromJson(Map json) { return SakenowaArea( id: json['id'] as int, name: json['name'] as String, ); } } /// 6軸フレーバーチャート /// f1: 華やか, f2: 芳醇, f3: 重厚, f4: 穏やか, f5: 軽快, f6: ドライ class SakenowaFlavorChart { final int brandId; final double f1; // 華やか final double f2; // 芳醇 final double f3; // 重厚 final double f4; // 穏やか final double f5; // 軽快 final double f6; // ドライ const SakenowaFlavorChart({ required this.brandId, required this.f1, required this.f2, required this.f3, required this.f4, required this.f5, required this.f6, }); factory SakenowaFlavorChart.fromJson(Map json) { return SakenowaFlavorChart( brandId: json['brandId'] as int, f1: (json['f1'] as num).toDouble(), f2: (json['f2'] as num).toDouble(), f3: (json['f3'] as num).toDouble(), f4: (json['f4'] as num).toDouble(), f5: (json['f5'] as num).toDouble(), f6: (json['f6'] as num).toDouble(), ); } /// 軸名のラベル static const axisLabels = { 'f1': '華やか', 'f2': '芳醇', 'f3': '重厚', 'f4': '穏やか', 'f5': '軽快', 'f6': 'ドライ', }; /// レーダーチャート用のリストに変換 List toList() => [f1, f2, f3, f4, f5, f6]; /// 五味チャート形式に変換(互換性維持) /// 既存の五味チャート(aroma, sweetness, acidity, bitterness, body)に対応 Map toFiveAxisTaste() { return { 'aroma': f1, // 華やか → 香り 'sweetness': (f2 + f4) / 2, // 芳醇・穏やか → 甘み 'acidity': f5, // 軽快 → 酸味 'bitterness': f6, // ドライ → キレ 'body': f3, // 重厚 → コク }; } /// 五味チャート形式(1-5スケール)に変換 /// Gemini AI解析結果との互換性維持 Map toFiveAxisTasteInt() { final fiveAxis = toFiveAxisTaste(); return fiveAxis.map((k, v) => MapEntry(k, (v * 5).round().clamp(1, 5))); } /// レーダーチャート表示用(6軸、ラベル付き) List> toRadarData() { return [ MapEntry(axisLabels['f1']!, f1), MapEntry(axisLabels['f2']!, f2), MapEntry(axisLabels['f3']!, f3), MapEntry(axisLabels['f4']!, f4), MapEntry(axisLabels['f5']!, f5), MapEntry(axisLabels['f6']!, f6), ]; } /// 英語ラベルでのレーダーチャート用 List> toRadarDataEn() { return [ MapEntry('Elegant', f1), // 華やか MapEntry('Rich', f2), // 芳醇 MapEntry('Full', f3), // 重厚 MapEntry('Mild', f4), // 穏やか MapEntry('Light', f5), // 軽快 MapEntry('Dry', f6), // ドライ ]; } } /// ランキングエントリ class SakenowaRanking { final int rank; final int brandId; final int? areaId; final double score; const SakenowaRanking({ required this.rank, required this.brandId, this.areaId, required this.score, }); factory SakenowaRanking.fromJson(Map json) { return SakenowaRanking( rank: json['rank'] as int, brandId: json['brandId'] as int, areaId: json['areaId'] as int?, score: (json['score'] as num).toDouble(), ); } } /// フレーバータグ class SakenowaFlavorTag { final int id; final String tag; const SakenowaFlavorTag({ required this.id, required this.tag, }); factory SakenowaFlavorTag.fromJson(Map json) { return SakenowaFlavorTag( id: json['id'] as int, tag: json['tag'] as String, ); } }