From a34891851bd3dc28c443d4255a955a3bc857e6d0 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 11 Oct 2024 10:32:27 +0800 Subject: [PATCH 01/26] fix(log list): prevent duplicate data fetch (#9190) --- web/app/components/app/log/list.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/app/components/app/log/list.tsx b/web/app/components/app/log/list.tsx index 149e877fa4ac2..7dff48c20a28e 100644 --- a/web/app/components/app/log/list.tsx +++ b/web/app/components/app/log/list.tsx @@ -299,10 +299,14 @@ function DetailPanel { - if (appDetail?.id && detail.id && appDetail?.mode !== 'completion') + if (appDetail?.id && detail.id && appDetail?.mode !== 'completion' && !fetchInitiated.current) { + fetchInitiated.current = true fetchData() - }, [appDetail?.id, detail.id, appDetail?.mode]) + } + }, [appDetail?.id, detail.id, appDetail?.mode, fetchData]) const isChatMode = appDetail?.mode !== 'completion' const isAdvanced = appDetail?.mode === 'advanced-chat' From cabdb4ef1779a139d464b0495b7ed9874818b81c Mon Sep 17 00:00:00 2001 From: Jyong <76649700+JohnJyong@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:32:42 +0800 Subject: [PATCH 02/26] fix retrieval resource positon missed (#9155) Co-authored-by: Bowen Liang --- api/core/rag/entities/context_entities.py | 4 +++- api/core/rag/retrieval/dataset_retrieval.py | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/api/core/rag/entities/context_entities.py b/api/core/rag/entities/context_entities.py index dde3beccf6e46..cd18ad081ff4f 100644 --- a/api/core/rag/entities/context_entities.py +++ b/api/core/rag/entities/context_entities.py @@ -1,3 +1,5 @@ +from typing import Optional + from pydantic import BaseModel @@ -7,4 +9,4 @@ class DocumentContext(BaseModel): """ content: str - score: float + score: Optional[float] = None diff --git a/api/core/rag/retrieval/dataset_retrieval.py b/api/core/rag/retrieval/dataset_retrieval.py index ae61ba7112243..ae79b44158c84 100644 --- a/api/core/rag/retrieval/dataset_retrieval.py +++ b/api/core/rag/retrieval/dataset_retrieval.py @@ -231,6 +231,9 @@ def retrieve( source["content"] = segment.content retrieval_resource_list.append(source) if hit_callback and retrieval_resource_list: + retrieval_resource_list = sorted(retrieval_resource_list, key=lambda x: x.get("score"), reverse=True) + for position, item in enumerate(retrieval_resource_list, start=1): + item["position"] = position hit_callback.return_retriever_resource_info(retrieval_resource_list) if document_context_list: document_context_list = sorted(document_context_list, key=lambda x: x.score, reverse=True) From 5c76131d3dc1e4a5719cc828ba5a485e97024d90 Mon Sep 17 00:00:00 2001 From: Fei He Date: Fri, 11 Oct 2024 10:35:56 +0800 Subject: [PATCH 03/26] feat: add gte rerank for tongyi (#9153) --- .../model_providers/tongyi/rerank/__init__.py | 0 .../tongyi/rerank/_position.yaml | 1 + .../tongyi/rerank/gte-rerank.yaml | 4 + .../model_providers/tongyi/rerank/rerank.py | 136 ++++++++++++++++++ .../model_providers/tongyi/tongyi.yaml | 1 + .../model_runtime/tongyi/test_rerank.py | 40 ++++++ 6 files changed, 182 insertions(+) create mode 100644 api/core/model_runtime/model_providers/tongyi/rerank/__init__.py create mode 100644 api/core/model_runtime/model_providers/tongyi/rerank/_position.yaml create mode 100644 api/core/model_runtime/model_providers/tongyi/rerank/gte-rerank.yaml create mode 100644 api/core/model_runtime/model_providers/tongyi/rerank/rerank.py create mode 100644 api/tests/integration_tests/model_runtime/tongyi/test_rerank.py diff --git a/api/core/model_runtime/model_providers/tongyi/rerank/__init__.py b/api/core/model_runtime/model_providers/tongyi/rerank/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/api/core/model_runtime/model_providers/tongyi/rerank/_position.yaml b/api/core/model_runtime/model_providers/tongyi/rerank/_position.yaml new file mode 100644 index 0000000000000..439afda99263a --- /dev/null +++ b/api/core/model_runtime/model_providers/tongyi/rerank/_position.yaml @@ -0,0 +1 @@ +- gte-rerank diff --git a/api/core/model_runtime/model_providers/tongyi/rerank/gte-rerank.yaml b/api/core/model_runtime/model_providers/tongyi/rerank/gte-rerank.yaml new file mode 100644 index 0000000000000..44d51b9b0d9cd --- /dev/null +++ b/api/core/model_runtime/model_providers/tongyi/rerank/gte-rerank.yaml @@ -0,0 +1,4 @@ +model: gte-rerank +model_type: rerank +model_properties: + context_size: 4000 diff --git a/api/core/model_runtime/model_providers/tongyi/rerank/rerank.py b/api/core/model_runtime/model_providers/tongyi/rerank/rerank.py new file mode 100644 index 0000000000000..c9245bd82ddb0 --- /dev/null +++ b/api/core/model_runtime/model_providers/tongyi/rerank/rerank.py @@ -0,0 +1,136 @@ +from typing import Optional + +import dashscope +from dashscope.common.error import ( + AuthenticationError, + InvalidParameter, + RequestFailure, + ServiceUnavailableError, + UnsupportedHTTPMethod, + UnsupportedModel, +) + +from core.model_runtime.entities.rerank_entities import RerankDocument, RerankResult +from core.model_runtime.errors.invoke import ( + InvokeAuthorizationError, + InvokeBadRequestError, + InvokeConnectionError, + InvokeError, + InvokeRateLimitError, + InvokeServerUnavailableError, +) +from core.model_runtime.errors.validate import CredentialsValidateFailedError +from core.model_runtime.model_providers.__base.rerank_model import RerankModel + + +class GTERerankModel(RerankModel): + """ + Model class for GTE rerank model. + """ + + def _invoke( + self, + model: str, + credentials: dict, + query: str, + docs: list[str], + score_threshold: Optional[float] = None, + top_n: Optional[int] = None, + user: Optional[str] = None, + ) -> RerankResult: + """ + Invoke rerank model + + :param model: model name + :param credentials: model credentials + :param query: search query + :param docs: docs for reranking + :param score_threshold: score threshold + :param top_n: top n + :param user: unique user id + :return: rerank result + """ + if len(docs) == 0: + return RerankResult(model=model, docs=docs) + + # initialize client + dashscope.api_key = credentials["dashscope_api_key"] + + response = dashscope.TextReRank.call( + query=query, + documents=docs, + model=model, + top_n=top_n, + return_documents=True, + ) + + rerank_documents = [] + for _, result in enumerate(response.output.results): + # format document + rerank_document = RerankDocument( + index=result.index, + score=result.relevance_score, + text=result["document"]["text"], + ) + + # score threshold check + if score_threshold is not None: + if result.relevance_score >= score_threshold: + rerank_documents.append(rerank_document) + else: + rerank_documents.append(rerank_document) + + return RerankResult(model=model, docs=rerank_documents) + + def validate_credentials(self, model: str, credentials: dict) -> None: + """ + Validate model credentials + + :param model: model name + :param credentials: model credentials + :return: + """ + try: + self.invoke( + model=model, + credentials=credentials, + query="What is the capital of the United States?", + docs=[ + "Carson City is the capital city of the American state of Nevada. At the 2010 United States " + "Census, Carson City had a population of 55,274.", + "The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean that " + "are a political division controlled by the United States. Its capital is Saipan.", + ], + score_threshold=0.8, + ) + except Exception as ex: + print(ex) + raise CredentialsValidateFailedError(str(ex)) + + @property + def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]: + """ + Map model invoke error to unified error + The key is the error type thrown to the caller + The value is the error type thrown by the model, + which needs to be converted into a unified error type for the caller. + + :return: Invoke error mapping + """ + return { + InvokeConnectionError: [ + RequestFailure, + ], + InvokeServerUnavailableError: [ + ServiceUnavailableError, + ], + InvokeRateLimitError: [], + InvokeAuthorizationError: [ + AuthenticationError, + ], + InvokeBadRequestError: [ + InvalidParameter, + UnsupportedModel, + UnsupportedHTTPMethod, + ], + } diff --git a/api/core/model_runtime/model_providers/tongyi/tongyi.yaml b/api/core/model_runtime/model_providers/tongyi/tongyi.yaml index 1a09c20fd93f6..6349c22714265 100644 --- a/api/core/model_runtime/model_providers/tongyi/tongyi.yaml +++ b/api/core/model_runtime/model_providers/tongyi/tongyi.yaml @@ -18,6 +18,7 @@ supported_model_types: - llm - tts - text-embedding + - rerank configurate_methods: - predefined-model - customizable-model diff --git a/api/tests/integration_tests/model_runtime/tongyi/test_rerank.py b/api/tests/integration_tests/model_runtime/tongyi/test_rerank.py new file mode 100644 index 0000000000000..2dcfb92c63fee --- /dev/null +++ b/api/tests/integration_tests/model_runtime/tongyi/test_rerank.py @@ -0,0 +1,40 @@ +import os + +import dashscope +import pytest + +from core.model_runtime.entities.rerank_entities import RerankResult +from core.model_runtime.errors.validate import CredentialsValidateFailedError +from core.model_runtime.model_providers.tongyi.rerank.rerank import GTERerankModel + + +def test_validate_credentials(): + model = GTERerankModel() + + with pytest.raises(CredentialsValidateFailedError): + model.validate_credentials(model="get-rank", credentials={"dashscope_api_key": "invalid_key"}) + + model.validate_credentials( + model="get-rank", credentials={"dashscope_api_key": os.environ.get("TONGYI_DASHSCOPE_API_KEY")} + ) + + +def test_invoke_model(): + model = GTERerankModel() + + result = model.invoke( + model=dashscope.TextReRank.Models.gte_rerank, + credentials={"dashscope_api_key": os.environ.get("TONGYI_DASHSCOPE_API_KEY")}, + query="什么是文本排序模型", + docs=[ + "文本排序模型广泛用于搜索引擎和推荐系统中,它们根据文本相关性对候选文本进行排序", + "量子计算是计算科学的一个前沿领域", + "预训练语言模型的发展给文本排序模型带来了新的进展", + ], + score_threshold=0.7, + ) + + assert isinstance(result, RerankResult) + assert len(result.docs) == 1 + assert result.docs[0].index == 0 + assert result.docs[0].score >= 0.7 From 8bcad002dffcf0cb3c06f6240370d331dcad6949 Mon Sep 17 00:00:00 2001 From: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:22:59 +0800 Subject: [PATCH 04/26] fix: add loading to 'delete' button & 'save' button (#9214) --- web/app/components/datasets/documents/list.tsx | 6 ++++++ web/app/components/datasets/settings/form/index.tsx | 2 ++ 2 files changed, 8 insertions(+) diff --git a/web/app/components/datasets/documents/list.tsx b/web/app/components/datasets/documents/list.tsx index 540474e7a5739..0e0eebb034df5 100644 --- a/web/app/components/datasets/documents/list.tsx +++ b/web/app/components/datasets/documents/list.tsx @@ -122,6 +122,7 @@ export const OperationAction: FC<{ }> = ({ embeddingAvailable, datasetId, detail, onUpdate, scene = 'list', className = '' }) => { const { id, enabled = false, archived = false, data_source_type } = detail || {} const [showModal, setShowModal] = useState(false) + const [deleting, setDeleting] = useState(false) const { notify } = useContext(ToastContext) const { t } = useTranslation() const router = useRouter() @@ -153,6 +154,7 @@ export const OperationAction: FC<{ break default: opApi = deleteDocument + setDeleting(true) break } const [e] = await asyncRunSafe(opApi({ datasetId, documentId: id }) as Promise) @@ -160,6 +162,8 @@ export const OperationAction: FC<{ notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) else notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) + if (operationName === 'delete') + setDeleting(false) onUpdate(operationName) } @@ -295,6 +299,8 @@ export const OperationAction: FC<{ {showModal && {