6.7 KiB
6.7 KiB
Gemini AI API 整合文檔
概述
本文檔說明如何整合 Google Gemini API 來實現 AI 詞卡生成功能。
API 設置
1. 取得 API Key
- 訪問 Google AI Studio
- 點擊 "Create API Key"
- 選擇專案或建立新專案
- 複製生成的 API Key
2. 安裝 SDK
npm install @google/generative-ai
3. 環境變數配置
GEMINI_API_KEY=your_api_key_here
API 實作
基礎設置
// lib/gemini.ts
import { GoogleGenerativeAI } from '@google/generative-ai';
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
export const geminiModel = genAI.getGenerativeModel({
model: "gemini-pro"
});
詞卡生成功能
// app/api/ai/generate-flashcard/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { geminiModel } from '@/lib/gemini';
export async function POST(request: NextRequest) {
try {
const { text, type } = await request.json();
const prompt = createPrompt(text, type);
const result = await geminiModel.generateContent(prompt);
const response = await result.response;
const generatedText = response.text();
const flashcards = parseFlashcards(generatedText);
return NextResponse.json({ flashcards });
} catch (error) {
console.error('Gemini API error:', error);
return NextResponse.json(
{ error: 'Failed to generate flashcards' },
{ status: 500 }
);
}
}
Prompt 工程
基礎 Prompt 模板
const FLASHCARD_PROMPT = `
你是一個專業的英語教學助手,專門幫助台灣學生透過美劇學習英文。
請根據以下內容生成詞卡:
輸入文本:{input_text}
請生成5個最重要的詞彙學習卡片,每個卡片包含:
1. 英文單字或片語
2. 中文翻譯
3. 詞性和用法說明
4. 原文例句(從輸入文本中提取)
5. 額外例句(創造一個相似情境的例句)
6. 使用情境說明(什麼場合使用)
7. 難度等級(1-5,1最簡單)
請以 JSON 格式回覆,格式如下:
{
"flashcards": [
{
"word": "英文單字或片語",
"translation": "中文翻譯",
"partOfSpeech": "詞性",
"usage": "用法說明",
"originalExample": "原文例句",
"additionalExample": "額外例句",
"context": "使用情境",
"difficulty": 難度數字
}
]
}
`;
不同類型的 Prompt
1. 美劇對話分析
const DRAMA_DIALOGUE_PROMPT = `
分析以下美劇對話,提取日常對話中的重要表達:
- 重點關注俚語、慣用語、口語表達
- 解釋文化背景和使用場合
- 標註正式程度(非常口語/口語/中性/正式)
`;
2. 主題學習
const TOPIC_LEARNING_PROMPT = `
生成關於「{topic}」主題的詞彙卡片:
- 包含該主題最常用的詞彙
- 提供實用的搭配詞和片語
- 給出真實對話場景的例句
`;
3. 語法重點
const GRAMMAR_FOCUS_PROMPT = `
分析文本中的語法結構:
- 識別重要的語法模式
- 解釋語法規則和例外
- 提供類似結構的變化練習
`;
回應解析
JSON 解析函數
function parseFlashcards(responseText: string) {
try {
// 清理回應文本(移除可能的 markdown 標記)
const cleanedText = responseText
.replace(/```json\n?/g, '')
.replace(/```\n?/g, '')
.trim();
const parsed = JSON.parse(cleanedText);
return parsed.flashcards;
} catch (error) {
console.error('Parse error:', error);
// 備用解析邏輯
return extractFlashcardsManually(responseText);
}
}
錯誤處理與重試
async function generateWithRetry(prompt: string, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const result = await geminiModel.generateContent(prompt);
return result;
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
Rate Limiting 與配額管理
請求限制
import { RateLimiter } from '@/lib/rate-limiter';
const limiter = new RateLimiter({
tokensPerInterval: 60, // Gemini Free: 60 QPM
interval: 'minute',
});
export async function checkRateLimit(userId: string) {
const isAllowed = await limiter.check(userId);
if (!isAllowed) {
throw new Error('Rate limit exceeded');
}
}
配額追蹤
// 記錄用戶使用量
async function trackUsage(userId: string, tokensUsed: number) {
await supabase
.from('user_usage')
.upsert({
user_id: userId,
date: new Date().toISOString().split('T')[0],
gemini_tokens: tokensUsed,
});
}
最佳實踐
1. Prompt 優化
- 使用具體、清晰的指示
- 提供輸出格式範例
- 設定合適的 temperature (0.7-0.9)
2. 成本控制
- 限制每個請求的 token 數量
- 實施用戶配額系統
- 快取常見請求結果
3. 錯誤處理
- 實施重試機制
- 提供降級方案
- 記錄錯誤日誌
4. 安全考量
- 不在前端暴露 API Key
- 實施內容過濾
- 驗證用戶輸入
測試範例
單元測試
describe('Gemini Integration', () => {
it('should generate flashcards from text', async () => {
const input = "I'm gonna grab a coffee, wanna come?";
const result = await generateFlashcards(input);
expect(result).toHaveLength(5);
expect(result[0]).toHaveProperty('word');
expect(result[0]).toHaveProperty('translation');
});
it('should handle rate limiting', async () => {
// 測試超過限制的請求
});
});
整合測試
describe('API Endpoint', () => {
it('should return flashcards via API', async () => {
const response = await fetch('/api/ai/generate-flashcard', {
method: 'POST',
body: JSON.stringify({ text: 'test input' }),
});
expect(response.status).toBe(200);
const data = await response.json();
expect(data.flashcards).toBeDefined();
});
});
監控與日誌
關鍵指標
- API 回應時間
- 成功/失敗率
- Token 使用量
- 用戶滿意度
日誌記錄
import { logger } from '@/lib/logger';
logger.info('Gemini API called', {
userId,
promptLength: prompt.length,
responseTime: Date.now() - startTime,
});
故障排除
常見問題
-
API Key 無效
- 確認環境變數設置正確
- 檢查 API Key 是否啟用
-
Rate Limit 錯誤
- 實施請求隊列
- 升級到付費方案
-
回應解析失敗
- 改進 prompt 明確性
- 實施備用解析邏輯
-
生成品質不佳
- 調整 temperature 參數
- 優化 prompt 內容
- 提供更多範例