merge main
commit
684896d100
@ -0,0 +1,29 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class BaiduOBSStorageConfig(BaseModel):
|
||||||
|
"""
|
||||||
|
Configuration settings for Baidu Object Storage Service (OBS)
|
||||||
|
"""
|
||||||
|
|
||||||
|
BAIDU_OBS_BUCKET_NAME: Optional[str] = Field(
|
||||||
|
description="Name of the Baidu OBS bucket to store and retrieve objects (e.g., 'my-obs-bucket')",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_OBS_ACCESS_KEY: Optional[str] = Field(
|
||||||
|
description="Access Key ID for authenticating with Baidu OBS",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_OBS_SECRET_KEY: Optional[str] = Field(
|
||||||
|
description="Secret Access Key for authenticating with Baidu OBS",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_OBS_ENDPOINT: Optional[str] = Field(
|
||||||
|
description="URL of the Baidu OSS endpoint for your chosen region (e.g., 'https://.bj.bcebos.com')",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class SupabaseStorageConfig(BaseModel):
|
||||||
|
"""
|
||||||
|
Configuration settings for Supabase Object Storage Service
|
||||||
|
"""
|
||||||
|
|
||||||
|
SUPABASE_BUCKET_NAME: Optional[str] = Field(
|
||||||
|
description="Name of the Supabase bucket to store and retrieve objects (e.g., 'dify-bucket')",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
SUPABASE_API_KEY: Optional[str] = Field(
|
||||||
|
description="API KEY for authenticating with Supabase",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
SUPABASE_URL: Optional[str] = Field(
|
||||||
|
description="URL of the Supabase",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import Field, NonNegativeInt, PositiveInt
|
||||||
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
|
|
||||||
|
class BaiduVectorDBConfig(BaseSettings):
|
||||||
|
"""
|
||||||
|
Configuration settings for Baidu Vector Database
|
||||||
|
"""
|
||||||
|
|
||||||
|
BAIDU_VECTOR_DB_ENDPOINT: Optional[str] = Field(
|
||||||
|
description="URL of the Baidu Vector Database service (e.g., 'http://vdb.bj.baidubce.com')",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS: PositiveInt = Field(
|
||||||
|
description="Timeout in milliseconds for Baidu Vector Database operations (default is 30000 milliseconds)",
|
||||||
|
default=30000,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_VECTOR_DB_ACCOUNT: Optional[str] = Field(
|
||||||
|
description="Account for authenticating with the Baidu Vector Database",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_VECTOR_DB_API_KEY: Optional[str] = Field(
|
||||||
|
description="API key for authenticating with the Baidu Vector Database service",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_VECTOR_DB_DATABASE: Optional[str] = Field(
|
||||||
|
description="Name of the specific Baidu Vector Database to connect to",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_VECTOR_DB_SHARD: PositiveInt = Field(
|
||||||
|
description="Number of shards for the Baidu Vector Database (default is 1)",
|
||||||
|
default=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
BAIDU_VECTOR_DB_REPLICAS: NonNegativeInt = Field(
|
||||||
|
description="Number of replicas for the Baidu Vector Database (default is 3)",
|
||||||
|
default=3,
|
||||||
|
)
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class VikingDBConfig(BaseModel):
|
||||||
|
"""
|
||||||
|
Configuration for connecting to Volcengine VikingDB.
|
||||||
|
Refer to the following documentation for details on obtaining credentials:
|
||||||
|
https://www.volcengine.com/docs/6291/65568
|
||||||
|
"""
|
||||||
|
|
||||||
|
VIKINGDB_ACCESS_KEY: Optional[str] = Field(
|
||||||
|
default=None, description="The Access Key provided by Volcengine VikingDB for API authentication."
|
||||||
|
)
|
||||||
|
VIKINGDB_SECRET_KEY: Optional[str] = Field(
|
||||||
|
default=None, description="The Secret Key provided by Volcengine VikingDB for API authentication."
|
||||||
|
)
|
||||||
|
VIKINGDB_REGION: Optional[str] = Field(
|
||||||
|
default="cn-shanghai",
|
||||||
|
description="The region of the Volcengine VikingDB service.(e.g., 'cn-shanghai', 'cn-beijing').",
|
||||||
|
)
|
||||||
|
VIKINGDB_HOST: Optional[str] = Field(
|
||||||
|
default="api-vikingdb.mlp.cn-shanghai.volces.com",
|
||||||
|
description="The host of the Volcengine VikingDB service.(e.g., 'api-vikingdb.volces.com', \
|
||||||
|
'api-vikingdb.mlp.cn-shanghai.volces.com')",
|
||||||
|
)
|
||||||
|
VIKINGDB_SCHEME: Optional[str] = Field(
|
||||||
|
default="http",
|
||||||
|
description="The scheme of the Volcengine VikingDB service.(e.g., 'http', 'https').",
|
||||||
|
)
|
||||||
|
VIKINGDB_CONNECTION_TIMEOUT: Optional[int] = Field(
|
||||||
|
default=30, description="The connection timeout of the Volcengine VikingDB service."
|
||||||
|
)
|
||||||
|
VIKINGDB_SOCKET_TIMEOUT: Optional[int] = Field(
|
||||||
|
default=30, description="The socket timeout of the Volcengine VikingDB service."
|
||||||
|
)
|
||||||
@ -0,0 +1,263 @@
|
|||||||
|
from flask import request
|
||||||
|
from flask_login import current_user
|
||||||
|
from flask_restful import Resource, marshal, reqparse
|
||||||
|
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
|
||||||
|
|
||||||
|
import services
|
||||||
|
from controllers.console import api
|
||||||
|
from controllers.console.datasets.error import DatasetNameDuplicateError
|
||||||
|
from controllers.console.setup import setup_required
|
||||||
|
from controllers.console.wraps import account_initialization_required
|
||||||
|
from fields.dataset_fields import dataset_detail_fields
|
||||||
|
from libs.login import login_required
|
||||||
|
from services.dataset_service import DatasetService
|
||||||
|
from services.external_knowledge_service import ExternalDatasetService
|
||||||
|
from services.hit_testing_service import HitTestingService
|
||||||
|
from services.knowledge_service import ExternalDatasetTestService
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_name(name):
|
||||||
|
if not name or len(name) < 1 or len(name) > 100:
|
||||||
|
raise ValueError("Name must be between 1 to 100 characters.")
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_description_length(description):
|
||||||
|
if description and len(description) > 400:
|
||||||
|
raise ValueError("Description cannot exceed 400 characters.")
|
||||||
|
return description
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalApiTemplateListApi(Resource):
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def get(self):
|
||||||
|
page = request.args.get("page", default=1, type=int)
|
||||||
|
limit = request.args.get("limit", default=20, type=int)
|
||||||
|
search = request.args.get("keyword", default=None, type=str)
|
||||||
|
|
||||||
|
external_knowledge_apis, total = ExternalDatasetService.get_external_knowledge_apis(
|
||||||
|
page, limit, current_user.current_tenant_id, search
|
||||||
|
)
|
||||||
|
response = {
|
||||||
|
"data": [item.to_dict() for item in external_knowledge_apis],
|
||||||
|
"has_more": len(external_knowledge_apis) == limit,
|
||||||
|
"limit": limit,
|
||||||
|
"total": total,
|
||||||
|
"page": page,
|
||||||
|
}
|
||||||
|
return response, 200
|
||||||
|
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def post(self):
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"name",
|
||||||
|
nullable=False,
|
||||||
|
required=True,
|
||||||
|
help="Name is required. Name must be between 1 to 100 characters.",
|
||||||
|
type=_validate_name,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"settings",
|
||||||
|
type=dict,
|
||||||
|
location="json",
|
||||||
|
nullable=False,
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
ExternalDatasetService.validate_api_list(args["settings"])
|
||||||
|
|
||||||
|
# The role of the current user in the ta table must be admin, owner, or editor, or dataset_operator
|
||||||
|
if not current_user.is_dataset_editor:
|
||||||
|
raise Forbidden()
|
||||||
|
|
||||||
|
try:
|
||||||
|
external_knowledge_api = ExternalDatasetService.create_external_knowledge_api(
|
||||||
|
tenant_id=current_user.current_tenant_id, user_id=current_user.id, args=args
|
||||||
|
)
|
||||||
|
except services.errors.dataset.DatasetNameDuplicateError:
|
||||||
|
raise DatasetNameDuplicateError()
|
||||||
|
|
||||||
|
return external_knowledge_api.to_dict(), 201
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalApiTemplateApi(Resource):
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def get(self, external_knowledge_api_id):
|
||||||
|
external_knowledge_api_id = str(external_knowledge_api_id)
|
||||||
|
external_knowledge_api = ExternalDatasetService.get_external_knowledge_api(external_knowledge_api_id)
|
||||||
|
if external_knowledge_api is None:
|
||||||
|
raise NotFound("API template not found.")
|
||||||
|
|
||||||
|
return external_knowledge_api.to_dict(), 200
|
||||||
|
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def patch(self, external_knowledge_api_id):
|
||||||
|
external_knowledge_api_id = str(external_knowledge_api_id)
|
||||||
|
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"name",
|
||||||
|
nullable=False,
|
||||||
|
required=True,
|
||||||
|
help="type is required. Name must be between 1 to 100 characters.",
|
||||||
|
type=_validate_name,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"settings",
|
||||||
|
type=dict,
|
||||||
|
location="json",
|
||||||
|
nullable=False,
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
ExternalDatasetService.validate_api_list(args["settings"])
|
||||||
|
|
||||||
|
external_knowledge_api = ExternalDatasetService.update_external_knowledge_api(
|
||||||
|
tenant_id=current_user.current_tenant_id,
|
||||||
|
user_id=current_user.id,
|
||||||
|
external_knowledge_api_id=external_knowledge_api_id,
|
||||||
|
args=args,
|
||||||
|
)
|
||||||
|
|
||||||
|
return external_knowledge_api.to_dict(), 200
|
||||||
|
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def delete(self, external_knowledge_api_id):
|
||||||
|
external_knowledge_api_id = str(external_knowledge_api_id)
|
||||||
|
|
||||||
|
# The role of the current user in the ta table must be admin, owner, or editor
|
||||||
|
if not current_user.is_editor or current_user.is_dataset_operator:
|
||||||
|
raise Forbidden()
|
||||||
|
|
||||||
|
ExternalDatasetService.delete_external_knowledge_api(current_user.current_tenant_id, external_knowledge_api_id)
|
||||||
|
return {"result": "success"}, 200
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalApiUseCheckApi(Resource):
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def get(self, external_knowledge_api_id):
|
||||||
|
external_knowledge_api_id = str(external_knowledge_api_id)
|
||||||
|
|
||||||
|
external_knowledge_api_is_using, count = ExternalDatasetService.external_knowledge_api_use_check(
|
||||||
|
external_knowledge_api_id
|
||||||
|
)
|
||||||
|
return {"is_using": external_knowledge_api_is_using, "count": count}, 200
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalDatasetCreateApi(Resource):
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def post(self):
|
||||||
|
# The role of the current user in the ta table must be admin, owner, or editor
|
||||||
|
if not current_user.is_editor:
|
||||||
|
raise Forbidden()
|
||||||
|
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
parser.add_argument("external_knowledge_api_id", type=str, required=True, nullable=False, location="json")
|
||||||
|
parser.add_argument("external_knowledge_id", type=str, required=True, nullable=False, location="json")
|
||||||
|
parser.add_argument(
|
||||||
|
"name",
|
||||||
|
nullable=False,
|
||||||
|
required=True,
|
||||||
|
help="name is required. Name must be between 1 to 100 characters.",
|
||||||
|
type=_validate_name,
|
||||||
|
)
|
||||||
|
parser.add_argument("description", type=str, required=False, nullable=True, location="json")
|
||||||
|
parser.add_argument("external_retrieval_model", type=dict, required=False, location="json")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# The role of the current user in the ta table must be admin, owner, or editor, or dataset_operator
|
||||||
|
if not current_user.is_dataset_editor:
|
||||||
|
raise Forbidden()
|
||||||
|
|
||||||
|
try:
|
||||||
|
dataset = ExternalDatasetService.create_external_dataset(
|
||||||
|
tenant_id=current_user.current_tenant_id,
|
||||||
|
user_id=current_user.id,
|
||||||
|
args=args,
|
||||||
|
)
|
||||||
|
except services.errors.dataset.DatasetNameDuplicateError:
|
||||||
|
raise DatasetNameDuplicateError()
|
||||||
|
|
||||||
|
return marshal(dataset, dataset_detail_fields), 201
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalKnowledgeHitTestingApi(Resource):
|
||||||
|
@setup_required
|
||||||
|
@login_required
|
||||||
|
@account_initialization_required
|
||||||
|
def post(self, dataset_id):
|
||||||
|
dataset_id_str = str(dataset_id)
|
||||||
|
dataset = DatasetService.get_dataset(dataset_id_str)
|
||||||
|
if dataset is None:
|
||||||
|
raise NotFound("Dataset not found.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
DatasetService.check_dataset_permission(dataset, current_user)
|
||||||
|
except services.errors.account.NoPermissionError as e:
|
||||||
|
raise Forbidden(str(e))
|
||||||
|
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
parser.add_argument("query", type=str, location="json")
|
||||||
|
parser.add_argument("external_retrieval_model", type=dict, required=False, location="json")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
HitTestingService.hit_testing_args_check(args)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = HitTestingService.external_retrieve(
|
||||||
|
dataset=dataset,
|
||||||
|
query=args["query"],
|
||||||
|
account=current_user,
|
||||||
|
external_retrieval_model=args["external_retrieval_model"],
|
||||||
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
raise InternalServerError(str(e))
|
||||||
|
|
||||||
|
|
||||||
|
class BedrockRetrievalApi(Resource):
|
||||||
|
# this api is only for internal testing
|
||||||
|
def post(self):
|
||||||
|
parser = reqparse.RequestParser()
|
||||||
|
parser.add_argument("retrieval_setting", nullable=False, required=True, type=dict, location="json")
|
||||||
|
parser.add_argument(
|
||||||
|
"query",
|
||||||
|
nullable=False,
|
||||||
|
required=True,
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
parser.add_argument("knowledge_id", nullable=False, required=True, type=str)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Call the knowledge retrieval service
|
||||||
|
result = ExternalDatasetTestService.knowledge_retrieval(
|
||||||
|
args["retrieval_setting"], args["query"], args["knowledge_id"]
|
||||||
|
)
|
||||||
|
return result, 200
|
||||||
|
|
||||||
|
|
||||||
|
api.add_resource(ExternalKnowledgeHitTestingApi, "/datasets/<uuid:dataset_id>/external-hit-testing")
|
||||||
|
api.add_resource(ExternalDatasetCreateApi, "/datasets/external")
|
||||||
|
api.add_resource(ExternalApiTemplateListApi, "/datasets/external-knowledge-api")
|
||||||
|
api.add_resource(ExternalApiTemplateApi, "/datasets/external-knowledge-api/<uuid:external_knowledge_api_id>")
|
||||||
|
api.add_resource(ExternalApiUseCheckApi, "/datasets/external-knowledge-api/<uuid:external_knowledge_api_id>/use-check")
|
||||||
|
# this api is only for internal test
|
||||||
|
api.add_resource(BedrockRetrievalApi, "/test/retrieval")
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
from libs.exception import BaseHTTPException
|
||||||
|
|
||||||
|
|
||||||
|
class UnsupportedFileTypeError(BaseHTTPException):
|
||||||
|
error_code = "unsupported_file_type"
|
||||||
|
description = "File type not allowed."
|
||||||
|
code = 415
|
||||||
@ -1,2 +1,2 @@
|
|||||||
class VariableError(Exception):
|
class VariableError(ValueError):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 230 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 205 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
@ -0,0 +1,173 @@
|
|||||||
|
## Predefined Model Integration
|
||||||
|
|
||||||
|
After completing the vendor integration, the next step is to integrate the models from the vendor.
|
||||||
|
|
||||||
|
First, we need to determine the type of model to be integrated and create the corresponding model type `module` under the respective vendor's directory.
|
||||||
|
|
||||||
|
Currently supported model types are:
|
||||||
|
|
||||||
|
- `llm` Text Generation Model
|
||||||
|
- `text_embedding` Text Embedding Model
|
||||||
|
- `rerank` Rerank Model
|
||||||
|
- `speech2text` Speech-to-Text
|
||||||
|
- `tts` Text-to-Speech
|
||||||
|
- `moderation` Moderation
|
||||||
|
|
||||||
|
Continuing with `Anthropic` as an example, `Anthropic` only supports LLM, so create a `module` named `llm` under `model_providers.anthropic`.
|
||||||
|
|
||||||
|
For predefined models, we first need to create a YAML file named after the model under the `llm` `module`, such as `claude-2.1.yaml`.
|
||||||
|
|
||||||
|
### Prepare Model YAML
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
model: claude-2.1 # Model identifier
|
||||||
|
# Display name of the model, which can be set to en_US English or zh_Hans Chinese. If zh_Hans is not set, it will default to en_US.
|
||||||
|
# This can also be omitted, in which case the model identifier will be used as the label
|
||||||
|
label:
|
||||||
|
en_US: claude-2.1
|
||||||
|
model_type: llm # Model type, claude-2.1 is an LLM
|
||||||
|
features: # Supported features, agent-thought supports Agent reasoning, vision supports image understanding
|
||||||
|
- agent-thought
|
||||||
|
model_properties: # Model properties
|
||||||
|
mode: chat # LLM mode, complete for text completion models, chat for conversation models
|
||||||
|
context_size: 200000 # Maximum context size
|
||||||
|
parameter_rules: # Parameter rules for the model call; only LLM requires this
|
||||||
|
- name: temperature # Parameter variable name
|
||||||
|
# Five default configuration templates are provided: temperature/top_p/max_tokens/presence_penalty/frequency_penalty
|
||||||
|
# The template variable name can be set directly in use_template, which will use the default configuration in entities.defaults.PARAMETER_RULE_TEMPLATE
|
||||||
|
# Additional configuration parameters will override the default configuration if set
|
||||||
|
use_template: temperature
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: top_k
|
||||||
|
label: # Display name of the parameter
|
||||||
|
zh_Hans: 取样数量
|
||||||
|
en_US: Top k
|
||||||
|
type: int # Parameter type, supports float/int/string/boolean
|
||||||
|
help: # Help information, describing the parameter's function
|
||||||
|
zh_Hans: 仅从每个后续标记的前 K 个选项中采样。
|
||||||
|
en_US: Only sample from the top K options for each subsequent token.
|
||||||
|
required: false # Whether the parameter is mandatory; can be omitted
|
||||||
|
- name: max_tokens_to_sample
|
||||||
|
use_template: max_tokens
|
||||||
|
default: 4096 # Default value of the parameter
|
||||||
|
min: 1 # Minimum value of the parameter, applicable to float/int only
|
||||||
|
max: 4096 # Maximum value of the parameter, applicable to float/int only
|
||||||
|
pricing: # Pricing information
|
||||||
|
input: '8.00' # Input unit price, i.e., prompt price
|
||||||
|
output: '24.00' # Output unit price, i.e., response content price
|
||||||
|
unit: '0.000001' # Price unit, meaning the above prices are per 100K
|
||||||
|
currency: USD # Price currency
|
||||||
|
```
|
||||||
|
|
||||||
|
It is recommended to prepare all model configurations before starting the implementation of the model code.
|
||||||
|
|
||||||
|
You can also refer to the YAML configuration information under the corresponding model type directories of other vendors in the `model_providers` directory. For the complete YAML rules, refer to: [Schema](schema.md#aimodelentity).
|
||||||
|
|
||||||
|
### Implement the Model Call Code
|
||||||
|
|
||||||
|
Next, create a Python file named `llm.py` under the `llm` `module` to write the implementation code.
|
||||||
|
|
||||||
|
Create an Anthropic LLM class named `AnthropicLargeLanguageModel` (or any other name), inheriting from the `__base.large_language_model.LargeLanguageModel` base class, and implement the following methods:
|
||||||
|
|
||||||
|
- LLM Call
|
||||||
|
|
||||||
|
Implement the core method for calling the LLM, supporting both streaming and synchronous responses.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def _invoke(self, model: str, credentials: dict,
|
||||||
|
prompt_messages: list[PromptMessage], model_parameters: dict,
|
||||||
|
tools: Optional[list[PromptMessageTool]] = None, stop: Optional[list[str]] = None,
|
||||||
|
stream: bool = True, user: Optional[str] = None) \
|
||||||
|
-> Union[LLMResult, Generator]:
|
||||||
|
"""
|
||||||
|
Invoke large language model
|
||||||
|
|
||||||
|
:param model: model name
|
||||||
|
:param credentials: model credentials
|
||||||
|
:param prompt_messages: prompt messages
|
||||||
|
:param model_parameters: model parameters
|
||||||
|
:param tools: tools for tool calling
|
||||||
|
:param stop: stop words
|
||||||
|
:param stream: is stream response
|
||||||
|
:param user: unique user id
|
||||||
|
:return: full response or stream response chunk generator result
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensure to use two functions for returning data, one for synchronous returns and the other for streaming returns, because Python identifies functions containing the `yield` keyword as generator functions, fixing the return type to `Generator`. Thus, synchronous and streaming returns need to be implemented separately, as shown below (note that the example uses simplified parameters, for actual implementation follow the above parameter list):
|
||||||
|
|
||||||
|
```python
|
||||||
|
def _invoke(self, stream: bool, **kwargs) \
|
||||||
|
-> Union[LLMResult, Generator]:
|
||||||
|
if stream:
|
||||||
|
return self._handle_stream_response(**kwargs)
|
||||||
|
return self._handle_sync_response(**kwargs)
|
||||||
|
|
||||||
|
def _handle_stream_response(self, **kwargs) -> Generator:
|
||||||
|
for chunk in response:
|
||||||
|
yield chunk
|
||||||
|
def _handle_sync_response(self, **kwargs) -> LLMResult:
|
||||||
|
return LLMResult(**response)
|
||||||
|
```
|
||||||
|
|
||||||
|
- Pre-compute Input Tokens
|
||||||
|
|
||||||
|
If the model does not provide an interface to precompute tokens, return 0 directly.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_num_tokens(self, model: str, credentials: dict, prompt_messages: list[PromptMessage],
|
||||||
|
tools: Optional[list[PromptMessageTool]] = None) -> int:
|
||||||
|
"""
|
||||||
|
Get number of tokens for given prompt messages
|
||||||
|
|
||||||
|
:param model: model name
|
||||||
|
:param credentials: model credentials
|
||||||
|
:param prompt_messages: prompt messages
|
||||||
|
:param tools: tools for tool calling
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
- Validate Model Credentials
|
||||||
|
|
||||||
|
Similar to vendor credential validation, but specific to a single model.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def validate_credentials(self, model: str, credentials: dict) -> None:
|
||||||
|
"""
|
||||||
|
Validate model credentials
|
||||||
|
|
||||||
|
:param model: model name
|
||||||
|
:param credentials: model credentials
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
- Map Invoke Errors
|
||||||
|
|
||||||
|
When a model call fails, map it to a specific `InvokeError` type as required by Runtime, allowing Dify to handle different errors accordingly.
|
||||||
|
|
||||||
|
Runtime Errors:
|
||||||
|
|
||||||
|
- `InvokeConnectionError` Connection error
|
||||||
|
|
||||||
|
- `InvokeServerUnavailableError` Service provider unavailable
|
||||||
|
- `InvokeRateLimitError` Rate limit reached
|
||||||
|
- `InvokeAuthorizationError` Authorization failed
|
||||||
|
- `InvokeBadRequestError` Parameter error
|
||||||
|
|
||||||
|
```python
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
For interface method explanations, see: [Interfaces](./interfaces.md). For detailed implementation, refer to: [llm.py](https://github.com/langgenius/dify-runtime/blob/main/lib/model_providers/anthropic/llm/llm.py).
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
model: ai21.jamba-1-5-large-v1:0
|
||||||
|
label:
|
||||||
|
en_US: Jamba 1.5 Large
|
||||||
|
model_type: llm
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 256000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 1
|
||||||
|
min: 0.0
|
||||||
|
max: 2.0
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 4096
|
||||||
|
min: 1
|
||||||
|
max: 4096
|
||||||
|
pricing:
|
||||||
|
input: '0.002'
|
||||||
|
output: '0.008'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
model: ai21.jamba-1-5-mini-v1:0
|
||||||
|
label:
|
||||||
|
en_US: Jamba 1.5 Mini
|
||||||
|
model_type: llm
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 256000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 1
|
||||||
|
min: 0.0
|
||||||
|
max: 2.0
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 4096
|
||||||
|
min: 1
|
||||||
|
max: 4096
|
||||||
|
pricing:
|
||||||
|
input: '0.0002'
|
||||||
|
output: '0.0004'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
model: us.meta.llama3-2-11b-instruct-v1:0
|
||||||
|
label:
|
||||||
|
en_US: US Meta Llama 3.2 11B Instruct
|
||||||
|
model_type: llm
|
||||||
|
features:
|
||||||
|
- vision
|
||||||
|
- tool-call
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 128000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 0.5
|
||||||
|
min: 0.0
|
||||||
|
max: 1
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 2048
|
||||||
|
pricing:
|
||||||
|
input: '0.00035'
|
||||||
|
output: '0.00035'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
model: us.meta.llama3-2-1b-instruct-v1:0
|
||||||
|
label:
|
||||||
|
en_US: US Meta Llama 3.2 1B Instruct
|
||||||
|
model_type: llm
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 128000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 0.5
|
||||||
|
min: 0.0
|
||||||
|
max: 1
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 2048
|
||||||
|
pricing:
|
||||||
|
input: '0.0001'
|
||||||
|
output: '0.0001'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
model: us.meta.llama3-2-3b-instruct-v1:0
|
||||||
|
label:
|
||||||
|
en_US: US Meta Llama 3.2 3B Instruct
|
||||||
|
model_type: llm
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 128000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 0.5
|
||||||
|
min: 0.0
|
||||||
|
max: 1
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 2048
|
||||||
|
pricing:
|
||||||
|
input: '0.00015'
|
||||||
|
output: '0.00015'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
model: us.meta.llama3-2-90b-instruct-v1:0
|
||||||
|
label:
|
||||||
|
en_US: US Meta Llama 3.2 90B Instruct
|
||||||
|
model_type: llm
|
||||||
|
features:
|
||||||
|
- tool-call
|
||||||
|
model_properties:
|
||||||
|
mode: completion
|
||||||
|
context_size: 128000
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
default: 0.5
|
||||||
|
min: 0.0
|
||||||
|
max: 1
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
default: 0.9
|
||||||
|
min: 0
|
||||||
|
max: 1
|
||||||
|
- name: max_gen_len
|
||||||
|
use_template: max_tokens
|
||||||
|
required: true
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 2048
|
||||||
|
pricing:
|
||||||
|
input: '0.002'
|
||||||
|
output: '0.002'
|
||||||
|
unit: '0.001'
|
||||||
|
currency: USD
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
- gemini-1.5-pro
|
||||||
|
- gemini-1.5-pro-latest
|
||||||
|
- gemini-1.5-pro-001
|
||||||
|
- gemini-1.5-pro-002
|
||||||
|
- gemini-1.5-pro-exp-0801
|
||||||
|
- gemini-1.5-pro-exp-0827
|
||||||
|
- gemini-1.5-flash
|
||||||
|
- gemini-1.5-flash-latest
|
||||||
|
- gemini-1.5-flash-001
|
||||||
|
- gemini-1.5-flash-002
|
||||||
|
- gemini-1.5-flash-exp-0827
|
||||||
|
- gemini-1.5-flash-8b-exp-0827
|
||||||
|
- gemini-1.5-flash-8b-exp-0924
|
||||||
|
- gemini-pro
|
||||||
|
- gemini-pro-vision
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
model: llama-guard-3-8b
|
||||||
|
label:
|
||||||
|
zh_Hans: Llama-Guard-3-8B
|
||||||
|
en_US: Llama-Guard-3-8B
|
||||||
|
model_type: llm
|
||||||
|
features:
|
||||||
|
- agent-thought
|
||||||
|
model_properties:
|
||||||
|
mode: chat
|
||||||
|
context_size: 8192
|
||||||
|
parameter_rules:
|
||||||
|
- name: temperature
|
||||||
|
use_template: temperature
|
||||||
|
- name: top_p
|
||||||
|
use_template: top_p
|
||||||
|
- name: max_tokens
|
||||||
|
use_template: max_tokens
|
||||||
|
default: 512
|
||||||
|
min: 1
|
||||||
|
max: 8192
|
||||||
|
pricing:
|
||||||
|
input: '0.20'
|
||||||
|
output: '0.20'
|
||||||
|
unit: '0.000001'
|
||||||
|
currency: USD
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue