import { expandKeysAtom } from '@/atoms/clusters'; import DeleteModal from '@/components/delete-modal'; import IconFont from '@/components/icon-font'; import { FilterBar } from '@/components/page-tools'; import SealTable from '@/components/seal-table'; import TableContext from '@/components/seal-table/table-context'; import { TableOrder } from '@/components/seal-table/types'; import { PageAction } from '@/config'; import { TABLE_SORT_DIRECTIONS } from '@/config/settings'; import useExpandedRowKeys from '@/hooks/use-expanded-row-keys'; import useTableFetch from '@/hooks/use-table-fetch'; import useWatchList from '@/hooks/use-watch-list'; import APIAccessInfoModal from '@/pages/llmodels/components/api-access-info'; import { useIntl } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; import { message } from 'antd'; import { useAtom } from 'jotai'; import _ from 'lodash'; import { useEffect, useState } from 'react'; import NoResult from '../_components/no-result'; import PageBox from '../_components/page-box'; import { queryModelsList } from '../llmodels/apis'; import AccessControlModal from '../llmodels/components/access-control-modal'; import { MODEL_ROUTES, MODEL_ROUTE_TARGETS, createModelRoute, deleteModelRoute, deleteModelRouteTarget, queryModelRoutes, queryRouteTargets, setRouteTargetAsFallback, updateModelRoute } from './apis'; import AddRouteModal from './components/add-route-modal'; import RouteTargets from './components/route-targets'; import { FormData, RouteItem as ListItem } from './config/types'; import useAccessControl from './hooks/use-access-control'; import useCreateRoute from './hooks/use-create-route'; import useOpenPlayground from './hooks/use-open-playground'; import useRoutesColumns from './hooks/use-routes-columns'; import useTargetSourceModels from './hooks/use-target-source-models'; import useViewApIInfo from './hooks/use-view-api-info'; const ModelRoutes: React.FC = () => { const { dataSource, rowSelection, queryParams, modalRef, handleTableChange, handleDelete, handleDeleteBatch, fetchData, handlePageChange, handleSearch, handleNameChange } = useTableFetch({ fetchAPI: queryModelRoutes, deleteAPI: deleteModelRoute, watch: true, API: MODEL_ROUTES, contentForDelete: 'menu.models.routes' }); const { watchDataList: allRouteTargets, deleteItemFromCache } = useWatchList(MODEL_ROUTE_TARGETS); const [expandAtom] = useAtom(expandKeysAtom); const { handleExpandChange, handleExpandAll, updateExpandedRowKeys, removeExpandedRowKey, expandedRowKeys } = useExpandedRowKeys(expandAtom); const intl = useIntl(); const { openRouteModalStatus, openRouteModal, closeRouteModal } = useCreateRoute(); const { openAccessControlModal, closeAccessControlModal, openAccessControlModalStatus } = useAccessControl(); const { sourceModels, fetchSourceModels } = useTargetSourceModels(); const { handleOpenPlayGround } = useOpenPlayground(); const { apiAccessInfo, openViewAPIInfo, closeViewAPIInfo } = useViewApIInfo(); const [modelList, setModelsList] = useState[]>([]); useEffect(() => { const fetchModels = async () => { try { const res = await queryModelsList({ page: -1 }); const models = res.items?.map((model) => ({ label: model.name, value: model.id })) || []; setModelsList(models); } catch (error) { setModelsList([]); } }; fetchModels(); }, []); const handleClickDropdown = () => { openRouteModal( PageAction.CREATE, intl.formatMessage({ id: 'routes.button.add' }) ); }; const handleModalOk = async (data: FormData) => { const params = { ...data }; try { let data: ListItem = {} as any; if (openRouteModalStatus.action === PageAction.EDIT) { data = await updateModelRoute({ data: params, id: openRouteModalStatus.currentData!.id }); } if (openRouteModalStatus.action === PageAction.CREATE) { data = await createModelRoute({ data: params }); } if (data.targets > 0) { updateExpandedRowKeys([data.id, ...expandedRowKeys]); } fetchData(); closeRouteModal(); message.success(intl.formatMessage({ id: 'common.message.success' })); } catch (error) {} }; const handleModalCancel = () => { console.log('handleModalCancel'); closeRouteModal(); }; const handleEditProvider = (row: ListItem) => { openRouteModal( PageAction.EDIT, intl.formatMessage({ id: 'common.button.edit.item' }, { name: row.name }), row ); }; const handleSelect = useMemoizedFn((val: any, row: ListItem) => { if (val === 'edit') { handleEditProvider(row); } else if (val === 'delete') { handleDelete({ ...row, name: row.name }); } else if (val === 'accessControl') { openAccessControlModal( PageAction.EDIT, intl.formatMessage({ id: 'models.button.accessSettings' }), row ); } else if (val === 'chat') { handleOpenPlayGround(row); } else if (val === 'api') { openViewAPIInfo(row); } }); const handleOnToggleExpandAll = () => { // do nothing }; const handleToggleExpandAll = useMemoizedFn((expanded: boolean) => { const keys = dataSource.dataList?.map((item) => item.id); handleExpandAll(expanded, keys); if (expanded) { handleOnToggleExpandAll(); } }); const loadChildrenData = useMemoizedFn( async (row: ListItem, options?: any) => { const params = { id: row.id }; const res = await queryRouteTargets(params, { token: options?.token }); return res.items || []; } ); const handleOnSortChange = (order: TableOrder | Array) => { handleTableChange({}, {}, order, { action: 'sort' }); }; const handleDeleteTarget = (row: any) => { modalRef.current?.show({ content: 'routes.table.routeTargets', okText: 'common.button.delete', operation: 'common.delete.single.confirm', name: row.name, async onOk() { await deleteModelRouteTarget(row.id); deleteItemFromCache?.(row.id); } }); }; const onChildSelect = useMemoizedFn(async (val: any, record: any) => { try { if (val === 'fallback') { await setRouteTargetAsFallback({ id: record.id, data: { fallback_status_codes: ['4xx', '5xx'] } }); message.success(intl.formatMessage({ id: 'common.message.success' })); } else if (val === 'delete') { handleDeleteTarget(record); } } catch (error) {} }); const renderChildren = ( list: any, options: { parent?: any; [key: string]: any } ) => { return ( ); }; const setDisableExpand = (record: any) => { return !record?.targets; }; useEffect(() => { fetchSourceModels(); }, []); const columns = useRoutesColumns(handleSelect); return ( <> } filters={_.omit(queryParams, ['sort_by'])} noFoundText={intl.formatMessage({ id: 'noresult.routes.nofound' })} title={intl.formatMessage({ id: 'noresult.routes.title' })} subTitle={intl.formatMessage({ id: 'noresult.routes.subTitle' })} onClick={handleClickDropdown} buttonText={intl.formatMessage({ id: 'noresult.button.add' })} > } pagination={{ showSizeChanger: true, pageSize: queryParams.perPage, current: queryParams.page, total: dataSource.total, hideOnSinglePage: queryParams.perPage === 10, onChange: handlePageChange }} > ); }; export default ModelRoutes;