Files
hr-position-system/CORS_FIX_GUIDE.md
DonaldFang 方士碩 29c1633e49 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>
2025-12-04 00:46:53 +08:00

316 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 APIhttp://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 跨域請求錯誤
**解決狀態**: ✅ 已提供完整解決方案