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

8.1 KiB
Raw Permalink Blame History

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

步驟 2: 找到第 1264 行的 callClaudeAPI 函數

步驟 3: 將整個函數替換為以下代碼:

// ==================== 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 後端

# 使用包含 LLM 端點的版本
python app_updated.py

步驟 6: 重新載入瀏覽器頁面


方案 2: 使用已修正的文件(快速方案)

我已經創建了包含完整修正的文件,您可以選擇以下方式之一:

選項 A: 手動修改(最安全)

  1. 打開 index.html
  2. 搜尋 async function callClaudeAPI(prompt)
  3. 用上面方案 1 的代碼替換

選項 B: 使用腳本自動修正

參考 fix_cors.js 文件中的完整說明。


📋 完整修正步驟

1. 確認後端已啟動並包含 LLM 端點

# 停止當前運行的 Flask如果有
# 按 Ctrl+C

# 啟動更新版後端
python app_updated.py

您應該看到:

✓ LLM 功能已啟用
  已配置的 API: gemini, deepseek, openai

2. 配置 LLM API Key

編輯 .env 文件,添加至少一個 API Key

# 至少配置其中一個
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:

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 解決:

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> 標籤中添加錯誤處理腳本:

<script src="error_handler.js"></script>

2. 選擇 LLM API

如果想使用特定的 LLM API可以修改調用

// 使用 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

<select id="llm-selector">
    <option value="gemini">Google Gemini</option>
    <option value="deepseek">DeepSeek</option>
    <option value="openai">OpenAI</option>
</select>

然後在調用時使用:

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:

    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 配置


📚 相關文件


文件版本: 1.0 最後更新: 2024-12-04 問題類型: CORS 跨域請求錯誤 解決狀態: 已提供完整解決方案