100 lines
3.5 KiB
TypeScript
100 lines
3.5 KiB
TypeScript
import { useState } from 'react';
|
|
import { Table, Button, Modal, Form, Input, Select, Switch, Popconfirm, Tag } from 'antd';
|
|
import { PlusOutlined } from '@ant-design/icons';
|
|
import { useInjectionRules, useCreateInjectionRule, useDeleteInjectionRule, useToggleInjectionRule } from '../../application/useLLMGateway';
|
|
import type { InjectionRule } from '../../infrastructure/llm-gateway.api';
|
|
|
|
const { TextArea } = Input;
|
|
|
|
export function InjectionRulesTab() {
|
|
const { data, isLoading } = useInjectionRules();
|
|
const createMutation = useCreateInjectionRule();
|
|
const deleteMutation = useDeleteInjectionRule();
|
|
const toggleMutation = useToggleInjectionRule();
|
|
const [createOpen, setCreateOpen] = useState(false);
|
|
const [form] = Form.useForm();
|
|
|
|
const handleCreate = async () => {
|
|
const values = await form.validateFields();
|
|
await createMutation.mutateAsync(values);
|
|
setCreateOpen(false);
|
|
form.resetFields();
|
|
};
|
|
|
|
const columns = [
|
|
{ title: '名称', dataIndex: 'name', key: 'name' },
|
|
{
|
|
title: '位置',
|
|
dataIndex: 'position',
|
|
key: 'position',
|
|
render: (v: string) => <Tag color={v === 'prepend' ? 'blue' : 'green'}>{v === 'prepend' ? '前置' : '追加'}</Tag>,
|
|
},
|
|
{
|
|
title: '内容预览',
|
|
dataIndex: 'content',
|
|
key: 'content',
|
|
ellipsis: true,
|
|
width: 300,
|
|
},
|
|
{
|
|
title: '匹配模型',
|
|
dataIndex: 'matchModels',
|
|
key: 'matchModels',
|
|
render: (v: string[]) => v?.includes('*') ? <Tag>全部</Tag> : v?.map((m: string) => <Tag key={m}>{m}</Tag>),
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'enabled',
|
|
key: 'enabled',
|
|
render: (v: boolean, record: InjectionRule) => (
|
|
<Switch checked={v} size="small" onChange={() => toggleMutation.mutate(record.id)} />
|
|
),
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'actions',
|
|
render: (_: any, record: InjectionRule) => (
|
|
<Popconfirm title="确认删除?" onConfirm={() => deleteMutation.mutate(record.id)}>
|
|
<Button type="link" danger size="small">删除</Button>
|
|
</Popconfirm>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<>
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 16 }}>
|
|
<Button type="primary" icon={<PlusOutlined />} onClick={() => setCreateOpen(true)}>
|
|
创建注入规则
|
|
</Button>
|
|
</div>
|
|
|
|
<Table columns={columns} dataSource={data?.items} rowKey="id" loading={isLoading} size="small" pagination={false} />
|
|
|
|
<Modal
|
|
title="创建注入规则"
|
|
open={createOpen}
|
|
onOk={handleCreate}
|
|
onCancel={() => setCreateOpen(false)}
|
|
confirmLoading={createMutation.isPending}
|
|
width={600}
|
|
>
|
|
<Form form={form} layout="vertical">
|
|
<Form.Item name="name" label="规则名称" rules={[{ required: true }]}>
|
|
<Input placeholder="例如: 合规声明" />
|
|
</Form.Item>
|
|
<Form.Item name="position" label="注入位置" initialValue="append">
|
|
<Select options={[{ label: '追加到 system prompt 末尾', value: 'append' }, { label: '前置到 system prompt 开头', value: 'prepend' }]} />
|
|
</Form.Item>
|
|
<Form.Item name="content" label="注入内容" rules={[{ required: true }]}>
|
|
<TextArea rows={6} placeholder="输入要注入到 system prompt 中的监管内容..." />
|
|
</Form.Item>
|
|
<Form.Item name="description" label="描述">
|
|
<Input placeholder="规则说明(可选)" />
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
</>
|
|
);
|
|
}
|