feat: update model_provider jina to support custom url and model (#4110)
Co-authored-by: Gimling <huangjl@ruyi.ai> Co-authored-by: takatost <takatost@gmail.com>
This commit is contained in:
@@ -19,6 +19,7 @@ supported_model_types:
|
|||||||
- rerank
|
- rerank
|
||||||
configurate_methods:
|
configurate_methods:
|
||||||
- predefined-model
|
- predefined-model
|
||||||
|
- customizable-model
|
||||||
provider_credential_schema:
|
provider_credential_schema:
|
||||||
credential_form_schemas:
|
credential_form_schemas:
|
||||||
- variable: api_key
|
- variable: api_key
|
||||||
@@ -29,3 +30,40 @@ provider_credential_schema:
|
|||||||
placeholder:
|
placeholder:
|
||||||
zh_Hans: 在此输入您的 API Key
|
zh_Hans: 在此输入您的 API Key
|
||||||
en_US: Enter your API Key
|
en_US: Enter your API Key
|
||||||
|
model_credential_schema:
|
||||||
|
model:
|
||||||
|
label:
|
||||||
|
en_US: Model Name
|
||||||
|
zh_Hans: 模型名称
|
||||||
|
placeholder:
|
||||||
|
en_US: Enter your model name
|
||||||
|
zh_Hans: 输入模型名称
|
||||||
|
credential_form_schemas:
|
||||||
|
- variable: api_key
|
||||||
|
label:
|
||||||
|
en_US: API Key
|
||||||
|
type: secret-input
|
||||||
|
required: true
|
||||||
|
placeholder:
|
||||||
|
zh_Hans: 在此输入您的 API Key
|
||||||
|
en_US: Enter your API Key
|
||||||
|
- variable: base_url
|
||||||
|
label:
|
||||||
|
zh_Hans: 服务器 URL
|
||||||
|
en_US: Base URL
|
||||||
|
type: text-input
|
||||||
|
required: true
|
||||||
|
placeholder:
|
||||||
|
zh_Hans: Base URL, e.g. https://api.jina.ai/v1
|
||||||
|
en_US: Base URL, e.g. https://api.jina.ai/v1
|
||||||
|
default: 'https://api.jina.ai/v1'
|
||||||
|
- variable: context_size
|
||||||
|
label:
|
||||||
|
zh_Hans: 上下文大小
|
||||||
|
en_US: Context size
|
||||||
|
placeholder:
|
||||||
|
zh_Hans: 输入上下文大小
|
||||||
|
en_US: Enter context size
|
||||||
|
required: false
|
||||||
|
type: text-input
|
||||||
|
default: '8192'
|
||||||
|
@@ -2,6 +2,8 @@ from typing import Optional
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
|
from core.model_runtime.entities.common_entities import I18nObject
|
||||||
|
from core.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelPropertyKey, ModelType
|
||||||
from core.model_runtime.entities.rerank_entities import RerankDocument, RerankResult
|
from core.model_runtime.entities.rerank_entities import RerankDocument, RerankResult
|
||||||
from core.model_runtime.errors.invoke import (
|
from core.model_runtime.errors.invoke import (
|
||||||
InvokeAuthorizationError,
|
InvokeAuthorizationError,
|
||||||
@@ -38,9 +40,13 @@ class JinaRerankModel(RerankModel):
|
|||||||
if len(docs) == 0:
|
if len(docs) == 0:
|
||||||
return RerankResult(model=model, docs=[])
|
return RerankResult(model=model, docs=[])
|
||||||
|
|
||||||
|
base_url = credentials.get('base_url', 'https://api.jina.ai/v1')
|
||||||
|
if base_url.endswith('/'):
|
||||||
|
base_url = base_url[:-1]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = httpx.post(
|
response = httpx.post(
|
||||||
"https://api.jina.ai/v1/rerank",
|
base_url + '/rerank',
|
||||||
json={
|
json={
|
||||||
"model": model,
|
"model": model,
|
||||||
"query": query,
|
"query": query,
|
||||||
@@ -103,3 +109,19 @@ class JinaRerankModel(RerankModel):
|
|||||||
InvokeAuthorizationError: [httpx.HTTPStatusError],
|
InvokeAuthorizationError: [httpx.HTTPStatusError],
|
||||||
InvokeBadRequestError: [httpx.RequestError]
|
InvokeBadRequestError: [httpx.RequestError]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_customizable_model_schema(self, model: str, credentials: dict) -> AIModelEntity:
|
||||||
|
"""
|
||||||
|
generate custom model entities from credentials
|
||||||
|
"""
|
||||||
|
entity = AIModelEntity(
|
||||||
|
model=model,
|
||||||
|
label=I18nObject(en_US=model),
|
||||||
|
model_type=ModelType.RERANK,
|
||||||
|
fetch_from=FetchFrom.CUSTOMIZABLE_MODEL,
|
||||||
|
model_properties={
|
||||||
|
ModelPropertyKey.CONTEXT_SIZE: int(credentials.get('context_size'))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return entity
|
@@ -4,7 +4,8 @@ from typing import Optional
|
|||||||
|
|
||||||
from requests import post
|
from requests import post
|
||||||
|
|
||||||
from core.model_runtime.entities.model_entities import PriceType
|
from core.model_runtime.entities.common_entities import I18nObject
|
||||||
|
from core.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelPropertyKey, ModelType, PriceType
|
||||||
from core.model_runtime.entities.text_embedding_entities import EmbeddingUsage, TextEmbeddingResult
|
from core.model_runtime.entities.text_embedding_entities import EmbeddingUsage, TextEmbeddingResult
|
||||||
from core.model_runtime.errors.invoke import (
|
from core.model_runtime.errors.invoke import (
|
||||||
InvokeAuthorizationError,
|
InvokeAuthorizationError,
|
||||||
@@ -23,8 +24,7 @@ class JinaTextEmbeddingModel(TextEmbeddingModel):
|
|||||||
"""
|
"""
|
||||||
Model class for Jina text embedding model.
|
Model class for Jina text embedding model.
|
||||||
"""
|
"""
|
||||||
api_base: str = 'https://api.jina.ai/v1/embeddings'
|
api_base: str = 'https://api.jina.ai/v1'
|
||||||
models: list[str] = ['jina-embeddings-v2-base-en', 'jina-embeddings-v2-small-en', 'jina-embeddings-v2-base-zh', 'jina-embeddings-v2-base-de']
|
|
||||||
|
|
||||||
def _invoke(self, model: str, credentials: dict,
|
def _invoke(self, model: str, credentials: dict,
|
||||||
texts: list[str], user: Optional[str] = None) \
|
texts: list[str], user: Optional[str] = None) \
|
||||||
@@ -39,11 +39,14 @@ class JinaTextEmbeddingModel(TextEmbeddingModel):
|
|||||||
:return: embeddings result
|
:return: embeddings result
|
||||||
"""
|
"""
|
||||||
api_key = credentials['api_key']
|
api_key = credentials['api_key']
|
||||||
if model not in self.models:
|
|
||||||
raise InvokeBadRequestError('Invalid model name')
|
|
||||||
if not api_key:
|
if not api_key:
|
||||||
raise CredentialsValidateFailedError('api_key is required')
|
raise CredentialsValidateFailedError('api_key is required')
|
||||||
url = self.api_base
|
|
||||||
|
base_url = credentials.get('base_url', self.api_base)
|
||||||
|
if base_url.endswith('/'):
|
||||||
|
base_url = base_url[:-1]
|
||||||
|
|
||||||
|
url = base_url + '/embeddings'
|
||||||
headers = {
|
headers = {
|
||||||
'Authorization': 'Bearer ' + api_key,
|
'Authorization': 'Bearer ' + api_key,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@@ -70,7 +73,7 @@ class JinaTextEmbeddingModel(TextEmbeddingModel):
|
|||||||
elif response.status_code == 500:
|
elif response.status_code == 500:
|
||||||
raise InvokeServerUnavailableError(msg)
|
raise InvokeServerUnavailableError(msg)
|
||||||
else:
|
else:
|
||||||
raise InvokeError(msg)
|
raise InvokeBadRequestError(msg)
|
||||||
except JSONDecodeError as e:
|
except JSONDecodeError as e:
|
||||||
raise InvokeServerUnavailableError(f"Failed to convert response to json: {e} with text: {response.text}")
|
raise InvokeServerUnavailableError(f"Failed to convert response to json: {e} with text: {response.text}")
|
||||||
|
|
||||||
@@ -118,8 +121,8 @@ class JinaTextEmbeddingModel(TextEmbeddingModel):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self._invoke(model=model, credentials=credentials, texts=['ping'])
|
self._invoke(model=model, credentials=credentials, texts=['ping'])
|
||||||
except InvokeAuthorizationError:
|
except Exception as e:
|
||||||
raise CredentialsValidateFailedError('Invalid api key')
|
raise CredentialsValidateFailedError(f'Credentials validation failed: {e}')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]:
|
def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]:
|
||||||
@@ -137,7 +140,8 @@ class JinaTextEmbeddingModel(TextEmbeddingModel):
|
|||||||
InvokeAuthorizationError
|
InvokeAuthorizationError
|
||||||
],
|
],
|
||||||
InvokeBadRequestError: [
|
InvokeBadRequestError: [
|
||||||
KeyError
|
KeyError,
|
||||||
|
InvokeBadRequestError
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,3 +174,19 @@ class JinaTextEmbeddingModel(TextEmbeddingModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return usage
|
return usage
|
||||||
|
|
||||||
|
def get_customizable_model_schema(self, model: str, credentials: dict) -> AIModelEntity:
|
||||||
|
"""
|
||||||
|
generate custom model entities from credentials
|
||||||
|
"""
|
||||||
|
entity = AIModelEntity(
|
||||||
|
model=model,
|
||||||
|
label=I18nObject(en_US=model),
|
||||||
|
model_type=ModelType.TEXT_EMBEDDING,
|
||||||
|
fetch_from=FetchFrom.CUSTOMIZABLE_MODEL,
|
||||||
|
model_properties={
|
||||||
|
ModelPropertyKey.CONTEXT_SIZE: int(credentials.get('context_size'))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return entity
|
||||||
|
Reference in New Issue
Block a user