Compare commits

..

No commits in common. "b3d07f8794e9cae85491bade0db4bca5addede8b" and "d1a41b4d3be900c2c26c15b8876c4061f40235ed" have entirely different histories.

2 changed files with 32 additions and 64 deletions

View File

@ -261,9 +261,14 @@ $extractedText
throw Exception('Gemini API Key is missing. Please set GEMINI_API_KEY.'); throw Exception('Gemini API Key is missing. Please set GEMINI_API_KEY.');
} }
// : 503/UNAVAILABLE final model = GenerativeModel(
const primaryModel = 'gemini-2.5-flash'; // FIXED - confirmed 2026-01-17 model: 'gemini-2.5-flash', // FIXED MODEL NAME - DO NOT CHANGE without explicit user approval (confirmed working on 2026-01-17)
const fallbackModel = 'gemini-2.0-flash'; // 503 apiKey: apiKey,
generationConfig: GenerationConfig(
responseMimeType: 'application/json',
temperature: 0.2, // 0.40.2 (2026-02-09)
),
);
// Prepare Prompt // Prepare Prompt
final promptText = customPrompt ?? ''' final promptText = customPrompt ?? '''
@ -291,74 +296,37 @@ $extractedText
null null
'''; ''';
// Prepare Content parts () // Prepare Content
final contentParts = <Part>[TextPart(promptText)]; final contentParts = <Part>[TextPart(promptText)];
for (var path in imagePaths) { for (var path in imagePaths) {
//
final bytes = await File(path).readAsBytes(); final bytes = await File(path).readAsBytes();
contentParts.add(DataPart('image/jpeg', bytes)); contentParts.add(DataPart('image/jpeg', bytes));
} }
// 503 : try {
const maxRetries = 3; final response = await model.generateContent([Content.multi(contentParts)]);
final modelsToTry = [primaryModel, primaryModel, primaryModel, fallbackModel];
for (int attempt = 0; attempt <= maxRetries; attempt++) { final jsonString = response.text;
final modelName = modelsToTry[attempt]; if (jsonString == null) throw Exception('Empty response from Gemini');
final isLastAttempt = attempt == maxRetries;
try { final jsonMap = jsonDecode(jsonString);
if (attempt > 0) { final result = SakeAnalysisResult.fromJson(jsonMap);
final waitSec = attempt == maxRetries ? 2 : (attempt * 3);
debugPrint('Retry $attempt/$maxRetries (model: $modelName, wait: ${waitSec}s)...');
await Future.delayed(Duration(seconds: waitSec));
}
final model = GenerativeModel( // 3.
model: modelName, if (imagePaths.isNotEmpty) {
apiKey: apiKey, final imageHash = await AnalysisCacheService.computeCombinedHash(imagePaths);
generationConfig: GenerationConfig( await AnalysisCacheService.saveCache(imageHash, result);
responseMimeType: 'application/json', // 4. v1.0.15:
temperature: 0.2, await AnalysisCacheService.registerBrandIndex(result.name, imageHash);
),
);
final response = await model.generateContent([Content.multi(contentParts)]);
final jsonString = response.text;
if (jsonString == null) throw Exception('Empty response from Gemini');
final jsonMap = jsonDecode(jsonString);
final result = SakeAnalysisResult.fromJson(jsonMap);
// 3.
if (imagePaths.isNotEmpty) {
final imageHash = await AnalysisCacheService.computeCombinedHash(imagePaths);
await AnalysisCacheService.saveCache(imageHash, result);
// 4. v1.0.15:
await AnalysisCacheService.registerBrandIndex(result.name, imageHash);
}
if (attempt > 0) debugPrint('Succeeded on attempt $attempt (model: $modelName)');
return result;
} catch (e) {
final errStr = e.toString();
final is503 = errStr.contains('503') || errStr.contains('UNAVAILABLE') || errStr.contains('high demand');
debugPrint('Direct API Error (attempt $attempt, model: $modelName): $e');
if (isLastAttempt || !is503) {
// or 503
if (is503) {
throw Exception('AIサーバーが混雑しています。しばらく待ってから再試行してください。');
}
throw Exception('AI解析エラー(Direct): $e');
}
// 503
} }
}
// return result;
throw Exception('AI解析に失敗しました。再試行してください。');
} catch (e) {
debugPrint('Direct API Error: $e');
throw Exception('AI解析エラー(Direct): $e');
}
} }
} }

View File

@ -1,18 +1,18 @@
{ {
"date": "2026-04-06", "date": "2026-04-06",
"name": "Ponshu Room 1.0.22 (2026-04-09)", "name": "Ponshu Room 1.0.21 (2026-04-06)",
"version": "v1.0.22", "version": "v1.0.21",
"apks": { "apks": {
"eiji": { "eiji": {
"lite": { "lite": {
"url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.22/ponshu_room_consumer_eiji.apk", "url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.21/ponshu_room_consumer_eiji.apk",
"size_mb": 89, "size_mb": 89,
"filename": "ponshu_room_consumer_eiji.apk" "filename": "ponshu_room_consumer_eiji.apk"
} }
}, },
"maita": { "maita": {
"lite": { "lite": {
"url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.22/ponshu_room_consumer_maita.apk", "url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.21/ponshu_room_consumer_maita.apk",
"size_mb": 89, "size_mb": 89,
"filename": "ponshu_room_consumer_maita.apk" "filename": "ponshu_room_consumer_maita.apk"
} }