主要功能更新: - 崗位描述保存功能:保存後資料寫入資料庫 - 崗位清單自動刷新:切換模組時自動載入最新資料 - 崗位清單檢視功能:點擊「檢視」按鈕載入對應描述 - 管理者頁面擴充:新增崗位資料管理與匯出功能 - CSV 批次匯入:支援崗位與職務資料批次匯入 後端 API 新增: - Position Description CRUD APIs - Position List Query & Export APIs - CSV Template Download & Import APIs 文件更新: - SDD.md 更新至版本 2.1 - README.md 更新功能說明與版本歷史 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
156 lines
4.6 KiB
JavaScript
156 lines
4.6 KiB
JavaScript
/**
|
||
* CORS 錯誤修正
|
||
* 將直接調用 Claude API 改為通過後端 Flask API 調用
|
||
*
|
||
* 使用方法:
|
||
* 1. 在 index.html 中找到 callClaudeAPI 函數
|
||
* 2. 將其替換為下面的新版本
|
||
*/
|
||
|
||
// ==================== 修正後的 AI Generation Functions ====================
|
||
|
||
/**
|
||
* 調用後端 LLM API 生成文字
|
||
* @param {string} prompt - 提示詞
|
||
* @param {string} api - API 名稱 (gemini, deepseek, openai)
|
||
* @returns {Promise<Object>} - 生成的 JSON 數據
|
||
*/
|
||
async function callClaudeAPI(prompt, api = 'gemini') {
|
||
try {
|
||
// 調用後端 Flask API,而不是直接調用 Claude API
|
||
const response = await fetch("/api/llm/generate", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
body: JSON.stringify({
|
||
api: api, // 使用 Gemini 作為默認
|
||
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;
|
||
|
||
// 移除可能的 markdown 代碼塊標記
|
||
responseText = responseText.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
|
||
|
||
// 解析 JSON
|
||
return JSON.parse(responseText);
|
||
|
||
} catch (error) {
|
||
console.error("Error calling LLM API:", error);
|
||
|
||
// 使用全局錯誤處理器顯示錯誤
|
||
if (window.errorHandler) {
|
||
window.errorHandler.showError({
|
||
title: 'AI 生成錯誤',
|
||
message: error.message || '調用 AI API 時發生錯誤',
|
||
type: 'error',
|
||
details: error.stack
|
||
});
|
||
} else {
|
||
alert(`AI 生成錯誤: ${error.message}`);
|
||
}
|
||
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 設置按鈕載入狀態
|
||
* @param {HTMLElement} btn - 按鈕元素
|
||
* @param {boolean} loading - 是否載入中
|
||
*/
|
||
function setButtonLoading(btn, loading) {
|
||
if (loading) {
|
||
btn.disabled = true;
|
||
btn.innerHTML = '<div class="spinner"></div><span>AI 生成中...</span>';
|
||
} else {
|
||
btn.disabled = false;
|
||
btn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg><span>✨ I\'m feeling lucky</span>';
|
||
}
|
||
}
|
||
|
||
// ==================== 選擇 LLM API 提供者 ====================
|
||
|
||
/**
|
||
* 讓用戶選擇使用哪個 LLM API
|
||
* @returns {Promise<string>} - 選擇的 API 名稱
|
||
*/
|
||
async function selectLLMProvider() {
|
||
// 獲取可用的 API 列表
|
||
try {
|
||
const response = await fetch('/api/llm/config');
|
||
const config = await response.json();
|
||
|
||
const enabledAPIs = [];
|
||
for (const [key, value] of Object.entries(config)) {
|
||
if (value.enabled) {
|
||
enabledAPIs.push({
|
||
key: key,
|
||
name: value.name
|
||
});
|
||
}
|
||
}
|
||
|
||
if (enabledAPIs.length === 0) {
|
||
throw new Error('沒有可用的 LLM API,請先配置 API Key');
|
||
}
|
||
|
||
// 如果只有一個 API,直接使用
|
||
if (enabledAPIs.length === 1) {
|
||
return enabledAPIs[0].key;
|
||
}
|
||
|
||
// 多個 API 時,使用第一個(默認 Gemini)
|
||
return enabledAPIs[0].key;
|
||
|
||
} catch (error) {
|
||
console.error('無法獲取 LLM 配置:', error);
|
||
// 默認使用 Gemini
|
||
return 'gemini';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 增強版的 callClaudeAPI - 自動選擇最佳 API
|
||
* @param {string} prompt - 提示詞
|
||
* @returns {Promise<Object>} - 生成的 JSON 數據
|
||
*/
|
||
async function callAIAPI(prompt) {
|
||
const api = await selectLLMProvider();
|
||
return callClaudeAPI(prompt, api);
|
||
}
|
||
|
||
// ==================== 使用示例 ====================
|
||
|
||
/*
|
||
// 原來的調用方式(會導致 CORS 錯誤):
|
||
const result = await callClaudeAPI(prompt);
|
||
|
||
// 修正後的調用方式 1(使用默認 Gemini):
|
||
const result = await callClaudeAPI(prompt, 'gemini');
|
||
|
||
// 修正後的調用方式 2(使用 DeepSeek):
|
||
const result = await callClaudeAPI(prompt, 'deepseek');
|
||
|
||
// 修正後的調用方式 3(使用 OpenAI):
|
||
const result = await callClaudeAPI(prompt, 'openai');
|
||
|
||
// 修正後的調用方式 4(自動選擇最佳 API):
|
||
const result = await callAIAPI(prompt);
|
||
*/
|