Refactor AI chat: streaming, tool calls, UI polish
All checks were successful
CI / check (pull_request) Successful in 3m25s

This commit is contained in:
2026-07-24 16:27:50 +08:00
parent e605586fc9
commit 8656394b9b
55 changed files with 2774 additions and 460 deletions

View File

@@ -15,13 +15,13 @@ import {
Typography,
Space,
Steps,
Switch,
} from 'antd';
import {
SaveOutlined,
ApiOutlined,
CheckCircleOutlined,
CloseCircleOutlined,
KeyOutlined,
WarningOutlined,
ReloadOutlined,
CloudServerOutlined,
@@ -58,6 +58,7 @@ interface AiConfigData {
keySource: 'database' | 'environment' | 'none';
defaultModel: string | null;
enabled: boolean;
supportsVision: boolean;
timeoutMs: number;
verified: boolean;
lastTestedAt: string | null;
@@ -97,6 +98,7 @@ interface FormValues {
apiKey: string;
defaultModel: string;
timeoutMs: number;
supportsVision: boolean;
}
const DEFAULT_FORM_VALUES: FormValues = {
@@ -105,6 +107,7 @@ const DEFAULT_FORM_VALUES: FormValues = {
apiKey: '',
defaultModel: '',
timeoutMs: 30000,
supportsVision: false,
};
// ---------------------------------------------------------------------------
@@ -167,6 +170,7 @@ const AiConfigPage: React.FC = () => {
apiKey: '',
defaultModel: res.data.defaultModel ?? '',
timeoutMs: res.data.timeoutMs,
supportsVision: res.data.supportsVision,
};
form.setFieldsValue(initial);
setFormValues(initial);
@@ -248,7 +252,7 @@ const AiConfigPage: React.FC = () => {
// Validate fields (for UI error display) — actual values come from state
await form.validateFields(['provider', 'baseUrl', 'timeoutMs']);
const { provider, baseUrl, defaultModel, apiKey, timeoutMs } = formValues;
const { provider, baseUrl, defaultModel, apiKey, timeoutMs, supportsVision } = formValues;
if (provider === 'OPENAI_COMPATIBLE' && !baseUrl) {
message.error('OPENAI_COMPATIBLE 模式必须填写 Base URL');
@@ -264,6 +268,7 @@ const AiConfigPage: React.FC = () => {
baseUrl: resolvedBaseUrl,
defaultModel: defaultModel || undefined,
enabled: true,
supportsVision,
timeoutMs,
};
@@ -567,6 +572,16 @@ const AiConfigPage: React.FC = () => {
/>
</Form.Item>
<Form.Item
name="supportsVision"
label="图片理解"
valuePropName="checked"
extra="仅当所选模型确实支持图片输入时开启;关闭时 AI 助手会阻止发送图片。"
preserve
>
<Switch disabled={!canWrite} checkedChildren="已启用" unCheckedChildren="未启用" />
</Form.Item>
{config?.verified && (
<div style={{ marginTop: 8 }}>
<Tag icon={<CheckCircleOutlined />} color="success">
@@ -624,6 +639,11 @@ const AiConfigPage: React.FC = () => {
<Descriptions.Item label="超时">
{formValues.timeoutMs}ms
</Descriptions.Item>
<Descriptions.Item label="图片理解">
<Tag color={formValues.supportsVision ? 'blue' : 'default'}>
{formValues.supportsVision ? '已启用' : '未启用'}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="状态">
<Tag color={config?.enabled ? 'green' : 'default'}>
{config?.enabled ? '已启用' : '未启用'}