|
|
@@ -0,0 +1,324 @@
|
|
|
+import React, { useState, useEffect } from 'react';
|
|
|
+import { Table, Button, Modal, Form, Input, Switch, InputNumber, message, Space, Popconfirm, Card, Descriptions } from 'antd';
|
|
|
+import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined } from '@ant-design/icons';
|
|
|
+import type { ColumnsType } from 'antd/es/table';
|
|
|
+import { aiAgentClient } from '@/client/api';
|
|
|
+import type { InferResponseType, InferRequestType } from 'hono/client';
|
|
|
+
|
|
|
+// 类型定义
|
|
|
+type AIAgent = InferResponseType<typeof aiAgentClient.$get, 200>['data'][0];
|
|
|
+type CreateAIAgentDto = InferRequestType<typeof aiAgentClient.$post>['json'];
|
|
|
+type UpdateAIAgentDto = InferRequestType<typeof aiAgentClient[':id']['$put']>['json'];
|
|
|
+
|
|
|
+const AIAgents: React.FC = () => {
|
|
|
+ const [form] = Form.useForm();
|
|
|
+ const [loading, setLoading] = useState(false);
|
|
|
+ const [modalVisible, setModalVisible] = useState(false);
|
|
|
+ const [modalType, setModalType] = useState<'create' | 'edit'>('create');
|
|
|
+ const [editingRecord, setEditingRecord] = useState<AIAgent | null>(null);
|
|
|
+ const [data, setData] = useState<AIAgent[]>([]);
|
|
|
+
|
|
|
+ // 获取智能体列表
|
|
|
+ const fetchAgents = async () => {
|
|
|
+ setLoading(true);
|
|
|
+ try {
|
|
|
+ const response = await aiAgentClient.$get();
|
|
|
+ const result = await response.json();
|
|
|
+ setData(result.data);
|
|
|
+ } catch (error) {
|
|
|
+ message.error('获取智能体列表失败');
|
|
|
+ } finally {
|
|
|
+ setLoading(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ fetchAgents();
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ // 创建或更新智能体
|
|
|
+ const handleSubmit = async (values: any) => {
|
|
|
+ try {
|
|
|
+ if (modalType === 'create') {
|
|
|
+ const response = await aiAgentClient.$post({
|
|
|
+ json: values as CreateAIAgentDto,
|
|
|
+ });
|
|
|
+ if (response.ok) {
|
|
|
+ message.success('创建成功');
|
|
|
+ } else {
|
|
|
+ throw new Error('创建失败');
|
|
|
+ }
|
|
|
+ } else if (editingRecord) {
|
|
|
+ const response = await aiAgentClient[':id'].$put({
|
|
|
+ param: { id: editingRecord.id.toString() },
|
|
|
+ json: values as UpdateAIAgentDto,
|
|
|
+ });
|
|
|
+ if (response.ok) {
|
|
|
+ message.success('更新成功');
|
|
|
+ } else {
|
|
|
+ throw new Error('更新失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ setModalVisible(false);
|
|
|
+ form.resetFields();
|
|
|
+ fetchAgents();
|
|
|
+ } catch (error) {
|
|
|
+ message.error(modalType === 'create' ? '创建失败' : '更新失败');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 删除智能体
|
|
|
+ const handleDelete = async (record: AIAgent) => {
|
|
|
+ try {
|
|
|
+ const response = await aiAgentClient[':id'].$delete({
|
|
|
+ param: { id: record.id.toString() },
|
|
|
+ });
|
|
|
+ if (response.ok) {
|
|
|
+ message.success('删除成功');
|
|
|
+ fetchAgents();
|
|
|
+ } else {
|
|
|
+ throw new Error('删除失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error('删除失败');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 打开创建/编辑模态框
|
|
|
+ const openModal = (type: 'create' | 'edit', record?: AIAgent) => {
|
|
|
+ setModalType(type);
|
|
|
+ setEditingRecord(record || null);
|
|
|
+ setModalVisible(true);
|
|
|
+
|
|
|
+ if (record) {
|
|
|
+ form.setFieldsValue({
|
|
|
+ ...record,
|
|
|
+ isActive: record.isActive === 1,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ form.resetFields();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 表格列配置
|
|
|
+ const columns: ColumnsType<AIAgent> = [
|
|
|
+ {
|
|
|
+ title: 'ID',
|
|
|
+ dataIndex: 'id',
|
|
|
+ key: 'id',
|
|
|
+ width: 80,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '名称',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ ellipsis: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '描述',
|
|
|
+ dataIndex: 'description',
|
|
|
+ key: 'description',
|
|
|
+ ellipsis: true,
|
|
|
+ render: (text) => text || '-',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '模型',
|
|
|
+ dataIndex: 'model',
|
|
|
+ key: 'model',
|
|
|
+ width: 120,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '温度',
|
|
|
+ dataIndex: 'temperature',
|
|
|
+ key: 'temperature',
|
|
|
+ width: 80,
|
|
|
+ render: (value) => value.toFixed(2),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '最大令牌',
|
|
|
+ dataIndex: 'maxTokens',
|
|
|
+ key: 'maxTokens',
|
|
|
+ width: 100,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '状态',
|
|
|
+ dataIndex: 'isActive',
|
|
|
+ key: 'isActive',
|
|
|
+ width: 100,
|
|
|
+ render: (isActive) => (
|
|
|
+ <Switch
|
|
|
+ checked={isActive === 1}
|
|
|
+ disabled
|
|
|
+ checkedChildren="启用"
|
|
|
+ unCheckedChildren="禁用"
|
|
|
+ />
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '创建时间',
|
|
|
+ dataIndex: 'createdAt',
|
|
|
+ key: 'createdAt',
|
|
|
+ width: 180,
|
|
|
+ render: (text) => new Date(text).toLocaleString(),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'action',
|
|
|
+ width: 150,
|
|
|
+ fixed: 'right',
|
|
|
+ render: (_, record) => (
|
|
|
+ <Space>
|
|
|
+ <Button
|
|
|
+ type="text"
|
|
|
+ icon={<EditOutlined />}
|
|
|
+ onClick={() => openModal('edit', record)}
|
|
|
+ />
|
|
|
+ <Popconfirm
|
|
|
+ title="确定要删除这个智能体吗?"
|
|
|
+ onConfirm={() => handleDelete(record)}
|
|
|
+ okText="确定"
|
|
|
+ cancelText="取消"
|
|
|
+ >
|
|
|
+ <Button type="text" danger icon={<DeleteOutlined />} />
|
|
|
+ </Popconfirm>
|
|
|
+ </Space>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ ];
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <Card>
|
|
|
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
|
|
|
+ <h1 style={{ margin: 0 }}>AI智能体管理</h1>
|
|
|
+ <Button type="primary" icon={<PlusOutlined />} onClick={() => openModal('create')}>
|
|
|
+ 创建智能体
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <Table
|
|
|
+ columns={columns}
|
|
|
+ dataSource={data}
|
|
|
+ rowKey="id"
|
|
|
+ loading={loading}
|
|
|
+ scroll={{ x: 1200 }}
|
|
|
+ pagination={{
|
|
|
+ showSizeChanger: true,
|
|
|
+ showQuickJumper: true,
|
|
|
+ showTotal: (total) => `共 ${total} 条记录`,
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Card>
|
|
|
+
|
|
|
+ <Modal
|
|
|
+ title={modalType === 'create' ? '创建智能体' : '编辑智能体'}
|
|
|
+ open={modalVisible}
|
|
|
+ onCancel={() => setModalVisible(false)}
|
|
|
+ footer={null}
|
|
|
+ width={800}
|
|
|
+ destroyOnClose
|
|
|
+ >
|
|
|
+ <Form
|
|
|
+ form={form}
|
|
|
+ layout="vertical"
|
|
|
+ onFinish={handleSubmit}
|
|
|
+ initialValues={{
|
|
|
+ model: 'gpt-3.5-turbo',
|
|
|
+ temperature: 0.7,
|
|
|
+ maxTokens: 1000,
|
|
|
+ isActive: true,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Form.Item
|
|
|
+ label="智能体名称"
|
|
|
+ name="name"
|
|
|
+ rules={[{ required: true, message: '请输入智能体名称' }]}
|
|
|
+ >
|
|
|
+ <Input placeholder="例如:银龄助手" maxLength={100} />
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
+ <Form.Item
|
|
|
+ label="描述"
|
|
|
+ name="description"
|
|
|
+ >
|
|
|
+ <Input.TextArea
|
|
|
+ placeholder="智能体的功能描述"
|
|
|
+ rows={3}
|
|
|
+ maxLength={500}
|
|
|
+ showCount
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
+ <Form.Item
|
|
|
+ label="系统提示词"
|
|
|
+ name="systemPrompt"
|
|
|
+ tooltip="定义AI助手的角色和行为方式"
|
|
|
+ >
|
|
|
+ <Input.TextArea
|
|
|
+ placeholder="你是一个友好的银龄助手,专门帮助老年用户..."
|
|
|
+ rows={4}
|
|
|
+ maxLength={2000}
|
|
|
+ showCount
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
+ <Form.Item
|
|
|
+ label="AI模型"
|
|
|
+ name="model"
|
|
|
+ rules={[{ required: true, message: '请选择AI模型' }]}
|
|
|
+ >
|
|
|
+ <Input placeholder="例如:gpt-3.5-turbo" />
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
+ <Form.Item
|
|
|
+ label="温度参数"
|
|
|
+ name="temperature"
|
|
|
+ tooltip="控制AI回复的随机性,0-1之间,值越大回复越多样"
|
|
|
+ rules={[{ required: true, message: '请输入温度参数' }]}
|
|
|
+ >
|
|
|
+ <InputNumber
|
|
|
+ min={0}
|
|
|
+ max={2}
|
|
|
+ step={0.1}
|
|
|
+ style={{ width: '100%' }}
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
+ <Form.Item
|
|
|
+ label="最大令牌数"
|
|
|
+ name="maxTokens"
|
|
|
+ tooltip="控制AI回复的最大长度"
|
|
|
+ rules={[{ required: true, message: '请输入最大令牌数' }]}
|
|
|
+ >
|
|
|
+ <InputNumber
|
|
|
+ min={1}
|
|
|
+ max={4000}
|
|
|
+ style={{ width: '100%' }}
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
+ <Form.Item
|
|
|
+ label="启用状态"
|
|
|
+ name="isActive"
|
|
|
+ valuePropName="checked"
|
|
|
+ >
|
|
|
+ <Switch checkedChildren="启用" unCheckedChildren="禁用" />
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
+ <Form.Item>
|
|
|
+ <Space>
|
|
|
+ <Button type="primary" htmlType="submit">
|
|
|
+ {modalType === 'create' ? '创建' : '更新'}
|
|
|
+ </Button>
|
|
|
+ <Button onClick={() => setModalVisible(false)}>
|
|
|
+ 取消
|
|
|
+ </Button>
|
|
|
+ </Space>
|
|
|
+ </Form.Item>
|
|
|
+ </Form>
|
|
|
+ </Modal>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default AIAgents;
|