fix(ai): 再解析を専用プロンプト+temperature=0.3に変更(東魁hallucination対策)

- reanalyzeSakeLabel() を新設: 前回のname/brandを渡し「本当に正しいか?」と問い直す
- 通常解析(temperature=0)と再解析(temperature=0.3)を分離
  → 同じ画像で毎回同じ誤答を返す問題を解消
- _callDirectApi に temperature パラメータを追加
This commit is contained in:
Ponshu Developer 2026-04-23 13:07:55 +09:00
parent 902128a3ff
commit 582553ccfa
3 changed files with 78 additions and 4 deletions

View File

@ -345,7 +345,13 @@ class _SakeDetailScreenState extends ConsumerState<SakeDetailScreen> {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AnalyzingDialog()); showDialog(context: context, barrierDismissible: false, builder: (context) => const AnalyzingDialog());
final geminiService = ref.read(geminiServiceProvider); final geminiService = ref.read(geminiServiceProvider);
final result = await geminiService.analyzeSakeLabel(existingPaths, forceRefresh: true); // : name/brand
// temperature=0.3 hallucination
final result = await geminiService.reanalyzeSakeLabel(
existingPaths,
previousName: _sake.displayData.displayName,
previousBrand: _sake.displayData.displayBrewery,
);
final newItem = _sake.copyWith( final newItem = _sake.copyWith(
name: result.name ?? _sake.displayData.displayName, name: result.name ?? _sake.displayData.displayName,

View File

@ -93,6 +93,74 @@ name・brand を出力する直前に以下を確認してください:
); );
} }
/// :
///
/// analyzeSakeLabel :
/// - name/brand
/// - temperature=0.3
/// - hallucination
Future<SakeAnalysisResult> reanalyzeSakeLabel(
List<String> imagePaths, {
String? previousName,
String? previousBrand,
}) async {
final prevNameStr = previousName != null ? '$previousName' : '不明';
final prevBrandStr = previousBrand != null ? '$previousBrand' : '不明';
final challengePrompt = '''
:
- name: $prevNameStr
- brand: $prevBrandStr
##
1. 1
2. name=$prevNameStr
3.
4. N N
## namebrandprefectureの読み取りOCR厳守
-
-
- /
- prefecture null
##
使
##
JSONのみ返す:
{
"name": "ラベルに写っている銘柄名(補完禁止)",
"brand": "ラベルに写っている蔵元名(補完禁止)",
"prefecture": "ラベルに書かれた都道府県名なければnull",
"type": "特定名称なければnull",
"description": "説明文100文字程度",
"catchCopy": "20文字以内のキャッチコピー",
"confidenceScore": 80,
"flavorTags": ["フルーティー", "辛口"],
"tasteStats": {"aroma":3,"sweetness":3,"acidity":3,"bitterness":3,"body":3},
"alcoholContent": 15.0,
"polishingRatio": 50,
"sakeMeterValue": 3.0,
"riceVariety": null,
"yeast": null,
"manufacturingYearMonth": null
}
''';
return _callDirectApi(
imagePaths,
challengePrompt,
forceRefresh: true,
temperature: 0.3,
);
}
/// : ProxyへのAPIコール /// : ProxyへのAPIコール
Future<SakeAnalysisResult> _callProxyApi({ Future<SakeAnalysisResult> _callProxyApi({
required List<String> imagePaths, required List<String> imagePaths,
@ -215,7 +283,7 @@ name・brand を出力する直前に以下を確認してください:
} }
/// Direct Cloud API Implementation (No Proxy) /// Direct Cloud API Implementation (No Proxy)
Future<SakeAnalysisResult> _callDirectApi(List<String> imagePaths, String? customPrompt, {bool forceRefresh = false}) async { Future<SakeAnalysisResult> _callDirectApi(List<String> imagePaths, String? customPrompt, {bool forceRefresh = false, double temperature = 0}) async {
// 1. // 1.
// forceRefresh=trueの場合はキャッシュをスキップ // forceRefresh=trueの場合はキャッシュをスキップ
if (!forceRefresh && imagePaths.isNotEmpty) { if (!forceRefresh && imagePaths.isNotEmpty) {
@ -316,7 +384,7 @@ name・brand を出力する直前に以下を確認してください:
), ),
generationConfig: GenerationConfig( generationConfig: GenerationConfig(
responseMimeType: 'application/json', responseMimeType: 'application/json',
temperature: 0, temperature: temperature,
), ),
); );

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.46+53 version: 1.0.47+54
environment: environment:
sdk: ^3.10.1 sdk: ^3.10.1