diff --git a/src/pages/llmodels/components/data-form.tsx b/src/pages/llmodels/components/data-form.tsx index 0553f3f6..956d2dbd 100644 --- a/src/pages/llmodels/components/data-form.tsx +++ b/src/pages/llmodels/components/data-form.tsx @@ -248,6 +248,7 @@ const DataForm: React.FC = forwardRef((props, ref) => { diff --git a/src/pages/llmodels/components/model-card.tsx b/src/pages/llmodels/components/model-card.tsx index 420d8f6e..3f51ee3e 100644 --- a/src/pages/llmodels/components/model-card.tsx +++ b/src/pages/llmodels/components/model-card.tsx @@ -49,8 +49,7 @@ const MarkDownTitle: React.FC<{ return ( - {' '} - {intl.formatMessage({ id: 'models.readme' })} + README.md {collapsed ? ( diff --git a/src/pages/llmodels/components/search-model.tsx b/src/pages/llmodels/components/search-model.tsx index 6acd54d1..70fab7c5 100644 --- a/src/pages/llmodels/components/search-model.tsx +++ b/src/pages/llmodels/components/search-model.tsx @@ -33,6 +33,12 @@ const UL = styled.ul` margin: 0; `; +const PaginationMain = styled(Pagination)` + .ant-pagination-slash { + margin-inline: 5px; + } +`; + interface SearchInputProps { hasLinuxWorker?: boolean; modelSource: string; @@ -87,6 +93,7 @@ const SearchModel: React.FC = (props) => { const filterTaskRef = useRef(''); const timer = useRef(null); const requestIdRef = useRef(0); + const searchIdRef = useRef(0); const [query, setQuery] = useState({ page: 1, perPage: 10, @@ -111,6 +118,11 @@ const SearchModel: React.FC = (props) => { } ]); + const updateSearchId = () => { + searchIdRef.current += 1; + return searchIdRef.current; + }; + const updateRequestId = () => { requestIdRef.current += 1; return requestIdRef.current; @@ -135,6 +147,7 @@ const SearchModel: React.FC = (props) => { // huggeface const getModelsFromHuggingface = async (sort: string) => { + const currentSearchId = updateSearchId(); try { const task: any = searchInputRef.current ? '' : 'text-generation'; const params = { @@ -148,6 +161,11 @@ const SearchModel: React.FC = (props) => { const data = await queryHuggingfaceModels(params, { signal: axiosTokenRef.current.signal }); + if (searchIdRef.current !== currentSearchId) { + return { + notSameRequest: true + }; + } let list = _.map(data || [], (item: any) => { return { ...item, @@ -159,6 +177,11 @@ const SearchModel: React.FC = (props) => { }); return list; } catch (error) { + if (searchIdRef.current !== currentSearchId) { + return { + notSameRequest: true + }; + } return []; } }; @@ -169,6 +192,7 @@ const SearchModel: React.FC = (props) => { page: number; perPage?: number; }) => { + const currentSearchId = updateSearchId(); try { const params = { Name: `${searchInputRef.current}`, @@ -183,6 +207,11 @@ const SearchModel: React.FC = (props) => { const data = await queryModelScopeModels(params, { signal: axiosTokenRef.current.signal }); + if (searchIdRef.current !== currentSearchId) { + return { + notSameRequest: true + }; + } let list = _.map(_.get(data, 'Data.Model.Models') || [], (item: any) => { return { path: item.Path, @@ -214,6 +243,11 @@ const SearchModel: React.FC = (props) => { }); return list; } catch (error) { + if (searchIdRef.current !== currentSearchId) { + return { + notSameRequest: true + }; + } setQuery((prev) => { return { ...prev, @@ -343,6 +377,9 @@ const SearchModel: React.FC = (props) => { let list: any[] = []; if (modelSource === modelSourceMap.huggingface_value) { const resultList = await getModelsFromHuggingface(sort); + if (resultList?.notSameRequest) { + return; + } cacheRepoOptions.current = resultList; // hf has no page and perPage, so we need to slice the resultList @@ -356,6 +393,9 @@ const SearchModel: React.FC = (props) => { }); } else if (modelSource === modelSourceMap.modelscope_value) { list = await getModelsFromModelscope(params); + if (list?.notSameRequest) { + return; + } cacheRepoOptions.current = list; } @@ -370,7 +410,7 @@ const SearchModel: React.FC = (props) => { unlockWarningStatus?.(); displayEvaluateStatus?.( { - show: list.length > 0, + show: list?.length > 0, message: '' }, { @@ -389,6 +429,7 @@ const SearchModel: React.FC = (props) => { sortType: sort, networkError: error?.message === 'Failed to fetch' }); + setLoadingModel?.(false); displayEvaluateStatus?.({ show: false, @@ -472,6 +513,12 @@ const SearchModel: React.FC = (props) => { handleOnSelectModel(currentList[0]); handleEvaluate(currentList); } else if (modelSource === modelSourceMap.modelscope_value) { + setQuery((prev) => { + return { + ...prev, + page: page + }; + }); handleOnSearchRepo({ sortType: dataSource.sortType, page: page, @@ -539,7 +586,7 @@ const SearchModel: React.FC = (props) => { {renderGGUFTips} - = (props) => { onChange={handleOnPageChange} showSizeChanger={false} hideOnSinglePage={query.total <= query.perPage} - > + > ); diff --git a/src/pages/llmodels/config/form-context.ts b/src/pages/llmodels/config/form-context.ts index 1864f344..991c633a 100644 --- a/src/pages/llmodels/config/form-context.ts +++ b/src/pages/llmodels/config/form-context.ts @@ -15,6 +15,7 @@ interface FormContextProps { interface FormInnerContextProps { onBackendChange?: (backend: string) => void; + onValuesChange?: (changedValues: any, allValues: any) => void; gpuOptions?: any[]; } diff --git a/src/pages/llmodels/forms/local-path.tsx b/src/pages/llmodels/forms/local-path.tsx index 7ba6826c..3174e2e0 100644 --- a/src/pages/llmodels/forms/local-path.tsx +++ b/src/pages/llmodels/forms/local-path.tsx @@ -19,7 +19,7 @@ const LocalPathForm: React.FC = () => { const formCtx = useFormContext(); const formInnerCtx = useFormInnerContext(); const source = Form.useWatch('source', form); - const { onBackendChange, gpuOptions } = formInnerCtx; + const { onBackendChange, onValuesChange, gpuOptions } = formInnerCtx; const { byBuiltIn } = formCtx; const { getRuleMessage } = useAppUtils(); const intl = useIntl(); @@ -29,7 +29,7 @@ const LocalPathForm: React.FC = () => { return null; } - const handleLocalPathBlur = (e: any) => { + const handleLocalPathBlur = async (e: any) => { const value = e.target.value; if (value === localPathCache.current || !value) { return; @@ -37,6 +37,7 @@ const LocalPathForm: React.FC = () => { const isEndwithGGUF = _.endsWith(value, '.gguf'); const isBlobFile = value.split('/').pop().includes('sha256'); let backend = form.getFieldValue('backend'); + const oldBackend = backend; if (isEndwithGGUF || isBlobFile) { backend = backendOptionsMap.llamaBox; @@ -51,7 +52,17 @@ const LocalPathForm: React.FC = () => { } form.setFieldValue('backend', backend); - onBackendChange?.(backend); + await new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, 0); + }); + + if (oldBackend !== backend) { + onBackendChange?.(backend); + } else { + onValuesChange?.({ local_path: value }, form.getFieldsValue()); + } }; const handleOnFocus = () => { diff --git a/src/pages/playground/components/message-input.tsx b/src/pages/playground/components/message-input.tsx index a18e7db2..ac751f5b 100644 --- a/src/pages/playground/components/message-input.tsx +++ b/src/pages/playground/components/message-input.tsx @@ -164,7 +164,10 @@ const MessageInput: React.FC = forwardRef( const isDisabled = useMemo(() => { return disabled ? true - : !message.content && isEmpty && !message.imgs?.length; + : !message.content && + isEmpty && + !message.imgs?.length && + !message.audio?.length; }, [disabled, message, isEmpty]); const resetMessage = () => {