""" 自動修正 index.html 中的 CORS 錯誤 將直接調用 Claude API 改為通過 Flask 後端調用 """ import os import re from pathlib import Path def fix_cors_in_index_html(): """修正 index.html 中的 CORS 問題""" # 文件路徑 index_path = Path(__file__).parent / 'index.html' backup_path = Path(__file__).parent / 'index.html.backup' if not index_path.exists(): print(f"❌ 錯誤: 找不到 {index_path}") return False print(f"📂 讀取文件: {index_path}") # 讀取文件內容 with open(index_path, 'r', encoding='utf-8') as f: content = f.read() # 檢查是否已經修正過 if '/api/llm/generate' in content: print("✓ 文件已經修正過,無需重複修正") return True # 備份原文件 print(f"💾 創建備份: {backup_path}") with open(backup_path, 'w', encoding='utf-8') as f: f.write(content) # 原始代碼模式 old_pattern = r'''async function callClaudeAPI\(prompt\) \{ try \{ const response = await fetch\("https://api\.anthropic\.com/v1/messages", \{ method: "POST", headers: \{ "Content-Type": "application/json", \}, body: JSON\.stringify\(\{ model: "claude-sonnet-4-20250514", max_tokens: 2000, messages: \[ \{ role: "user", content: prompt \} \] \}\) \}\); if \(!response\.ok\) \{ throw new Error\(`API request failed: \$\{response\.status\}`\); \} const data = await response\.json\(\); let responseText = data\.content\[0\]\.text; responseText = responseText\.replace\(/```json\\n\?/g, ""\)\.replace\(/```\\n\?/g, ""\)\.trim\(\); return JSON\.parse\(responseText\); \} catch \(error\) \{ console\.error\("Error calling Claude API:", error\); throw error; \} \}''' # 新代碼 new_code = '''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 後端已啟動 (python app_updated.py)\\n2. 已在 .env 文件中配置 LLM API Key\\n3. 網路連線正常`); throw error; } }''' # 簡單替換(如果正則表達式匹配失敗) old_simple = '''async function callClaudeAPI(prompt) { try { const response = await fetch("https://api.anthropic.com/v1/messages", {''' new_simple = '''async function callClaudeAPI(prompt, api = 'gemini') { try { // 調用後端 Flask API,避免 CORS 錯誤 const response = await fetch("/api/llm/generate", {''' print("🔧 應用修正...") # 嘗試正則表達式替換 new_content = re.sub(old_pattern, new_code, content, flags=re.MULTILINE) # 如果正則表達式沒有匹配,使用簡單替換 if new_content == content: print("⚠️ 正則表達式未匹配,使用簡單替換...") # 找到函數的開始和結束 start_marker = 'async function callClaudeAPI(prompt) {' end_marker = ' }' start_idx = content.find(start_marker) if start_idx == -1: print("❌ 錯誤: 找不到 callClaudeAPI 函數") return False # 找到函數結束(找到第一個與縮進匹配的 }) end_idx = start_idx brace_count = 0 in_function = False for i in range(start_idx, len(content)): if content[i] == '{': brace_count += 1 in_function = True elif content[i] == '}': brace_count -= 1 if in_function and brace_count == 0: end_idx = i + 1 break if end_idx == start_idx: print("❌ 錯誤: 無法找到函數結束位置") return False # 替換函數 new_content = content[:start_idx] + new_code + content[end_idx:] # 寫回文件 print(f"💾 保存修正後的文件: {index_path}") with open(index_path, 'w', encoding='utf-8') as f: f.write(new_content) print("\n✅ CORS 修正完成!") print("\n📋 接下來的步驟:") print("1. 確保 .env 文件中已配置至少一個 LLM API Key") print("2. 啟動 Flask 後端: python app_updated.py") print("3. 在瀏覽器中重新載入頁面 (Ctrl+F5)") print("4. 測試 AI 自動填充功能") print(f"\n💡 原文件已備份至: {backup_path}") return True def verify_flask_backend(): """檢查是否有正確的 Flask 後端文件""" app_updated = Path(__file__).parent / 'app_updated.py' if not app_updated.exists(): print("\n⚠️ 警告: 找不到 app_updated.py") print("請確保使用包含 LLM API 端點的 Flask 後端") return False print(f"\n✓ 找到更新版 Flask 後端: {app_updated}") return True def check_env_file(): """檢查 .env 文件配置""" env_path = Path(__file__).parent / '.env' if not env_path.exists(): print("\n⚠️ 警告: 找不到 .env 文件") return False with open(env_path, 'r', encoding='utf-8') as f: env_content = f.read() has_gemini = 'GEMINI_API_KEY=' in env_content and 'your_gemini_api_key_here' not in env_content has_deepseek = 'DEEPSEEK_API_KEY=' in env_content and 'your_deepseek_api_key_here' not in env_content has_openai = 'OPENAI_API_KEY=' in env_content and 'your_openai_api_key_here' not in env_content print("\n📋 LLM API Key 配置狀態:") print(f" {'✓' if has_gemini else '✗'} Gemini API Key") print(f" {'✓' if has_deepseek else '✗'} DeepSeek API Key") print(f" {'✓' if has_openai else '✗'} OpenAI API Key") if not (has_gemini or has_deepseek or has_openai): print("\n⚠️ 警告: 沒有配置任何 LLM API Key") print("請編輯 .env 文件,添加至少一個有效的 API Key") return False return True if __name__ == '__main__': print("=" * 60) print("HR Position System - CORS 錯誤自動修正工具") print("=" * 60) print() # 修正 CORS 問題 if fix_cors_in_index_html(): # 驗證其他配置 verify_flask_backend() check_env_file() print("\n" + "=" * 60) print("✅ 修正完成!") print("=" * 60) else: print("\n" + "=" * 60) print("❌ 修正失敗,請查看上述錯誤訊息") print("=" * 60) print("\n您也可以手動修正,請參考: CORS_FIX_GUIDE.md")