Initial commit: HR Position System
- Database schema with MySQL support - LLM API integration (Gemini 2.5 Flash, DeepSeek, OpenAI) - Error handling with copyable error messages - CORS fix for API calls - Complete setup documentation 🤖 Generated with Claude Code https://claude.com/claude-code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
315
CORS_FIX_GUIDE.md
Normal file
315
CORS_FIX_GUIDE.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# CORS 錯誤修正指南
|
||||
|
||||
## 🔴 問題說明
|
||||
|
||||
您遇到的錯誤有兩個:
|
||||
|
||||
### 1. CORS (跨域資源共享) 錯誤
|
||||
```
|
||||
Access to fetch at 'https://api.anthropic.com/v1/messages' from origin 'http://127.0.0.1:5000'
|
||||
has been blocked by CORS policy: Response to preflight request doesn't pass access control check:
|
||||
No 'Access-Control-Allow-Origin' header is present on the requested resource.
|
||||
```
|
||||
|
||||
**原因**: 前端代碼直接從瀏覽器調用 Claude API,但 Claude API 不允許來自瀏覽器的直接請求(出於安全考量)。
|
||||
|
||||
### 2. Storage 訪問錯誤
|
||||
```
|
||||
Uncaught (in promise) Error: Access to storage is not allowed from this context.
|
||||
```
|
||||
|
||||
**原因**: 瀏覽器的本地存儲權限問題,通常在使用 `file://` 協議或某些安全限制下出現。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 解決方案
|
||||
|
||||
### 方案 1: 修改 index.html 中的 callClaudeAPI 函數(推薦)
|
||||
|
||||
**步驟 1**: 打開 [index.html](./index.html)
|
||||
|
||||
**步驟 2**: 找到第 1264 行的 `callClaudeAPI` 函數
|
||||
|
||||
**步驟 3**: 將整個函數替換為以下代碼:
|
||||
|
||||
```javascript
|
||||
// ==================== AI Generation Functions ====================
|
||||
async function callClaudeAPI(prompt, api = 'gemini') {
|
||||
try {
|
||||
// 調用後端 Flask API,避免 CORS 錯誤
|
||||
const response = await fetch("/api/llm/generate", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
api: api, // 使用指定的 LLM API (gemini, deepseek, openai)
|
||||
prompt: prompt,
|
||||
max_tokens: 2000
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.error || `API 請求失敗: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.success) {
|
||||
throw new Error(data.error || 'API 調用失敗');
|
||||
}
|
||||
|
||||
// 解析返回的文字為 JSON
|
||||
let responseText = data.text;
|
||||
responseText = responseText.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
||||
return JSON.parse(responseText);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error calling LLM API:", error);
|
||||
|
||||
// 顯示友好的錯誤訊息
|
||||
alert(`AI 生成錯誤: ${error.message}\n\n請確保:\n1. Flask 後端已啟動\n2. 已在 .env 文件中配置 LLM API Key\n3. 網路連線正常`);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**步驟 4**: 保存文件
|
||||
|
||||
**步驟 5**: 確保使用更新版的 Flask 後端
|
||||
|
||||
```bash
|
||||
# 使用包含 LLM 端點的版本
|
||||
python app_updated.py
|
||||
```
|
||||
|
||||
**步驟 6**: 重新載入瀏覽器頁面
|
||||
|
||||
---
|
||||
|
||||
### 方案 2: 使用已修正的文件(快速方案)
|
||||
|
||||
我已經創建了包含完整修正的文件,您可以選擇以下方式之一:
|
||||
|
||||
#### 選項 A: 手動修改(最安全)
|
||||
|
||||
1. 打開 `index.html`
|
||||
2. 搜尋 `async function callClaudeAPI(prompt)`
|
||||
3. 用上面方案 1 的代碼替換
|
||||
|
||||
#### 選項 B: 使用腳本自動修正
|
||||
|
||||
參考 [fix_cors.js](./fix_cors.js) 文件中的完整說明。
|
||||
|
||||
---
|
||||
|
||||
## 📋 完整修正步驟
|
||||
|
||||
### 1. 確認後端已啟動並包含 LLM 端點
|
||||
|
||||
```bash
|
||||
# 停止當前運行的 Flask(如果有)
|
||||
# 按 Ctrl+C
|
||||
|
||||
# 啟動更新版後端
|
||||
python app_updated.py
|
||||
```
|
||||
|
||||
您應該看到:
|
||||
```
|
||||
✓ LLM 功能已啟用
|
||||
已配置的 API: gemini, deepseek, openai
|
||||
```
|
||||
|
||||
### 2. 配置 LLM API Key
|
||||
|
||||
編輯 [.env](./.env) 文件,添加至少一個 API Key:
|
||||
|
||||
```env
|
||||
# 至少配置其中一個
|
||||
GEMINI_API_KEY=your_actual_gemini_api_key_here
|
||||
DEEPSEEK_API_KEY=your_actual_deepseek_api_key_here
|
||||
OPENAI_API_KEY=your_actual_openai_api_key_here
|
||||
```
|
||||
|
||||
**獲取 API Key:**
|
||||
- **Gemini**: https://makersuite.google.com/app/apikey
|
||||
- **DeepSeek**: https://www.deepseek.com/
|
||||
- **OpenAI**: https://platform.openai.com/api-keys
|
||||
|
||||
### 3. 測試 LLM API 連線
|
||||
|
||||
訪問測試頁面:http://localhost:5000/api-test
|
||||
|
||||
點擊「測試連線」按鈕,確保至少一個 API 顯示「✓ 連線成功」。
|
||||
|
||||
### 4. 修改 index.html
|
||||
|
||||
按照方案 1 的步驟修改 `callClaudeAPI` 函數。
|
||||
|
||||
### 5. 重新載入頁面
|
||||
|
||||
在瀏覽器中按 `Ctrl+F5` 強制重新載入頁面(清除緩存)。
|
||||
|
||||
### 6. 測試 AI 功能
|
||||
|
||||
1. 在主頁面點擊「新增崗位」
|
||||
2. 填寫部分欄位(例如崗位名稱)
|
||||
3. 點擊「✨ I'm feeling lucky」按鈕
|
||||
4. 應該會成功生成內容,不再出現 CORS 錯誤
|
||||
|
||||
---
|
||||
|
||||
## 🔍 驗證修正是否成功
|
||||
|
||||
打開瀏覽器的開發者工具(F12),切換到 Console 標籤:
|
||||
|
||||
### ✅ 成功的表現:
|
||||
- 沒有 CORS 錯誤
|
||||
- 看到 `POST http://localhost:5000/api/llm/generate` 請求成功 (200 OK)
|
||||
- AI 自動填充正常工作
|
||||
|
||||
### ❌ 仍有問題:
|
||||
|
||||
#### 如果看到 `403 LLM 功能未啟用`
|
||||
**原因**: 沒有使用 `app_updated.py`
|
||||
**解決**:
|
||||
```bash
|
||||
python app_updated.py
|
||||
```
|
||||
|
||||
#### 如果看到 `API Key 未設定`
|
||||
**原因**: .env 文件中沒有配置 API Key
|
||||
**解決**: 編輯 `.env` 文件,添加有效的 API Key
|
||||
|
||||
#### 如果看到 `連線逾時`
|
||||
**原因**: 網路連線問題或 API 伺服器問題
|
||||
**解決**:
|
||||
1. 檢查網路連線
|
||||
2. 嘗試使用不同的 LLM API(修改 `callClaudeAPI(prompt, 'deepseek')`)
|
||||
|
||||
#### 如果看到 `API Key 無效`
|
||||
**原因**: API Key 錯誤或已過期
|
||||
**解決**: 重新獲取有效的 API Key
|
||||
|
||||
---
|
||||
|
||||
## 🎯 架構變更說明
|
||||
|
||||
### 修正前(錯誤):
|
||||
```
|
||||
瀏覽器 → 直接調用 → Claude API (❌ CORS 錯誤)
|
||||
```
|
||||
|
||||
### 修正後(正確):
|
||||
```
|
||||
瀏覽器 → Flask 後端 → Gemini/DeepSeek/OpenAI API (✅ 正常)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 為什麼這樣修改
|
||||
|
||||
### 1. 安全性
|
||||
- **API Key 保護**: API Key 只存儲在服務器端(.env 文件),不暴露給前端
|
||||
- **防止濫用**: 用戶無法看到或竊取 API Key
|
||||
|
||||
### 2. CORS 問題
|
||||
- **同源請求**: 前端只調用同域的 Flask API(http://localhost:5000)
|
||||
- **服務器端請求**: Flask 服務器調用外部 API,不受 CORS 限制
|
||||
|
||||
### 3. 靈活性
|
||||
- **多 API 支持**: 可以輕鬆切換不同的 LLM API
|
||||
- **統一接口**: 前端代碼無需關心使用哪個 LLM API
|
||||
|
||||
---
|
||||
|
||||
## 📝 其他建議
|
||||
|
||||
### 1. 添加錯誤處理 UI
|
||||
|
||||
在 `<head>` 標籤中添加錯誤處理腳本:
|
||||
|
||||
```html
|
||||
<script src="error_handler.js"></script>
|
||||
```
|
||||
|
||||
### 2. 選擇 LLM API
|
||||
|
||||
如果想使用特定的 LLM API,可以修改調用:
|
||||
|
||||
```javascript
|
||||
// 使用 Gemini(默認)
|
||||
const result = await callClaudeAPI(prompt, 'gemini');
|
||||
|
||||
// 使用 DeepSeek
|
||||
const result = await callClaudeAPI(prompt, 'deepseek');
|
||||
|
||||
// 使用 OpenAI
|
||||
const result = await callClaudeAPI(prompt, 'openai');
|
||||
```
|
||||
|
||||
### 3. 添加 API 選擇器
|
||||
|
||||
可以在前端添加一個下拉選單,讓用戶選擇使用哪個 LLM API:
|
||||
|
||||
```html
|
||||
<select id="llm-selector">
|
||||
<option value="gemini">Google Gemini</option>
|
||||
<option value="deepseek">DeepSeek</option>
|
||||
<option value="openai">OpenAI</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
然後在調用時使用:
|
||||
```javascript
|
||||
const api = document.getElementById('llm-selector').value;
|
||||
const result = await callClaudeAPI(prompt, api);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🆘 仍然遇到問題?
|
||||
|
||||
### 檢查清單
|
||||
|
||||
- [ ] Flask 後端是否正在運行?
|
||||
- [ ] 是否使用 `app_updated.py` 而不是 `app.py`?
|
||||
- [ ] .env 文件中是否配置了至少一個 API Key?
|
||||
- [ ] API Key 是否有效?(可以在 http://localhost:5000/api-test 測試)
|
||||
- [ ] 是否已修改 index.html 中的 `callClaudeAPI` 函數?
|
||||
- [ ] 瀏覽器是否已重新載入頁面(Ctrl+F5)?
|
||||
- [ ] 瀏覽器控制台是否還有其他錯誤?
|
||||
|
||||
### 調試步驟
|
||||
|
||||
1. **測試後端 API**:
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/llm/generate \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"api":"gemini","prompt":"測試","max_tokens":100}'
|
||||
```
|
||||
|
||||
2. **檢查 Flask 日誌**: 查看終端中 Flask 的輸出
|
||||
|
||||
3. **瀏覽器控制台**: 查看詳細的錯誤訊息
|
||||
|
||||
4. **測試頁面**: 訪問 http://localhost:5000/api-test 確認 API 配置
|
||||
|
||||
---
|
||||
|
||||
## 📚 相關文件
|
||||
|
||||
- [SETUP.md](./SETUP.md) - 完整安裝指南
|
||||
- [fix_cors.js](./fix_cors.js) - 詳細修正代碼
|
||||
- [error_handler.js](./error_handler.js) - 全局錯誤處理
|
||||
- [app_updated.py](./app_updated.py) - 包含 LLM 端點的 Flask 後端
|
||||
|
||||
---
|
||||
|
||||
**文件版本**: 1.0
|
||||
**最後更新**: 2024-12-04
|
||||
**問題類型**: CORS 跨域請求錯誤
|
||||
**解決狀態**: ✅ 已提供完整解決方案
|
||||
Reference in New Issue
Block a user