refactor: 移除通用频道管理(LangBot)模块,IM Bot 改为直接对接;迁移 _call_real_llm 至 im_llm
This commit is contained in:
1 parent
945eeb8ba0
commit
ab54d7344c
15 files changed
+3208
-8784
No files matched your search
@@ -33,7 +33,7 @@ const statusColors: Record<string, string> = {
|
||||
disconnected: '#6b7280',
|
||||
};
|
||||
|
||||
type Tab = 'dashboard' | 'channels' | 'routes' | 'langbot' | 'messages' | 'setup';
|
||||
type Tab = 'dashboard' | 'channels' | 'routes' | 'messages' | 'setup';
|
||||
|
||||
const ImBots: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState<Tab>('dashboard');
|
||||
@@ -46,7 +46,6 @@ const ImBots: React.FC = () => {
|
||||
const [filterPlatform, setFilterPlatform] = useState('');
|
||||
const [filterStatus, setFilterStatus] = useState('');
|
||||
const [routes, setRoutes] = useState<any[]>([]);
|
||||
const [langbotConfig, setLangbotConfig] = useState<any[]>([]);
|
||||
const [messages, setMessages] = useState<any[]>([]);
|
||||
const [messagesTotal, setMessagesTotal] = useState(0);
|
||||
const [messagesPage, setMessagesPage] = useState(1);
|
||||
@@ -77,18 +76,6 @@ const ImBots: React.FC = () => {
|
||||
credentials: '',
|
||||
});
|
||||
|
||||
// LangBot form state
|
||||
const [langbotForm, setLangbotForm] = useState({
|
||||
id: 1,
|
||||
gateway_url: '',
|
||||
api_key: '',
|
||||
webhook_secret: '',
|
||||
bot_uuid: '',
|
||||
callback_url: '',
|
||||
sync_channels: 0,
|
||||
status: 'inactive',
|
||||
});
|
||||
|
||||
const showToast = (msg: string, type: 'success' | 'error' = 'success') => {
|
||||
setToast({ msg, type });
|
||||
setTimeout(() => setToast(null), 3000);
|
||||
@@ -155,22 +142,6 @@ const ImBots: React.FC = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Load LangBot config
|
||||
const loadLangbot = useCallback(async () => {
|
||||
try {
|
||||
const res = await adminAPI.getLangbotConfig();
|
||||
if ((res as any)?.success) {
|
||||
const configs = res.data || [];
|
||||
setLangbotConfig(configs);
|
||||
if (configs.length > 0) {
|
||||
setLangbotForm({ ...langbotForm, ...configs[0] });
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
showToast('Failed to load LangBot config', 'error');
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Load messages
|
||||
const loadMessages = useCallback(async () => {
|
||||
try {
|
||||
@@ -211,8 +182,6 @@ const ImBots: React.FC = () => {
|
||||
} else if (activeTab === 'routes') {
|
||||
loadRoutes();
|
||||
loadChannels();
|
||||
} else if (activeTab === 'langbot') {
|
||||
loadLangbot();
|
||||
} else if (activeTab === 'messages') {
|
||||
loadMessages();
|
||||
}
|
||||
@@ -348,51 +317,7 @@ const ImBots: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Handle LangBot config save
|
||||
const handleSaveLangbot = async () => {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
config_id: String(langbotForm.id || 1),
|
||||
gateway_url: langbotForm.gateway_url,
|
||||
status: langbotForm.status,
|
||||
sync_channels: String(langbotForm.sync_channels),
|
||||
});
|
||||
if (langbotForm.api_key) params.append('api_key', langbotForm.api_key);
|
||||
if (langbotForm.webhook_secret) params.append('webhook_secret', langbotForm.webhook_secret);
|
||||
if (langbotForm.bot_uuid) params.append('bot_uuid', langbotForm.bot_uuid);
|
||||
if (langbotForm.callback_url) params.append('callback_url', langbotForm.callback_url);
|
||||
await adminAPI.updateLangbotConfig('?' + params.toString());
|
||||
showToast('LangBot config saved');
|
||||
loadLangbot();
|
||||
} catch (e) {
|
||||
showToast('Failed to save LangBot config', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
// Handle LangBot test
|
||||
const handleTestLangbot = async () => {
|
||||
if (!langbotForm.gateway_url) {
|
||||
showToast('Please enter gateway URL', 'error');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
gateway_url: langbotForm.gateway_url,
|
||||
});
|
||||
if (langbotForm.api_key) params.append('api_key', langbotForm.api_key);
|
||||
const res = await adminAPI.testLangbot('?' + params.toString());
|
||||
if ((res as any)?.success) {
|
||||
const data = res.data;
|
||||
if (data.reachable) {
|
||||
showToast(`LangBot reachable! Status: ${data.status_code}`);
|
||||
} else {
|
||||
showToast(`LangBot unreachable: ${data.error}`, 'error');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
showToast('Test failed', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
// Copy to clipboard
|
||||
const copyToClipboard = (text: string) => {
|
||||
@@ -411,7 +336,6 @@ const ImBots: React.FC = () => {
|
||||
{ key: 'dashboard', label: '仪表盘', icon: 'M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z' },
|
||||
{ key: 'channels', label: '频道管理', icon: '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' },
|
||||
{ key: 'routes', label: '消息路由', icon: 'M3.5 18.5l6-6.01 4 4L22 6.92l-1.41-1.41-7.09 7.97-4-4L2 17l1.5 1.5z' },
|
||||
{ key: 'langbot', label: 'LangBot 网关', icon: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z' },
|
||||
{ key: 'messages', label: '消息日志', icon: 'M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z' },
|
||||
{ key: 'setup', label: '快速接入', icon: 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z' },
|
||||
];
|
||||
@@ -422,7 +346,7 @@ const ImBots: React.FC = () => {
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '24px' }}>
|
||||
<div>
|
||||
<h1 style={{ fontSize: '24px', fontWeight: 700, margin: 0 }}>IM 机器人管理</h1>
|
||||
<p style={{ color: '#888', fontSize: '14px', margin: '4px 0 0 0' }}>管理即时通讯平台接入、消息路由和 LangBot 网关</p>
|
||||
<p style={{ color: '#888', fontSize: '14px', margin: '4px 0 0 0' }}>管理即时通讯平台接入与消息路由</p>
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: '8px' }}>
|
||||
{stats && (
|
||||
@@ -430,7 +354,6 @@ const ImBots: React.FC = () => {
|
||||
<StatBadge label="频道" value={stats.total_channels} color="#3370FF" />
|
||||
<StatBadge label="在线" value={stats.active_channels} color="#10b981" />
|
||||
<StatBadge label="今日消息" value={stats.today_messages_in + stats.today_messages_out} color="#f59e0b" />
|
||||
<StatBadge label="LangBot" value={stats.langbot_status === 'active' ? 'ON' : 'OFF'} color={stats.langbot_status === 'active' ? '#10b981' : '#6b7280'} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -744,105 +667,6 @@ const ImBots: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* LangBot Tab */}
|
||||
{activeTab === 'langbot' && (
|
||||
<div style={{ maxWidth: '800px' }}>
|
||||
<div style={{ background: '#1a1d27', borderRadius: '12px', padding: '24px' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
||||
<h3 style={{ margin: 0, fontSize: '16px' }}>LangBot 网关配置</h3>
|
||||
<span style={{
|
||||
padding: '4px 12px', borderRadius: '4px', fontSize: '12px',
|
||||
background: langbotForm.status === 'active' ? '#10b98120' : '#6b728020',
|
||||
color: langbotForm.status === 'active' ? '#10b981' : '#6b7280',
|
||||
}}>
|
||||
{langbotForm.status === 'active' ? '已启用' : '未启用'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px' }}>
|
||||
<FormField label="网关 URL" >
|
||||
<input
|
||||
value={langbotForm.gateway_url}
|
||||
onChange={(e) => setLangbotForm({ ...langbotForm, gateway_url: e.target.value })}
|
||||
placeholder="http://localhost:5300"
|
||||
style={inputStyle}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="Bot UUID">
|
||||
<input
|
||||
value={langbotForm.bot_uuid || ''}
|
||||
onChange={(e) => setLangbotForm({ ...langbotForm, bot_uuid: e.target.value })}
|
||||
placeholder="LangBot HTTP Bot UUID"
|
||||
style={inputStyle}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="API Key">
|
||||
<input
|
||||
type="password"
|
||||
value={langbotForm.api_key || ''}
|
||||
onChange={(e) => setLangbotForm({ ...langbotForm, api_key: e.target.value })}
|
||||
placeholder="LangBot REST API Key"
|
||||
style={inputStyle}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="Webhook Secret">
|
||||
<input
|
||||
type="password"
|
||||
value={langbotForm.webhook_secret || ''}
|
||||
onChange={(e) => setLangbotForm({ ...langbotForm, webhook_secret: e.target.value })}
|
||||
placeholder="HMAC-SHA256 签名密钥"
|
||||
style={inputStyle}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="回调 URL">
|
||||
<input
|
||||
value={langbotForm.callback_url || ''}
|
||||
onChange={(e) => setLangbotForm({ ...langbotForm, callback_url: e.target.value })}
|
||||
placeholder="http://210.16.161.218:12888/app/api/channels/webhook/langbot"
|
||||
style={inputStyle}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="自动同步频道">
|
||||
<select
|
||||
value={langbotForm.sync_channels}
|
||||
onChange={(e) => setLangbotForm({ ...langbotForm, sync_channels: Number(e.target.value) })}
|
||||
style={selectStyle}
|
||||
>
|
||||
<option value={0}>否</option>
|
||||
<option value={1}>是</option>
|
||||
</select>
|
||||
</FormField>
|
||||
<FormField label="状态">
|
||||
<select
|
||||
value={langbotForm.status}
|
||||
onChange={(e) => setLangbotForm({ ...langbotForm, status: e.target.value })}
|
||||
style={selectStyle}
|
||||
>
|
||||
<option value="inactive">未启用</option>
|
||||
<option value="active">启用</option>
|
||||
</select>
|
||||
</FormField>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '12px', marginTop: '24px' }}>
|
||||
<button onClick={handleSaveLangbot} style={primaryButtonStyle}>保存配置</button>
|
||||
<button onClick={handleTestLangbot} style={secondaryButtonStyle}>测试连接</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* LangBot Info */}
|
||||
<div style={{ background: '#1a1d27', borderRadius: '12px', padding: '24px', marginTop: '16px' }}>
|
||||
<h4 style={{ marginTop: 0, fontSize: '14px', color: '#888' }}>LangBot 集成说明</h4>
|
||||
<ul style={{ fontSize: '13px', color: '#aaa', lineHeight: '1.8', paddingLeft: '20px' }}>
|
||||
<li>LangBot 是开源的 LLM 原生 IM 机器人平台,支持飞书、微信、钉钉等</li>
|
||||
<li>配置 LangBot 作为外部网关后,IM 消息将通过 LangBot 转发到本平台</li>
|
||||
<li>在 LangBot 中创建 HTTP Bot 适配器,将 Webhook URL 指向本平台</li>
|
||||
<li>API Key 在 LangBot 的 config.yaml 中通过 api.global_api_key 配置</li>
|
||||
<li>Webhook Secret 用于 HMAC-SHA256 双向签名验证</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Messages Tab */}
|
||||
{activeTab === 'messages' && (
|
||||
|
||||
Reference in new issue
Block a user