| @@ -30,7 +30,7 @@ prepare-web: | |||
| prepare-api: | |||
| @echo "🔧 Setting up API environment..." | |||
| @cp -n api/.env.example api/.env 2>/dev/null || echo "API .env already exists" | |||
| @cd api && uv sync --dev --extra all | |||
| @cd api && uv sync --dev | |||
| @cd api && uv run flask db upgrade | |||
| @echo "✅ API environment prepared (not started)" | |||
| @@ -75,6 +75,7 @@ DB_PASSWORD=difyai123456 | |||
| DB_HOST=localhost | |||
| DB_PORT=5432 | |||
| DB_DATABASE=dify | |||
| SQLALCHEMY_POOL_PRE_PING=true | |||
| # Storage configuration | |||
| # use for store upload files, private keys... | |||
| @@ -2,7 +2,7 @@ from functools import wraps | |||
| from typing import cast | |||
| import flask_login | |||
| from flask import request | |||
| from flask import jsonify, request | |||
| from flask_restx import Resource, reqparse | |||
| from werkzeug.exceptions import BadRequest, NotFound | |||
| @@ -46,23 +46,38 @@ def oauth_server_access_token_required(view): | |||
| authorization_header = request.headers.get("Authorization") | |||
| if not authorization_header: | |||
| raise BadRequest("Authorization header is required") | |||
| response = jsonify({"error": "Authorization header is required"}) | |||
| response.status_code = 401 | |||
| response.headers["WWW-Authenticate"] = "Bearer" | |||
| return response | |||
| parts = authorization_header.strip().split(" ") | |||
| parts = authorization_header.strip().split(None, 1) | |||
| if len(parts) != 2: | |||
| raise BadRequest("Invalid Authorization header format") | |||
| response = jsonify({"error": "Invalid Authorization header format"}) | |||
| response.status_code = 401 | |||
| response.headers["WWW-Authenticate"] = "Bearer" | |||
| return response | |||
| token_type = parts[0].strip() | |||
| if token_type.lower() != "bearer": | |||
| raise BadRequest("token_type is invalid") | |||
| response = jsonify({"error": "token_type is invalid"}) | |||
| response.status_code = 401 | |||
| response.headers["WWW-Authenticate"] = "Bearer" | |||
| return response | |||
| access_token = parts[1].strip() | |||
| if not access_token: | |||
| raise BadRequest("access_token is required") | |||
| response = jsonify({"error": "access_token is required"}) | |||
| response.status_code = 401 | |||
| response.headers["WWW-Authenticate"] = "Bearer" | |||
| return response | |||
| account = OAuthServerService.validate_oauth_access_token(oauth_provider_app.client_id, access_token) | |||
| if not account: | |||
| raise BadRequest("access_token or client_id is invalid") | |||
| response = jsonify({"error": "access_token or client_id is invalid"}) | |||
| response.status_code = 401 | |||
| response.headers["WWW-Authenticate"] = "Bearer" | |||
| return response | |||
| kwargs["account"] = account | |||
| @@ -305,7 +305,7 @@ class AdvancedChatAppGenerateTaskPipeline: | |||
| err = self._base_task_pipeline._handle_error(event=event, session=session, message_id=self._message_id) | |||
| yield self._base_task_pipeline._error_to_stream_response(err) | |||
| def _handle_workflow_started_event(self, **kwargs) -> Generator[StreamResponse, None, None]: | |||
| def _handle_workflow_started_event(self, *args, **kwargs) -> Generator[StreamResponse, None, None]: | |||
| """Handle workflow started events.""" | |||
| with self._database_session() as session: | |||
| workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start() | |||
| @@ -410,10 +410,9 @@ class ProviderConfiguration(BaseModel): | |||
| :return: | |||
| """ | |||
| with Session(db.engine) as session: | |||
| if credential_name and self._check_provider_credential_name_exists( | |||
| credential_name=credential_name, session=session | |||
| ): | |||
| raise ValueError(f"Credential with name '{credential_name}' already exists.") | |||
| if credential_name: | |||
| if self._check_provider_credential_name_exists(credential_name=credential_name, session=session): | |||
| raise ValueError(f"Credential with name '{credential_name}' already exists.") | |||
| else: | |||
| credential_name = self._generate_provider_credential_name(session) | |||
| @@ -891,10 +890,11 @@ class ProviderConfiguration(BaseModel): | |||
| :return: | |||
| """ | |||
| with Session(db.engine) as session: | |||
| if credential_name and self._check_custom_model_credential_name_exists( | |||
| model=model, model_type=model_type, credential_name=credential_name, session=session | |||
| ): | |||
| raise ValueError(f"Model credential with name '{credential_name}' already exists for {model}.") | |||
| if credential_name: | |||
| if self._check_custom_model_credential_name_exists( | |||
| model=model, model_type=model_type, credential_name=credential_name, session=session | |||
| ): | |||
| raise ValueError(f"Model credential with name '{credential_name}' already exists for {model}.") | |||
| else: | |||
| credential_name = self._generate_custom_model_credential_name( | |||
| model=model, model_type=model_type, session=session | |||
| @@ -1,7 +1,7 @@ | |||
| import os | |||
| from collections import OrderedDict | |||
| from collections.abc import Callable | |||
| from typing import Any | |||
| from typing import TypeVar | |||
| from configs import dify_config | |||
| from core.tools.utils.yaml_utils import load_yaml_file | |||
| @@ -72,11 +72,14 @@ def pin_position_map(original_position_map: dict[str, int], pin_list: list[str]) | |||
| return position_map | |||
| T = TypeVar("T") | |||
| def is_filtered( | |||
| include_set: set[str], | |||
| exclude_set: set[str], | |||
| data: Any, | |||
| name_func: Callable[[Any], str], | |||
| data: T, | |||
| name_func: Callable[[T], str], | |||
| ) -> bool: | |||
| """ | |||
| Check if the object should be filtered out. | |||
| @@ -103,9 +106,9 @@ def is_filtered( | |||
| def sort_by_position_map( | |||
| position_map: dict[str, int], | |||
| data: list[Any], | |||
| name_func: Callable[[Any], str], | |||
| ) -> list[Any]: | |||
| data: list[T], | |||
| name_func: Callable[[T], str], | |||
| ): | |||
| """ | |||
| Sort the objects by the position map. | |||
| If the name of the object is not in the position map, it will be put at the end. | |||
| @@ -122,9 +125,9 @@ def sort_by_position_map( | |||
| def sort_to_dict_by_position_map( | |||
| position_map: dict[str, int], | |||
| data: list[Any], | |||
| name_func: Callable[[Any], str], | |||
| ) -> OrderedDict[str, Any]: | |||
| data: list[T], | |||
| name_func: Callable[[T], str], | |||
| ): | |||
| """ | |||
| Sort the objects into a ordered dict by the position map. | |||
| If the name of the object is not in the position map, it will be put at the end. | |||
| @@ -134,4 +137,4 @@ def sort_to_dict_by_position_map( | |||
| :return: an OrderedDict with the sorted pairs of name and object | |||
| """ | |||
| sorted_items = sort_by_position_map(position_map, data, name_func) | |||
| return OrderedDict([(name_func(item), item) for item in sorted_items]) | |||
| return OrderedDict((name_func(item), item) for item in sorted_items) | |||
| @@ -246,6 +246,10 @@ class StreamableHTTPTransport: | |||
| logger.debug("Received 202 Accepted") | |||
| return | |||
| if response.status_code == 204: | |||
| logger.debug("Received 204 No Content") | |||
| return | |||
| if response.status_code == 404: | |||
| if isinstance(message.root, JSONRPCRequest): | |||
| self._send_session_terminated_error( | |||
| @@ -258,5 +258,5 @@ def convert_input_form_to_parameters( | |||
| parameters[item.variable]["type"] = "string" | |||
| parameters[item.variable]["enum"] = item.options | |||
| elif item.type == VariableEntityType.NUMBER: | |||
| parameters[item.variable]["type"] = "float" | |||
| parameters[item.variable]["type"] = "number" | |||
| return parameters, required | |||
| @@ -152,8 +152,8 @@ class MyScaleVector(BaseVector): | |||
| ) | |||
| for r in self._client.query(sql).named_results() | |||
| ] | |||
| except Exception as e: | |||
| logger.exception("\033[91m\033[1m%s\033[0m \033[95m%s\033[0m", type(e), str(e)) # noqa:TRY401 | |||
| except Exception: | |||
| logger.exception("Vector search operation failed") | |||
| return [] | |||
| def delete(self) -> None: | |||
| @@ -1,7 +1,8 @@ | |||
| """ClickZetta Volume file lifecycle management | |||
| This module provides file lifecycle management features including version control, automatic cleanup, backup and restore | |||
| Supports complete lifecycle management for knowledge base files. | |||
| This module provides file lifecycle management features including version control, | |||
| automatic cleanup, backup and restore. Supports complete lifecycle management for | |||
| knowledge base files. | |||
| """ | |||
| import json | |||
| @@ -1,6 +1,6 @@ | |||
| [project] | |||
| name = "dify-api" | |||
| version = "1.8.0" | |||
| version = "1.8.1" | |||
| requires-python = ">=3.11,<3.13" | |||
| dependencies = [ | |||
| @@ -1,6 +1,7 @@ | |||
| import json | |||
| from unittest.mock import Mock, patch | |||
| import jsonschema | |||
| import pytest | |||
| from core.app.app_config.entities import VariableEntity, VariableEntityType | |||
| @@ -434,7 +435,7 @@ class TestUtilityFunctions: | |||
| assert parameters["category"]["enum"] == ["A", "B", "C"] | |||
| assert "count" in parameters | |||
| assert parameters["count"]["type"] == "float" | |||
| assert parameters["count"]["type"] == "number" | |||
| # FILE type should be skipped - it creates empty dict but gets filtered later | |||
| # Check that it doesn't have any meaningful content | |||
| @@ -447,3 +448,65 @@ class TestUtilityFunctions: | |||
| assert "category" not in required | |||
| # Note: _get_request_id function has been removed as request_id is now passed as parameter | |||
| def test_convert_input_form_to_parameters_jsonschema_validation_ok(self): | |||
| """Current schema uses 'number' for numeric fields; it should be a valid JSON Schema.""" | |||
| user_input_form = [ | |||
| VariableEntity( | |||
| type=VariableEntityType.NUMBER, | |||
| variable="count", | |||
| description="Count", | |||
| label="Count", | |||
| required=True, | |||
| ), | |||
| VariableEntity( | |||
| type=VariableEntityType.TEXT_INPUT, | |||
| variable="name", | |||
| description="User name", | |||
| label="Name", | |||
| required=False, | |||
| ), | |||
| ] | |||
| parameters_dict = { | |||
| "count": "Enter count", | |||
| "name": "Enter your name", | |||
| } | |||
| parameters, required = convert_input_form_to_parameters(user_input_form, parameters_dict) | |||
| # Build a complete JSON Schema | |||
| schema = { | |||
| "type": "object", | |||
| "properties": parameters, | |||
| "required": required, | |||
| } | |||
| # 1) The schema itself must be valid | |||
| jsonschema.Draft202012Validator.check_schema(schema) | |||
| # 2) Both float and integer instances should pass validation | |||
| jsonschema.validate(instance={"count": 3.14, "name": "alice"}, schema=schema) | |||
| jsonschema.validate(instance={"count": 2, "name": "bob"}, schema=schema) | |||
| def test_legacy_float_type_schema_is_invalid(self): | |||
| """Legacy/buggy behavior: using 'float' should produce an invalid JSON Schema.""" | |||
| # Manually construct a legacy/incorrect schema (simulating old behavior) | |||
| bad_schema = { | |||
| "type": "object", | |||
| "properties": { | |||
| "count": { | |||
| "type": "float", # Invalid type: JSON Schema does not support 'float' | |||
| "description": "Enter count", | |||
| } | |||
| }, | |||
| "required": ["count"], | |||
| } | |||
| # The schema itself should raise a SchemaError | |||
| with pytest.raises(jsonschema.exceptions.SchemaError): | |||
| jsonschema.Draft202012Validator.check_schema(bad_schema) | |||
| # Or validation should also raise SchemaError | |||
| with pytest.raises(jsonschema.exceptions.SchemaError): | |||
| jsonschema.validate(instance={"count": 1.23}, schema=bad_schema) | |||
| @@ -1260,7 +1260,7 @@ wheels = [ | |||
| [[package]] | |||
| name = "dify-api" | |||
| version = "1.8.0" | |||
| version = "1.8.1" | |||
| source = { virtual = "." } | |||
| dependencies = [ | |||
| { name = "arize-phoenix-otel" }, | |||
| @@ -2,7 +2,7 @@ x-shared-env: &shared-api-worker-env | |||
| services: | |||
| # API service | |||
| api: | |||
| image: langgenius/dify-api:1.8.0 | |||
| image: langgenius/dify-api:1.8.1 | |||
| 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.8.0 | |||
| image: langgenius/dify-api:1.8.1 | |||
| restart: always | |||
| environment: | |||
| # Use the shared environment variables. | |||
| @@ -58,7 +58,7 @@ services: | |||
| # worker_beat service | |||
| # Celery beat for scheduling periodic tasks. | |||
| worker_beat: | |||
| image: langgenius/dify-api:1.8.0 | |||
| image: langgenius/dify-api:1.8.1 | |||
| restart: always | |||
| environment: | |||
| # Use the shared environment variables. | |||
| @@ -76,7 +76,7 @@ services: | |||
| # Frontend web application. | |||
| web: | |||
| image: langgenius/dify-web:1.8.0 | |||
| image: langgenius/dify-web:1.8.1 | |||
| restart: always | |||
| environment: | |||
| CONSOLE_API_URL: ${CONSOLE_API_URL:-} | |||
| @@ -118,7 +118,17 @@ services: | |||
| volumes: | |||
| - ./volumes/db/data:/var/lib/postgresql/data | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready', '-h', 'db', '-U', '${PGUSER:-postgres}', '-d', '${POSTGRES_DB:-dify}' ] | |||
| test: | |||
| [ | |||
| "CMD", | |||
| "pg_isready", | |||
| "-h", | |||
| "db", | |||
| "-U", | |||
| "${PGUSER:-postgres}", | |||
| "-d", | |||
| "${POSTGRES_DB:-dify}", | |||
| ] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 60 | |||
| @@ -135,7 +145,11 @@ services: | |||
| # Set the redis password when startup redis server. | |||
| command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456} | |||
| healthcheck: | |||
| test: [ 'CMD-SHELL', 'redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG' ] | |||
| test: | |||
| [ | |||
| "CMD-SHELL", | |||
| "redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG", | |||
| ] | |||
| # The DifySandbox | |||
| sandbox: | |||
| @@ -157,7 +171,7 @@ services: | |||
| - ./volumes/sandbox/dependencies:/dependencies | |||
| - ./volumes/sandbox/conf:/conf | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-f', 'http://localhost:8194/health' ] | |||
| test: ["CMD", "curl", "-f", "http://localhost:8194/health"] | |||
| networks: | |||
| - ssrf_proxy_network | |||
| @@ -231,7 +245,12 @@ services: | |||
| volumes: | |||
| - ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template | |||
| - ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh | |||
| entrypoint: [ 'sh', '-c', "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ] | |||
| entrypoint: | |||
| [ | |||
| "sh", | |||
| "-c", | |||
| "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh", | |||
| ] | |||
| environment: | |||
| # pls clearly modify the squid env vars to fit your network environment. | |||
| HTTP_PORT: ${SSRF_HTTP_PORT:-3128} | |||
| @@ -260,8 +279,8 @@ services: | |||
| - CERTBOT_EMAIL=${CERTBOT_EMAIL} | |||
| - CERTBOT_DOMAIN=${CERTBOT_DOMAIN} | |||
| - CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-} | |||
| entrypoint: [ '/docker-entrypoint.sh' ] | |||
| command: [ 'tail', '-f', '/dev/null' ] | |||
| entrypoint: ["/docker-entrypoint.sh"] | |||
| command: ["tail", "-f", "/dev/null"] | |||
| # The nginx reverse proxy. | |||
| # used for reverse proxying the API service and Web service. | |||
| @@ -278,7 +297,12 @@ services: | |||
| - ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container) | |||
| - ./volumes/certbot/conf:/etc/letsencrypt | |||
| - ./volumes/certbot/www:/var/www/html | |||
| entrypoint: [ 'sh', '-c', "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ] | |||
| entrypoint: | |||
| [ | |||
| "sh", | |||
| "-c", | |||
| "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh", | |||
| ] | |||
| environment: | |||
| NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_} | |||
| NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false} | |||
| @@ -300,14 +324,14 @@ services: | |||
| - api | |||
| - web | |||
| ports: | |||
| - '${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}' | |||
| - '${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}' | |||
| - "${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}" | |||
| - "${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}" | |||
| # The Weaviate vector store. | |||
| weaviate: | |||
| image: semitechnologies/weaviate:1.19.0 | |||
| profiles: | |||
| - '' | |||
| - "" | |||
| - weaviate | |||
| restart: always | |||
| volumes: | |||
| @@ -360,13 +384,17 @@ services: | |||
| working_dir: /opt/couchbase | |||
| stdin_open: true | |||
| tty: true | |||
| entrypoint: [ "" ] | |||
| entrypoint: [""] | |||
| command: sh -c "/opt/couchbase/init/init-cbserver.sh" | |||
| volumes: | |||
| - ./volumes/couchbase/data:/opt/couchbase/var/lib/couchbase/data | |||
| healthcheck: | |||
| # ensure bucket was created before proceeding | |||
| test: [ "CMD-SHELL", "curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1" ] | |||
| test: | |||
| [ | |||
| "CMD-SHELL", | |||
| "curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1", | |||
| ] | |||
| interval: 10s | |||
| retries: 10 | |||
| start_period: 30s | |||
| @@ -392,9 +420,9 @@ services: | |||
| volumes: | |||
| - ./volumes/pgvector/data:/var/lib/postgresql/data | |||
| - ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh | |||
| entrypoint: [ '/docker-entrypoint.sh' ] | |||
| entrypoint: ["/docker-entrypoint.sh"] | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready' ] | |||
| test: ["CMD", "pg_isready"] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 30 | |||
| @@ -411,14 +439,14 @@ services: | |||
| - VB_USERNAME=dify | |||
| - VB_PASSWORD=Difyai123456 | |||
| ports: | |||
| - '5434:5432' | |||
| - "5434:5432" | |||
| volumes: | |||
| - ./vastbase/lic:/home/vastbase/vastbase/lic | |||
| - ./vastbase/data:/home/vastbase/data | |||
| - ./vastbase/backup:/home/vastbase/backup | |||
| - ./vastbase/backup_log:/home/vastbase/backup_log | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready' ] | |||
| test: ["CMD", "pg_isready"] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 30 | |||
| @@ -440,7 +468,7 @@ services: | |||
| volumes: | |||
| - ./volumes/pgvecto_rs/data:/var/lib/postgresql/data | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready' ] | |||
| test: ["CMD", "pg_isready"] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 30 | |||
| @@ -479,7 +507,11 @@ services: | |||
| ports: | |||
| - "${OCEANBASE_VECTOR_PORT:-2881}:2881" | |||
| healthcheck: | |||
| test: [ 'CMD-SHELL', 'obclient -h127.0.0.1 -P2881 -uroot@test -p$${OB_TENANT_PASSWORD} -e "SELECT 1;"' ] | |||
| test: | |||
| [ | |||
| "CMD-SHELL", | |||
| 'obclient -h127.0.0.1 -P2881 -uroot@test -p$${OB_TENANT_PASSWORD} -e "SELECT 1;"', | |||
| ] | |||
| interval: 10s | |||
| retries: 30 | |||
| start_period: 30s | |||
| @@ -515,7 +547,7 @@ services: | |||
| - ./volumes/milvus/etcd:/etcd | |||
| command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd | |||
| healthcheck: | |||
| test: [ 'CMD', 'etcdctl', 'endpoint', 'health' ] | |||
| test: ["CMD", "etcdctl", "endpoint", "health"] | |||
| interval: 30s | |||
| timeout: 20s | |||
| retries: 3 | |||
| @@ -534,7 +566,7 @@ services: | |||
| - ./volumes/milvus/minio:/minio_data | |||
| command: minio server /minio_data --console-address ":9001" | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live' ] | |||
| test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] | |||
| interval: 30s | |||
| timeout: 20s | |||
| retries: 3 | |||
| @@ -546,7 +578,7 @@ services: | |||
| image: milvusdb/milvus:v2.5.15 | |||
| profiles: | |||
| - milvus | |||
| command: [ 'milvus', 'run', 'standalone' ] | |||
| command: ["milvus", "run", "standalone"] | |||
| environment: | |||
| ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379} | |||
| MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000} | |||
| @@ -554,7 +586,7 @@ services: | |||
| volumes: | |||
| - ./volumes/milvus/milvus:/var/lib/milvus | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-f', 'http://localhost:9091/healthz' ] | |||
| test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] | |||
| interval: 30s | |||
| start_period: 90s | |||
| timeout: 20s | |||
| @@ -620,7 +652,7 @@ services: | |||
| volumes: | |||
| - ./volumes/opengauss/data:/var/lib/opengauss/data | |||
| healthcheck: | |||
| test: [ "CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1" ] | |||
| test: ["CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1"] | |||
| interval: 10s | |||
| timeout: 10s | |||
| retries: 10 | |||
| @@ -673,18 +705,19 @@ services: | |||
| node.name: dify-es0 | |||
| discovery.type: single-node | |||
| xpack.license.self_generated.type: basic | |||
| xpack.security.enabled: 'true' | |||
| xpack.security.enrollment.enabled: 'false' | |||
| xpack.security.http.ssl.enabled: 'false' | |||
| xpack.security.enabled: "true" | |||
| xpack.security.enrollment.enabled: "false" | |||
| xpack.security.http.ssl.enabled: "false" | |||
| ports: | |||
| - ${ELASTICSEARCH_PORT:-9200}:9200 | |||
| deploy: | |||
| resources: | |||
| limits: | |||
| memory: 2g | |||
| entrypoint: [ 'sh', '-c', "sh /docker-entrypoint-mount.sh" ] | |||
| entrypoint: ["sh", "-c", "sh /docker-entrypoint-mount.sh"] | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-s', 'http://localhost:9200/_cluster/health?pretty' ] | |||
| test: | |||
| ["CMD", "curl", "-s", "http://localhost:9200/_cluster/health?pretty"] | |||
| interval: 30s | |||
| timeout: 10s | |||
| retries: 50 | |||
| @@ -702,17 +735,17 @@ services: | |||
| environment: | |||
| XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: d1a66dfd-c4d3-4a0a-8290-2abcb83ab3aa | |||
| NO_PROXY: localhost,127.0.0.1,elasticsearch,kibana | |||
| XPACK_SECURITY_ENABLED: 'true' | |||
| XPACK_SECURITY_ENROLLMENT_ENABLED: 'false' | |||
| XPACK_SECURITY_HTTP_SSL_ENABLED: 'false' | |||
| XPACK_FLEET_ISAIRGAPPED: 'true' | |||
| XPACK_SECURITY_ENABLED: "true" | |||
| XPACK_SECURITY_ENROLLMENT_ENABLED: "false" | |||
| XPACK_SECURITY_HTTP_SSL_ENABLED: "false" | |||
| XPACK_FLEET_ISAIRGAPPED: "true" | |||
| I18N_LOCALE: zh-CN | |||
| SERVER_PORT: '5601' | |||
| SERVER_PORT: "5601" | |||
| ELASTICSEARCH_HOSTS: http://elasticsearch:9200 | |||
| ports: | |||
| - ${KIBANA_PORT:-5601}:5601 | |||
| healthcheck: | |||
| test: [ 'CMD-SHELL', 'curl -s http://localhost:5601 >/dev/null || exit 1' ] | |||
| test: ["CMD-SHELL", "curl -s http://localhost:5601 >/dev/null || exit 1"] | |||
| interval: 30s | |||
| timeout: 10s | |||
| retries: 3 | |||
| @@ -586,7 +586,7 @@ x-shared-env: &shared-api-worker-env | |||
| services: | |||
| # API service | |||
| api: | |||
| image: langgenius/dify-api:1.8.0 | |||
| image: langgenius/dify-api:1.8.1 | |||
| restart: always | |||
| environment: | |||
| # Use the shared environment variables. | |||
| @@ -615,7 +615,7 @@ services: | |||
| # worker service | |||
| # The Celery worker for processing the queue. | |||
| worker: | |||
| image: langgenius/dify-api:1.8.0 | |||
| image: langgenius/dify-api:1.8.1 | |||
| restart: always | |||
| environment: | |||
| # Use the shared environment variables. | |||
| @@ -642,7 +642,7 @@ services: | |||
| # worker_beat service | |||
| # Celery beat for scheduling periodic tasks. | |||
| worker_beat: | |||
| image: langgenius/dify-api:1.8.0 | |||
| image: langgenius/dify-api:1.8.1 | |||
| restart: always | |||
| environment: | |||
| # Use the shared environment variables. | |||
| @@ -660,7 +660,7 @@ services: | |||
| # Frontend web application. | |||
| web: | |||
| image: langgenius/dify-web:1.8.0 | |||
| image: langgenius/dify-web:1.8.1 | |||
| restart: always | |||
| environment: | |||
| CONSOLE_API_URL: ${CONSOLE_API_URL:-} | |||
| @@ -702,7 +702,17 @@ services: | |||
| volumes: | |||
| - ./volumes/db/data:/var/lib/postgresql/data | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready', '-h', 'db', '-U', '${PGUSER:-postgres}', '-d', '${POSTGRES_DB:-dify}' ] | |||
| test: | |||
| [ | |||
| "CMD", | |||
| "pg_isready", | |||
| "-h", | |||
| "db", | |||
| "-U", | |||
| "${PGUSER:-postgres}", | |||
| "-d", | |||
| "${POSTGRES_DB:-dify}", | |||
| ] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 60 | |||
| @@ -719,7 +729,11 @@ services: | |||
| # Set the redis password when startup redis server. | |||
| command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456} | |||
| healthcheck: | |||
| test: [ 'CMD-SHELL', 'redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG' ] | |||
| test: | |||
| [ | |||
| "CMD-SHELL", | |||
| "redis-cli -a ${REDIS_PASSWORD:-difyai123456} ping | grep -q PONG", | |||
| ] | |||
| # The DifySandbox | |||
| sandbox: | |||
| @@ -741,7 +755,7 @@ services: | |||
| - ./volumes/sandbox/dependencies:/dependencies | |||
| - ./volumes/sandbox/conf:/conf | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-f', 'http://localhost:8194/health' ] | |||
| test: ["CMD", "curl", "-f", "http://localhost:8194/health"] | |||
| networks: | |||
| - ssrf_proxy_network | |||
| @@ -815,7 +829,12 @@ services: | |||
| volumes: | |||
| - ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template | |||
| - ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh | |||
| entrypoint: [ 'sh', '-c', "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ] | |||
| entrypoint: | |||
| [ | |||
| "sh", | |||
| "-c", | |||
| "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh", | |||
| ] | |||
| environment: | |||
| # pls clearly modify the squid env vars to fit your network environment. | |||
| HTTP_PORT: ${SSRF_HTTP_PORT:-3128} | |||
| @@ -844,8 +863,8 @@ services: | |||
| - CERTBOT_EMAIL=${CERTBOT_EMAIL} | |||
| - CERTBOT_DOMAIN=${CERTBOT_DOMAIN} | |||
| - CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-} | |||
| entrypoint: [ '/docker-entrypoint.sh' ] | |||
| command: [ 'tail', '-f', '/dev/null' ] | |||
| entrypoint: ["/docker-entrypoint.sh"] | |||
| command: ["tail", "-f", "/dev/null"] | |||
| # The nginx reverse proxy. | |||
| # used for reverse proxying the API service and Web service. | |||
| @@ -862,7 +881,12 @@ services: | |||
| - ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container) | |||
| - ./volumes/certbot/conf:/etc/letsencrypt | |||
| - ./volumes/certbot/www:/var/www/html | |||
| entrypoint: [ 'sh', '-c', "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ] | |||
| entrypoint: | |||
| [ | |||
| "sh", | |||
| "-c", | |||
| "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh", | |||
| ] | |||
| environment: | |||
| NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_} | |||
| NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false} | |||
| @@ -884,14 +908,14 @@ services: | |||
| - api | |||
| - web | |||
| ports: | |||
| - '${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}' | |||
| - '${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}' | |||
| - "${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}" | |||
| - "${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}" | |||
| # The Weaviate vector store. | |||
| weaviate: | |||
| image: semitechnologies/weaviate:1.19.0 | |||
| profiles: | |||
| - '' | |||
| - "" | |||
| - weaviate | |||
| restart: always | |||
| volumes: | |||
| @@ -944,13 +968,17 @@ services: | |||
| working_dir: /opt/couchbase | |||
| stdin_open: true | |||
| tty: true | |||
| entrypoint: [ "" ] | |||
| entrypoint: [""] | |||
| command: sh -c "/opt/couchbase/init/init-cbserver.sh" | |||
| volumes: | |||
| - ./volumes/couchbase/data:/opt/couchbase/var/lib/couchbase/data | |||
| healthcheck: | |||
| # ensure bucket was created before proceeding | |||
| test: [ "CMD-SHELL", "curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1" ] | |||
| test: | |||
| [ | |||
| "CMD-SHELL", | |||
| "curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1", | |||
| ] | |||
| interval: 10s | |||
| retries: 10 | |||
| start_period: 30s | |||
| @@ -976,9 +1004,9 @@ services: | |||
| volumes: | |||
| - ./volumes/pgvector/data:/var/lib/postgresql/data | |||
| - ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh | |||
| entrypoint: [ '/docker-entrypoint.sh' ] | |||
| entrypoint: ["/docker-entrypoint.sh"] | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready' ] | |||
| test: ["CMD", "pg_isready"] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 30 | |||
| @@ -995,14 +1023,14 @@ services: | |||
| - VB_USERNAME=dify | |||
| - VB_PASSWORD=Difyai123456 | |||
| ports: | |||
| - '5434:5432' | |||
| - "5434:5432" | |||
| volumes: | |||
| - ./vastbase/lic:/home/vastbase/vastbase/lic | |||
| - ./vastbase/data:/home/vastbase/data | |||
| - ./vastbase/backup:/home/vastbase/backup | |||
| - ./vastbase/backup_log:/home/vastbase/backup_log | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready' ] | |||
| test: ["CMD", "pg_isready"] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 30 | |||
| @@ -1024,7 +1052,7 @@ services: | |||
| volumes: | |||
| - ./volumes/pgvecto_rs/data:/var/lib/postgresql/data | |||
| healthcheck: | |||
| test: [ 'CMD', 'pg_isready' ] | |||
| test: ["CMD", "pg_isready"] | |||
| interval: 1s | |||
| timeout: 3s | |||
| retries: 30 | |||
| @@ -1063,7 +1091,11 @@ services: | |||
| ports: | |||
| - "${OCEANBASE_VECTOR_PORT:-2881}:2881" | |||
| healthcheck: | |||
| test: [ 'CMD-SHELL', 'obclient -h127.0.0.1 -P2881 -uroot@test -p$${OB_TENANT_PASSWORD} -e "SELECT 1;"' ] | |||
| test: | |||
| [ | |||
| "CMD-SHELL", | |||
| 'obclient -h127.0.0.1 -P2881 -uroot@test -p$${OB_TENANT_PASSWORD} -e "SELECT 1;"', | |||
| ] | |||
| interval: 10s | |||
| retries: 30 | |||
| start_period: 30s | |||
| @@ -1099,7 +1131,7 @@ services: | |||
| - ./volumes/milvus/etcd:/etcd | |||
| command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd | |||
| healthcheck: | |||
| test: [ 'CMD', 'etcdctl', 'endpoint', 'health' ] | |||
| test: ["CMD", "etcdctl", "endpoint", "health"] | |||
| interval: 30s | |||
| timeout: 20s | |||
| retries: 3 | |||
| @@ -1118,7 +1150,7 @@ services: | |||
| - ./volumes/milvus/minio:/minio_data | |||
| command: minio server /minio_data --console-address ":9001" | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live' ] | |||
| test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] | |||
| interval: 30s | |||
| timeout: 20s | |||
| retries: 3 | |||
| @@ -1130,7 +1162,7 @@ services: | |||
| image: milvusdb/milvus:v2.5.15 | |||
| profiles: | |||
| - milvus | |||
| command: [ 'milvus', 'run', 'standalone' ] | |||
| command: ["milvus", "run", "standalone"] | |||
| environment: | |||
| ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379} | |||
| MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000} | |||
| @@ -1138,7 +1170,7 @@ services: | |||
| volumes: | |||
| - ./volumes/milvus/milvus:/var/lib/milvus | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-f', 'http://localhost:9091/healthz' ] | |||
| test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] | |||
| interval: 30s | |||
| start_period: 90s | |||
| timeout: 20s | |||
| @@ -1204,7 +1236,7 @@ services: | |||
| volumes: | |||
| - ./volumes/opengauss/data:/var/lib/opengauss/data | |||
| healthcheck: | |||
| test: [ "CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1" ] | |||
| test: ["CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1"] | |||
| interval: 10s | |||
| timeout: 10s | |||
| retries: 10 | |||
| @@ -1257,18 +1289,19 @@ services: | |||
| node.name: dify-es0 | |||
| discovery.type: single-node | |||
| xpack.license.self_generated.type: basic | |||
| xpack.security.enabled: 'true' | |||
| xpack.security.enrollment.enabled: 'false' | |||
| xpack.security.http.ssl.enabled: 'false' | |||
| xpack.security.enabled: "true" | |||
| xpack.security.enrollment.enabled: "false" | |||
| xpack.security.http.ssl.enabled: "false" | |||
| ports: | |||
| - ${ELASTICSEARCH_PORT:-9200}:9200 | |||
| deploy: | |||
| resources: | |||
| limits: | |||
| memory: 2g | |||
| entrypoint: [ 'sh', '-c', "sh /docker-entrypoint-mount.sh" ] | |||
| entrypoint: ["sh", "-c", "sh /docker-entrypoint-mount.sh"] | |||
| healthcheck: | |||
| test: [ 'CMD', 'curl', '-s', 'http://localhost:9200/_cluster/health?pretty' ] | |||
| test: | |||
| ["CMD", "curl", "-s", "http://localhost:9200/_cluster/health?pretty"] | |||
| interval: 30s | |||
| timeout: 10s | |||
| retries: 50 | |||
| @@ -1286,17 +1319,17 @@ services: | |||
| environment: | |||
| XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: d1a66dfd-c4d3-4a0a-8290-2abcb83ab3aa | |||
| NO_PROXY: localhost,127.0.0.1,elasticsearch,kibana | |||
| XPACK_SECURITY_ENABLED: 'true' | |||
| XPACK_SECURITY_ENROLLMENT_ENABLED: 'false' | |||
| XPACK_SECURITY_HTTP_SSL_ENABLED: 'false' | |||
| XPACK_FLEET_ISAIRGAPPED: 'true' | |||
| XPACK_SECURITY_ENABLED: "true" | |||
| XPACK_SECURITY_ENROLLMENT_ENABLED: "false" | |||
| XPACK_SECURITY_HTTP_SSL_ENABLED: "false" | |||
| XPACK_FLEET_ISAIRGAPPED: "true" | |||
| I18N_LOCALE: zh-CN | |||
| SERVER_PORT: '5601' | |||
| SERVER_PORT: "5601" | |||
| ELASTICSEARCH_HOSTS: http://elasticsearch:9200 | |||
| ports: | |||
| - ${KIBANA_PORT:-5601}:5601 | |||
| healthcheck: | |||
| test: [ 'CMD-SHELL', 'curl -s http://localhost:5601 >/dev/null || exit 1' ] | |||
| test: ["CMD-SHELL", "curl -s http://localhost:5601 >/dev/null || exit 1"] | |||
| interval: 30s | |||
| timeout: 10s | |||
| retries: 3 | |||
| @@ -52,6 +52,10 @@ const ChatWrapper = () => { | |||
| allInputsHidden, | |||
| initUserVariables, | |||
| } = useChatWithHistoryContext() | |||
| // Semantic variable for better code readability | |||
| const isHistoryConversation = !!currentConversationId | |||
| const appConfig = useMemo(() => { | |||
| const config = appParams || {} | |||
| @@ -62,9 +66,9 @@ const ChatWrapper = () => { | |||
| fileUploadConfig: (config as any).system_parameters, | |||
| }, | |||
| supportFeedback: true, | |||
| opening_statement: currentConversationId ? currentConversationItem?.introduction : (config as any).opening_statement, | |||
| opening_statement: isHistoryConversation ? currentConversationItem?.introduction : (config as any).opening_statement, | |||
| } as ChatConfig | |||
| }, [appParams, currentConversationItem?.introduction, currentConversationId]) | |||
| }, [appParams, currentConversationItem?.introduction, isHistoryConversation]) | |||
| const { | |||
| chatList, | |||
| setTargetMessageId, | |||
| @@ -75,7 +79,7 @@ const ChatWrapper = () => { | |||
| } = useChat( | |||
| appConfig, | |||
| { | |||
| inputs: (currentConversationId ? currentConversationInputs : newConversationInputs) as any, | |||
| inputs: (isHistoryConversation ? currentConversationInputs : newConversationInputs) as any, | |||
| inputsForm: inputsForms, | |||
| }, | |||
| appPrevChatTree, | |||
| @@ -83,7 +87,7 @@ const ChatWrapper = () => { | |||
| clearChatList, | |||
| setClearChatList, | |||
| ) | |||
| const inputsFormValue = currentConversationId ? currentConversationInputs : newConversationInputsRef?.current | |||
| const inputsFormValue = isHistoryConversation ? currentConversationInputs : newConversationInputsRef?.current | |||
| const inputDisabled = useMemo(() => { | |||
| if (allInputsHidden) | |||
| return false | |||
| @@ -132,7 +136,7 @@ const ChatWrapper = () => { | |||
| const data: any = { | |||
| query: message, | |||
| files, | |||
| inputs: formatBooleanInputs(inputsForms, currentConversationId ? currentConversationInputs : newConversationInputs), | |||
| inputs: formatBooleanInputs(inputsForms, isHistoryConversation ? currentConversationInputs : newConversationInputs), | |||
| conversation_id: currentConversationId, | |||
| parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null, | |||
| } | |||
| @@ -142,11 +146,11 @@ const ChatWrapper = () => { | |||
| data, | |||
| { | |||
| onGetSuggestedQuestions: responseItemId => fetchSuggestedQuestions(responseItemId, isInstalledApp, appId), | |||
| onConversationComplete: currentConversationId ? undefined : handleNewConversationCompleted, | |||
| onConversationComplete: isHistoryConversation ? undefined : handleNewConversationCompleted, | |||
| isPublicAPI: !isInstalledApp, | |||
| }, | |||
| ) | |||
| }, [chatList, handleNewConversationCompleted, handleSend, currentConversationId, currentConversationInputs, newConversationInputs, isInstalledApp, appId]) | |||
| }, [chatList, handleNewConversationCompleted, handleSend, isHistoryConversation, currentConversationInputs, newConversationInputs, isInstalledApp, appId]) | |||
| const doRegenerate = useCallback((chatItem: ChatItemInTree, editedQuestion?: { message: string, files?: FileEntity[] }) => { | |||
| const question = editedQuestion ? chatItem : chatList.find(item => item.id === chatItem.parentMessageId)! | |||
| @@ -159,31 +163,30 @@ const ChatWrapper = () => { | |||
| }, [chatList, doSend]) | |||
| const messageList = useMemo(() => { | |||
| if (currentConversationId) | |||
| return chatList | |||
| // Always filter out opening statement from message list as it's handled separately in welcome component | |||
| return chatList.filter(item => !item.isOpeningStatement) | |||
| }, [chatList, currentConversationId]) | |||
| }, [chatList]) | |||
| const [collapsed, setCollapsed] = useState(!!currentConversationId) | |||
| const [collapsed, setCollapsed] = useState(isHistoryConversation) | |||
| const chatNode = useMemo(() => { | |||
| if (allInputsHidden || !inputsForms.length) | |||
| return null | |||
| if (isMobile) { | |||
| if (!currentConversationId) | |||
| if (!isHistoryConversation) | |||
| return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} /> | |||
| return null | |||
| } | |||
| else { | |||
| return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} /> | |||
| } | |||
| }, [inputsForms.length, isMobile, currentConversationId, collapsed, allInputsHidden]) | |||
| }, [inputsForms.length, isMobile, isHistoryConversation, collapsed, allInputsHidden]) | |||
| const welcome = useMemo(() => { | |||
| const welcomeMessage = chatList.find(item => item.isOpeningStatement) | |||
| if (respondingState) | |||
| return null | |||
| if (currentConversationId) | |||
| if (isHistoryConversation) | |||
| return null | |||
| if (!welcomeMessage) | |||
| return null | |||
| @@ -224,7 +227,7 @@ const ChatWrapper = () => { | |||
| </div> | |||
| </div> | |||
| ) | |||
| }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, currentConversationId, inputsForms.length, respondingState, allInputsHidden]) | |||
| }, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, isHistoryConversation, inputsForms.length, respondingState, allInputsHidden]) | |||
| const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon) | |||
| ? <AnswerIcon | |||
| @@ -248,7 +251,7 @@ const ChatWrapper = () => { | |||
| chatFooterClassName='pb-4' | |||
| chatFooterInnerClassName={`mx-auto w-full max-w-[768px] ${isMobile ? 'px-2' : 'px-4'}`} | |||
| onSend={doSend} | |||
| inputs={currentConversationId ? currentConversationInputs as any : newConversationInputs} | |||
| inputs={isHistoryConversation ? currentConversationInputs as any : newConversationInputs} | |||
| inputsForm={inputsForms} | |||
| onRegenerate={doRegenerate} | |||
| onStopResponding={handleStop} | |||
| @@ -14,7 +14,7 @@ export enum FormTypeEnum { | |||
| secretInput = 'secret-input', | |||
| select = 'select', | |||
| radio = 'radio', | |||
| boolean = 'boolean', | |||
| boolean = 'checkbox', | |||
| files = 'files', | |||
| file = 'file', | |||
| modelSelector = 'model-selector', | |||
| @@ -115,7 +115,7 @@ const ModelModal: FC<ModelModalProps> = ({ | |||
| const [selectedCredential, setSelectedCredential] = useState<Credential & { addNewCredential?: boolean } | undefined>() | |||
| const formRef2 = useRef<FormRefObject>(null) | |||
| const isEditMode = !!Object.keys(formValues).filter((key) => { | |||
| return key !== '__model_name' && key !== '__model_type' | |||
| return key !== '__model_name' && key !== '__model_type' && !!formValues[key] | |||
| }).length && isCurrentWorkspaceManager | |||
| const handleSave = useCallback(async () => { | |||
| @@ -167,7 +167,7 @@ const ModelModal: FC<ModelModalProps> = ({ | |||
| __authorization_name__, | |||
| ...rest | |||
| } = values | |||
| if (__model_name && __model_type && __authorization_name__) { | |||
| if (__model_name && __model_type) { | |||
| await handleSaveCredential({ | |||
| credential_id: credential?.credential_id, | |||
| credentials: rest, | |||
| @@ -90,8 +90,8 @@ const FormInputItem: FC<Props> = ({ | |||
| // return VarType.appSelector | |||
| // else if (isModelSelector) | |||
| // return VarType.modelSelector | |||
| // else if (isBoolean) | |||
| // return VarType.boolean | |||
| else if (isBoolean) | |||
| return VarType.boolean | |||
| else if (isObject) | |||
| return VarType.object | |||
| else if (isArray) | |||
| @@ -183,7 +183,7 @@ const FormInputItem: FC<Props> = ({ | |||
| return ( | |||
| <div className={cn('gap-1', !(isShowJSONEditor && isConstant) && 'flex')}> | |||
| {showTypeSwitch && ( | |||
| <FormInputTypeSwitch value={varInput?.type || VarKindType.constant} onChange={handleTypeChange}/> | |||
| <FormInputTypeSwitch value={varInput?.type || VarKindType.constant} onChange={handleTypeChange} /> | |||
| )} | |||
| {isString && ( | |||
| <MixedVariableTextInput | |||
| @@ -203,7 +203,7 @@ const FormInputItem: FC<Props> = ({ | |||
| placeholder={placeholder?.[language] || placeholder?.en_US} | |||
| /> | |||
| )} | |||
| {isBoolean && ( | |||
| {isBoolean && isConstant && ( | |||
| <FormInputBoolean | |||
| value={varInput?.value as boolean} | |||
| onChange={handleValueChange} | |||
| @@ -490,6 +490,7 @@ const translation = { | |||
| providerManagedTip: 'Die aktuelle Konfiguration wird vom Anbieter gehostet.', | |||
| configLoadBalancing: 'Konfiguration Lastenverteilung', | |||
| specifyModelCredentialTip: 'Verwenden Sie ein konfiguriertes Modellzugang.', | |||
| manageCredentials: 'Anmeldeinformationen verwalten', | |||
| }, | |||
| }, | |||
| dataSource: { | |||
| @@ -494,6 +494,7 @@ const translation = { | |||
| specifyModelCredentialTip: 'از اعتبارنامه مدل پیکربندی شده استفاده کنید.', | |||
| providerManagedTip: 'تنظیمات فعلی توسط ارائهدهنده میزبانی میشود.', | |||
| modelCredentials: 'مدل اعتبارنامه', | |||
| manageCredentials: 'مدیریت اعتبارنامه ها', | |||
| }, | |||
| }, | |||
| dataSource: { | |||
| @@ -510,6 +510,7 @@ const translation = { | |||
| specifyModelCredential: 'मॉडल की क्रेडेंशियल निर्दिष्ट करें', | |||
| specifyModelCredentialTip: 'कॉन्फ़िगर की गई मॉडल क्रेडेंशियल का उपयोग करें।', | |||
| providerManagedTip: 'वर्तमान कॉन्फ़िगरेशन प्रदाता द्वारा होस्ट किया गया है।', | |||
| selectModelCredential: 'एक मॉडल क्रेडेंशियल चुनें', | |||
| }, | |||
| }, | |||
| dataSource: { | |||
| @@ -5,10 +5,10 @@ const translation = { | |||
| }, | |||
| table: { | |||
| header: { | |||
| answer: 'menjawab', | |||
| answer: 'Jawaban', | |||
| question: 'pertanyaan', | |||
| createdAt: 'dibuat di', | |||
| hits: 'Hits', | |||
| hits: 'Kecocokan', | |||
| addAnnotation: 'Tambahkan Anotasi', | |||
| bulkImport: 'Impor Massal', | |||
| clearAllConfirm: 'Menghapus semua anotasi?', | |||
| @@ -29,7 +29,7 @@ const translation = { | |||
| answerName: 'Bot Pendongeng', | |||
| }, | |||
| addModal: { | |||
| answerName: 'Menjawab', | |||
| answerName: 'Jawaban', | |||
| title: 'Tambahkan Anotasi Balasan', | |||
| queryName: 'Pertanyaan', | |||
| createNext: 'Tambahkan respons beranotasi lainnya', | |||
| @@ -44,10 +44,10 @@ const translation = { | |||
| run: 'Jalankan Batch', | |||
| cancel: 'Membatalkan', | |||
| title: 'Impor Massal', | |||
| browse: 'ramban', | |||
| browse: 'Telusuri', | |||
| template: 'Unduh templat di sini', | |||
| tip: 'File CSV harus sesuai dengan struktur berikut:', | |||
| answer: 'menjawab', | |||
| answer: 'Jawaban', | |||
| contentTitle: 'konten potongan', | |||
| processing: 'Dalam pemrosesan batch', | |||
| completed: 'Impor selesai', | |||
| @@ -69,15 +69,15 @@ const translation = { | |||
| answerRequired: 'Jawaban diperlukan', | |||
| }, | |||
| viewModal: { | |||
| hit: 'Pukul', | |||
| hitHistory: 'Riwayat Hit', | |||
| noHitHistory: 'Tidak ada riwayat hit', | |||
| hit: 'Kecocokan', | |||
| hitHistory: 'Riwayat Kecocokan', | |||
| noHitHistory: 'Tidak ada riwayat kecocokan', | |||
| annotatedResponse: 'Balas Anotasi', | |||
| hits: 'Hits', | |||
| hits: 'Kecocokan', | |||
| }, | |||
| hitHistoryTable: { | |||
| response: 'Jawaban', | |||
| match: 'Korek api', | |||
| match: 'Kecocokan', | |||
| query: 'Kueri', | |||
| source: 'Sumber', | |||
| time: 'Waktu', | |||
| @@ -19,8 +19,8 @@ const translation = { | |||
| completionMode: { | |||
| createCompletionApi: 'Membuat Pesan Penyelesaian', | |||
| messageIDTip: 'ID Pesan', | |||
| messageFeedbackApi: 'Umpan balik pesan (seperti)', | |||
| ratingTip: 'suka atau tidak suka, null adalah undo', | |||
| messageFeedbackApi: 'Umpan balik pesan (mis. spam, tidak relevan, pujian)', | |||
| ratingTip: '(mis. suka/tidak suka), null berarti membatalkan penilaian', | |||
| parametersApi: 'Dapatkan informasi parameter aplikasi', | |||
| parametersApiTip: 'Ambil parameter Input yang dikonfigurasi, termasuk nama variabel, nama bidang, jenis, dan nilai default. Biasanya digunakan untuk menampilkan bidang ini dalam formulir atau mengisi nilai default setelah klien dimuat.', | |||
| info: 'Untuk pembuatan teks berkualitas tinggi, seperti artikel, ringkasan, dan terjemahan, gunakan API pesan penyelesaian dengan input pengguna. Pembuatan teks bergantung pada parameter model dan templat prompt yang ditetapkan di Dify Prompt Engineering.', | |||
| @@ -48,7 +48,7 @@ const translation = { | |||
| conversationsListLimitTip: 'Berapa banyak obrolan yang dikembalikan dalam satu permintaan', | |||
| chatMsgHistoryLimit: 'Berapa banyak obrolan yang dikembalikan dalam satu permintaan', | |||
| conversationsListFirstIdTip: 'ID rekaman terakhir di halaman saat ini, default tidak ada.', | |||
| messageFeedbackApi: 'Umpan balik pengguna terminal pesan, seperti', | |||
| messageFeedbackApi: 'Umpan balik pengguna terminal pesan (mis. spam, tidak relevan, pujian)', | |||
| parametersApi: 'Dapatkan informasi parameter aplikasi', | |||
| streaming: 'streaming kembali. Implementasi pengembalian streaming berdasarkan SSE (Server-Sent Events).', | |||
| inputsTips: '(Opsional) Berikan bidang input pengguna sebagai pasangan kunci-nilai, sesuai dengan variabel di Prompt Eng. Kunci adalah nama variabel, Nilai adalah nilai parameter. Jika jenis bidang adalah Pilih, Nilai yang dikirimkan harus menjadi salah satu pilihan prasetel.', | |||
| @@ -58,7 +58,7 @@ const translation = { | |||
| createChatApiTip: 'Buat pesan percakapan baru atau lanjutkan dialog yang ada.', | |||
| chatMsgHistoryApiTip: 'Halaman pertama mengembalikan bilah \'batas\' terbaru, yang dalam urutan terbalik.', | |||
| conversationsListApi: 'Dapatkan daftar percakapan', | |||
| ratingTip: 'suka atau tidak suka, null adalah undo', | |||
| ratingTip: '(mis. suka/tidak suka), null berarti membatalkan penilaian', | |||
| conversationRenamingApi: 'Penggantian nama percakapan', | |||
| }, | |||
| develop: { | |||
| @@ -67,19 +67,19 @@ const translation = { | |||
| pathParams: 'Parameter Jalur', | |||
| requestBody: 'Isi Permintaan', | |||
| }, | |||
| apiServer: 'API Server', | |||
| apiServer: 'Server API', | |||
| copied: 'Disalin', | |||
| copy: 'Menyalin', | |||
| ok: 'Dalam Layanan', | |||
| regenerate: 'Regenerasi', | |||
| status: 'Keadaan', | |||
| copy: 'Salin', | |||
| ok: 'OK', | |||
| regenerate: 'Hasilkan Ulang', | |||
| status: 'Status', | |||
| never: 'Tidak pernah', | |||
| playing: 'Bermain', | |||
| play: 'Bermain', | |||
| disabled: 'Cacat', | |||
| playing: 'Sedang Memutar', | |||
| play: 'Putar', | |||
| disabled: 'Dinonaktifkan', | |||
| apiKey: 'Kunci API', | |||
| pause: 'Jeda', | |||
| loading: 'Loading', | |||
| loading: 'Memuat...', | |||
| } | |||
| export default translation | |||
| @@ -324,7 +324,7 @@ const translation = { | |||
| }, | |||
| variableTable: { | |||
| action: 'Tindakan', | |||
| typeString: 'Tali', | |||
| typeString: 'String', | |||
| optional: 'Fakultatif', | |||
| typeSelect: 'Pilih', | |||
| type: 'Jenis Masukan', | |||
| @@ -346,7 +346,7 @@ const translation = { | |||
| name: 'Audio', | |||
| }, | |||
| document: { | |||
| name: 'Surat', | |||
| name: 'Dokumen', | |||
| }, | |||
| video: { | |||
| name: 'Video', | |||
| @@ -421,7 +421,7 @@ const translation = { | |||
| language: 'Bahasa', | |||
| title: 'Pengaturan Suara', | |||
| autoPlay: 'Putar Otomatis', | |||
| autoPlayDisabled: 'Off', | |||
| autoPlayDisabled: 'Dinonaktifkan', | |||
| resolutionTooltip: 'Bahasa pendukung suara text-to-speech。', | |||
| }, | |||
| settings: 'Pengaturan', | |||
| @@ -448,7 +448,7 @@ const translation = { | |||
| }, | |||
| inputs: { | |||
| queryPlaceholder: 'Silakan masukkan teks permintaan.', | |||
| run: 'LARI', | |||
| run: 'Jalankan', | |||
| completionVarTip: 'Isi nilai variabel, yang akan secara otomatis diganti dengan kata-kata prompt setiap kali pertanyaan diajukan.', | |||
| noVar: 'Isi nilai variabel, yang akan secara otomatis diganti dalam kata prompt setiap kali sesi baru dimulai.', | |||
| noPrompt: 'Coba tulis beberapa prompt dalam input pra-prompt', | |||
| @@ -5,8 +5,8 @@ const translation = { | |||
| version: 'VERSI', | |||
| time: 'Waktu yang dibuat', | |||
| messageCount: 'Jumlah Pesan', | |||
| summary: 'Titel', | |||
| adminRate: 'Tingkat Op.', | |||
| summary: 'Ringkasan', | |||
| adminRate: 'Tingkat Admin', | |||
| user: 'Pengguna Akhir atau Akun', | |||
| startTime: 'WAKTU MULAI', | |||
| updatedTime: 'Waktu yang diperbarui', | |||
| @@ -18,8 +18,8 @@ const translation = { | |||
| runtime: 'WAKTU BERJALAN', | |||
| }, | |||
| pagination: { | |||
| previous: 'Prev', | |||
| next: 'Depan', | |||
| previous: 'Sebelumnya', | |||
| next: 'Selanjutnya', | |||
| }, | |||
| empty: { | |||
| element: { | |||
| @@ -30,12 +30,12 @@ const translation = { | |||
| }, | |||
| }, | |||
| detail: { | |||
| timeConsuming: '', | |||
| timeConsuming: 'Memakan waktu', | |||
| operation: { | |||
| dislike: 'tidak suka', | |||
| like: 'suka', | |||
| addAnnotation: 'Tambahkan Peningkatan', | |||
| editAnnotation: 'Edit Peningkatan', | |||
| addAnnotation: 'Tambahkan Anotasi', | |||
| editAnnotation: 'Edit Anotasi', | |||
| annotationPlaceholder: 'Masukkan jawaban yang diharapkan yang Anda inginkan untuk dibalas AI, yang dapat digunakan untuk penyempurnaan model dan peningkatan berkelanjutan kualitas pembuatan teks di masa mendatang.', | |||
| }, | |||
| time: 'Waktu', | |||
| @@ -67,7 +67,7 @@ const translation = { | |||
| }, | |||
| ascending: 'Naik', | |||
| descending: 'Turun', | |||
| sortBy: 'Kota hitam:', | |||
| sortBy: 'Urutkan berdasarkan', | |||
| }, | |||
| runDetail: { | |||
| fileListDetail: 'Detail', | |||
| @@ -119,8 +119,8 @@ const translation = { | |||
| explanation: 'Mudah diintegrasikan ke dalam aplikasi Anda', | |||
| }, | |||
| status: { | |||
| disable: 'Cacat', | |||
| running: 'Dalam Layanan', | |||
| disable: 'Nonaktif', | |||
| running: 'Berjalan', | |||
| }, | |||
| title: 'Ikhtisar', | |||
| }, | |||
| @@ -23,7 +23,7 @@ const translation = { | |||
| appCreated: 'Aplikasi dibuat', | |||
| appNamePlaceholder: 'Beri nama aplikasi Anda', | |||
| appCreateDSLErrorPart3: 'Versi DSL aplikasi saat ini:', | |||
| Cancel: 'Membatalkan', | |||
| Cancel: 'Batal', | |||
| previewDemo: 'Pratinjau demo', | |||
| appCreateDSLWarning: 'Perhatian: Perbedaan versi DSL dapat memengaruhi fitur tertentu', | |||
| appCreateDSLErrorPart1: 'Perbedaan yang signifikan dalam versi DSL telah terdeteksi. Memaksa impor dapat menyebabkan aplikasi tidak berfungsi.', | |||
| @@ -46,7 +46,7 @@ const translation = { | |||
| showTemplates: 'Saya ingin memilih dari templat', | |||
| caution: 'Hati', | |||
| chatbotShortDescription: 'Chatbot berbasis LLM dengan pengaturan sederhana', | |||
| Confirm: 'Mengkonfirmasi', | |||
| Confirm: 'Konfirmasi', | |||
| agentAssistant: 'Asisten Agen Baru', | |||
| appCreateFailed: 'Gagal membuat aplikasi', | |||
| appCreateDSLErrorTitle: 'Ketidakcocokan Versi', | |||
| @@ -58,7 +58,7 @@ const translation = { | |||
| appTypeRequired: 'Silakan pilih jenis aplikasi', | |||
| advancedShortDescription: 'Alur kerja disempurnakan untuk obrolan multi-giliran', | |||
| completeAppIntro: 'Saya ingin membuat aplikasi yang menghasilkan teks berkualitas tinggi berdasarkan petunjuk, seperti menghasilkan artikel, ringkasan, terjemahan, dan banyak lagi.', | |||
| Create: 'Menciptakan', | |||
| Create: 'Buat', | |||
| advancedUserDescription: 'Alur kerja dengan fitur memori tambahan dan antarmuka chatbot.', | |||
| dropDSLToCreateApp: 'Jatuhkan file DSL di sini untuk membuat aplikasi', | |||
| completeApp: 'Pembuat Teks', | |||
| @@ -83,10 +83,10 @@ const translation = { | |||
| searchAllTemplate: 'Cari semua templat...', | |||
| }, | |||
| iconPicker: { | |||
| cancel: 'Membatalkan', | |||
| cancel: 'Batal', | |||
| emoji: 'Emoji', | |||
| image: 'Citra', | |||
| ok: 'OKE', | |||
| ok: 'OK', | |||
| }, | |||
| answerIcon: { | |||
| title: 'Gunakan ikon aplikasi web untuk mengganti 🤖', | |||
| @@ -129,7 +129,7 @@ const translation = { | |||
| }, | |||
| weave: { | |||
| description: 'Weave adalah platform sumber terbuka untuk mengevaluasi, menguji, dan memantau aplikasi LLM.', | |||
| title: 'Anyam', | |||
| title: 'Weave', | |||
| }, | |||
| aliyun: { | |||
| title: 'Monitor Awan', | |||
| @@ -148,8 +148,8 @@ const translation = { | |||
| collapse: 'Roboh', | |||
| tracing: 'Menelusuri', | |||
| title: 'Melacak performa aplikasi', | |||
| disabled: 'Cacat', | |||
| enabled: 'Dalam Layanan', | |||
| disabled: 'Nonaktif', | |||
| enabled: 'Aktif', | |||
| config: 'Konfigurasi', | |||
| description: 'Mengonfigurasi penyedia LLMOps Pihak Ketiga dan melacak performa aplikasi.', | |||
| inUse: 'Sedang digunakan', | |||
| @@ -1,9 +1,9 @@ | |||
| const translation = { | |||
| theme: { | |||
| theme: 'Tema', | |||
| light: 'ringan', | |||
| auto: 'sistem', | |||
| dark: 'gelap', | |||
| light: 'Terang', | |||
| auto: 'Otomatis', | |||
| dark: 'Gelap', | |||
| }, | |||
| api: { | |||
| success: 'Keberhasilan', | |||
| @@ -16,8 +16,8 @@ const translation = { | |||
| setup: 'Setup', | |||
| download: 'Mengunduh', | |||
| getForFree: 'Dapatkan gratis', | |||
| reload: 'Reload', | |||
| lineBreak: 'Istirahat baris', | |||
| reload: 'Muat Ulang', | |||
| lineBreak: 'Baris Baru', | |||
| learnMore: 'Pelajari lebih lanjut', | |||
| saveAndRegenerate: 'Simpan & Buat Ulang Potongan Anak', | |||
| zoomOut: 'Perkecil', | |||
| @@ -26,7 +26,7 @@ const translation = { | |||
| selectAll: 'Pilih Semua', | |||
| in: 'di', | |||
| skip: 'Lewat', | |||
| remove: 'Buka', | |||
| remove: 'Hapus', | |||
| rename: 'Ubah nama', | |||
| close: 'Tutup', | |||
| ok: 'OKE', | |||
| @@ -35,8 +35,8 @@ const translation = { | |||
| log: 'Batang', | |||
| delete: 'Menghapus', | |||
| viewDetails: 'Lihat Detail', | |||
| view: 'Melihat', | |||
| clear: 'Jelas', | |||
| view: 'Lihat', | |||
| clear: 'Hapus', | |||
| deleteApp: 'Hapus Aplikasi', | |||
| downloadSuccess: 'Unduh Selesai.', | |||
| change: 'Ubah', | |||
| @@ -45,7 +45,7 @@ const translation = { | |||
| copied: 'Disalin', | |||
| deSelectAll: 'Batalkan pilihan Semua', | |||
| saveAndEnable: 'Simpan & Aktifkan', | |||
| refresh: 'Restart', | |||
| refresh: 'Segarkan', | |||
| downloadFailed: 'Unduhan gagal. Silakan coba lagi nanti.', | |||
| edit: 'Mengedit', | |||
| send: 'Kirim', | |||
| @@ -56,7 +56,7 @@ const translation = { | |||
| add: 'Tambah', | |||
| copy: 'Menyalin', | |||
| audioSourceUnavailable: 'AudioSource tidak tersedia', | |||
| submit: 'Tunduk', | |||
| submit: 'Kirim', | |||
| duplicate: 'Duplikat', | |||
| save: 'Simpan', | |||
| added: 'Ditambahkan', | |||
| @@ -100,7 +100,7 @@ const translation = { | |||
| }, | |||
| }, | |||
| unit: { | |||
| char: 'Tank', | |||
| char: 'karakter', | |||
| }, | |||
| actionMsg: { | |||
| noModification: 'Tidak ada modifikasi saat ini.', | |||
| @@ -148,7 +148,7 @@ const translation = { | |||
| account: 'Rekening', | |||
| newApp: 'Aplikasi Baru', | |||
| explore: 'Menjelajahi', | |||
| apps: 'Belajar', | |||
| apps: 'Aplikasi', | |||
| status: 'beta', | |||
| tools: 'Perkakas', | |||
| exploreMarketplace: 'Jelajahi Marketplace', | |||
| @@ -165,7 +165,7 @@ const translation = { | |||
| settings: 'Pengaturan', | |||
| support: 'Dukung', | |||
| github: 'GitHub', | |||
| about: 'Sekitar', | |||
| about: 'Tentang', | |||
| workspace: 'Workspace', | |||
| createWorkspace: 'Membuat Ruang Kerja', | |||
| }, | |||
| @@ -503,13 +503,13 @@ const translation = { | |||
| }, | |||
| integratedAlert: 'Notion terintegrasi melalui kredensial internal, tidak perlu mengotorisasi ulang.', | |||
| disconnected: 'Terputus', | |||
| remove: 'Buka', | |||
| remove: 'Hapus', | |||
| addWorkspace: 'Menambahkan ruang kerja', | |||
| description: 'Menggunakan Notion sebagai sumber data untuk Pengetahuan.', | |||
| connected: 'Terhubung', | |||
| pagesAuthorized: 'Halaman yang disahkan', | |||
| changeAuthorizedPages: 'Mengubah halaman resmi', | |||
| title: 'Gagasan', | |||
| title: 'Notion', | |||
| sync: 'Sync', | |||
| connectedWorkspace: 'Ruang kerja yang terhubung', | |||
| }, | |||
| @@ -597,7 +597,7 @@ const translation = { | |||
| 'claude-2': 'Claude-2', | |||
| 'gpt-3.5-turbo': 'GPT-3.5-Turbo', | |||
| 'gpt-4': 'GPT-4', | |||
| 'whisper-1': 'Bisikan-1', | |||
| 'whisper-1': 'Whisper-1', | |||
| 'text-davinci-003': 'Teks-Davinci-003', | |||
| 'gpt-4-32k': 'GPT-4-32K', | |||
| 'gpt-3.5-turbo-16k': 'GPT-3.5-Turbo-16K', | |||
| @@ -615,7 +615,7 @@ const translation = { | |||
| }, | |||
| resend: 'Kirim Ulang', | |||
| conversationName: 'Nama percakapan', | |||
| thinking: 'Pikiran...', | |||
| thinking: 'Sedang berpikir...', | |||
| conversationNameCanNotEmpty: 'Nama percakapan diperlukan', | |||
| thought: 'Pikiran', | |||
| renameConversation: 'Ganti Nama Percakapan', | |||
| @@ -712,7 +712,7 @@ const translation = { | |||
| deleteDescription: 'Apakah Anda yakin ingin menghapus gambar profil Anda? Akun Anda akan menggunakan avatar awal default.', | |||
| }, | |||
| imageInput: { | |||
| browse: 'ramban', | |||
| browse: 'Telusuri', | |||
| supportedFormats: 'Mendukung PNG, JPG, JPEG, WEBP dan GIF', | |||
| dropImageHere: 'Letakkan gambar Anda di sini, atau', | |||
| }, | |||
| @@ -7,25 +7,25 @@ const translation = { | |||
| }, | |||
| webapp: { | |||
| changeLogoTip: 'Format SVG atau PNG dengan ukuran minimum 40x40px', | |||
| removeBrand: 'Hapus Didukung oleh Dify', | |||
| changeLogo: 'Perubahan Didukung oleh Citra Merek', | |||
| title: 'Sesuaikan merek aplikasi web', | |||
| removeBrand: 'Hapus Branding Dify', | |||
| changeLogo: 'Ubah Logo Merek', | |||
| title: 'Kustomisasi Branding Aplikasi Web', | |||
| }, | |||
| app: { | |||
| title: 'Menyesuaikan merek header aplikasi', | |||
| title: 'Kustomisasi Branding Header Aplikasi', | |||
| changeLogoTip: 'Format SVG atau PNG dengan ukuran minimal 80x80px', | |||
| }, | |||
| customize: { | |||
| suffix: 'untuk meningkatkan ke edisi Enterprise.', | |||
| prefix: 'Untuk menyesuaikan logo merek di dalam aplikasi, silakan', | |||
| contactUs: 'Hubungi', | |||
| suffix: 'untuk upgrade ke edisi Enterprise.', | |||
| prefix: 'Untuk kustomisasi logo merek di dalam aplikasi, silakan', | |||
| contactUs: 'Hubungi Kami', | |||
| }, | |||
| custom: 'Kustomisasi', | |||
| uploading: 'Meng', | |||
| uploading: 'Mengunggah...', | |||
| upload: 'Unggah', | |||
| change: 'Ubah', | |||
| restore: 'Pulihkan Default', | |||
| apply: 'Berlaku', | |||
| apply: 'Terapkan', | |||
| uploadedFail: 'Unggahan gambar gagal, silakan unggah ulang.', | |||
| } | |||
| @@ -56,17 +56,17 @@ const translation = { | |||
| tip: 'Pengetahuan kosong tidak akan berisi dokumen, dan Anda dapat mengunggah dokumen kapan saja.', | |||
| }, | |||
| website: { | |||
| configure: 'Mengkonfigurasi', | |||
| configure: 'Konfigurasikan', | |||
| fireCrawlNotConfigured: 'Firecrawl tidak dikonfigurasi', | |||
| chooseProvider: 'Pilih penyedia', | |||
| configureFirecrawl: 'Mengonfigurasi Firecrawl', | |||
| configureFirecrawl: 'Konfigurasikan Firecrawl', | |||
| watercrawlDoc: 'Dokumen Watercrawl', | |||
| options: 'Pilihan', | |||
| firecrawlTitle: 'Mengekstrak konten web dengan 🔥Firecrawl', | |||
| jinaReaderNotConfigured: 'Jina Reader tidak dikonfigurasi', | |||
| preview: 'Pratayang', | |||
| resetAll: 'Atur Ulang Semua', | |||
| run: 'Lari', | |||
| run: 'Jalankan', | |||
| limit: 'Batas', | |||
| useSitemap: 'Menggunakan peta situs', | |||
| jinaReaderDoc: 'Pelajari lebih lanjut tentang Jina Reader', | |||
| @@ -87,19 +87,19 @@ const translation = { | |||
| maxDepth: 'Kedalaman maks', | |||
| jinaReaderDocLink: 'https://jina.ai/reader', | |||
| selectAll: 'Pilih Semua', | |||
| maxDepthTooltip: 'Kedalaman maksimum untuk di-crawl relatif terhadap URL yang dimasukkan. Kedalaman 0 hanya mengikis halaman url yang dimasukkan, kedalaman 1 mengikis url dan semuanya setelah dimasukkanURL satu /, dan seterusnya.', | |||
| maxDepthTooltip: 'Kedalaman maksimum untuk di-crawl relatif terhadap URL yang dimasukkan. Kedalaman 0 hanya mengikis halaman url yang dimasukkan, kedalaman 1 mengikis url dan semuanya setelah dimasukkan URL satu /, dan seterusnya.', | |||
| waterCrawlNotConfiguredDescription: 'Konfigurasikan Watercrawl dengan kunci API untuk menggunakannya.', | |||
| firecrawlDoc: 'Dokumen Firecrawl', | |||
| configureWatercrawl: 'Mengonfigurasi Watercrawl', | |||
| configureWatercrawl: 'Konfigurasikan Watercrawl', | |||
| }, | |||
| pagePreview: 'Pratinjau Halaman', | |||
| notionSyncTitle: 'Gagasan tidak terhubung', | |||
| notionSyncTitle: 'Notion tidak terhubung', | |||
| filePreview: 'Pratinjau File', | |||
| cancel: 'Membatalkan', | |||
| emptyDatasetCreation: 'Saya ingin membuat Pengetahuan kosong', | |||
| button: 'Depan', | |||
| button: 'Berikutnya', | |||
| notionSyncTip: 'Untuk menyinkronkan dengan Notion, koneksi ke Notion harus dibuat terlebih dahulu.', | |||
| connect: 'Buka terhubung', | |||
| connect: 'Hubungkan', | |||
| }, | |||
| stepTwo: { | |||
| paragraph: 'Paragraf', | |||
| @@ -162,7 +162,7 @@ const translation = { | |||
| previewChunkTip: 'Klik tombol \'Pratinjau Potongan\' di sebelah kiri untuk memuat pratinjau', | |||
| sideTipP4: 'Potongan dan pembersihan yang tepat meningkatkan kinerja model, memberikan hasil yang lebih akurat dan berharga.', | |||
| previewTitleButton: 'Pratayang', | |||
| switch: 'Sakelar', | |||
| switch: 'Beralih', | |||
| datasetSettingLink: 'Pengaturan pengetahuan.', | |||
| rules: 'Aturan Pra-pemrosesan Teks', | |||
| sideTipP2: 'Segmentasi membagi teks panjang menjadi paragraf sehingga model dapat memahami dengan lebih baik. Ini meningkatkan kualitas dan relevansi hasil model.', | |||
| @@ -193,7 +193,7 @@ const translation = { | |||
| resume: 'Melanjutkan pemrosesan', | |||
| stop: 'Hentikan pemrosesan', | |||
| creationContent: 'Kami secara otomatis menamai Pengetahuan, Anda dapat memodifikasinya kapan saja.', | |||
| modelButtonConfirm: 'Mengkonfirmasi', | |||
| modelButtonConfirm: 'Konfirmasi', | |||
| sideTipContent: 'Setelah dokumen selesai diindeks, Pengetahuan dapat diintegrasikan ke dalam aplikasi sebagai konteks, Anda dapat menemukan pengaturan konteks di halaman orkestrasi perintah. Anda juga dapat membuatnya sebagai plugin pengindeksan ChatGPT independen untuk dirilis.', | |||
| modelButtonCancel: 'Membatalkan', | |||
| label: 'Nama pengetahuan', | |||
| @@ -11,7 +11,7 @@ const translation = { | |||
| countWarning: 'Hingga 200 karakter.', | |||
| placeholder: 'Silakan masukkan teks, disarankan untuk memasukkan kalimat deklaratif singkat.', | |||
| indexWarning: 'Pengetahuan berkualitas tinggi saja.', | |||
| testing: 'Ujian', | |||
| testing: 'Pengujian', | |||
| }, | |||
| hit: { | |||
| emptyTip: 'Hasil Pengujian Pengambilan akan ditampilkan di sini', | |||
| @@ -22,7 +22,7 @@ const translation = { | |||
| open: 'Buka', | |||
| settingTitle: 'Pengaturan Pengambilan', | |||
| dateTimeFormat: 'MM / DD / YYYY hh: mm A', | |||
| desc: 'Uji efek pukulan Pengetahuan berdasarkan teks kueri yang diberikan.', | |||
| desc: 'Uji dampak pengetahuan terhadap hasil pencarian berdasarkan teks kueri yang diberikan.', | |||
| viewDetail: 'Lihat Detail', | |||
| viewChart: 'Lihat GRAFIK VAKTOR', | |||
| chunkDetail: 'Detail Potongan', | |||
| @@ -3,7 +3,7 @@ const translation = { | |||
| retrievalSetting: { | |||
| title: 'Pengaturan Pengambilan', | |||
| description: 'tentang metode pengambilan.', | |||
| longDescription: 'tentang metode pengambilan, Anda dapat mengudagnya kapan saja di pengaturan Pengetahuan.', | |||
| longDescription: 'tentang metode pengambilan, Anda dapat mengunduhnya kapan saja di pengaturan Pengetahuan.', | |||
| method: 'Metode Pengambilan', | |||
| learnMore: 'Pelajari lebih lanjut', | |||
| }, | |||
| @@ -133,7 +133,7 @@ const translation = { | |||
| search: 'Metadata pencarian', | |||
| }, | |||
| datasetMetadata: { | |||
| disabled: 'Cacat', | |||
| disabled: 'Nonaktif', | |||
| addMetaData: 'Tambahkan Metadata', | |||
| description: 'Anda dapat mengelola semua metadata dalam pengetahuan ini di sini. Modifikasi akan disinkronkan ke setiap dokumen.', | |||
| deleteTitle: 'Konfirmasi untuk menghapus', | |||
| @@ -141,7 +141,7 @@ const translation = { | |||
| rename: 'Ubah nama', | |||
| builtInDescription: 'Metadata bawaan secara otomatis diekstrak dan dihasilkan. Itu harus diaktifkan sebelum digunakan dan tidak dapat diedit.', | |||
| namePlaceholder: 'Nama metadata', | |||
| builtIn: 'Built-in', | |||
| builtIn: 'Bawaan', | |||
| }, | |||
| documentMetadata: { | |||
| metadataToolTip: 'Metadata berfungsi sebagai filter penting yang meningkatkan akurasi dan relevansi pengambilan informasi. Anda dapat memodifikasi dan menambahkan metadata untuk dokumen ini di sini.', | |||
| @@ -60,7 +60,7 @@ const translation = { | |||
| }, | |||
| dateFormat: 'MM / DD / YYYY', | |||
| }, | |||
| submit: 'Tunduk', | |||
| submit: 'Kirim', | |||
| toVerified: 'Dapatkan Pendidikan Terverifikasi', | |||
| currentSigned: 'SAAT INI MASUK SEBAGAI', | |||
| successTitle: 'Anda telah mendapatkan Dify Education Verified', | |||
| @@ -1,10 +1,10 @@ | |||
| const translation = { | |||
| sidebar: { | |||
| action: { | |||
| unpin: 'Lepaskan pin', | |||
| pin: 'Pin', | |||
| delete: 'Menghapus', | |||
| rename: 'Ubah nama', | |||
| unpin: 'Lepaskan sematan', | |||
| pin: 'Sematkan', | |||
| delete: 'Hapus', | |||
| rename: 'Ganti nama', | |||
| }, | |||
| delete: { | |||
| content: 'Apakah Anda yakin ingin menghapus aplikasi ini?', | |||
| @@ -36,8 +36,8 @@ const translation = { | |||
| continueWithCode: 'Lanjutkan dengan kode', | |||
| sendVerificationCode: 'Kirim Kode Verifikasi', | |||
| invalidInvitationCode: 'Kode undangan tidak valid', | |||
| installBtn: 'Mengatur', | |||
| joinTipStart: 'Mengundang Anda bergabung', | |||
| installBtn: 'Siapkan', | |||
| joinTipStart: 'Mengundang Anda untuk bergabung', | |||
| or: 'ATAU', | |||
| namePlaceholder: 'Nama pengguna Anda', | |||
| withSSO: 'Lanjutkan dengan SSO', | |||
| @@ -53,23 +53,23 @@ const translation = { | |||
| invitationCodePlaceholder: 'Kode undangan Anda', | |||
| emailPlaceholder: 'Email Anda', | |||
| tos: 'Ketentuan Layanan', | |||
| go: 'Pergi ke Dify', | |||
| go: 'Buka Dify', | |||
| forgotPassword: 'Lupa Kata Sandi Anda?', | |||
| sendUsMail: 'Kirimkan perkenalan Anda melalui email kepada kami, dan kami akan menangani permintaan undangan.', | |||
| pp: 'Kebijakan Privasi', | |||
| activatedTipEnd: 'tim', | |||
| backToSignIn: 'Kembali untuk login', | |||
| backToSignIn: 'Kembali ke halaman masuk', | |||
| passwordChanged: 'Masuk sekarang', | |||
| withGitHub: 'Lanjutkan dengan GitHub', | |||
| accountAlreadyInited: 'Akun sudah diinisialisasi', | |||
| withGoogle: 'Lanjutkan dengan Google', | |||
| rightDesc: 'Bangun aplikasi AI yang menawan secara visual, dapat dioperasikan, dan ditingkatkan dengan mudah.', | |||
| rightDesc: 'Bangun aplikasi AI yang menarik secara visual, mudah dioperasikan, dan mudah diskalakan.', | |||
| invitationCode: 'Kode Undangan', | |||
| invalidToken: 'Token tidak valid atau kedaluwarsa', | |||
| setAdminAccount: 'Menyiapkan akun admin', | |||
| forgotPasswordDesc: 'Silakan masukkan alamat email Anda untuk mengatur ulang kata sandi Anda. Kami akan mengirimi Anda email dengan instruksi tentang cara mengatur ulang kata sandi Anda.', | |||
| confirmPassword: 'Konfirmasi Kata Sandi', | |||
| changePasswordBtn: 'Menetapkan kata sandi', | |||
| changePasswordBtn: 'Tetapkan kata sandi', | |||
| resetPassword: 'Atur Ulang Kata Sandi', | |||
| explore: 'Jelajahi Dify', | |||
| useVerificationCode: 'Gunakan Kode Verifikasi', | |||
| @@ -84,7 +84,7 @@ const translation = { | |||
| licenseLost: 'Lisensi Hilang', | |||
| licenseInactive: 'Lisensi Tidak Aktif', | |||
| enterYourName: 'Silakan masukkan nama pengguna Anda', | |||
| back: 'Belakang', | |||
| back: 'Kembali', | |||
| activated: 'Masuk sekarang', | |||
| goToInit: 'Jika Anda belum menginisialisasi akun, silakan buka halaman inisialisasi', | |||
| licenseExpired: 'Lisensi Kedaluwarsa', | |||
| @@ -94,9 +94,9 @@ const translation = { | |||
| validate: 'Memvalidasi', | |||
| resetPasswordDesc: 'Ketik email yang Anda gunakan untuk mendaftar di Dify dan kami akan mengirimkan email reset kata sandi kepada Anda.', | |||
| licenseLostTip: 'Gagal menghubungkan server lisensi Dify. Hubungi administrator Anda untuk terus menggunakan Dify.', | |||
| signBtn: 'Tandatangan', | |||
| signBtn: 'Masuk', | |||
| sendResetLink: 'Kirim tautan reset', | |||
| createAndSignIn: 'Membuat dan masuk', | |||
| createAndSignIn: 'Buat dan masuk', | |||
| licenseExpiredTip: 'Lisensi Dify Enterprise untuk ruang kerja Anda telah kedaluwarsa. Hubungi administrator Anda untuk terus menggunakan Dify.', | |||
| email: 'Alamat email', | |||
| noLoginMethodTip: 'Silakan hubungi admin sistem untuk menambahkan metode autentikasi.', | |||
| @@ -104,11 +104,11 @@ const translation = { | |||
| licenseInactiveTip: 'Lisensi Dify Enterprise untuk ruang kerja Anda tidak aktif. Hubungi administrator Anda untuk terus menggunakan Dify.', | |||
| rightTitle: 'Buka potensi penuh LLM', | |||
| welcome: '👋 Selamat datang di Dify, silakan login untuk melanjutkan.', | |||
| changePassword: 'Menetapkan kata sandi', | |||
| setAdminAccountDesc: 'Hak istimewa maksimum untuk akun admin, yang dapat digunakan untuk membuat aplikasi dan mengelola penyedia LLM, dll.', | |||
| join: 'Ikat', | |||
| changePassword: 'Ubah kata sandi', | |||
| setAdminAccountDesc: 'Akun admin memiliki hak istimewa penuh untuk membuat aplikasi, mengelola penyedia LLM, dll.', | |||
| join: 'Gabung', | |||
| forget: 'Lupa Kata Sandi Anda?', | |||
| backToLogin: 'Kembali ke login', | |||
| backToLogin: 'Kembali ke halaman masuk', | |||
| oneMoreStep: 'Satu langkah lagi', | |||
| } | |||
| @@ -17,11 +17,11 @@ const translation = { | |||
| authorizeFailed: 'Otorisasi gagal', | |||
| authAppInfoFetchFailed: 'Gagal mengambil info aplikasi untuk otorisasi', | |||
| }, | |||
| continue: 'Terus', | |||
| unknownApp: 'Aplikasi Tidak Dikenal', | |||
| login: 'Login', | |||
| connect: 'Hubungkan ke', | |||
| switchAccount: 'Beralih Akun', | |||
| continue: 'Lanjut', | |||
| unknownApp: 'Aplikasi tidak dikenal', | |||
| login: 'Masuk', | |||
| connect: 'Hubungkan', | |||
| switchAccount: 'Ganti Akun', | |||
| } | |||
| export default translation | |||
| @@ -39,7 +39,7 @@ const translation = { | |||
| local: 'Plugin Lokal', | |||
| }, | |||
| operation: { | |||
| remove: 'Buka', | |||
| remove: 'Hapus', | |||
| info: 'Plugin Info', | |||
| update: 'Pemutakhiran', | |||
| detail: 'Rincian', | |||
| @@ -55,7 +55,7 @@ const translation = { | |||
| empty: 'Klik tombol \' \' untuk menambahkan alat. Anda dapat menambahkan beberapa alat.', | |||
| params: 'KONFIGURASI PENALARAN', | |||
| unsupportedMCPTool: 'Saat ini versi plugin strategi agen yang dipilih tidak mendukung alat MCP.', | |||
| auto: 'Mobil', | |||
| auto: 'Otomatis', | |||
| descriptionPlaceholder: 'Deskripsi singkat tentang tujuan alat, misalnya, mendapatkan suhu untuk lokasi tertentu.', | |||
| toolSetting: 'Pengaturan Alat', | |||
| settings: 'PENGATURAN PENGGUNA', | |||
| @@ -174,11 +174,11 @@ const translation = { | |||
| installing: 'Menginstal...', | |||
| uploadFailed: 'Upload gagal', | |||
| pluginLoadErrorDesc: 'Plugin ini tidak akan diinstal', | |||
| next: 'Depan', | |||
| next: 'Lanjut', | |||
| installedSuccessfully: 'Instalasi berhasil', | |||
| install: 'Pasang', | |||
| installFailed: 'Instalasi gagal', | |||
| back: 'Belakang', | |||
| back: 'Kembali', | |||
| readyToInstallPackage: 'Tentang menginstal plugin berikut', | |||
| installedSuccessfullyDesc: 'Plugin telah berhasil diinstal.', | |||
| pluginLoadError: 'Kesalahan pemuatan plugin', | |||
| @@ -227,7 +227,7 @@ const translation = { | |||
| empower: 'Berdayakan pengembangan AI Anda', | |||
| partnerTip: 'Diverifikasi oleh partner Dify', | |||
| moreFrom: 'Selengkapnya dari Marketplace', | |||
| sortBy: 'Kota hitam', | |||
| sortBy: 'Urutkan berdasarkan', | |||
| and: 'dan', | |||
| difyMarketplace: 'Dify Marketplace', | |||
| verifiedTip: 'Diverifikasi oleh Dify', | |||
| @@ -1,17 +1,17 @@ | |||
| const translation = { | |||
| daysInWeek: { | |||
| Wed: 'Bertaruh', | |||
| Wed: 'Rabu', | |||
| Thu: 'Kamis', | |||
| Sun: 'Matahari', | |||
| Tue: 'Membunuh', | |||
| Mon: 'Mon', | |||
| Sat: 'Hari sabtu', | |||
| Fri: 'Bebas', | |||
| Sun: 'Minggu', | |||
| Tue: 'Selasa', | |||
| Mon: 'Senin', | |||
| Sat: 'Sabtu', | |||
| Fri: 'Jumat', | |||
| }, | |||
| months: { | |||
| August: 'Agustus', | |||
| October: 'Oktober', | |||
| May: 'Menjahit', | |||
| May: 'Mei', | |||
| September: 'September', | |||
| December: 'Desember', | |||
| November: 'November', | |||
| @@ -34,7 +34,7 @@ const translation = { | |||
| dateFormats: { | |||
| display: 'MMMM D, YYYY', | |||
| input: 'YYYY-MM-DD', | |||
| outputWithTime: 'YYYY-MM-DDTHH:mm:ss. SSSZ', | |||
| outputWithTime: 'YYYY-MM-DDTHH:mm:ss.SSSZ', | |||
| output: 'YYYY-MM-DD', | |||
| displayWithTime: 'MMMM D, YYYY hh:mm A', | |||
| }, | |||
| @@ -14,7 +14,7 @@ const translation = { | |||
| title: 'Tarik', | |||
| }, | |||
| }, | |||
| undo: 'Buka', | |||
| undo: 'Urungkan', | |||
| embedIntoSite: 'Sematkan ke Situs', | |||
| editing: 'Mengedit', | |||
| inRunMode: 'Dalam Mode Jalankan', | |||
| @@ -33,10 +33,10 @@ const translation = { | |||
| addParallelNode: 'Tambahkan Node Paralel', | |||
| onFailure: 'Pada Kegagalan', | |||
| update: 'Pemutakhiran', | |||
| parallelRun: 'Lari Paralel', | |||
| configure: 'Mengkonfigurasi', | |||
| parallelRun: 'Jalankan Paralel', | |||
| configure: 'Konfigurasikan', | |||
| copy: 'Menyalin', | |||
| redo: 'Siap', | |||
| redo: 'Ulangi', | |||
| runApp: 'Jalankan Aplikasi', | |||
| noHistory: 'Tidak Ada Sejarah', | |||
| importDSLTip: 'Draf saat ini akan ditimpa.\nEkspor alur kerja sebagai cadangan sebelum mengimpor.', | |||
| @@ -54,7 +54,7 @@ const translation = { | |||
| importSuccess: 'Berhasil Impor', | |||
| jumpToNode: 'Lompat ke simpul ini', | |||
| tagBound: 'Jumlah aplikasi yang menggunakan tag ini', | |||
| model: 'Pola', | |||
| model: 'Model', | |||
| workflowAsToolTip: 'Konfigurasi ulang alat diperlukan setelah pembaruan alur kerja.', | |||
| currentDraft: 'Draf Saat Ini', | |||
| parallel: 'SEJAJAR', | |||
| @@ -65,7 +65,7 @@ const translation = { | |||
| importWarning: 'Hati', | |||
| running: 'Menjalankan', | |||
| publishedAt: 'Diterbitkan', | |||
| run: 'Lari', | |||
| run: 'Jalankan', | |||
| importDSL: 'Impor DSL', | |||
| featuresDescription: 'Tingkatkan pengalaman pengguna aplikasi web', | |||
| inPreviewMode: 'Dalam Mode Pratinjau', | |||
| @@ -168,9 +168,9 @@ const translation = { | |||
| nodeAdd: 'Node ditambahkan', | |||
| nodePaste: 'Node ditempelkan', | |||
| noteDelete: 'Catatan dihapus', | |||
| hint: 'Indian', | |||
| hint: 'Petunjuk', | |||
| nodeTitleChange: 'Judul simpul diubah', | |||
| title: 'Perubahan Riwayat', | |||
| title: 'Riwayat Perubahan', | |||
| nodeDescriptionChange: 'Deskripsi simpul diubah', | |||
| clearHistory: 'Hapus Sejarah', | |||
| placeholder: 'Anda belum mengubah apa pun', | |||
| @@ -189,7 +189,7 @@ const translation = { | |||
| errorMsg: { | |||
| fields: { | |||
| variable: 'Nama Variabel', | |||
| model: 'Pola', | |||
| model: 'Model', | |||
| rerankModel: 'Model Peringkat Ulang yang dikonfigurasi', | |||
| visionVariable: 'Variabel Penglihatan', | |||
| variableValue: 'Nilai Variabel', | |||
| @@ -238,11 +238,11 @@ const translation = { | |||
| 'question-classifier': 'Pengklasifikasi Pertanyaan', | |||
| 'iteration-start': 'Iterasi Mulai', | |||
| 'knowledge-retrieval': 'Pengambilan Pengetahuan', | |||
| 'loop': 'Lari', | |||
| 'loop': 'Perulangan', | |||
| 'assigner': 'Penerima Variabel', | |||
| 'agent': 'Agen', | |||
| 'list-operator': 'Operator Daftar', | |||
| 'answer': 'Menjawab', | |||
| 'answer': 'Jawaban', | |||
| 'parameter-extractor': 'Ekstraktor Parameter', | |||
| 'document-extractor': 'Ekstraktor Dokumen', | |||
| 'end': 'Ujung', | |||
| @@ -286,10 +286,10 @@ const translation = { | |||
| horizontal: 'Horisontal', | |||
| distributeHorizontal: 'Spasi Secara Horizontal', | |||
| zoomTo100: 'Perbesar hingga 100%', | |||
| alignLeft: 'Kiri', | |||
| alignLeft: 'Rata Kiri', | |||
| distributeVertical: 'Ruang Secara Vertikal', | |||
| zoomTo50: 'Perbesar hingga 50%', | |||
| alignBottom: 'Dasar', | |||
| alignBottom: 'Rata Bawah', | |||
| }, | |||
| variableReference: { | |||
| conversationVars: 'variabel percakapan', | |||
| @@ -490,6 +490,7 @@ const translation = { | |||
| providerManagedTip: 'Configurarea curentă este găzduită de furnizor.', | |||
| modelCredentials: 'Credențiale model', | |||
| specifyModelCredentialTip: 'Utilizați un acreditiv de model configurat.', | |||
| addNewModelCredential: 'Adăugați acreditive noi pentru model', | |||
| }, | |||
| }, | |||
| dataSource: { | |||
| @@ -489,6 +489,7 @@ const translation = { | |||
| authorizationError: 'ข้อผิดพลาดในการอนุญาต', | |||
| specifyModelCredentialTip: 'ใช้ข้อมูลรับรองโมเดลที่กำหนดไว้', | |||
| providerManagedTip: 'การกำหนดค่าปัจจุบันถูกโฮสต์โดยผู้ให้บริการ.', | |||
| customModelCredentialsDeleteTip: 'ข้อมูลรับรองกำลังถูกใช้งานและไม่สามารถลบได้', | |||
| }, | |||
| }, | |||
| dataSource: { | |||
| @@ -746,7 +746,7 @@ const translation = { | |||
| content: 'Geri Bildirim İçeriği', | |||
| subtitle: 'Lütfen bu yanıtla ilgili neyin yanlış gittiğini bize bildirin', | |||
| title: 'Geri Bildirim Sağla', | |||
| placeholder: 'Lütfen neyin yanlış gittiğini veya nasıl iyileşebileceğimizı açıklayın...', | |||
| placeholder: 'Lütfen neyin yanlış gittiğini veya nasıl iyileşebileceğimizi açıklayın...', | |||
| }, | |||
| } | |||
| @@ -747,7 +747,7 @@ const translation = { | |||
| title: 'Надати відгук', | |||
| content: 'Зміст відгуку', | |||
| placeholder: 'Будь ласка, опишіть, що пішло не так або як ми можемо покращити...', | |||
| subtitle: 'Будь ласка, скажіть нам, що пішло не так з цим відповіді', | |||
| subtitle: 'Будь ласка, скажіть нам, що пішло не так із цією відповіддю', | |||
| }, | |||
| } | |||
| @@ -1,8 +1,8 @@ | |||
| { | |||
| "name": "dify-web", | |||
| "version": "1.8.0", | |||
| "version": "1.8.1", | |||
| "private": true, | |||
| "packageManager": "pnpm@10.15.0", | |||
| "packageManager": "pnpm@10.15.1", | |||
| "engines": { | |||
| "node": ">=v22.11.0" | |||
| }, | |||