feat: AI 对话支持 A2UI 表单/审查/图表与 Excel 读取

This commit is contained in:
2026-08-04 14:41:40 +08:00
parent f07ffdc64c
commit 50c44e4410
51 changed files with 11588 additions and 175 deletions

View File

@@ -60,6 +60,7 @@ interface AiConfigData {
enabled: boolean;
supportsVision: boolean;
timeoutMs: number;
reasoningEffort: string | null;
verified: boolean;
lastTestedAt: string | null;
lastTestLatencyMs: number | null;
@@ -99,6 +100,7 @@ interface FormValues {
defaultModel: string;
timeoutMs: number;
supportsVision: boolean;
reasoningEffort: string;
}
const DEFAULT_FORM_VALUES: FormValues = {
@@ -108,6 +110,7 @@ const DEFAULT_FORM_VALUES: FormValues = {
defaultModel: '',
timeoutMs: 30000,
supportsVision: false,
reasoningEffort: '',
};
// ---------------------------------------------------------------------------
@@ -171,6 +174,7 @@ const AiConfigPage: React.FC = () => {
defaultModel: res.data.defaultModel ?? '',
timeoutMs: res.data.timeoutMs,
supportsVision: res.data.supportsVision,
reasoningEffort: res.data.reasoningEffort ?? '',
};
form.setFieldsValue(initial);
setFormValues(initial);
@@ -252,7 +256,8 @@ 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, supportsVision } = formValues;
const { provider, baseUrl, defaultModel, apiKey, timeoutMs, supportsVision, reasoningEffort } =
formValues;
if (provider === 'OPENAI_COMPATIBLE' && !baseUrl) {
message.error('OPENAI_COMPATIBLE 模式必须填写 Base URL');
@@ -270,6 +275,7 @@ const AiConfigPage: React.FC = () => {
enabled: true,
supportsVision,
timeoutMs,
reasoningEffort: reasoningEffort || null,
};
if (apiKey && apiKey !== '••••') {
@@ -308,11 +314,12 @@ const AiConfigPage: React.FC = () => {
setTesting(true);
setTestResult(null);
const { provider, baseUrl, defaultModel, apiKey, timeoutMs } = formValues;
const { provider, baseUrl, defaultModel, apiKey, timeoutMs, reasoningEffort } = formValues;
const body: Record<string, unknown> = { provider, timeoutMs };
if (baseUrl) body.baseUrl = baseUrl;
if (defaultModel) body.defaultModel = defaultModel;
if (apiKey && apiKey !== '••••') body.apiKey = apiKey;
if (reasoningEffort) body.reasoningEffort = reasoningEffort;
const res = await api.post<TestResult>('/ai/config/test', body);
setTestResult(res);
@@ -582,6 +589,25 @@ const AiConfigPage: React.FC = () => {
<Switch disabled={!canWrite} checkedChildren="已启用" unCheckedChildren="未启用" />
</Form.Item>
<Form.Item
name="reasoningEffort"
label="推理强度 (reasoning_effort)"
extra="OpenAI o 系列等支持该参数的模型生效DeepSeek 官方接口不支持,选择后也不会发送。"
preserve
>
<Select
disabled={!canWrite}
size="large"
options={[
{ value: '', label: '不设置(跟随模型默认)' },
{ value: 'low', label: '低 (low)' },
{ value: 'medium', label: '中 (medium)' },
{ value: 'high', label: '高 (high)' },
{ value: 'xhigh', label: '极高 (xhigh)' },
]}
/>
</Form.Item>
{config?.verified && (
<div style={{ marginTop: 8 }}>
<Tag icon={<CheckCircleOutlined />} color="success">