Compare commits

...

19 Commits
1.4.2 ... 1.4.3

Author SHA1 Message Date
809a0ab6bf chore: bump version to 1.4.3 (#21045)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2025-06-16 15:29:53 +08:00
51b63b2398 chore: rename workflow blocks (#21052) 2025-06-16 14:55:32 +08:00
59b89b9971 fix: update documentation links for various components to support localization (#21048) 2025-06-16 14:13:04 +08:00
ecd8f32cce Feat/add rag dev deploy (#21049)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-06-16 14:07:11 +08:00
909259da37 fix: delete some dead code using vulture (#20999)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2025-06-16 12:07:41 +08:00
366ddb05ae test: run vdb test of oceanbase with docker compose in CI tests (#20945) 2025-06-16 11:05:19 +08:00
d587480a3e fix(web): optimize conversation-panel Modal width adjustment logic (#21018) 2025-06-15 09:22:10 +02:00
765189d4f5 fix: correct description for edu coupon (#21020) 2025-06-15 09:21:28 +02:00
f6aa2498a3 document indexing not bound to a Session (#21015)
Co-authored-by: xuhaixing <xuhaixing@itiger.com>
2025-06-14 17:44:35 +02:00
f6641c0f41 docs: conv and user_id (#21004) 2025-06-13 15:07:30 +02:00
f4df759ba6 refactor: generalize method for getting doc link respecting locale and fix error link paths (#20801) 2025-06-13 10:58:43 +02:00
3a628bc671 chore: app info add author_name (#20973) 2025-06-13 10:17:35 +02:00
175571e740 fix(auth): Clear login rate limit after password reset (#20948) 2025-06-13 10:17:12 +02:00
8cb3ed5cc2 feat: add S3_USE_AWS env var to explicitly distinguish AWS S3 usage in plugin-daemon (#20923) 2025-06-13 15:05:55 +08:00
c05e47ebc0 refactor(sqlalchemy_workflow_execution_repository): Use the max funtion for getting next_sequence_number. (#20966) 2025-06-13 09:42:02 +08:00
b2ac11bc47 fix: markdown button can't send message (#20933) 2025-06-12 08:18:15 +02:00
af83120832 🐛 Fix(Gemini LLM): Support Gemini 0.2.x plugin on agent app (#20794)
Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com>
2025-06-12 00:49:38 +08:00
1e03c97663 fix(llm_node): missing parameters for structure outputs (#20915)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2025-06-11 18:56:07 +08:00
41e3ecc837 fix remote ip header CF-Connecting-IP (#20846) 2025-06-11 16:57:24 +08:00
94 changed files with 1354 additions and 1633 deletions

28
.github/workflows/deploy-rag-dev.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Deploy RAG Dev
permissions:
contents: read
on:
workflow_run:
workflows: ["Build and Push API & Web"]
branches:
- "deploy/rag-dev"
types:
- completed
jobs:
deploy:
runs-on: ubuntu-latest
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'deploy/rag-dev'
steps:
- name: Deploy to server
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ secrets.RAG_SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
${{ vars.SSH_SCRIPT || secrets.SSH_SCRIPT }}

View File

@ -10,6 +10,7 @@ yq eval '.services["elasticsearch"].ports += ["9200:9200"]' -i docker/docker-com
yq eval '.services.couchbase-server.ports += ["8091-8096:8091-8096"]' -i docker/docker-compose.yaml
yq eval '.services.couchbase-server.ports += ["11210:11210"]' -i docker/docker-compose.yaml
yq eval '.services.tidb.ports += ["4000:4000"]' -i docker/tidb/docker-compose.yaml
yq eval '.services.oceanbase.ports += ["2881:2881"]' -i docker/docker-compose.yaml
yq eval '.services.opengauss.ports += ["6600:6600"]' -i docker/docker-compose.yaml
echo "Ports exposed for sandbox, weaviate, tidb, qdrant, chroma, milvus, pgvector, pgvecto-rs, elasticsearch, couchbase, opengauss"

View File

@ -31,6 +31,13 @@ jobs:
with:
persist-credentials: false
- name: Free Disk Space
uses: endersonmenezes/free-disk-space@v2
with:
remove_dotnet: true
remove_haskell: true
remove_tool_cache: true
- name: Setup UV and Python
uses: ./.github/actions/setup-uv
with:
@ -59,7 +66,7 @@ jobs:
tidb
tiflash
- name: Set up Vector Stores (Weaviate, Qdrant, PGVector, Milvus, PgVecto-RS, Chroma, MyScale, ElasticSearch, Couchbase)
- name: Set up Vector Stores (Weaviate, Qdrant, PGVector, Milvus, PgVecto-RS, Chroma, MyScale, ElasticSearch, Couchbase, OceanBase)
uses: hoverkraft-tech/compose-action@v2.0.2
with:
compose-file: |
@ -75,9 +82,12 @@ jobs:
pgvector
chroma
elasticsearch
oceanbase
- name: Check TiDB Ready
run: uv run --project api python api/tests/integration_tests/vdb/tidb_vector/check_tiflash_ready.py
- name: Check VDB Ready (TiDB, Oceanbase)
run: |
uv run --project api python api/tests/integration_tests/vdb/tidb_vector/check_tiflash_ready.py
uv run --project api python api/tests/integration_tests/vdb/oceanbase/check_oceanbase_ready.py
- name: Test Vector Stores
run: uv run --project api bash dev/pytest/pytest_vdb.sh

View File

@ -27,7 +27,7 @@ from models.dataset import Dataset, DatasetCollectionBinding, DatasetMetadata, D
from models.dataset import Document as DatasetDocument
from models.model import Account, App, AppAnnotationSetting, AppMode, Conversation, MessageAnnotation
from models.provider import Provider, ProviderModel
from services.account_service import RegisterService, TenantService
from services.account_service import AccountService, RegisterService, TenantService
from services.clear_free_plan_tenant_expired_logs import ClearFreePlanTenantExpiredLogs
from services.plugin.data_migration import PluginDataMigration
from services.plugin.plugin_migration import PluginMigration
@ -68,6 +68,7 @@ def reset_password(email, new_password, password_confirm):
account.password = base64_password_hashed
account.password_salt = base64_salt
db.session.commit()
AccountService.reset_login_error_rate_limit(email)
click.echo(click.style("Password reset successfully.", fg="green"))

View File

@ -9,7 +9,7 @@ class PackagingInfo(BaseSettings):
CURRENT_VERSION: str = Field(
description="Dify version",
default="1.4.2",
default="1.4.3",
)
COMMIT_SHA: str = Field(

View File

@ -47,7 +47,13 @@ class AppInfoApi(Resource):
def get(self, app_model: App):
"""Get app information"""
tags = [tag.name for tag in app_model.tags]
return {"name": app_model.name, "description": app_model.description, "tags": tags, "mode": app_model.mode}
return {
"name": app_model.name,
"description": app_model.description,
"tags": tags,
"mode": app_model.mode,
"author_name": app_model.author_name,
}
api.add_resource(AppParameterApi, "/parameters")

View File

@ -1,3 +1,4 @@
import logging
import time
from collections.abc import Generator, Mapping, Sequence
from typing import TYPE_CHECKING, Any, Optional, Union
@ -33,6 +34,8 @@ from models.model import App, AppMode, Message, MessageAnnotation
if TYPE_CHECKING:
from core.file.models import File
_logger = logging.getLogger(__name__)
class AppRunner:
def get_pre_calculate_rest_tokens(
@ -298,7 +301,7 @@ class AppRunner:
)
def _handle_invoke_result_stream(
self, invoke_result: Generator, queue_manager: AppQueueManager, agent: bool
self, invoke_result: Generator[LLMResultChunk, None, None], queue_manager: AppQueueManager, agent: bool
) -> None:
"""
Handle invoke result
@ -317,18 +320,28 @@ class AppRunner:
else:
queue_manager.publish(QueueAgentMessageEvent(chunk=result), PublishFrom.APPLICATION_MANAGER)
text += result.delta.message.content
message = result.delta.message
if isinstance(message.content, str):
text += message.content
elif isinstance(message.content, list):
for content in message.content:
if not isinstance(content, str):
# TODO(QuantumGhost): Add multimodal output support for easy ui.
_logger.warning("received multimodal output, type=%s", type(content))
text += content.data
else:
text += content # failback to str
if not model:
model = result.model
if not prompt_messages:
prompt_messages = result.prompt_messages
prompt_messages = list(result.prompt_messages)
if result.delta.usage:
usage = result.delta.usage
if not usage:
if usage is None:
usage = LLMUsage.empty_usage()
llm_result = LLMResult(

View File

@ -48,6 +48,7 @@ from core.model_manager import ModelInstance
from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage
from core.model_runtime.entities.message_entities import (
AssistantPromptMessage,
TextPromptMessageContent,
)
from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel
from core.ops.entities.trace_entity import TraceTaskName
@ -309,6 +310,23 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline):
delta_text = chunk.delta.message.content
if delta_text is None:
continue
if isinstance(chunk.delta.message.content, list):
delta_text = ""
for content in chunk.delta.message.content:
logger.debug(
"The content type %s in LLM chunk delta message content.: %r", type(content), content
)
if isinstance(content, TextPromptMessageContent):
delta_text += content.data
elif isinstance(content, str):
delta_text += content # failback to str
else:
logger.warning(
"Unsupported content type %s in LLM chunk delta message content.: %r",
type(content),
content,
)
continue
if not self._task_state.llm_result.prompt_messages:
self._task_state.llm_result.prompt_messages = chunk.prompt_messages

View File

@ -80,6 +80,23 @@ class OceanBaseVector(BaseVector):
self.delete()
vals = []
params = self._client.perform_raw_text_sql("SHOW PARAMETERS LIKE '%ob_vector_memory_limit_percentage%'")
for row in params:
val = int(row[6])
vals.append(val)
if len(vals) == 0:
raise ValueError("ob_vector_memory_limit_percentage not found in parameters.")
if any(val == 0 for val in vals):
try:
self._client.perform_raw_text_sql("ALTER SYSTEM SET ob_vector_memory_limit_percentage = 30")
except Exception as e:
raise Exception(
"Failed to set ob_vector_memory_limit_percentage. "
+ "Maybe the database user has insufficient privilege.",
e,
)
cols = [
Column("id", String(36), primary_key=True, autoincrement=False),
Column("vector", VECTOR(self._vec_dim)),
@ -110,22 +127,6 @@ class OceanBaseVector(BaseVector):
+ "to support fulltext index and vector index in the same table",
e,
)
vals = []
params = self._client.perform_raw_text_sql("SHOW PARAMETERS LIKE '%ob_vector_memory_limit_percentage%'")
for row in params:
val = int(row[6])
vals.append(val)
if len(vals) == 0:
raise ValueError("ob_vector_memory_limit_percentage not found in parameters.")
if any(val == 0 for val in vals):
try:
self._client.perform_raw_text_sql("ALTER SYSTEM SET ob_vector_memory_limit_percentage = 30")
except Exception as e:
raise Exception(
"Failed to set ob_vector_memory_limit_percentage. "
+ "Maybe the database user has insufficient privilege.",
e,
)
redis_client.set(collection_exist_cache_key, 1, ex=3600)
def _check_hybrid_search_support(self) -> bool:

View File

@ -6,7 +6,7 @@ import json
import logging
from typing import Optional, Union
from sqlalchemy import select
from sqlalchemy import func, select
from sqlalchemy.engine import Engine
from sqlalchemy.orm import sessionmaker
@ -151,11 +151,11 @@ class SQLAlchemyWorkflowExecutionRepository(WorkflowExecutionRepository):
existing = session.scalar(select(WorkflowRun).where(WorkflowRun.id == domain_model.id_))
if not existing:
# For new records, get the next sequence number
stmt = select(WorkflowRun.sequence_number).where(
stmt = select(func.max(WorkflowRun.sequence_number)).where(
WorkflowRun.app_id == self._app_id,
WorkflowRun.tenant_id == self._tenant_id,
)
max_sequence = session.scalar(stmt.order_by(WorkflowRun.sequence_number.desc()))
max_sequence = session.scalar(stmt)
db_model.sequence_number = (max_sequence or 0) + 1
else:
# For updates, keep the existing sequence number

View File

@ -6,7 +6,6 @@ from pydantic import BaseModel, Field
from core.model_runtime.entities.llm_entities import LLMUsage
from core.rag.entities.citation_metadata import RetrievalSourceMetadata
from core.workflow.entities.node_entities import NodeRunResult
from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus
class RunCompletedEvent(BaseModel):
@ -39,11 +38,3 @@ class RunRetryEvent(BaseModel):
error: str = Field(..., description="error")
retry_index: int = Field(..., description="Retry attempt number")
start_at: datetime = Field(..., description="Retry start time")
class SingleStepRetryEvent(NodeRunResult):
"""Single step retry event"""
status: WorkflowNodeExecutionStatus = WorkflowNodeExecutionStatus.RETRY
elapsed_time: float = Field(..., description="elapsed time")

View File

@ -525,6 +525,8 @@ class LLMNode(BaseNode[LLMNodeData]):
# Set appropriate response format based on model capabilities
self._set_response_format(completion_params, model_schema.parameter_rules)
model_config_with_cred.parameters = completion_params
# NOTE(-LAN-): This line modify the `self.node_data.model`, which is used in `_invoke_llm()`.
node_data_model.completion_params = completion_params
return model, model_config_with_cred
def _fetch_prompt_messages(

View File

@ -39,10 +39,6 @@ from core.variables.variables import (
from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, ENVIRONMENT_VARIABLE_NODE_ID
class InvalidSelectorError(ValueError):
pass
class UnsupportedSegmentTypeError(Exception):
pass

View File

@ -185,7 +185,7 @@ def generate_string(n):
def extract_remote_ip(request) -> str:
if request.headers.get("CF-Connecting-IP"):
return cast(str, request.headers.get("Cf-Connecting-Ip"))
return cast(str, request.headers.get("CF-Connecting-IP"))
elif request.headers.getlist("X-Forwarded-For"):
return cast(str, request.headers.getlist("X-Forwarded-For")[0])
else:

View File

@ -4,7 +4,6 @@ from . import (
app_model_config,
audio,
base,
completion,
conversation,
dataset,
document,
@ -19,7 +18,6 @@ __all__ = [
"app_model_config",
"audio",
"base",
"completion",
"conversation",
"dataset",
"document",

View File

@ -55,7 +55,3 @@ class MemberNotInTenantError(BaseServiceError):
class RoleAlreadyAssignedError(BaseServiceError):
pass
class RateLimitExceededError(BaseServiceError):
pass

View File

@ -1,5 +0,0 @@
from services.errors.base import BaseServiceError
class CompletionStoppedError(BaseServiceError):
pass

View File

@ -30,11 +30,11 @@ def retry_document_indexing_task(dataset_id: str, document_ids: list[str]):
logging.info(click.style("Dataset not found: {}".format(dataset_id), fg="red"))
db.session.close()
return
tenant_id = dataset.tenant_id
for document_id in document_ids:
retry_indexing_cache_key = "document_{}_is_retried".format(document_id)
# check document limit
features = FeatureService.get_features(dataset.tenant_id)
features = FeatureService.get_features(tenant_id)
try:
if features.billing.enabled:
vector_space = features.vector_space

View File

@ -0,0 +1,49 @@
import time
import pymysql
def check_oceanbase_ready() -> bool:
try:
connection = pymysql.connect(
host="localhost",
port=2881,
user="root",
password="difyai123456",
)
affected_rows = connection.query("SELECT 1")
return affected_rows == 1
except Exception as e:
print(f"Oceanbase is not ready. Exception: {e}")
return False
finally:
if connection:
connection.close()
def main():
max_attempts = 50
retry_interval_seconds = 2
is_oceanbase_ready = False
for attempt in range(max_attempts):
try:
is_oceanbase_ready = check_oceanbase_ready()
except Exception as e:
print(f"Oceanbase is not ready. Exception: {e}")
is_oceanbase_ready = False
if is_oceanbase_ready:
break
else:
print(f"Attempt {attempt + 1} failed, retry in {retry_interval_seconds} seconds...")
time.sleep(retry_interval_seconds)
if is_oceanbase_ready:
print("Oceanbase is ready.")
else:
print(f"Oceanbase is not ready after {max_attempts} attempting checks.")
exit(1)
if __name__ == "__main__":
main()

View File

@ -1,15 +1,11 @@
from unittest.mock import MagicMock, patch
import pytest
from core.rag.datasource.vdb.oceanbase.oceanbase_vector import (
OceanBaseVector,
OceanBaseVectorConfig,
)
from tests.integration_tests.vdb.__mock.tcvectordb import setup_tcvectordb_mock
from tests.integration_tests.vdb.test_vector_store import (
AbstractVectorTest,
get_example_text,
setup_mock_redis,
)
@ -20,10 +16,11 @@ def oceanbase_vector():
"dify_test_collection",
config=OceanBaseVectorConfig(
host="127.0.0.1",
port="2881",
user="root@test",
port=2881,
user="root",
database="test",
password="test",
password="difyai123456",
enable_hybrid_search=True,
),
)
@ -33,39 +30,13 @@ class OceanBaseVectorTest(AbstractVectorTest):
super().__init__()
self.vector = vector
def search_by_vector(self):
hits_by_vector = self.vector.search_by_vector(query_vector=self.example_embedding)
assert len(hits_by_vector) == 0
def search_by_full_text(self):
hits_by_full_text = self.vector.search_by_full_text(query=get_example_text())
assert len(hits_by_full_text) == 0
def text_exists(self):
exist = self.vector.text_exists(self.example_doc_id)
assert exist == True
def get_ids_by_metadata_field(self):
ids = self.vector.get_ids_by_metadata_field(key="document_id", value=self.example_doc_id)
assert len(ids) == 0
@pytest.fixture
def setup_mock_oceanbase_client():
with patch("core.rag.datasource.vdb.oceanbase.oceanbase_vector.ObVecClient", new_callable=MagicMock) as mock_client:
yield mock_client
@pytest.fixture
def setup_mock_oceanbase_vector(oceanbase_vector):
with patch.object(oceanbase_vector, "_client"):
yield oceanbase_vector
assert len(ids) == 1
def test_oceanbase_vector(
setup_mock_redis,
setup_mock_oceanbase_client,
setup_mock_oceanbase_vector,
oceanbase_vector,
):
OceanBaseVectorTest(oceanbase_vector).run_all_tests()

View File

@ -1067,6 +1067,7 @@ PLUGIN_MEDIA_CACHE_PATH=assets
# Plugin oss bucket
PLUGIN_STORAGE_OSS_BUCKET=
# Plugin oss s3 credentials
PLUGIN_S3_USE_AWS=
PLUGIN_S3_USE_AWS_MANAGED_IAM=false
PLUGIN_S3_ENDPOINT=
PLUGIN_S3_USE_PATH_STYLE=false

View File

@ -2,7 +2,7 @@ x-shared-env: &shared-api-worker-env
services:
# API service
api:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -31,7 +31,7 @@ services:
# worker service
# The Celery worker for processing the queue.
worker:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -57,7 +57,7 @@ services:
# Frontend web application.
web:
image: langgenius/dify-web:1.4.2
image: langgenius/dify-web:1.4.3
restart: always
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
@ -168,6 +168,7 @@ services:
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
@ -434,7 +435,7 @@ services:
# OceanBase vector database
oceanbase:
image: oceanbase/oceanbase-ce:4.3.5.1-101000042025031818
image: oceanbase/oceanbase-ce:4.3.5-lts
container_name: oceanbase
profiles:
- oceanbase
@ -449,9 +450,7 @@ services:
OB_TENANT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
OB_SERVER_IP: 127.0.0.1
MODE: MINI
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
MODE: mini
# Oracle vector database
oracle:

View File

@ -104,6 +104,7 @@ services:
PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}

View File

@ -467,6 +467,7 @@ x-shared-env: &shared-api-worker-env
PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
PLUGIN_S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-}
PLUGIN_S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
PLUGIN_S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
PLUGIN_S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
@ -508,7 +509,7 @@ x-shared-env: &shared-api-worker-env
services:
# API service
api:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -537,7 +538,7 @@ services:
# worker service
# The Celery worker for processing the queue.
worker:
image: langgenius/dify-api:1.4.2
image: langgenius/dify-api:1.4.3
restart: always
environment:
# Use the shared environment variables.
@ -563,7 +564,7 @@ services:
# Frontend web application.
web:
image: langgenius/dify-web:1.4.2
image: langgenius/dify-web:1.4.3
restart: always
environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-}
@ -674,6 +675,7 @@ services:
PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-}
S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
@ -940,7 +942,7 @@ services:
# OceanBase vector database
oceanbase:
image: oceanbase/oceanbase-ce:4.3.5.1-101000042025031818
image: oceanbase/oceanbase-ce:4.3.5-lts
container_name: oceanbase
profiles:
- oceanbase
@ -955,9 +957,7 @@ services:
OB_TENANT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
OB_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
OB_SERVER_IP: 127.0.0.1
MODE: MINI
ports:
- "${OCEANBASE_VECTOR_PORT:-2881}:2881"
MODE: mini
# Oracle vector database
oracle:

View File

@ -133,6 +133,7 @@ PLUGIN_MEDIA_CACHE_PATH=assets
PLUGIN_STORAGE_OSS_BUCKET=
# Plugin oss s3 credentials
PLUGIN_S3_USE_AWS_MANAGED_IAM=false
PLUGIN_S3_USE_AWS=
PLUGIN_S3_ENDPOINT=
PLUGIN_S3_USE_PATH_STYLE=false
PLUGIN_AWS_ACCESS_KEY=

View File

@ -25,9 +25,8 @@ import Loading from '@/app/components/base/loading'
import DatasetDetailContext from '@/context/dataset-detail'
import { DataSourceType } from '@/models/datasets'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { LanguagesSupported } from '@/i18n/language'
import { useStore } from '@/app/components/app/store'
import { getLocaleOnClient } from '@/i18n'
import { useDocLink } from '@/context/i18n'
import { useAppContext } from '@/context/app-context'
import Tooltip from '@/app/components/base/tooltip'
import LinkedAppsPanel from '@/app/components/base/linked-apps-panel'
@ -45,9 +44,9 @@ type IExtraInfoProps = {
}
const ExtraInfo = ({ isMobile, relatedApps, expand }: IExtraInfoProps) => {
const locale = getLocaleOnClient()
const [isShowTips, { toggle: toggleTips, set: setShowTips }] = useBoolean(!isMobile)
const { t } = useTranslation()
const docLink = useDocLink()
const hasRelatedApps = relatedApps?.data && relatedApps?.data?.length > 0
const relatedAppsTotal = relatedApps?.data?.length || 0
@ -97,11 +96,7 @@ const ExtraInfo = ({ isMobile, relatedApps, expand }: IExtraInfoProps) => {
<div className='my-2 text-xs text-text-tertiary'>{t('common.datasetMenus.emptyTip')}</div>
<a
className='mt-2 inline-flex cursor-pointer items-center text-xs text-text-accent'
href={
locale === LanguagesSupported[1]
? 'https://docs.dify.ai/zh-hans/guides/knowledge-base/integrate-knowledge-within-application'
: 'https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application'
}
href={docLink('/guides/knowledge-base/integrate-knowledge-within-application')}
target='_blank' rel='noopener noreferrer'
>
<RiBookOpenLine className='mr-1 text-text-accent' />

View File

@ -1,13 +1,11 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next'
import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
import Panel from '@/app/components/app/configuration/base/feature-panel'
import { MessageClockCircle } from '@/app/components/base/icons/src/vender/solid/general'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language'
import { useDocLink } from '@/context/i18n'
type Props = {
showWarning: boolean
@ -19,7 +17,7 @@ const HistoryPanel: FC<Props> = ({
onShowEditModal,
}) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
return (
<Panel
@ -45,9 +43,8 @@ const HistoryPanel: FC<Props> = ({
{showWarning && (
<div className='flex justify-between rounded-b-xl bg-background-section-burn px-3 py-2 text-xs text-text-secondary'>
<div>{t('appDebug.feature.conversationHistory.tip')}
<a href={`${locale === LanguagesSupported[1]
? 'https://docs.dify.ai/zh-hans/learn-more/extended-reading/prompt-engineering/README'
: 'https://docs.dify.ai/en/features/prompt-engineering'}`}
<a href={docLink('/learn-more/extended-reading/what-is-llmops',
{ 'zh-Hans': '/learn-more/extended-reading/prompt-engineering/README' })}
target='_blank' rel='noopener noreferrer'
className='text-[#155EEF]'>{t('appDebug.feature.conversationHistory.learnMore')}
</a>

View File

@ -31,6 +31,7 @@ import {
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { fetchMembers } from '@/service/common'
import type { Member } from '@/models/common'
import { useDocLink } from '@/context/i18n'
type SettingsModalProps = {
currentDataset: DataSet
@ -58,6 +59,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
currentModel: isRerankDefaultModelValid,
} = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
const { t } = useTranslation()
const docLink = useDocLink()
const { notify } = useToastContext()
const ref = useRef(null)
const isExternal = currentDataset.provider === 'external'
@ -328,7 +330,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
<div>
<div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='text-xs font-normal leading-[18px] text-text-tertiary'>
<a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
<a target='_blank' rel='noopener noreferrer' href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#setting-the-retrieval-setting')} className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
{t('datasetSettings.form.retrievalSetting.description')}
</div>
</div>

View File

@ -2,9 +2,7 @@
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language'
import { useDocLink } from '@/context/i18n'
type Props = {
onReturnToSimpleMode: () => void
}
@ -13,7 +11,7 @@ const AdvancedModeWarning: FC<Props> = ({
onReturnToSimpleMode,
}) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
const [show, setShow] = React.useState(true)
if (!show)
return null
@ -25,7 +23,7 @@ const AdvancedModeWarning: FC<Props> = ({
<span className='text-gray-700'>{t('appDebug.promptMode.advancedWarning.description')}</span>
<a
className='font-medium text-[#155EEF]'
href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? '/guides/features/prompt-engineering' : 'features/prompt-engineering'}`}
href={docLink('/guides/features/prompt-engineering')}
target='_blank' rel='noopener noreferrer'
>
{t('appDebug.promptMode.advancedWarning.learnMore')}

View File

@ -29,6 +29,7 @@ import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { getRedirection } from '@/utils/app-redirection'
import FullScreenModal from '@/app/components/base/fullscreen-modal'
import useTheme from '@/hooks/use-theme'
import { useDocLink } from '@/context/i18n'
type CreateAppProps = {
onSuccess: () => void
@ -303,31 +304,41 @@ function AppTypeCard({ icon, title, description, active, onClick }: AppTypeCardP
function AppPreview({ mode }: { mode: AppMode }) {
const { t } = useTranslation()
const docLink = useDocLink()
const modeToPreviewInfoMap = {
'chat': {
title: t('app.types.chatbot'),
description: t('app.newApp.chatbotUserDescription'),
link: 'https://docs.dify.ai/guides/application-orchestrate/readme',
link: docLink('/guides/application-orchestrate/chatbot-application'),
},
'advanced-chat': {
title: t('app.types.advanced'),
description: t('app.newApp.advancedUserDescription'),
link: 'https://docs.dify.ai/en/guides/workflow/README',
link: docLink('/guides/workflow/README', {
'zh-Hans': '/guides/workflow/readme',
'ja-JP': '/guides/workflow/concepts',
}),
},
'agent-chat': {
title: t('app.types.agent'),
description: t('app.newApp.agentUserDescription'),
link: 'https://docs.dify.ai/en/guides/application-orchestrate/agent',
link: docLink('/guides/application-orchestrate/agent'),
},
'completion': {
title: t('app.newApp.completeApp'),
description: t('app.newApp.completionUserDescription'),
link: null,
link: docLink('/guides/application-orchestrate/text-generator', {
'zh-Hans': '/guides/application-orchestrate/readme',
'ja-JP': '/guides/application-orchestrate/README',
}),
},
'workflow': {
title: t('app.types.workflow'),
description: t('app.newApp.workflowUserDescription'),
link: 'https://docs.dify.ai/en/guides/workflow/README',
link: docLink('/guides/workflow/README', {
'zh-Hans': '/guides/workflow/readme',
'ja-JP': '/guides/workflow/concepts',
}),
},
}
const previewInfo = modeToPreviewInfoMap[mode]

View File

@ -354,7 +354,8 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
}
useEffect(() => {
adjustModalWidth()
const raf = requestAnimationFrame(adjustModalWidth)
return () => cancelAnimationFrame(raf)
}, [])
return (

View File

@ -3,13 +3,11 @@ import type { FC } from 'react'
import React from 'react'
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { useDocLink } from '@/context/i18n'
import type { AppMode } from '@/types/app'
import I18n from '@/context/i18n'
import Button from '@/app/components/base/button'
import Modal from '@/app/components/base/modal'
import Tag from '@/app/components/base/tag'
import { LanguagesSupported } from '@/i18n/language'
type IShareLinkProps = {
isShow: boolean
@ -43,7 +41,7 @@ const CustomizeModal: FC<IShareLinkProps> = ({
mode,
}) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
const isChatApp = mode === 'chat' || mode === 'advanced-chat'
return <Modal
@ -101,10 +99,7 @@ const CustomizeModal: FC<IShareLinkProps> = ({
className='mt-2'
onClick={() =>
window.open(
`https://docs.dify.ai/${locale !== LanguagesSupported[1]
? 'user-guide/launching-dify-apps/developing-with-apis'
: `${locale.toLowerCase()}/guides/application-publishing/developing-with-apis`
}`,
docLink('/guides/application-publishing/developing-with-apis'),
'_blank',
)
}

View File

@ -4,7 +4,6 @@ import React, { useCallback, useEffect, useState } from 'react'
import { RiArrowRightSLine, RiCloseLine } from '@remixicon/react'
import Link from 'next/link'
import { Trans, useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { SparklesSoft } from '@/app/components/base/icons/src/public/common'
import Modal from '@/app/components/base/modal'
import ActionButton from '@/app/components/base/action-button'
@ -19,14 +18,14 @@ import { SimpleSelect } from '@/app/components/base/select'
import type { AppDetailResponse } from '@/models/app'
import type { AppIconType, AppSSO, Language } from '@/types/app'
import { useToastContext } from '@/app/components/base/toast'
import { LanguagesSupported, languages } from '@/i18n/language'
import { languages } from '@/i18n/language'
import Tooltip from '@/app/components/base/tooltip'
import { useProviderContext } from '@/context/provider-context'
import { useModalContext } from '@/context/modal-context'
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
import AppIconPicker from '@/app/components/base/app-icon-picker'
import I18n from '@/context/i18n'
import cn from '@/utils/classnames'
import { useDocLink } from '@/context/i18n'
export type ISettingsModalProps = {
isChat: boolean
@ -98,7 +97,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
const [language, setLanguage] = useState(default_language)
const [saveLoading, setSaveLoading] = useState(false)
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
const [showAppIconPicker, setShowAppIconPicker] = useState(false)
const [appIcon, setAppIcon] = useState<AppIconSelection>(
@ -238,7 +237,10 @@ const SettingsModal: FC<ISettingsModalProps> = ({
</div>
<div className='system-xs-regular mt-0.5 text-text-tertiary'>
<span>{t(`${prefixSettings}.modalTip`)}</span>
<Link href={`${locale === LanguagesSupported[1] ? 'https://docs.dify.ai/zh-hans/guides/application-publishing/launch-your-webapp-quickly#she-zhi-ni-de-ai-zhan-dian' : 'https://docs.dify.ai/en/guides/application-publishing/launch-your-webapp-quickly/README'}`} target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link>
<Link href={docLink('/guides/application-publishing/launch-your-webapp-quickly/README', {
'zh-Hans': '/guides/application-publishing/launch-your-webapp-quickly/readme',
})}
target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link>
</div>
</div>
{/* form body */}

View File

@ -1,6 +1,5 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { RiCloseLine, RiInformation2Fill } from '@remixicon/react'
import DialogWrapper from '@/app/components/base/features/new-feature-panel/dialog-wrapper'
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
@ -19,8 +18,7 @@ import Moderation from '@/app/components/base/features/new-feature-panel/moderat
import AnnotationReply from '@/app/components/base/features/new-feature-panel/annotation-reply'
import type { PromptVariable } from '@/models/debug'
import type { InputVar } from '@/app/components/workflow/types'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language'
import { useDocLink } from '@/context/i18n'
type Props = {
show: boolean
@ -48,7 +46,7 @@ const NewFeaturePanel = ({
onAutoAddPromptVariable,
}: Props) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
const { data: speech2textDefaultModel } = useDefaultModel(ModelTypeEnum.speech2text)
const { data: text2speechDefaultModel } = useDefaultModel(ModelTypeEnum.tts)
@ -80,7 +78,7 @@ const NewFeaturePanel = ({
<span>{isChatMode ? t('workflow.common.fileUploadTip') : t('workflow.common.ImageUploadLegacyTip')}</span>
<a
className='text-text-accent'
href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? 'v/zh-hans/' : ''}guides/workflow/bulletin`}
href={docLink('/guides/workflow/bulletin')}
target='_blank' rel='noopener noreferrer'
>{t('workflow.common.featuresDocLink')}</a>
</div>

View File

@ -14,7 +14,7 @@ const MarkdownButton = ({ node }: any) => {
size={size}
className={cn('!h-auto min-h-8 select-none whitespace-normal !px-3')}
onClick={() => {
if (isValidUrl(link)) {
if (link && isValidUrl(link)) {
window.open(link, '_blank')
return
}

View File

@ -63,6 +63,7 @@ import CustomDialog from '@/app/components/base/dialog'
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import { noop } from 'lodash-es'
import { useDocLink } from '@/context/i18n'
const TextLabel: FC<PropsWithChildren> = (props) => {
return <label className='system-sm-semibold text-text-secondary'>{props.children}</label>
@ -146,6 +147,7 @@ const StepTwo = ({
updateRetrievalMethodCache,
}: StepTwoProps) => {
const { t } = useTranslation()
const docLink = useDocLink()
const { locale } = useContext(I18n)
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
@ -962,7 +964,9 @@ const StepTwo = ({
<div className={'mb-1'}>
<div className='system-md-semibold mb-0.5 text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='body-xs-regular text-text-tertiary'>
<a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
<a target='_blank' rel='noopener noreferrer'
href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents')}
className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
{t('datasetSettings.form.retrievalSetting.longDescription')}
</div>
</div>

View File

@ -4,6 +4,7 @@ import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from './input'
import Button from '@/app/components/base/button'
import { useDocLink } from '@/context/i18n'
const I18N_PREFIX = 'datasetCreation.stepOne.website'
@ -17,6 +18,7 @@ const UrlInput: FC<Props> = ({
onRun,
}) => {
const { t } = useTranslation()
const docLink = useDocLink()
const [url, setUrl] = useState('')
const handleUrlChange = useCallback((url: string | number) => {
setUrl(url as string)
@ -32,7 +34,7 @@ const UrlInput: FC<Props> = ({
<Input
value={url}
onChange={handleUrlChange}
placeholder='https://docs.dify.ai'
placeholder={docLink()}
/>
<Button
variant='primary'

View File

@ -4,6 +4,7 @@ import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from './input'
import Button from '@/app/components/base/button'
import { useDocLink } from '@/context/i18n'
const I18N_PREFIX = 'datasetCreation.stepOne.website'
@ -17,6 +18,7 @@ const UrlInput: FC<Props> = ({
onRun,
}) => {
const { t } = useTranslation()
const docLink = useDocLink()
const [url, setUrl] = useState('')
const handleUrlChange = useCallback((url: string | number) => {
setUrl(url as string)
@ -32,7 +34,7 @@ const UrlInput: FC<Props> = ({
<Input
value={url}
onChange={handleUrlChange}
placeholder='https://docs.dify.ai'
placeholder={docLink()}
/>
<Button
variant='primary'

View File

@ -29,8 +29,7 @@ import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/u
import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata'
import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer'
import StatusWithAction from '../common/document-status-with-action/status-with-action'
import { LanguagesSupported } from '@/i18n/language'
import { getLocaleOnClient } from '@/i18n'
import { useDocLink } from '@/context/i18n'
const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => {
return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
@ -86,6 +85,7 @@ const DEFAULT_LIMIT = 10
const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
const { t } = useTranslation()
const docLink = useDocLink()
const { plan } = useProviderContext()
const isFreePlan = plan.type === 'sandbox'
const [inputValue, setInputValue] = useState<string>('') // the input value
@ -100,7 +100,6 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
const isDataSourceWeb = dataset?.data_source_type === DataSourceType.WEB
const isDataSourceFile = dataset?.data_source_type === DataSourceType.FILE
const embeddingAvailable = !!dataset?.embedding_available
const locale = getLocaleOnClient()
const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
const { data: documentsRes, isFetching: isListLoading } = useDocumentList({
@ -262,11 +261,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
<a
className='flex items-center text-text-accent'
target='_blank'
href={
locale === LanguagesSupported[1]
? 'https://docs.dify.ai/zh-hans/guides/knowledge-base/integrate-knowledge-within-application'
: 'https://docs.dify.ai/en/guides/knowledge-base/integrate-knowledge-within-application'
}
href={docLink('/guides/knowledge-base/integrate-knowledge-within-application')}
>
<span>{t('datasetDocuments.list.learnMore')}</span>
<RiExternalLinkLine className='h-3 w-3' />

View File

@ -5,6 +5,7 @@ import { RiBookOpenLine } from '@remixicon/react'
import type { CreateExternalAPIReq, FormSchema } from '../declarations'
import Input from '@/app/components/base/input'
import cn from '@/utils/classnames'
import { useDocLink } from '@/context/i18n'
type FormProps = {
className?: string
@ -26,6 +27,7 @@ const Form: FC<FormProps> = React.memo(({
inputClassName,
}) => {
const { t, i18n } = useTranslation()
const docLink = useDocLink()
const [changeKey, setChangeKey] = useState('')
const handleFormChange = (key: string, val: string) => {
@ -57,7 +59,7 @@ const Form: FC<FormProps> = React.memo(({
</label>
{variable === 'endpoint' && (
<a
href={'https://docs.dify.ai/guides/knowledge-base/external-knowledge-api-documentation' || '/'}
href={docLink('/guides/knowledge-base/connect-external-knowledge-base') || '/'}
target='_blank'
rel='noopener noreferrer'
className='body-xs-regular flex items-center text-text-accent'

View File

@ -12,6 +12,7 @@ import ActionButton from '@/app/components/base/action-button'
import Button from '@/app/components/base/button'
import Loading from '@/app/components/base/loading'
import { useModalContext } from '@/context/modal-context'
import { useDocLink } from '@/context/i18n'
type ExternalAPIPanelProps = {
onClose: () => void
@ -19,6 +20,7 @@ type ExternalAPIPanelProps = {
const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({ onClose }) => {
const { t } = useTranslation()
const docLink = useDocLink()
const { setShowExternalKnowledgeAPIModal } = useModalContext()
const { externalKnowledgeApiList, mutateExternalKnowledgeApis, isLoading } = useExternalKnowledgeApi()
@ -50,7 +52,8 @@ const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({ onClose }) => {
<div className='flex grow flex-col items-start gap-1'>
<div className='system-xl-semibold self-stretch text-text-primary'>{t('dataset.externalAPIPanelTitle')}</div>
<div className='body-xs-regular self-stretch text-text-tertiary'>{t('dataset.externalAPIPanelDescription')}</div>
<a className='flex cursor-pointer items-center justify-center gap-1 self-stretch' href='https://docs.dify.ai/guides/knowledge-base/external-knowledge-api-documentation' target='_blank'>
<a className='flex cursor-pointer items-center justify-center gap-1 self-stretch'
href={docLink('/guides/knowledge-base/connect-external-knowledge-base')} target='_blank'>
<RiBookOpenLine className='h-3 w-3 text-text-accent' />
<div className='body-xs-regular grow text-text-accent'>{t('dataset.externalAPIPanelDocumentation')}</div>
</a>

View File

@ -1,8 +1,10 @@
import { RiBookOpenLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import { useDocLink } from '@/context/i18n'
const InfoPanel = () => {
const { t } = useTranslation()
const docLink = useDocLink()
return (
<div className='flex w-[360px] flex-col items-start pb-2 pr-8 pt-[108px]'>
@ -16,12 +18,15 @@ const InfoPanel = () => {
</span>
<span className='system-sm-regular text-text-tertiary'>
{t('dataset.connectDatasetIntro.content.front')}
<a className='system-sm-regular ml-1 text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/external-knowledge-api' target='_blank' rel="noopener noreferrer">
<a className='system-sm-regular ml-1 text-text-accent' href={docLink('/guides/knowledge-base/external-knowledge-api')} target='_blank' rel="noopener noreferrer">
{t('dataset.connectDatasetIntro.content.link')}
</a>
{t('dataset.connectDatasetIntro.content.end')}
</span>
<a className='system-sm-regular self-stretch text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/connect-external-knowledge-base' target='_blank' rel="noopener noreferrer">
<a className='system-sm-regular self-stretch text-text-accent'
href={docLink('/guides/knowledge-base/connect-external-knowledge-base')}
target='_blank'
rel="noopener noreferrer">
{t('dataset.connectDatasetIntro.learnMore')}
</a>
</p>

View File

@ -11,6 +11,7 @@ import InfoPanel from './InfoPanel'
import type { CreateKnowledgeBaseReq } from './declarations'
import Divider from '@/app/components/base/divider'
import Button from '@/app/components/base/button'
import { useDocLink } from '@/context/i18n'
type ExternalKnowledgeBaseCreateProps = {
onConnect: (formValue: CreateKnowledgeBaseReq) => void
@ -19,6 +20,7 @@ type ExternalKnowledgeBaseCreateProps = {
const ExternalKnowledgeBaseCreate: React.FC<ExternalKnowledgeBaseCreateProps> = ({ onConnect, loading }) => {
const { t } = useTranslation()
const docLink = useDocLink()
const router = useRouter()
const [formData, setFormData] = useState<CreateKnowledgeBaseReq>({
name: '',
@ -59,7 +61,7 @@ const ExternalKnowledgeBaseCreate: React.FC<ExternalKnowledgeBaseCreateProps> =
<span>{t('dataset.connectHelper.helper1')}</span>
<span className='system-sm-medium text-text-secondary'>{t('dataset.connectHelper.helper2')}</span>
<span>{t('dataset.connectHelper.helper3')}</span>
<a className='system-sm-regular self-stretch text-text-accent' href='https://docs.dify.ai/en/guides/knowledge-base/connect-external-knowledge-base' target='_blank' rel="noopener noreferrer">
<a className='system-sm-regular self-stretch text-text-accent' href={docLink('/guides/knowledge-base/connect-external-knowledge-base')} target='_blank' rel="noopener noreferrer">
{t('dataset.connectHelper.helper4')}
</a>
<span>{t('dataset.connectHelper.helper5')} </span>

View File

@ -11,6 +11,7 @@ import EconomicalRetrievalMethodConfig from '@/app/components/datasets/common/ec
import Button from '@/app/components/base/button'
import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { useDocLink } from '@/context/i18n'
type Props = {
indexMethod: string
@ -29,6 +30,7 @@ const ModifyRetrievalModal: FC<Props> = ({
}) => {
const ref = useRef(null)
const { t } = useTranslation()
const docLink = useDocLink()
const [retrievalConfig, setRetrievalConfig] = useState(value)
// useClickAway(() => {
@ -72,7 +74,10 @@ const ModifyRetrievalModal: FC<Props> = ({
<a
target='_blank'
rel='noopener noreferrer'
href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings'
href={docLink('/guides/knowledge-base/retrieval-test-and-citation#modify-text-retrieval-setting', {
'zh-Hans': '/guides/knowledge-base/retrieval-test-and-citation#修改文本检索方式',
'ja-JP': '/guides/knowledge-base/retrieval-test-and-citation',
})}
className='text-text-accent'
>
{t('datasetSettings.form.retrievalSetting.learnMore')}

View File

@ -32,6 +32,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
import { fetchMembers } from '@/service/common'
import type { Member } from '@/models/common'
import AlertTriangle from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle'
import { useDocLink } from '@/context/i18n'
const rowClass = 'flex'
const labelClass = `
@ -46,6 +47,7 @@ const getKey = (pageIndex: number, previousPageData: DataSetListResponse) => {
const Form = () => {
const { t } = useTranslation()
const docLink = useDocLink()
const { notify } = useContext(ToastContext)
const { mutate } = useSWRConfig()
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
@ -308,7 +310,16 @@ const Form = () => {
<div>
<div className='system-sm-semibold text-text-secondary'>{t('datasetSettings.form.retrievalSetting.title')}</div>
<div className='body-xs-regular text-text-tertiary'>
<a target='_blank' rel='noopener noreferrer' href='https://docs.dify.ai/guides/knowledge-base/create-knowledge-and-upload-documents#id-4-retrieval-settings' className='text-text-accent'>{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
<a
target='_blank'
rel='noopener noreferrer'
href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#setting-the-retrieval-setting', {
'zh-Hans': '/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#指定检索方式',
'ja-JP': '/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#検索方法の指定',
})}
className='text-text-accent'>
{t('datasetSettings.form.retrievalSetting.learnMore')}
</a>
{t('datasetSettings.form.retrievalSetting.description')}
</div>
</div>

View File

@ -57,8 +57,8 @@ The text generation application offers non-session support and is ideal for tran
<i>Due to Cloudflare restrictions, the request will be interrupted without a return after 100 seconds.</i>
</Property>
<Property name='user' type='string' key='user'>
User identifier, used to define the identity of the end-user for retrieval and statistics.
Should be uniquely defined by the developer within the application.
User identifier, used to define the identity of the end-user, convenient for retrieval and statistics.
The rules are defined by the developer and need to ensure that the user identifier is unique within the application. The Service API does not share conversations created by the WebApp.
</Property>
<Property name='files' type='array[object]' key='files'>
File list, suitable for inputting files (images) combined with text understanding and answering questions, available only when the model supports Vision capability.
@ -220,7 +220,7 @@ The text generation application offers non-session support and is ideal for tran
- `file` (File) Required
The file to be uploaded.
- `user` (string) Required
User identifier, defined by the developer's rules, must be unique within the application.
User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp.
### Response
After a successful upload, the server will return the file's ID and related information.
@ -290,7 +290,7 @@ The text generation application offers non-session support and is ideal for tran
- `task_id` (string) Task ID, can be obtained from the streaming chunk return
Request Body
- `user` (string) Required
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface. The Service API does not share conversations created by the WebApp.
### Response
- `result` (string) Always returns "success"
</Col>
@ -512,6 +512,8 @@ The text generation application offers non-session support and is ideal for tran
- `name` (string) application name
- `description` (string) application description
- `tags` (array[string]) application tags
- `mode` (string) application mode
- `author_name` (string) author name
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -528,7 +530,9 @@ The text generation application offers non-session support and is ideal for tran
"tags": [
"tag1",
"tag2"
]
],
"mode": "chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -220,7 +220,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `file` (File) 必須
アップロードするファイル。
- `user` (string) 必須
開発者のルールで定義されたユーザー識別子。アプリケーション内で一意である必要があります。
開発者のルールで定義されたユーザー識別子。アプリケーション内で一意である必要があります。サービス API は WebApp によって作成された会話を共有しません。
### レスポンス
アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。
@ -289,7 +289,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `task_id` (string) タスク ID、ストリーミングチャンクの返信から取得可能
リクエストボディ
- `user` (string) 必須
ユーザー識別子。エンドユーザーの身元を定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致する必要があります。
ユーザー識別子。エンドユーザーの身元を定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致する必要があります。サービス API は WebApp によって作成された会話を共有しません。
### レスポンス
- `result` (string) 常に"success"を返します
</Col>
@ -510,6 +510,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `name` (string) アプリケーションの名前
- `description` (string) アプリケーションの説明
- `tags` (array[string]) アプリケーションのタグ
- `mode` (string) アプリケーションのモード
- `author_name` (string) 作者の名前
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -526,7 +528,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
"tags": [
"tag1",
"tag2"
]
],
"mode": "chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -266,7 +266,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
### Request Body
- `user` (string) Required
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。
### Response
- `result` (string) 固定返回 success
</Col>
@ -485,6 +485,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
- `name` (string) 应用名称
- `description` (string) 应用描述
- `tags` (array[string]) 应用标签
- `mode` (string) 应用模式
- 'author_name' (string) 作者名称
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -501,7 +503,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
"tags": [
"tag1",
"tag2"
]
],
"mode": "chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -59,7 +59,7 @@ Chat applications support session persistence, allowing previous chat history to
</Property>
<Property name='user' type='string' key='user'>
User identifier, used to define the identity of the end-user for retrieval and statistics.
Should be uniquely defined by the developer within the application.
Should be uniquely defined by the developer within the application. The Service API does not share conversations created by the WebApp.
</Property>
<Property name='conversation_id' type='string' key='conversation_id'>
Conversation ID, to continue the conversation based on previous chat records, it is necessary to pass the previous message's conversation_id.
@ -324,7 +324,7 @@ Chat applications support session persistence, allowing previous chat history to
- `file` (File) Required
The file to be uploaded.
- `user` (string) Required
User identifier, defined by the developer's rules, must be unique within the application.
User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp.
### Response
After a successful upload, the server will return the file's ID and related information.
@ -394,7 +394,7 @@ Chat applications support session persistence, allowing previous chat history to
- `task_id` (string) Task ID, can be obtained from the streaming chunk return
### Request Body
- `user` (string) Required
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp.
### Response
- `result` (string) Always returns "success"
</Col>
@ -448,7 +448,7 @@ Chat applications support session persistence, allowing previous chat history to
Upvote as `like`, downvote as `dislike`, revoke upvote as `null`
</Property>
<Property name='user' type='string' key='user'>
User identifier, defined by the developer's rules, must be unique within the application.
User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp.
</Property>
<Property name='content' type='string' key='content'>
The specific content of message feedback.
@ -1123,6 +1123,8 @@ Chat applications support session persistence, allowing previous chat history to
- `name` (string) application name
- `description` (string) application description
- `tags` (array[string]) application tags
- `mode` (string) application mode
- `author_name` (string) application author name
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -1139,7 +1141,9 @@ Chat applications support session persistence, allowing previous chat history to
"tags": [
"tag1",
"tag2"
]
],
"mode": "advanced-chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -59,7 +59,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
</Property>
<Property name='user' type='string' key='user'>
ユーザー識別子、エンドユーザーの身元を定義するために使用され、統計のために使用されます。
アプリケーション内で開発者によって一意に定義されるべきです。
アプリケーション内で開発者によって一意に定義されるべきです。サービス API は WebApp によって作成された会話を共有しません。
</Property>
<Property name='conversation_id' type='string' key='conversation_id'>
会話ID、以前のチャット記録に基づいて会話を続けるには、以前のメッセージのconversation_idを渡す必要があります。
@ -324,7 +324,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `file` (File) 必須
アップロードするファイル。
- `user` (string) 必須
ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。
ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。サービス API は WebApp によって作成された会話を共有しません。
### 応答
アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。
@ -394,7 +394,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得できます
### リクエストボディ
- `user` (string) 必須
ユーザー識別子、エンドユーザーの身元を定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。
ユーザー識別子、エンドユーザーの身元を定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。サービス API は WebApp によって作成された会話を共有しません。
### 応答
- `result` (string) 常に"success"を返します
</Col>
@ -1123,6 +1123,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `name` (string) アプリケーションの名前
- `description` (string) アプリケーションの説明
- `tags` (array[string]) アプリケーションのタグ
- `mode` (string) アプリケーションのモード
- `author_name` (string) 作者の名前
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -1139,7 +1141,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
"tags": [
"tag1",
"tag2"
]
],
"mode": "advanced-chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -56,7 +56,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
</Property>
<Property name='user' type='string' key='user'>
用户标识,用于定义终端用户的身份,方便检索、统计。
由开发者定义规则,需保证用户标识在应用内唯一。
由开发者定义规则,需保证用户标识在应用内唯一。服务 API 不会共享 WebApp 创建的对话。
</Property>
<Property name='conversation_id' type='string' key='conversation_id'>
(选填)会话 ID需要基于之前的聊天记录继续对话必须传之前消息的 conversation_id。
@ -402,7 +402,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
### Request Body
- `user` (string) Required
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。
### Response
- `result` (string) 固定返回 success
</Col>
@ -1173,7 +1173,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
"tags": [
"tag1",
"tag2"
]
],
"mode": "advanced-chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -287,7 +287,7 @@ Chat applications support session persistence, allowing previous chat history to
- `file` (File) Required
The file to be uploaded.
- `user` (string) Required
User identifier, defined by the developer's rules, must be unique within the application.
User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp.
### Response
After a successful upload, the server will return the file's ID and related information.
@ -357,7 +357,7 @@ Chat applications support session persistence, allowing previous chat history to
- `task_id` (string) Task ID, can be obtained from the streaming chunk return
### Request Body
- `user` (string) Required
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp.
### Response
- `result` (string) Always returns "success"
</Col>
@ -1151,6 +1151,8 @@ Chat applications support session persistence, allowing previous chat history to
- `name` (string) application name
- `description` (string) application description
- `tags` (array[string]) application tags
- `mode` (string) application mode
- `author_name` (string) application author name
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -1167,7 +1169,9 @@ Chat applications support session persistence, allowing previous chat history to
"tags": [
"tag1",
"tag2"
]
],
"mode": "advanced-chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -287,7 +287,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `file` (File) 必須
アップロードするファイル。
- `user` (string) 必須
ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。
ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。サービス API は WebApp によって作成された会話を共有しません。
### 応答
アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。
@ -357,7 +357,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得できます
### リクエストボディ
- `user` (string) 必須
ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致している必要があります。
ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致している必要があります。サービス API は WebApp によって作成された会話を共有しません。
### 応答
- `result` (string) 常に"success"を返します
</Col>
@ -1150,6 +1150,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `name` (string) アプリケーションの名前
- `description` (string) アプリケーションの説明
- `tags` (array[string]) アプリケーションのタグ
- `mode` (string) アプリケーションのモード
- `author_name` (string) 作者の名前
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -1166,7 +1168,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
"tags": [
"tag1",
"tag2"
]
],
"mode": "chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -56,7 +56,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
</Property>
<Property name='user' type='string' key='user'>
用户标识,用于定义终端用户的身份,方便检索、统计。
由开发者定义规则,需保证用户标识在应用内唯一。
由开发者定义规则,需保证用户标识在应用内唯一。服务 API 不会共享 WebApp 创建的对话。
</Property>
<Property name='conversation_id' type='string' key='conversation_id'>
(选填)会话 ID需要基于之前的聊天记录继续对话必须传之前消息的 conversation_id。
@ -306,7 +306,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
要上传的文件。
</Property>
<Property name='user' type='string' key='user'>
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。服务 API 不会共享 WebApp 创建的对话。
</Property>
</Properties>
@ -373,7 +373,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
### Request Body
- `user` (string) Required
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。
### Response
- `result` (string) 固定返回 success
</Col>
@ -425,7 +425,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
点赞 like, 点踩 dislike, 撤销点赞 null
</Property>
<Property name='user' type='string' key='user'>
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。服务 API 不会共享 WebApp 创建的对话。
</Property>
<Property name='content' type='string' key='content'>
消息反馈的具体信息。
@ -1162,6 +1162,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
- `name` (string) 应用名称
- `description` (string) 应用描述
- `tags` (array[string]) 应用标签
- `mode` (string) 应用模式
- 'author_name' (string) 作者名称
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -1178,7 +1180,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
"tags": [
"tag1",
"tag2"
]
],
"mode": "chat",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -64,6 +64,8 @@ Workflow applications offers non-session support and is ideal for translation, a
- `user` (string) Required
User identifier, used to define the identity of the end-user for retrieval and statistics.
Should be uniquely defined by the developer within the application.
<br/>
<i>The user identifier should be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp.</i>
### Response
When `response_mode` is `blocking`, return a CompletionResponse object.
@ -401,7 +403,7 @@ Workflow applications offers non-session support and is ideal for translation, a
- `task_id` (string) Task ID, can be obtained from the streaming chunk return
### Request Body
- `user` (string) Required
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the send message interface.
User identifier, used to define the identity of the end-user, must be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp.
### Response
- `result` (string) Always returns "success"
</Col>
@ -448,7 +450,7 @@ Workflow applications offers non-session support and is ideal for translation, a
- `file` (File) Required
The file to be uploaded.
- `user` (string) Required
User identifier, defined by the developer's rules, must be unique within the application.
User identifier, defined by the developer's rules, must be unique within the application. The Service API does not share conversations created by the WebApp.
### Response
After a successful upload, the server will return the file's ID and related information.
@ -625,6 +627,8 @@ Workflow applications offers non-session support and is ideal for translation, a
- `name` (string) application name
- `description` (string) application description
- `tags` (array[string]) application tags
- `mode` (string) application mode
- `author_name` (string) application author name
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -641,7 +645,9 @@ Workflow applications offers non-session support and is ideal for translation, a
"tags": [
"tag1",
"tag2"
]
],
"mode": "workflow",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -404,7 +404,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得可能
### リクエストボディ
- `user` (string) 必須
ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。
ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。サービス API は WebApp によって作成された会話を共有しません。
### 応答
- `result` (string) 常に"success"を返します
</Col>
@ -451,7 +451,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `file` (File) 必須
アップロードするファイル。
- `user` (string) 必須
ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。
ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。サービス API は WebApp によって作成された会話を共有しません。
### 応答
アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。
@ -628,6 +628,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
- `name` (string) アプリケーションの名前
- `description` (string) アプリケーションの説明
- `tags` (array[string]) アプリケーションのタグ
- `mode` (string) アプリケーションのモード
- `author_name` (string) 作者の名前
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -644,7 +646,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
"tags": [
"tag1",
"tag2"
]
],
"mode": "workflow",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -59,7 +59,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
<i>由于 Cloudflare 限制,请求会在 100 秒超时无返回后中断。</i>
- `user` (string) Required
用户标识,用于定义终端用户的身份,方便检索、统计。
由开发者定义规则,需保证用户标识在应用内唯一。
由开发者定义规则,需保证用户标识在应用内唯一。API 无法访问 WebApp 创建的会话。
### Response
@ -394,7 +394,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
- `task_id` (string) 任务 ID可在流式返回 Chunk 中获取
### Request Body
- `user` (string) Required
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。API 无法访问 WebApp 创建的会话。
### Response
- `result` (string) 固定返回 "success"
</Col>
@ -443,7 +443,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
要上传的文件。
</Property>
<Property name='user' type='string' key='user'>
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。
用户标识,用于定义终端用户的身份,必须和发送消息接口传入 user 保持一致。服务 API 不会共享 WebApp 创建的对话。
</Property>
</Properties>
@ -615,6 +615,8 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
- `name` (string) 应用名称
- `description` (string) 应用描述
- `tags` (array[string]) 应用标签
- `mode` (string) 应用模式
- 'author_name' (string) 作者名称
</Col>
<Col>
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info' \\\n-H 'Authorization: Bearer {api_key}'`}>
@ -631,7 +633,9 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
"tags": [
"tag1",
"tag2"
]
],
"mode": "workflow",
"author_name": "Dify"
}
```
</CodeGroup>

View File

@ -23,7 +23,6 @@ import GithubStar from '../github-star'
import Support from './support'
import Compliance from './compliance'
import PremiumBadge from '@/app/components/base/premium-badge'
import { useGetDocLanguage } from '@/context/i18n'
import Avatar from '@/app/components/base/avatar'
import ThemeSwitcher from '@/app/components/base/theme-switcher'
import { logout } from '@/service/common'
@ -33,6 +32,7 @@ import { useModalContext } from '@/context/modal-context'
import { IS_CLOUD_EDITION } from '@/config'
import cn from '@/utils/classnames'
import { useGlobalPublicStore } from '@/context/global-public-context'
import { useDocLink } from '@/context/i18n'
export default function AppSelector() {
const itemClassName = `
@ -44,10 +44,10 @@ export default function AppSelector() {
const { systemFeatures } = useGlobalPublicStore()
const { t } = useTranslation()
const docLink = useDocLink()
const { userProfile, langeniusVersionInfo, isCurrentWorkspaceOwner } = useAppContext()
const { isEducationAccount } = useProviderContext()
const { setShowAccountSettingModal } = useModalContext()
const docLanguage = useGetDocLanguage()
const handleLogout = async () => {
await logout({
@ -133,7 +133,7 @@ export default function AppSelector() {
className={cn(itemClassName, 'group justify-between',
'data-[active]:bg-state-base-hover',
)}
href={`https://docs.dify.ai/${docLanguage}/introduction`}
href={docLink('/introduction')}
target='_blank' rel='noopener noreferrer'>
<RiBookOpenLine className='size-4 shrink-0 text-text-tertiary' />
<div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.helpCenter')}</div>

View File

@ -1,6 +1,6 @@
import React, { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { useDocLink } from '@/context/i18n'
import { useBoolean } from 'ahooks'
import {
RiAddLine,
@ -20,8 +20,6 @@ import {
useInvalidateEndpointList,
} from '@/service/use-endpoints'
import type { PluginDetail } from '@/app/components/plugins/types'
import { LanguagesSupported } from '@/i18n/language'
import I18n from '@/context/i18n'
import cn from '@/utils/classnames'
type Props = {
@ -29,7 +27,7 @@ type Props = {
}
const EndpointList = ({ detail }: Props) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
const pluginUniqueID = detail.plugin_unique_identifier
const declaration = detail.declaration.endpoint
const showTopBorder = detail.declaration.tool
@ -79,7 +77,7 @@ const EndpointList = ({ detail }: Props) => {
</div>
<div className='system-xs-regular text-text-tertiary'>{t('plugin.detailPanel.endpointsTip')}</div>
<a
href={`https://docs.dify.ai/${locale === LanguagesSupported[1] ? 'v/zh-hans/' : ''}plugins/schema-definition/endpoint`}
href={docLink('/plugins/schema-definition/endpoint')}
target='_blank'
rel='noopener noreferrer'
>

View File

@ -14,6 +14,7 @@ import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-m
import { createCustomCollection } from '@/service/tools'
import Toast from '@/app/components/base/toast'
import { useAppContext } from '@/context/app-context'
import { useDocLink } from '@/context/i18n'
type Props = {
onRefreshData: () => void
@ -25,10 +26,11 @@ const Contribute = ({ onRefreshData }: Props) => {
const language = getLanguage(locale)
const { isCurrentWorkspaceManager } = useAppContext()
const docLink = useDocLink()
const linkUrl = useMemo(() => {
if (language.startsWith('zh_'))
return 'https://docs.dify.ai/zh-hans/guides/tools#ru-he-chuang-jian-zi-ding-yi-gong-ju'
return 'https://docs.dify.ai/en/guides/tools#how-to-create-custom-tools'
return docLink('/guides/tools#how-to-create-custom-tools', {
'zh-Hans': '/guides/tools#ru-he-chuang-jian-zi-ding-yi-gong-ju',
})
}, [language])
const [isShowEditCollectionToolModal, setIsShowEditCustomCollectionModal] = useState(false)

View File

@ -19,9 +19,7 @@ import { useWorkflowStore } from '../../../store'
import { useRenderI18nObject } from '@/hooks/use-i18n'
import type { NodeOutPutVar } from '../../../types'
import type { Node } from 'reactflow'
import { useContext } from 'use-context-selector'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language'
import { useDocLink } from '@/context/i18n'
export type Strategy = {
agent_strategy_provider_name: string
@ -52,7 +50,7 @@ type CustomField = ToolSelectorSchema | MultipleToolSelectorSchema
export const AgentStrategy = memo((props: AgentStrategyProps) => {
const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange, nodeOutputVars, availableNodes, nodeId } = props
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
const defaultModel = useDefaultModel(ModelTypeEnum.textGeneration)
const renderI18nObject = useRenderI18nObject()
const workflowStore = useWorkflowStore()
@ -223,11 +221,11 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
title={t('workflow.nodes.agent.strategy.configureTip')}
description={<div className='text-xs text-text-tertiary'>
{t('workflow.nodes.agent.strategy.configureTipDesc')} <br />
<Link href={
locale === LanguagesSupported[1]
? 'https://docs.dify.ai/zh-hans/guides/workflow/node/agent#xuan-ze-agent-ce-le'
: 'https://docs.dify.ai/en/guides/workflow/node/agent#select-an-agent-strategy'
} className='text-text-accent-secondary' target='_blank'>
<Link href={docLink('/guides/workflow/node/agent#select-an-agent-strategy', {
'zh-Hans': '/guides/workflow/node/agent#选择-agent-策略',
'ja-JP': '/guides/workflow/node/agent#エージェント戦略の選択',
})}
className='text-text-accent-secondary' target='_blank'>
{t('workflow.nodes.agent.learnMore')}
</Link>
</div>}

View File

@ -5,6 +5,7 @@ import Input from '@/app/components/base/input'
import { VarType } from '@/app/components/workflow/types'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import { useDocLink } from '@/context/i18n'
type DefaultValueProps = {
forms: DefaultValueForm[]
@ -15,6 +16,7 @@ const DefaultValue = ({
onFormChange,
}: DefaultValueProps) => {
const { t } = useTranslation()
const docLink = useDocLink()
const getFormChangeHandler = useCallback(({ key, type }: DefaultValueForm) => {
return (payload: any) => {
let value
@ -34,7 +36,9 @@ const DefaultValue = ({
{t('workflow.nodes.common.errorHandle.defaultValue.desc')}
&nbsp;
<a
href='https://docs.dify.ai/en/guides/workflow/error-handling/README'
href={docLink('/guides/workflow/error-handling/README', {
'zh-Hans': '/guides/workflow/error-handling/readme',
})}
target='_blank'
className='text-text-accent'
>

View File

@ -1,8 +1,10 @@
import { RiMindMap } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import { useDocLink } from '@/context/i18n'
const FailBranchCard = () => {
const { t } = useTranslation()
const docLink = useDocLink()
return (
<div className='px-4 pt-2'>
@ -17,7 +19,7 @@ const FailBranchCard = () => {
{t('workflow.nodes.common.errorHandle.failBranch.customizeTip')}
&nbsp;
<a
href='https://docs.dify.ai/guides/workflow/error-handling'
href={docLink('/guides/workflow/error-handling/error-type')}
target='_blank'
className='text-text-accent'
>

View File

@ -2,12 +2,10 @@
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import VarReferenceVars from './var-reference-vars'
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
import ListEmpty from '@/app/components/base/list-empty'
import { LanguagesSupported } from '@/i18n/language'
import I18n from '@/context/i18n'
import { useDocLink } from '@/context/i18n'
type Props = {
vars: NodeOutPutVar[]
@ -24,7 +22,7 @@ const VarReferencePopup: FC<Props> = ({
isSupportFileVar = true,
}) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
return (
<div className='space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg' style={{
@ -47,7 +45,12 @@ const VarReferencePopup: FC<Props> = ({
{t('workflow.variableReference.assignedVarsDescription')}
<a target='_blank' rel='noopener noreferrer'
className='text-text-accent-secondary'
href={locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/guides/workflow/variables#conversation-variables' : `https://docs.dify.ai/${locale.toLowerCase()}/guides/workflow/variables#hui-hua-bian-liang`}>{t('workflow.variableReference.conversationVars')}</a>
href={docLink('/guides/workflow/variables#conversation-variables', {
'zh-Hans': '/guides/workflow/variables#会话变量',
'ja-JP': '/guides/workflow/variables#会話変数',
})}>
{t('workflow.variableReference.conversationVars')}
</a>
</div>}
/>
))

View File

@ -1,14 +1,12 @@
import { useMemo } from 'react'
import { useGetLanguage } from '@/context/i18n'
import { useDocLink, useGetLanguage } from '@/context/i18n'
import { BlockEnum } from '@/app/components/workflow/types'
export const useNodeHelpLink = (nodeType: BlockEnum) => {
const language = useGetLanguage()
const docLink = useDocLink()
const prefixLink = useMemo(() => {
if (language === 'zh_Hans')
return 'https://docs.dify.ai/zh-hans/guides/workflow/node/'
return 'https://docs.dify.ai/en/guides/workflow/node/'
return docLink('/guides/workflow/node/')
}, [language])
const linkMap = useMemo(() => {
if (language === 'zh_Hans') {

View File

@ -21,8 +21,8 @@ import { MittProvider, VisualEditorContextProvider, useMittContext } from './vis
import ErrorMessage from './error-message'
import { useVisualEditorStore } from './visual-editor/store'
import Toast from '@/app/components/base/toast'
import { useGetDocLanguage } from '@/context/i18n'
import { JSON_SCHEMA_MAX_DEPTH } from '@/config'
import { useDocLink } from '@/context/i18n'
type JsonSchemaConfigProps = {
defaultSchema?: SchemaRoot
@ -53,7 +53,7 @@ const JsonSchemaConfig: FC<JsonSchemaConfigProps> = ({
onClose,
}) => {
const { t } = useTranslation()
const docLanguage = useGetDocLanguage()
const docLink = useDocLink()
const [currentTab, setCurrentTab] = useState(SchemaView.VisualEditor)
const [jsonSchema, setJsonSchema] = useState(defaultSchema || DEFAULT_SCHEMA)
const [json, setJson] = useState(JSON.stringify(jsonSchema, null, 2))
@ -252,7 +252,7 @@ const JsonSchemaConfig: FC<JsonSchemaConfigProps> = ({
<div className='flex items-center gap-x-2 p-6 pt-5'>
<a
className='flex grow items-center gap-x-1 text-text-accent'
href={`https://docs.dify.ai/${docLanguage}/guides/workflow/structured-outputs`}
href={docLink('/guides/workflow/structured-outputs')}
target='_blank'
rel='noopener noreferrer'
>

View File

@ -3,7 +3,6 @@ import {
useCallback,
useState,
} from 'react'
import { useContext } from 'use-context-selector'
import {
useStoreApi,
} from 'reactflow'
@ -22,13 +21,12 @@ import type {
import { findUsedVarNodes, updateNodeVars } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import { useNodesSyncDraft } from '@/app/components/workflow/hooks/use-nodes-sync-draft'
import { BlockEnum } from '@/app/components/workflow/types'
import I18n from '@/context/i18n'
import { LanguagesSupported } from '@/i18n/language'
import { useDocLink } from '@/context/i18n'
import cn from '@/utils/classnames'
const ChatVariablePanel = () => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
const docLink = useDocLink()
const store = useStoreApi()
const setShowChatVariablePanel = useStore(s => s.setShowChatVariablePanel)
const varList = useStore(s => s.conversationVariables) as ConversationVariable[]
@ -139,7 +137,13 @@ const ChatVariablePanel = () => {
<div className='system-2xs-medium-uppercase inline-block rounded-[5px] border border-divider-deep px-[5px] py-[3px] text-text-tertiary'>TIPS</div>
<div className='system-sm-regular mb-4 mt-1 text-text-secondary'>
{t('workflow.chatVariable.panelDescription')}
<a target='_blank' rel='noopener noreferrer' className='text-text-accent' href={locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/guides/workflow/variables#conversation-variables' : `https://docs.dify.ai/${locale.toLowerCase()}/guides/workflow/variables#hui-hua-bian-liang`}>{t('workflow.chatVariable.docLink')}</a>
<a target='_blank' rel='noopener noreferrer' className='text-text-accent'
href={docLink('/guides/workflow/variables#conversation-variables', {
'zh-Hans': '/guides/workflow/variables#会话变量',
'ja-JP': '/guides/workflow/variables#会話変数',
})}>
{t('workflow.chatVariable.docLink')}
</a>
</div>
<div className='flex items-center gap-2'>
<div className='radius-lg flex flex-col border border-workflow-block-border bg-workflow-block-bg p-3 pb-4 shadow-md'>
@ -166,7 +170,7 @@ const ChatVariablePanel = () => {
</div>
</div>
</div>
<div className='absolute right-[38px] top-[-4px] z-10 h-3 w-3 rotate-45 bg-background-section-burn'/>
<div className='absolute right-[38px] top-[-4px] z-10 h-3 w-3 rotate-45 bg-background-section-burn' />
</div>
</div>
)}

View File

@ -28,6 +28,7 @@ import type {
} from '@/types/workflow'
import ErrorHandleTip from '@/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip'
import { hasRetryNode } from '@/app/components/workflow/utils'
import { useDocLink } from '@/context/i18n'
type Props = {
className?: string
@ -65,6 +66,7 @@ const NodePanel: FC<Props> = ({
doSetCollapseState(state)
}, [hideProcessDetail])
const { t } = useTranslation()
const docLink = useDocLink()
const getTime = (time: number) => {
if (time < 1)
@ -195,7 +197,7 @@ const NodePanel: FC<Props> = ({
<StatusContainer status='stopped'>
{nodeInfo.error}
<a
href='https://docs.dify.ai/guides/workflow/error-handling/error-type'
href={docLink('/guides/workflow/error-handling/error-type')}
target='_blank'
className='text-text-accent'
>

View File

@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames'
import Indicator from '@/app/components/header/indicator'
import StatusContainer from '@/app/components/workflow/run/status-container'
import { useDocLink } from '@/context/i18n'
type ResultProps = {
status: string
@ -21,6 +22,7 @@ const StatusPanel: FC<ResultProps> = ({
exceptionCounts,
}) => {
const { t } = useTranslation()
const docLink = useDocLink()
return (
<StatusContainer status={status}>
@ -134,7 +136,7 @@ const StatusPanel: FC<ResultProps> = ({
<div className='system-xs-medium text-text-warning'>
{error}
<a
href='https://docs.dify.ai/guides/workflow/error-handling/error-type'
href={docLink('/guides/workflow/error-handling/error-type')}
target='_blank'
className='text-text-accent'
>

View File

@ -1,7 +1,6 @@
'use client'
import {
useMemo,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
@ -23,13 +22,11 @@ import {
import { useProviderContext } from '@/context/provider-context'
import { useToastContext } from '@/app/components/base/toast'
import { EDUCATION_VERIFYING_LOCALSTORAGE_ITEM } from '@/app/education-apply/constants'
import { getLocaleOnClient } from '@/i18n'
import { noop } from 'lodash-es'
import DifyLogo from '../components/base/logo/dify-logo'
import { useDocLink } from '@/context/i18n'
const EducationApplyAge = () => {
const { t } = useTranslation()
const locale = getLocaleOnClient()
const [schoolName, setSchoolName] = useState('')
const [role, setRole] = useState('Student')
const [ageChecked, setAgeChecked] = useState(false)
@ -43,14 +40,7 @@ const EducationApplyAge = () => {
const updateEducationStatus = useInvalidateEducationStatus()
const { notify } = useToastContext()
const router = useRouter()
const docLink = useMemo(() => {
if (locale === 'zh-Hans')
return 'https://docs.dify.ai/zh-hans/getting-started/dify-for-education'
if (locale === 'ja-JP')
return 'https://docs.dify.ai/ja-jp/getting-started/dify-for-education'
return 'https://docs.dify.ai/getting-started/dify-for-education'
}, [locale])
const docLink = useDocLink()
const handleModalConfirm = () => {
setShowModal(undefined)
@ -167,7 +157,7 @@ const EducationApplyAge = () => {
<div className='mb-4 mt-5 h-[1px] bg-gradient-to-r from-[rgba(16,24,40,0.08)]'></div>
<a
className='system-xs-regular flex items-center text-text-accent'
href={docLink}
href={docLink('/getting-started/dify-for-education')}
target='_blank'
>
{t('education.learn')}

View File

@ -1,11 +1,11 @@
import React, { useEffect, useMemo, useRef, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { useTranslation } from 'react-i18next'
import {
RiExternalLinkLine,
} from '@remixicon/react'
import Button from '@/app/components/base/button'
import { getLocaleOnClient } from '@/i18n'
import { useDocLink } from '@/context/i18n'
export type IConfirm = {
className?: string
@ -30,20 +30,13 @@ function Confirm({
email,
}: IConfirm) {
const { t } = useTranslation()
const locale = getLocaleOnClient()
const docLink = useDocLink()
const dialogRef = useRef<HTMLDivElement>(null)
const [isVisible, setIsVisible] = useState(isShow)
const docLink = useMemo(() => {
if (locale === 'zh-Hans')
return 'https://docs.dify.ai/zh-hans/getting-started/dify-for-education'
if (locale === 'ja-JP')
return 'https://docs.dify.ai/ja-jp/getting-started/dify-for-education'
return 'https://docs.dify.ai/getting-started/dify-for-education'
}, [locale])
const eduDocLink = docLink('/getting-started/dify-for-education')
const handleClick = () => {
window.open(docLink, '_blank', 'noopener,noreferrer')
window.open(eduDocLink, '_blank', 'noopener,noreferrer')
}
useEffect(() => {
@ -106,7 +99,7 @@ function Confirm({
<div className='flex items-center gap-1'>
{showLink && (
<>
<a onClick={handleClick} href={docLink} target='_blank' className='system-xs-regular cursor-pointer text-text-accent'>{t('education.learn')}</a>
<a onClick={handleClick} href={eduDocLink} target='_blank' className='system-xs-regular cursor-pointer text-text-accent'>{t('education.learn')}</a>
<RiExternalLinkLine className='h-3 w-3 text-text-accent' />
</>
)}

View File

@ -17,6 +17,7 @@ import Button from '@/app/components/base/button'
import { fetchInitValidateStatus, fetchSetupStatus, setup } from '@/service/common'
import type { InitValidateStatusResponse, SetupStatusResponse } from '@/models/common'
import useDocumentTitle from '@/hooks/use-document-title'
import { useDocLink } from '@/context/i18n'
const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/
@ -36,6 +37,7 @@ type AccountFormValues = z.infer<typeof accountFormSchema>
const InstallForm = () => {
useDocumentTitle('')
const { t } = useTranslation()
const docLink = useDocLink()
const router = useRouter()
const [showPassword, setShowPassword] = React.useState(false)
const [loading, setLoading] = React.useState(true)
@ -174,7 +176,7 @@ const InstallForm = () => {
<Link
className='text-text-accent'
target='_blank' rel='noopener noreferrer'
href={'https://docs.dify.ai/user-agreement/open-source'}
href={docLink('/policies/open-source')}
>{t('login.license.link')}</Link>
</div>
</div>

View File

@ -1,5 +1,6 @@
'use client'
import { useTranslation } from 'react-i18next'
import { useDocLink } from '@/context/i18n'
import { useCallback, useState } from 'react'
import Link from 'next/link'
import { useContext } from 'use-context-selector'
@ -18,10 +19,11 @@ import Toast from '@/app/components/base/toast'
export default function InviteSettingsPage() {
const { t } = useTranslation()
const docLink = useDocLink()
const router = useRouter()
const searchParams = useSearchParams()
const token = decodeURIComponent(searchParams.get('invite_token') as string)
const { locale, setLocaleOnClient } = useContext(I18n)
const { setLocaleOnClient } = useContext(I18n)
const [name, setName] = useState('')
const [language, setLanguage] = useState(LanguagesSupported[0])
const [timezone, setTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone || 'America/Los_Angeles')
@ -147,7 +149,7 @@ export default function InviteSettingsPage() {
<Link
className='system-xs-medium text-text-accent-secondary'
target='_blank' rel='noopener noreferrer'
href={`https://docs.dify.ai/${language !== LanguagesSupported[1] ? 'user-agreement' : `v/${locale.toLowerCase()}/policies`}/open-source`}
href={docLink('/policies/open-source')}
>{t('login.license.link')}</Link>
</div>
</div>

View File

@ -12,6 +12,7 @@ import { timezones } from '@/utils/timezone'
import { LanguagesSupported, languages } from '@/i18n/language'
import { oneMoreStep } from '@/service/common'
import Toast from '@/app/components/base/toast'
import { useDocLink } from '@/context/i18n'
type IState = {
formState: 'processing' | 'error' | 'success' | 'initial'
@ -51,6 +52,7 @@ const reducer: Reducer<IState, IAction> = (state: IState, action: IAction) => {
const OneMoreStep = () => {
const { t } = useTranslation()
const docLink = useDocLink()
const router = useRouter()
const searchParams = useSearchParams()
@ -164,7 +166,7 @@ const OneMoreStep = () => {
<Link
className='system-xs-medium text-text-accent-secondary'
target='_blank' rel='noopener noreferrer'
href={'https://docs.dify.ai/en/policies/agreement/README'}
href={docLink('/policies/agreement/README')}
>{t('login.license.link')}</Link>
</div>
</div>

View File

@ -24,15 +24,23 @@ export const useGetLanguage = () => {
return getLanguage(locale)
}
export const useGetDocLanguage = () => {
const { locale } = useI18N()
return getDocLanguage(locale)
}
export const useGetPricingPageLanguage = () => {
const { locale } = useI18N()
return getPricingPageLanguage(locale)
}
const defaultDocBaseUrl = 'https://docs.dify.ai'
export const useDocLink = (baseUrl?: string): ((path?: string, pathMap?: { [index: string]: string }) => string) => {
let baseDocUrl = baseUrl || defaultDocBaseUrl
baseDocUrl = (baseDocUrl.endsWith('/')) ? baseDocUrl.slice(0, -1) : baseDocUrl
const { locale } = useI18N()
const docLanguage = getDocLanguage(locale)
return (path?: string, pathMap?: { [index: string]: string }): string => {
const pathUrl = path || ''
let targetPath = (pathMap) ? pathMap[locale] || pathUrl : pathUrl
targetPath = (targetPath.startsWith('/')) ? targetPath.slice(1) : targetPath
return `${baseDocUrl}/${docLanguage}/${targetPath}`
}
}
export default I18NContext

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Variable setzen',
needConnectTip: 'Dieser Schritt ist mit nichts verbunden',
maxTreeDepth: 'Maximales Limit von {{depth}} Knoten pro Ast',
needEndNode: 'Der Endblock muss hinzugefügt werden',
needAnswerNode: 'Der Antwortblock muss hinzugefügt werden',
workflowProcess: 'Arbeitsablauf',
notRunning: 'Noch nicht ausgeführt',
previewPlaceholder: 'Geben Sie den Inhalt in das Feld unten ein, um das Debuggen des Chatbots zu starten',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Mehr erfahren',
copy: 'Kopieren',
duplicate: 'Duplizieren',
addBlock: 'Block hinzufügen',
pasteHere: 'Hier einfügen',
pointerMode: 'Zeigermodus',
handMode: 'Handmodus',
@ -115,6 +112,9 @@ const translation = {
exportJPEG: 'Als JPEG exportieren',
exitVersions: 'Ausgangsversionen',
exportPNG: 'Als PNG exportieren',
addBlock: 'Knoten hinzufügen',
needEndNode: 'Der Endknoten muss hinzugefügt werden.',
needAnswerNode: 'Der Antwortknoten muss hinzugefügt werden.',
},
env: {
envPanelTitle: 'Umgebungsvariablen',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} Schritte vorwärts',
sessionStart: 'Sitzungsstart',
currentState: 'Aktueller Zustand',
nodeTitleChange: 'Blocktitel geändert',
nodeDescriptionChange: 'Blockbeschreibung geändert',
nodeDragStop: 'Block verschoben',
nodeChange: 'Block geändert',
nodeConnect: 'Block verbunden',
nodePaste: 'Block eingefügt',
nodeDelete: 'Block gelöscht',
nodeAdd: 'Block hinzugefügt',
nodeResize: 'Blockgröße geändert',
noteAdd: 'Notiz hinzugefügt',
noteChange: 'Notiz geändert',
noteDelete: 'Notiz gelöscht',
edgeDelete: 'Block getrennt',
edgeDelete: 'Knoten getrennt',
nodeAdd: 'Knoten hinzugefügt',
nodeTitleChange: 'Knotenüberschrift geändert',
nodePaste: 'Knoten eingefügt',
nodeResize: 'Knoten verkleinert',
nodeDescriptionChange: 'Die Knotenbeschreibung wurde geändert',
nodeChange: 'Knoten geändert',
nodeConnect: 'Node verbunden',
nodeDragStop: 'Knoten verschoben',
nodeDelete: 'Knoten gelöscht',
},
errorMsg: {
fieldRequired: '{{field}} ist erforderlich',
@ -217,8 +217,6 @@ const translation = {
loop: 'Schleife',
},
tabs: {
'searchBlock': 'Block suchen',
'blocks': 'Blöcke',
'tools': 'Werkzeuge',
'allTool': 'Alle',
'builtInTool': 'Eingebaut',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Suchwerkzeug',
'plugin': 'Stecker',
'agent': 'Agenten-Strategie',
'searchBlock': 'Suchknoten',
'blocks': 'Knoten',
},
blocks: {
'start': 'Start',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Benutzereingabefeld',
changeBlock: 'Block ändern',
helpLink: 'Hilfelink',
about: 'Über',
createdBy: 'Erstellt von ',
nextStep: 'Nächster Schritt',
addNextStep: 'Fügen Sie den nächsten Block in diesem Workflow hinzu',
selectNextStep: 'Nächsten Block auswählen',
runThisStep: 'Diesen Schritt ausführen',
checklist: 'Checkliste',
checklistTip: 'Stellen Sie sicher, dass alle Probleme vor der Veröffentlichung gelöst sind',
checklistResolved: 'Alle Probleme wurden gelöst',
organizeBlocks: 'Blöcke organisieren',
change: 'Ändern',
optional: '(optional)',
moveToThisNode: 'Bewege zu diesem Knoten',
selectNextStep: 'Nächsten Schritt auswählen',
addNextStep: 'Fügen Sie den nächsten Schritt in diesem Arbeitsablauf hinzu.',
organizeBlocks: 'Knoten organisieren',
changeBlock: 'Knoten ändern',
},
nodes: {
common: {

View File

@ -46,8 +46,8 @@ const translation = {
setVarValuePlaceholder: 'Set variable',
needConnectTip: 'This step is not connected to anything',
maxTreeDepth: 'Maximum limit of {{depth}} nodes per branch',
needEndNode: 'The End block must be added',
needAnswerNode: 'The Answer block must be added',
needEndNode: 'The End node must be added',
needAnswerNode: 'The Answer node must be added',
workflowProcess: 'Workflow Process',
notRunning: 'Not running yet',
previewPlaceholder: 'Enter content in the box below to start debugging the Chatbot',
@ -66,7 +66,7 @@ const translation = {
learnMore: 'Learn More',
copy: 'Copy',
duplicate: 'Duplicate',
addBlock: 'Add Block',
addBlock: 'Add Node',
pasteHere: 'Paste Here',
pointerMode: 'Pointer Mode',
handMode: 'Hand Mode',
@ -174,19 +174,19 @@ const translation = {
stepForward_other: '{{count}} steps forward',
sessionStart: 'Session Start',
currentState: 'Current State',
nodeTitleChange: 'Block title changed',
nodeDescriptionChange: 'Block description changed',
nodeDragStop: 'Block moved',
nodeChange: 'Block changed',
nodeConnect: 'Block connected',
nodePaste: 'Block pasted',
nodeDelete: 'Block deleted',
nodeAdd: 'Block added',
nodeResize: 'Block resized',
nodeTitleChange: 'Node title changed',
nodeDescriptionChange: 'Node description changed',
nodeDragStop: 'Node moved',
nodeChange: 'Node changed',
nodeConnect: 'Node connected',
nodePaste: 'Node pasted',
nodeDelete: 'Node deleted',
nodeAdd: 'Node added',
nodeResize: 'Node resized',
noteAdd: 'Note added',
noteChange: 'Note changed',
noteDelete: 'Note deleted',
edgeDelete: 'Block disconnected',
edgeDelete: 'Node disconnected',
},
errorMsg: {
fieldRequired: '{{field}} is required',
@ -215,8 +215,8 @@ const translation = {
loop: 'Loop',
},
tabs: {
'searchBlock': 'Search block',
'blocks': 'Blocks',
'searchBlock': 'Search node',
'blocks': 'Nodes',
'searchTool': 'Search tool',
'tools': 'Tools',
'allTool': 'All',
@ -292,19 +292,19 @@ const translation = {
},
panel: {
userInputField: 'User Input Field',
changeBlock: 'Change Block',
changeBlock: 'Change Node',
helpLink: 'Help Link',
about: 'About',
createdBy: 'Created By ',
nextStep: 'Next Step',
addNextStep: 'Add the next block in this workflow',
selectNextStep: 'Select Next Block',
addNextStep: 'Add the next step in this workflow',
selectNextStep: 'Select Next Step',
runThisStep: 'Run this step',
moveToThisNode: 'Move to this node',
checklist: 'Checklist',
checklistTip: 'Make sure all issues are resolved before publishing',
checklistResolved: 'All issues are resolved',
organizeBlocks: 'Organize blocks',
organizeBlocks: 'Organize nodes',
change: 'Change',
optional: '(optional)',
},

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Establecer variable',
needConnectTip: 'Este paso no está conectado a nada',
maxTreeDepth: 'Límite máximo de {{depth}} nodos por rama',
needEndNode: 'Debe agregarse el bloque de Fin',
needAnswerNode: 'Debe agregarse el bloque de Respuesta',
workflowProcess: 'Proceso de flujo de trabajo',
notRunning: 'Aún no se está ejecutando',
previewPlaceholder: 'Ingrese contenido en el cuadro de abajo para comenzar a depurar el Chatbot',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Más información',
copy: 'Copiar',
duplicate: 'Duplicar',
addBlock: 'Agregar bloque',
pasteHere: 'Pegar aquí',
pointerMode: 'Modo puntero',
handMode: 'Modo mano',
@ -115,6 +112,9 @@ const translation = {
publishUpdate: 'Publicar actualización',
noExist: 'No existe tal variable',
exportImage: 'Exportar imagen',
needAnswerNode: 'Se debe agregar el nodo de respuesta',
needEndNode: 'Se debe agregar el nodo Final',
addBlock: 'Agregar nodo',
},
env: {
envPanelTitle: 'Variables de Entorno',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} pasos hacia adelante',
sessionStart: 'Inicio de sesión',
currentState: 'Estado actual',
nodeTitleChange: 'Se cambió el título del bloque',
nodeDescriptionChange: 'Se cambió la descripción del bloque',
nodeDragStop: 'Bloque movido',
nodeChange: 'Bloque cambiado',
nodeConnect: 'Bloque conectado',
nodePaste: 'Bloque pegado',
nodeDelete: 'Bloque eliminado',
nodeAdd: 'Bloque agregado',
nodeResize: 'Bloque redimensionado',
noteAdd: 'Nota agregada',
noteChange: 'Nota cambiada',
noteDelete: 'Nota eliminada',
edgeDelete: 'Bloque desconectado',
nodeTitleChange: 'Título del nodo cambiado',
nodeAdd: 'Nodo añadido',
nodePaste: 'Nodo pegado',
nodeDragStop: 'Nodo movido',
nodeConnect: 'Nodo conectado',
edgeDelete: 'Nodo desconectado',
nodeDelete: 'Nodo eliminado',
nodeChange: 'Nodo cambiado',
nodeDescriptionChange: 'Descripción del nodo cambiada',
nodeResize: 'Nodo redimensionado',
},
errorMsg: {
fieldRequired: 'Se requiere {{field}}',
@ -217,8 +217,6 @@ const translation = {
loop: 'Bucle',
},
tabs: {
'searchBlock': 'Buscar bloque',
'blocks': 'Bloques',
'tools': 'Herramientas',
'allTool': 'Todos',
'builtInTool': 'Incorporadas',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Herramienta de búsqueda',
'agent': 'Estrategia del agente',
'plugin': 'Plugin',
'searchBlock': 'Buscar nodo',
'blocks': 'Nodos',
},
blocks: {
'start': 'Inicio',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Campo de entrada del usuario',
changeBlock: 'Cambiar bloque',
helpLink: 'Enlace de ayuda',
about: 'Acerca de',
createdBy: 'Creado por ',
nextStep: 'Siguiente paso',
addNextStep: 'Agregar el siguiente bloque en este flujo de trabajo',
selectNextStep: 'Seleccionar siguiente bloque',
runThisStep: 'Ejecutar este paso',
checklist: 'Lista de verificación',
checklistTip: 'Asegúrate de resolver todos los problemas antes de publicar',
checklistResolved: 'Se resolvieron todos los problemas',
organizeBlocks: 'Organizar bloques',
change: 'Cambiar',
optional: '(opcional)',
moveToThisNode: 'Mueve a este nodo',
organizeBlocks: 'Organizar nodos',
addNextStep: 'Agrega el siguiente paso en este flujo de trabajo',
changeBlock: 'Cambiar Nodo',
selectNextStep: 'Seleccionar siguiente paso',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'تنظیم متغیر',
needConnectTip: 'این مرحله به هیچ چیزی متصل نیست',
maxTreeDepth: 'حداکثر عمق {{depth}} نود در هر شاخه',
needEndNode: 'بلوک پایان باید اضافه شود',
needAnswerNode: 'بلوک پاسخ باید اضافه شود',
workflowProcess: 'فرآیند جریان کار',
notRunning: 'هنوز در حال اجرا نیست',
previewPlaceholder: 'محتوا را در کادر زیر وارد کنید تا اشکال‌زدایی چت‌بات را شروع کنید',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'اطلاعات بیشتر',
copy: 'کپی',
duplicate: 'تکرار',
addBlock: 'افزودن بلوک',
pasteHere: 'چسباندن اینجا',
pointerMode: 'حالت اشاره‌گر',
handMode: 'حالت دست',
@ -115,6 +112,9 @@ const translation = {
exportImage: 'تصویر را صادر کنید',
versionHistory: 'تاریخچه نسخه',
publishUpdate: 'به‌روزرسانی منتشر کنید',
needEndNode: 'باید گره پایان اضافه شود',
needAnswerNode: 'باید گره پاسخ اضافه شود',
addBlock: 'نود اضافه کنید',
},
env: {
envPanelTitle: 'متغیرهای محیطی',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} قدم به جلو',
sessionStart: 'شروع جلسه',
currentState: 'وضعیت کنونی',
nodeTitleChange: 'عنوان بلوک تغییر کرده است',
nodeDescriptionChange: 'توضیحات بلوک تغییر کرده است',
nodeDragStop: 'بلوک جابجا شده است',
nodeChange: 'بلوک تغییر کرده است',
nodeConnect: 'بلوک متصل شده است',
nodePaste: 'بلوک چسبانده شده است',
nodeDelete: 'بلوک حذف شده است',
nodeAdd: 'بلوک اضافه شده است',
nodeResize: 'اندازه بلوک تغییر کرده است',
noteAdd: 'یادداشت اضافه شده است',
noteChange: 'یادداشت تغییر کرده است',
noteDelete: 'یادداشت حذف شده است',
edgeDelete: 'بلوک قطع شده است',
nodeDelete: 'نود حذف شد',
nodeAdd: 'نود اضافه شد',
nodeDragStop: 'گره منتقل شد',
edgeDelete: 'گره قطع شده است',
nodeResize: 'اندازه نود تغییر یافته است',
nodePaste: 'نود پیست شده است',
nodeTitleChange: 'عنوان نود تغییر کرد',
nodeConnect: 'گره متصل است',
nodeDescriptionChange: 'شرح نود تغییر کرد',
nodeChange: 'نود تغییر کرد',
},
errorMsg: {
fieldRequired: '{{field}} الزامی است',
@ -217,8 +217,6 @@ const translation = {
loop: 'حلقه',
},
tabs: {
'searchBlock': 'جستجوی بلوک',
'blocks': 'بلوک‌ها',
'tools': 'ابزارها',
'allTool': 'همه',
'builtInTool': 'درون‌ساخت',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'ابزار جستجو',
'plugin': 'افزونه',
'agent': 'استراتژی نمایندگی',
'blocks': 'گره‌ها',
'searchBlock': 'گره جستجو',
},
blocks: {
'start': 'شروع',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'فیلد ورودی کاربر',
changeBlock: 'تغییر بلوک',
helpLink: 'لینک کمک',
about: 'درباره',
createdBy: 'ساخته شده توسط',
nextStep: 'مرحله بعدی',
addNextStep: 'افزودن بلوک بعدی به این جریان کار',
selectNextStep: 'انتخاب بلوک بعدی',
runThisStep: 'اجرا کردن این مرحله',
checklist: 'چک‌لیست',
checklistTip: 'اطمینان حاصل کنید که همه مسائل قبل از انتشار حل شده‌اند',
checklistResolved: 'تمام مسائل حل شده‌اند',
organizeBlocks: 'سازماندهی بلوک‌ها',
change: 'تغییر',
optional: '(اختیاری)',
moveToThisNode: 'به این گره بروید',
selectNextStep: 'گام بعدی را انتخاب کنید',
changeBlock: 'تغییر گره',
organizeBlocks: 'گره‌ها را سازماندهی کنید',
addNextStep: 'مرحله بعدی را به این فرآیند اضافه کنید',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Définir la valeur de la variable',
needConnectTip: 'Cette étape n\'est connectée à rien',
maxTreeDepth: 'Limite maximale de {{depth}} nœuds par branche',
needEndNode: 'Le bloc de fin doit être ajouté',
needAnswerNode: 'Le bloc de réponse doit être ajouté',
workflowProcess: 'Processus de flux de travail',
notRunning: 'Pas encore en cours d\'exécution',
previewPlaceholder: 'Entrez le contenu dans la boîte ci-dessous pour commencer à déboguer le Chatbot',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'En savoir plus',
copy: 'Copier',
duplicate: 'Dupliquer',
addBlock: 'Ajouter un bloc',
pasteHere: 'Coller ici',
pointerMode: 'Mode pointeur',
handMode: 'Mode main',
@ -115,6 +112,9 @@ const translation = {
referenceVar: 'Variable de référence',
exportImage: 'Exporter l\'image',
exportJPEG: 'Exporter en JPEG',
needEndNode: 'Le nœud de fin doit être ajouté',
needAnswerNode: 'Le nœud de réponse doit être ajouté.',
addBlock: 'Ajouter un nœud',
},
env: {
envPanelTitle: 'Variables d\'Environnement',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} pas en avant',
sessionStart: 'Début de la session',
currentState: 'État actuel',
nodeTitleChange: 'Titre du bloc modifié',
nodeDescriptionChange: 'Description du bloc modifiée',
nodeDragStop: 'Bloc déplacé',
nodeChange: 'Bloc modifié',
nodeConnect: 'Bloc connecté',
nodePaste: 'Bloc collé',
nodeDelete: 'Bloc supprimé',
nodeAdd: 'Bloc ajouté',
nodeResize: 'Bloc redimensionné',
noteAdd: 'Note ajoutée',
noteChange: 'Note modifiée',
noteDelete: 'Note supprimée',
edgeDelete: 'Bloc déconnecté',
nodeConnect: 'Node connecté',
nodeChange: 'Nœud changé',
nodeResize: 'Nœud redimensionné',
edgeDelete: 'Nœud déconnecté',
nodeDelete: 'Nœud supprimé',
nodePaste: 'Node collé',
nodeDragStop: 'Nœud déplacé',
nodeTitleChange: 'Titre du nœud modifié',
nodeAdd: 'Nœud ajouté',
nodeDescriptionChange: 'La description du nœud a changé',
},
errorMsg: {
fieldRequired: '{{field}} est requis',
@ -217,8 +217,6 @@ const translation = {
loop: 'Boucle',
},
tabs: {
'searchBlock': 'Rechercher un bloc',
'blocks': 'Blocs',
'tools': 'Outils',
'allTool': 'Tous',
'builtInTool': 'Intégré',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Outil de recherche',
'plugin': 'Plugin',
'agent': 'Stratégie dagent',
'blocks': 'Nœuds',
'searchBlock': 'Nœud de recherche',
},
blocks: {
'start': 'Début',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Champ de saisie de l\'utilisateur',
changeBlock: 'Changer de bloc',
helpLink: 'Lien d\'aide',
about: 'À propos',
createdBy: 'Créé par',
nextStep: 'Étape suivante',
addNextStep: 'Ajouter le prochain bloc dans ce flux de travail',
selectNextStep: 'Sélectionner le prochain bloc',
runThisStep: 'Exécuter cette étape',
checklist: 'Liste de contrôle',
checklistTip: 'Assurez-vous que tous les problèmes sont résolus avant de publier',
checklistResolved: 'Tous les problèmes ont été résolus',
organizeBlocks: 'Organiser les blocs',
change: 'Modifier',
optional: '(facultatif)',
moveToThisNode: 'Déplacer vers ce nœud',
organizeBlocks: 'Organiser les nœuds',
addNextStep: 'Ajoutez la prochaine étape dans ce flux de travail',
selectNextStep: 'Sélectionner la prochaine étape',
changeBlock: 'Changer de nœud',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'वेरिएबल सेट करें',
needConnectTip: 'यह चरण किसी से जुड़ा नहीं है',
maxTreeDepth: 'प्रति शाखा अधिकतम {{depth}} नोड्स की सीमा',
needEndNode: 'अंत ब्लॉक जोड़ा जाना चाहिए',
needAnswerNode: 'उत्तर ब्लॉक जोड़ा जाना चाहिए',
workflowProcess: 'कार्यप्रवाह प्रक्रिया',
notRunning: 'अभी तक नहीं चल रहा',
previewPlaceholder:
@ -60,7 +58,6 @@ const translation = {
learnMore: 'अधिक जानें',
copy: 'कॉपी करें',
duplicate: 'डुप्लिकेट करें',
addBlock: 'ब्लॉक जोड़ें',
pasteHere: 'यहां पेस्ट करें',
pointerMode: 'पॉइंटर मोड',
handMode: 'हैंड मोड',
@ -118,6 +115,9 @@ const translation = {
publishUpdate: 'अपडेट प्रकाशित करें',
exportSVG: 'SVG के रूप में निर्यात करें',
versionHistory: 'संस्करण इतिहास',
needAnswerNode: 'उत्तर नोड जोड़ा जाना चाहिए',
addBlock: 'नोड जोड़ें',
needEndNode: 'अंत नोड जोड़ा जाना चाहिए',
},
env: {
envPanelTitle: 'पर्यावरण चर',
@ -179,19 +179,19 @@ const translation = {
stepForward_other: '{{count}} कदम आगे',
sessionStart: 'सत्र प्रारंभ',
currentState: 'वर्तमान स्थिति',
nodeTitleChange: 'ब्लॉक शीर्षक बदला गया',
nodeDescriptionChange: 'ब्लॉक विवरण बदला गया',
nodeDragStop: 'ब्लॉक स्थानांतरित किया गया',
nodeChange: 'ब्लॉक बदला गया',
nodeConnect: 'ब्लॉक कनेक्ट किया गया',
nodePaste: 'ब्लॉक पेस्ट किया गया',
nodeDelete: 'ब्लॉक हटाया गया',
nodeAdd: 'ब्लॉक जोड़ा गया',
nodeResize: 'ब्लॉक का आकार बदला गया',
noteAdd: 'नोट जोड़ा गया',
noteChange: 'नोट बदला गया',
noteDelete: 'नोट हटाया गया',
edgeDelete: 'ब्लॉक डिस्कनेक्ट किया गया',
nodeConnect: 'नोड कनेक्टेड',
nodeResize: 'नोड का आकार बदला गया',
nodeDelete: 'नोड हटा दिया गया',
nodeDragStop: 'नोड स्थानांतरित किया गया',
nodeChange: 'नोड बदला गया',
nodeAdd: 'नोड जोड़ा गया',
nodeTitleChange: 'नोड का शीर्षक बदल दिया गया',
edgeDelete: 'नोड डिस्कनेक्ट हो गया',
nodePaste: 'नोड चिपका हुआ',
nodeDescriptionChange: 'नोड का वर्णन बदल गया',
},
errorMsg: {
fieldRequired: '{{field}} आवश्यक है',
@ -220,8 +220,6 @@ const translation = {
loop: 'लूप',
},
tabs: {
'searchBlock': 'ब्लॉक खोजें',
'blocks': 'ब्लॉक्स',
'tools': 'टूल्स',
'allTool': 'सभी',
'builtInTool': 'अंतर्निहित',
@ -235,6 +233,8 @@ const translation = {
'searchTool': 'खोज उपकरण',
'plugin': 'प्लगइन',
'agent': 'एजेंट रणनीति',
'searchBlock': 'खोज नोड',
'blocks': 'नोड्स',
},
blocks: {
'start': 'प्रारंभ',
@ -299,22 +299,22 @@ const translation = {
},
panel: {
userInputField: 'उपयोगकर्ता इनपुट फ़ील्ड',
changeBlock: 'ब्लॉक बदलें',
helpLink: 'सहायता लिंक',
about: 'के बारे में',
createdBy: 'द्वारा बनाया गया ',
nextStep: 'अगला कदम',
addNextStep: 'इस वर्कफ़्लो में अगला ब्लॉक जोड़ें',
selectNextStep: 'अगला ब्लॉक चुनें',
runThisStep: 'इस कदम को चलाएं',
checklist: 'चेकलिस्ट',
checklistTip:
'प्रकाशित करने से पहले सुनिश्चित करें कि सभी समस्याएं हल हो गई हैं',
checklistResolved: 'सभी समस्याएं हल हो गई हैं',
organizeBlocks: 'ब्लॉक्स को व्यवस्थित करें',
change: 'बदलें',
optional: '(वैकल्पिक)',
moveToThisNode: 'इस नोड पर जाएं',
changeBlock: 'नोड बदलें',
addNextStep: 'इस कार्यप्रवाह में अगला कदम जोड़ें',
selectNextStep: 'अगला कदम चुनें',
organizeBlocks: 'नोड्स का आयोजन करें',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Imposta variabile',
needConnectTip: 'Questo passaggio non è collegato a nulla',
maxTreeDepth: 'Limite massimo di {{depth}} nodi per ramo',
needEndNode: 'Deve essere aggiunto il blocco di Fine',
needAnswerNode: 'Deve essere aggiunto il blocco di Risposta',
workflowProcess: 'Processo di flusso di lavoro',
notRunning: 'Non ancora in esecuzione',
previewPlaceholder:
@ -60,7 +58,6 @@ const translation = {
learnMore: 'Scopri di più',
copy: 'Copia',
duplicate: 'Duplica',
addBlock: 'Aggiungi Blocco',
pasteHere: 'Incolla Qui',
pointerMode: 'Modalità Puntatore',
handMode: 'Modalità Mano',
@ -119,6 +116,9 @@ const translation = {
exportJPEG: 'Esporta come JPEG',
noExist: 'Nessuna variabile del genere',
exportPNG: 'Esporta come PNG',
needEndNode: 'Deve essere aggiunto il nodo finale',
addBlock: 'Aggiungi nodo',
needAnswerNode: 'Deve essere aggiunto il nodo di risposta',
},
env: {
envPanelTitle: 'Variabili d\'Ambiente',
@ -181,19 +181,19 @@ const translation = {
stepForward_other: '{{count}} passi avanti',
sessionStart: 'Inizio sessione',
currentState: 'Stato attuale',
nodeTitleChange: 'Titolo del blocco modificato',
nodeDescriptionChange: 'Descrizione del blocco modificata',
nodeDragStop: 'Blocco spostato',
nodeChange: 'Blocco modificato',
nodeConnect: 'Blocco collegato',
nodePaste: 'Blocco incollato',
nodeDelete: 'Blocco eliminato',
nodeAdd: 'Blocco aggiunto',
nodeResize: 'Blocco ridimensionato',
noteAdd: 'Nota aggiunta',
noteChange: 'Nota modificata',
noteDelete: 'Nota eliminata',
edgeDelete: 'Blocco scollegato',
nodeDescriptionChange: 'Descrizione del nodo cambiata',
nodePaste: 'Nodo incollato',
nodeChange: 'Nodo cambiato',
nodeResize: 'Nodo ridimensionato',
nodeDelete: 'Nodo eliminato',
nodeTitleChange: 'Titolo del nodo cambiato',
edgeDelete: 'Nodo disconnesso',
nodeAdd: 'Nodo aggiunto',
nodeDragStop: 'Nodo spostato',
nodeConnect: 'Nodo connesso',
},
errorMsg: {
fieldRequired: '{{field}} è richiesto',
@ -222,8 +222,6 @@ const translation = {
loop: 'Anello',
},
tabs: {
'searchBlock': 'Cerca blocco',
'blocks': 'Blocchi',
'tools': 'Strumenti',
'allTool': 'Tutti',
'builtInTool': 'Integrato',
@ -237,6 +235,8 @@ const translation = {
'searchTool': 'Strumento di ricerca',
'agent': 'Strategia dell\'agente',
'plugin': 'Plugin',
'searchBlock': 'Cerca nodo',
'blocks': 'Nodi',
},
blocks: {
'start': 'Inizio',
@ -302,22 +302,22 @@ const translation = {
},
panel: {
userInputField: 'Campo di Input Utente',
changeBlock: 'Cambia Blocco',
helpLink: 'Link di Aiuto',
about: 'Informazioni',
createdBy: 'Creato da ',
nextStep: 'Prossimo Passo',
addNextStep: 'Aggiungi il prossimo blocco in questo flusso di lavoro',
selectNextStep: 'Seleziona Prossimo Blocco',
runThisStep: 'Esegui questo passo',
checklist: 'Checklist',
checklistTip:
'Assicurati che tutti i problemi siano risolti prima di pubblicare',
checklistResolved: 'Tutti i problemi sono risolti',
organizeBlocks: 'Organizza blocchi',
change: 'Cambia',
optional: '(opzionale)',
moveToThisNode: 'Sposta a questo nodo',
changeBlock: 'Cambia Nodo',
selectNextStep: 'Seleziona il prossimo passo',
organizeBlocks: 'Organizzare i nodi',
addNextStep: 'Aggiungi il prossimo passo in questo flusso di lavoro',
},
nodes: {
common: {

View File

@ -2,7 +2,7 @@ const translation = {
toVerified: '教育認証を取得',
toVerifiedTip: {
front: '現在、教育認証ステータスを取得する資格があります。以下に教育情報を入力し、認証プロセスを完了すると、Dify プロフェッショナルプランの',
coupon: '50割引クーポン',
coupon: '100割引クーポン',
end: 'を受け取ることができます。',
},
currentSigned: '現在ログイン中のアカウントは',
@ -38,9 +38,9 @@ const translation = {
submitError: 'フォームの送信に失敗しました。しばらくしてから再度ご提出ください。',
learn: '教育認証の取得方法はこちら',
successTitle: 'Dify 教育認証を取得しました!',
successContent: 'お客様のアカウントに Dify プロフェッショナルプランの 50% 割引クーポン を発行しました。有効期間は 1 年間 ですので、期限内にご利用ください。',
successContent: 'お客様のアカウントに Dify プロフェッショナルプランの 100% 割引クーポン を発行しました。有効期間は 1 年間 ですので、期限内にご利用ください。',
rejectTitle: 'Dify 教育認証が拒否されました',
rejectContent: '申し訳ございませんが、このメールアドレスでは 教育認証 の資格を取得できず、Dify プロフェッショナルプランの 50割引クーポン を受け取ることはできません。',
rejectContent: '申し訳ございませんが、このメールアドレスでは 教育認証 の資格を取得できず、Dify プロフェッショナルプランの 100割引クーポン を受け取ることはできません。',
emailLabel: '現在のメールアドレス',
}

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: '변수 값 설정',
needConnectTip: '이 단계는 아무것도 연결되어 있지 않습니다',
maxTreeDepth: '분기당 최대 {{depth}} 노드 제한',
needEndNode: '종료 블록을 추가해야 합니다',
needAnswerNode: '답변 블록을 추가해야 합니다',
workflowProcess: '워크플로우 과정',
notRunning: '아직 실행되지 않음',
previewPlaceholder: '디버깅을 시작하려면 아래 상자에 내용을 입력하세요',
@ -58,7 +56,6 @@ const translation = {
learnMore: '더 알아보기',
copy: '복사',
duplicate: '복제',
addBlock: '블록 추가',
pasteHere: '여기에 붙여넣기',
pointerMode: '포인터 모드',
handMode: '핸드 모드',
@ -115,6 +112,9 @@ const translation = {
versionHistory: '버전 기록',
exportPNG: 'PNG 로 내보내기',
referenceVar: '참조 변수',
addBlock: '노드 추가',
needAnswerNode: '답변 노드를 추가해야 합니다.',
needEndNode: '종단 노드를 추가해야 합니다.',
},
env: {
envPanelTitle: '환경 변수',
@ -176,19 +176,18 @@ const translation = {
stepForward_other: '{{count}} 단계 앞으로',
sessionStart: '세션 시작',
currentState: '현재 상태',
nodeTitleChange: '블록 제목 변경됨',
nodeDescriptionChange: '블록 설명 변경됨',
nodeDragStop: '블록 이동됨',
nodeChange: '블록 변경됨',
nodeConnect: '블록 연결됨',
nodePaste: '블록 붙여넣기됨',
nodeDelete: '블록 삭제됨',
nodeAdd: '블록 추가됨',
nodeResize: '블록 크기 조정됨',
noteAdd: '노트 추가됨',
noteChange: '노트 변경됨',
noteDelete: '노트 삭제됨',
edgeDelete: '블록 연결 해제됨',
nodeConnect: '노드가 연결되었습니다.',
nodePaste: '노드 붙여넣기',
nodeDelete: '노드가 삭제되었습니다.',
nodeAdd: '노드가 추가되었습니다.',
nodeChange: '노드가 변경되었습니다.',
nodeDescriptionChange: '노드 설명이 변경됨',
nodeResize: '노드 크기 조정됨',
nodeDragStop: '노드가 이동했습니다.',
edgeDelete: '노드가 연결이 끊어졌습니다.',
},
errorMsg: {
fieldRequired: '{{field}}가 필요합니다',
@ -217,8 +216,6 @@ const translation = {
loop: '루프',
},
tabs: {
'searchBlock': '블록 검색',
'blocks': '블록',
'tools': '도구',
'allTool': '전체',
'builtInTool': '내장',
@ -232,6 +229,8 @@ const translation = {
'searchTool': '검색 도구',
'plugin': '플러그인',
'agent': '에이전트 전략',
'blocks': '노드',
'searchBlock': '검색 노드',
},
blocks: {
'start': '시작',
@ -288,21 +287,21 @@ const translation = {
},
panel: {
userInputField: '사용자 입력 필드',
changeBlock: '블록 변경',
helpLink: '도움말 링크',
about: '정보',
createdBy: '작성자 ',
nextStep: '다음 단계',
addNextStep: '이 워크플로우의 다음 블록 추가',
selectNextStep: '다음 블록 선택',
runThisStep: '이 단계 실행',
checklist: '체크리스트',
checklistTip: '게시하기 전에 모든 문제가 해결되었는지 확인하세요',
checklistResolved: '모든 문제가 해결되었습니다',
organizeBlocks: '블록 정리',
change: '변경',
optional: '(선택사항)',
moveToThisNode: '이 노드로 이동',
organizeBlocks: '노드 정리하기',
selectNextStep: '다음 단계 선택',
changeBlock: '노드 변경',
addNextStep: '이 워크플로우에 다음 단계를 추가하세요.',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Ustaw zmienną',
needConnectTip: 'Ten krok nie jest połączony z niczym',
maxTreeDepth: 'Maksymalny limit {{depth}} węzłów na gałąź',
needEndNode: 'Należy dodać blok końcowy',
needAnswerNode: 'Należy dodać blok odpowiedzi',
workflowProcess: 'Proces przepływu pracy',
notRunning: 'Jeszcze nie uruchomiono',
previewPlaceholder: 'Wprowadź treść w poniższym polu, aby rozpocząć debugowanie Chatbota',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Dowiedz się więcej',
copy: 'Kopiuj',
duplicate: 'Duplikuj',
addBlock: 'Dodaj blok',
pasteHere: 'Wklej tutaj',
pointerMode: 'Tryb wskaźnika',
handMode: 'Tryb ręczny',
@ -115,6 +112,9 @@ const translation = {
exportPNG: 'Eksportuj jako PNG',
publishUpdate: 'Opublikuj aktualizację',
referenceVar: 'Zmienna odniesienia',
addBlock: 'Dodaj węzeł',
needEndNode: 'Należy dodać węzeł końcowy',
needAnswerNode: 'Węzeł odpowiedzi musi zostać dodany',
},
env: {
envPanelTitle: 'Zmienne Środowiskowe',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} kroki do przodu',
sessionStart: 'Początek sesji',
currentState: 'Aktualny stan',
nodeTitleChange: 'Tytuł bloku zmieniony',
nodeDescriptionChange: 'Opis bloku zmieniony',
nodeDragStop: 'Blok przeniesiony',
nodeChange: 'Blok zmieniony',
nodeConnect: 'Blok połączony',
nodePaste: 'Blok wklejony',
nodeDelete: 'Blok usunięty',
nodeAdd: 'Blok dodany',
nodeResize: 'Notatka zmieniona',
noteAdd: 'Notatka dodana',
noteChange: 'Notatka zmieniona',
noteDelete: 'Notatka usunięta',
edgeDelete: 'Blok rozłączony',
edgeDelete: 'Węzeł rozłączony',
nodeAdd: 'Węzeł dodany',
nodePaste: 'Węzeł wklejony',
nodeChange: 'Węzeł zmieniony',
nodeDelete: 'Węzeł usunięty',
nodeResize: 'Węzeł zmieniony rozmiar',
nodeConnect: 'Węzeł połączony',
nodeTitleChange: 'Tytuł węzła zmieniony',
nodeDescriptionChange: 'Opis węzła zmieniony',
nodeDragStop: 'Węzeł przeniesiony',
},
errorMsg: {
fieldRequired: '{{field}} jest wymagane',
@ -217,8 +217,6 @@ const translation = {
loop: 'Pętla',
},
tabs: {
'searchBlock': 'Szukaj bloku',
'blocks': 'Bloki',
'tools': 'Narzędzia',
'allTool': 'Wszystkie',
'builtInTool': 'Wbudowane',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Wyszukiwarka',
'agent': 'Strategia agenta',
'plugin': 'Wtyczka',
'searchBlock': 'Wyszukaj węzeł',
'blocks': 'Węzły',
},
blocks: {
'start': 'Start',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Pole wprowadzania użytkownika',
changeBlock: 'Zmień blok',
helpLink: 'Link do pomocy',
about: 'O',
createdBy: 'Stworzone przez ',
nextStep: 'Następny krok',
addNextStep: 'Dodaj następny blok w tym przepływie pracy',
selectNextStep: 'Wybierz następny blok',
runThisStep: 'Uruchom ten krok',
checklist: 'Lista kontrolna',
checklistTip: 'Upewnij się, że wszystkie problemy zostały rozwiązane przed opublikowaniem',
checklistResolved: 'Wszystkie problemy zostały rozwiązane',
organizeBlocks: 'Organizuj bloki',
change: 'Zmień',
optional: '(opcjonalne)',
moveToThisNode: 'Przenieś do tego węzła',
selectNextStep: 'Wybierz następny krok',
addNextStep: 'Dodaj następny krok w tym procesie roboczym',
changeBlock: 'Zmień węzeł',
organizeBlocks: 'Organizuj węzły',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Definir valor da variável',
needConnectTip: 'Este passo não está conectado a nada',
maxTreeDepth: 'Limite máximo de {{depth}} nós por ramo',
needEndNode: 'O bloco de fim deve ser adicionado',
needAnswerNode: 'O bloco de resposta deve ser adicionado',
workflowProcess: 'Processo de fluxo de trabalho',
notRunning: 'Ainda não está em execução',
previewPlaceholder: 'Digite o conteúdo na caixa abaixo para começar a depurar o Chatbot',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Saiba mais',
copy: 'Copiar',
duplicate: 'Duplicar',
addBlock: 'Adicionar bloco',
pasteHere: 'Colar aqui',
pointerMode: 'Modo ponteiro',
handMode: 'Modo mão',
@ -115,6 +112,9 @@ const translation = {
exitVersions: 'Versões de Sair',
exportSVG: 'Exportar como SVG',
exportJPEG: 'Exportar como JPEG',
addBlock: 'Adicionar Nó',
needEndNode: 'O nó de Fim deve ser adicionado',
needAnswerNode: 'O nó de resposta deve ser adicionado',
},
env: {
envPanelTitle: 'Variáveis de Ambiente',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} passos para frente',
sessionStart: 'Início da sessão',
currentState: 'Estado atual',
nodeTitleChange: 'Título do bloco alterado',
nodeDescriptionChange: 'Descrição do bloco alterada',
nodeDragStop: 'Bloco movido',
nodeChange: 'Bloco alterado',
nodeConnect: 'Bloco conectado',
nodePaste: 'Bloco colado',
nodeDelete: 'Bloco excluído',
nodeAdd: 'Bloco adicionado',
nodeResize: 'Nota redimensionada',
noteAdd: 'Nota adicionada',
noteChange: 'Nota alterada',
noteDelete: 'Conexão excluída',
edgeDelete: 'Bloco desconectado',
nodeConnect: 'Nó conectado',
nodeDelete: 'Nó deletado',
nodePaste: 'Nó colado',
nodeTitleChange: 'Título do nó alterado',
nodeAdd: 'Nó adicionado',
nodeDescriptionChange: 'Descrição do nó alterada',
edgeDelete: 'Nó desconectado',
nodeResize: 'Nó redimensionado',
nodeChange: 'Nó alterado',
nodeDragStop: 'Nó movido',
},
errorMsg: {
fieldRequired: '{{field}} é obrigatório',
@ -217,8 +217,6 @@ const translation = {
loop: 'Laço',
},
tabs: {
'searchBlock': 'Buscar bloco',
'blocks': 'Blocos',
'tools': 'Ferramentas',
'allTool': 'Todos',
'builtInTool': 'Integrado',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Ferramenta de pesquisa',
'plugin': 'Plug-in',
'agent': 'Estratégia do agente',
'blocks': 'Nodos',
'searchBlock': 'Nó de busca',
},
blocks: {
'start': 'Iniciar',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Campo de entrada do usuário',
changeBlock: 'Mudar bloco',
helpLink: 'Link de ajuda',
about: 'Sobre',
createdBy: 'Criado por ',
nextStep: 'Próximo passo',
addNextStep: 'Adicionar o próximo bloco neste fluxo de trabalho',
selectNextStep: 'Selecionar próximo bloco',
runThisStep: 'Executar este passo',
checklist: 'Lista de verificação',
checklistTip: 'Certifique-se de que todos os problemas foram resolvidos antes de publicar',
checklistResolved: 'Todos os problemas foram resolvidos',
organizeBlocks: 'Organizar blocos',
change: 'Mudar',
optional: '(opcional)',
moveToThisNode: 'Mova-se para este nó',
changeBlock: 'Mudar Nó',
addNextStep: 'Adicione o próximo passo neste fluxo de trabalho',
organizeBlocks: 'Organizar nós',
selectNextStep: 'Selecione o próximo passo',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Setează valoarea variabilei',
needConnectTip: 'Acest pas nu este conectat la nimic',
maxTreeDepth: 'Limită maximă de {{depth}} noduri pe ramură',
needEndNode: 'Trebuie adăugat blocul de sfârșit',
needAnswerNode: 'Trebuie adăugat blocul de răspuns',
workflowProcess: 'Proces de flux de lucru',
notRunning: 'Încă nu rulează',
previewPlaceholder: 'Introduceți conținutul în caseta de mai jos pentru a începe depanarea Chatbotului',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Află mai multe',
copy: 'Copiază',
duplicate: 'Duplică',
addBlock: 'Adaugă bloc',
pasteHere: 'Lipește aici',
pointerMode: 'Modul pointer',
handMode: 'Modul mână',
@ -115,6 +112,9 @@ const translation = {
publishUpdate: 'Publicați actualizarea',
referenceVar: 'Variabilă de referință',
exportJPEG: 'Exportă ca JPEG',
addBlock: 'Adaugă nod',
needAnswerNode: 'Nodul de răspuns trebuie adăugat',
needEndNode: 'Nodul de sfârșit trebuie adăugat',
},
env: {
envPanelTitle: 'Variabile de Mediu',
@ -176,19 +176,18 @@ const translation = {
stepForward_other: '{{count}} pași înainte',
sessionStart: 'Începutul sesiuni',
currentState: 'Stare actuală',
nodeTitleChange: 'Titlul blocului a fost schimbat',
nodeDescriptionChange: 'Descrierea blocului a fost schimbată',
nodeDragStop: 'Bloc mutat',
nodeChange: 'Bloc schimbat',
nodeConnect: 'Bloc conectat',
nodePaste: 'Bloc lipit',
nodeDelete: 'Bloc șters',
nodeAdd: 'Bloc adăugat',
nodeResize: 'Bloc redimensionat',
noteAdd: 'Notă adăugată',
noteChange: 'Notă modificată',
noteDelete: 'Notă ștearsă',
edgeDelete: 'Bloc deconectat',
nodeResize: 'Nod redimensionat',
nodeConnect: 'Nod conectat',
nodeTitleChange: 'Titlul nodului a fost schimbat',
nodeChange: 'Nodul s-a schimbat',
nodePaste: 'Node lipit',
nodeDelete: 'Nod șters',
nodeDescriptionChange: 'Descrierea nodului a fost modificată',
edgeDelete: 'Nod deconectat',
nodeAdd: 'Nod adăugat',
},
errorMsg: {
fieldRequired: '{{field}} este obligatoriu',
@ -217,8 +216,6 @@ const translation = {
loop: 'Loop',
},
tabs: {
'searchBlock': 'Caută bloc',
'blocks': 'Blocuri',
'tools': 'Instrumente',
'allTool': 'Toate',
'builtInTool': 'Integrat',
@ -232,6 +229,8 @@ const translation = {
'searchTool': 'Instrument de căutare',
'agent': 'Strategia agentului',
'plugin': 'Plugin',
'blocks': 'Noduri',
'searchBlock': 'Căutare nod',
},
blocks: {
'start': 'Începe',
@ -288,21 +287,21 @@ const translation = {
},
panel: {
userInputField: 'Câmp de introducere utilizator',
changeBlock: 'Schimbă blocul',
helpLink: 'Link de ajutor',
about: 'Despre',
createdBy: 'Creat de ',
nextStep: 'Pasul următor',
addNextStep: 'Adăugați următorul bloc în acest flux de lucru',
selectNextStep: 'Selectați următorul bloc',
runThisStep: 'Rulează acest pas',
checklist: 'Lista de verificare',
checklistTip: 'Asigurați-vă că toate problemele sunt rezolvate înainte de publicare',
checklistResolved: 'Toate problemele au fost rezolvate',
organizeBlocks: 'Organizează blocurile',
change: 'Schimbă',
optional: '(opțional)',
moveToThisNode: 'Mutați la acest nod',
organizeBlocks: 'Organizează nodurile',
addNextStep: 'Adăugați următorul pas în acest flux de lucru',
changeBlock: 'Schimbă nodul',
selectNextStep: 'Selectați Pasul Următor',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Установить значение переменной',
needConnectTip: 'Этот шаг ни к чему не подключен',
maxTreeDepth: 'Максимальный предел {{depth}} узлов на ветку',
needEndNode: 'Необходимо добавить блок "Конец"',
needAnswerNode: 'Необходимо добавить блок "Ответ"',
workflowProcess: 'Процесс рабочего процесса',
notRunning: 'Еще не запущено',
previewPlaceholder: 'Введите текст в поле ниже, чтобы начать отладку чат-бота',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Узнать больше',
copy: 'Копировать',
duplicate: 'Дублировать',
addBlock: 'Добавить блок',
pasteHere: 'Вставить сюда',
pointerMode: 'Режим указателя',
handMode: 'Режим руки',
@ -115,6 +112,9 @@ const translation = {
exitVersions: 'Выходные версии',
exportSVG: 'Экспортировать как SVG',
publishUpdate: 'Опубликовать обновление',
addBlock: 'Добавить узел',
needAnswerNode: 'В узел ответа необходимо добавить',
needEndNode: 'Узел конца должен быть добавлен',
},
env: {
envPanelTitle: 'Переменные среды',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} шагов вперед',
sessionStart: 'Начало сеанса',
currentState: 'Текущее состояние',
nodeTitleChange: 'Изменено название блока',
nodeDescriptionChange: 'Изменено описание блока',
nodeDragStop: 'Блок перемещен',
nodeChange: 'Блок изменен',
nodeConnect: 'Блок подключен',
nodePaste: 'Блок вставлен',
nodeDelete: 'Блок удален',
nodeAdd: 'Блок добавлен',
nodeResize: 'Размер блока изменен',
noteAdd: 'Заметка добавлена',
noteChange: 'Заметка изменена',
noteDelete: 'Заметка удалена',
edgeDelete: 'Блок отключен',
nodeDragStop: 'Узел перемещен',
nodeResize: 'Узел изменен в размере',
nodeTitleChange: 'Название узла изменено',
edgeDelete: 'Узел отключен',
nodeConnect: 'Узел подключен',
nodeDelete: 'Узел удален',
nodePaste: 'Узел вставлен',
nodeChange: 'Узел изменен',
nodeAdd: 'Узел добавлен',
nodeDescriptionChange: 'Описание узла изменено',
},
errorMsg: {
fieldRequired: '{{field}} обязательно для заполнения',
@ -217,8 +217,6 @@ const translation = {
loop: 'Цикл',
},
tabs: {
'searchBlock': 'Поиск блока',
'blocks': 'Блоки',
'searchTool': 'Поиск инструмента',
'tools': 'Инструменты',
'allTool': 'Все',
@ -232,6 +230,8 @@ const translation = {
'noResult': 'Ничего не найдено',
'plugin': 'Плагин',
'agent': 'Агентская стратегия',
'blocks': 'Узлы',
'searchBlock': 'Поиск узла',
},
blocks: {
'start': 'Начало',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Поле ввода пользователя',
changeBlock: 'Изменить блок',
helpLink: 'Ссылка на справку',
about: 'О программе',
createdBy: 'Создано ',
nextStep: 'Следующий шаг',
addNextStep: 'Добавить следующий блок в этот рабочий процесс',
selectNextStep: 'Выбрать следующий блок',
runThisStep: 'Выполнить этот шаг',
checklist: 'Контрольный список',
checklistTip: 'Убедитесь, что все проблемы решены перед публикацией',
checklistResolved: 'Все проблемы решены',
organizeBlocks: 'Организовать блоки',
change: 'Изменить',
optional: '(необязательно)',
moveToThisNode: 'Перейдите к этому узлу',
selectNextStep: 'Выберите следующий шаг',
organizeBlocks: 'Организовать узлы',
addNextStep: 'Добавьте следующий шаг в этот рабочий процесс',
changeBlock: 'Изменить узел',
},
nodes: {
common: {

File diff suppressed because it is too large Load Diff

View File

@ -42,8 +42,6 @@ const translation = {
setVarValuePlaceholder: 'ตั้งค่าตัวแปร',
needConnectTip: 'ขั้นตอนนี้ไม่ได้เชื่อมต่อกับสิ่งใด',
maxTreeDepth: 'ขีดจํากัดสูงสุดของ {{depth}} โหนดต่อสาขา',
needEndNode: 'ต้องเพิ่มบล็อก End',
needAnswerNode: 'ต้องเพิ่มบล็อกคําตอบ',
workflowProcess: 'กระบวนการเวิร์กโฟลว์',
notRunning: 'ยังไม่ได้ทํางาน',
previewPlaceholder: 'ป้อนเนื้อหาในช่องด้านล่างเพื่อเริ่มแก้ไขข้อบกพร่องของแชทบอท',
@ -62,7 +60,6 @@ const translation = {
learnMore: 'ศึกษาเพิ่มเติม',
copy: 'ลอก',
duplicate: 'สำเนา',
addBlock: 'เพิ่มบล็อก',
pasteHere: 'วางที่นี่',
pointerMode: 'โหมดตัวชี้',
handMode: 'โหมดมือ',
@ -115,6 +112,9 @@ const translation = {
exitVersions: 'ออกเวอร์ชัน',
exportImage: 'ส่งออกภาพ',
exportSVG: 'ส่งออกเป็น SVG',
needAnswerNode: 'ต้องเพิ่มโหนดคำตอบ',
addBlock: 'เพิ่มโนด',
needEndNode: 'ต้องเพิ่มโหนดจบ',
},
env: {
envPanelTitle: 'ตัวแปรสภาพแวดล้อม',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} ก้าวไปข้างหน้า',
sessionStart: 'เริ่มเซสชัน',
currentState: 'สถานะปัจจุบัน',
nodeTitleChange: 'เปลี่ยนชื่อบล็อก',
nodeDescriptionChange: 'คําอธิบายบล็อกเปลี่ยนไป',
nodeDragStop: 'บล็อกย้าย',
nodeChange: 'บล็อกเปลี่ยนไป',
nodeConnect: 'บล็อกเชื่อมต่อ',
nodePaste: 'บล็อกวาง',
nodeDelete: 'บล็อกลบ',
nodeAdd: 'เพิ่มบล็อก',
nodeResize: 'บล็อกปรับขนาด',
noteAdd: 'เพิ่มหมายเหตุ',
noteChange: 'เปลี่ยนหมายเหตุ',
noteDelete: 'ลบโน้ต',
edgeDelete: 'บล็อกตัดการเชื่อมต่อ',
nodeDelete: 'โหนดถูกลบแล้ว',
nodeDescriptionChange: 'คำอธิบายของโหนดถูกเปลี่ยน',
nodeDragStop: 'โหนดถูกย้าย',
edgeDelete: 'เชื่อมต่อ Node ขาดหาย',
nodeTitleChange: 'ชื่อโหนดเปลี่ยน',
nodeAdd: 'เพิ่มโนด',
nodeChange: 'โหนดเปลี่ยนแปลง',
nodeResize: 'ขนาดของโหนดถูกปรับขนาด',
nodeConnect: 'เชื่อมต่อ Node',
nodePaste: 'โนดที่วางไว้',
},
errorMsg: {
fieldRequired: '{{field}} เป็นสิ่งจําเป็น',
@ -217,8 +217,6 @@ const translation = {
loop: 'ลูป',
},
tabs: {
'searchBlock': 'บล็อกการค้นหา',
'blocks': 'บล็อก',
'searchTool': 'เครื่องมือค้นหา',
'tools': 'เครื่อง มือ',
'allTool': 'ทั้งหมด',
@ -232,6 +230,8 @@ const translation = {
'noResult': 'ไม่พบการจับคู่',
'agent': 'กลยุทธ์ตัวแทน',
'plugin': 'ปลั๊กอิน',
'searchBlock': 'ค้นหาโหนด',
'blocks': 'โหนด',
},
blocks: {
'start': 'เริ่ม',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'ฟิลด์ป้อนข้อมูลของผู้ใช้',
changeBlock: 'เปลี่ยนบล็อก',
helpLink: 'ลิงค์ช่วยเหลือ',
about: 'ประมาณ',
createdBy: 'สร้างโดย',
nextStep: 'ขั้นตอนถัดไป',
addNextStep: 'เพิ่มบล็อกถัดไปในเวิร์กโฟลว์นี้',
selectNextStep: 'เลือกบล็อกถัดไป',
runThisStep: 'เรียกใช้ขั้นตอนนี้',
checklist: 'ตรวจ สอบ',
checklistTip: 'ตรวจสอบให้แน่ใจว่าปัญหาทั้งหมดได้รับการแก้ไขแล้วก่อนที่จะเผยแพร่',
checklistResolved: 'ปัญหาทั้งหมดได้รับการแก้ไขแล้ว',
organizeBlocks: 'จัดระเบียบบล็อก',
change: 'เปลี่ยน',
optional: '(ไม่บังคับ)',
moveToThisNode: 'ย้ายไปที่โหนดนี้',
organizeBlocks: 'จัดระเบียบโหนด',
addNextStep: 'เพิ่มขั้นตอนถัดไปในกระบวนการทำงานนี้',
changeBlock: 'เปลี่ยนโหนด',
selectNextStep: 'เลือกขั้นตอนถัดไป',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Değişkeni ayarla',
needConnectTip: 'Bu adım hiçbir şeye bağlı değil',
maxTreeDepth: 'Her dal için maksimum {{depth}} düğüm limiti',
needEndNode: 'Son blok eklenmelidir',
needAnswerNode: 'Yanıt bloğu eklenmelidir',
workflowProcess: 'Workflow Süreci',
notRunning: 'Henüz çalıştırılmadı',
previewPlaceholder: 'Sohbet Robotunu hata ayıklamak için aşağıdaki kutuya içerik girin',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Daha Fazla Bilgi',
copy: 'Kopyala',
duplicate: 'Çoğalt',
addBlock: 'Blok Ekle',
pasteHere: 'Buraya Yapıştır',
pointerMode: 'İşaretçi Modu',
handMode: 'El Modu',
@ -115,6 +112,9 @@ const translation = {
noExist: 'Böyle bir değişken yok',
exportSVG: 'SVG olarak dışa aktar',
referenceVar: 'Referans Değişken',
addBlock: 'Düğüm Ekle',
needAnswerNode: 'Cevap düğümü eklenmelidir.',
needEndNode: 'Son düğüm eklenmelidir',
},
env: {
envPanelTitle: 'Çevre Değişkenleri',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} adım ileri',
sessionStart: 'Oturum Başladı',
currentState: 'Geçerli Durum',
nodeTitleChange: 'Blok başlığı değiştirildi',
nodeDescriptionChange: 'Blok açıklaması değiştirildi',
nodeDragStop: 'Blok taşındı',
nodeChange: 'Blok değiştirildi',
nodeConnect: 'Blok bağlandı',
nodePaste: 'Blok yapıştırıldı',
nodeDelete: 'Blok silindi',
nodeAdd: 'Blok eklendi',
nodeResize: 'Blok yeniden boyutlandırıldı',
noteAdd: 'Not eklendi',
noteChange: 'Not değiştirildi',
noteDelete: 'Not silindi',
edgeDelete: 'Blok bağlantısı kesildi',
nodeDragStop: 'Düğüm taşındı',
nodeConnect: 'Node bağlandı',
nodeDescriptionChange: 'Düğüm açıklaması değiştirildi',
edgeDelete: 'Düğüm bağlantısı kesildi',
nodeChange: 'Düğüm değişti',
nodeDelete: 'Düğüm silindi',
nodeResize: 'Düğüm boyutu değiştirildi',
nodeTitleChange: 'Düğüm başlığı değiştirildi',
nodeAdd: 'Düğüm eklendi',
nodePaste: 'Düğüm yapıştırıldı',
},
errorMsg: {
fieldRequired: '{{field}} gereklidir',
@ -217,8 +217,6 @@ const translation = {
loop: 'Döngü',
},
tabs: {
'searchBlock': 'Blok ara',
'blocks': 'Bloklar',
'tools': 'Araçlar',
'allTool': 'Hepsi',
'builtInTool': 'Yerleşik',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Arama aracı',
'agent': 'Temsilci Stratejisi',
'plugin': 'Eklenti',
'blocks': 'Düğümler',
'searchBlock': 'Arama düğümü',
},
blocks: {
'start': 'Başlat',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Kullanıcı Giriş Alanı',
changeBlock: 'Blok Değiştir',
helpLink: 'Yardım Linki',
about: 'Hakkında',
createdBy: 'Oluşturan: ',
nextStep: 'Sonraki Adım',
addNextStep: 'Bu iş akışında sonraki bloğu ekleyin',
selectNextStep: 'Sonraki Bloğu Seç',
runThisStep: 'Bu adımı çalıştır',
checklist: 'Kontrol Listesi',
checklistTip: 'Yayınlamadan önce tüm sorunların çözüldüğünden emin olun',
checklistResolved: 'Tüm sorunlar çözüldü',
organizeBlocks: 'Blokları Düzenle',
change: 'Değiştir',
optional: '(isteğe bağlı)',
moveToThisNode: 'Bu düğüme geç',
changeBlock: 'Düğümü Değiştir',
addNextStep: 'Bu iş akışına bir sonraki adımı ekleyin',
organizeBlocks: 'Düğümleri düzenle',
selectNextStep: 'Sonraki Adımı Seç',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Встановити значення змінної',
needConnectTip: 'Цей крок ні до чого не підключений',
maxTreeDepth: 'Максимальний ліміт {{depth}} вузлів на гілку',
needEndNode: 'Потрібно додати кінцевий блок',
needAnswerNode: 'Потрібно додати блок відповіді',
workflowProcess: 'Процес робочого потоку',
notRunning: 'Ще не запущено',
previewPlaceholder: 'Введіть вміст у поле нижче, щоб розпочати налагодження чат-бота',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Дізнатися більше',
copy: 'Копіювати',
duplicate: 'Дублювати',
addBlock: 'Додати блок',
pasteHere: 'Вставити сюди',
pointerMode: 'Режим вказівника',
handMode: 'Ручний режим',
@ -115,6 +112,9 @@ const translation = {
exportImage: 'Експорт зображення',
exportSVG: 'Експортувати як SVG',
exportJPEG: 'Експортувати як JPEG',
addBlock: 'Додати вузол',
needEndNode: 'Необхідно додати кінцевий вузол',
needAnswerNode: 'Вузол Відповіді повинен бути доданий',
},
env: {
envPanelTitle: 'Змінні середовища',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} кроки вперед',
sessionStart: 'Початок сесії',
currentState: 'Поточний стан',
nodeTitleChange: 'Назву блоку змінено',
nodeDescriptionChange: 'Опис блоку змінено',
nodeDragStop: 'Блок переміщено',
nodeChange: 'Блок змінено',
nodeConnect: 'Блок підключено',
nodePaste: 'Блок вставлено',
nodeDelete: 'Блок видалено',
nodeAdd: 'Блок додано',
nodeResize: 'Розмір блоку змінено',
noteAdd: 'Додано нотатку',
noteChange: 'Нотатку змінено',
noteDelete: 'Нотатку видалено',
edgeDelete: 'Блок відключено',
nodeTitleChange: 'Заголовок вузла змінено',
nodeResize: 'Вузол змінив розмір',
nodePaste: 'Вузол вставлений',
nodeDelete: 'Вузол видалено',
nodeDragStop: 'Вузол переміщено',
edgeDelete: 'Вузол відключено',
nodeChange: 'Вузол змінився',
nodeAdd: 'Додано вузол',
nodeDescriptionChange: 'Опис вузла змінено',
nodeConnect: 'Вузол підключено',
},
errorMsg: {
fieldRequired: '{{field}} є обов\'язковим',
@ -217,8 +217,6 @@ const translation = {
loop: 'Петля',
},
tabs: {
'searchBlock': 'Пошук блоку',
'blocks': 'Блоки',
'tools': 'Інструменти',
'allTool': 'Усі',
'builtInTool': 'Вбудовані',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Інструмент пошуку',
'plugin': 'Плагін',
'agent': 'Стратегія агента',
'blocks': 'Вузли',
'searchBlock': 'Пошуковий вузол',
},
blocks: {
'start': 'Початок',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Поле введення користувача',
changeBlock: 'Змінити блок',
helpLink: 'Посилання на допомогу',
about: 'Про',
createdBy: 'Створено ',
nextStep: 'Наступний крок',
addNextStep: 'Додати наступний блок у цей робочий потік',
selectNextStep: 'Вибрати наступний блок',
runThisStep: 'Запустити цей крок',
checklist: 'Контрольний список',
checklistTip: 'Переконайтеся, що всі проблеми вирішені перед публікацією',
checklistResolved: 'Всі проблеми вирішені',
organizeBlocks: 'Організувати блоки',
change: 'Змінити',
optional: '(необов\'язково)',
moveToThisNode: 'Перемістіть до цього вузла',
organizeBlocks: 'Організуйте вузли',
changeBlock: 'Змінити вузол',
selectNextStep: 'Виберіть наступний крок',
addNextStep: 'Додайте наступний крок у цей робочий процес',
},
nodes: {
common: {

View File

@ -38,8 +38,6 @@ const translation = {
setVarValuePlaceholder: 'Đặt giá trị biến',
needConnectTip: 'Bước này không được kết nối với bất kỳ điều gì',
maxTreeDepth: 'Giới hạn tối đa {{depth}} nút trên mỗi nhánh',
needEndNode: 'Phải thêm khối Kết thúc',
needAnswerNode: 'Phải thêm khối Trả lời',
workflowProcess: 'Quy trình làm việc',
notRunning: 'Chưa chạy',
previewPlaceholder: 'Nhập nội dung vào hộp bên dưới để bắt đầu gỡ lỗi Chatbot',
@ -58,7 +56,6 @@ const translation = {
learnMore: 'Tìm hiểu thêm',
copy: 'Sao chép',
duplicate: 'Nhân bản',
addBlock: 'Thêm khối',
pasteHere: 'Dán vào đây',
pointerMode: 'Chế độ con trỏ',
handMode: 'Chế độ tay',
@ -115,6 +112,9 @@ const translation = {
noExist: 'Không có biến như vậy',
exportJPEG: 'Xuất dưới dạng JPEG',
referenceVar: 'Biến tham chiếu',
needAnswerNode: 'Nút Trả lời phải được thêm vào',
addBlock: 'Thêm Node',
needEndNode: 'Nút Kết thúc phải được thêm vào',
},
env: {
envPanelTitle: 'Biến Môi Trường',
@ -176,19 +176,19 @@ const translation = {
stepForward_other: '{{count}} bước tiến',
sessionStart: 'Bắt đầu phiên',
currentState: 'Trạng thái hiện tại',
nodeTitleChange: 'Tiêu đề khối đã thay đổi',
nodeDescriptionChange: 'Mô tả khối đã thay đổi',
nodeDragStop: 'Khối đã di chuyển',
nodeChange: 'Khối đã thay đổi',
nodeConnect: 'Khối đã kết nối',
nodePaste: 'Khối đã dán',
nodeDelete: 'Khối đã xóa',
nodeAdd: 'Khối đã thêm',
nodeResize: 'Khối đã thay đổi kích thước',
noteAdd: 'Ghi chú đã thêm',
noteChange: 'Ghi chú đã thay đổi',
noteDelete: 'Ghi chú đã xóa',
edgeDelete: 'Khối đã ngắt kết nối',
nodeAdd: 'Đã thêm nút',
nodeChange: 'Node đã thay đổi',
nodeDescriptionChange: 'Mô tả nút đã thay đổi',
nodeTitleChange: 'Tiêu đề nút đã được thay đổi',
nodeDelete: 'Nút đã bị xóa',
nodeDragStop: 'Nút đã được di chuyển',
nodeConnect: 'Nút đã kết nối',
nodeResize: 'Kích thước nút đã được thay đổi',
nodePaste: 'Node đã dán',
edgeDelete: 'Nút đã bị ngắt kết nối',
},
errorMsg: {
fieldRequired: '{{field}} là bắt buộc',
@ -217,8 +217,6 @@ const translation = {
loop: 'Vòng',
},
tabs: {
'searchBlock': 'Tìm kiếm khối',
'blocks': 'Khối',
'tools': 'Công cụ',
'allTool': 'Tất cả',
'builtInTool': 'Tích hợp sẵn',
@ -232,6 +230,8 @@ const translation = {
'searchTool': 'Công cụ tìm kiếm',
'agent': 'Chiến lược đại lý',
'plugin': 'Plugin',
'blocks': 'Nút',
'searchBlock': 'Tìm kiếm nút',
},
blocks: {
'start': 'Bắt đầu',
@ -288,21 +288,21 @@ const translation = {
},
panel: {
userInputField: 'Trường đầu vào của người dùng',
changeBlock: 'Thay đổi khối',
helpLink: 'Liên kết trợ giúp',
about: 'Giới thiệu',
createdBy: 'Tạo bởi ',
nextStep: 'Bước tiếp theo',
addNextStep: 'Thêm khối tiếp theo trong quy trình làm việc này',
selectNextStep: 'Chọn khối tiếp theo',
runThisStep: 'Chạy bước này',
checklist: 'Danh sách kiểm tra',
checklistTip: 'Đảm bảo rằng tất cả các vấn đề đã được giải quyết trước khi xuất bản',
checklistResolved: 'Tất cả các vấn đề đã được giải quyết',
organizeBlocks: 'Tổ chức các khối',
change: 'Thay đổi',
optional: '(tùy chọn)',
moveToThisNode: 'Di chuyển đến nút này',
changeBlock: 'Thay đổi Node',
selectNextStep: 'Chọn bước tiếp theo',
organizeBlocks: 'Tổ chức các nút',
addNextStep: 'Thêm bước tiếp theo trong quy trình này',
},
nodes: {
common: {

View File

@ -1,6 +1,6 @@
{
"name": "dify-web",
"version": "1.4.2",
"version": "1.4.3",
"private": true,
"engines": {
"node": ">=v22.11.0"