Initial commit: HR Performance System
- Database schema with 31 tables for 4-card system - LLM API integration (Gemini, DeepSeek, OpenAI) - Error handling system with modal component - Connection test UI for LLM services - Environment configuration files - Complete database documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
228
components/LLMConnectionTest.jsx
Normal file
228
components/LLMConnectionTest.jsx
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* LLM 連線測試元件
|
||||
* 測試 Gemini, DeepSeek, OpenAI 三種 LLM API 的連線狀態
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import './LLMConnectionTest.css';
|
||||
|
||||
const LLMConnectionTest = () => {
|
||||
const [testResults, setTestResults] = useState({
|
||||
gemini: null,
|
||||
deepseek: null,
|
||||
openai: null,
|
||||
});
|
||||
|
||||
const [testing, setTesting] = useState({
|
||||
gemini: false,
|
||||
deepseek: false,
|
||||
openai: false,
|
||||
});
|
||||
|
||||
const [testingAll, setTestingAll] = useState(false);
|
||||
|
||||
const providers = [
|
||||
{
|
||||
id: 'gemini',
|
||||
name: 'Google Gemini',
|
||||
icon: '🤖',
|
||||
color: '#4285f4',
|
||||
},
|
||||
{
|
||||
id: 'deepseek',
|
||||
name: 'DeepSeek',
|
||||
icon: '🧠',
|
||||
color: '#7c3aed',
|
||||
},
|
||||
{
|
||||
id: 'openai',
|
||||
name: 'OpenAI',
|
||||
icon: '✨',
|
||||
color: '#10a37f',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 測試單一 LLM 連線
|
||||
*/
|
||||
const testConnection = async (provider) => {
|
||||
setTesting((prev) => ({ ...prev, [provider]: true }));
|
||||
setTestResults((prev) => ({ ...prev, [provider]: null }));
|
||||
|
||||
try {
|
||||
const response = await axios.post(`/api/llm/test/${provider}`);
|
||||
setTestResults((prev) => ({ ...prev, [provider]: response.data }));
|
||||
} catch (error) {
|
||||
const errorData = error.response?.data || {
|
||||
success: false,
|
||||
message: error.message || '連線測試失敗',
|
||||
provider,
|
||||
};
|
||||
setTestResults((prev) => ({ ...prev, [provider]: errorData }));
|
||||
} finally {
|
||||
setTesting((prev) => ({ ...prev, [provider]: false }));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 測試所有 LLM 連線
|
||||
*/
|
||||
const testAllConnections = async () => {
|
||||
setTestingAll(true);
|
||||
setTestResults({
|
||||
gemini: null,
|
||||
deepseek: null,
|
||||
openai: null,
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await axios.post('/api/llm/test/all');
|
||||
setTestResults(response.data);
|
||||
} catch (error) {
|
||||
console.error('測試所有連線失敗:', error);
|
||||
} finally {
|
||||
setTestingAll(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 取得測試結果樣式
|
||||
*/
|
||||
const getResultClass = (result) => {
|
||||
if (!result) return '';
|
||||
return result.success ? 'success' : 'failure';
|
||||
};
|
||||
|
||||
/**
|
||||
* 取得測試結果圖示
|
||||
*/
|
||||
const getResultIcon = (result) => {
|
||||
if (!result) return '⏳';
|
||||
return result.success ? '✅' : '❌';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="llm-connection-test">
|
||||
<div className="test-header">
|
||||
<h2>LLM API 連線測試</h2>
|
||||
<p className="test-description">
|
||||
測試與外部 LLM 服務的連線狀態,確保 API 金鑰配置正確
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="test-actions">
|
||||
<button
|
||||
className="test-all-button"
|
||||
onClick={testAllConnections}
|
||||
disabled={testingAll || Object.values(testing).some(Boolean)}
|
||||
>
|
||||
{testingAll ? (
|
||||
<>
|
||||
<span className="spinner"></span>
|
||||
測試中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>🔄</span>
|
||||
測試所有連線
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="providers-grid">
|
||||
{providers.map((provider) => {
|
||||
const result = testResults[provider.id];
|
||||
const isTesting = testing[provider.id];
|
||||
|
||||
return (
|
||||
<div
|
||||
key={provider.id}
|
||||
className={`provider-card ${getResultClass(result)}`}
|
||||
style={{ borderColor: provider.color }}
|
||||
>
|
||||
<div className="provider-header">
|
||||
<div className="provider-info">
|
||||
<span className="provider-icon" style={{ color: provider.color }}>
|
||||
{provider.icon}
|
||||
</span>
|
||||
<h3>{provider.name}</h3>
|
||||
</div>
|
||||
<span className="result-icon">{getResultIcon(result)}</span>
|
||||
</div>
|
||||
|
||||
<div className="provider-body">
|
||||
{result && (
|
||||
<div className="result-details">
|
||||
<div className={`status-badge ${result.success ? 'success' : 'failure'}`}>
|
||||
{result.success ? '連線成功' : '連線失敗'}
|
||||
</div>
|
||||
|
||||
<p className="result-message">{result.message}</p>
|
||||
|
||||
{result.model && (
|
||||
<div className="result-meta">
|
||||
<span className="meta-label">模型:</span>
|
||||
<span className="meta-value">{result.model}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{result.error && (
|
||||
<details className="error-details">
|
||||
<summary>錯誤詳情</summary>
|
||||
<pre>{result.error}</pre>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!result && !isTesting && (
|
||||
<p className="no-result">尚未測試</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="provider-footer">
|
||||
<button
|
||||
className="test-button"
|
||||
onClick={() => testConnection(provider.id)}
|
||||
disabled={isTesting || testingAll}
|
||||
style={{ borderColor: provider.color, color: provider.color }}
|
||||
>
|
||||
{isTesting ? (
|
||||
<>
|
||||
<span className="spinner small"></span>
|
||||
測試中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>🔌</span>
|
||||
測試連線
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="test-footer">
|
||||
<div className="info-box">
|
||||
<span className="info-icon">ℹ️</span>
|
||||
<div className="info-content">
|
||||
<strong>提示:</strong>
|
||||
<p>請確保在 .env 文件中正確配置了對應的 API 金鑰</p>
|
||||
<ul>
|
||||
<li>GEMINI_API_KEY - Google Gemini API 金鑰</li>
|
||||
<li>DEEPSEEK_API_KEY - DeepSeek API 金鑰</li>
|
||||
<li>OPENAI_API_KEY - OpenAI API 金鑰</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LLMConnectionTest;
|
||||
Reference in New Issue
Block a user