Files
hr-performance-system/components/LLMConnectionTest.jsx
donald c24634f4b7 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>
2025-12-03 23:34:13 +08:00

229 lines
6.3 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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;