Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28edbbac0b | ||
|
|
782abcecd8 | ||
|
|
4deb02fc2c | ||
|
|
f967180dc2 | ||
|
|
cead13cbc3 | ||
|
|
078c151065 | ||
|
|
17babca362 | ||
|
|
8efed8858c | ||
|
|
0d411a0b5a | ||
|
|
13f0c01f93 | ||
|
|
3c014f3ae5 | ||
|
|
e4c4490175 |
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- plugins/beta
|
||||
paths:
|
||||
- api/**
|
||||
- docker/**
|
||||
@@ -47,15 +48,9 @@ jobs:
|
||||
- name: Run Unit tests
|
||||
run: poetry run -C api bash dev/pytest/pytest_unit_tests.sh
|
||||
|
||||
- name: Run ModelRuntime
|
||||
run: poetry run -C api bash dev/pytest/pytest_model_runtime.sh
|
||||
|
||||
- name: Run dify config tests
|
||||
run: poetry run -C api python dev/pytest/pytest_config_tests.py
|
||||
|
||||
- name: Run Tool
|
||||
run: poetry run -C api bash dev/pytest/pytest_tools.sh
|
||||
|
||||
- name: Run mypy
|
||||
run: |
|
||||
pushd api
|
||||
|
||||
@@ -5,7 +5,7 @@ on:
|
||||
branches:
|
||||
- "main"
|
||||
- "deploy/dev"
|
||||
- "dev/plugin-deploy"
|
||||
- "plugins/beta"
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
@@ -140,16 +140,3 @@ jobs:
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env[matrix.image_name_env] }}:${{ steps.meta.outputs.version }}
|
||||
|
||||
- name: print context var
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: deploy pod in plugin env
|
||||
if: github.ref == 'refs/heads/dev/plugin-deploy'
|
||||
env:
|
||||
IMAGEHASH: ${{ github.sha }}
|
||||
APICMD: "${{ secrets.PLUGIN_CD_API_CURL }}"
|
||||
WEBCMD: "${{ secrets.PLUGIN_CD_WEB_CURL }}"
|
||||
run: |
|
||||
bash -c "${APICMD/yourNewVersion/$IMAGEHASH}"
|
||||
bash -c "${WEBCMD/yourNewVersion/$IMAGEHASH}"
|
||||
|
||||
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- plugins/beta
|
||||
paths:
|
||||
- api/migrations/**
|
||||
- .github/workflows/db-migration-test.yml
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: Deploy Plugin Dev
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Build and Push API & Web"]
|
||||
branches:
|
||||
- "dev/plugin-deploy"
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.event.workflow_run.conclusion == 'success'
|
||||
steps:
|
||||
- name: Deploy to server
|
||||
uses: appleboy/[email protected]
|
||||
with:
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
username: ${{ secrets.SSH_USER }}
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
script: "echo 123"
|
||||
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- plugins/beta
|
||||
|
||||
concurrency:
|
||||
group: style-${{ github.head_ref || github.run_id }}
|
||||
@@ -82,34 +83,6 @@ jobs:
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: pnpm run lint
|
||||
|
||||
docker-compose-template:
|
||||
name: Docker Compose Template
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v45
|
||||
with:
|
||||
files: |
|
||||
docker/generate_docker_compose
|
||||
docker/.env.example
|
||||
docker/docker-compose-template.yaml
|
||||
docker/docker-compose.yaml
|
||||
|
||||
- name: Generate Docker Compose
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: |
|
||||
cd docker
|
||||
./generate_docker_compose
|
||||
|
||||
- name: Check for changes
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
run: git diff --exit-code
|
||||
|
||||
superlinter:
|
||||
name: SuperLinter
|
||||
runs-on: ubuntu-latest
|
||||
@@ -134,7 +107,7 @@ jobs:
|
||||
if: steps.changed-files.outputs.any_changed == 'true'
|
||||
env:
|
||||
BASH_SEVERITY: warning
|
||||
DEFAULT_BRANCH: main
|
||||
DEFAULT_BRANCH: plugins/beta
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
IGNORE_GENERATED_FILES: true
|
||||
IGNORE_GITIGNORED_FILES: true
|
||||
|
||||
@@ -55,6 +55,7 @@ RUN apt-get update \
|
||||
&& echo "deb http://deb.debian.org/debian testing main" > /etc/apt/sources.list \
|
||||
&& apt-get update \
|
||||
# For Security
|
||||
&& apt-get install -y --no-install-recommends expat=2.6.4-1 libldap-2.5-0=2.5.19+dfsg-1 perl=5.40.0-8 libsqlite3-0=3.46.1-1 zlib1g=1:1.3.dfsg+really1.3.1-1+b1 \
|
||||
# install a chinese font to support the use of tools like matplotlib
|
||||
&& apt-get install -y fonts-noto-cjk \
|
||||
&& apt-get autoremove -y \
|
||||
|
||||
@@ -9,7 +9,7 @@ class PackagingInfo(BaseSettings):
|
||||
|
||||
CURRENT_VERSION: str = Field(
|
||||
description="Dify version",
|
||||
default="0.15.0",
|
||||
default="1.0.0-beta.1",
|
||||
)
|
||||
|
||||
COMMIT_SHA: str = Field(
|
||||
|
||||
@@ -384,6 +384,7 @@ class AdvancedChatAppGenerateTaskPipeline:
|
||||
task_id=self._application_generate_entity.task_id,
|
||||
workflow_node_execution=workflow_node_execution,
|
||||
)
|
||||
session.commit()
|
||||
|
||||
if node_finish_resp:
|
||||
yield node_finish_resp
|
||||
|
||||
@@ -386,7 +386,6 @@ class WorkflowBasedAppRunner(AppRunner):
|
||||
status=event.status,
|
||||
data=event.data,
|
||||
metadata=event.metadata,
|
||||
node_id=event.node_id,
|
||||
)
|
||||
)
|
||||
elif isinstance(event, ParallelBranchRunStartedEvent):
|
||||
|
||||
@@ -330,7 +330,6 @@ class QueueAgentLogEvent(AppQueueEvent):
|
||||
status: str
|
||||
data: Mapping[str, Any]
|
||||
metadata: Optional[Mapping[str, Any]] = None
|
||||
node_id: str
|
||||
|
||||
|
||||
class QueueNodeRetryEvent(QueueNodeStartedEvent):
|
||||
|
||||
@@ -717,7 +717,6 @@ class AgentLogStreamResponse(StreamResponse):
|
||||
status: str
|
||||
data: Mapping[str, Any]
|
||||
metadata: Optional[Mapping[str, Any]] = None
|
||||
node_id: str
|
||||
|
||||
event: StreamEvent = StreamEvent.AGENT_LOG
|
||||
data: Data
|
||||
|
||||
@@ -863,6 +863,5 @@ class WorkflowCycleManage:
|
||||
status=event.status,
|
||||
data=event.data,
|
||||
metadata=event.metadata,
|
||||
node_id=event.node_id,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -60,10 +60,12 @@ def make_request(method, url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
|
||||
if response.status_code not in STATUS_FORCELIST:
|
||||
return response
|
||||
else:
|
||||
logging.warning(f"Received status code {response.status_code} for URL {url} which is in the force list")
|
||||
logging.warning(
|
||||
f"Received status code {response.status_code} for URL {url} which is in the force list")
|
||||
|
||||
except httpx.RequestError as e:
|
||||
logging.warning(f"Request to URL {url} failed on attempt {retries + 1}: {e}")
|
||||
logging.warning(f"Request to URL {url} failed on attempt {
|
||||
retries + 1}: {e}")
|
||||
if max_retries == 0:
|
||||
raise
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ from extensions.ext_redis import redis_client
|
||||
from models.dataset import Dataset
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format="%(asctime)s - %(levelname)s - %(message)s")
|
||||
logging.getLogger("lindorm").setLevel(logging.WARN)
|
||||
|
||||
ROUTING_FIELD = "routing_field"
|
||||
@@ -134,7 +135,8 @@ class LindormVectorStore(BaseVector):
|
||||
self._client.delete(index=self._collection_name, id=id, params=params)
|
||||
self.refresh()
|
||||
else:
|
||||
logger.warning(f"DELETE BY ID: ID {id} does not exist in the index.")
|
||||
logger.warning(
|
||||
f"DELETE BY ID: ID {id} does not exist in the index.")
|
||||
|
||||
def delete(self) -> None:
|
||||
if self._using_ugc:
|
||||
@@ -145,7 +147,8 @@ class LindormVectorStore(BaseVector):
|
||||
self.refresh()
|
||||
else:
|
||||
if self._client.indices.exists(index=self._collection_name):
|
||||
self._client.indices.delete(index=self._collection_name, params={"timeout": 60})
|
||||
self._client.indices.delete(
|
||||
index=self._collection_name, params={"timeout": 60})
|
||||
logger.info("Delete index success")
|
||||
else:
|
||||
logger.warning(f"Index '{self._collection_name}' does not exist. No deletion performed.")
|
||||
@@ -168,13 +171,14 @@ class LindormVectorStore(BaseVector):
|
||||
raise ValueError("All elements in query_vector should be floats")
|
||||
|
||||
top_k = kwargs.get("top_k", 10)
|
||||
query = default_vector_search_query(query_vector=query_vector, k=top_k, **kwargs)
|
||||
query = default_vector_search_query(
|
||||
query_vector=query_vector, k=top_k, **kwargs)
|
||||
try:
|
||||
params = {}
|
||||
if self._using_ugc:
|
||||
params["routing"] = self._routing
|
||||
response = self._client.search(index=self._collection_name, body=query, params=params)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.exception(f"Error executing vector search, query: {query}")
|
||||
raise
|
||||
|
||||
@@ -220,7 +224,8 @@ class LindormVectorStore(BaseVector):
|
||||
routing=routing,
|
||||
routing_field=self._routing_field,
|
||||
)
|
||||
response = self._client.search(index=self._collection_name, body=full_text_query)
|
||||
response = self._client.search(
|
||||
index=self._collection_name, body=full_text_query)
|
||||
docs = []
|
||||
for hit in response["hits"]["hits"]:
|
||||
docs.append(
|
||||
@@ -238,7 +243,8 @@ class LindormVectorStore(BaseVector):
|
||||
with redis_client.lock(lock_name, timeout=20):
|
||||
collection_exist_cache_key = f"vector_indexing_{self._collection_name}"
|
||||
if redis_client.get(collection_exist_cache_key):
|
||||
logger.info(f"Collection {self._collection_name} already exists.")
|
||||
logger.info(
|
||||
f"Collection {self._collection_name} already exists.")
|
||||
return
|
||||
if self._client.indices.exists(index=self._collection_name):
|
||||
logger.info(f"{self._collection_name.lower()} already exists.")
|
||||
@@ -258,10 +264,13 @@ class LindormVectorStore(BaseVector):
|
||||
hnsw_ef_construction = kwargs.pop("hnsw_ef_construction", 500)
|
||||
ivfpq_m = kwargs.pop("ivfpq_m", dimension)
|
||||
nlist = kwargs.pop("nlist", 1000)
|
||||
centroids_use_hnsw = kwargs.pop("centroids_use_hnsw", True if nlist >= 5000 else False)
|
||||
centroids_use_hnsw = kwargs.pop(
|
||||
"centroids_use_hnsw", True if nlist >= 5000 else False)
|
||||
centroids_hnsw_m = kwargs.pop("centroids_hnsw_m", 24)
|
||||
centroids_hnsw_ef_construct = kwargs.pop("centroids_hnsw_ef_construct", 500)
|
||||
centroids_hnsw_ef_search = kwargs.pop("centroids_hnsw_ef_search", 100)
|
||||
centroids_hnsw_ef_construct = kwargs.pop(
|
||||
"centroids_hnsw_ef_construct", 500)
|
||||
centroids_hnsw_ef_search = kwargs.pop(
|
||||
"centroids_hnsw_ef_search", 100)
|
||||
mapping = default_text_mapping(
|
||||
dimension,
|
||||
method_name,
|
||||
@@ -281,7 +290,8 @@ class LindormVectorStore(BaseVector):
|
||||
using_ugc=self._using_ugc,
|
||||
**kwargs,
|
||||
)
|
||||
self._client.indices.create(index=self._collection_name.lower(), body=mapping)
|
||||
self._client.indices.create(
|
||||
index=self._collection_name.lower(), body=mapping)
|
||||
redis_client.set(collection_exist_cache_key, 1, ex=3600)
|
||||
# logger.info(f"create index success: {self._collection_name}")
|
||||
|
||||
@@ -386,7 +396,8 @@ def default_text_search_query(
|
||||
# build complex search_query when either of must/must_not/should/filter is specified
|
||||
if must:
|
||||
if not isinstance(must, list):
|
||||
raise RuntimeError(f"unexpected [must] clause with {type(filters)}")
|
||||
raise RuntimeError(
|
||||
f"unexpected [must] clause with {type(filters)}")
|
||||
if query_clause not in must:
|
||||
must.append(query_clause)
|
||||
else:
|
||||
@@ -396,19 +407,22 @@ def default_text_search_query(
|
||||
|
||||
if must_not:
|
||||
if not isinstance(must_not, list):
|
||||
raise RuntimeError(f"unexpected [must_not] clause with {type(filters)}")
|
||||
raise RuntimeError(
|
||||
f"unexpected [must_not] clause with {type(filters)}")
|
||||
boolean_query["must_not"] = must_not
|
||||
|
||||
if should:
|
||||
if not isinstance(should, list):
|
||||
raise RuntimeError(f"unexpected [should] clause with {type(filters)}")
|
||||
raise RuntimeError(
|
||||
f"unexpected [should] clause with {type(filters)}")
|
||||
boolean_query["should"] = should
|
||||
if minimum_should_match != 0:
|
||||
boolean_query["minimum_should_match"] = minimum_should_match
|
||||
|
||||
if filters:
|
||||
if not isinstance(filters, list):
|
||||
raise RuntimeError(f"unexpected [filter] clause with {type(filters)}")
|
||||
raise RuntimeError(
|
||||
f"unexpected [filter] clause with {type(filters)}")
|
||||
boolean_query["filter"] = filters
|
||||
|
||||
search_query = {"size": k, "query": {"bool": boolean_query}}
|
||||
|
||||
@@ -50,7 +50,7 @@ class WordExtractor(BaseExtractor):
|
||||
|
||||
self.web_path = self.file_path
|
||||
# TODO: use a better way to handle the file
|
||||
self.temp_file = tempfile.NamedTemporaryFile() # noqa: SIM115
|
||||
self.temp_file = tempfile.NamedTemporaryFile() # noqa SIM115
|
||||
self.temp_file.write(r.content)
|
||||
self.file_path = self.temp_file.name
|
||||
elif not os.path.isfile(self.file_path):
|
||||
|
||||
@@ -160,8 +160,8 @@ class ToolManager:
|
||||
"""
|
||||
get the tool runtime
|
||||
|
||||
:param provider_type: the type of the provider
|
||||
:param provider_name: the name of the provider
|
||||
:param provider_type: the type of the provider
|
||||
:param provider_name: the name of the provider
|
||||
:param tool_name: the name of the tool
|
||||
|
||||
:return: the tool
|
||||
|
||||
@@ -204,7 +204,6 @@ class AgentLogEvent(BaseAgentEvent):
|
||||
status: str = Field(..., description="status")
|
||||
data: Mapping[str, Any] = Field(..., description="data")
|
||||
metadata: Optional[Mapping[str, Any]] = Field(default=None, description="metadata")
|
||||
node_id: str = Field(..., description="agent node id")
|
||||
|
||||
|
||||
InNodeEvent = BaseNodeEvent | BaseParallelBranchEvent | BaseIterationEvent | BaseAgentEvent
|
||||
|
||||
@@ -338,7 +338,6 @@ class ToolNode(BaseNode[ToolNodeData]):
|
||||
data=message.message.data,
|
||||
label=message.message.label,
|
||||
metadata=message.message.metadata,
|
||||
node_id=self.node_id,
|
||||
)
|
||||
|
||||
# check if the agent log is already in the list
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy.orm import Mapped
|
||||
|
||||
from extensions.ext_database import db
|
||||
from models.base import Base
|
||||
|
||||
from .types import StringUUID
|
||||
|
||||
|
||||
class StagingAccountWhitelist(Base):
|
||||
__tablename__ = "staging_account_whitelists"
|
||||
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="staging_account_whitelist_pkey"),
|
||||
db.Index("account_email_idx", "email"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
email: Mapped[str] = db.Column(db.String(255), nullable=False)
|
||||
disabled: Mapped[bool] = db.Column(db.Boolean, nullable=False, server_default=db.text("false"))
|
||||
created_at: Mapped[datetime] = db.Column(
|
||||
db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)")
|
||||
)
|
||||
updated_at: Mapped[datetime] = db.Column(
|
||||
db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)")
|
||||
)
|
||||
@@ -33,7 +33,6 @@ from models.account import (
|
||||
TenantStatus,
|
||||
)
|
||||
from models.model import DifySetup
|
||||
from models.staging import StagingAccountWhitelist
|
||||
from services.billing_service import BillingService
|
||||
from services.errors.account import (
|
||||
AccountAlreadyInTenantError,
|
||||
@@ -348,9 +347,6 @@ class AccountService:
|
||||
|
||||
@staticmethod
|
||||
def login(account: Account, *, ip_address: Optional[str] = None) -> TokenPair:
|
||||
if not AccountService.verify_account_whitelist(account.email):
|
||||
raise ValueError("Account is not whitelisted")
|
||||
|
||||
if ip_address:
|
||||
AccountService.update_login_info(account=account, ip_address=ip_address)
|
||||
|
||||
@@ -382,9 +378,6 @@ class AccountService:
|
||||
if not account:
|
||||
raise ValueError("Invalid account")
|
||||
|
||||
if not AccountService.verify_account_whitelist(account.email):
|
||||
raise ValueError("Account is not whitelisted")
|
||||
|
||||
# Generate new access token and refresh token
|
||||
new_access_token = AccountService.get_account_jwt_token(account)
|
||||
new_refresh_token = _generate_refresh_token()
|
||||
@@ -394,16 +387,6 @@ class AccountService:
|
||||
|
||||
return TokenPair(access_token=new_access_token, refresh_token=new_refresh_token)
|
||||
|
||||
@staticmethod
|
||||
def verify_account_whitelist(email: str) -> bool:
|
||||
with Session(db.engine) as session:
|
||||
return (
|
||||
session.query(StagingAccountWhitelist)
|
||||
.filter(StagingAccountWhitelist.email == email, StagingAccountWhitelist.disabled == False)
|
||||
.first()
|
||||
is not None
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def load_logged_in_account(*, account_id: str):
|
||||
return AccountService.load_user(account_id)
|
||||
@@ -448,13 +431,9 @@ class AccountService:
|
||||
def send_email_code_login_email(
|
||||
cls, account: Optional[Account] = None, email: Optional[str] = None, language: Optional[str] = "en-US"
|
||||
):
|
||||
if email:
|
||||
if not AccountService.verify_account_whitelist(email):
|
||||
raise ValueError("Account is not whitelisted")
|
||||
elif account:
|
||||
if not AccountService.verify_account_whitelist(account.email):
|
||||
raise ValueError("Account is not whitelisted")
|
||||
|
||||
email = account.email if account else email
|
||||
if email is None:
|
||||
raise ValueError("Email must be provided.")
|
||||
if cls.email_code_login_rate_limiter.is_rate_limited(email):
|
||||
from controllers.console.auth.error import EmailCodeLoginRateLimitExceededError
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ class BuiltinToolManageService:
|
||||
include_set=dify_config.POSITION_TOOL_INCLUDES_SET, # type: ignore
|
||||
exclude_set=dify_config.POSITION_TOOL_EXCLUDES_SET, # type: ignore
|
||||
data=provider_controller,
|
||||
name_func=lambda x: x.entity.identity.name,
|
||||
name_func=lambda x: x.identity.name,
|
||||
):
|
||||
continue
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class ToolTransformService:
|
||||
@staticmethod
|
||||
def repack_provider(tenant_id: str, provider: Union[dict, ToolProviderApiEntity]):
|
||||
"""
|
||||
repack provider
|
||||
repack provider
|
||||
|
||||
:param provider: the provider dict
|
||||
"""
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from core.model_runtime.errors.validate import CredentialsValidateFailedError
|
||||
from core.model_runtime.model_providers.gpustack.speech2text.speech2text import GPUStackSpeech2TextModel
|
||||
|
||||
|
||||
def test_validate_credentials():
|
||||
model = GPUStackSpeech2TextModel()
|
||||
|
||||
with pytest.raises(CredentialsValidateFailedError):
|
||||
model.validate_credentials(
|
||||
model="faster-whisper-medium",
|
||||
credentials={
|
||||
"endpoint_url": "invalid_url",
|
||||
"api_key": "invalid_api_key",
|
||||
},
|
||||
)
|
||||
|
||||
model.validate_credentials(
|
||||
model="faster-whisper-medium",
|
||||
credentials={
|
||||
"endpoint_url": os.environ.get("GPUSTACK_SERVER_URL"),
|
||||
"api_key": os.environ.get("GPUSTACK_API_KEY"),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_invoke_model():
|
||||
model = GPUStackSpeech2TextModel()
|
||||
|
||||
# Get the directory of the current file
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Get assets directory
|
||||
assets_dir = os.path.join(os.path.dirname(current_dir), "assets")
|
||||
|
||||
# Construct the path to the audio file
|
||||
audio_file_path = os.path.join(assets_dir, "audio.mp3")
|
||||
|
||||
file = Path(audio_file_path).read_bytes()
|
||||
|
||||
result = model.invoke(
|
||||
model="faster-whisper-medium",
|
||||
credentials={
|
||||
"endpoint_url": os.environ.get("GPUSTACK_SERVER_URL"),
|
||||
"api_key": os.environ.get("GPUSTACK_API_KEY"),
|
||||
},
|
||||
file=file,
|
||||
)
|
||||
|
||||
assert isinstance(result, str)
|
||||
assert result == "1, 2, 3, 4, 5, 6, 7, 8, 9, 10"
|
||||
@@ -1,24 +0,0 @@
|
||||
import os
|
||||
|
||||
from core.model_runtime.model_providers.gpustack.tts.tts import GPUStackText2SpeechModel
|
||||
|
||||
|
||||
def test_invoke_model():
|
||||
model = GPUStackText2SpeechModel()
|
||||
|
||||
result = model.invoke(
|
||||
model="cosyvoice-300m-sft",
|
||||
tenant_id="test",
|
||||
credentials={
|
||||
"endpoint_url": os.environ.get("GPUSTACK_SERVER_URL"),
|
||||
"api_key": os.environ.get("GPUSTACK_API_KEY"),
|
||||
},
|
||||
content_text="Hello world",
|
||||
voice="Chinese Female",
|
||||
)
|
||||
|
||||
content = b""
|
||||
for chunk in result:
|
||||
content += chunk
|
||||
|
||||
assert content != b""
|
||||
@@ -2,6 +2,6 @@ from core.helper.marketplace import download_plugin_pkg
|
||||
|
||||
|
||||
def test_download_plugin_pkg():
|
||||
pkg = download_plugin_pkg("yeuoly/google:0.0.1@4ff79ee644987e5b744d9c5b7a735d459fe66f26b28724326a7834d7e459e708")
|
||||
pkg = download_plugin_pkg("langgenius/bing:0.0.1@e58735424d2104f208c2bd683c5142e0332045b425927067acf432b26f3d970b")
|
||||
assert pkg is not None
|
||||
assert len(pkg) > 0
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
from unittest.mock import MagicMock
|
||||
# from unittest.mock import MagicMock
|
||||
|
||||
from core.app.app_config.entities import ModelConfigEntity
|
||||
from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle
|
||||
from core.model_runtime.entities.message_entities import UserPromptMessage
|
||||
from core.model_runtime.entities.model_entities import AIModelEntity, ModelPropertyKey, ParameterRule
|
||||
from core.model_runtime.entities.provider_entities import ProviderEntity
|
||||
from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel
|
||||
from core.prompt.prompt_transform import PromptTransform
|
||||
# from core.app.app_config.entities import ModelConfigEntity
|
||||
# from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle
|
||||
# from core.model_runtime.entities.message_entities import UserPromptMessage
|
||||
# from core.model_runtime.entities.model_entities import AIModelEntity, ModelPropertyKey, ParameterRule
|
||||
# from core.model_runtime.entities.provider_entities import ProviderEntity
|
||||
# from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel
|
||||
# from core.prompt.prompt_transform import PromptTransform
|
||||
|
||||
|
||||
def test__calculate_rest_token():
|
||||
model_schema_mock = MagicMock(spec=AIModelEntity)
|
||||
parameter_rule_mock = MagicMock(spec=ParameterRule)
|
||||
parameter_rule_mock.name = "max_tokens"
|
||||
model_schema_mock.parameter_rules = [parameter_rule_mock]
|
||||
model_schema_mock.model_properties = {ModelPropertyKey.CONTEXT_SIZE: 62}
|
||||
# def test__calculate_rest_token():
|
||||
# model_schema_mock = MagicMock(spec=AIModelEntity)
|
||||
# parameter_rule_mock = MagicMock(spec=ParameterRule)
|
||||
# parameter_rule_mock.name = "max_tokens"
|
||||
# model_schema_mock.parameter_rules = [parameter_rule_mock]
|
||||
# model_schema_mock.model_properties = {ModelPropertyKey.CONTEXT_SIZE: 62}
|
||||
|
||||
large_language_model_mock = MagicMock(spec=LargeLanguageModel)
|
||||
large_language_model_mock.get_num_tokens.return_value = 6
|
||||
# large_language_model_mock = MagicMock(spec=LargeLanguageModel)
|
||||
# large_language_model_mock.get_num_tokens.return_value = 6
|
||||
|
||||
provider_mock = MagicMock(spec=ProviderEntity)
|
||||
provider_mock.provider = "openai"
|
||||
# provider_mock = MagicMock(spec=ProviderEntity)
|
||||
# provider_mock.provider = "openai"
|
||||
|
||||
provider_configuration_mock = MagicMock(spec=ProviderConfiguration)
|
||||
provider_configuration_mock.provider = provider_mock
|
||||
provider_configuration_mock.model_settings = None
|
||||
# provider_configuration_mock = MagicMock(spec=ProviderConfiguration)
|
||||
# provider_configuration_mock.provider = provider_mock
|
||||
# provider_configuration_mock.model_settings = None
|
||||
|
||||
provider_model_bundle_mock = MagicMock(spec=ProviderModelBundle)
|
||||
provider_model_bundle_mock.model_type_instance = large_language_model_mock
|
||||
provider_model_bundle_mock.configuration = provider_configuration_mock
|
||||
# provider_model_bundle_mock = MagicMock(spec=ProviderModelBundle)
|
||||
# provider_model_bundle_mock.model_type_instance = large_language_model_mock
|
||||
# provider_model_bundle_mock.configuration = provider_configuration_mock
|
||||
|
||||
model_config_mock = MagicMock(spec=ModelConfigEntity)
|
||||
model_config_mock.model = "gpt-4"
|
||||
model_config_mock.credentials = {}
|
||||
model_config_mock.parameters = {"max_tokens": 50}
|
||||
model_config_mock.model_schema = model_schema_mock
|
||||
model_config_mock.provider_model_bundle = provider_model_bundle_mock
|
||||
# model_config_mock = MagicMock(spec=ModelConfigEntity)
|
||||
# model_config_mock.model = "gpt-4"
|
||||
# model_config_mock.credentials = {}
|
||||
# model_config_mock.parameters = {"max_tokens": 50}
|
||||
# model_config_mock.model_schema = model_schema_mock
|
||||
# model_config_mock.provider_model_bundle = provider_model_bundle_mock
|
||||
|
||||
prompt_transform = PromptTransform()
|
||||
# prompt_transform = PromptTransform()
|
||||
|
||||
prompt_messages = [UserPromptMessage(content="Hello, how are you?")]
|
||||
rest_tokens = prompt_transform._calculate_rest_token(prompt_messages, model_config_mock)
|
||||
# prompt_messages = [UserPromptMessage(content="Hello, how are you?")]
|
||||
# rest_tokens = prompt_transform._calculate_rest_token(prompt_messages, model_config_mock)
|
||||
|
||||
# Validate based on the mock configuration and expected logic
|
||||
expected_rest_tokens = (
|
||||
model_schema_mock.model_properties[ModelPropertyKey.CONTEXT_SIZE]
|
||||
- model_config_mock.parameters["max_tokens"]
|
||||
- large_language_model_mock.get_num_tokens.return_value
|
||||
)
|
||||
assert rest_tokens == expected_rest_tokens
|
||||
assert rest_tokens == 6
|
||||
# # Validate based on the mock configuration and expected logic
|
||||
# expected_rest_tokens = (
|
||||
# model_schema_mock.model_properties[ModelPropertyKey.CONTEXT_SIZE]
|
||||
# - model_config_mock.parameters["max_tokens"]
|
||||
# - large_language_model_mock.get_num_tokens.return_value
|
||||
# )
|
||||
# assert rest_tokens == expected_rest_tokens
|
||||
# assert rest_tokens == 6
|
||||
|
||||
@@ -1,186 +1,190 @@
|
||||
from core.entities.provider_entities import ModelSettings
|
||||
from core.model_runtime.entities.model_entities import ModelType
|
||||
from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory
|
||||
from core.provider_manager import ProviderManager
|
||||
from models.provider import LoadBalancingModelConfig, ProviderModelSetting
|
||||
# from core.entities.provider_entities import ModelSettings
|
||||
# from core.model_runtime.entities.model_entities import ModelType
|
||||
# from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory
|
||||
# from core.provider_manager import ProviderManager
|
||||
# from models.provider import LoadBalancingModelConfig, ProviderModelSetting
|
||||
|
||||
|
||||
def test__to_model_settings(mocker):
|
||||
# Get all provider entities
|
||||
model_provider_factory = ModelProviderFactory("test_tenant")
|
||||
provider_entities = model_provider_factory.get_providers()
|
||||
# def test__to_model_settings(mocker):
|
||||
# # Get all provider entities
|
||||
# model_provider_factory = ModelProviderFactory("test_tenant")
|
||||
# provider_entities = model_provider_factory.get_providers()
|
||||
|
||||
provider_entity = None
|
||||
for provider in provider_entities:
|
||||
if provider.provider == "openai":
|
||||
provider_entity = provider
|
||||
# provider_entity = None
|
||||
# for provider in provider_entities:
|
||||
# if provider.provider == "openai":
|
||||
# provider_entity = provider
|
||||
|
||||
# Mocking the inputs
|
||||
provider_model_settings = [
|
||||
ProviderModelSetting(
|
||||
id="id",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
enabled=True,
|
||||
load_balancing_enabled=True,
|
||||
)
|
||||
]
|
||||
load_balancing_model_configs = [
|
||||
LoadBalancingModelConfig(
|
||||
id="id1",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
name="__inherit__",
|
||||
encrypted_config=None,
|
||||
enabled=True,
|
||||
),
|
||||
LoadBalancingModelConfig(
|
||||
id="id2",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
name="first",
|
||||
encrypted_config='{"openai_api_key": "fake_key"}',
|
||||
enabled=True,
|
||||
),
|
||||
]
|
||||
# # Mocking the inputs
|
||||
# provider_model_settings = [
|
||||
# ProviderModelSetting(
|
||||
# id="id",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# enabled=True,
|
||||
# load_balancing_enabled=True,
|
||||
# )
|
||||
# ]
|
||||
# load_balancing_model_configs = [
|
||||
# LoadBalancingModelConfig(
|
||||
# id="id1",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# name="__inherit__",
|
||||
# encrypted_config=None,
|
||||
# enabled=True,
|
||||
# ),
|
||||
# LoadBalancingModelConfig(
|
||||
# id="id2",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# name="first",
|
||||
# encrypted_config='{"openai_api_key": "fake_key"}',
|
||||
# enabled=True,
|
||||
# ),
|
||||
# ]
|
||||
|
||||
mocker.patch(
|
||||
"core.helper.model_provider_cache.ProviderCredentialsCache.get", return_value={"openai_api_key": "fake_key"}
|
||||
)
|
||||
# mocker.patch(
|
||||
# "core.helper.model_provider_cache.ProviderCredentialsCache.get", return_value={"openai_api_key": "fake_key"}
|
||||
# )
|
||||
|
||||
provider_manager = ProviderManager()
|
||||
# provider_manager = ProviderManager()
|
||||
|
||||
# Running the method
|
||||
result = provider_manager._to_model_settings(provider_entity, provider_model_settings, load_balancing_model_configs)
|
||||
# # Running the method
|
||||
# result = provider_manager._to_model_settings(provider_entity,
|
||||
# provider_model_settings, load_balancing_model_configs)
|
||||
|
||||
# Asserting that the result is as expected
|
||||
assert len(result) == 1
|
||||
assert isinstance(result[0], ModelSettings)
|
||||
assert result[0].model == "gpt-4"
|
||||
assert result[0].model_type == ModelType.LLM
|
||||
assert result[0].enabled is True
|
||||
assert len(result[0].load_balancing_configs) == 2
|
||||
assert result[0].load_balancing_configs[0].name == "__inherit__"
|
||||
assert result[0].load_balancing_configs[1].name == "first"
|
||||
# # Asserting that the result is as expected
|
||||
# assert len(result) == 1
|
||||
# assert isinstance(result[0], ModelSettings)
|
||||
# assert result[0].model == "gpt-4"
|
||||
# assert result[0].model_type == ModelType.LLM
|
||||
# assert result[0].enabled is True
|
||||
# assert len(result[0].load_balancing_configs) == 2
|
||||
# assert result[0].load_balancing_configs[0].name == "__inherit__"
|
||||
# assert result[0].load_balancing_configs[1].name == "first"
|
||||
|
||||
|
||||
def test__to_model_settings_only_one_lb(mocker):
|
||||
# Get all provider entities
|
||||
model_provider_factory = ModelProviderFactory("test_tenant")
|
||||
provider_entities = model_provider_factory.get_providers()
|
||||
# def test__to_model_settings_only_one_lb(mocker):
|
||||
# # Get all provider entities
|
||||
# model_provider_factory = ModelProviderFactory("test_tenant")
|
||||
# provider_entities = model_provider_factory.get_providers()
|
||||
|
||||
provider_entity = None
|
||||
for provider in provider_entities:
|
||||
if provider.provider == "openai":
|
||||
provider_entity = provider
|
||||
# provider_entity = None
|
||||
# for provider in provider_entities:
|
||||
# if provider.provider == "openai":
|
||||
# provider_entity = provider
|
||||
|
||||
# Mocking the inputs
|
||||
provider_model_settings = [
|
||||
ProviderModelSetting(
|
||||
id="id",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
enabled=True,
|
||||
load_balancing_enabled=True,
|
||||
)
|
||||
]
|
||||
load_balancing_model_configs = [
|
||||
LoadBalancingModelConfig(
|
||||
id="id1",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
name="__inherit__",
|
||||
encrypted_config=None,
|
||||
enabled=True,
|
||||
)
|
||||
]
|
||||
# # Mocking the inputs
|
||||
# provider_model_settings = [
|
||||
# ProviderModelSetting(
|
||||
# id="id",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# enabled=True,
|
||||
# load_balancing_enabled=True,
|
||||
# )
|
||||
# ]
|
||||
# load_balancing_model_configs = [
|
||||
# LoadBalancingModelConfig(
|
||||
# id="id1",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# name="__inherit__",
|
||||
# encrypted_config=None,
|
||||
# enabled=True,
|
||||
# )
|
||||
# ]
|
||||
|
||||
mocker.patch(
|
||||
"core.helper.model_provider_cache.ProviderCredentialsCache.get", return_value={"openai_api_key": "fake_key"}
|
||||
)
|
||||
# mocker.patch(
|
||||
# "core.helper.model_provider_cache.ProviderCredentialsCache.get", return_value={"openai_api_key": "fake_key"}
|
||||
# )
|
||||
|
||||
provider_manager = ProviderManager()
|
||||
# provider_manager = ProviderManager()
|
||||
|
||||
# Running the method
|
||||
result = provider_manager._to_model_settings(provider_entity, provider_model_settings, load_balancing_model_configs)
|
||||
# # Running the method
|
||||
# result = provider_manager._to_model_settings(
|
||||
# provider_entity, provider_model_settings, load_balancing_model_configs)
|
||||
|
||||
# Asserting that the result is as expected
|
||||
assert len(result) == 1
|
||||
assert isinstance(result[0], ModelSettings)
|
||||
assert result[0].model == "gpt-4"
|
||||
assert result[0].model_type == ModelType.LLM
|
||||
assert result[0].enabled is True
|
||||
assert len(result[0].load_balancing_configs) == 0
|
||||
# # Asserting that the result is as expected
|
||||
# assert len(result) == 1
|
||||
# assert isinstance(result[0], ModelSettings)
|
||||
# assert result[0].model == "gpt-4"
|
||||
# assert result[0].model_type == ModelType.LLM
|
||||
# assert result[0].enabled is True
|
||||
# assert len(result[0].load_balancing_configs) == 0
|
||||
|
||||
|
||||
def test__to_model_settings_lb_disabled(mocker):
|
||||
# Get all provider entities
|
||||
model_provider_factory = ModelProviderFactory("test_tenant")
|
||||
provider_entities = model_provider_factory.get_providers()
|
||||
# def test__to_model_settings_lb_disabled(mocker):
|
||||
# # Get all provider entities
|
||||
# model_provider_factory = ModelProviderFactory("test_tenant")
|
||||
# provider_entities = model_provider_factory.get_providers()
|
||||
|
||||
provider_entity = None
|
||||
for provider in provider_entities:
|
||||
if provider.provider == "openai":
|
||||
provider_entity = provider
|
||||
# provider_entity = None
|
||||
# for provider in provider_entities:
|
||||
# if provider.provider == "openai":
|
||||
# provider_entity = provider
|
||||
|
||||
# Mocking the inputs
|
||||
provider_model_settings = [
|
||||
ProviderModelSetting(
|
||||
id="id",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
enabled=True,
|
||||
load_balancing_enabled=False,
|
||||
)
|
||||
]
|
||||
load_balancing_model_configs = [
|
||||
LoadBalancingModelConfig(
|
||||
id="id1",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
name="__inherit__",
|
||||
encrypted_config=None,
|
||||
enabled=True,
|
||||
),
|
||||
LoadBalancingModelConfig(
|
||||
id="id2",
|
||||
tenant_id="tenant_id",
|
||||
provider_name="openai",
|
||||
model_name="gpt-4",
|
||||
model_type="text-generation",
|
||||
name="first",
|
||||
encrypted_config='{"openai_api_key": "fake_key"}',
|
||||
enabled=True,
|
||||
),
|
||||
]
|
||||
# # Mocking the inputs
|
||||
# provider_model_settings = [
|
||||
# ProviderModelSetting(
|
||||
# id="id",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# enabled=True,
|
||||
# load_balancing_enabled=False,
|
||||
# )
|
||||
# ]
|
||||
# load_balancing_model_configs = [
|
||||
# LoadBalancingModelConfig(
|
||||
# id="id1",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# name="__inherit__",
|
||||
# encrypted_config=None,
|
||||
# enabled=True,
|
||||
# ),
|
||||
# LoadBalancingModelConfig(
|
||||
# id="id2",
|
||||
# tenant_id="tenant_id",
|
||||
# provider_name="openai",
|
||||
# model_name="gpt-4",
|
||||
# model_type="text-generation",
|
||||
# name="first",
|
||||
# encrypted_config='{"openai_api_key": "fake_key"}',
|
||||
# enabled=True,
|
||||
# ),
|
||||
# ]
|
||||
|
||||
mocker.patch(
|
||||
"core.helper.model_provider_cache.ProviderCredentialsCache.get", return_value={"openai_api_key": "fake_key"}
|
||||
)
|
||||
# mocker.patch(
|
||||
# "core.helper.model_provider_cache.ProviderCredentialsCache.get",
|
||||
# return_value={"openai_api_key": "fake_key"}
|
||||
# )
|
||||
|
||||
provider_manager = ProviderManager()
|
||||
# provider_manager = ProviderManager()
|
||||
|
||||
# Running the method
|
||||
result = provider_manager._to_model_settings(provider_entity, provider_model_settings, load_balancing_model_configs)
|
||||
# # Running the method
|
||||
# result = provider_manager._to_model_settings(provider_entity,
|
||||
# provider_model_settings, load_balancing_model_configs)
|
||||
|
||||
# Asserting that the result is as expected
|
||||
assert len(result) == 1
|
||||
assert isinstance(result[0], ModelSettings)
|
||||
assert result[0].model == "gpt-4"
|
||||
assert result[0].model_type == ModelType.LLM
|
||||
assert result[0].enabled is True
|
||||
assert len(result[0].load_balancing_configs) == 0
|
||||
# # Asserting that the result is as expected
|
||||
# assert len(result) == 1
|
||||
# assert isinstance(result[0], ModelSettings)
|
||||
# assert result[0].model == "gpt-4"
|
||||
# assert result[0].model_type == ModelType.LLM
|
||||
# assert result[0].enabled is True
|
||||
# assert len(result[0].load_balancing_configs) == 0
|
||||
|
||||
@@ -3,24 +3,20 @@ from typing import Optional
|
||||
|
||||
import pytest
|
||||
|
||||
from configs import dify_config
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom, ModelConfigWithCredentialsEntity
|
||||
from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle
|
||||
from core.entities.provider_entities import CustomConfiguration, SystemConfiguration
|
||||
from core.file import File, FileTransferMethod, FileType
|
||||
from core.model_runtime.entities.common_entities import I18nObject
|
||||
from core.model_runtime.entities.message_entities import (
|
||||
AssistantPromptMessage,
|
||||
ImagePromptMessageContent,
|
||||
PromptMessage,
|
||||
PromptMessageRole,
|
||||
SystemPromptMessage,
|
||||
TextPromptMessageContent,
|
||||
UserPromptMessage,
|
||||
)
|
||||
from core.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelFeature, ModelType
|
||||
from core.model_runtime.entities.model_entities import AIModelEntity, FetchFrom, ModelType
|
||||
from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory
|
||||
from core.prompt.entities.advanced_prompt_entities import MemoryConfig
|
||||
from core.variables import ArrayAnySegment, ArrayFileSegment, NoneSegment
|
||||
from core.workflow.entities.variable_pool import VariablePool
|
||||
from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState
|
||||
@@ -38,7 +34,6 @@ from core.workflow.nodes.llm.node import LLMNode
|
||||
from models.enums import UserFrom
|
||||
from models.provider import ProviderType
|
||||
from models.workflow import WorkflowType
|
||||
from tests.unit_tests.core.workflow.nodes.llm.test_scenarios import LLMNodeTestScenario
|
||||
|
||||
|
||||
class MockTokenBufferMemory:
|
||||
@@ -112,22 +107,21 @@ def llm_node():
|
||||
@pytest.fixture
|
||||
def model_config():
|
||||
# Create actual provider and model type instances
|
||||
model_provider_factory = ModelProviderFactory()
|
||||
provider_instance = model_provider_factory.get_provider_instance("openai")
|
||||
model_type_instance = provider_instance.get_model_instance(ModelType.LLM)
|
||||
model_provider_factory = ModelProviderFactory(tenant_id="test")
|
||||
provider_instance = model_provider_factory.get_plugin_model_provider("openai")
|
||||
model_type_instance = model_provider_factory.get_model_type_instance("openai", ModelType.LLM)
|
||||
|
||||
# Create a ProviderModelBundle
|
||||
provider_model_bundle = ProviderModelBundle(
|
||||
configuration=ProviderConfiguration(
|
||||
tenant_id="1",
|
||||
provider=provider_instance.get_provider_schema(),
|
||||
provider=provider_instance,
|
||||
preferred_provider_type=ProviderType.CUSTOM,
|
||||
using_provider_type=ProviderType.CUSTOM,
|
||||
system_configuration=SystemConfiguration(enabled=False),
|
||||
custom_configuration=CustomConfiguration(provider=None),
|
||||
model_settings=[],
|
||||
),
|
||||
provider_instance=provider_instance,
|
||||
model_type_instance=model_type_instance,
|
||||
)
|
||||
|
||||
@@ -211,236 +205,240 @@ def test_fetch_files_with_non_existent_variable(llm_node):
|
||||
assert result == []
|
||||
|
||||
|
||||
def test_fetch_prompt_messages__vison_disabled(faker, llm_node, model_config):
|
||||
prompt_template = []
|
||||
llm_node.node_data.prompt_template = prompt_template
|
||||
# def test_fetch_prompt_messages__vison_disabled(faker, llm_node, model_config):
|
||||
# TODO: Add test
|
||||
# pass
|
||||
# prompt_template = []
|
||||
# llm_node.node_data.prompt_template = prompt_template
|
||||
|
||||
fake_vision_detail = faker.random_element(
|
||||
[ImagePromptMessageContent.DETAIL.HIGH, ImagePromptMessageContent.DETAIL.LOW]
|
||||
)
|
||||
fake_remote_url = faker.url()
|
||||
files = [
|
||||
File(
|
||||
id="1",
|
||||
tenant_id="test",
|
||||
type=FileType.IMAGE,
|
||||
filename="test1.jpg",
|
||||
transfer_method=FileTransferMethod.REMOTE_URL,
|
||||
remote_url=fake_remote_url,
|
||||
storage_key="",
|
||||
)
|
||||
]
|
||||
# fake_vision_detail = faker.random_element(
|
||||
# [ImagePromptMessageContent.DETAIL.HIGH, ImagePromptMessageContent.DETAIL.LOW]
|
||||
# )
|
||||
# fake_remote_url = faker.url()
|
||||
# files = [
|
||||
# File(
|
||||
# id="1",
|
||||
# tenant_id="test",
|
||||
# type=FileType.IMAGE,
|
||||
# filename="test1.jpg",
|
||||
# transfer_method=FileTransferMethod.REMOTE_URL,
|
||||
# remote_url=fake_remote_url,
|
||||
# storage_key="",
|
||||
# )
|
||||
# ]
|
||||
|
||||
fake_query = faker.sentence()
|
||||
# fake_query = faker.sentence()
|
||||
|
||||
prompt_messages, _ = llm_node._fetch_prompt_messages(
|
||||
sys_query=fake_query,
|
||||
sys_files=files,
|
||||
context=None,
|
||||
memory=None,
|
||||
model_config=model_config,
|
||||
prompt_template=prompt_template,
|
||||
memory_config=None,
|
||||
vision_enabled=False,
|
||||
vision_detail=fake_vision_detail,
|
||||
variable_pool=llm_node.graph_runtime_state.variable_pool,
|
||||
jinja2_variables=[],
|
||||
)
|
||||
# prompt_messages, _ = llm_node._fetch_prompt_messages(
|
||||
# sys_query=fake_query,
|
||||
# sys_files=files,
|
||||
# context=None,
|
||||
# memory=None,
|
||||
# model_config=model_config,
|
||||
# prompt_template=prompt_template,
|
||||
# memory_config=None,
|
||||
# vision_enabled=False,
|
||||
# vision_detail=fake_vision_detail,
|
||||
# variable_pool=llm_node.graph_runtime_state.variable_pool,
|
||||
# jinja2_variables=[],
|
||||
# )
|
||||
|
||||
assert prompt_messages == [UserPromptMessage(content=fake_query)]
|
||||
# assert prompt_messages == [UserPromptMessage(content=fake_query)]
|
||||
|
||||
|
||||
def test_fetch_prompt_messages__basic(faker, llm_node, model_config):
|
||||
# Setup dify config
|
||||
dify_config.MULTIMODAL_SEND_FORMAT = "url"
|
||||
# def test_fetch_prompt_messages__basic(faker, llm_node, model_config):
|
||||
# TODO: Add test
|
||||
# pass
|
||||
# Setup dify config
|
||||
# dify_config.MULTIMODAL_SEND_FORMAT = "url"
|
||||
|
||||
# Generate fake values for prompt template
|
||||
fake_assistant_prompt = faker.sentence()
|
||||
fake_query = faker.sentence()
|
||||
fake_context = faker.sentence()
|
||||
fake_window_size = faker.random_int(min=1, max=3)
|
||||
fake_vision_detail = faker.random_element(
|
||||
[ImagePromptMessageContent.DETAIL.HIGH, ImagePromptMessageContent.DETAIL.LOW]
|
||||
)
|
||||
fake_remote_url = faker.url()
|
||||
# # Generate fake values for prompt template
|
||||
# fake_assistant_prompt = faker.sentence()
|
||||
# fake_query = faker.sentence()
|
||||
# fake_context = faker.sentence()
|
||||
# fake_window_size = faker.random_int(min=1, max=3)
|
||||
# fake_vision_detail = faker.random_element(
|
||||
# [ImagePromptMessageContent.DETAIL.HIGH, ImagePromptMessageContent.DETAIL.LOW]
|
||||
# )
|
||||
# fake_remote_url = faker.url()
|
||||
|
||||
# Setup mock memory with history messages
|
||||
mock_history = [
|
||||
UserPromptMessage(content=faker.sentence()),
|
||||
AssistantPromptMessage(content=faker.sentence()),
|
||||
UserPromptMessage(content=faker.sentence()),
|
||||
AssistantPromptMessage(content=faker.sentence()),
|
||||
UserPromptMessage(content=faker.sentence()),
|
||||
AssistantPromptMessage(content=faker.sentence()),
|
||||
]
|
||||
# # Setup mock memory with history messages
|
||||
# mock_history = [
|
||||
# UserPromptMessage(content=faker.sentence()),
|
||||
# AssistantPromptMessage(content=faker.sentence()),
|
||||
# UserPromptMessage(content=faker.sentence()),
|
||||
# AssistantPromptMessage(content=faker.sentence()),
|
||||
# UserPromptMessage(content=faker.sentence()),
|
||||
# AssistantPromptMessage(content=faker.sentence()),
|
||||
# ]
|
||||
|
||||
# Setup memory configuration
|
||||
memory_config = MemoryConfig(
|
||||
role_prefix=MemoryConfig.RolePrefix(user="Human", assistant="Assistant"),
|
||||
window=MemoryConfig.WindowConfig(enabled=True, size=fake_window_size),
|
||||
query_prompt_template=None,
|
||||
)
|
||||
# # Setup memory configuration
|
||||
# memory_config = MemoryConfig(
|
||||
# role_prefix=MemoryConfig.RolePrefix(user="Human", assistant="Assistant"),
|
||||
# window=MemoryConfig.WindowConfig(enabled=True, size=fake_window_size),
|
||||
# query_prompt_template=None,
|
||||
# )
|
||||
|
||||
memory = MockTokenBufferMemory(history_messages=mock_history)
|
||||
# memory = MockTokenBufferMemory(history_messages=mock_history)
|
||||
|
||||
# Test scenarios covering different file input combinations
|
||||
test_scenarios = [
|
||||
LLMNodeTestScenario(
|
||||
description="No files",
|
||||
sys_query=fake_query,
|
||||
sys_files=[],
|
||||
features=[],
|
||||
vision_enabled=False,
|
||||
vision_detail=None,
|
||||
window_size=fake_window_size,
|
||||
prompt_template=[
|
||||
LLMNodeChatModelMessage(
|
||||
text=fake_context,
|
||||
role=PromptMessageRole.SYSTEM,
|
||||
edition_type="basic",
|
||||
),
|
||||
LLMNodeChatModelMessage(
|
||||
text="{#context#}",
|
||||
role=PromptMessageRole.USER,
|
||||
edition_type="basic",
|
||||
),
|
||||
LLMNodeChatModelMessage(
|
||||
text=fake_assistant_prompt,
|
||||
role=PromptMessageRole.ASSISTANT,
|
||||
edition_type="basic",
|
||||
),
|
||||
],
|
||||
expected_messages=[
|
||||
SystemPromptMessage(content=fake_context),
|
||||
UserPromptMessage(content=fake_context),
|
||||
AssistantPromptMessage(content=fake_assistant_prompt),
|
||||
]
|
||||
+ mock_history[fake_window_size * -2 :]
|
||||
+ [
|
||||
UserPromptMessage(content=fake_query),
|
||||
],
|
||||
),
|
||||
LLMNodeTestScenario(
|
||||
description="User files",
|
||||
sys_query=fake_query,
|
||||
sys_files=[
|
||||
File(
|
||||
tenant_id="test",
|
||||
type=FileType.IMAGE,
|
||||
filename="test1.jpg",
|
||||
transfer_method=FileTransferMethod.REMOTE_URL,
|
||||
remote_url=fake_remote_url,
|
||||
extension=".jpg",
|
||||
mime_type="image/jpg",
|
||||
storage_key="",
|
||||
)
|
||||
],
|
||||
vision_enabled=True,
|
||||
vision_detail=fake_vision_detail,
|
||||
features=[ModelFeature.VISION],
|
||||
window_size=fake_window_size,
|
||||
prompt_template=[
|
||||
LLMNodeChatModelMessage(
|
||||
text=fake_context,
|
||||
role=PromptMessageRole.SYSTEM,
|
||||
edition_type="basic",
|
||||
),
|
||||
LLMNodeChatModelMessage(
|
||||
text="{#context#}",
|
||||
role=PromptMessageRole.USER,
|
||||
edition_type="basic",
|
||||
),
|
||||
LLMNodeChatModelMessage(
|
||||
text=fake_assistant_prompt,
|
||||
role=PromptMessageRole.ASSISTANT,
|
||||
edition_type="basic",
|
||||
),
|
||||
],
|
||||
expected_messages=[
|
||||
SystemPromptMessage(content=fake_context),
|
||||
UserPromptMessage(content=fake_context),
|
||||
AssistantPromptMessage(content=fake_assistant_prompt),
|
||||
]
|
||||
+ mock_history[fake_window_size * -2 :]
|
||||
+ [
|
||||
UserPromptMessage(
|
||||
content=[
|
||||
TextPromptMessageContent(data=fake_query),
|
||||
ImagePromptMessageContent(
|
||||
url=fake_remote_url, mime_type="image/jpg", format="jpg", detail=fake_vision_detail
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
),
|
||||
LLMNodeTestScenario(
|
||||
description="Prompt template with variable selector of File",
|
||||
sys_query=fake_query,
|
||||
sys_files=[],
|
||||
vision_enabled=False,
|
||||
vision_detail=fake_vision_detail,
|
||||
features=[ModelFeature.VISION],
|
||||
window_size=fake_window_size,
|
||||
prompt_template=[
|
||||
LLMNodeChatModelMessage(
|
||||
text="{{#input.image#}}",
|
||||
role=PromptMessageRole.USER,
|
||||
edition_type="basic",
|
||||
),
|
||||
],
|
||||
expected_messages=[
|
||||
UserPromptMessage(
|
||||
content=[
|
||||
ImagePromptMessageContent(
|
||||
url=fake_remote_url, mime_type="image/jpg", format="jpg", detail=fake_vision_detail
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
+ mock_history[fake_window_size * -2 :]
|
||||
+ [UserPromptMessage(content=fake_query)],
|
||||
file_variables={
|
||||
"input.image": File(
|
||||
tenant_id="test",
|
||||
type=FileType.IMAGE,
|
||||
filename="test1.jpg",
|
||||
transfer_method=FileTransferMethod.REMOTE_URL,
|
||||
remote_url=fake_remote_url,
|
||||
extension=".jpg",
|
||||
mime_type="image/jpg",
|
||||
storage_key="",
|
||||
)
|
||||
},
|
||||
),
|
||||
]
|
||||
# # Test scenarios covering different file input combinations
|
||||
# test_scenarios = [
|
||||
# LLMNodeTestScenario(
|
||||
# description="No files",
|
||||
# sys_query=fake_query,
|
||||
# sys_files=[],
|
||||
# features=[],
|
||||
# vision_enabled=False,
|
||||
# vision_detail=None,
|
||||
# window_size=fake_window_size,
|
||||
# prompt_template=[
|
||||
# LLMNodeChatModelMessage(
|
||||
# text=fake_context,
|
||||
# role=PromptMessageRole.SYSTEM,
|
||||
# edition_type="basic",
|
||||
# ),
|
||||
# LLMNodeChatModelMessage(
|
||||
# text="{#context#}",
|
||||
# role=PromptMessageRole.USER,
|
||||
# edition_type="basic",
|
||||
# ),
|
||||
# LLMNodeChatModelMessage(
|
||||
# text=fake_assistant_prompt,
|
||||
# role=PromptMessageRole.ASSISTANT,
|
||||
# edition_type="basic",
|
||||
# ),
|
||||
# ],
|
||||
# expected_messages=[
|
||||
# SystemPromptMessage(content=fake_context),
|
||||
# UserPromptMessage(content=fake_context),
|
||||
# AssistantPromptMessage(content=fake_assistant_prompt),
|
||||
# ]
|
||||
# + mock_history[fake_window_size * -2 :]
|
||||
# + [
|
||||
# UserPromptMessage(content=fake_query),
|
||||
# ],
|
||||
# ),
|
||||
# LLMNodeTestScenario(
|
||||
# description="User files",
|
||||
# sys_query=fake_query,
|
||||
# sys_files=[
|
||||
# File(
|
||||
# tenant_id="test",
|
||||
# type=FileType.IMAGE,
|
||||
# filename="test1.jpg",
|
||||
# transfer_method=FileTransferMethod.REMOTE_URL,
|
||||
# remote_url=fake_remote_url,
|
||||
# extension=".jpg",
|
||||
# mime_type="image/jpg",
|
||||
# storage_key="",
|
||||
# )
|
||||
# ],
|
||||
# vision_enabled=True,
|
||||
# vision_detail=fake_vision_detail,
|
||||
# features=[ModelFeature.VISION],
|
||||
# window_size=fake_window_size,
|
||||
# prompt_template=[
|
||||
# LLMNodeChatModelMessage(
|
||||
# text=fake_context,
|
||||
# role=PromptMessageRole.SYSTEM,
|
||||
# edition_type="basic",
|
||||
# ),
|
||||
# LLMNodeChatModelMessage(
|
||||
# text="{#context#}",
|
||||
# role=PromptMessageRole.USER,
|
||||
# edition_type="basic",
|
||||
# ),
|
||||
# LLMNodeChatModelMessage(
|
||||
# text=fake_assistant_prompt,
|
||||
# role=PromptMessageRole.ASSISTANT,
|
||||
# edition_type="basic",
|
||||
# ),
|
||||
# ],
|
||||
# expected_messages=[
|
||||
# SystemPromptMessage(content=fake_context),
|
||||
# UserPromptMessage(content=fake_context),
|
||||
# AssistantPromptMessage(content=fake_assistant_prompt),
|
||||
# ]
|
||||
# + mock_history[fake_window_size * -2 :]
|
||||
# + [
|
||||
# UserPromptMessage(
|
||||
# content=[
|
||||
# TextPromptMessageContent(data=fake_query),
|
||||
# ImagePromptMessageContent(
|
||||
# url=fake_remote_url, mime_type="image/jpg", format="jpg", detail=fake_vision_detail
|
||||
# ),
|
||||
# ]
|
||||
# ),
|
||||
# ],
|
||||
# ),
|
||||
# LLMNodeTestScenario(
|
||||
# description="Prompt template with variable selector of File",
|
||||
# sys_query=fake_query,
|
||||
# sys_files=[],
|
||||
# vision_enabled=False,
|
||||
# vision_detail=fake_vision_detail,
|
||||
# features=[ModelFeature.VISION],
|
||||
# window_size=fake_window_size,
|
||||
# prompt_template=[
|
||||
# LLMNodeChatModelMessage(
|
||||
# text="{{#input.image#}}",
|
||||
# role=PromptMessageRole.USER,
|
||||
# edition_type="basic",
|
||||
# ),
|
||||
# ],
|
||||
# expected_messages=[
|
||||
# UserPromptMessage(
|
||||
# content=[
|
||||
# ImagePromptMessageContent(
|
||||
# url=fake_remote_url, mime_type="image/jpg", format="jpg", detail=fake_vision_detail
|
||||
# ),
|
||||
# ]
|
||||
# ),
|
||||
# ]
|
||||
# + mock_history[fake_window_size * -2 :]
|
||||
# + [UserPromptMessage(content=fake_query)],
|
||||
# file_variables={
|
||||
# "input.image": File(
|
||||
# tenant_id="test",
|
||||
# type=FileType.IMAGE,
|
||||
# filename="test1.jpg",
|
||||
# transfer_method=FileTransferMethod.REMOTE_URL,
|
||||
# remote_url=fake_remote_url,
|
||||
# extension=".jpg",
|
||||
# mime_type="image/jpg",
|
||||
# storage_key="",
|
||||
# )
|
||||
# },
|
||||
# ),
|
||||
# ]
|
||||
|
||||
for scenario in test_scenarios:
|
||||
model_config.model_schema.features = scenario.features
|
||||
# for scenario in test_scenarios:
|
||||
# model_config.model_schema.features = scenario.features
|
||||
|
||||
for k, v in scenario.file_variables.items():
|
||||
selector = k.split(".")
|
||||
llm_node.graph_runtime_state.variable_pool.add(selector, v)
|
||||
# for k, v in scenario.file_variables.items():
|
||||
# selector = k.split(".")
|
||||
# llm_node.graph_runtime_state.variable_pool.add(selector, v)
|
||||
|
||||
# Call the method under test
|
||||
prompt_messages, _ = llm_node._fetch_prompt_messages(
|
||||
sys_query=scenario.sys_query,
|
||||
sys_files=scenario.sys_files,
|
||||
context=fake_context,
|
||||
memory=memory,
|
||||
model_config=model_config,
|
||||
prompt_template=scenario.prompt_template,
|
||||
memory_config=memory_config,
|
||||
vision_enabled=scenario.vision_enabled,
|
||||
vision_detail=scenario.vision_detail,
|
||||
variable_pool=llm_node.graph_runtime_state.variable_pool,
|
||||
jinja2_variables=[],
|
||||
)
|
||||
# # Call the method under test
|
||||
# prompt_messages, _ = llm_node._fetch_prompt_messages(
|
||||
# sys_query=scenario.sys_query,
|
||||
# sys_files=scenario.sys_files,
|
||||
# context=fake_context,
|
||||
# memory=memory,
|
||||
# model_config=model_config,
|
||||
# prompt_template=scenario.prompt_template,
|
||||
# memory_config=memory_config,
|
||||
# vision_enabled=scenario.vision_enabled,
|
||||
# vision_detail=scenario.vision_detail,
|
||||
# variable_pool=llm_node.graph_runtime_state.variable_pool,
|
||||
# jinja2_variables=[],
|
||||
# )
|
||||
|
||||
# Verify the result
|
||||
assert len(prompt_messages) == len(scenario.expected_messages), f"Scenario failed: {scenario.description}"
|
||||
assert (
|
||||
prompt_messages == scenario.expected_messages
|
||||
), f"Message content mismatch in scenario: {scenario.description}"
|
||||
# # Verify the result
|
||||
# assert len(prompt_messages) == len(scenario.expected_messages), f"Scenario failed: {scenario.description}"
|
||||
# assert (
|
||||
# prompt_messages == scenario.expected_messages
|
||||
# ), f"Message content mismatch in scenario: {scenario.description}"
|
||||
|
||||
|
||||
def test_handle_list_messages_basic(llm_node):
|
||||
|
||||
@@ -126,7 +126,7 @@ class ContinueOnErrorTestHelper:
|
||||
},
|
||||
}
|
||||
if default_value:
|
||||
node["data"]["default_value"] = default_value
|
||||
node.node_data.default_value = default_value
|
||||
return node
|
||||
|
||||
@staticmethod
|
||||
@@ -331,55 +331,55 @@ def test_http_node_fail_branch_continue_on_error():
|
||||
assert sum(1 for e in events if isinstance(e, NodeRunStreamChunkEvent)) == 1
|
||||
|
||||
|
||||
def test_tool_node_default_value_continue_on_error():
|
||||
"""Test tool node with default value error strategy"""
|
||||
graph_config = {
|
||||
"edges": DEFAULT_VALUE_EDGE,
|
||||
"nodes": [
|
||||
{"data": {"title": "start", "type": "start", "variables": []}, "id": "start"},
|
||||
{"data": {"title": "answer", "type": "answer", "answer": "{{#node.result#}}"}, "id": "answer"},
|
||||
ContinueOnErrorTestHelper.get_tool_node(
|
||||
"default-value", [{"key": "result", "type": "string", "value": "default tool result"}]
|
||||
),
|
||||
],
|
||||
}
|
||||
# def test_tool_node_default_value_continue_on_error():
|
||||
# """Test tool node with default value error strategy"""
|
||||
# graph_config = {
|
||||
# "edges": DEFAULT_VALUE_EDGE,
|
||||
# "nodes": [
|
||||
# {"data": {"title": "start", "type": "start", "variables": []}, "id": "start"},
|
||||
# {"data": {"title": "answer", "type": "answer", "answer": "{{#node.result#}}"}, "id": "answer"},
|
||||
# ContinueOnErrorTestHelper.get_tool_node(
|
||||
# "default-value", [{"key": "result", "type": "string", "value": "default tool result"}]
|
||||
# ),
|
||||
# ],
|
||||
# }
|
||||
|
||||
graph_engine = ContinueOnErrorTestHelper.create_test_graph_engine(graph_config)
|
||||
events = list(graph_engine.run())
|
||||
# graph_engine = ContinueOnErrorTestHelper.create_test_graph_engine(graph_config)
|
||||
# events = list(graph_engine.run())
|
||||
|
||||
assert any(isinstance(e, NodeRunExceptionEvent) for e in events)
|
||||
assert any(
|
||||
isinstance(e, GraphRunPartialSucceededEvent) and e.outputs == {"answer": "default tool result"} for e in events
|
||||
)
|
||||
assert sum(1 for e in events if isinstance(e, NodeRunStreamChunkEvent)) == 1
|
||||
# assert any(isinstance(e, NodeRunExceptionEvent) for e in events)
|
||||
# assert any(
|
||||
# isinstance(e, GraphRunPartialSucceededEvent) and e.outputs == {"answer": "default tool result"} for e in events # noqa: E501
|
||||
# )
|
||||
# assert sum(1 for e in events if isinstance(e, NodeRunStreamChunkEvent)) == 1
|
||||
|
||||
|
||||
def test_tool_node_fail_branch_continue_on_error():
|
||||
"""Test HTTP node with fail-branch error strategy"""
|
||||
graph_config = {
|
||||
"edges": FAIL_BRANCH_EDGES,
|
||||
"nodes": [
|
||||
{"data": {"title": "Start", "type": "start", "variables": []}, "id": "start"},
|
||||
{
|
||||
"data": {"title": "success", "type": "answer", "answer": "tool execute successful"},
|
||||
"id": "success",
|
||||
},
|
||||
{
|
||||
"data": {"title": "error", "type": "answer", "answer": "tool execute failed"},
|
||||
"id": "error",
|
||||
},
|
||||
ContinueOnErrorTestHelper.get_tool_node(),
|
||||
],
|
||||
}
|
||||
# def test_tool_node_fail_branch_continue_on_error():
|
||||
# """Test HTTP node with fail-branch error strategy"""
|
||||
# graph_config = {
|
||||
# "edges": FAIL_BRANCH_EDGES,
|
||||
# "nodes": [
|
||||
# {"data": {"title": "Start", "type": "start", "variables": []}, "id": "start"},
|
||||
# {
|
||||
# "data": {"title": "success", "type": "answer", "answer": "tool execute successful"},
|
||||
# "id": "success",
|
||||
# },
|
||||
# {
|
||||
# "data": {"title": "error", "type": "answer", "answer": "tool execute failed"},
|
||||
# "id": "error",
|
||||
# },
|
||||
# ContinueOnErrorTestHelper.get_tool_node(),
|
||||
# ],
|
||||
# }
|
||||
|
||||
graph_engine = ContinueOnErrorTestHelper.create_test_graph_engine(graph_config)
|
||||
events = list(graph_engine.run())
|
||||
# graph_engine = ContinueOnErrorTestHelper.create_test_graph_engine(graph_config)
|
||||
# events = list(graph_engine.run())
|
||||
|
||||
assert any(isinstance(e, NodeRunExceptionEvent) for e in events)
|
||||
assert any(
|
||||
isinstance(e, GraphRunPartialSucceededEvent) and e.outputs == {"answer": "tool execute failed"} for e in events
|
||||
)
|
||||
assert sum(1 for e in events if isinstance(e, NodeRunStreamChunkEvent)) == 1
|
||||
# assert any(isinstance(e, NodeRunExceptionEvent) for e in events)
|
||||
# assert any(
|
||||
# isinstance(e, GraphRunPartialSucceededEvent) and e.outputs == {"answer": "tool execute failed"} for e in events # noqa: E501
|
||||
# )
|
||||
# assert sum(1 for e in events if isinstance(e, NodeRunStreamChunkEvent)) == 1
|
||||
|
||||
|
||||
def test_llm_node_default_value_continue_on_error():
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3'
|
||||
services:
|
||||
# API service
|
||||
api:
|
||||
image: langgenius/dify-api:0.15.0
|
||||
image: langgenius/dify-api:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
# Startup mode, 'api' starts the API server.
|
||||
@@ -227,7 +227,7 @@ services:
|
||||
# worker service
|
||||
# The Celery worker for processing the queue.
|
||||
worker:
|
||||
image: langgenius/dify-api:0.15.0
|
||||
image: langgenius/dify-api:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
CONSOLE_WEB_URL: ''
|
||||
@@ -397,7 +397,7 @@ services:
|
||||
|
||||
# Frontend web application.
|
||||
web:
|
||||
image: langgenius/dify-web:0.15.0
|
||||
image: langgenius/dify-web:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
# The base URL of console application api server, refers to the Console base URL of WEB service if console domain is
|
||||
|
||||
+1
-1
@@ -937,7 +937,7 @@ TOP_K_MAX_VALUE=10
|
||||
# Plugin Daemon Configuration
|
||||
# ------------------------------
|
||||
|
||||
DB_PLUGIN_DATABASE=dify-plugin
|
||||
DB_PLUGIN_DATABASE=dify_plugin
|
||||
EXPOSE_PLUGIN_DAEMON_PORT=5002
|
||||
PLUGIN_DAEMON_PORT=5002
|
||||
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
|
||||
|
||||
@@ -2,13 +2,15 @@ x-shared-env: &shared-api-worker-env
|
||||
services:
|
||||
# API service
|
||||
api:
|
||||
image: langgenius/dify-api:dev-plugin-deploy
|
||||
image: langgenius/dify-api:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
# Use the shared environment variables.
|
||||
<<: *shared-api-worker-env
|
||||
# Startup mode, 'api' starts the API server.
|
||||
MODE: api
|
||||
CONSOLE_API_URL: ${CONSOLE_API_URL:-http://localhost:5001}
|
||||
CONSOLE_WEB_URL: ${CONSOLE_WEB_URL:-http://localhost:3000}
|
||||
SENTRY_DSN: ${API_SENTRY_DSN:-}
|
||||
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
|
||||
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
|
||||
@@ -16,8 +18,8 @@ services:
|
||||
PLUGIN_API_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002}
|
||||
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
|
||||
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
|
||||
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-true}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
|
||||
PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
|
||||
PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
|
||||
ENDPOINT_URL_TEMPLATE: ${ENDPOINT_URL_TEMPLATE:-http://localhost/e/{hook_id}}
|
||||
@@ -34,7 +36,7 @@ services:
|
||||
# worker service
|
||||
# The Celery worker for processing the queue.
|
||||
worker:
|
||||
image: langgenius/dify-api:dev-plugin-deploy
|
||||
image: langgenius/dify-api:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
# Use the shared environment variables.
|
||||
@@ -49,7 +51,7 @@ services:
|
||||
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
|
||||
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
|
||||
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
@@ -62,7 +64,7 @@ services:
|
||||
|
||||
# Frontend web application.
|
||||
web:
|
||||
image: langgenius/dify-web:dev-plugin-deploy
|
||||
image: langgenius/dify-web:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
|
||||
@@ -71,8 +73,8 @@ services:
|
||||
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
|
||||
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
|
||||
CSP_WHITELIST: ${CSP_WHITELIST:-}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
|
||||
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
|
||||
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}
|
||||
|
||||
# The postgres database.
|
||||
@@ -138,7 +140,7 @@ services:
|
||||
|
||||
# plugin daemon
|
||||
plugin_daemon:
|
||||
image: langgenius/dify-plugin-daemon:47c8bed17c22f67bd035d0979e696cb00ca45b16-local
|
||||
image: langgenius/dify-plugin-daemon:0.0.1-local
|
||||
restart: always
|
||||
environment:
|
||||
# Use the shared environment variables.
|
||||
|
||||
@@ -66,7 +66,7 @@ services:
|
||||
|
||||
# plugin daemon
|
||||
plugin_daemon:
|
||||
image: langgenius/dify-plugin-daemon:47c8bed17c22f67bd035d0979e696cb00ca45b16-local
|
||||
image: langgenius/dify-plugin-daemon:0.0.1-local
|
||||
restart: always
|
||||
environment:
|
||||
# Use the shared environment variables.
|
||||
|
||||
+12
-13
@@ -388,6 +388,7 @@ x-shared-env: &shared-api-worker-env
|
||||
CSP_WHITELIST: ${CSP_WHITELIST:-}
|
||||
CREATE_TIDB_SERVICE_JOB_ENABLED: ${CREATE_TIDB_SERVICE_JOB_ENABLED:-false}
|
||||
MAX_SUBMIT_COUNT: ${MAX_SUBMIT_COUNT:-100}
|
||||
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-10}
|
||||
DB_PLUGIN_DATABASE: ${DB_PLUGIN_DATABASE:-dify-plugin}
|
||||
EXPOSE_PLUGIN_DAEMON_PORT: ${EXPOSE_PLUGIN_DAEMON_PORT:-5002}
|
||||
PLUGIN_DAEMON_PORT: ${PLUGIN_DAEMON_PORT:-5002}
|
||||
@@ -404,18 +405,19 @@ x-shared-env: &shared-api-worker-env
|
||||
ENDPOINT_URL_TEMPLATE: ${ENDPOINT_URL_TEMPLATE:-http://localhost/e/{hook_id}}
|
||||
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-true}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev}
|
||||
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-10}
|
||||
|
||||
services:
|
||||
# API service
|
||||
api:
|
||||
image: langgenius/dify-api:dev-plugin-deploy
|
||||
image: langgenius/dify-api:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
# Use the shared environment variables.
|
||||
<<: *shared-api-worker-env
|
||||
# Startup mode, 'api' starts the API server.
|
||||
MODE: api
|
||||
CONSOLE_API_URL: ${CONSOLE_API_URL:-http://localhost:5001}
|
||||
CONSOLE_WEB_URL: ${CONSOLE_WEB_URL:-http://localhost:3000}
|
||||
SENTRY_DSN: ${API_SENTRY_DSN:-}
|
||||
SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
|
||||
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
|
||||
@@ -423,8 +425,8 @@ services:
|
||||
PLUGIN_API_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002}
|
||||
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
|
||||
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
|
||||
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-true}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
|
||||
PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
|
||||
PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
|
||||
ENDPOINT_URL_TEMPLATE: ${ENDPOINT_URL_TEMPLATE:-http://localhost/e/{hook_id}}
|
||||
@@ -441,7 +443,7 @@ services:
|
||||
# worker service
|
||||
# The Celery worker for processing the queue.
|
||||
worker:
|
||||
image: langgenius/dify-api:dev-plugin-deploy
|
||||
image: langgenius/dify-api:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
# Use the shared environment variables.
|
||||
@@ -456,7 +458,7 @@ services:
|
||||
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
|
||||
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
|
||||
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
@@ -469,19 +471,17 @@ services:
|
||||
|
||||
# Frontend web application.
|
||||
web:
|
||||
image: langgenius/dify-web:dev-plugin-deploy
|
||||
image: langgenius/dify-web:1.0.0-beta.1
|
||||
restart: always
|
||||
environment:
|
||||
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
|
||||
APP_API_URL: ${APP_API_URL:-}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-}
|
||||
MARKETPLACE_URL: ${MARKETPLACE_URL:-}
|
||||
SENTRY_DSN: ${WEB_SENTRY_DSN:-}
|
||||
NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
|
||||
TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
|
||||
CSP_WHITELIST: ${CSP_WHITELIST:-}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace-plugin.dify.dev}
|
||||
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
|
||||
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
|
||||
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}
|
||||
|
||||
# The postgres database.
|
||||
@@ -547,7 +547,7 @@ services:
|
||||
|
||||
# plugin daemon
|
||||
plugin_daemon:
|
||||
image: langgenius/dify-plugin-daemon:47c8bed17c22f67bd035d0979e696cb00ca45b16-local
|
||||
image: langgenius/dify-plugin-daemon:0.0.1-local
|
||||
restart: always
|
||||
environment:
|
||||
# Use the shared environment variables.
|
||||
@@ -557,7 +557,6 @@ services:
|
||||
SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
|
||||
MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
|
||||
PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
|
||||
DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
|
||||
DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
|
||||
DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
|
||||
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
|
||||
|
||||
@@ -92,7 +92,7 @@ EXPOSE_WEAVIATE_PORT=8080
|
||||
# Plugin Daemon Configuration
|
||||
# ------------------------------
|
||||
|
||||
DB_PLUGIN_DATABASE=dify-plugin
|
||||
DB_PLUGIN_DATABASE=dify_plugin
|
||||
EXPOSE_PLUGIN_DAEMON_PORT=5002
|
||||
PLUGIN_DAEMON_PORT=5002
|
||||
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react'
|
||||
import Main from '@/app/components/app/log-annotation'
|
||||
import { PageType } from '@/app/components/base/features/new-feature-panel/annotation-reply/type'
|
||||
|
||||
export type IProps = {
|
||||
export interface IProps {
|
||||
params: { appId: string }
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { logout } from '@/service/common'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
|
||||
export type IAppSelector = {
|
||||
export interface IAppSelector {
|
||||
isMobile: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ import useSWR from 'swr'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { fetchAnnotationsCount } from '@/service/log'
|
||||
|
||||
export type QueryParam = {
|
||||
export interface QueryParam {
|
||||
keyword?: string
|
||||
}
|
||||
|
||||
type IFilterProps = {
|
||||
interface IFilterProps {
|
||||
appId: string
|
||||
queryParams: QueryParam
|
||||
setQueryParams: (v: QueryParam) => void
|
||||
|
||||
@@ -9,7 +9,7 @@ import ActionButton from '@/app/components/base/action-button'
|
||||
import useTimestamp from '@/hooks/use-timestamp'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
list: AnnotationItem[]
|
||||
onRemove: (id: string) => void
|
||||
onView: (item: AnnotationItem) => void
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid
|
||||
import I18n from '@/context/i18n'
|
||||
import { LanguagesSupported } from '@/i18n/language'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
showWarning: boolean
|
||||
onShowEditModal: () => void
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
title: string
|
||||
children: JSX.Element
|
||||
|
||||
@@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
||||
|
||||
const TEXT_MAX_LENGTH = 256
|
||||
|
||||
export type IConfigModalProps = {
|
||||
export interface IConfigModalProps {
|
||||
isCreate?: boolean
|
||||
payload?: InputVar
|
||||
isShow: boolean
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { FC } from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import Input from '@/app/components/base/input'
|
||||
|
||||
export type IConfigStringProps = {
|
||||
export interface IConfigStringProps {
|
||||
value: number | undefined
|
||||
maxLength: number
|
||||
modelId: string
|
||||
|
||||
@@ -33,7 +33,7 @@ import { InputVarType } from '@/app/components/workflow/types'
|
||||
|
||||
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
|
||||
|
||||
type ExternalDataToolParams = {
|
||||
interface ExternalDataToolParams {
|
||||
key: string
|
||||
type: string
|
||||
index: number
|
||||
@@ -43,7 +43,7 @@ type ExternalDataToolParams = {
|
||||
icon_background?: string
|
||||
}
|
||||
|
||||
export type IConfigVarProps = {
|
||||
export interface IConfigVarProps {
|
||||
promptVariables: PromptVariable[]
|
||||
readonly?: boolean
|
||||
onPromptVariablesChange?: (promptVariables: PromptVariable[]) => void
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { InputVarType } from '@/app/components/workflow/types'
|
||||
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
||||
export type ISelectTypeItemProps = {
|
||||
export interface ISelectTypeItemProps {
|
||||
type: InputVarType
|
||||
selected: boolean
|
||||
onClick: () => void
|
||||
|
||||
@@ -38,7 +38,7 @@ import ModelName from '@/app/components/header/account-setting/model-provider-pa
|
||||
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
|
||||
export type IGetAutomaticResProps = {
|
||||
export interface IGetAutomaticResProps {
|
||||
mode: AppType
|
||||
model: Model
|
||||
isShow: boolean
|
||||
|
||||
@@ -12,7 +12,7 @@ import Divider from '@/app/components/base/divider'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import type { DataSet } from '@/models/datasets'
|
||||
import { type DataSet } from '@/models/datasets'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { updateDatasetSetting } from '@/service/datasets'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
@@ -33,7 +33,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
|
||||
import { fetchMembers } from '@/service/common'
|
||||
import type { Member } from '@/models/common'
|
||||
|
||||
type SettingsModalProps = {
|
||||
interface SettingsModalProps {
|
||||
currentDataset: DataSet
|
||||
onCancel: () => void
|
||||
onSave: (newDataset: DataSet) => void
|
||||
|
||||
@@ -31,7 +31,7 @@ import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
||||
|
||||
type ChatItemProps = {
|
||||
interface ChatItemProps {
|
||||
modelAndParameter: ModelAndParameter
|
||||
}
|
||||
const ChatItem: FC<ChatItemProps> = ({
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
|
||||
type TextGenerationItemProps = {
|
||||
interface TextGenerationItemProps {
|
||||
modelAndParameter: ModelAndParameter
|
||||
}
|
||||
const TextGenerationItem: FC<TextGenerationItemProps> = ({
|
||||
|
||||
@@ -27,10 +27,10 @@ import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||
|
||||
type DebugWithSingleModelProps = {
|
||||
interface DebugWithSingleModelProps {
|
||||
checkCanSend?: () => boolean
|
||||
}
|
||||
export type DebugWithSingleModelRefType = {
|
||||
export interface DebugWithSingleModelRefType {
|
||||
handleRestart: () => void
|
||||
}
|
||||
const DebugWithSingleModel = forwardRef<DebugWithSingleModelRefType, DebugWithSingleModelProps>(({
|
||||
|
||||
@@ -48,7 +48,7 @@ import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
|
||||
type IDebug = {
|
||||
interface IDebug {
|
||||
isAPIKeySet: boolean
|
||||
onSetting: () => void
|
||||
inputs: Inputs
|
||||
|
||||
@@ -23,7 +23,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type IPromptValuePanelProps = {
|
||||
export interface IPromptValuePanelProps {
|
||||
appType: AppType
|
||||
onSend?: () => void
|
||||
inputs: Inputs
|
||||
|
||||
@@ -21,13 +21,13 @@ import { useToastContext } from '@/app/components/base/toast'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
|
||||
const systemTypes = ['api']
|
||||
type ExternalDataToolModalProps = {
|
||||
interface ExternalDataToolModalProps {
|
||||
data: ExternalDataTool
|
||||
onCancel: () => void
|
||||
onSave: (externalDataTool: ExternalDataTool) => void
|
||||
onValidateBeforeSave?: (externalDataTool: ExternalDataTool) => boolean
|
||||
}
|
||||
type Provider = {
|
||||
interface Provider {
|
||||
key: string
|
||||
name: string
|
||||
form_schema?: CodeBasedExtensionItem['form_schema']
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useProviderContext } from '@/context/provider-context'
|
||||
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||
import type { AppIconType } from '@/types/app'
|
||||
|
||||
export type DuplicateAppModalProps = {
|
||||
export interface DuplicateAppModalProps {
|
||||
appName: string
|
||||
icon_type: AppIconType | null
|
||||
icon: string
|
||||
|
||||
@@ -2,7 +2,7 @@ import { create } from 'zustand'
|
||||
import type { App, AppSSO } from '@/types/app'
|
||||
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
||||
|
||||
type State = {
|
||||
interface State {
|
||||
appDetail?: App & Partial<AppSSO>
|
||||
appSidebarExpand: string
|
||||
currentLogItem?: IChatItem
|
||||
@@ -13,7 +13,7 @@ type State = {
|
||||
showAppConfigureFeaturesModal: boolean
|
||||
}
|
||||
|
||||
type Action = {
|
||||
interface Action {
|
||||
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
|
||||
setAppSiderbarExpand: (state: string) => void
|
||||
setCurrentLogItem: (item?: IChatItem) => void
|
||||
|
||||
@@ -25,7 +25,7 @@ import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/aler
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
|
||||
type SwitchAppModalProps = {
|
||||
interface SwitchAppModalProps {
|
||||
show: boolean
|
||||
appDetail: App
|
||||
onSuccess?: () => void
|
||||
|
||||
@@ -33,7 +33,7 @@ import { useChatContext } from '@/app/components/base/chat/chat/context'
|
||||
|
||||
const MAX_DEPTH = 3
|
||||
|
||||
export type IGenerationItemProps = {
|
||||
export interface IGenerationItemProps {
|
||||
isWorkflow?: boolean
|
||||
workflowProcessData?: WorkflowProcess
|
||||
className?: string
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import Run from '@/app/components/workflow/run'
|
||||
|
||||
type ILogDetail = {
|
||||
interface ILogDetail {
|
||||
runID: string
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { QueryParam } from './index'
|
||||
import Chip from '@/app/components/base/chip'
|
||||
import Input from '@/app/components/base/input'
|
||||
|
||||
type IFilterProps = {
|
||||
interface IFilterProps {
|
||||
queryParams: QueryParam
|
||||
setQueryParams: (v: QueryParam) => void
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export class AudioPlayerManager {
|
||||
private audioPlayers: AudioPlayer | null = null
|
||||
private msgId: string | undefined
|
||||
|
||||
// eslint-disable-next-line
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
||||
|
||||
type AudioBtnProps = {
|
||||
interface AudioBtnProps {
|
||||
id?: string
|
||||
voice?: string
|
||||
value?: string
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from 'react'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { memo } from 'react'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
|
||||
type InputProps = {
|
||||
interface InputProps {
|
||||
form: any
|
||||
value: string
|
||||
onChange: (variable: string, value: string) => void
|
||||
|
||||
@@ -16,7 +16,7 @@ import type {
|
||||
ConversationItem,
|
||||
} from '@/models/share'
|
||||
|
||||
export type ChatWithHistoryContextValue = {
|
||||
export interface ChatWithHistoryContextValue {
|
||||
appInfoError?: any
|
||||
appInfoLoading?: boolean
|
||||
appMeta?: AppMeta
|
||||
|
||||
@@ -20,7 +20,7 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import { checkOrSetAccessToken } from '@/app/components/share/utils'
|
||||
import AppUnavailable from '@/app/components/base/app-unavailable'
|
||||
|
||||
type ChatWithHistoryProps = {
|
||||
interface ChatWithHistoryProps {
|
||||
className?: string
|
||||
}
|
||||
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||
@@ -99,7 +99,7 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
|
||||
)
|
||||
}
|
||||
|
||||
export type ChatWithHistoryWrapProps = {
|
||||
export interface ChatWithHistoryWrapProps {
|
||||
installedAppInfo?: InstalledApp
|
||||
className?: string
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import Thought from '@/app/components/base/chat/chat/thought'
|
||||
import { FileList } from '@/app/components/base/file-uploader'
|
||||
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
|
||||
|
||||
type AgentContentProps = {
|
||||
interface AgentContentProps {
|
||||
item: ChatItem
|
||||
responding?: boolean
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { ChatItem } from '../../types'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type BasicContentProps = {
|
||||
interface BasicContentProps {
|
||||
item: ChatItem
|
||||
}
|
||||
const BasicContent: FC<BasicContentProps> = ({
|
||||
|
||||
@@ -23,7 +23,7 @@ import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows
|
||||
import cn from '@/utils/classnames'
|
||||
import { FileList } from '@/app/components/base/file-uploader'
|
||||
|
||||
type AnswerProps = {
|
||||
interface AnswerProps {
|
||||
item: ChatItem
|
||||
question: string
|
||||
index: number
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Log from '@/app/components/base/chat/chat/log'
|
||||
|
||||
type OperationProps = {
|
||||
interface OperationProps {
|
||||
item: ChatItem
|
||||
question: string
|
||||
index: number
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
} from '@/app/components/base/file-uploader/utils'
|
||||
|
||||
type GetAbortController = (abortController: AbortController) => void
|
||||
type SendCallback = {
|
||||
interface SendCallback {
|
||||
onGetConversationMessages?: (conversationId: string, getAbortController: GetAbortController) => Promise<any>
|
||||
onGetSuggestedQuestions?: (responseItemId: string, getAbortController: GetAbortController) => Promise<any>
|
||||
onConversationComplete?: (conversationId: string) => void
|
||||
|
||||
@@ -35,7 +35,7 @@ import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import type { AppData } from '@/models/share'
|
||||
|
||||
export type ChatProps = {
|
||||
export interface ChatProps {
|
||||
appData?: AppData
|
||||
chatList: ChatItem[]
|
||||
config?: ChatConfig
|
||||
|
||||
@@ -12,7 +12,7 @@ import { User } from '@/app/components/base/icons/src/public/avatar'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import { FileList } from '@/app/components/base/file-uploader'
|
||||
|
||||
type QuestionProps = {
|
||||
interface QuestionProps {
|
||||
item: ChatItem
|
||||
questionIcon?: ReactNode
|
||||
theme: Theme | null | undefined
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from 'react'
|
||||
import type { ThoughtItem, ToolInfoInThought } from '../type'
|
||||
import ToolDetail from '@/app/components/base/chat/chat/answer/tool-detail'
|
||||
|
||||
export type IThoughtProps = {
|
||||
export interface IThoughtProps {
|
||||
thought: ThoughtItem
|
||||
isFinished: boolean
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
import type { InputVarType } from '@/app/components/workflow/types'
|
||||
import type { FileResponse } from '@/types/workflow'
|
||||
|
||||
export type MessageMore = {
|
||||
export interface MessageMore {
|
||||
time: string
|
||||
tokens: number
|
||||
latency: number | string
|
||||
}
|
||||
|
||||
export type FeedbackType = {
|
||||
export interface FeedbackType {
|
||||
rating: MessageRating
|
||||
content?: string | null
|
||||
}
|
||||
@@ -26,7 +26,7 @@ export type SubmitAnnotationFunc = (
|
||||
|
||||
export type DisplayScene = 'web' | 'console'
|
||||
|
||||
export type ToolInfoInThought = {
|
||||
export interface ToolInfoInThought {
|
||||
name: string
|
||||
label: string
|
||||
input: string
|
||||
@@ -34,7 +34,7 @@ export type ToolInfoInThought = {
|
||||
isFinished: boolean
|
||||
}
|
||||
|
||||
export type ThoughtItem = {
|
||||
export interface ThoughtItem {
|
||||
id: string
|
||||
tool: string // plugin or dataset. May has multi.
|
||||
thought: string
|
||||
@@ -47,7 +47,7 @@ export type ThoughtItem = {
|
||||
message_files?: FileEntity[]
|
||||
}
|
||||
|
||||
export type CitationItem = {
|
||||
export interface CitationItem {
|
||||
content: string
|
||||
data_source_type: string
|
||||
dataset_name: string
|
||||
@@ -62,7 +62,7 @@ export type CitationItem = {
|
||||
word_count: number
|
||||
}
|
||||
|
||||
export type IChatItem = {
|
||||
export interface IChatItem {
|
||||
id: string
|
||||
content: string
|
||||
citation?: CitationItem[]
|
||||
@@ -104,7 +104,7 @@ export type IChatItem = {
|
||||
nextSibling?: string
|
||||
}
|
||||
|
||||
export type Metadata = {
|
||||
export interface Metadata {
|
||||
retriever_resources?: CitationItem[]
|
||||
annotation_reply: {
|
||||
id: string
|
||||
@@ -115,20 +115,20 @@ export type Metadata = {
|
||||
}
|
||||
}
|
||||
|
||||
export type MessageEnd = {
|
||||
export interface MessageEnd {
|
||||
id: string
|
||||
metadata: Metadata
|
||||
files?: FileResponse[]
|
||||
}
|
||||
|
||||
export type MessageReplace = {
|
||||
export interface MessageReplace {
|
||||
id: string
|
||||
task_id: string
|
||||
answer: string
|
||||
conversation_id: string
|
||||
}
|
||||
|
||||
export type AnnotationReply = {
|
||||
export interface AnnotationReply {
|
||||
id: string
|
||||
task_id: string
|
||||
answer: string
|
||||
@@ -137,7 +137,7 @@ export type AnnotationReply = {
|
||||
annotation_author_name: string
|
||||
}
|
||||
|
||||
export type InputForm = {
|
||||
export interface InputForm {
|
||||
type: InputVarType
|
||||
label: string
|
||||
variable: any
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { memo } from 'react'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
|
||||
type InputProps = {
|
||||
interface InputProps {
|
||||
form: any
|
||||
value: string
|
||||
onChange: (variable: string, value: string) => void
|
||||
|
||||
@@ -15,7 +15,7 @@ import type {
|
||||
ConversationItem,
|
||||
} from '@/models/share'
|
||||
|
||||
export type EmbeddedChatbotContextValue = {
|
||||
export interface EmbeddedChatbotContextValue {
|
||||
appInfoError?: any
|
||||
appInfoLoading?: boolean
|
||||
appMeta?: AppMeta
|
||||
|
||||
@@ -14,32 +14,32 @@ export type {
|
||||
PromptVariable,
|
||||
} from '@/models/debug'
|
||||
|
||||
export type UserInputForm = {
|
||||
export interface UserInputForm {
|
||||
default: string
|
||||
label: string
|
||||
required: boolean
|
||||
variable: string
|
||||
}
|
||||
|
||||
export type UserInputFormTextInput = {
|
||||
export interface UserInputFormTextInput {
|
||||
'text-input': UserInputForm & {
|
||||
max_length: number
|
||||
}
|
||||
}
|
||||
|
||||
export type UserInputFormSelect = {
|
||||
export interface UserInputFormSelect {
|
||||
select: UserInputForm & {
|
||||
options: string[]
|
||||
}
|
||||
}
|
||||
|
||||
export type UserInputFormParagraph = {
|
||||
export interface UserInputFormParagraph {
|
||||
paragraph: UserInputForm
|
||||
}
|
||||
|
||||
export type VisionConfig = VisionSettings
|
||||
|
||||
export type EnableType = {
|
||||
export interface EnableType {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export type ChatConfig = Omit<ModelConfig, 'model'> & {
|
||||
supportCitationHitInfo?: boolean
|
||||
}
|
||||
|
||||
export type WorkflowProcess = {
|
||||
export interface WorkflowProcess {
|
||||
status: WorkflowRunningStatus
|
||||
tracing: NodeTracing[]
|
||||
expand?: boolean // for UI
|
||||
@@ -73,10 +73,10 @@ export type OnSend = (message: string, files?: FileEntity[], last_answer?: ChatI
|
||||
|
||||
export type OnRegenerate = (chatItem: ChatItem) => void
|
||||
|
||||
export type Callback = {
|
||||
export interface Callback {
|
||||
onSuccess: () => void
|
||||
}
|
||||
|
||||
export type Feedback = {
|
||||
export interface Feedback {
|
||||
rating: 'like' | 'dislike' | null
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@ import { createStore } from 'zustand'
|
||||
import type { Features } from './types'
|
||||
import { Resolution, TransferMethod } from '@/types/app'
|
||||
|
||||
export type FeaturesModal = {
|
||||
export interface FeaturesModal {
|
||||
showFeaturesModal: boolean
|
||||
setShowFeaturesModal: (showFeaturesModal: boolean) => void
|
||||
}
|
||||
|
||||
export type FeaturesState = {
|
||||
export interface FeaturesState {
|
||||
features: Features
|
||||
}
|
||||
|
||||
export type FeaturesAction = {
|
||||
export interface FeaturesAction {
|
||||
setFeatures: (features: Features) => void
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Resolution, TransferMethod, TtsAutoPlay } from '@/types/app'
|
||||
import type { FileUploadConfigResponse } from '@/models/common'
|
||||
|
||||
export type EnabledOrDisabled = {
|
||||
export interface EnabledOrDisabled {
|
||||
enabled?: boolean
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export type FileUpload = {
|
||||
fileUploadConfig?: FileUploadConfigResponse
|
||||
} & EnabledOrDisabled
|
||||
|
||||
export type AnnotationReplyConfig = {
|
||||
export interface AnnotationReplyConfig {
|
||||
enabled: boolean
|
||||
id?: string
|
||||
score_threshold?: number
|
||||
@@ -64,7 +64,7 @@ export enum FeatureEnum {
|
||||
annotationReply = 'annotationReply',
|
||||
}
|
||||
|
||||
export type Features = {
|
||||
export interface Features {
|
||||
[FeatureEnum.moreLikeThis]?: MoreLikeThis
|
||||
[FeatureEnum.opening]?: OpeningStatement
|
||||
[FeatureEnum.suggested]?: SuggestedQuestionsAfterAnswer
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useHotkeys } from 'react-hotkeys-hook'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
|
||||
type ImagePreviewProps = {
|
||||
interface ImagePreviewProps {
|
||||
url: string
|
||||
title: string
|
||||
onCancel: () => void
|
||||
|
||||
@@ -9,7 +9,7 @@ import RemarkGfm from 'remark-gfm'
|
||||
import RehypeRaw from 'rehype-raw'
|
||||
import SyntaxHighlighter from 'react-syntax-highlighter'
|
||||
import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
|
||||
import { Component, createContext, memo, useContext, useMemo, useRef, useState } from 'react'
|
||||
import { Component, createContext, memo, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
import CopyBtn from '@/app/components/base/copy-btn'
|
||||
import SVGBtn from '@/app/components/base/svg'
|
||||
|
||||
@@ -7,7 +7,7 @@ import cn from '@/utils/classnames'
|
||||
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
||||
import Run from '@/app/components/workflow/run'
|
||||
|
||||
type MessageLogModalProps = {
|
||||
interface MessageLogModalProps {
|
||||
currentLogItem?: IChatItem
|
||||
defaultTab?: string
|
||||
width: number
|
||||
|
||||
@@ -12,7 +12,7 @@ type Props = {
|
||||
}
|
||||
|
||||
const maxTopK = (() => {
|
||||
const configValue = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-top-k-max-value') || '', 10)
|
||||
const configValue = parseInt(globalThis.document?.body?.getAttribute('data-public-top-k-max-value') || '', 10)
|
||||
if (configValue && !isNaN(configValue))
|
||||
return configValue
|
||||
return 10
|
||||
@@ -33,7 +33,7 @@ const TopKItem: FC<Props> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const handleParamChange = (key: string, value: number) => {
|
||||
let notOutRangeValue = Number.parseFloat(value.toFixed(2))
|
||||
let notOutRangeValue = parseFloat(value.toFixed(2))
|
||||
notOutRangeValue = Math.max(VALUE_LIMIT.min, notOutRangeValue)
|
||||
notOutRangeValue = Math.min(VALUE_LIMIT.max, notOutRangeValue)
|
||||
onChange(key, notOutRangeValue)
|
||||
|
||||
@@ -61,7 +61,7 @@ import {
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type PromptEditorProps = {
|
||||
export interface PromptEditorProps {
|
||||
instanceId?: string
|
||||
compact?: boolean
|
||||
className?: string
|
||||
|
||||
@@ -32,7 +32,7 @@ import type { PickerBlockMenuOption } from './menu'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
|
||||
type ComponentPickerProps = {
|
||||
interface ComponentPickerProps {
|
||||
triggerString: string
|
||||
contextBlock?: ContextBlockType
|
||||
queryBlock?: QueryBlockType
|
||||
|
||||
@@ -14,7 +14,7 @@ export type Item = {
|
||||
name: string
|
||||
} & Record<string, any>
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
order?: string
|
||||
value: number | string
|
||||
items: Item[]
|
||||
|
||||
@@ -11,60 +11,62 @@ type SwitchProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const Switch = React.forwardRef<HTMLButtonElement>(({ onChange, size = 'md', defaultValue = false, disabled = false, className }: SwitchProps, ref) => {
|
||||
const [enabled, setEnabled] = useState(defaultValue)
|
||||
useEffect(() => {
|
||||
setEnabled(defaultValue)
|
||||
}, [defaultValue])
|
||||
const wrapStyle = {
|
||||
lg: 'h-6 w-11',
|
||||
l: 'h-5 w-9',
|
||||
md: 'h-4 w-7',
|
||||
sm: 'h-3 w-5',
|
||||
}
|
||||
const Switch = React.forwardRef(
|
||||
({ onChange, size = 'md', defaultValue = false, disabled = false, className }: SwitchProps,
|
||||
propRef: React.Ref<HTMLButtonElement>) => {
|
||||
const [enabled, setEnabled] = useState(defaultValue)
|
||||
useEffect(() => {
|
||||
setEnabled(defaultValue)
|
||||
}, [defaultValue])
|
||||
const wrapStyle = {
|
||||
lg: 'h-6 w-11',
|
||||
l: 'h-5 w-9',
|
||||
md: 'h-4 w-7',
|
||||
sm: 'h-3 w-5',
|
||||
}
|
||||
|
||||
const circleStyle = {
|
||||
lg: 'h-5 w-5',
|
||||
l: 'h-4 w-4',
|
||||
md: 'h-3 w-3',
|
||||
sm: 'h-2 w-2',
|
||||
}
|
||||
const circleStyle = {
|
||||
lg: 'h-5 w-5',
|
||||
l: 'h-4 w-4',
|
||||
md: 'h-3 w-3',
|
||||
sm: 'h-2 w-2',
|
||||
}
|
||||
|
||||
const translateLeft = {
|
||||
lg: 'translate-x-5',
|
||||
l: 'translate-x-4',
|
||||
md: 'translate-x-3',
|
||||
sm: 'translate-x-2',
|
||||
}
|
||||
return (
|
||||
<OriginalSwitch
|
||||
ref={ref}
|
||||
checked={enabled}
|
||||
onChange={(checked: boolean) => {
|
||||
if (disabled)
|
||||
return
|
||||
setEnabled(checked)
|
||||
onChange?.(checked)
|
||||
}}
|
||||
className={classNames(
|
||||
wrapStyle[size],
|
||||
enabled ? 'bg-components-toggle-bg' : 'bg-components-toggle-bg-unchecked',
|
||||
'relative inline-flex flex-shrink-0 cursor-pointer rounded-[5px] border-2 border-transparent transition-colors duration-200 ease-in-out',
|
||||
disabled ? '!opacity-50 !cursor-not-allowed' : '',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
const translateLeft = {
|
||||
lg: 'translate-x-5',
|
||||
l: 'translate-x-4',
|
||||
md: 'translate-x-3',
|
||||
sm: 'translate-x-2',
|
||||
}
|
||||
return (
|
||||
<OriginalSwitch
|
||||
ref={propRef}
|
||||
checked={enabled}
|
||||
onChange={(checked: boolean) => {
|
||||
if (disabled)
|
||||
return
|
||||
setEnabled(checked)
|
||||
onChange?.(checked)
|
||||
}}
|
||||
className={classNames(
|
||||
circleStyle[size],
|
||||
enabled ? translateLeft[size] : 'translate-x-0',
|
||||
'pointer-events-none inline-block transform rounded-[3px] bg-components-toggle-knob shadow ring-0 transition duration-200 ease-in-out',
|
||||
wrapStyle[size],
|
||||
enabled ? 'bg-components-toggle-bg' : 'bg-components-toggle-bg-unchecked',
|
||||
'relative inline-flex flex-shrink-0 cursor-pointer rounded-[5px] border-2 border-transparent transition-colors duration-200 ease-in-out',
|
||||
disabled ? '!opacity-50 !cursor-not-allowed' : '',
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
</OriginalSwitch>
|
||||
)
|
||||
})
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={classNames(
|
||||
circleStyle[size],
|
||||
enabled ? translateLeft[size] : 'translate-x-0',
|
||||
'pointer-events-none inline-block transform rounded-[3px] bg-components-toggle-knob shadow ring-0 transition duration-200 ease-in-out',
|
||||
)}
|
||||
/>
|
||||
</OriginalSwitch>
|
||||
)
|
||||
})
|
||||
|
||||
Switch.displayName = 'Switch'
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Option = {
|
||||
interface Option {
|
||||
value: string
|
||||
text: string | JSX.Element
|
||||
}
|
||||
|
||||
type ItemProps = {
|
||||
interface ItemProps {
|
||||
className?: string
|
||||
isActive: boolean
|
||||
onClick: (v: string) => void
|
||||
@@ -38,7 +38,7 @@ const Item: FC<ItemProps> = ({
|
||||
)
|
||||
}
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
value: string
|
||||
onChange: (v: string) => void
|
||||
|
||||
@@ -7,7 +7,7 @@ import { RiAddLine, RiCloseLine } from '@remixicon/react'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
|
||||
type TagInputProps = {
|
||||
interface TagInputProps {
|
||||
items: string[]
|
||||
onChange: (items: string[]) => void
|
||||
disableRemove?: boolean
|
||||
|
||||
@@ -18,7 +18,7 @@ import type { Tag } from '@/app/components/base/tag-management/constant'
|
||||
|
||||
import { fetchTagList } from '@/service/tag'
|
||||
|
||||
type TagFilterProps = {
|
||||
interface TagFilterProps {
|
||||
type: 'knowledge' | 'app'
|
||||
value: string[]
|
||||
onChange: (v: string[]) => void
|
||||
|
||||
@@ -16,7 +16,7 @@ import Checkbox from '@/app/components/base/checkbox'
|
||||
import { bindTag, createTag, fetchTagList, unBindTag } from '@/service/tag'
|
||||
import { ToastContext } from '@/app/components/base/toast'
|
||||
|
||||
type TagSelectorProps = {
|
||||
interface TagSelectorProps {
|
||||
targetID: string
|
||||
isPopover?: boolean
|
||||
position?: 'bl' | 'br'
|
||||
|
||||
@@ -7,32 +7,32 @@ import type { ExternalDataTool } from '@/models/common'
|
||||
export type { VisionFile } from '@/types/app'
|
||||
export { TransferMethod } from '@/types/app'
|
||||
|
||||
export type UserInputForm = {
|
||||
export interface UserInputForm {
|
||||
default: string
|
||||
label: string
|
||||
required: boolean
|
||||
variable: string
|
||||
}
|
||||
|
||||
export type UserInputFormTextInput = {
|
||||
export interface UserInputFormTextInput {
|
||||
'text-input': UserInputForm & {
|
||||
max_length: number
|
||||
}
|
||||
}
|
||||
|
||||
export type UserInputFormSelect = {
|
||||
export interface UserInputFormSelect {
|
||||
select: UserInputForm & {
|
||||
options: string[]
|
||||
}
|
||||
}
|
||||
|
||||
export type UserInputFormParagraph = {
|
||||
export interface UserInputFormParagraph {
|
||||
paragraph: UserInputForm
|
||||
}
|
||||
|
||||
export type VisionConfig = VisionSettings
|
||||
|
||||
export type EnableType = {
|
||||
export interface EnableType {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ const Toast = ({
|
||||
'top-0',
|
||||
'right-0',
|
||||
)}>
|
||||
<div className={`absolute inset-0 opacity-40 -z-10 ${(type === 'success' && 'bg-toast-success-bg')
|
||||
<div className={`absolute inset-0 opacity-40 ${
|
||||
(type === 'success' && 'bg-toast-success-bg')
|
||||
|| (type === 'warning' && 'bg-toast-warning-bg')
|
||||
|| (type === 'error' && 'bg-toast-error-bg')
|
||||
|| (type === 'info' && 'bg-toast-info-bg')
|
||||
@@ -64,11 +65,8 @@ const Toast = ({
|
||||
{type === 'warning' && <RiAlertFill className={`${size === 'md' ? 'w-5 h-5' : 'w-4 h-4'} text-text-warning-secondary`} aria-hidden="true" />}
|
||||
{type === 'info' && <RiInformation2Fill className={`${size === 'md' ? 'w-5 h-5' : 'w-4 h-4'} text-text-accent`} aria-hidden="true" />}
|
||||
</div>
|
||||
<div className={`flex py-1 ${size === 'md' ? 'px-1' : 'px-0.5'} flex-col items-start gap-1 grow z-10`}>
|
||||
<div className='flex items-center gap-1'>
|
||||
<div className='text-text-primary system-sm-semibold'>{message}</div>
|
||||
{customComponent}
|
||||
</div>
|
||||
<div className={`flex py-1 ${size === 'md' ? 'px-1' : 'px-0.5'} flex-col items-start gap-1 grow`}>
|
||||
<div className='text-text-primary system-sm-semibold'>{message}</div>
|
||||
{children && <div className='text-text-secondary system-xs-regular'>
|
||||
{children}
|
||||
</div>
|
||||
@@ -132,7 +130,7 @@ Toast.notify = ({
|
||||
|
||||
root.render(
|
||||
<ToastContext.Provider value={{
|
||||
notify: () => { },
|
||||
notify: () => {},
|
||||
close: () => {
|
||||
if (holder) {
|
||||
root.unmount()
|
||||
|
||||
@@ -12,7 +12,7 @@ import Button from '@/app/components/base/button'
|
||||
import { ToastContext } from '@/app/components/base/toast'
|
||||
import { createEmptyDataset } from '@/service/datasets'
|
||||
|
||||
type IProps = {
|
||||
interface IProps {
|
||||
show: boolean
|
||||
onHide: () => void
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import Button from '@/app/components/base/button'
|
||||
import FloatRightContainer from '@/app/components/base/float-right-container'
|
||||
import RetrievalMethodConfig from '@/app/components/datasets/common/retrieval-method-config'
|
||||
import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/economical-retrieval-method-config'
|
||||
import type { RetrievalConfig } from '@/types/app'
|
||||
import { type RetrievalConfig } from '@/types/app'
|
||||
import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import type { NotionPage } from '@/models/common'
|
||||
@@ -205,7 +205,7 @@ const StepTwo = ({
|
||||
if (value === ChunkingMode.parentChild && indexType === IndexingType.ECONOMICAL)
|
||||
setIndexType(IndexingType.QUALIFIED)
|
||||
setDocForm(value)
|
||||
// eslint-disable-next-line
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
currentEstimateMutation.reset()
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ const StepTwo = ({
|
||||
score_threshold_enabled: false,
|
||||
score_threshold: 0.5,
|
||||
})
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [rerankDefaultModel, isRerankDefaultModelValid])
|
||||
|
||||
const getCreationParams = () => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import cn from '@/utils/classnames'
|
||||
import Popover from '@/app/components/base/popover'
|
||||
import { languages } from '@/i18n/language'
|
||||
|
||||
export type ILanguageSelectProps = {
|
||||
export interface ILanguageSelectProps {
|
||||
currentLanguage: string
|
||||
onSelect: (language: string) => void
|
||||
disabled?: boolean
|
||||
|
||||
@@ -5,7 +5,7 @@ import cn from '@/utils/classnames'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
isChecked: boolean
|
||||
onChange: (isChecked: boolean) => void
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
title: string
|
||||
errorMsg?: string
|
||||
|
||||
@@ -5,7 +5,7 @@ import Input from './input'
|
||||
import cn from '@/utils/classnames'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
className?: string
|
||||
label: string
|
||||
labelClassName?: string
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
value: string | number
|
||||
onChange: (value: string | number) => void
|
||||
placeholder?: string
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user