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:
2025-12-04 00:46:53 +08:00
commit 29c1633e49
13 changed files with 6184 additions and 0 deletions

315
CORS_FIX_GUIDE.md Normal file
View 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 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 跨域請求錯誤
**解決狀態**: ✅ 已提供完整解決方案