iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
Mobile Development

我的 Flutter 進化論:30 天打造「Crew Up!」的架構之旅系列 第 21

Day 21 - Google Gemini API:為 App 加入 AI

  • 分享至 

  • xImage
  •  

大家好,歡迎來到第二十一天!在 Day 20,我們建立了完整的效能監控系統。今天,我們要為 Crew Up! 加入 AI 功能,讓應用程式能夠理解聊天內容、分析氣氛,並提供建議。

從專案開發的經驗來看,社群活動 App 最大的挑戰之一就是維持聊天室的活躍度。有時候群組太安靜,有時候不知道該聊什麼話題。我們想到:能不能用 AI 來幫忙炒熱氣氛呢?今天就來分享我們整合 Google Gemini API 的實際過程。

🎯 為什麼選擇 Gemini API?技術選型的考量

Gemini API vs Vertex AI:我們的決策過程

在開始實作前,我們面臨一個重要的選擇:使用 Gemini Developer API 還是 Vertex AI?

Gemini Developer API 的優勢

  • 免費額度充足:每分鐘 15 次請求,每天 1500 次請求(免費層)
  • 整合簡單:只需要 API Key,無需複雜的 GCP 設定
  • 快速上手:幾分鐘就能開始使用
  • 適合個人和小型專案:Crew Up! 的規模很適合

Vertex AI 的特點

  • 企業級功能:進階的配額管理、IAM 權限控制
  • 需要 GCP 專案:需要設定 Google Cloud Platform
  • 成本較高:沒有免費層,從第一次呼叫就開始計費
  • 適合大型企業:需要 SLA 和進階管控的場景

我們的選擇:Gemini Developer API

對於 Crew Up! 這樣的專案來說,Gemini Developer API 是更好的選擇:

  1. 開發階段免費額度足夠測試和驗證功能
  2. 整合過程簡單,可以快速看到成果
  3. 未來如果需要,可以輕鬆遷移到 Vertex AI

💡 重要提示:Google 提供了統一的 SDK,讓你可以先用 Gemini API 開發,未來需要時只需要改幾行初始化程式碼就能切換到 Vertex AI,不需要重寫整個應用。

Gemini API 的強大功能

多模態理解能力

  • 文字生成和理解
  • 對話式 AI(聊天機器人)
  • 內容分析和摘要
  • 情緒分析

適合 Crew Up! 的應用場景

  • 聊天室氣氛分析:了解群組的活躍度和情緒
  • 自動回應生成:提供適合的話題和回應建議
  • 活動建議:根據聊天內容推薦適合的活動
  • 內容審核:檢測不當內容

📋 準備工作

重要:Gemini Developer API vs Google Cloud Vertex AI

在開始之前,必須先釐清一個容易混淆的概念:Gemini API 有兩種不同的存取方式

🔵 Gemini Developer API(本文使用)

特點:

  • 透過 Google AI Studio 取得 API Key
  • 不需要 Google Cloud Platform (GCP) 帳號
  • 不需要 設定 billing(付費帳單)
  • 有慷慨的免費額度(每天 1500 次請求)
  • 直接透過 HTTPS 呼叫 generativelanguage.googleapis.com
  • 適合個人開發者和小型專案

API 端點:

https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent

🟢 Google Cloud Vertex AI(企業級方案)

特點:

  • 需要在 Google Cloud Console 建立專案
  • 必須啟用 billing(付費帳單),即使使用免費額度
  • 需要設定 Service AccountIAM 權限
  • 沒有免費額度,從第一次呼叫就開始計費
  • 透過 Google Cloud SDK 呼叫 us-central1-aiplatform.googleapis.com
  • 適合企業級應用,有 SLA 保證

API 端點:

https://us-central1-aiplatform.googleapis.com/v1/projects/YOUR_PROJECT/locations/us-central1/publishers/google/models/gemini-1.5-flash:generateContent

💡 我們的選擇:Gemini Developer API

為什麼?

  1. 不需要 GCP 帳號和 billing 設定 - 降低入門門檻
  2. 有免費額度 - 開發和測試階段完全免費
  3. 設定簡單 - 只需要一個 API Key
  4. 功能完整 - 支援所有 Gemini 模型和功能
  5. 未來可遷移 - 需要時可以無痛切換到 Vertex AI

⚠️ 重要提醒:如果你看到教學文章要求設定 Google Cloud Platform、啟用 billing、建立 Service Account,那是在講 Vertex AI,不是我們這篇文章要介紹的 Gemini Developer API。兩者雖然都能呼叫 Gemini 模型,但設定方式和使用場景完全不同!

1. 使用 Google AI Studio 獲取 API Key

我們使用 Gemini Developer API,所以只需要從 Google AI Studio 取得 API Key,不需要設定 Google Cloud Platform。過程非常簡單:

方式一:使用 Google AI Studio(推薦,最簡單)

步驟 1:前往 Google AI Studio

開啟瀏覽器,前往 Google AI Studio

步驟 2:登入 Google 帳號

使用你的 Google 帳號登入。如果還沒有帳號,可以免費註冊一個。

步驟 3:獲取 API Key

  1. 在左側選單中,點擊「Get API Key」
  2. 你會看到兩個選項:
    • Create API key in new project(在新專案中建立 API Key)- 建議選這個

步驟 4:複製 API Key

  1. 點擊「Create API key in new project」
  2. 系統會自動建立一個新的 Google Cloud 專案
  3. 幾秒鐘後,API Key 就會顯示在畫面上
  4. 點擊「Copy」按鈕複製 API Key

💡 提示:API Key 格式通常是 AIzaSy 開頭,後面接著一串英文和數字

步驟 5:儲存 API Key

將 API Key 儲存在安全的地方。我們建議:

  • 使用密碼管理工具(如 1Password、LastPass)
  • 記錄在安全的筆記本中
  • 絕對不要提交到 Git 儲存庫或公開分享

📝 Google AI Studio vs Google Cloud Console
Google AI Studio 建立 API Key 時,背後也會自動建立一個 Google Cloud 專案。但你不需要自己去 Google Cloud Console 設定任何東西。這是 Gemini Developer API 的優點 - 簡化了繁瑣的 GCP 設定流程。

驗證 API Key

獲取 API Key 後,我們可以用簡單的測試來驗證是否正常:

# 使用 curl 測試 API(Mac/Linux)
curl \
  -H 'Content-Type: application/json' \
  -d '{"contents":[{"parts":[{"text":"Say hello in Traditional Chinese"}]}]}' \
  -X POST 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=YOUR_API_KEY'

這個指令做了什麼?

這個 curl 指令會向 Gemini API 發送一個 POST 請求,要求它用繁體中文說「你好」。讓我們拆解一下:

  • -H 'Content-Type: application/json':告訴 API 我們發送的是 JSON 格式
  • -d '{"contents":...}':請求內容,包含我們要 AI 處理的提示詞
  • -X POST:使用 POST 方法
  • key=YOUR_API_KEY:在 URL 中帶入您的 API Key(記得替換成真實的 Key)

成功的回應範例

{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "你好!"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP"
    }
  ]
}

✅ 如果您看到類似上面的 JSON 回應,且包含繁體中文的「你好」或其他問候語,恭喜!您的 API Key 設定成功了。

失敗的回應範例

{
  "error": {
    "code": 400,
    "message": "API key not valid. Please pass a valid API key.",
    "status": "INVALID_ARGUMENT"
  }
}

❌ 如果看到類似的錯誤訊息,通常代表:

  • API Key 複製錯誤或不完整
  • API Key 尚未生效(剛建立時可能需要等待幾分鐘)
  • Generative Language API 尚未啟用

⚠️ 安全提醒

  1. 絕對不要將 API Key 硬編碼在程式碼中
  2. 絕對不要將 API Key 提交到 Git 儲存庫
  3. 絕對不要在公開的地方分享 API Key
  4. 如果不小心洩漏了 API Key,立即到 Google Cloud Console 刪除並重新建立

免費配額說明(2025年1月)

Gemini API 提供慷慨的免費配額:

免費層(Free Tier)

  • 每分鐘請求數:60 次(gemini-1.5-flash)
  • 每天請求數:1,500 次
  • 每月 Token 數:100 萬 Token

對於 Crew Up! 這樣的專案來說,免費配額在開發和測試階段已經相當充足。如果未來需要更多配額,可以升級到付費方案。

成本估算

付費方案的定價(2025年1月參考):

  • Gemini 1.5 Flash:輸入 $0.075 / 百萬 Token,輸出 $0.30 / 百萬 Token
  • Gemini 1.5 Pro:輸入 $1.25 / 百萬 Token,輸出 $5.00 / 百萬 Token

一則聊天室氣氛分析大約使用 500-1000 Token,成本不到 $0.001(約台幣 0.03 元)。

2. 套件安裝

# pubspec.yaml
dependencies:
  google_generative_ai: ^0.4.7    # Google Gemini API SDK
  flutter_riverpod: ^2.6.1        # 狀態管理
  riverpod_annotation: ^2.6.1     # Riverpod 程式碼生成

安裝套件:

flutter pub get

3. 環境變數設定

為了安全起見,我們使用 --dart-define 傳遞 API Key。這個方法可以讓 API Key 在編譯時被傳入,而不需要硬編碼在程式碼中。

方法一:命令列執行(適合臨時測試)

# 開發環境執行
flutter run --dart-define=GEMINI_API_KEY=your_api_key_here

# 建置 APK
flutter build apk --dart-define=GEMINI_API_KEY=your_api_key_here

方法二:VS Code 設定(推薦)

在專案根目錄建立或編輯 .vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "crew_up (development)",
      "request": "launch",
      "type": "dart",
      "args": [
        "--dart-define=GEMINI_API_KEY=your_api_key_here"
      ]
    },
    {
      "name": "crew_up (profile mode)",
      "request": "launch",
      "type": "dart",
      "flutterMode": "profile",
      "args": [
        "--dart-define=GEMINI_API_KEY=your_api_key_here"
      ]
    }
  ]
}

設定完成後,在 VS Code 的 Run and Debug 面板中選擇 "crew_up (development)",就可以一鍵啟動並自動帶入 API Key。

方法三:Android Studio / IntelliJ IDEA 設定

  1. 點擊頂部工具列的 Run Configuration 下拉選單
  2. 選擇「Edit Configurations...」
  3. 在「Additional run args」欄位中輸入:
    --dart-define=GEMINI_API_KEY=your_api_key_here
    
  4. 點擊「Apply」和「OK」

之後每次點擊 Run 按鈕,都會自動帶入這個參數。

方法四:團隊開發 - 使用 .env 檔案(進階)

對於團隊開發,我們可以結合 .env 檔案和建置腳本:

步驟 1:建立 .env 檔案

在專案根目錄建立 .env 檔案:

GEMINI_API_KEY=your_api_key_here

步驟 2:將 .env 加入 .gitignore

echo ".env" >> .gitignore

步驟 3:建立 .env.example 作為範本

# .env.example
GEMINI_API_KEY=your_api_key_here_replace_this

這個檔案可以提交到 Git,讓團隊成員知道需要哪些環境變數。

步驟 4:使用建置腳本

建立 scripts/run_with_gemini.sh(已在專案中):

#!/bin/bash
set -a
source .env
set +a

flutter run --dart-define=GEMINI_API_KEY=$GEMINI_API_KEY

執行:

chmod +x scripts/run_with_gemini.sh
./scripts/run_with_gemini.sh

💡 最佳實踐

  • 開發環境:使用 VS Code 或 Android Studio 的 Run Configuration
  • CI/CD:使用環境變數或密鑰管理服務
  • 生產環境:改用 Firebase Remote Config 或後端代理(詳見「安全性考量」章節)

🎛️ AI 參數基礎觀念

在開始整合之前,我們需要了解一些控制 AI 行為的重要參數。這些參數就像是 AI 的「個性調整器」,會大幅影響回應的風格和品質。

GeminiConfig:AI 的設定檔

/// Gemini AI 服務配置
class GeminiConfig {
  /// 預設模型
  static const String defaultModel = 'gemini-1.5-flash-latest';

  /// Temperature(控制回應的隨機性)
  static const double defaultTemperature = 0.7;

  /// 最大輸出 Token 數
  static const int maxOutputTokens = 1024;

  /// Top-K 參數(控制候選詞數量)
  static const int topK = 40;

  /// Top-P 參數(累積機率閾值)
  static const double topP = 0.95;

  const GeminiConfig();
}

核心參數詳解

1. Temperature(溫度):控制創意性 vs 一致性

這個參數做什麼?

想像 AI 在選擇下一個詞時,面前有很多選項。Temperature 決定了 AI 會不會「冒險」選擇不太可能的詞。

範圍:0.0 ~ 2.0(實務上常用 0.0 ~ 1.0)

不同溫度的效果

  • Temperature = 0.0(冰冷、確定)

    提示:「用一句話描述台灣」
    回應:「台灣是位於東亞的島國。」(每次都一樣)
    
    • ✅ 適合:客服機器人、事實查詢、程式碼生成
    • ❌ 不適合:需要創意的內容、聊天氛圍分析
  • Temperature = 0.7(溫暖、平衡) ⭐ 我們的選擇

    提示:「用一句話描述台灣」
    回應可能:
      - 「台灣是個充滿活力的美麗島嶼。」
      - 「台灣以美食和友善的人民聞名。」
      - 「台灣擁有豐富的文化和自然景觀。」
    
    • ✅ 適合:聊天室氛圍分析、鼓勵訊息生成
    • 平衡創意和穩定性
  • Temperature = 1.0+(火熱、創意)

    提示:「用一句話描述台灣」
    回應可能:
      - 「台灣!夜市、高山、海浪,一切都在這座心形島嶼跳動!」
      - 「福爾摩沙,東方的珍珠,科技與傳統交織的奇蹟之地。」
    
    • ✅ 適合:創意寫作、腦力激盪
    • ❌ 不適合:需要穩定輸出的場景

為什麼我們選 0.7?

對於聊天室氛圍分析,我們需要:

  • 夠穩定:不會每次分析同樣的訊息給出天差地別的結果
  • 夠靈活:能根據不同情境給出適當的建議

2. maxOutputTokens:控制回應長度

這個參數做什麼?

限制 AI 一次最多可以生成多少內容。

1 Token ≈ 0.75 個英文單詞
1 Token ≈ 0.5 ~ 1 個中文字

1024 Tokens ≈ 500-800 個中文字

為什麼設 1024?

  • ✅ 夠長:可以生成完整的氣氛分析報告(分數、情緒、建議、話題)
  • ✅ 不太長:避免浪費配額和等待時間
  • ✅ 成本考量:Token 越多,API 費用越高

範例

// maxOutputTokens = 100(太短)
「氣氛分數 75 分,情緒正面,建議...」(可能被截斷)

// maxOutputTokens = 1024(剛好)
完整的 JSON 格式氣氛分析,包含所有欄位

// maxOutputTokens = 4096(太長)
可能產生冗長的廢話,浪費成本

3. Top-K 和 Top-P:詞彙選擇策略

這兩個參數更進階,控制 AI 如何從候選詞中挑選。

Top-K = 40:只考慮前 40 個最可能的詞

假設 AI 要選下一個詞,所有候選詞的機率:

「台灣」(30%), 「島嶼」(25%), 「美麗」(15%), 「友善」(10%), ...

Top-K = 40 → 只從機率最高的前 40 個詞中選擇
  • ✅ 避免選到太不合理的詞
  • ✅ 保持一定的多樣性

Top-P = 0.95:累積機率達到 95% 就停止

候選詞按機率排序:
「台灣」(30%) → 累計 30%
「島嶼」(25%) → 累計 55%
「美麗」(15%) → 累計 70%
「友善」(10%) → 累計 80%
「文化」(8%)  → 累計 88%
「科技」(7%)  → 累計 95% ✓ 到這裡就停止

只從這 6 個詞中選擇,忽略剩下機率很低的詞
  • ✅ 動態調整候選詞數量
  • ✅ 更自然的語言生成

Top-K 和 Top-P 的協同作用

這兩個參數通常一起使用,提供雙重過濾:

  1. 先用 Top-K 限制最多考慮 40 個詞
  2. 再用 Top-P 進一步篩選到累積機率 95% 的詞

GeminiException:統一的錯誤處理

class GeminiException implements Exception {
  final String message;
  final String? code;
  final dynamic originalError;

  const GeminiException(this.message, {this.code, this.originalError});
}

為什麼需要自訂異常?

當 AI API 出錯時,我們需要知道:

  • message:人類可讀的錯誤訊息
  • code:程式可判斷的錯誤代碼(如 API_KEY_INVALIDQUOTA_EXCEEDED
  • originalError:原始錯誤,方便除錯

範例

try {
  await geminiService.ping();
} on GeminiException catch (e) {
  if (e.code == 'QUOTA_EXCEEDED') {
    // 顯示「今日配額已用完,請明天再試」
  } else if (e.code == 'API_KEY_INVALID') {
    // 顯示「API Key 設定錯誤」
  }
}

實務建議

參數 Crew Up! 的設定 原因
Temperature 0.7 平衡穩定性和靈活性,適合聊天分析
maxOutputTokens 1024 足夠完整分析,不會太浪費
Top-K 40 Google 建議的預設值,適合大多數場景
Top-P 0.95 保持多樣性但避免太離譜的回應

💡 進階提示:這些參數不是固定的!在 Day 22,我們會根據不同功能(氣氛分析 vs 鼓勵訊息)調整這些參數。


🔧 整合與驗證

現在我們已經了解 AI 參數的意義,接下來要建立一個輕量級的 GeminiService 來驗證整合是否成功。

建立輕量級 GeminiService

在 Day 21,我們不會馬上實作複雜的聊天室氣氛分析功能。相反地,我們先建立一個簡單的服務來確保環境設定正確。

// lib/app/core/services/gemini_service.dart
import 'dart:developer' as developer;

import 'package:google_generative_ai/google_generative_ai.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'gemini_service.g.dart';

/// Gemini AI 服務異常
class GeminiException implements Exception {
  final String message;
  final String? code;
  final dynamic originalError;

  const GeminiException(this.message, {this.code, this.originalError});

  @override
  String toString() =>
      'GeminiException: $message${code != null ? ' (code: $code)' : ''}';
}

/// 輕量級 Gemini AI 服務(驗證版本)
///
/// 這個版本只用來驗證 API Key 是否正確設定
/// 完整的功能實作將在 Day 22 介紹
class GeminiService {
  final GenerativeModel _model;
  final String _apiKey;

  GeminiService({required String apiKey})
      : _apiKey = apiKey,
        _model = GenerativeModel(
          model: 'gemini-1.5-flash-latest',
          apiKey: apiKey,
        );

  /// 初始化並驗證 Gemini AI 服務
  static Future<GeminiService?> initialize() async {
    try {
      // 從環境變數讀取 API Key
      const apiKey = String.fromEnvironment('GEMINI_API_KEY', defaultValue: '');

      if (apiKey.isEmpty) {
        developer.log(
          '⚠️  Gemini API Key not found. Please set GEMINI_API_KEY.',
          name: 'GeminiService',
        );
        return null;
      }

      developer.log(
        '🔄 Initializing Gemini AI Service...',
        name: 'GeminiService',
      );

      final service = GeminiService(apiKey: apiKey);

      // 發送一個簡單的 ping 請求來驗證連線
      await service.ping();

      developer.log(
        '✅ Gemini AI Service initialized and validated successfully',
        name: 'GeminiService',
      );

      return service;
    } on Exception catch (e) {
      developer.log(
        '❌ Gemini AI Service initialization failed: $e',
        name: 'GeminiService',
        error: e,
        level: 1000,
      );
      return null;
    }
  }

  /// 發送簡單的 ping 請求來驗證 API 連線
  Future<void> ping() async {
    try {
      final content = [Content.text('Say hello in Traditional Chinese')];
      final response = await _model.generateContent(content);

      if (response.text == null || response.text!.isEmpty) {
        throw const GeminiException(
          'Empty response from Gemini API',
          code: 'EMPTY_RESPONSE',
        );
      }

      developer.log(
        '✅ Ping successful. Response: ${response.text}',
        name: 'GeminiService',
      );
    } on Exception catch (e) {
      developer.log(
        '❌ Ping failed: $e',
        name: 'GeminiService',
        error: e,
      );
      throw GeminiException(
        'Failed to ping Gemini API',
        code: 'PING_FAILED',
        originalError: e,
      );
    }
  }
}

/// Gemini Service Provider
@riverpod
Future<GeminiService?> geminiService(GeminiServiceRef ref) async =>
    await GeminiService.initialize();

這個服務做了什麼?

  1. 簡單初始化:只接收 API Key 並建立 GenerativeModel
  2. Ping 驗證:發送一個簡單的「用繁體中文說你好」請求
  3. 清晰的日誌:在控制台清楚顯示初始化和驗證的狀態
  4. 優雅降級:如果 API Key 未設定或驗證失敗,返回 null 而不是崩潰

註冊到 Firebase 初始化流程

將 Gemini Service 加入到 App 的初始化流程中:

// lib/app/core/services/firebase_initializer.dart
import 'dart:developer' as developer;

import 'package:crew_up/app/core/services/crashlytics_service.dart';
import 'package:crew_up/app/core/services/gemini_service.dart';
import 'package:crew_up/app/core/services/performance_service.dart';
import 'package:crew_up/firebase_options.dart';
import 'package:firebase_core/firebase_core.dart';

class FirebaseInitializer {
  FirebaseInitializer._();

  /// 初始化所有 Firebase 和核心服務
  ///
  /// 返回 true 表示初始化完成(不論個別服務成功或失敗)
  /// 返回 false 表示核心初始化流程失敗
  static Future<bool> initialize() async {
    try {
      developer.log('🚀 Initializing Firebase services...', name: 'Firebase');

      // 初始化 Firebase
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      );

      // 初始化其他服務
      await CrashlyticsService.initialize();
      await PerformanceService.initialize();

      // 🆕 初始化 Gemini AI Service 並取得實例
      final gemini = await GeminiService.initialize();

      if (gemini == null) {
        developer.log(
          '⚠️  Gemini Service initialization returned null. AI features will be disabled.',
          name: 'Firebase',
        );
      }

      developer.log('✅ All services initialized', name: 'Firebase');
      return true; // 代表初始化流程完成
    } catch (e, stackTrace) {
      developer.log(
        '❌ Core services initialization failed',
        name: 'Firebase',
        error: e,
        stackTrace: stackTrace,
      );
      return false; // 初始化失敗
    }
  }
}

更新 main.dart 來等待初始化完成

最後,我們需要在 main.dart 中等待 FirebaseInitializer.initialize() 完成:

// lib/main.dart
import 'package:crew_up/app/core/services/firebase_initializer.dart';
import 'package:crew_up/app/crew_up_app.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 執行並等待所有核心服務初始化
  await FirebaseInitializer.initialize();

  runApp(
    const ProviderScope(
      child: CrewUpApp(),
    ),
  );
}

關鍵改動

  • main 函數現在是 async
  • ✅ 使用 await 等待 FirebaseInitializer.initialize() 完成
  • ✅ 確保所有服務(包括 Gemini)在 App 啟動前就緒

這個模式與 Day 18 (Crashlytics) 和 Day 20 (Performance) 保持一致。

執行並查看結果

現在執行您的 App:

flutter run --dart-define=GEMINI_API_KEY=your_api_key_here

成功的控制台輸出

🚀 Initializing Firebase services...
🔄 Initializing Gemini AI Service...
✅ Ping successful. Response: 你好!
✅ Gemini AI Service initialized and validated successfully
✅ All services initialized

✅ 如果您看到這樣的輸出,恭喜!Day 21 的環境設定任務完成了。

失敗的控制台輸出

🚀 Initializing Firebase services...
⚠️  Gemini API Key not found. Please set GEMINI_API_KEY.

🚀 Initializing Firebase services...
🔄 Initializing Gemini AI Service...
❌ Ping failed: GeminiException: API key not valid
❌ Gemini AI Service initialization failed

❌ 如果看到錯誤,請檢查:

  • API Key 是否正確複製(沒有多餘空格)
  • --dart-define 參數是否正確傳入
  • Generative Language API 是否已在 Google Cloud Console 中啟用

🎯 Day 21 總結

今天我們完成了 Google Gemini API 的環境設定:

✅ 已完成的任務

  1. ✅ 在 Google AI Studio 或 Cloud Console 建立專案並取得 API Key
  2. ✅ 使用 curl 驗證 API Key 是否有效
  3. ✅ 學習如何使用 --dart-define 傳遞環境變數
  4. ✅ 了解不同 IDE(VS Code、Android Studio)的設定方式
  5. ✅ 安裝 google_generative_ai 套件
  6. ✅ 建立輕量級 GeminiService 並成功驗證連線

🎓 關鍵學習

從今天的設定過程中,我們學到:

  1. 安全第一:絕對不要將 API Key 硬編碼或提交到 Git
  2. 先驗證再整合:使用 curl 先確認 API 可用,再寫程式
  3. 優雅降級:服務初始化失敗不應導致 App 崩潰
  4. 清晰的日誌:在開發階段,詳細的日誌能快速定位問題

🔗 與前幾天的關聯

  • Day 18 (Crashlytics):相同的服務層設計模式
  • Day 20 (Performance):統一的初始化流程
  • Day 7 (Clean Architecture):分層架構的延續

🚀 下一步:Day 22 預告

Day 21 我們只是完成了環境設定和基礎驗證。在 Day 22,我們將深入實作:

即將實作的功能

  • 🤖 聊天室氣氛分析:分析訊息情緒和活躍度
  • 💬 自動回應生成:AI 生成適合的話題和鼓勵訊息
  • 🏗️ Clean Architecture 整合:Use Case 和 Repository Pattern
  • 🧪 測試與 UI 整合:在真實的聊天室中使用 AI

期待在 Day 22 與您分享 AI 實作!



📋 相關資源

Gemini Developer API(本文使用)

Google Cloud Vertex AI(進階參考)

Flutter 相關

📝 專案資訊

  • 專案名稱: Crew Up!
  • 開發日誌: Day 21 - Google Gemini API 環境設定
  • 文章日期: 2025-10-05
  • 技術棧: Flutter 3.8+, Google Generative AI 0.4.7, Riverpod 2.6.1

上一篇
Day 20 - Firebase Performance Monitoring:數據驅動的效能優化
下一篇
Day 22 - AI Agent 實作:聊天室氣氛分析與建議系統
系列文
我的 Flutter 進化論:30 天打造「Crew Up!」的架構之旅22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言