diff --git a/frontend/packages/common/src/components/aoplatform/prompt-editor/PromptEditorResizable.tsx b/frontend/packages/common/src/components/aoplatform/prompt-editor/PromptEditorResizable.tsx index fd114a42..d93491b5 100644 --- a/frontend/packages/common/src/components/aoplatform/prompt-editor/PromptEditorResizable.tsx +++ b/frontend/packages/common/src/components/aoplatform/prompt-editor/PromptEditorResizable.tsx @@ -9,8 +9,9 @@ const PromptEditorResizable = (props: { onChange?: (value: string) => void variablesChange?: (keys: string[]) => void promptVariables: VariableItems[] + disabled?: boolean }) => { - const { value, onChange, variablesChange, promptVariables } = props + const { value, onChange, variablesChange, promptVariables, disabled } = props const minHeight = 68 const [editorHeight, setEditorHeight] = useState(minHeight) const [previousKeys, setPreviousKeys] = useState([]) @@ -82,7 +83,7 @@ const PromptEditorResizable = (props: { setPreviousKeys(keys) } }} - editable={true} + editable={disabled ? false : true} /> )} diff --git a/frontend/packages/common/src/contexts/GlobalStateContext.tsx b/frontend/packages/common/src/contexts/GlobalStateContext.tsx index c75721f4..d7720cf3 100644 --- a/frontend/packages/common/src/contexts/GlobalStateContext.tsx +++ b/frontend/packages/common/src/contexts/GlobalStateContext.tsx @@ -157,7 +157,7 @@ const mockData = [ { name: 'AI API', key: 'aiApiList', - path: '/aiapis', + path: '/aiApis', icon: 'ic:baseline-api' // access: 'system.settings.ai_api.view' } diff --git a/frontend/packages/common/src/hooks/pluginLoader.ts b/frontend/packages/common/src/hooks/pluginLoader.ts index 3f20b78f..a33eb8e4 100644 --- a/frontend/packages/common/src/hooks/pluginLoader.ts +++ b/frontend/packages/common/src/hooks/pluginLoader.ts @@ -92,10 +92,10 @@ const mockData = { }, { driver: 'apipark.builtIn.component', - name: 'aiapis', + name: 'aiApis', router: [ { - path: 'aiapis', + path: 'aiApis', type: 'normal' } ] diff --git a/frontend/packages/core/src/const/const.tsx b/frontend/packages/core/src/const/const.tsx index 1661b591..f4833725 100644 --- a/frontend/packages/core/src/const/const.tsx +++ b/frontend/packages/core/src/const/const.tsx @@ -468,10 +468,29 @@ export const routerMap: Map = new Map([ } ], [ - 'aiapis', + 'aiApis', { type: 'component', - lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiApis/index.tsx')) + lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiApis/aiApisLayout.tsx')), + key: 'aiApis', + provider: AiServiceProvider, + children: [ + { + path: 'list', + key: 'apiList', + lazy: lazy(() => import(/* webpackChunkName: "[request]" */ '@core/pages/aiApis/index.tsx')), + }, + { + path: 'service/:teamId/aiInside/:serviceId/route/:routeId/:type', + key: 'apiDetail', + lazy: lazy( + () => + import( + /* webpackChunkName: "[request]" */ '@core/pages/aiService/api/AiServiceInsideRouterCreate.tsx' + ) + ) + } + ] } ], [ diff --git a/frontend/packages/core/src/pages/aiApis/aiApisLayout.tsx b/frontend/packages/core/src/pages/aiApis/aiApisLayout.tsx new file mode 100644 index 00000000..3a67332c --- /dev/null +++ b/frontend/packages/core/src/pages/aiApis/aiApisLayout.tsx @@ -0,0 +1,14 @@ +import { useEffect } from "react"; +import { Outlet, useLocation, useNavigate } from "react-router-dom"; + +export default function GlobalPolicyLayout(){ + const location = useLocation() + const pathName = location.pathname + const navigator = useNavigate() + useEffect(()=>{ + if(pathName === '/aiApis'){ + navigator('/aiApis/list') + } + },[pathName]) + return () +} \ No newline at end of file diff --git a/frontend/packages/core/src/pages/aiApis/index.tsx b/frontend/packages/core/src/pages/aiApis/index.tsx index f7450511..4e5d975d 100644 --- a/frontend/packages/core/src/pages/aiApis/index.tsx +++ b/frontend/packages/core/src/pages/aiApis/index.tsx @@ -22,6 +22,7 @@ const ApiSettings: React.FC = () => { const [provider, setProvider] = useState() const { fetchData } = useFetch() const [searchWord, setSearchWord] = useState('') + const [columns, setColumns] = useState[]>([]) const [total, setTotal] = useState(0) const [timeButton, setTimeButton] = useState('day') const navigate = useNavigate() @@ -36,9 +37,14 @@ const ApiSettings: React.FC = () => { }, [selectedProvider]) const handlePreview = (record: APIs) => { - navigate(`service/${record.team.id}/aiInside/${record.service.id}/route/${record.id}`) + navigate(`../service/${record.team.id}/aiInside/${record.service.id}/route/${record.id}/apiDetail`) } - const requestApis = async (params: any) => { + const requestApis = async (params: any & { + pageSize: number; + current: number; + }, + sort: Record, + filter: Record) => { if (!selectedProvider) return setQueryBtnLoading(true) try { @@ -46,6 +52,11 @@ const ApiSettings: React.FC = () => { provider: selectedProvider, page_size: params.pageSize, keyword: searchWord, + sort: Object.keys(sort)?.length > 0 ? 'use_token' : undefined, + asc: Object.keys(sort)?.length > 0 ? Object.values(sort)?.[0] === 'ascend' : undefined, + models: filter?.model && filter?.model?.length ? JSON.stringify(filter.model) : undefined, + services: filter?.name && filter?.name?.length ? JSON.stringify(filter.name) : undefined, + disabled: filter?.disable && filter?.disable?.length ? filter.disable[0] : undefined, page: params.current, start: timeRange.start, end: timeRange.end @@ -62,8 +73,21 @@ const ApiSettings: React.FC = () => { setQueryBtnLoading(false) if (response.code === STATUS_CODE.SUCCESS) { setTotal(response.data.total) + const modalMap: { + [key: string]: string + } = response.data?.condition?.models.reduce((acc: { [key: string]: string }, item: { id: string; name: string }) => { + acc[item.id] = $t(item.name) + return acc + }, {}) + const serviceMap: { + [key: string]: string + } = response.data?.condition?.services.reduce((acc: { [key: string]: string }, item: { id: string; name: string }) => { + acc[item.id] = $t(item.name) + return acc + }, {}) + setTableColumns(modalMap, serviceMap) return { - data: response.data.apis, + data: response.data.apis || [], success: true, total: response.data.total } @@ -83,7 +107,74 @@ const ApiSettings: React.FC = () => { } } } - + const setTableColumns = (modalMap: { + [key: string]: string + }, serviceMap: { + [key: string]: string + }) => { + setColumns([ + { + title: $t('AI 服务'), + dataIndex: 'name', + key: 'name', + width: 180, + filters: true, + valueEnum: serviceMap || {} + }, + { + title: 'API URL', + dataIndex: 'request_path', + key: 'request_path', + ellipsis: true, + render: (text: string, record: APIs) => ( +

+ {record.method} + {text} +

+ ) + }, + { + title: $t('模型'), + dataIndex: ['model', 'name'], + key: 'model', + width: 150, + filters: true, + onFilter: true, + valueType: 'select', + valueEnum: modalMap || {} + }, + { + title: $t('已用 Token'), + dataIndex: 'use_token', + key: 'use_token', + width: 120, + sorter: (a: any, b: any) => { + return (a.priority as number) - (b.priority as number) + } + }, + { + title: $t('是否放行'), + dataIndex: 'disable', + ellipsis: true, + width: 120, + filters: true, + onFilter: true, + valueType: 'select', + valueEnum: { + true: { text: {$t('拦截')} }, + false: { text: {$t('放行')} } + } + }, + { + title: $t('编辑时间'), + dataIndex: 'update_time', + key: 'update_time', + width: 200, + render: (time: string) => {dayjs(time).format('YYYY-MM-DD HH:mm:ss')} + }, + ...operation + ]) + } const operation: PageProColumns[] = [ { title: '', @@ -95,7 +186,7 @@ const ApiSettings: React.FC = () => { handlePreview(entity)} btnTitle={$t('预览')} /> @@ -103,65 +194,6 @@ const ApiSettings: React.FC = () => { } ] - const columns: PageProColumns[] = [ - { - title: $t('AI 服务'), - dataIndex: 'name', - key: 'name', - width: 180 - }, - { - title: 'API URL', - dataIndex: 'request_path', - key: 'request_path', - width: 200, - ellipsis: true, - render: (text: string, record: APIs) => ( -

- {record.method} - {text} -

- ) - }, - { - title: $t('模型'), - dataIndex: ['model', 'name'], - key: 'model', - width: 150, - filters: true, - onFilter: true, - valueType: 'select', - valueEnum: {} - }, - { - title: $t('已用 Token'), - dataIndex: 'use_token', - key: 'use_token', - width: 120, - sorter: true - }, - { - title: $t('是否放行'), - dataIndex: 'disabled', - ellipsis: true, - filters: true, - onFilter: true, - valueType: 'select', - valueEnum: { - true: { text: {$t('拦截')} }, - false: { text: {$t('放行')} } - } - }, - { - title: $t('编辑时间'), - dataIndex: 'update_time', - key: 'update_time', - width: 200, - render: (time: string) => {dayjs(time).format('YYYY-MM-DD HH:mm:ss')} - }, - ...operation - ] - const resetQuery = () => { setTimeButton('day') setTimeRange({ start: null, end: null }) @@ -255,7 +287,12 @@ const ApiSettings: React.FC = () => { } - request={requestApis} + request={async (params: any & { + pageSize: number; + current: number; + }, + sort: Record, + filter: Record) => requestApis(params, sort, filter)} onSearchWordChange={(e) => { setSearchWord(e.target.value) }} diff --git a/frontend/packages/core/src/pages/aiService/api/AiServiceInsideRouterCreate.tsx b/frontend/packages/core/src/pages/aiService/api/AiServiceInsideRouterCreate.tsx index 3ed0819c..c65b4541 100644 --- a/frontend/packages/core/src/pages/aiService/api/AiServiceInsideRouterCreate.tsx +++ b/frontend/packages/core/src/pages/aiService/api/AiServiceInsideRouterCreate.tsx @@ -20,6 +20,7 @@ import { App, Button, Form, Input, InputNumber, Row, Select, Space, Spin, Switch import { MutableRefObject, useEffect, useMemo, useRef, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import AiServiceRouterModelConfig, { AiServiceRouterModelConfigHandle } from './AiServiceInsideRouterModelConfig' +import WithPermission from '@common/components/aoplatform/WithPermission' type AiServiceRouterField = { name: string @@ -51,7 +52,7 @@ type AiServiceRouterConfig = { const AiServiceInsideRouterCreate = () => { const navigator = useNavigate() const { message } = App.useApp() - const { serviceId, teamId, routeId } = useParams() + const { serviceId, teamId, routeId, type } = useParams() const [form] = Form.useForm() const { fetchData } = useFetch() const [loading, setLoading] = useState(false) @@ -103,7 +104,8 @@ const AiServiceInsideRouterCreate = () => { }) .catch((errInfo) => Promise.reject(errInfo)) } - + const isDelete = type === 'apiDetail' + const backUrl = isDelete ? `/aiApis/list` : `/service/${teamId}/aiInside/${serviceId}/route` const openDrawer = (type: 'edit') => { setDrawerType(type) } @@ -208,6 +210,7 @@ const AiServiceInsideRouterCreate = () => { }, []) const addVariable = () => { + if (isDelete) return form.setFieldsValue({ variables: [...form.getFieldValue('variables'), { key: '', value: '', require: true }] }) @@ -264,12 +267,13 @@ const AiServiceInsideRouterCreate = () => { showBorder={false} scrollPage={false} className="overflow-y-auto" - backUrl={`/service/${teamId}/aiInside/${serviceId}/route`} + backUrl={backUrl} customBtn={
- - + { + type !== 'apiDetail' && () + }
} > @@ -293,125 +298,130 @@ const AiServiceInsideRouterCreate = () => { spinning={loading} wrapperClassName=" pb-PAGE_INSIDE_B pr-PAGE_INSIDE_X" > -
-
- - - className="flex-1" - label={$t('路由名称')} - name="name" - rules={[{ required: true, whitespace: true }]} - > - - + + +
+ + + className="flex-1" + label={$t('路由名称')} + name="name" + rules={[{ required: true, whitespace: true }]} + > + + - - - - { - if ((e.target.value as string).endsWith('/*')) { - form.setFieldValue('path', e.target.value.slice(0, -2)) - form.setFieldValue('pathMatch', 'prefix') + + + - - + ]} + noStyle + > + { + if ((e.target.value as string).endsWith('/*')) { + form.setFieldValue('path', e.target.value.slice(0, -2)) + form.setFieldValue('pathMatch', 'prefix') + } + }} + /> + + + + + + label={$t('提示词')} name="prompt"> + - - label={$t('提示词')} name="prompt"> - - - - - label={ -
- {$t('变量')} - - - New - -
- } - name="variables" - className="[&>.ant-row>.ant-col>label]:w-full" - > - - getFromRef={setVariablesTableRef} - configFields={AI_SERVICE_VARIABLES_TABLE_COLUMNS} - /> - - - label={$t('描述')} name="description"> - - - - - className="flex-1" - label={$t('请求超时时间')} - name={'timeout'} - rules={[{ required: true }]} + label={ +
+ {$t('变量')} + + + New + +
+ } + name="variables" + className="[&>.ant-row>.ant-col>label]:w-full" > - + + getFromRef={setVariablesTableRef} + configFields={AI_SERVICE_VARIABLES_TABLE_COLUMNS} + /> + + label={$t('描述')} name="description"> + + + + + + className="flex-1" + label={$t('请求超时时间')} + name={'timeout'} + rules={[{ required: true }]} + > + + + + className="flex-1" + label={$t('重试次数')} + name={'retry'} + rules={[{ required: true }]} + > + + + - className="flex-1" - label={$t('重试次数')} - name={'retry'} - rules={[{ required: true }]} + label={$t('拦截接口')} + name="disabled" + extra={$t('开启拦截后,网关会拦截所有该路径的请求。')} > - + -
- - label={$t('拦截接口')} - name="disabled" - extra={$t('开启拦截后,网关会拦截所有该路径的请求。')} - > - - -
- +
+ + handlerSubmit()}> diff --git a/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx b/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx index c4afd894..7e350a2c 100644 --- a/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx +++ b/frontend/packages/core/src/pages/aiSetting/components/CustomEdge.tsx @@ -31,7 +31,7 @@ export default function CustomEdge({ {label && (