diff --git a/build_consumer_apks.ps1 b/build_consumer_apks.ps1 index 1b33ffe..1d4f44f 100644 --- a/build_consumer_apks.ps1 +++ b/build_consumer_apks.ps1 @@ -20,8 +20,11 @@ Get-Content $envFile | ForEach-Object { } } -$maitaKey = $env:GEMINI_API_KEY_MAITA -$eijiKey = $env:GEMINI_API_KEY_EIJI +$maitaKey = $env:GEMINI_API_KEY_MAITA +$eijiKey = $env:GEMINI_API_KEY_EIJI +# POSIMAI_BASE_URL: .env.local で上書き可能。未設定時は secrets.dart のデフォルト値と一致させる +$posimaiBaseUrl = if ($env:POSIMAI_BASE_URL) { $env:POSIMAI_BASE_URL } else { 'https://api.soar-enrich.com' } + if (-not $maitaKey) { Write-Error "GEMINI_API_KEY_MAITA not set in .env.local"; exit 1 } if (-not $eijiKey) { Write-Error "GEMINI_API_KEY_EIJI not set in .env.local"; exit 1 } @@ -33,14 +36,16 @@ New-Item -ItemType Directory -Path $outputDir -Force | Out-Null Write-Host "============================================" -ForegroundColor Cyan Write-Host " Ponshu Room - Consumer APK Build" -ForegroundColor Cyan Write-Host "============================================" -ForegroundColor Cyan -Write-Host " Output: $outputDir" -ForegroundColor Gray +Write-Host " Output: $outputDir" -ForegroundColor Gray +Write-Host " POSIMAI_BASE_URL: $posimaiBaseUrl" -ForegroundColor Gray Write-Host "" # --- 1. Maita --- Write-Host "[1/2] Building Maita..." -ForegroundColor Yellow flutter build apk --release ` --dart-define=GEMINI_API_KEY=$maitaKey ` - --dart-define=IS_BUSINESS_APP=false + --dart-define=IS_BUSINESS_APP=false ` + --dart-define=POSIMAI_BASE_URL=$posimaiBaseUrl if ($LASTEXITCODE -ne 0) { Write-Error "Maita build failed"; exit 1 } @@ -53,7 +58,8 @@ Write-Host " OK: ponshu_room_consumer_maita.apk ($sz MB)" -ForegroundColor Gree Write-Host "[2/2] Building Eiji..." -ForegroundColor Yellow flutter build apk --release ` --dart-define=GEMINI_API_KEY=$eijiKey ` - --dart-define=IS_BUSINESS_APP=false + --dart-define=IS_BUSINESS_APP=false ` + --dart-define=POSIMAI_BASE_URL=$posimaiBaseUrl if ($LASTEXITCODE -ne 0) { Write-Error "Eiji build failed"; exit 1 } diff --git a/lib/services/backup_service.dart b/lib/services/backup_service.dart index 2fc16dd..b7f919d 100644 --- a/lib/services/backup_service.dart +++ b/lib/services/backup_service.dart @@ -37,7 +37,7 @@ class BackupService { try { await _googleSignIn.signInSilently(); } catch (e) { - debugPrint('⚠️ サイレントサインインエラー: $e'); + debugPrint('[BACKUP] Silent sign-in error: $e'); } } @@ -62,7 +62,7 @@ class BackupService { final account = await _googleSignIn.signIn(); return account; } catch (error) { - debugPrint('❌ Google Sign In エラー: $error'); + debugPrint('[BACKUP] Google Sign In error: $error'); return null; } } @@ -89,14 +89,14 @@ class BackupService { // 1. サインイン確認 final account = _googleSignIn.currentUser; if (account == null) { - debugPrint('❌ サインインが必要です'); + debugPrint('[BACKUP] Sign-in required'); return false; } // 2. Drive APIクライアントを作成 final authClient = await _googleSignIn.authenticatedClient(); if (authClient == null) { - debugPrint('❌ 認証クライアントの取得に失敗しました'); + debugPrint('[BACKUP] Failed to get authenticated client'); return false; } @@ -105,7 +105,7 @@ class BackupService { // 3. バックアップZIPファイルを作成 final zipFile = await _createBackupZip(); if (zipFile == null) { - debugPrint('❌ バックアップファイルの作成に失敗しました'); + debugPrint('[BACKUP] Failed to create backup ZIP'); return false; } @@ -117,7 +117,7 @@ class BackupService { return success; } catch (error) { - debugPrint('❌ バックアップ作成エラー: $error'); + debugPrint('[BACKUP] Backup creation error: $error'); return false; } } @@ -188,7 +188,7 @@ class BackupService { }).toList(); final sakeItemsFile = File(path.join(backupDir.path, 'sake_items.json')); await sakeItemsFile.writeAsString(json.encode(sakeItems)); - debugPrint('📄 sake_items.json 作成: ${await sakeItemsFile.length()} bytes'); + debugPrint('[BACKUP] sake_items.json created: ${await sakeItemsFile.length()} bytes'); // 3. settings.jsonを作成 final settings = Map.from(settingsBox.toMap()); @@ -221,10 +221,10 @@ class BackupService { // 6. 一時ディレクトリを削除 await backupDir.delete(recursive: true); - debugPrint('✅ バックアップZIPファイル作成完了: $zipPath'); + debugPrint('[BACKUP] ZIP created: $zipPath'); return File(zipPath); } catch (error) { - debugPrint('❌ ZIP作成エラー: $error'); + debugPrint('[BACKUP] ZIP creation error: $error'); return null; } } @@ -232,7 +232,7 @@ class BackupService { /// Google DriveにZIPファイルをアップロード Future _uploadToDrive(drive.DriveApi driveApi, File zipFile) async { try { - debugPrint('[BACKUP] 📤 アップロード開始: ${zipFile.lengthSync()} bytes'); + debugPrint('[BACKUP] Upload start: ${zipFile.lengthSync()} bytes'); // 1. 既存のバックアップファイルを検索 final fileList = await driveApi.files.list( q: "name = '$backupFileName' and trashed = false", @@ -244,9 +244,9 @@ class BackupService { for (var file in fileList.files!) { try { await driveApi.files.delete(file.id!); - debugPrint('🗑️ [BACKUP] 既存ファイルを削除: ${file.id}'); + debugPrint('[BACKUP] Deleted existing file: ${file.id}'); } catch (e) { - debugPrint('⚠️ [BACKUP] 既存ファイル削除失敗 (無視): $e'); + debugPrint('[BACKUP] Failed to delete existing file (ignored): $e'); } } } @@ -257,7 +257,7 @@ class BackupService { final media = drive.Media(zipFile.openRead(), zipFile.lengthSync()); - debugPrint('[BACKUP] 🚀 Driveへ送信中...'); + debugPrint('[BACKUP] Uploading to Drive...'); final uploadedFile = await driveApi.files.create( driveFile, uploadMedia: media, @@ -266,11 +266,11 @@ class BackupService { }); if (uploadedFile.id == null) { - debugPrint('❌ [BACKUP] ID取得失敗'); + debugPrint('[BACKUP] Upload failed: no file ID returned'); return false; } - debugPrint('✅ [BACKUP] アップロード完了 ID: ${uploadedFile.id}'); + debugPrint('[BACKUP] Upload complete. ID: ${uploadedFile.id}'); // 4. 検証ステップ int retryCount = 0; @@ -281,16 +281,16 @@ class BackupService { try { await driveApi.files.get(uploadedFile.id!); verified = true; - debugPrint('✅ [BACKUP] 検証成功'); + debugPrint('[BACKUP] Verification succeeded'); } catch (e) { - debugPrint('⚠️ [BACKUP] 検証試行 ${retryCount + 1} 失敗: $e'); + debugPrint('[BACKUP] Verification attempt ${retryCount + 1} failed: $e'); } retryCount++; } return verified; } catch (error) { - debugPrint('❌ [BACKUP] アップロードエラー: $error'); + debugPrint('[BACKUP] Upload error: $error'); return false; } } @@ -312,14 +312,14 @@ class BackupService { // 1. サインイン確認 final account = _googleSignIn.currentUser; if (account == null) { - debugPrint('❌ サインインが必要です'); + debugPrint('[RESTORE] Sign-in required'); return false; } // 2. Drive APIクライアントを作成 final authClient = await _googleSignIn.authenticatedClient(); if (authClient == null) { - debugPrint('❌ 認証クライアントの取得に失敗しました'); + debugPrint('[RESTORE] Failed to get authenticated client'); return false; } @@ -331,7 +331,7 @@ class BackupService { // 4. Google Driveからダウンロード final zipFile = await _downloadFromDrive(driveApi); if (zipFile == null) { - debugPrint('❌ ダウンロードに失敗しました'); + debugPrint('[RESTORE] Download failed'); return false; } @@ -343,7 +343,7 @@ class BackupService { return success; } catch (error) { - debugPrint('❌ 復元エラー: $error'); + debugPrint('[RESTORE] Restore error: $error'); return false; } } @@ -358,10 +358,10 @@ class BackupService { if (zipFile != null) { await zipFile.copy(backupPath); await zipFile.delete(); - debugPrint('✅ 復元前のデータを退避しました: $backupPath'); + debugPrint('[RESTORE] Pre-restore backup saved: $backupPath'); } } catch (error) { - debugPrint('⚠️ データ退避エラー: $error'); + debugPrint('[RESTORE] Pre-restore backup error: $error'); } } @@ -375,7 +375,7 @@ class BackupService { ); if (fileList.files == null || fileList.files!.isEmpty) { - debugPrint('❌ バックアップファイルが見つかりません'); + debugPrint('[RESTORE] No backup file found on Drive'); return null; } @@ -395,10 +395,10 @@ class BackupService { final sink = downloadFile.openWrite(); await media.stream.pipe(sink); - debugPrint('✅ ダウンロード完了: $downloadPath'); + debugPrint('[RESTORE] Download complete: $downloadPath'); return downloadFile; } catch (error) { - debugPrint('❌ ダウンロードエラー: $error'); + debugPrint('[RESTORE] Download error: $error'); return null; } } @@ -430,12 +430,12 @@ class BackupService { final outFile = File(extractPath); await outFile.create(recursive: true); await outFile.writeAsBytes(data); - debugPrint('📦 展開: $filename (${data.length} bytes)'); + debugPrint('[RESTORE] Extracted: $filename (${data.length} bytes)'); } } // デバッグ: 展開されたファイル一覧を表示 - debugPrint('📂 展開ディレクトリの中身:'); + debugPrint('[RESTORE] Extracted directory contents:'); extractDir.listSync(recursive: true).forEach((f) => debugPrint(' - ${path.basename(f.path)}')); // 2. sake_items.jsonを検索 (ルートまたはサブディレクトリ) @@ -446,12 +446,12 @@ class BackupService { sakeItemsFile = potentialFiles.firstWhere((f) => path.basename(f.path) == 'sake_items.json'); } catch (e) { // 見つからない場合 - debugPrint('❌ sake_items.json が見つかりません'); + debugPrint('[RESTORE] sake_items.json not found'); } if (sakeItemsFile != null && await sakeItemsFile.exists()) { final sakeItemsJson = json.decode(await sakeItemsFile.readAsString()) as List; - debugPrint('🔍 復元対象データ数: ${sakeItemsJson.length}件'); + debugPrint('[RESTORE] Items to restore: ${sakeItemsJson.length}'); final sakeBox = Hive.box('sake_items'); await sakeBox.clear(); @@ -499,7 +499,7 @@ class BackupService { // IDを保持するためにput()を使用(add()は新しいキーを生成してしまう) await sakeBox.put(item.id, item); } - debugPrint('✅ SakeItemsを復元しました(${sakeItemsJson.length}件)'); + debugPrint('[RESTORE] SakeItems restored (${sakeItemsJson.length} items)'); // UI更新のためにわずかに待機 await Future.delayed(const Duration(milliseconds: 500)); } @@ -509,7 +509,7 @@ class BackupService { try { settingsFile = potentialFiles.firstWhere((f) => path.basename(f.path) == 'settings.json'); } catch (e) { - debugPrint('⚠️ settings.json が見つかりません (スキップ)'); + debugPrint('[RESTORE] settings.json not found (skipped)'); } if (settingsFile != null && await settingsFile.exists()) { @@ -520,7 +520,7 @@ class BackupService { for (var entry in settingsJson.entries) { await settingsBox.put(entry.key, entry.value); } - debugPrint('✅ 設定を復元しました'); + debugPrint('[RESTORE] Settings restored'); } // 4. 画像ファイルを復元 (sake_items.jsonと同じ階層のimagesフォルダを探す) @@ -538,17 +538,17 @@ class BackupService { await imageFile.copy(path.join(appDir.path, fileName)); } } - debugPrint('✅ 画像ファイルを復元しました(${imageFiles.length}ファイル)'); + debugPrint('[RESTORE] Images restored (${imageFiles.length} files)'); } } // 5. 一時ディレクトリを削除 await extractDir.delete(recursive: true); - debugPrint('✅ データの復元が完了しました'); + debugPrint('[RESTORE] Restore complete'); return true; } catch (error) { - debugPrint('❌ 復元処理エラー: $error'); + debugPrint('[RESTORE] Restore process error: $error'); // スタックトレースも出す debugPrint(error.toString()); if (error is Error) { @@ -576,7 +576,7 @@ class BackupService { return fileList.files != null && fileList.files!.isNotEmpty; } catch (error) { - debugPrint('❌ バックアップ確認エラー: $error'); + debugPrint('[BACKUP] Check error: $error'); return false; } } diff --git a/lib/services/gemini_service.dart b/lib/services/gemini_service.dart index 2d88307..c907b63 100644 --- a/lib/services/gemini_service.dart +++ b/lib/services/gemini_service.dart @@ -199,8 +199,10 @@ class GeminiService { } // モデル候補: 503/UNAVAILABLE 時にフォールバック - const primaryModel = 'gemini-2.5-flash'; // ⚠️ FIXED - confirmed 2026-01-17 - const fallbackModel = 'gemini-2.0-flash'; // 503 連続時のフォールバック + // NOTE: Google は予告なしでモデルを廃止することがある。定期的に動作確認を行うこと。 + // Phase 2(プロキシ移行)後はサーバー側から設定を取得する設計に変更する予定。 + const primaryModel = 'gemini-2.5-flash'; + const fallbackModel = 'gemini-2.0-flash'; // Prepare Prompt (customPrompt が null のケースは通常発生しないが念のため同じ内容を保持) final promptText = customPrompt ?? '''