mirror of https://github.com/langgenius/dify.git
merge main
This commit is contained in:
commit
11977596c9
|
|
@ -476,6 +476,7 @@ LOGIN_LOCKOUT_DURATION=86400
|
|||
ENABLE_OTEL=false
|
||||
OTLP_BASE_ENDPOINT=http://localhost:4318
|
||||
OTLP_API_KEY=
|
||||
OTEL_EXPORTER_OTLP_PROTOCOL=
|
||||
OTEL_EXPORTER_TYPE=otlp
|
||||
OTEL_SAMPLING_RATE=0.1
|
||||
OTEL_BATCH_EXPORT_SCHEDULE_DELAY=5000
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ class OTelConfig(BaseSettings):
|
|||
default="otlp",
|
||||
)
|
||||
|
||||
OTEL_EXPORTER_OTLP_PROTOCOL: str = Field(
|
||||
description="OTLP exporter protocol ('grpc' or 'http')",
|
||||
default="http",
|
||||
)
|
||||
|
||||
OTEL_SAMPLING_RATE: float = Field(default=0.1, description="Sampling rate for traces (0.0 to 1.0)")
|
||||
|
||||
OTEL_BATCH_EXPORT_SCHEDULE_DELAY: int = Field(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from flask_restful import fields
|
||||
|
||||
from libs.helper import AppIconUrlField
|
||||
|
||||
parameters__system_parameters = {
|
||||
"image_file_size_limit": fields.Integer,
|
||||
"video_file_size_limit": fields.Integer,
|
||||
|
|
@ -22,3 +24,20 @@ parameters_fields = {
|
|||
"file_upload": fields.Raw,
|
||||
"system_parameters": fields.Nested(parameters__system_parameters),
|
||||
}
|
||||
|
||||
site_fields = {
|
||||
"title": fields.String,
|
||||
"chat_color_theme": fields.String,
|
||||
"chat_color_theme_inverted": fields.Boolean,
|
||||
"icon_type": fields.String,
|
||||
"icon": fields.String,
|
||||
"icon_background": fields.String,
|
||||
"icon_url": AppIconUrlField,
|
||||
"description": fields.String,
|
||||
"copyright": fields.String,
|
||||
"privacy_policy": fields.String,
|
||||
"custom_disclaimer": fields.String,
|
||||
"default_language": fields.String,
|
||||
"show_workflow_steps": fields.Boolean,
|
||||
"use_icon_as_answer_icon": fields.Boolean,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ bp = Blueprint("service_api", __name__, url_prefix="/v1")
|
|||
api = ExternalApi(bp)
|
||||
|
||||
from . import index
|
||||
from .app import annotation, app, audio, completion, conversation, file, message, workflow
|
||||
from .app import annotation, app, audio, completion, conversation, file, message, site, workflow
|
||||
from .dataset import dataset, document, hit_testing, metadata, segment, upload_file
|
||||
from .workspace import models
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
from flask_restful import Resource, marshal_with
|
||||
from werkzeug.exceptions import Forbidden
|
||||
|
||||
from controllers.common import fields
|
||||
from controllers.service_api import api
|
||||
from controllers.service_api.wraps import validate_app_token
|
||||
from extensions.ext_database import db
|
||||
from models.account import TenantStatus
|
||||
from models.model import App, Site
|
||||
|
||||
|
||||
class AppSiteApi(Resource):
|
||||
"""Resource for app sites."""
|
||||
|
||||
@validate_app_token
|
||||
@marshal_with(fields.site_fields)
|
||||
def get(self, app_model: App):
|
||||
"""Retrieve app site info."""
|
||||
site = db.session.query(Site).filter(Site.app_id == app_model.id).first()
|
||||
|
||||
if not site:
|
||||
raise Forbidden()
|
||||
|
||||
if app_model.tenant.status == TenantStatus.ARCHIVE:
|
||||
raise Forbidden()
|
||||
|
||||
return site
|
||||
|
||||
|
||||
api.add_resource(AppSiteApi, "/site")
|
||||
|
|
@ -313,7 +313,7 @@ class DatasetApi(DatasetApiResource):
|
|||
try:
|
||||
if DatasetService.delete_dataset(dataset_id_str, current_user):
|
||||
DatasetPermissionService.clear_partial_member_list(dataset_id_str)
|
||||
return {"result": "success"}, 204
|
||||
return 204
|
||||
else:
|
||||
raise NotFound("Dataset not found.")
|
||||
except services.errors.dataset.DatasetInUseError:
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ class DocumentDeleteApi(DatasetApiResource):
|
|||
except services.errors.document.DocumentIndexingError:
|
||||
raise DocumentIndexingError("Cannot delete document during indexing.")
|
||||
|
||||
return {"result": "success"}, 204
|
||||
return 204
|
||||
|
||||
|
||||
class DocumentListApi(DatasetApiResource):
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ class DatasetSegmentApi(DatasetApiResource):
|
|||
if not segment:
|
||||
raise NotFound("Segment not found.")
|
||||
SegmentService.delete_segment(segment, document, dataset)
|
||||
return {"result": "success"}, 204
|
||||
return 204
|
||||
|
||||
@cloud_edition_billing_resource_check("vector_space", "dataset")
|
||||
def post(self, tenant_id, dataset_id, document_id, segment_id):
|
||||
|
|
@ -344,7 +344,7 @@ class DatasetChildChunkApi(DatasetApiResource):
|
|||
except ChildChunkDeleteIndexServiceError as e:
|
||||
raise ChildChunkDeleteIndexError(str(e))
|
||||
|
||||
return {"result": "success"}, 204
|
||||
return 204
|
||||
|
||||
@cloud_edition_billing_resource_check("vector_space", "dataset")
|
||||
@cloud_edition_billing_knowledge_limit_check("add_segment", "dataset")
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ class KnowledgeRetrievalNode(LLMNode):
|
|||
"data_source_type": "external",
|
||||
"retriever_from": "workflow",
|
||||
"score": item.metadata.get("score"),
|
||||
"doc_metadata": item.metadata,
|
||||
},
|
||||
"title": item.metadata.get("title"),
|
||||
"content": item.page_content,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ def init_app(app: DifyApp):
|
|||
handlers=log_handlers,
|
||||
force=True,
|
||||
)
|
||||
|
||||
# Apply RequestIdFormatter to all handlers
|
||||
apply_request_id_formatter()
|
||||
|
||||
# Disable propagation for noisy loggers to avoid duplicate logs
|
||||
logging.getLogger("sqlalchemy.engine").propagate = False
|
||||
log_tz = dify_config.LOG_TZ
|
||||
|
|
@ -74,3 +78,16 @@ class RequestIdFilter(logging.Filter):
|
|||
def filter(self, record):
|
||||
record.req_id = get_request_id() if flask.has_request_context() else ""
|
||||
return True
|
||||
|
||||
|
||||
class RequestIdFormatter(logging.Formatter):
|
||||
def format(self, record):
|
||||
if not hasattr(record, "req_id"):
|
||||
record.req_id = ""
|
||||
return super().format(record)
|
||||
|
||||
|
||||
def apply_request_id_formatter():
|
||||
for handler in logging.root.handlers:
|
||||
if handler.formatter:
|
||||
handler.formatter = RequestIdFormatter(dify_config.LOG_FORMAT, dify_config.LOG_DATEFORMAT)
|
||||
|
|
|
|||
|
|
@ -114,8 +114,10 @@ def init_app(app: DifyApp):
|
|||
pass
|
||||
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter as GRPCMetricExporter
|
||||
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter as GRPCSpanExporter
|
||||
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter as HTTPMetricExporter
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter as HTTPSpanExporter
|
||||
from opentelemetry.instrumentation.celery import CeleryInstrumentor
|
||||
from opentelemetry.instrumentation.flask import FlaskInstrumentor
|
||||
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
|
||||
|
|
@ -158,19 +160,32 @@ def init_app(app: DifyApp):
|
|||
sampler = ParentBasedTraceIdRatio(dify_config.OTEL_SAMPLING_RATE)
|
||||
provider = TracerProvider(resource=resource, sampler=sampler)
|
||||
set_tracer_provider(provider)
|
||||
exporter: Union[OTLPSpanExporter, ConsoleSpanExporter]
|
||||
metric_exporter: Union[OTLPMetricExporter, ConsoleMetricExporter]
|
||||
exporter: Union[GRPCSpanExporter, HTTPSpanExporter, ConsoleSpanExporter]
|
||||
metric_exporter: Union[GRPCMetricExporter, HTTPMetricExporter, ConsoleMetricExporter]
|
||||
protocol = (dify_config.OTEL_EXPORTER_OTLP_PROTOCOL or "").lower()
|
||||
if dify_config.OTEL_EXPORTER_TYPE == "otlp":
|
||||
exporter = OTLPSpanExporter(
|
||||
endpoint=dify_config.OTLP_BASE_ENDPOINT + "/v1/traces",
|
||||
headers={"Authorization": f"Bearer {dify_config.OTLP_API_KEY}"},
|
||||
)
|
||||
metric_exporter = OTLPMetricExporter(
|
||||
endpoint=dify_config.OTLP_BASE_ENDPOINT + "/v1/metrics",
|
||||
headers={"Authorization": f"Bearer {dify_config.OTLP_API_KEY}"},
|
||||
)
|
||||
if protocol == "grpc":
|
||||
exporter = GRPCSpanExporter(
|
||||
endpoint=dify_config.OTLP_BASE_ENDPOINT,
|
||||
# Header field names must consist of lowercase letters, check RFC7540
|
||||
headers=(("authorization", f"Bearer {dify_config.OTLP_API_KEY}"),),
|
||||
insecure=True,
|
||||
)
|
||||
metric_exporter = GRPCMetricExporter(
|
||||
endpoint=dify_config.OTLP_BASE_ENDPOINT,
|
||||
headers=(("authorization", f"Bearer {dify_config.OTLP_API_KEY}"),),
|
||||
insecure=True,
|
||||
)
|
||||
else:
|
||||
exporter = HTTPSpanExporter(
|
||||
endpoint=dify_config.OTLP_BASE_ENDPOINT + "/v1/traces",
|
||||
headers={"Authorization": f"Bearer {dify_config.OTLP_API_KEY}"},
|
||||
)
|
||||
metric_exporter = HTTPMetricExporter(
|
||||
endpoint=dify_config.OTLP_BASE_ENDPOINT + "/v1/metrics",
|
||||
headers={"Authorization": f"Bearer {dify_config.OTLP_API_KEY}"},
|
||||
)
|
||||
else:
|
||||
# Fallback to console exporter
|
||||
exporter = ConsoleSpanExporter()
|
||||
metric_exporter = ConsoleMetricExporter()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
"""add index for workflow_conversation_variables.conversation_id
|
||||
|
||||
Revision ID: d28f2004b072
|
||||
Revises: 6a9f914f656c
|
||||
Create Date: 2025-05-14 14:03:36.713828
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import models as models
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'd28f2004b072'
|
||||
down_revision = '6a9f914f656c'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('workflow_conversation_variables', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('workflow_conversation_variables_conversation_id_idx'), ['conversation_id'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('workflow_conversation_variables', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('workflow_conversation_variables_conversation_id_idx'))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -770,7 +770,7 @@ class ConversationVariable(Base):
|
|||
__tablename__ = "workflow_conversation_variables"
|
||||
|
||||
id: Mapped[str] = mapped_column(StringUUID, primary_key=True)
|
||||
conversation_id: Mapped[str] = mapped_column(StringUUID, nullable=False, primary_key=True)
|
||||
conversation_id: Mapped[str] = mapped_column(StringUUID, nullable=False, primary_key=True, index=True)
|
||||
app_id: Mapped[str] = mapped_column(StringUUID, nullable=False, index=True)
|
||||
data = mapped_column(db.Text, nullable=False)
|
||||
created_at = mapped_column(db.DateTime, nullable=False, server_default=func.current_timestamp(), index=True)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||
cd "$SCRIPT_DIR/.."
|
||||
|
||||
|
||||
uv --directory api run \
|
||||
flask run --host 0.0.0.0 --port=5001 --debug
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||
cd "$SCRIPT_DIR/.."
|
||||
|
||||
|
||||
uv --directory api run \
|
||||
celery -A app.celery worker \
|
||||
-P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion
|
||||
|
|
@ -1081,6 +1081,7 @@ PLUGIN_TENCENT_COS_REGION=
|
|||
ENABLE_OTEL=false
|
||||
OTLP_BASE_ENDPOINT=http://localhost:4318
|
||||
OTLP_API_KEY=
|
||||
OTEL_EXPORTER_OTLP_PROTOCOL=
|
||||
OTEL_EXPORTER_TYPE=otlp
|
||||
OTEL_SAMPLING_RATE=0.1
|
||||
OTEL_BATCH_EXPORT_SCHEDULE_DELAY=5000
|
||||
|
|
|
|||
|
|
@ -478,6 +478,7 @@ x-shared-env: &shared-api-worker-env
|
|||
ENABLE_OTEL: ${ENABLE_OTEL:-false}
|
||||
OTLP_BASE_ENDPOINT: ${OTLP_BASE_ENDPOINT:-http://localhost:4318}
|
||||
OTLP_API_KEY: ${OTLP_API_KEY:-}
|
||||
OTEL_EXPORTER_OTLP_PROTOCOL: ${OTEL_EXPORTER_OTLP_PROTOCOL:-}
|
||||
OTEL_EXPORTER_TYPE: ${OTEL_EXPORTER_TYPE:-otlp}
|
||||
OTEL_SAMPLING_RATE: ${OTEL_SAMPLING_RATE:-0.1}
|
||||
OTEL_BATCH_EXPORT_SCHEDULE_DELAY: ${OTEL_BATCH_EXPORT_SCHEDULE_DELAY:-5000}
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
|||
{
|
||||
currentTab === CreateFromDSLModalTab.FROM_URL && (
|
||||
<div>
|
||||
<div className='system-md-semibold leading6 mb-1'>DSL URL</div>
|
||||
<div className='system-md-semibold mb-1 text-text-secondary'>DSL URL</div>
|
||||
<Input
|
||||
placeholder={t('app.importFromDSLUrlPlaceholder') || ''}
|
||||
value={dslUrlValue}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import type { FC } from 'react'
|
|||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
RiUploadCloud2Line,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
|
|
@ -10,8 +11,7 @@ import { formatFileSize } from '@/utils/format'
|
|||
import cn from '@/utils/classnames'
|
||||
import { Yaml as YamlIcon } from '@/app/components/base/icons/src/public/files'
|
||||
import { ToastContext } from '@/app/components/base/toast'
|
||||
import { UploadCloud01 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import Button from '@/app/components/base/button'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
|
||||
export type Props = {
|
||||
file: File | undefined
|
||||
|
|
@ -102,19 +102,19 @@ const Uploader: FC<Props> = ({
|
|||
/>
|
||||
<div ref={dropRef}>
|
||||
{!file && (
|
||||
<div className={cn('flex h-12 items-center rounded-xl border border-dashed border-gray-200 bg-gray-50 text-sm font-normal', dragging && 'border border-[#B2CCFF] bg-[#F5F8FF]')}>
|
||||
<div className={cn('flex h-12 items-center rounded-[10px] border border-dashed border-components-dropzone-border bg-components-dropzone-bg text-sm font-normal', dragging && 'border-components-dropzone-border-accent bg-components-dropzone-bg-accent')}>
|
||||
<div className='flex w-full items-center justify-center space-x-2'>
|
||||
<UploadCloud01 className='mr-2 h-6 w-6' />
|
||||
<div className='text-gray-500'>
|
||||
<RiUploadCloud2Line className='h-6 w-6 text-text-tertiary' />
|
||||
<div className='text-text-tertiary'>
|
||||
{t('datasetCreation.stepOne.uploader.button')}
|
||||
<span className='cursor-pointer pl-1 text-[#155eef]' onClick={selectHandle}>{t('datasetDocuments.list.batchModal.browse')}</span>
|
||||
<span className='cursor-pointer pl-1 text-text-accent' onClick={selectHandle}>{t('datasetDocuments.list.batchModal.browse')}</span>
|
||||
</div>
|
||||
</div>
|
||||
{dragging && <div ref={dragRef} className='absolute left-0 top-0 h-full w-full' />}
|
||||
</div>
|
||||
)}
|
||||
{file && (
|
||||
<div className={cn('group flex items-center rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg shadow-xs', 'hover:border-[#B2CCFF] hover:bg-[#F5F8FF]')}>
|
||||
<div className={cn('group flex items-center rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg shadow-xs', ' hover:bg-components-panel-on-panel-item-bg-hover')}>
|
||||
<div className='flex items-center justify-center p-3'>
|
||||
<YamlIcon className="h-6 w-6 shrink-0" />
|
||||
</div>
|
||||
|
|
@ -126,12 +126,10 @@ const Uploader: FC<Props> = ({
|
|||
<span>{formatFileSize(file.size)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='hidden items-center group-hover:flex'>
|
||||
<Button onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.change')}</Button>
|
||||
<div className='mx-2 h-4 w-px bg-gray-200' />
|
||||
<div className='cursor-pointer p-2' onClick={removeFile}>
|
||||
<div className='hidden items-center pr-3 group-hover:flex'>
|
||||
<ActionButton onClick={removeFile}>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary' />
|
||||
</div>
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import type {
|
|||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import type { ChatItem } from '../types'
|
||||
|
|
@ -52,6 +54,8 @@ const Question: FC<QuestionProps> = ({
|
|||
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
const [editedContent, setEditedContent] = useState(content)
|
||||
const [contentWidth, setContentWidth] = useState(0)
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const handleEdit = useCallback(() => {
|
||||
setIsEditing(true)
|
||||
|
|
@ -75,14 +79,31 @@ const Question: FC<QuestionProps> = ({
|
|||
item.nextSibling && switchSibling?.(item.nextSibling)
|
||||
}, [switchSibling, item.prevSibling, item.nextSibling])
|
||||
|
||||
const getContentWidth = () => {
|
||||
if (contentRef.current)
|
||||
setContentWidth(contentRef.current?.clientWidth)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!contentRef.current)
|
||||
return
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
getContentWidth()
|
||||
})
|
||||
resizeObserver.observe(contentRef.current)
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='mb-2 flex justify-end pl-14 last:mb-0'>
|
||||
<div className={cn('group relative mr-4 flex max-w-full items-start', isEditing && 'flex-1')}>
|
||||
<div className='mb-2 flex justify-end last:mb-0'>
|
||||
<div className={cn('group relative mr-4 flex max-w-full items-start pl-14', isEditing && 'flex-1')}>
|
||||
<div className={cn('mr-2 gap-1', isEditing ? 'hidden' : 'flex')}>
|
||||
<div className="
|
||||
absolutegap-0.5 hidden rounded-[10px] border-[0.5px] border-components-actionbar-border
|
||||
bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm group-hover:flex
|
||||
">
|
||||
<div
|
||||
className="absolute hidden gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm group-hover:flex"
|
||||
style={{ right: contentWidth + 8 }}
|
||||
>
|
||||
<ActionButton onClick={() => {
|
||||
copy(content)
|
||||
Toast.notify({ type: 'success', message: t('common.actionMsg.copySuccessfully') })
|
||||
|
|
@ -95,6 +116,7 @@ const Question: FC<QuestionProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref={contentRef}
|
||||
className='w-full rounded-2xl bg-[#D1E9FF]/50 px-4 py-3 text-sm text-gray-900'
|
||||
style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon L">
|
||||
<g id="Vector">
|
||||
<path d="M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z" fill="#354052"/>
|
||||
<path d="M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z" fill="#354052"/>
|
||||
<path d="M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z" fill="#354052"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 579 B |
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon L"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Vector"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Collapse"
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Collapse.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = (
|
||||
{
|
||||
ref,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement> & {
|
||||
ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
|
||||
},
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />
|
||||
|
||||
Icon.displayName = 'Collapse'
|
||||
|
||||
export default Icon
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
export { default as AlignLeft } from './AlignLeft'
|
||||
export { default as BezierCurve03 } from './BezierCurve03'
|
||||
export { default as Collapse } from './Collapse'
|
||||
export { default as Colors } from './Colors'
|
||||
export { default as ImageIndentLeft } from './ImageIndentLeft'
|
||||
export { default as LeftIndent02 } from './LeftIndent02'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
RiCheckLine,
|
||||
RiComputerLine,
|
||||
RiMoonLine,
|
||||
RiSunLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useTheme } from 'next-themes'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
|
||||
export type Theme = 'light' | 'dark' | 'system'
|
||||
|
||||
export default function ThemeSelector() {
|
||||
const { t } = useTranslation()
|
||||
const { theme, setTheme } = useTheme()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleThemeChange = (newTheme: Theme) => {
|
||||
setTheme(newTheme)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const getCurrentIcon = () => {
|
||||
switch (theme) {
|
||||
case 'light': return <RiSunLine className='h-4 w-4 text-text-tertiary' />
|
||||
case 'dark': return <RiMoonLine className='h-4 w-4 text-text-tertiary' />
|
||||
default: return <RiComputerLine className='h-4 w-4 text-text-tertiary' />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-end'
|
||||
offset={{ mainAxis: 6 }}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
<ActionButton
|
||||
className={`h-8 w-8 p-[6px] ${open && 'bg-state-base-hover'}`}
|
||||
>
|
||||
{getCurrentIcon()}
|
||||
</ActionButton>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className='flex w-[144px] flex-col items-start rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
|
||||
<button
|
||||
className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
|
||||
onClick={() => handleThemeChange('light')}
|
||||
>
|
||||
<RiSunLine className='h-4 w-4 text-text-tertiary' />
|
||||
<div className='flex grow items-center justify-start px-1'>
|
||||
<span className='system-md-regular'>{t('common.theme.light')}</span>
|
||||
</div>
|
||||
{theme === 'light' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
</div>}
|
||||
</button>
|
||||
<button
|
||||
className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
|
||||
onClick={() => handleThemeChange('dark')}
|
||||
>
|
||||
<RiMoonLine className='h-4 w-4 text-text-tertiary' />
|
||||
<div className='flex grow items-center justify-start px-1'>
|
||||
<span className='system-md-regular'>{t('common.theme.dark')}</span>
|
||||
</div>
|
||||
{theme === 'dark' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
</div>}
|
||||
</button>
|
||||
<button
|
||||
className='flex w-full items-center gap-1 rounded-lg px-2 py-1.5 text-text-secondary hover:bg-state-base-hover'
|
||||
onClick={() => handleThemeChange('system')}
|
||||
>
|
||||
<RiComputerLine className='h-4 w-4 text-text-tertiary' />
|
||||
<div className='flex grow items-center justify-start px-1'>
|
||||
<span className='system-md-regular'>{t('common.theme.auto')}</span>
|
||||
</div>
|
||||
{theme === 'system' && <div className='flex h-4 w-4 shrink-0 items-center justify-center'>
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
</div>}
|
||||
</button>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
'use client'
|
||||
import {
|
||||
RiComputerLine,
|
||||
RiMoonLine,
|
||||
RiSunLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type Theme = 'light' | 'dark' | 'system'
|
||||
|
||||
export default function ThemeSwitcher() {
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
const handleThemeChange = (newTheme: Theme) => {
|
||||
setTheme(newTheme)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex items-center rounded-[10px] bg-components-segmented-control-bg-normal p-0.5'>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
theme === 'system' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => handleThemeChange('system')}
|
||||
>
|
||||
<div className='p-0.5'>
|
||||
<RiComputerLine className='h-4 w-4' />
|
||||
</div>
|
||||
</div>
|
||||
<div className={cn('h-[14px] w-px bg-transparent', theme === 'dark' && 'bg-divider-regular')}></div>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
theme === 'light' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => handleThemeChange('light')}
|
||||
>
|
||||
<div className='p-0.5'>
|
||||
<RiSunLine className='h-4 w-4' />
|
||||
</div>
|
||||
</div>
|
||||
<div className={cn('h-[14px] w-px bg-transparent', theme === 'system' && 'bg-divider-regular')}></div>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
theme === 'dark' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => handleThemeChange('dark')}
|
||||
>
|
||||
<div className='p-0.5'>
|
||||
<RiMoonLine className='h-4 w-4' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ const Doc = ({ apiBaseUrl }: DocProps) => {
|
|||
</button>
|
||||
)}
|
||||
</div>
|
||||
<article className={cn('prose-xl prose mx-1 rounded-t-xl bg-background-default px-4 pt-16 sm:mx-12', theme === Theme.dark && 'dark:prose-invert')}>
|
||||
<article className={cn('prose-xl prose mx-1 rounded-t-xl bg-background-default px-4 pt-16 sm:mx-12', theme === Theme.dark && 'prose-invert')}>
|
||||
{Template}
|
||||
</article>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ const Doc = ({ appDetail }: IDocProps) => {
|
|||
</button>
|
||||
)}
|
||||
</div>
|
||||
<article className={cn('prose-xl prose', theme === Theme.dark && 'dark:prose-invert')} >
|
||||
<article className={cn('prose-xl prose', theme === Theme.dark && 'prose-invert')} >
|
||||
{(appDetail?.mode === 'chat' || appDetail?.mode === 'agent-chat') && (
|
||||
(() => {
|
||||
switch (locale) {
|
||||
|
|
|
|||
|
|
@ -2,20 +2,18 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import { t } from 'i18next'
|
||||
import s from './style.module.css'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import CopyFeedback from '@/app/components/base/copy-feedback'
|
||||
|
||||
type IInputCopyProps = {
|
||||
value?: string
|
||||
className?: string
|
||||
readOnly?: boolean
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
const InputCopy = ({
|
||||
value = '',
|
||||
className,
|
||||
readOnly = true,
|
||||
children,
|
||||
}: IInputCopyProps) => {
|
||||
const [isCopied, setIsCopied] = useState(false)
|
||||
|
|
@ -45,23 +43,12 @@ const InputCopy = ({
|
|||
popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
|
||||
position='bottom'
|
||||
>
|
||||
{value}
|
||||
<span className='text-text-secondary'>{value}</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-4 shrink-0 border bg-divider-regular" />
|
||||
<Tooltip
|
||||
popupContent={isCopied ? `${t('appApi.copied')}` : `${t('appApi.copy')}`}
|
||||
position='bottom'
|
||||
>
|
||||
<div className="shrink-0 px-0.5">
|
||||
<div className={`box-border flex h-[30px] w-[30px] cursor-pointer items-center justify-center rounded-lg hover:bg-state-base-hover ${s.copyIcon} ${isCopied ? s.copied : ''}`} onClick={() => {
|
||||
copy(value)
|
||||
setIsCopied(true)
|
||||
}}>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="h-4 w-px shrink-0 bg-divider-regular" />
|
||||
<div className='mx-1'><CopyFeedback content={value} /></div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -647,3 +647,62 @@ The text generation application offers non-session support and is ideal for tran
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='Get Application WebApp Settings'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get the WebApp settings of the application.
|
||||
### Response
|
||||
- `title` (string) WebApp name
|
||||
- `chat_color_theme` (string) Chat color theme, in hex format
|
||||
- `chat_color_theme_inverted` (bool) Whether the chat color theme is inverted
|
||||
- `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
|
||||
- `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL.
|
||||
- `icon_background` (string) Background color in hex format
|
||||
- `icon_url` (string) Icon URL
|
||||
- `description` (string) Description
|
||||
- `copyright` (string) Copyright information
|
||||
- `privacy_policy` (string) Privacy policy link
|
||||
- `custom_disclaimer` (string) Custom disclaimer
|
||||
- `default_language` (string) Default language
|
||||
- `show_workflow_steps` (bool) Whether to show workflow details
|
||||
- `use_icon_as_answer_icon` (bool) Whether to replace 🤖 in chat with the WebApp icon
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
|
|
|||
|
|
@ -645,3 +645,62 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='アプリのWebApp設定を取得'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
アプリのWebApp設定を取得するために使用します。
|
||||
### レスポンス
|
||||
- `title` (string) WebApp名
|
||||
- `chat_color_theme` (string) チャットの色テーマ、16進数形式
|
||||
- `chat_color_theme_inverted` (bool) チャットの色テーマを反転するかどうか
|
||||
- `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像
|
||||
- `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL
|
||||
- `icon_background` (string) 16進数形式の背景色
|
||||
- `icon_url` (string) アイコンのURL
|
||||
- `description` (string) 説明
|
||||
- `copyright` (string) 著作権情報
|
||||
- `privacy_policy` (string) プライバシーポリシーのリンク
|
||||
- `custom_disclaimer` (string) カスタム免責事項
|
||||
- `default_language` (string) デフォルト言語
|
||||
- `show_workflow_steps` (bool) ワークフローの詳細を表示するかどうか
|
||||
- `use_icon_as_answer_icon` (bool) WebAppのアイコンをチャット内の🤖に置き換えるかどうか
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
|
|
|||
|
|
@ -507,7 +507,6 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
|
|
@ -612,6 +611,64 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
|||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='获取应用 WebApp 设置'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的 WebApp 设置
|
||||
### Response
|
||||
- `title` (string) WebApp 名称
|
||||
- `chat_color_theme` (string) 聊天颜色主题, hex 格式
|
||||
- `chat_color_theme_inverted` (bool) 聊天颜色主题是否反转
|
||||
- `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片
|
||||
- `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL
|
||||
- `icon_background` (string) hex 格式的背景色
|
||||
- `icon_url` (string) 图标 URL
|
||||
- `description` (string) 描述
|
||||
- `copyright` (string) 版权信息
|
||||
- `privacy_policy` (string) 隐私政策链接
|
||||
- `custom_disclaimer` (string) 自定义免责声明
|
||||
- `default_language` (string) 默认语言
|
||||
- `show_workflow_steps` (bool) 是否显示工作流详情
|
||||
- `use_icon_as_answer_icon` (bool) 是否使用 WebApp 图标替换聊天中的 🤖
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
||||
<Heading
|
||||
url='/apps/annotations'
|
||||
method='GET'
|
||||
|
|
|
|||
|
|
@ -1305,6 +1305,64 @@ Chat applications support session persistence, allowing previous chat history to
|
|||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='Get Application WebApp Settings'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get the WebApp settings of the application.
|
||||
### Response
|
||||
- `title` (string) WebApp name
|
||||
- `chat_color_theme` (string) Chat color theme, in hex format
|
||||
- `chat_color_theme_inverted` (bool) Whether the chat color theme is inverted
|
||||
- `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
|
||||
- `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL
|
||||
- `icon_background` (string) Background color in hex format
|
||||
- `icon_url` (string) Icon URL
|
||||
- `description` (string) Description
|
||||
- `copyright` (string) Copyright information
|
||||
- `privacy_policy` (string) Privacy policy link
|
||||
- `custom_disclaimer` (string) Custom disclaimer
|
||||
- `default_language` (string) Default language
|
||||
- `show_workflow_steps` (bool) Whether to show workflow details
|
||||
- `use_icon_as_answer_icon` (bool) Whether to replace 🤖 in chat with the WebApp icon
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
||||
<Heading
|
||||
url='/apps/annotations'
|
||||
method='GET'
|
||||
|
|
|
|||
|
|
@ -1303,3 +1303,63 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='アプリのWebApp設定を取得'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
アプリのWebApp設定を取得するために使用します。
|
||||
### 応答
|
||||
- `title` (string) WebApp名
|
||||
- `chat_color_theme` (string) チャットの色テーマ、16進数形式
|
||||
- `chat_color_theme_inverted` (bool) チャットの色テーマを反転するかどうか
|
||||
- `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像
|
||||
- `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL
|
||||
- `icon_background` (string) 16進数形式の背景色
|
||||
- `icon_url` (string) アイコンのURL
|
||||
- `description` (string) 説明
|
||||
- `copyright` (string) 著作権情報
|
||||
- `privacy_policy` (string) プライバシーポリシーのリンク
|
||||
- `custom_disclaimer` (string) カスタム免責事項
|
||||
- `default_language` (string) デフォルト言語
|
||||
- `show_workflow_steps` (bool) ワークフローの詳細を表示するかどうか
|
||||
- `use_icon_as_answer_icon` (bool) WebAppのアイコンをチャット内の🤖に置き換えるかどうか
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
|
|
|||
|
|
@ -1329,7 +1329,63 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
|||
</Row>
|
||||
---
|
||||
|
||||
---
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='获取应用 WebApp 设置'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的 WebApp 设置
|
||||
### Response
|
||||
- `title` (string) WebApp 名称
|
||||
- `chat_color_theme` (string) 聊天颜色主题, hex 格式
|
||||
- `chat_color_theme_inverted` (bool) 聊天颜色主题是否反转
|
||||
- `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片
|
||||
- `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL
|
||||
- `icon_background` (string) hex 格式的背景色
|
||||
- `icon_url` (string) 图标 URL
|
||||
- `description` (string) 描述
|
||||
- `copyright` (string) 版权信息
|
||||
- `privacy_policy` (string) 隐私政策链接
|
||||
- `custom_disclaimer` (string) 自定义免责声明
|
||||
- `default_language` (string) 默认语言
|
||||
- `show_workflow_steps` (bool) 是否显示工作流详情
|
||||
- `use_icon_as_answer_icon` (bool) 是否使用 WebApp 图标替换聊天中的 🤖
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
||||
<Heading
|
||||
url='/apps/annotations'
|
||||
|
|
|
|||
|
|
@ -1341,6 +1341,64 @@ Chat applications support session persistence, allowing previous chat history to
|
|||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='Get Application WebApp Settings'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get the WebApp settings of the application.
|
||||
### Response
|
||||
- `title` (string) WebApp name
|
||||
- `chat_color_theme` (string) Chat color theme, in hex format
|
||||
- `chat_color_theme_inverted` (bool) Whether the chat color theme is inverted
|
||||
- `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
|
||||
- `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL
|
||||
- `icon_background` (string) Background color in hex format
|
||||
- `icon_url` (string) Icon URL
|
||||
- `description` (string) Description
|
||||
- `copyright` (string) Copyright information
|
||||
- `privacy_policy` (string) Privacy policy link
|
||||
- `custom_disclaimer` (string) Custom disclaimer
|
||||
- `default_language` (string) Default language
|
||||
- `show_workflow_steps` (bool) Whether to show workflow details
|
||||
- `use_icon_as_answer_icon` (bool) Whether to replace 🤖 in chat with the WebApp icon
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
||||
<Heading
|
||||
url='/apps/annotations'
|
||||
method='GET'
|
||||
|
|
|
|||
|
|
@ -1330,3 +1330,63 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='アプリのWebApp設定を取得'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
アプリのWebApp設定を取得するために使用します。
|
||||
### 応答
|
||||
- `title` (string) WebApp名
|
||||
- `chat_color_theme` (string) チャットの色テーマ、16進数形式
|
||||
- `chat_color_theme_inverted` (bool) チャットの色テーマを反転するかどうか
|
||||
- `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像
|
||||
- `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL
|
||||
- `icon_background` (string) 16進数形式の背景色
|
||||
- `icon_url` (string) アイコンのURL
|
||||
- `description` (string) 説明
|
||||
- `copyright` (string) 著作権情報
|
||||
- `privacy_policy` (string) プライバシーポリシーのリンク
|
||||
- `custom_disclaimer` (string) カスタム免責事項
|
||||
- `default_language` (string) デフォルト言語
|
||||
- `show_workflow_steps` (bool) ワークフローの詳細を表示するかどうか
|
||||
- `use_icon_as_answer_icon` (bool) WebAppのアイコンをチャット内の🤖に置き換えるかどうか
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
|
|
|||
|
|
@ -1332,3 +1332,63 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='获取应用 WebApp 设置'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的 WebApp 设置
|
||||
### Response
|
||||
- `title` (string) WebApp 名称
|
||||
- `chat_color_theme` (string) 聊天颜色主题, hex 格式
|
||||
- `chat_color_theme_inverted` (bool) 聊天颜色主题是否反转
|
||||
- `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片
|
||||
- `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL
|
||||
- `icon_background` (string) hex 格式的背景色
|
||||
- `icon_url` (string) 图标 URL
|
||||
- `description` (string) 描述
|
||||
- `copyright` (string) 版权信息
|
||||
- `privacy_policy` (string) 隐私政策链接
|
||||
- `custom_disclaimer` (string) 自定义免责声明
|
||||
- `default_language` (string) 默认语言
|
||||
- `show_workflow_steps` (bool) 是否显示工作流详情
|
||||
- `use_icon_as_answer_icon` (bool) 是否使用 WebApp 图标替换聊天中的 🤖
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"chat_color_theme": "#ff4a4a",
|
||||
"chat_color_theme_inverted": false,
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
"use_icon_as_answer_icon": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
|
|
|||
|
|
@ -737,3 +737,56 @@ Workflow applications offers non-session support and is ideal for translation, a
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='Get Application WebApp Settings'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get the WebApp settings of the application.
|
||||
### Response
|
||||
- `title` (string) WebApp name
|
||||
- `icon_type` (string) Icon type, `emoji` - emoji, `image` - picture
|
||||
- `icon` (string) Icon. If it's `emoji` type, it's an emoji symbol; if it's `image` type, it's an image URL.
|
||||
- `icon_background` (string) Background color in hex format
|
||||
- `icon_url` (string) Icon URL
|
||||
- `description` (string) Description
|
||||
- `copyright` (string) Copyright information
|
||||
- `privacy_policy` (string) Privacy policy link
|
||||
- `custom_disclaimer` (string) Custom disclaimer
|
||||
- `default_language` (string) Default language
|
||||
- `show_workflow_steps` (bool) Whether to show workflow details
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
|
|
|||
|
|
@ -740,3 +740,57 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
———
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='アプリのWebApp設定を取得'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
アプリのWebApp設定を取得するために使用します。
|
||||
### 応答
|
||||
- `title` (string) WebApp名
|
||||
- `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像
|
||||
- `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL
|
||||
- `icon_background` (string) 16進数形式の背景色
|
||||
- `icon_url` (string) アイコンのURL
|
||||
- `description` (string) 説明
|
||||
- `copyright` (string) 著作権情報
|
||||
- `privacy_policy` (string) プライバシーポリシーのリンク
|
||||
- `custom_disclaimer` (string) カスタム免責事項
|
||||
- `default_language` (string) デフォルト言語
|
||||
- `show_workflow_steps` (bool) ワークフローの詳細を表示するかどうか
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
||||
|
|
|
|||
|
|
@ -727,3 +727,57 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
|
|||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/site'
|
||||
method='GET'
|
||||
title='获取应用 WebApp 设置'
|
||||
name='#site'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的 WebApp 设置
|
||||
### Response
|
||||
- `title` (string) WebApp 名称
|
||||
- `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片
|
||||
- `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL
|
||||
- `icon_background` (string) hex 格式的背景色
|
||||
- `icon_url` (string) 图标 URL
|
||||
- `description` (string) 描述
|
||||
- `copyright` (string) 版权信息
|
||||
- `privacy_policy` (string) 隐私政策链接
|
||||
- `custom_disclaimer` (string) 自定义免责声明
|
||||
- `default_language` (string) 默认语言
|
||||
- `show_workflow_steps` (bool) 是否显示工作流详情
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="POST" label="/meta" targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/site' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"title": "My App",
|
||||
"icon_type": "emoji",
|
||||
"icon": "😄",
|
||||
"icon_background": "#FFEAD5",
|
||||
"icon_url": null,
|
||||
"description": "This is my app.",
|
||||
"copyright": "all rights reserved",
|
||||
"privacy_policy": "",
|
||||
"custom_disclaimer": "All generated by AI",
|
||||
"default_language": "en-US",
|
||||
"show_workflow_steps": false,
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
___
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ const Category: FC<ICategoryProps> = ({
|
|||
const isAllCategories = !list.includes(value as AppCategory) || value === allCategoriesEn
|
||||
|
||||
const itemClassName = (isSelected: boolean) => cn(
|
||||
'flex h-[32px] cursor-pointer items-center rounded-lg border-[0.5px] border-transparent px-3 py-[7px] font-medium leading-[18px] text-gray-700 hover:bg-gray-200',
|
||||
isSelected && 'border-gray-200 bg-white text-primary-600 shadow-xs hover:bg-white',
|
||||
'flex h-[32px] cursor-pointer items-center rounded-lg border-[0.5px] border-transparent px-3 py-[7px] font-medium leading-[18px] text-text-tertiary hover:bg-components-main-nav-nav-button-bg-active',
|
||||
isSelected && 'border-components-main-nav-nav-button-border bg-components-main-nav-nav-button-bg-active text-components-main-nav-nav-button-text-active shadow-xs',
|
||||
)
|
||||
|
||||
return (
|
||||
|
|
@ -50,7 +50,7 @@ const Category: FC<ICategoryProps> = ({
|
|||
className={itemClassName(name === value)}
|
||||
onClick={() => onChange(name)}
|
||||
>
|
||||
{categoryI18n[name] ? t(`explore.category.${name}`) : name}
|
||||
{(categoryI18n as any)[name] ? t(`explore.category.${name}`) : name}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
RiMap2Line,
|
||||
RiSettings3Line,
|
||||
RiStarLine,
|
||||
RiTShirt2Line,
|
||||
} from '@remixicon/react'
|
||||
import Link from 'next/link'
|
||||
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
|
||||
|
|
@ -25,6 +26,7 @@ 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'
|
||||
import AppContext, { useAppContext } from '@/context/app-context'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
|
|
@ -82,8 +84,8 @@ export default function AppSelector() {
|
|||
<MenuItems
|
||||
className="
|
||||
absolute right-0 mt-1.5 w-60 max-w-80
|
||||
origin-top-right divide-y divide-divider-subtle rounded-xl bg-components-panel-bg-blur
|
||||
shadow-lg focus:outline-none
|
||||
origin-top-right divide-y divide-divider-subtle rounded-xl bg-components-panel-bg-blur shadow-lg
|
||||
backdrop-blur-sm focus:outline-none
|
||||
"
|
||||
>
|
||||
<MenuItem disabled>
|
||||
|
|
@ -186,6 +188,15 @@ export default function AppSelector() {
|
|||
)
|
||||
}
|
||||
</div>
|
||||
<MenuItem disabled>
|
||||
<div className='p-1'>
|
||||
<div className={cn(itemClassName, 'hover:bg-transparent')}>
|
||||
<RiTShirt2Line className='size-4 shrink-0 text-text-tertiary' />
|
||||
<div className='system-md-regular grow px-1 text-text-secondary'>{t('common.theme.theme')}</div>
|
||||
<ThemeSwitcher/>
|
||||
</div>
|
||||
</div>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<div className='p-1' onClick={() => handleLogout()}>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useCallback, useState } from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Link from 'next/link'
|
||||
import {
|
||||
|
|
@ -29,6 +30,7 @@ const InstallFromMarketplace = ({
|
|||
searchText,
|
||||
}: InstallFromMarketplaceProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const [collapse, setCollapse] = useState(false)
|
||||
const locale = getLocaleOnClient()
|
||||
const {
|
||||
|
|
@ -53,7 +55,7 @@ const InstallFromMarketplace = ({
|
|||
</div>
|
||||
<div className='mb-2 flex items-center pt-2'>
|
||||
<span className='system-sm-regular pr-1 text-text-tertiary'>{t('common.modelProvider.discoverMore')}</span>
|
||||
<Link target="_blank" href={`${MARKETPLACE_URL_PREFIX}`} className='system-sm-medium inline-flex items-center text-text-accent'>
|
||||
<Link target="_blank" href={`${MARKETPLACE_URL_PREFIX}${theme ? `?theme=${theme}` : ''}`} className='system-sm-medium inline-flex items-center text-text-accent'>
|
||||
{t('plugin.marketplace.difyMarketplace')}
|
||||
<RiArrowRightUpLine className='h-4 w-4' />
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
'use client'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { RiArrowRightUpLine } from '@remixicon/react'
|
||||
import { getPluginLinkInMarketplace } from '../utils'
|
||||
import Card from '@/app/components/plugins/card'
|
||||
|
|
@ -22,6 +23,7 @@ const CardWrapper = ({
|
|||
locale,
|
||||
}: CardWrapperProps) => {
|
||||
const { t } = useMixedTranslation(locale)
|
||||
const { theme } = useTheme()
|
||||
const [isShowInstallFromMarketplace, {
|
||||
setTrue: showInstallFromMarketplace,
|
||||
setFalse: hideInstallFromMarketplace,
|
||||
|
|
@ -54,7 +56,7 @@ const CardWrapper = ({
|
|||
>
|
||||
{t('plugin.detailPanel.operation.install')}
|
||||
</Button>
|
||||
<a href={`${getPluginLinkInMarketplace(plugin)}?language=${localeFromLocale}`} target='_blank' className='block w-[calc(50%-4px)] flex-1 shrink-0'>
|
||||
<a href={`${getPluginLinkInMarketplace(plugin)}?language=${localeFromLocale}${theme ? `&theme=${theme}` : ''}`} target='_blank' className='block w-[calc(50%-4px)] flex-1 shrink-0'>
|
||||
<Button
|
||||
className='w-full gap-0.5'
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import {
|
||||
|
|
@ -49,6 +50,7 @@ const DetailHeader = ({
|
|||
onUpdate,
|
||||
}: Props) => {
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const locale = useGetLanguage()
|
||||
const { checkForUpdates, fetchReleases } = useGitHubReleases()
|
||||
const { setShowUpdatePluginModal } = useModalContext()
|
||||
|
|
@ -85,9 +87,9 @@ const DetailHeader = ({
|
|||
if (isFromGitHub)
|
||||
return `https://github.com/${meta!.repo}`
|
||||
if (isFromMarketplace)
|
||||
return `${MARKETPLACE_URL_PREFIX}/plugins/${author}/${name}`
|
||||
return `${MARKETPLACE_URL_PREFIX}/plugins/${author}/${name}${theme ? `?theme=${theme}` : ''}`
|
||||
return ''
|
||||
}, [author, isFromGitHub, isFromMarketplace, meta, name])
|
||||
}, [author, isFromGitHub, isFromMarketplace, meta, name, theme])
|
||||
|
||||
const [isShowUpdateModal, {
|
||||
setTrue: showUpdateModal,
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||
<>
|
||||
{isString && (
|
||||
<Input
|
||||
className={cn(inputsIsFocus[variable] ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'rounded-lg border px-3 py-[6px]')}
|
||||
className={cn(inputsIsFocus[variable] ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs' : 'border-components-input-border-hover bg-components-input-bg-normal', 'rounded-lg border px-3 py-[6px]')}
|
||||
value={varInput?.value as string || ''}
|
||||
onChange={handleMixedTypeChange(variable)}
|
||||
nodesOutputVars={nodeOutputVars}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import {
|
||||
RiArrowRightUpLine,
|
||||
RiBugLine,
|
||||
|
|
@ -38,6 +39,7 @@ const PluginItem: FC<Props> = ({
|
|||
plugin,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const { categoriesMap } = useSingleCategories()
|
||||
const currentPluginID = usePluginPageContext(v => v.currentPluginID)
|
||||
const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID)
|
||||
|
|
@ -164,7 +166,7 @@ const PluginItem: FC<Props> = ({
|
|||
}
|
||||
{source === PluginSource.marketplace
|
||||
&& <>
|
||||
<a href={`${MARKETPLACE_URL_PREFIX}/plugins/${author}/${name}`} target='_blank' className='flex items-center gap-0.5'>
|
||||
<a href={`${MARKETPLACE_URL_PREFIX}/plugins/${author}/${name}${theme ? `?theme=${theme}` : ''}`} target='_blank' className='flex items-center gap-0.5'>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{t('plugin.from')} <span className='text-text-secondary'>marketplace</span></div>
|
||||
<RiArrowRightUpLine className='h-3 w-3 text-text-tertiary' />
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
'use client'
|
||||
import React from 'react'
|
||||
import type { FC } from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiArrowRightUpLine } from '@remixicon/react'
|
||||
import Badge from '../base/badge'
|
||||
|
|
@ -28,6 +29,7 @@ const ProviderCard: FC<Props> = ({
|
|||
}) => {
|
||||
const getValueFromI18nObject = useRenderI18nObject()
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const [isShowInstallFromMarketplace, {
|
||||
setTrue: showInstallFromMarketplace,
|
||||
setFalse: hideInstallFromMarketplace,
|
||||
|
|
@ -74,7 +76,7 @@ const ProviderCard: FC<Props> = ({
|
|||
className='grow'
|
||||
variant='secondary'
|
||||
>
|
||||
<a href={`${getPluginLinkInMarketplace(payload)}?language=${locale}`} target='_blank' className='flex items-center gap-0.5'>
|
||||
<a href={`${getPluginLinkInMarketplace(payload)}?language=${locale}${theme ? `&theme=${theme}` : ''}`} target='_blank' className='flex items-center gap-0.5'>
|
||||
{t('plugin.detailPanel.operation.detail')}
|
||||
<RiArrowRightUpLine className='h-4 w-4' />
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import {
|
|||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import ThemeSwitcher from '@/app/components/base/theme-switcher'
|
||||
import InfoModal from './info-modal'
|
||||
import type { SiteInfo } from '@/models/share'
|
||||
import cn from '@/utils/classnames'
|
||||
|
|
@ -59,6 +61,13 @@ const MenuDropdown: FC<Props> = ({
|
|||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-50'>
|
||||
<div className='w-[224px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm'>
|
||||
<div className='p-1'>
|
||||
<div className={cn('system-md-regular flex cursor-pointer items-center rounded-lg py-1.5 pl-3 pr-2 text-text-secondary')}>
|
||||
<div className='grow'>{t('common.theme.theme')}</div>
|
||||
<ThemeSwitcher/>
|
||||
</div>
|
||||
</div>
|
||||
<Divider type='horizontal' className='my-0' />
|
||||
<div className='p-1'>
|
||||
{data?.privacy_policy && (
|
||||
<a href={data.privacy_policy} target='_blank' className='system-md-regular flex cursor-pointer items-center rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover'>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {
|
|||
useEffect,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import {
|
||||
RiArrowRightUpLine,
|
||||
RiArrowUpDoubleLine,
|
||||
|
|
@ -25,7 +26,7 @@ const Marketplace = ({
|
|||
}: MarketplaceProps) => {
|
||||
const locale = getLocaleOnClient()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { theme } = useTheme()
|
||||
const {
|
||||
isLoading,
|
||||
marketplaceCollections,
|
||||
|
|
@ -83,7 +84,7 @@ const Marketplace = ({
|
|||
</span>
|
||||
{t('common.operation.in')}
|
||||
<a
|
||||
href={`${MARKETPLACE_URL_PREFIX}?language=${locale}&q=${searchPluginText}&tags=${filterPluginTags.join(',')}`}
|
||||
href={`${MARKETPLACE_URL_PREFIX}?language=${locale}&q=${searchPluginText}&tags=${filterPluginTags.join(',')}${theme ? `&theme=${theme}` : ''}`}
|
||||
className='system-sm-medium ml-1 flex items-center text-text-accent'
|
||||
target='_blank'
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
|
|
@ -31,6 +32,7 @@ const OperationDropdown: FC<Props> = ({
|
|||
version,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const openRef = useRef(open)
|
||||
const setOpen = useCallback((v: boolean) => {
|
||||
onOpenChange(v)
|
||||
|
|
@ -78,7 +80,7 @@ const OperationDropdown: FC<Props> = ({
|
|||
<PortalToFollowElemContent className='z-[9999]'>
|
||||
<div className='w-[112px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
|
||||
<div onClick={handleDownload} className='system-md-regular cursor-pointer rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover'>{t('common.operation.download')}</div>
|
||||
<a href={`${MARKETPLACE_URL_PREFIX}/plugins/${author}/${name}`} target='_blank' className='system-md-regular block cursor-pointer rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover'>{t('common.operation.viewDetails')}</a>
|
||||
<a href={`${MARKETPLACE_URL_PREFIX}/plugins/${author}/${name}${theme ? `?theme=${theme}` : ''}`} target='_blank' className='system-md-regular block cursor-pointer rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover'>{t('common.operation.viewDetails')}</a>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
|
|
|
|||
|
|
@ -140,6 +140,16 @@ const WorkflowChecklist = ({
|
|||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
node.varErrorMessage?.map((errorMessage: string) => (
|
||||
<div className='rounded-b-lg bg-gray-25 px-3 py-2'>
|
||||
<div className='flex text-xs leading-[18px] text-gray-500'>
|
||||
<AlertTriangle className='mr-2 mt-[3px] h-3 w-3 text-[#F79009]' />
|
||||
{errorMessage}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { useStore } from '../store'
|
|||
import {
|
||||
getToolCheckParams,
|
||||
getValidTreeNodes,
|
||||
transformStartNodeVariables,
|
||||
} from '../utils'
|
||||
import {
|
||||
CUSTOM_NODE,
|
||||
|
|
@ -45,6 +46,9 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
|||
const { data: strategyProviders } = useStrategyProviders()
|
||||
const datasetsDetail = useDatasetsDetailStore(s => s.datasetsDetail)
|
||||
|
||||
const chatVarList = useStore(s => s.conversationVariables)
|
||||
const environmentVariables = useStore(s => s.environmentVariables)
|
||||
|
||||
const getCheckData = useCallback((data: CommonNodeType<{}>) => {
|
||||
let checkData = data
|
||||
if (data.type === BlockEnum.KnowledgeRetrieval) {
|
||||
|
|
@ -64,7 +68,10 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
|||
|
||||
const needWarningNodes = useMemo(() => {
|
||||
const list = []
|
||||
const { validNodes } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges)
|
||||
const { validNodes } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges, true)
|
||||
|
||||
const allVariablesMap = transformStartNodeVariables(chatVarList, environmentVariables)
|
||||
const errMessageMap = new Map()
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i]
|
||||
|
|
@ -110,8 +117,32 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
|||
toolIcon,
|
||||
unConnected: !validNodes.find(n => n.id === node.id),
|
||||
errorMessage,
|
||||
varErrorMessage: [],
|
||||
})
|
||||
}
|
||||
errMessageMap.set(node.id, list[list.length - 1])
|
||||
if (nodesExtraData[node.data.type as BlockEnum].checkVarValid) {
|
||||
const { errorMessage: varErrorMessages } = nodesExtraData[node.data.type as BlockEnum].checkVarValid(node.data, { ...allVariablesMap, ...node._parentOutputVarMap }, t)
|
||||
|
||||
if (varErrorMessages?.length) {
|
||||
const errMessage = errMessageMap.get(node.id)
|
||||
if (errMessage) {
|
||||
errMessage.varErrorMessage = varErrorMessages
|
||||
}
|
||||
else {
|
||||
list.push({
|
||||
id: node.id,
|
||||
type: node.data.type,
|
||||
title: node.data.title,
|
||||
toolIcon,
|
||||
unConnected: !validNodes.find(n => n.id === node.id),
|
||||
errorMessage: '',
|
||||
varErrorMessage: varErrorMessages,
|
||||
})
|
||||
errMessageMap.set(node.id, list[list.length - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,8 +164,13 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
|||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < validNodes.length; i++) {
|
||||
const node = validNodes[i]
|
||||
delete node._parentOutputVarMap
|
||||
}
|
||||
|
||||
return list
|
||||
}, [nodes, edges, isChatMode, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders, getCheckData])
|
||||
}, [nodes, edges, isChatMode, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders, getCheckData, chatVarList, environmentVariables])
|
||||
|
||||
return needWarningNodes
|
||||
}
|
||||
|
|
@ -153,6 +189,9 @@ export const useChecklistBeforePublish = () => {
|
|||
const updateDatasetsDetail = useDatasetsDetailStore(s => s.updateDatasetsDetail)
|
||||
const updateTime = useRef(0)
|
||||
|
||||
const chatVarList = useStore(s => s.conversationVariables)
|
||||
const environmentVariables = useStore(s => s.environmentVariables)
|
||||
|
||||
const getCheckData = useCallback((data: CommonNodeType<{}>, datasets: DataSet[]) => {
|
||||
let checkData = data
|
||||
if (data.type === BlockEnum.KnowledgeRetrieval) {
|
||||
|
|
@ -183,12 +222,15 @@ export const useChecklistBeforePublish = () => {
|
|||
const {
|
||||
validNodes,
|
||||
maxDepth,
|
||||
} = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges)
|
||||
} = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges, true)
|
||||
|
||||
if (maxDepth > MAX_TREE_DEPTH) {
|
||||
notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) })
|
||||
return false
|
||||
}
|
||||
|
||||
const allVariablesMap = transformStartNodeVariables(chatVarList, environmentVariables)
|
||||
|
||||
// Before publish, we need to fetch datasets detail, in case of the settings of datasets have been changed
|
||||
const knowledgeRetrievalNodes = nodes.filter(node => node.data.type === BlockEnum.KnowledgeRetrieval)
|
||||
const allDatasetIds = knowledgeRetrievalNodes.reduce<string[]>((acc, node) => {
|
||||
|
|
@ -239,6 +281,14 @@ export const useChecklistBeforePublish = () => {
|
|||
notify({ type: 'error', message: `[${node.data.title}] ${t('workflow.common.needConnectTip')}` })
|
||||
return false
|
||||
}
|
||||
|
||||
if (nodesExtraData[node.data.type as BlockEnum].checkVarValid) {
|
||||
const { errorMessage: varErrorMessage } = nodesExtraData[node.data.type as BlockEnum].checkVarValid(node.data, { ...allVariablesMap, ...node._parentOutputVarMap }, t)
|
||||
if (varErrorMessage?.length) {
|
||||
notify({ type: 'error', message: `[${node.data.title}] ${varErrorMessage[0]}` })
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) {
|
||||
|
|
@ -252,7 +302,7 @@ export const useChecklistBeforePublish = () => {
|
|||
}
|
||||
|
||||
return true
|
||||
}, [store, isChatMode, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData])
|
||||
}, [store, isChatMode, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData, chatVarList, environmentVariables])
|
||||
|
||||
return {
|
||||
handleCheckBeforePublish,
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ const findExceptVarInObject = (obj: any, filterVar: (payload: Var, selector: Val
|
|||
return res
|
||||
}
|
||||
|
||||
const formatItem = (
|
||||
export const formatItem = (
|
||||
item: any,
|
||||
isChatMode: boolean,
|
||||
filterVar: (payload: Var, selector: ValueSelector) => boolean,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByText } from '../../utils/workflow'
|
||||
import type { AnswerNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -24,6 +25,19 @@ const nodeDefault: NodeDefault<AnswerNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: AnswerNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
|
||||
const answer_warnings = getNotExistVariablesByText(payload.answer || '', varMap)
|
||||
if (answer_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.answer.answer')} ${t('workflow.common.referenceVar')}${answer_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: [...answer_warnings],
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import { type AssignerNodeType, WriteMode } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -45,6 +46,23 @@ const nodeDefault: NodeDefault<AssignerNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
|
||||
checkVarValid(payload: AssignerNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr: string[] = []
|
||||
const variables_warnings = getNotExistVariablesByArray(payload.items.map(item => item.variable_selector ?? []) ?? [], varMap)
|
||||
if (variables_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.assigner.assignedVariable')} ${t('workflow.common.referenceVar')}${variables_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
const value_warnings = getNotExistVariablesByArray(payload.items.map(item => item.value ?? []) ?? [], varMap)
|
||||
if (value_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.assigner.setVariable')} ${t('workflow.common.referenceVar')}${value_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: [...variables_warnings, ...value_warnings],
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import { CodeLanguage, type CodeNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -34,7 +35,20 @@ const nodeDefault: NodeDefault<CodeNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: CodeNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
|
||||
const variables_selector = payload.variables.map(v => v.value_selector)
|
||||
const variables_selector_warnings = getNotExistVariablesByArray(variables_selector, varMap)
|
||||
if (variables_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.code.inputVars')} ${t('workflow.common.referenceVar')}${variables_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: variables_selector_warnings,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import type { DocExtractorNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -29,6 +30,19 @@ const nodeDefault: NodeDefault<DocExtractorNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: DocExtractorNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr: string[] = []
|
||||
|
||||
const variables_warnings = getNotExistVariablesByArray([payload.variable_selector], varMap)
|
||||
if (variables_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.docExtractor.inputVar')} ${t('workflow.common.referenceVar')}${variables_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: variables_warnings,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const Node: FC<NodeProps<EndNodeType>> = ({
|
|||
isChatMode,
|
||||
})
|
||||
return (
|
||||
<div key={index} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-components-badge-white-to-dark px-1 text-xs font-normal text-text-secondary'>
|
||||
<div key={index} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-workflow-block-parma-bg px-1 text-xs font-normal text-text-secondary'>
|
||||
<div className='flex items-center text-xs font-medium text-text-tertiary'>
|
||||
{!isEnv && !isChatVar && (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray, getNotExistVariablesByText } from '../../utils/workflow'
|
||||
import { AuthorizationType, BodyType, Method } from './types'
|
||||
import type { BodyPayload, HttpNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
|
|
@ -44,8 +45,8 @@ const nodeDefault: NodeDefault<HttpNodeType> = {
|
|||
errorMessages = t('workflow.errorMsg.fieldRequired', { field: t('workflow.nodes.http.api') })
|
||||
|
||||
if (!errorMessages
|
||||
&& payload.body.type === BodyType.binary
|
||||
&& ((!(payload.body.data as BodyPayload)[0]?.file) || (payload.body.data as BodyPayload)[0]?.file?.length === 0)
|
||||
&& payload.body.type === BodyType.binary
|
||||
&& ((!(payload.body.data as BodyPayload)[0]?.file) || (payload.body.data as BodyPayload)[0]?.file?.length === 0)
|
||||
)
|
||||
errorMessages = t('workflow.errorMsg.fieldRequired', { field: t('workflow.nodes.http.binaryFileVariable') })
|
||||
|
||||
|
|
@ -54,6 +55,53 @@ const nodeDefault: NodeDefault<HttpNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: HttpNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr: string[] = []
|
||||
const url_warnings = getNotExistVariablesByText(payload.url, varMap)
|
||||
if (url_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.http.api')} ${t('workflow.common.referenceVar')}${url_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
const headers_warnings = getNotExistVariablesByText(payload.headers, varMap)
|
||||
if (headers_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.http.headers')} ${t('workflow.common.referenceVar')}${headers_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
const params_warnings = getNotExistVariablesByText(payload.params, varMap)
|
||||
if (params_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.http.params')} ${t('workflow.common.referenceVar')}${params_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
const body_warnings: string[] = []
|
||||
|
||||
if ([BodyType.binary].includes(payload.body.type)) {
|
||||
const body_data = payload.body.data as BodyPayload
|
||||
body_data.forEach((item) => {
|
||||
const key_warnings = getNotExistVariablesByText(item.key || '', varMap)
|
||||
if (key_warnings.length)
|
||||
body_warnings.push(...key_warnings)
|
||||
const warnings = getNotExistVariablesByArray([item.file || []], varMap)
|
||||
if (warnings.length)
|
||||
body_warnings.push(...warnings)
|
||||
})
|
||||
}
|
||||
else {
|
||||
const body_data = payload.body.data as BodyPayload
|
||||
body_data.forEach((item) => {
|
||||
const key_warnings = getNotExistVariablesByText(item.key || '', varMap)
|
||||
if (key_warnings.length)
|
||||
body_warnings.push(...key_warnings)
|
||||
const value_warnings = getNotExistVariablesByText(item.value || '', varMap)
|
||||
if (value_warnings.length)
|
||||
body_warnings.push(...value_warnings)
|
||||
})
|
||||
}
|
||||
if (body_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.http.body')} ${t('workflow.common.referenceVar')}${body_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: [...url_warnings, ...headers_warnings, ...params_warnings, ...body_warnings],
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import type { Var } from '../../types'
|
||||
import type { NodeDefault } from '../../types'
|
||||
import { getNotExistVariablesByArray, getNotExistVariablesByText } from '../../utils/workflow'
|
||||
import { type IfElseNodeType, LogicalOperator } from './types'
|
||||
import { isEmptyRelatedOperator } from './utils'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
|
|
@ -74,6 +76,41 @@ const nodeDefault: NodeDefault<IfElseNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: IfElseNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
|
||||
const condition_variable_selector_warnings: string[] = []
|
||||
const condition_value_warnings: string[] = []
|
||||
payload.cases.forEach((caseItem) => {
|
||||
caseItem.conditions.forEach((condition) => {
|
||||
if (!condition.variable_selector)
|
||||
return
|
||||
const selector_warnings = getNotExistVariablesByArray([condition.variable_selector], varMap)
|
||||
if (selector_warnings.length)
|
||||
condition_variable_selector_warnings.push(...selector_warnings)
|
||||
const value_warnings = Array.isArray(condition.value) ? getNotExistVariablesByArray([condition.value], varMap) : getNotExistVariablesByText(condition.value, varMap)
|
||||
if (value_warnings.length)
|
||||
condition_value_warnings.push(...value_warnings)
|
||||
condition.sub_variable_condition?.conditions.forEach((subCondition) => {
|
||||
const sub_variable_value_warnings = Array.isArray(subCondition.value) ? getNotExistVariablesByArray([subCondition.value], varMap) : getNotExistVariablesByText(subCondition.value, varMap)
|
||||
if (sub_variable_value_warnings.length)
|
||||
condition_value_warnings.push(...sub_variable_value_warnings)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
if (condition_variable_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.ifElse.condition')} ${t('workflow.common.referenceVar')}${condition_variable_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
if (condition_value_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.ifElse.enterValue')} ${t('workflow.common.referenceVar')}${condition_value_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: condition_variable_selector_warnings,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { ErrorHandleMode } from '../../types'
|
||||
import type { NodeDefault } from '../../types'
|
||||
import { BlockEnum, ErrorHandleMode } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import type { IterationNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
|
||||
const i18nPrefix = 'workflow'
|
||||
|
||||
|
|
@ -49,6 +49,19 @@ const nodeDefault: NodeDefault<IterationNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: IterationNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr: string[] = []
|
||||
|
||||
const iterator_selector_warnings = getNotExistVariablesByArray([payload.iterator_selector], varMap)
|
||||
if (iterator_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.iteration.input')} ${t('workflow.common.referenceVar')}${iterator_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: iterator_selector_warnings,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import type { KnowledgeRetrievalNodeType } from './types'
|
||||
import { checkoutRerankModelConfigedInRetrievalSettings } from './utils'
|
||||
import { DATASET_DEFAULT } from '@/config'
|
||||
|
|
@ -47,6 +48,19 @@ const nodeDefault: NodeDefault<KnowledgeRetrievalNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: KnowledgeRetrievalNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
|
||||
const query_variable_selector_warnings = getNotExistVariablesByArray([payload.query_variable_selector], varMap)
|
||||
if (query_variable_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.knowledgeRetrieval.queryVariable')} ${t('workflow.common.referenceVar')}${query_variable_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: [...query_variable_selector_warnings],
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { VarType } from '../../types'
|
||||
import type { NodeDefault } from '../../types'
|
||||
import { BlockEnum, VarType } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import { comparisonOperatorNotRequireValue } from '../if-else/utils'
|
||||
import { type ListFilterNodeType, OrderBy } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
|
||||
const i18nPrefix = 'workflow.errorMsg'
|
||||
|
||||
|
|
@ -58,6 +58,18 @@ const nodeDefault: NodeDefault<ListFilterNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: ListFilterNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
|
||||
const variable_warnings = getNotExistVariablesByArray([payload.variable], varMap)
|
||||
if (variable_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.listFilter.inputVar')} ${t('workflow.common.referenceVar')}${variable_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: variable_warnings,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -97,16 +97,14 @@ const Panel: FC<NodePanelProps<ListFilterNodeType>> = ({
|
|||
{inputs.extract_by?.enabled
|
||||
? (
|
||||
<div className='flex items-center justify-between'>
|
||||
{hasSubVariable && (
|
||||
<div className='mr-2 grow'>
|
||||
<ExtractInput
|
||||
value={inputs.extract_by.serial as string}
|
||||
onChange={handleExtractsChange}
|
||||
readOnly={readOnly}
|
||||
nodeId={id}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className='mr-2 grow'>
|
||||
<ExtractInput
|
||||
value={inputs.extract_by.serial as string}
|
||||
onChange={handleExtractsChange}
|
||||
readOnly={readOnly}
|
||||
nodeId={id}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
: null}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { EditionType } from '../../types'
|
||||
import type { Var } from '../../types'
|
||||
import { BlockEnum, EditionType, VarType } from '../../types'
|
||||
import { type NodeDefault, type PromptItem, PromptRole } from '../../types'
|
||||
import { getNotExistVariablesByArray, getNotExistVariablesByText } from '../../utils/workflow'
|
||||
import type { LLMNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
const i18nPrefix = 'workflow.errorMsg'
|
||||
|
||||
|
|
@ -82,6 +83,37 @@ const nodeDefault: NodeDefault<LLMNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: LLMNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
const prompt_templates_warnings: string[] = []
|
||||
if (payload.context?.enabled && payload.context?.variable_selector?.length) {
|
||||
const context_variable_selector_warnings = getNotExistVariablesByArray([payload.context.variable_selector], varMap)
|
||||
if (context_variable_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.llm.context')} ${t('workflow.common.referenceVar')}${context_variable_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
}
|
||||
const prompt_templates = Array.isArray(payload.prompt_template) ? payload.prompt_template : [payload.prompt_template] as PromptItem[]
|
||||
prompt_templates.forEach((v) => {
|
||||
prompt_templates_warnings.push(...getNotExistVariablesByText(v.text, { context: { variable: 'context', type: VarType.string }, ...varMap }))
|
||||
})
|
||||
if (prompt_templates_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.llm.prompt')} ${t('workflow.common.referenceVar')}${prompt_templates_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
const memory_query_prompt_template_warnings = getNotExistVariablesByText(payload.memory?.query_prompt_template || '', varMap)
|
||||
if (memory_query_prompt_template_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.common.memories.title')}USER ${t('workflow.common.referenceVar')}${memory_query_prompt_template_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
if (payload.vision?.enabled && payload.vision?.configs?.variable_selector?.length) {
|
||||
const vision_variable_selector_warnings = getNotExistVariablesByArray([payload.vision.configs.variable_selector], varMap)
|
||||
if (vision_variable_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.llm.vision')} ${t('workflow.common.referenceVar')}${vision_variable_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
}
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: [...prompt_templates_warnings, ...memory_query_prompt_template_warnings],
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray, getNotExistVariablesByText } from '../../utils/workflow'
|
||||
import { type ParameterExtractorNodeType, ReasoningModeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -61,6 +62,30 @@ const nodeDefault: NodeDefault<ParameterExtractorNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: ParameterExtractorNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr: string[] = []
|
||||
|
||||
const variables_warnings = getNotExistVariablesByArray([payload.query], varMap)
|
||||
if (variables_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.parameterExtractor.inputVar')} ${t('workflow.common.referenceVar')}${variables_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
let vision_variable_warnings: string[] = []
|
||||
if (payload.vision?.configs?.variable_selector?.length) {
|
||||
vision_variable_warnings = getNotExistVariablesByArray([payload.vision.configs.variable_selector], varMap)
|
||||
if (vision_variable_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.llm.vision')} ${t('workflow.common.referenceVar')}${vision_variable_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
}
|
||||
|
||||
const instruction_warnings = getNotExistVariablesByText(payload.instruction, varMap)
|
||||
if (instruction_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.parameterExtractor.instruction')} ${t('workflow.common.referenceVar')}${instruction_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: [...variables_warnings, ...vision_variable_warnings, ...instruction_warnings],
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray, getNotExistVariablesByText } from '../../utils/workflow'
|
||||
import type { QuestionClassifierNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -68,6 +69,30 @@ const nodeDefault: NodeDefault<QuestionClassifierNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: QuestionClassifierNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
|
||||
const query_variable_selector_warnings = getNotExistVariablesByArray([payload.query_variable_selector], varMap)
|
||||
if (query_variable_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.questionClassifiers.inputVars')} ${t('workflow.common.referenceVar')}${query_variable_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
let vision_variable_selector_warnings: string[] = []
|
||||
if (payload.vision?.configs?.variable_selector?.length) {
|
||||
vision_variable_selector_warnings = getNotExistVariablesByArray([payload.vision?.configs?.variable_selector], varMap)
|
||||
if (vision_variable_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.llm.vision')} ${t('workflow.common.referenceVar')}${vision_variable_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
}
|
||||
|
||||
const instruction_warnings: string[] = getNotExistVariablesByText(payload.instruction, varMap)
|
||||
if (instruction_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.questionClassifiers.advancedSetting')}-${t('workflow.nodes.questionClassifiers.instruction')} ${t('workflow.common.referenceVar')}${instruction_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: [...query_variable_selector_warnings, ...vision_variable_selector_warnings, ...instruction_warnings],
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import type { TemplateTransformNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -32,6 +33,19 @@ const nodeDefault: NodeDefault<TemplateTransformNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: TemplateTransformNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
|
||||
const variables_selector = payload.variables.map(v => v.value_selector)
|
||||
const variables_selector_warnings = getNotExistVariablesByArray(variables_selector, varMap)
|
||||
if (variables_selector_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.templateTransform.inputVars')} ${t('workflow.common.referenceVar')}${variables_selector_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ const InputVarList: FC<Props> = ({
|
|||
</div>
|
||||
{isString && (
|
||||
<Input
|
||||
className={cn(inputsIsFocus[variable] ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'rounded-lg border px-3 py-[6px]')}
|
||||
className={cn(inputsIsFocus[variable] ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs' : 'border-components-input-border-hover bg-components-input-bg-normal', 'rounded-lg border px-3 py-[6px]')}
|
||||
value={varInput?.value as string || ''}
|
||||
onChange={handleMixedTypeChange(variable)}
|
||||
readOnly={readOnly}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import type { ToolNodeType } from './types'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import type { NodeDefault, Var } from '../../types'
|
||||
import type { ToolNodeType } from './types'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { getNotExistVariablesByArray, getNotExistVariablesByText } from '../../utils/workflow'
|
||||
|
||||
const i18nPrefix = 'workflow.errorMsg'
|
||||
|
||||
|
|
@ -59,6 +60,35 @@ const nodeDefault: NodeDefault<ToolNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: ToolNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr = []
|
||||
const tool_parametersMap = payload.tool_parameters
|
||||
const tool_parameters_array = Object.values(tool_parametersMap)
|
||||
const tool_parameters_warnings: string[] = []
|
||||
tool_parameters_array?.forEach((item) => {
|
||||
if (!item.value)
|
||||
return
|
||||
if (Array.isArray(item.value)) {
|
||||
const warnings = getNotExistVariablesByArray([item.value], varMap)
|
||||
if (warnings.length)
|
||||
tool_parameters_warnings.push(...warnings)
|
||||
return
|
||||
}
|
||||
if (typeof item.value === 'string') {
|
||||
const warnings = getNotExistVariablesByText(item.value, varMap)
|
||||
if (warnings.length)
|
||||
tool_parameters_warnings.push(...warnings)
|
||||
}
|
||||
})
|
||||
if (tool_parameters_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.tool.inputVars')} ${t('workflow.common.referenceVar')}${tool_parameters_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: tool_parameters_warnings,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import type { Var } from '../../types'
|
||||
import { type NodeDefault, VarType } from '../../types'
|
||||
import { getNotExistVariablesByArray } from '../../utils/workflow'
|
||||
import type { VariableAssignerNodeType } from './types'
|
||||
import { genNodeMetaData } from '@/app/components/workflow/utils'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
|
@ -51,6 +53,18 @@ const nodeDefault: NodeDefault<VariableAssignerNodeType> = {
|
|||
errorMessage: errorMessages,
|
||||
}
|
||||
},
|
||||
checkVarValid(payload: VariableAssignerNodeType, varMap: Record<string, Var>, t: any) {
|
||||
const errorMessageArr: string[] = []
|
||||
const variables_warnings = getNotExistVariablesByArray(payload.variables ?? [], varMap)
|
||||
if (variables_warnings.length)
|
||||
errorMessageArr.push(`${t('workflow.nodes.variableAssigner.title')} ${t('workflow.common.referenceVar')}${variables_warnings.join('、')}${t('workflow.common.noExist')}`)
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
warning_vars: variables_warnings,
|
||||
errorMessage: errorMessageArr,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default nodeDefault
|
||||
|
|
|
|||
|
|
@ -37,8 +37,13 @@ export type WorkflowSliceShape = {
|
|||
export const createWorkflowSlice: StateCreator<WorkflowSliceShape> = set => ({
|
||||
workflowRunningData: undefined,
|
||||
setWorkflowRunningData: workflowRunningData => set(() => ({ workflowRunningData })),
|
||||
clipboardElements: [],
|
||||
setClipboardElements: clipboardElements => set(() => ({ clipboardElements })),
|
||||
clipboardElements: (() => {
|
||||
const storedElements = localStorage.getItem('clipboard_elements')
|
||||
return storedElements ? JSON.parse(storedElements) : []
|
||||
})(),
|
||||
setClipboardElements: (clipboardElements) => {
|
||||
localStorage.setItem('clipboard_elements', JSON.stringify(clipboardElements))
|
||||
},
|
||||
selection: null,
|
||||
setSelection: selection => set(() => ({ selection })),
|
||||
bundleNodeSize: null,
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ export type NodeDefault<T = {}> = {
|
|||
}
|
||||
defaultValue: Partial<T>
|
||||
checkValid: (payload: T, t: any, moreDataForCheckValid?: any) => { isValid: boolean; errorMessage?: string }
|
||||
checkVarValid?: (payload: T, varMap: Record<string, Var>, t: any,) => { isValid: boolean; errorMessage?: string[] }
|
||||
}
|
||||
|
||||
export type OnSelectBlock = (type: BlockEnum, toolDefaultValue?: ToolDefaultValue) => void
|
||||
|
|
|
|||
|
|
@ -5,6 +5,18 @@ import type {
|
|||
} from '@/app/components/workflow/types'
|
||||
import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants'
|
||||
|
||||
jest.mock('ky', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
create: jest.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
jest.mock('lodash-es/groupBy', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn(),
|
||||
}))
|
||||
|
||||
describe('preprocessNodesAndEdges', () => {
|
||||
it('process nodes without iteration node or loop node should return origin nodes and edges.', () => {
|
||||
const nodes = [
|
||||
|
|
|
|||
|
|
@ -10,14 +10,20 @@ import {
|
|||
uniqBy,
|
||||
} from 'lodash-es'
|
||||
import type {
|
||||
ConversationVariable,
|
||||
Edge,
|
||||
EnvironmentVariable,
|
||||
Node,
|
||||
Var,
|
||||
} from '../types'
|
||||
import {
|
||||
BlockEnum,
|
||||
} from '../types'
|
||||
import type { IterationNodeType } from '../nodes/iteration/types'
|
||||
import type { LoopNodeType } from '../nodes/loop/types'
|
||||
import { VAR_REGEX_TEXT } from '@/config'
|
||||
import { formatItem } from '../nodes/_base/components/variable/utils'
|
||||
import type { StructuredOutput } from '../nodes/llm/types'
|
||||
|
||||
export const canRunBySingle = (nodeType: BlockEnum) => {
|
||||
return nodeType === BlockEnum.LLM
|
||||
|
|
@ -86,7 +92,17 @@ export const getNodesConnectedSourceOrTargetHandleIdsMap = (changes: ConnectedSo
|
|||
return nodesConnectedSourceOrTargetHandleIdsMap
|
||||
}
|
||||
|
||||
export const getValidTreeNodes = (nodes: Node[], edges: Edge[]) => {
|
||||
function getParentOutputVarMap(item: Var, path: string, varMap: Record<string, Var>) {
|
||||
if (!item.children || (Array.isArray(item.children) && !item.children.length) || ((item.children as StructuredOutput).schema))
|
||||
return
|
||||
(item.children as Var[]).forEach((child) => {
|
||||
const newPath = `${path}.${child.variable}`
|
||||
varMap[newPath] = child
|
||||
getParentOutputVarMap(child, newPath, varMap)
|
||||
})
|
||||
}
|
||||
|
||||
export const getValidTreeNodes = (nodes: Node[], edges: Edge[], isCollectVar?: boolean) => {
|
||||
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
||||
|
||||
if (!startNode) {
|
||||
|
|
@ -109,6 +125,19 @@ export const getValidTreeNodes = (nodes: Node[], edges: Edge[]) => {
|
|||
outgoers.forEach((outgoer) => {
|
||||
list.push(outgoer)
|
||||
|
||||
if (isCollectVar) {
|
||||
const nodeObj = formatItem(root, false, () => true)
|
||||
const varMap = {} as Record<string, Var>
|
||||
nodeObj.vars.forEach((item) => {
|
||||
if (item.variable.startsWith('sys.'))
|
||||
return
|
||||
const newPath = `${nodeObj.nodeId}.${item.variable}`
|
||||
varMap[newPath] = item
|
||||
getParentOutputVarMap(item, newPath, varMap)
|
||||
})
|
||||
outgoer._parentOutputVarMap = { ...(root._parentOutputVarMap ?? {}), ...varMap }
|
||||
}
|
||||
|
||||
if (outgoer.data.type === BlockEnum.Iteration)
|
||||
list.push(...nodes.filter(node => node.parentId === outgoer.id))
|
||||
if (outgoer.data.type === BlockEnum.Loop)
|
||||
|
|
@ -327,3 +356,48 @@ export const getParallelInfo = (nodes: Node[], edges: Edge[], parentNodeId?: str
|
|||
export const hasErrorHandleNode = (nodeType?: BlockEnum) => {
|
||||
return nodeType === BlockEnum.LLM || nodeType === BlockEnum.Tool || nodeType === BlockEnum.HttpRequest || nodeType === BlockEnum.Code
|
||||
}
|
||||
|
||||
export const transformStartNodeVariables = (chatVarList: ConversationVariable[], environmentVariables: EnvironmentVariable[]) => {
|
||||
const variablesMap: Record<string, ConversationVariable | EnvironmentVariable> = {}
|
||||
chatVarList.forEach((variable) => {
|
||||
variablesMap[`conversation.${variable.name}`] = variable
|
||||
})
|
||||
environmentVariables.forEach((variable) => {
|
||||
variablesMap[`env.${variable.name}`] = variable
|
||||
})
|
||||
return variablesMap
|
||||
}
|
||||
|
||||
export const getNotExistVariablesByText = (text: string, varMap: Record<string, Var>) => {
|
||||
const var_warnings: string[] = []
|
||||
text?.replace(VAR_REGEX_TEXT, (str, id_name) => {
|
||||
if (id_name.startsWith('sys.'))
|
||||
return str
|
||||
if (varMap[id_name])
|
||||
return str
|
||||
const arr = id_name.split('.')
|
||||
arr.shift()
|
||||
var_warnings.push(arr.join('.'))
|
||||
return str
|
||||
})
|
||||
return var_warnings
|
||||
}
|
||||
|
||||
export const getNotExistVariablesByArray = (array: string[][], varMap: Record<string, Var>) => {
|
||||
if (!array.length)
|
||||
return []
|
||||
const var_warnings: string[] = []
|
||||
array.forEach((item) => {
|
||||
if (!item.length)
|
||||
return
|
||||
if (['sys'].includes(item[0]))
|
||||
return
|
||||
const var_warning = varMap[item.join('.')]
|
||||
if (var_warning)
|
||||
return
|
||||
const arr = [...item]
|
||||
arr.shift()
|
||||
var_warnings.push(arr.join('.'))
|
||||
})
|
||||
return var_warnings
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ const LocaleLayout = async ({
|
|||
<TanstackQueryIniter>
|
||||
<ThemeProvider
|
||||
attribute='data-theme'
|
||||
forcedTheme='light'
|
||||
defaultTheme='light' // TODO: change to 'system' when dark mode ready
|
||||
defaultTheme='system'
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
import React from 'react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import Select from '@/app/components/base/select/locale'
|
||||
import ThemeSelector from '@/app/components/base/theme-selector'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { languages } from '@/i18n/language'
|
||||
import type { Locale } from '@/i18n'
|
||||
import I18n from '@/context/i18n'
|
||||
|
|
@ -10,17 +12,22 @@ import LogoSite from '@/app/components/base/logo/logo-site'
|
|||
const Header = () => {
|
||||
const { locale, setLocaleOnClient } = useContext(I18n)
|
||||
|
||||
return <div className='flex w-full items-center justify-between p-6'>
|
||||
<LogoSite />
|
||||
<Select
|
||||
value={locale}
|
||||
items={languages.filter(item => item.supported)}
|
||||
onChange={(value) => {
|
||||
setLocaleOnClient(value as Locale)
|
||||
}}
|
||||
/>
|
||||
|
||||
</div>
|
||||
return (
|
||||
<div className='flex w-full items-center justify-between p-6'>
|
||||
<LogoSite />
|
||||
<div className='flex items-center gap-1'>
|
||||
<Select
|
||||
value={locale}
|
||||
items={languages.filter(item => item.supported)}
|
||||
onChange={(value) => {
|
||||
setLocaleOnClient(value as Locale)
|
||||
}}
|
||||
/>
|
||||
<Divider type='vertical' className='mx-0 ml-2 h-4' />
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header
|
||||
|
|
|
|||
|
|
@ -282,6 +282,8 @@ Thought: {{agent_scratchpad}}
|
|||
|
||||
export const VAR_REGEX = /\{\{(#[a-zA-Z0-9_-]{1,50}(\.[a-zA-Z_]\w{0,29}){1,10}#)\}\}/gi
|
||||
|
||||
export const VAR_REGEX_TEXT = /\{\{#([a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*)#\}\}/gi
|
||||
|
||||
export const resetReg = () => VAR_REGEX.lastIndex = 0
|
||||
|
||||
export let textGenerationTimeoutMs = 60000
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ async function translateMissingKeyDeeply(sourceObj, targetObject, toLanguage) {
|
|||
targetObject[key] = translation
|
||||
}
|
||||
catch {
|
||||
console.error(`Error translating ${sourceObj[key]}(${key}) to ${toLanguage}`)
|
||||
console.error(`Error translating "${sourceObj[key]}" to ${toLanguage}. Key: ${key}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,6 +59,14 @@ async function autoGenTrans(fileName, toGenLanguage) {
|
|||
const toGenLanguageFilePath = path.join(__dirname, toGenLanguage, `${fileName}.ts`)
|
||||
// eslint-disable-next-line sonarjs/code-eval
|
||||
const fullKeyContent = eval(transpile(fs.readFileSync(fullKeyFilePath, 'utf8')))
|
||||
// if toGenLanguageFilePath is not exist, create it
|
||||
if (!fs.existsSync(toGenLanguageFilePath)) {
|
||||
fs.writeFileSync(toGenLanguageFilePath, `const translation = {
|
||||
}
|
||||
|
||||
export default translation
|
||||
`)
|
||||
}
|
||||
// To keep object format and format it for magicast to work: const translation = { ... } => export default {...}
|
||||
const readContent = await loadFile(toGenLanguageFilePath)
|
||||
const { code: toGenContent } = generateCode(readContent)
|
||||
|
|
|
|||
|
|
@ -27,9 +27,14 @@ async function getKeysFromLanuage(language) {
|
|||
// console.log(camelCaseFileName)
|
||||
const content = fs.readFileSync(filePath, 'utf8')
|
||||
// eslint-disable-next-line sonarjs/code-eval
|
||||
const translation = eval(transpile(content))
|
||||
const translationObj = eval(transpile(content))
|
||||
// console.log(translation)
|
||||
const keys = Object.keys(translation)
|
||||
if(!translationObj || typeof translationObj !== 'object') {
|
||||
console.error(`Error parsing file: ${filePath}`)
|
||||
reject(new Error(`Error parsing file: ${filePath}`))
|
||||
return
|
||||
}
|
||||
const keys = Object.keys(translationObj)
|
||||
const nestedKeys = []
|
||||
const iterateKeys = (obj, prefix = '') => {
|
||||
for (const key in obj) {
|
||||
|
|
@ -39,7 +44,7 @@ async function getKeysFromLanuage(language) {
|
|||
iterateKeys(obj[key], nestedKey)
|
||||
}
|
||||
}
|
||||
iterateKeys(translation)
|
||||
iterateKeys(translationObj)
|
||||
|
||||
allKeys = [...keys, ...nestedKeys].map(
|
||||
key => `${camelCaseFileName}.${key}`,
|
||||
|
|
|
|||
|
|
@ -161,6 +161,10 @@ const translation = {
|
|||
description: 'Opik ist eine Open-Source-Plattform zum Bewerten, Testen und Überwachen von LLM-Anwendungen.',
|
||||
title: 'Opik',
|
||||
},
|
||||
weave: {
|
||||
title: 'Weben',
|
||||
description: 'Weave ist eine Open-Source-Plattform zur Bewertung, Testung und Überwachung von LLM-Anwendungen.',
|
||||
},
|
||||
},
|
||||
answerIcon: {
|
||||
descriptionInExplore: 'Gibt an, ob das WebApp-Symbol zum Ersetzen 🤖 in Explore verwendet werden soll',
|
||||
|
|
@ -201,6 +205,17 @@ const translation = {
|
|||
label: 'APP',
|
||||
noParams: 'Keine Parameter erforderlich',
|
||||
},
|
||||
structOutput: {
|
||||
required: 'Erforderlich',
|
||||
structured: 'Strukturiert',
|
||||
structuredTip: 'Strukturierte Ausgaben ist eine Funktion, die sicherstellt, dass das Modell immer Antworten generiert, die Ihrem bereitgestellten JSON-Schema entsprechen.',
|
||||
modelNotSupportedTip: 'Das aktuelle Modell unterstützt diese Funktion nicht und wird automatisch auf Eingabeinjektion heruntergestuft.',
|
||||
modelNotSupported: 'Modell nicht unterstützt',
|
||||
configure: 'Konfigurieren',
|
||||
notConfiguredTip: 'Die strukturierte Ausgabe wurde bisher nicht konfiguriert.',
|
||||
moreFillTip: 'Maximal 10 Ebenen der Verschachtelung anzeigen',
|
||||
LLMResponse: 'LLM-Antwort',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ const translation = {
|
|||
messageRequest: {
|
||||
title: 'Nachrichtenguthaben',
|
||||
tooltip: 'Nachrichtenaufrufkontingente für verschiedene Tarife unter Verwendung von OpenAI-Modellen (außer gpt4).Nachrichten über dem Limit verwenden Ihren OpenAI-API-Schlüssel.',
|
||||
titlePerMonth: '{{count,number}} Nachrichten/Monat',
|
||||
},
|
||||
annotatedResponse: {
|
||||
title: 'Kontingentgrenzen für Annotationen',
|
||||
|
|
@ -77,27 +78,94 @@ const translation = {
|
|||
ragAPIRequestTooltip: 'Bezieht sich auf die Anzahl der API-Aufrufe, die nur die Wissensdatenbankverarbeitungsfähigkeiten von Dify aufrufen.',
|
||||
receiptInfo: 'Nur der Teaminhaber und der Teamadministrator können abonnieren und Abrechnungsinformationen einsehen',
|
||||
annotationQuota: 'Kontingent für Anmerkungen',
|
||||
unlimitedApiRate: 'Keine API-Ratebeschränkung',
|
||||
teamMember_other: '{{count,number}} Teammitglieder',
|
||||
priceTip: 'pro Arbeitsbereich/',
|
||||
teamWorkspace: '{{count,number}} Team Arbeitsplatz',
|
||||
annualBilling: 'Jährliche Abrechnung',
|
||||
self: 'Selbst gehostet',
|
||||
freeTrialTipPrefix: 'Melden Sie sich an und erhalten Sie ein',
|
||||
cloud: 'Cloud-Dienst',
|
||||
apiRateLimitTooltip: 'Die API-Datenbeschränkung gilt für alle Anfragen, die über die Dify-API gemacht werden, einschließlich Textgenerierung, Chat-Konversationen, Workflow-Ausführungen und Dokumentenverarbeitung.',
|
||||
getStarted: 'Loslegen',
|
||||
apiRateLimitUnit: '{{count,number}}/Tag',
|
||||
documentsTooltip: 'Vorgabe für die Anzahl der Dokumente, die aus der Wissensdatenquelle importiert werden.',
|
||||
apiRateLimit: 'API-Datenlimit',
|
||||
documents: '{{count,number}} Wissensdokumente',
|
||||
comparePlanAndFeatures: 'Pläne und Funktionen vergleichen',
|
||||
freeTrialTipSuffix: 'Keine Kreditkarte erforderlich',
|
||||
freeTrialTip: 'kostenlose Testversion von 200 OpenAI-Anfragen.',
|
||||
documentsRequestQuota: '{{count,number}}/min Wissensanforderungsratenlimit',
|
||||
teamMember_one: '{{count,number}} Teammitglied',
|
||||
documentsRequestQuotaTooltip: 'Gibt die Gesamtzahl der Aktionen an, die ein Arbeitsbereich pro Minute innerhalb der Wissensbasis ausführen kann, einschließlich der Erstellung, Löschung, Aktualisierung von Datensätzen, des Hochladens von Dokumenten, von Änderungen, der Archivierung und von Abfragen in der Wissensbasis. Diese Kennzahl wird verwendet, um die Leistung von Anfragen an die Wissensbasis zu bewerten. Wenn ein Sandbox-Nutzer beispielsweise in einer Minute 10 aufeinanderfolgende Testdurchläufe durchführt, wird sein Arbeitsbereich für die nächste Minute vorübergehend daran gehindert, die folgenden Aktionen auszuführen: Erstellung, Löschung, Aktualisierung von Datensätzen sowie das Hochladen oder Ändern von Dokumenten.',
|
||||
},
|
||||
plans: {
|
||||
sandbox: {
|
||||
name: 'Sandbox',
|
||||
description: '200 mal GPT kostenlos testen',
|
||||
includesTitle: 'Beinhaltet:',
|
||||
for: 'Kostenlose Testversion der Kernfunktionen',
|
||||
},
|
||||
professional: {
|
||||
name: 'Professionell',
|
||||
description: 'Für Einzelpersonen und kleine Teams, um mehr Leistung erschwinglich freizuschalten.',
|
||||
includesTitle: 'Alles im kostenlosen Tarif, plus:',
|
||||
for: 'Für unabhängige Entwickler/kleine Teams',
|
||||
},
|
||||
team: {
|
||||
name: 'Team',
|
||||
description: 'Zusammenarbeiten ohne Grenzen und Top-Leistung genießen.',
|
||||
includesTitle: 'Alles im Professionell-Tarif, plus:',
|
||||
for: 'Für mittelgroße Teams',
|
||||
},
|
||||
enterprise: {
|
||||
name: 'Unternehmen',
|
||||
description: 'Erhalten Sie volle Fähigkeiten und Unterstützung für großangelegte, missionskritische Systeme.',
|
||||
includesTitle: 'Alles im Team-Tarif, plus:',
|
||||
features: {
|
||||
2: 'Exklusive Unternehmensfunktionen',
|
||||
8: 'Professioneller technischer Support',
|
||||
6: 'Erweiterte Sicherheits- und Kontrollsysteme',
|
||||
4: 'SSO',
|
||||
0: 'Enterprise-Grade Skalierbare Bereitstellungslösungen',
|
||||
3: 'Mehrere Arbeitsbereiche und Unternehmensverwaltung',
|
||||
1: 'Kommerzielle Lizenzgenehmigung',
|
||||
5: 'Verhandelte SLAs durch Dify-Partner',
|
||||
7: 'Updates und Wartung von Dify offiziell',
|
||||
},
|
||||
btnText: 'Vertrieb kontaktieren',
|
||||
price: 'Benutzerdefiniert',
|
||||
priceTip: 'Jährliche Abrechnung nur',
|
||||
for: 'Für große Teams',
|
||||
},
|
||||
community: {
|
||||
features: {
|
||||
2: 'Entspricht der Dify Open Source Lizenz',
|
||||
1: 'Einzelner Arbeitsbereich',
|
||||
0: 'Alle Kernfunktionen wurden im öffentlichen Repository veröffentlicht.',
|
||||
},
|
||||
description: 'Für Einzelbenutzer, kleine Teams oder nicht-kommerzielle Projekte',
|
||||
for: 'Für Einzelbenutzer, kleine Teams oder nicht-kommerzielle Projekte',
|
||||
btnText: 'Beginnen Sie mit der Gemeinschaft',
|
||||
price: 'Kostenlos',
|
||||
includesTitle: 'Kostenlose Funktionen:',
|
||||
name: 'Gemeinschaft',
|
||||
},
|
||||
premium: {
|
||||
features: {
|
||||
2: 'WebApp-Logo und Branding-Anpassung',
|
||||
0: 'Selbstverwaltete Zuverlässigkeit durch verschiedene Cloud-Anbieter',
|
||||
3: 'Priorisierte E-Mail- und Chat-Unterstützung',
|
||||
1: 'Einzelner Arbeitsbereich',
|
||||
},
|
||||
includesTitle: 'Alles aus der Community, plus:',
|
||||
name: 'Premium',
|
||||
priceTip: 'Basierend auf dem Cloud-Marktplatz',
|
||||
for: 'Für mittelgroße Organisationen und Teams',
|
||||
btnText: 'Jetzt Premium erhalten in',
|
||||
comingSoon: 'Microsoft Azure- und Google Cloud-Support demnächst verfügbar',
|
||||
description: 'Für mittelgroße Organisationen und Teams',
|
||||
price: 'Skalierbar',
|
||||
},
|
||||
},
|
||||
vectorSpace: {
|
||||
|
|
@ -107,12 +175,26 @@ const translation = {
|
|||
apps: {
|
||||
fullTipLine1: 'Upgraden Sie Ihren Tarif, um',
|
||||
fullTipLine2: 'mehr Apps zu bauen.',
|
||||
contactUs: 'Kontaktieren Sie uns',
|
||||
fullTip1: 'Upgrade, um mehr Apps zu erstellen',
|
||||
fullTip2des: 'Es wird empfohlen, inaktive Anwendungen zu bereinigen, um Speicherplatz freizugeben, oder uns zu kontaktieren.',
|
||||
fullTip1des: 'Sie haben das Limit für das Erstellen von Apps in diesem Plan erreicht.',
|
||||
fullTip2: 'Limit erreicht',
|
||||
},
|
||||
annotatedResponse: {
|
||||
fullTipLine1: 'Upgraden Sie Ihren Tarif, um',
|
||||
fullTipLine2: 'mehr Konversationen zu annotieren.',
|
||||
quotaTitle: 'Kontingent für Annotation-Antworten',
|
||||
},
|
||||
usagePage: {
|
||||
buildApps: 'Apps erstellen',
|
||||
annotationQuota: 'Annotierungsquote',
|
||||
teamMembers: 'Teammitglieder',
|
||||
documentsUploadQuota: 'Dokumenten-Upload-Quota',
|
||||
vectorSpace: 'Wissensdatenbank',
|
||||
vectorSpaceTooltip: 'Dokumente mit dem Hochqualitäts-Indexierungsmodus verbrauchen Ressourcen des Knowledge Data Storage. Wenn der Knowledge Data Storage die Grenze erreicht, werden keine neuen Dokumente hochgeladen.',
|
||||
},
|
||||
teamMembers: 'Teammitglieder',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ const translation = {
|
|||
viewDetails: 'Details anzeigen',
|
||||
in: 'in',
|
||||
copied: 'Kopiert',
|
||||
downloadFailed: 'Download fehlgeschlagen. Bitte versuchen Sie es später erneut.',
|
||||
downloadSuccess: 'Download abgeschlossen.',
|
||||
more: 'Mehr',
|
||||
format: 'Format',
|
||||
},
|
||||
placeholder: {
|
||||
input: 'Bitte eingeben',
|
||||
|
|
@ -153,6 +157,9 @@ const translation = {
|
|||
community: 'Gemeinschaft',
|
||||
about: 'Über',
|
||||
logout: 'Abmelden',
|
||||
compliance: 'Einhaltung',
|
||||
support: 'Unterstützung',
|
||||
github: 'GitHub',
|
||||
},
|
||||
settings: {
|
||||
accountGroup: 'KONTO',
|
||||
|
|
@ -202,6 +209,9 @@ const translation = {
|
|||
feedbackLabel: 'Sagen Sie uns, warum Sie Ihr Konto gelöscht haben?',
|
||||
feedbackPlaceholder: 'Wahlfrei',
|
||||
permanentlyDeleteButton: 'Konto dauerhaft löschen',
|
||||
workspaceIcon: 'Arbeitsbereichssymbol',
|
||||
workspaceName: 'Arbeitsbereichsname',
|
||||
editWorkspaceInfo: 'Arbeitsbereichsinformationen bearbeiten',
|
||||
},
|
||||
members: {
|
||||
team: 'Team',
|
||||
|
|
@ -543,6 +553,7 @@ const translation = {
|
|||
inputPlaceholder: 'Sprechen Sie mit dem Bot',
|
||||
thought: 'Gedanke',
|
||||
thinking: 'Denken...',
|
||||
resend: 'Erneut senden',
|
||||
},
|
||||
promptEditor: {
|
||||
placeholder: 'Schreiben Sie hier Ihr Aufforderungswort, geben Sie \'{\' ein, um eine Variable einzufügen, geben Sie \'/\' ein, um einen Aufforderungs-Inhaltsblock einzufügen',
|
||||
|
|
@ -637,6 +648,25 @@ const translation = {
|
|||
pagination: {
|
||||
perPage: 'Artikel pro Seite',
|
||||
},
|
||||
theme: {
|
||||
light: 'Licht',
|
||||
theme: 'Thema',
|
||||
dark: 'dunkel',
|
||||
auto: 'System',
|
||||
},
|
||||
compliance: {
|
||||
iso27001: 'ISO 27001:2022 Zertifizierung',
|
||||
professionalUpgradeTooltip: 'Nur verfügbar mit einem Teamplan oder höher.',
|
||||
gdpr: 'DSGVO DPA',
|
||||
soc2Type2: 'SOC 2 Typ II Bericht',
|
||||
soc2Type1: 'SOC 2 Typ I Bericht',
|
||||
sandboxUpgradeTooltip: 'Nur verfügbar mit einem Professional- oder Teamplan.',
|
||||
},
|
||||
imageInput: {
|
||||
dropImageHere: 'Laden Sie Ihr Bild hierher hoch oder',
|
||||
browse: 'blättern',
|
||||
supportedFormats: 'Unterstützt PNG, JPG, JPEG, WEBP und GIF',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ const translation = {
|
|||
upgradeTip: {
|
||||
prefix: 'Erweitere deinen Plan auf',
|
||||
suffix: 'um deine Marke anzupassen.',
|
||||
title: 'Upgrade deinen Plan',
|
||||
des: 'Upgrade deinen Plan, um deine Marke anzupassen.',
|
||||
},
|
||||
webapp: {
|
||||
title: 'WebApp Marke anpassen',
|
||||
|
|
|
|||
|
|
@ -82,6 +82,14 @@ const translation = {
|
|||
jinaReaderNotConfiguredDescription: 'Richten Sie Jina Reader ein, indem Sie Ihren kostenlosen API-Schlüssel für den Zugriff eingeben.',
|
||||
useSitemapTooltip: 'Folgen Sie der Sitemap, um die Website zu crawlen. Ist dies nicht der Fall, crawlt Jina Reader iterativ basierend auf der Seitenrelevanz, sodass weniger, aber qualitativ hochwertigere Seiten angezeigt werden.',
|
||||
jinaReaderDoc: 'Erfahre mehr über Jina Reader',
|
||||
configureJinaReader: 'Jina Reader konfigurieren',
|
||||
waterCrawlNotConfigured: 'Watercrawl ist nicht konfiguriert',
|
||||
configureWatercrawl: 'Wasserkrabbe konfigurieren',
|
||||
watercrawlDocLink: 'https://docs.dify.ai/de/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website',
|
||||
watercrawlTitle: 'Webinhalt mit Watercrawl extrahieren',
|
||||
watercrawlDoc: 'Wasserkriechen-Dokumente',
|
||||
configureFirecrawl: 'Firecrawl konfigurieren',
|
||||
waterCrawlNotConfiguredDescription: 'Konfigurieren Sie Watercrawl mit dem API-Schlüssel, um es zu verwenden.',
|
||||
},
|
||||
cancel: 'Abbrechen',
|
||||
},
|
||||
|
|
@ -200,6 +208,11 @@ const translation = {
|
|||
title: 'Verbinden Sie sich mit anderen Datenquellen?',
|
||||
description: 'Derzeit verfügt die Wissensdatenbank von Dify nur über begrenzte Datenquellen. Das Beitragen einer Datenquelle zur Dify-Wissensdatenbank ist eine fantastische Möglichkeit, die Flexibilität und Leistungsfähigkeit der Plattform für alle Benutzer zu verbessern. Unser Beitragsleitfaden erleichtert Ihnen den Einstieg. Bitte klicken Sie auf den untenstehenden Link, um mehr zu erfahren.',
|
||||
},
|
||||
watercrawl: {
|
||||
configWatercrawl: 'Wasserkrabbe konfigurieren',
|
||||
apiKeyPlaceholder: 'API-Schlüssel von watercrawl.dev',
|
||||
getApiKeyLinkText: 'Holen Sie sich Ihren API-Schlüssel von watercrawl.dev',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const translation = {
|
|||
learnMore: 'Mehr erfahren',
|
||||
description: ' über die Abrufmethode.',
|
||||
longDescription: ' über die Abrufmethode, dies kann jederzeit in den Wissenseinstellungen geändert werden.',
|
||||
method: 'Abrufmethode',
|
||||
},
|
||||
save: 'Speichern',
|
||||
permissionsInvitedMembers: 'Teilweise Teammitglieder',
|
||||
|
|
|
|||
|
|
@ -168,6 +168,54 @@ const translation = {
|
|||
documentsDisabled: '{{num}} Dokumente deaktiviert - seit über 30 Tagen inaktiv',
|
||||
allKnowledge: 'Alles Wissen',
|
||||
allKnowledgeDescription: 'Wählen Sie diese Option aus, um das gesamte Wissen in diesem Arbeitsbereich anzuzeigen. Nur der Workspace-Besitzer kann das gesamte Wissen verwalten.',
|
||||
metadata: {
|
||||
createMetadata: {
|
||||
namePlaceholder: 'Metadatenname hinzufügen',
|
||||
back: 'Zurück',
|
||||
title: 'Neue Metadaten',
|
||||
name: 'Name',
|
||||
type: 'Art',
|
||||
},
|
||||
checkName: {
|
||||
empty: 'Der Metadatenname darf nicht leer sein.',
|
||||
invalid: 'Der Metadatenname darf nur Kleinbuchstaben, Zahlen und Unterstriche enthalten und muss mit einem Kleinbuchstaben beginnen.',
|
||||
},
|
||||
batchEditMetadata: {
|
||||
editMetadata: 'Metadaten bearbeiten',
|
||||
multipleValue: 'Mehrwert',
|
||||
applyToAllSelectDocument: 'Auf alle ausgewählten Dokumente anwenden',
|
||||
applyToAllSelectDocumentTip: 'Erstellen Sie automatisch alle oben bearbeiteten und neuen Metadaten für alle ausgewählten Dokumente, andernfalls wird die Bearbeitung der Metadaten nur auf Dokumente angewendet, die bereits Metadaten enthalten.',
|
||||
editDocumentsNum: 'Bearbeiten von {{num}} Dokumenten',
|
||||
},
|
||||
selectMetadata: {
|
||||
manageAction: 'Verwalten',
|
||||
search: 'Metadaten durchsuchen',
|
||||
newAction: 'Neue Metadaten',
|
||||
},
|
||||
datasetMetadata: {
|
||||
name: 'Name',
|
||||
disabled: 'Deaktiviert',
|
||||
description: 'Sie können alle Metadaten in diesem Wissen hier verwalten. Änderungen werden mit jedem Dokument synchronisiert.',
|
||||
deleteContent: 'Bist du sicher, dass du die Metadaten "{{name}}" löschen möchtest?',
|
||||
addMetaData: 'Metadaten hinzufügen',
|
||||
deleteTitle: 'Bestätigen Sie das Löschen',
|
||||
values: '{{num}} Werte',
|
||||
builtIn: 'Eingebaut',
|
||||
rename: 'Umbenennen',
|
||||
builtInDescription: 'Integrierte Metadaten werden automatisch extrahiert und generiert. Sie müssen vor der Verwendung aktiviert werden und können nicht bearbeitet werden.',
|
||||
namePlaceholder: 'Metadatenname',
|
||||
},
|
||||
documentMetadata: {
|
||||
startLabeling: 'Labeling starten',
|
||||
technicalParameters: 'Technische Parameter',
|
||||
documentInformation: 'Dokumentinformationen',
|
||||
metadataToolTip: 'Metadaten dienen als ein entscheidender Filter, der die Genauigkeit und Relevanz der Informationsbeschaffung verbessert. Sie können die Metadaten für dieses Dokument hier ändern und hinzufügen.',
|
||||
},
|
||||
chooseTime: 'Wählen Sie eine Zeit...',
|
||||
metadata: 'Metadaten',
|
||||
addMetadata: 'Metadaten hinzufügen',
|
||||
},
|
||||
embeddingModelNotAvailable: 'Das Einbettungsmodell ist nicht verfügbar.',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
const translation = {
|
||||
toVerifiedTip: {
|
||||
coupon: 'exklusiver 100% Gutschein',
|
||||
end: 'für den Dify Professional Plan.',
|
||||
front: 'Sie sind jetzt berechtigt, den Status „Bildung verifiziert“ zu erhalten. Bitte geben Sie unten Ihre Bildungsinformationen ein, um den Prozess abzuschließen und eine Zu erhalten.',
|
||||
},
|
||||
form: {
|
||||
schoolName: {
|
||||
placeholder: 'Geben Sie den offiziellen, unabgekürzten Namen Ihrer Schule ein.',
|
||||
title: 'Ihr Schulname',
|
||||
},
|
||||
schoolRole: {
|
||||
option: {
|
||||
teacher: 'Lehrer',
|
||||
administrator: 'Schuladministrator',
|
||||
student: 'Schüler',
|
||||
},
|
||||
title: 'Ihre Schulrolle',
|
||||
},
|
||||
terms: {
|
||||
desc: {
|
||||
and: 'und',
|
||||
privacyPolicy: 'Datenschutzrichtlinie',
|
||||
termsOfService: 'Nutzungsbedingungen',
|
||||
end: '. Durch die Einreichung:',
|
||||
front: 'Ihre Informationen und die Nutzung des Status "Bildung bestätigt" unterliegen unseren',
|
||||
},
|
||||
option: {
|
||||
inSchool: 'Ich bestätige, dass ich an der angegebenen Einrichtung eingeschrieben oder angestellt bin. Dify kann einen Nachweis über die Einschreibung/Anstellung anfordern. Wenn ich meine Berechtigung falsch darstelle, stimme ich zu, alle Gebühren zu zahlen, die aufgrund meines Bildungsstatus ursprünglich erlassen wurden.',
|
||||
age: 'Ich bestätige, dass ich mindestens 18 Jahre alt bin.',
|
||||
},
|
||||
title: 'Allgemeine Geschäftsbedingungen',
|
||||
},
|
||||
},
|
||||
toVerified: 'Bildung überprüfen lassen',
|
||||
rejectTitle: 'Ihre Dify-Ausbildungsüberprüfung wurde abgelehnt.',
|
||||
currentSigned: 'DERZEIT ANGEMELDET ALS',
|
||||
submit: 'Einreichen',
|
||||
submitError: 'Die Formularübermittlung ist fehlgeschlagen. Bitte versuchen Sie es später erneut.',
|
||||
rejectContent: 'Leider sind Sie nicht für den Status "Education Verified" berechtigt und können daher den exklusiven 100%-Gutschein für den Dify Professional Plan nicht erhalten, wenn Sie diese E-Mail-Adresse verwenden.',
|
||||
successContent: 'Wir haben einen 100% Rabattgutschein für den Dify Professional Plan auf Ihr Konto ausgestellt. Der Gutschein ist ein Jahr lang gültig, bitte nutzen Sie ihn innerhalb des Gültigkeitszeitraums.',
|
||||
learn: 'Erfahren Sie, wie Sie Ihre Ausbildung überprüfen lassen.',
|
||||
emailLabel: 'Ihre aktuelle E-Mail',
|
||||
successTitle: 'Sie haben die Dify-Ausbildung verifiziert',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
@ -37,6 +37,7 @@ const translation = {
|
|||
HR: 'Personalwesen',
|
||||
Agent: 'Agent',
|
||||
Workflow: 'Arbeitsablauf',
|
||||
Entertainment: 'Unterhaltung',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -180,6 +180,8 @@ const translation = {
|
|||
pluginsResult: '{{num}} Ergebnisse',
|
||||
empower: 'Unterstützen Sie Ihre KI-Entwicklung',
|
||||
and: 'und',
|
||||
partnerTip: 'Von einem Dify-Partner verifiziert',
|
||||
verifiedTip: 'Von Dify überprüft',
|
||||
},
|
||||
task: {
|
||||
clearAll: 'Alle löschen',
|
||||
|
|
@ -204,6 +206,10 @@ const translation = {
|
|||
findMoreInMarketplace: 'Weitere Informationen finden Sie im Marketplace',
|
||||
installPlugin: 'Plugin installieren',
|
||||
installFrom: 'INSTALLIEREN VON',
|
||||
metadata: {
|
||||
title: 'Plugins',
|
||||
},
|
||||
difyVersionNotCompatible: 'Die aktuelle Dify-Version ist mit diesem Plugin nicht kompatibel, bitte aktualisieren Sie auf die erforderliche Mindestversion: {{minimalDifyVersion}}',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ const translation = {
|
|||
temporarySystemIssue: 'Entschuldigung, vorübergehendes Systemproblem.',
|
||||
expand: 'Erweitern',
|
||||
collapse: 'Reduzieren',
|
||||
chatSettingsTitle: 'Neues Chat-Setup',
|
||||
newChatTip: 'Bereits in einem neuen Chat',
|
||||
viewChatSettings: 'Chateinstellungen anzeigen',
|
||||
chatFormTip: 'Chat-Einstellungen können nach Beginn des Chats nicht mehr geändert werden.',
|
||||
},
|
||||
generation: {
|
||||
tabs: {
|
||||
|
|
@ -70,6 +74,8 @@ const translation = {
|
|||
moreThanMaxLengthLine: 'Zeile {{rowIndex}}: {{varName}} Wert darf nicht mehr als {{maxLength}} Zeichen sein',
|
||||
atLeastOne: 'Bitte geben Sie mindestens eine Zeile in die hochgeladene Datei ein.',
|
||||
},
|
||||
executions: '{{num}} HINRICHTUNGEN',
|
||||
execution: 'AUSFÜHRUNG',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,37 @@
|
|||
const translation = {}
|
||||
const translation = {
|
||||
daysInWeek: {
|
||||
Sat: 'Sat',
|
||||
Fri: 'Freitag',
|
||||
Thu: 'Donnerstag',
|
||||
Tue: 'Tue',
|
||||
Sun: 'Sonne',
|
||||
Mon: 'Mon',
|
||||
Wed: 'Mittwoch',
|
||||
},
|
||||
months: {
|
||||
August: 'August',
|
||||
March: 'März',
|
||||
January: 'Januar',
|
||||
June: 'Juni',
|
||||
July: 'Juli',
|
||||
November: 'November',
|
||||
September: 'September',
|
||||
April: 'April',
|
||||
February: 'Februar',
|
||||
May: 'Mai',
|
||||
December: 'Dezember',
|
||||
October: 'Oktober',
|
||||
},
|
||||
operation: {
|
||||
pickDate: 'Datum auswählen',
|
||||
ok: 'OK',
|
||||
cancel: 'Stornieren',
|
||||
now: 'Jetzt',
|
||||
},
|
||||
title: {
|
||||
pickTime: 'Wähle Zeit',
|
||||
},
|
||||
defaultPlaceholder: 'Wähle eine Zeit...',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -106,6 +106,15 @@ const translation = {
|
|||
addFailureBranch: 'Fail-Branch hinzufügen',
|
||||
loadMore: 'Weitere Workflows laden',
|
||||
noHistory: 'Keine Geschichte',
|
||||
exportSVG: 'Als SVG exportieren',
|
||||
noExist: 'Keine solche Variable',
|
||||
versionHistory: 'Versionsverlauf',
|
||||
publishUpdate: 'Update veröffentlichen',
|
||||
referenceVar: 'Referenzvariable',
|
||||
exportImage: 'Bild exportieren',
|
||||
exportJPEG: 'Als JPEG exportieren',
|
||||
exitVersions: 'Ausgangsversionen',
|
||||
exportPNG: 'Als PNG exportieren',
|
||||
},
|
||||
env: {
|
||||
envPanelTitle: 'Umgebungsvariablen',
|
||||
|
|
@ -205,6 +214,7 @@ const translation = {
|
|||
testRunIteration: 'Testlaufiteration',
|
||||
back: 'Zurück',
|
||||
iteration: 'Iteration',
|
||||
loop: 'Schleife',
|
||||
},
|
||||
tabs: {
|
||||
'searchBlock': 'Block suchen',
|
||||
|
|
@ -243,6 +253,9 @@ const translation = {
|
|||
'list-operator': 'List-Operator',
|
||||
'document-extractor': 'Doc Extraktor',
|
||||
'agent': 'Agent',
|
||||
'loop': 'Schleife',
|
||||
'loop-start': 'Schleifenbeginn',
|
||||
'loop-end': 'Schleife beenden',
|
||||
},
|
||||
blocksAbout: {
|
||||
'start': 'Definieren Sie die Anfangsparameter zum Starten eines Workflows',
|
||||
|
|
@ -263,6 +276,8 @@ const translation = {
|
|||
'list-operator': 'Wird verwendet, um Array-Inhalte zu filtern oder zu sortieren.',
|
||||
'document-extractor': 'Wird verwendet, um hochgeladene Dokumente in Textinhalte zu analysieren, die für LLM leicht verständlich sind.',
|
||||
'agent': 'Aufruf großer Sprachmodelle zur Beantwortung von Fragen oder zur Verarbeitung natürlicher Sprache',
|
||||
'loop': 'Führen Sie eine Schleife aus, bis die Abschlussbedingungen erfüllt sind oder die maximalen Schleifenanzahl erreicht ist.',
|
||||
'loop-end': 'Entspricht "break". Dieser Knoten hat keine Konfigurationselemente. Wenn der Schleifenrumpf diesen Knoten erreicht, wird die Schleife beendet.',
|
||||
},
|
||||
operator: {
|
||||
zoomIn: 'Vergrößern',
|
||||
|
|
@ -404,6 +419,34 @@ const translation = {
|
|||
variable: 'Variable',
|
||||
},
|
||||
sysQueryInUser: 'sys.query in Benutzernachricht erforderlich',
|
||||
jsonSchema: {
|
||||
warningTips: {
|
||||
saveSchema: 'Bitte beenden Sie die Bearbeitung des aktuellen Feldes, bevor Sie das Schema speichern.',
|
||||
},
|
||||
stringValidations: 'Stringvalidierungen',
|
||||
addField: 'Feld hinzufügen',
|
||||
generateJsonSchema: 'JSON-Schema generieren',
|
||||
back: 'Zurück',
|
||||
addChildField: 'Kindfeld hinzufügen',
|
||||
generationTip: 'Sie können natürliche Sprache verwenden, um schnell ein JSON-Schema zu erstellen.',
|
||||
title: 'Strukturiertes Ausgabeschema',
|
||||
resetDefaults: 'Zurücksetzen',
|
||||
showAdvancedOptions: 'Erweiterte Optionen anzeigen',
|
||||
fieldNamePlaceholder: 'Feldname',
|
||||
descriptionPlaceholder: 'Fügen Sie eine Beschreibung hinzu.',
|
||||
resultTip: 'Hier ist das generierte Ergebnis. Wenn Sie nicht zufrieden sind, können Sie zurückgehen und Ihre Eingabeaufforderung ändern.',
|
||||
generatedResult: 'Generiertes Ergebnis',
|
||||
promptTooltip: 'Konvertiere die Textbeschreibung in eine standardisierte JSON-Schema-Struktur.',
|
||||
promptPlaceholder: 'Beschreibe dein JSON-Schema...',
|
||||
doc: 'Erfahren Sie mehr über strukturierten Output.',
|
||||
required: 'erforderlich',
|
||||
generate: 'Generieren',
|
||||
apply: 'Bewerben',
|
||||
import: 'Import aus JSON',
|
||||
generating: 'Generiere JSON-Schema...',
|
||||
instruction: 'Anleitung',
|
||||
regenerate: 'Regenerieren',
|
||||
},
|
||||
},
|
||||
knowledgeRetrieval: {
|
||||
queryVariable: 'Abfragevariable',
|
||||
|
|
@ -416,6 +459,33 @@ const translation = {
|
|||
url: 'Segmentierte URL',
|
||||
metadata: 'Weitere Metadaten',
|
||||
},
|
||||
metadata: {
|
||||
options: {
|
||||
disabled: {
|
||||
title: 'Deaktiviert',
|
||||
subTitle: 'Keine Aktivierung der Metadatfilterung',
|
||||
},
|
||||
automatic: {
|
||||
desc: 'Automatisch Filterbedingungen für Metadaten basierend auf Abfragevariablen generieren.',
|
||||
title: 'Automatisch',
|
||||
subTitle: 'Automatisch Metadatenfilterbedingungen basierend auf der Benutzeranfrage generieren',
|
||||
},
|
||||
manual: {
|
||||
title: 'Handbuch',
|
||||
subTitle: 'Manuell Filterbedingungen für Metadaten hinzufügen',
|
||||
},
|
||||
},
|
||||
panel: {
|
||||
placeholder: 'Wert eingeben',
|
||||
datePlaceholder: 'Wählen Sie eine Zeit...',
|
||||
add: 'Bedingung hinzufügen',
|
||||
title: 'Metadatenfilterbedingungen',
|
||||
select: 'Wählen Sie eine Variable aus...',
|
||||
conditions: 'Bedingungen',
|
||||
search: 'Suchmetadaten',
|
||||
},
|
||||
title: 'Metadatenfilterung',
|
||||
},
|
||||
},
|
||||
http: {
|
||||
inputVars: 'Eingabevariablen',
|
||||
|
|
@ -505,6 +575,8 @@ const translation = {
|
|||
'all of': 'alle',
|
||||
'exists': 'existiert',
|
||||
'not in': 'nicht in',
|
||||
'after': 'nach',
|
||||
'before': 'vor',
|
||||
},
|
||||
enterValue: 'Wert eingeben',
|
||||
addCondition: 'Bedingung hinzufügen',
|
||||
|
|
@ -520,6 +592,7 @@ const translation = {
|
|||
},
|
||||
select: 'Auswählen',
|
||||
addSubVariable: 'Untervariable',
|
||||
condition: 'Bedingung',
|
||||
},
|
||||
variableAssigner: {
|
||||
title: 'Variablen zuweisen',
|
||||
|
|
@ -562,6 +635,8 @@ const translation = {
|
|||
'extend': 'Ausdehnen',
|
||||
'*=': '*=',
|
||||
'overwrite': 'Überschreiben',
|
||||
'remove-first': 'Erste entfernen',
|
||||
'remove-last': 'Letzte entfernen',
|
||||
},
|
||||
'setParameter': 'Parameter setzen...',
|
||||
'noVarTip': 'Klicken Sie auf die Schaltfläche "+", um Variablen hinzuzufügen',
|
||||
|
|
@ -766,6 +841,38 @@ const translation = {
|
|||
configureModel: 'Modell konfigurieren',
|
||||
linkToPlugin: 'Link zu Plugins',
|
||||
},
|
||||
loop: {
|
||||
ErrorMethod: {
|
||||
removeAbnormalOutput: 'Abnormale Ausgaben entfernen',
|
||||
continueOnError: 'Fortfahren bei Fehler',
|
||||
operationTerminated: 'Beendet',
|
||||
},
|
||||
comma: ',',
|
||||
loopNode: 'Schleifen-Knoten',
|
||||
loop_other: '{{count}} Schleifen',
|
||||
totalLoopCount: 'Gesamtanzahl der Schleifen: {{count}}',
|
||||
deleteDesc: 'Das Löschen des Schleifen-Knotens entfernt alle untergeordneten Knoten.',
|
||||
loopVariables: 'Schleifenvariablen',
|
||||
loop_one: '{{count}} Schleife',
|
||||
breakCondition: 'Schleifenbeendigungsbedingung',
|
||||
setLoopVariables: 'Setze Variablen innerhalb des Schleifenbereichs',
|
||||
breakConditionTip: 'Nur Variablen innerhalb von Schleifen mit Abbruchbedingungen und Konversationsvariablen können referenziert werden.',
|
||||
loopMaxCountError: 'Bitte geben Sie eine gültige maximale Schleifenanzahl ein, die von 1 bis {{maxCount}} reicht.',
|
||||
deleteTitle: 'Schleifen-Knoten löschen?',
|
||||
currentLoop: 'Aktueller Loop',
|
||||
loopMaxCount: 'Maximale Schleifenanzahl',
|
||||
finalLoopVariables: 'Endgültige Schleifenvariablen',
|
||||
exitConditionTip: 'Ein Schleifen-Knoten benötigt mindestens eine Ausgangsbedingung.',
|
||||
errorResponseMethod: 'Fehlerantwortmethode',
|
||||
initialLoopVariables: 'Ursprüngliche Schleifenvariablen',
|
||||
variableName: 'Variablenname',
|
||||
error_one: '{{count}} Fehler',
|
||||
currentLoopCount: 'Aktuelle Schleifenanzahl: {{count}}',
|
||||
inputMode: 'Eingabemodus',
|
||||
error_other: '{{count}} Fehler',
|
||||
output: 'Ausgabewert',
|
||||
input: 'Eingabe',
|
||||
},
|
||||
},
|
||||
tracing: {
|
||||
stopBy: 'Gestoppt von {{user}}',
|
||||
|
|
@ -777,6 +884,38 @@ const translation = {
|
|||
noVarsForOperation: 'Es stehen keine Variablen für die Zuweisung mit der ausgewählten Operation zur Verfügung.',
|
||||
assignedVarsDescription: 'Zugewiesene Variablen müssen beschreibbare Variablen sein, z. B.',
|
||||
},
|
||||
versionHistory: {
|
||||
filter: {
|
||||
all: 'Alle',
|
||||
onlyShowNamedVersions: 'Nur benannte Versionen anzeigen',
|
||||
onlyYours: 'Nur dein',
|
||||
reset: 'Filter zurücksetzen',
|
||||
empty: 'Kein passendes Versionsprotokoll gefunden.',
|
||||
},
|
||||
editField: {
|
||||
releaseNotesLengthLimit: 'Die Versionshinweise dürfen {{limit}} Zeichen nicht überschreiten.',
|
||||
titleLengthLimit: 'Der Titel darf {{limit}} Zeichen nicht überschreiten.',
|
||||
releaseNotes: 'Versionshinweise',
|
||||
title: 'Titel',
|
||||
},
|
||||
action: {
|
||||
restoreFailure: 'Wiederherstellung der Version fehlgeschlagen',
|
||||
updateSuccess: 'Version aktualisiert',
|
||||
deleteSuccess: 'Version gelöscht',
|
||||
deleteFailure: 'Version löschen fehlgeschlagen',
|
||||
restoreSuccess: 'Version wiederhergestellt',
|
||||
updateFailure: 'Aktualisierung der Version fehlgeschlagen',
|
||||
},
|
||||
latest: 'Neueste',
|
||||
nameThisVersion: 'Nennen Sie diese Version',
|
||||
currentDraft: 'Aktueller Entwurf',
|
||||
releaseNotesPlaceholder: 'Beschreibe, was sich geändert hat.',
|
||||
defaultName: 'Unbetitelte Version',
|
||||
title: 'Versionen',
|
||||
editVersionInfo: 'Versionsinformationen bearbeiten',
|
||||
deletionTip: 'Die Löschung ist unumkehrbar, bitte bestätigen Sie.',
|
||||
restorationTip: 'Nach der Wiederherstellung der Version wird der aktuelle Entwurf überschrieben.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
const translation = {
|
||||
theme: {
|
||||
theme: 'Theme',
|
||||
light: 'light',
|
||||
dark: 'dark',
|
||||
auto: 'system',
|
||||
},
|
||||
api: {
|
||||
success: 'Success',
|
||||
actionSuccess: 'Action succeeded',
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ const translation = {
|
|||
addFailureBranch: 'Add Fail Branch',
|
||||
loadMore: 'Load More',
|
||||
noHistory: 'No History',
|
||||
referenceVar: 'Reference Variable',
|
||||
noExist: 'No such variable',
|
||||
},
|
||||
env: {
|
||||
envPanelTitle: 'Environment Variables',
|
||||
|
|
@ -599,6 +601,7 @@ const translation = {
|
|||
selectVariable: 'Select variable...',
|
||||
addSubVariable: 'Sub Variable',
|
||||
select: 'Select',
|
||||
condition: 'Condition',
|
||||
},
|
||||
variableAssigner: {
|
||||
title: 'Assign variables',
|
||||
|
|
|
|||
|
|
@ -159,6 +159,10 @@ const translation = {
|
|||
description: 'Opik es una plataforma de código abierto para evaluar, probar y monitorear aplicaciones LLM.',
|
||||
title: 'Opik',
|
||||
},
|
||||
weave: {
|
||||
description: 'Weave es una plataforma de código abierto para evaluar, probar y monitorear aplicaciones de LLM.',
|
||||
title: 'Tejer',
|
||||
},
|
||||
},
|
||||
answerIcon: {
|
||||
title: 'Usar el icono de la aplicación web para reemplazar 🤖',
|
||||
|
|
@ -194,6 +198,16 @@ const translation = {
|
|||
noParams: 'No se necesitan parámetros',
|
||||
params: 'PARÁMETROS DE LA APLICACIÓN',
|
||||
},
|
||||
structOutput: {
|
||||
notConfiguredTip: 'La salida estructurada aún no ha sido configurada.',
|
||||
required: 'Requerido',
|
||||
configure: 'Configurar',
|
||||
LLMResponse: 'Respuesta del LLM',
|
||||
moreFillTip: 'Mostrando un máximo de 10 niveles de anidación',
|
||||
modelNotSupportedTip: 'El modelo actual no admite esta función y se degrada automáticamente a inyección de comandos.',
|
||||
structuredTip: 'Las Salidas Estructuradas son una función que garantiza que el modelo siempre generará respuestas que se ajusten a su esquema JSON proporcionado.',
|
||||
modelNotSupported: 'Modelo no soportado',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ const translation = {
|
|||
messageRequest: {
|
||||
title: 'Créditos de Mensajes',
|
||||
tooltip: 'Cuotas de invocación de mensajes para varios planes utilizando modelos de OpenAI (excepto gpt4). Los mensajes que excedan el límite utilizarán tu clave API de OpenAI.',
|
||||
titlePerMonth: '{{count,number}} mensajes/mes',
|
||||
},
|
||||
annotatedResponse: {
|
||||
title: 'Límites de Cuota de Anotación',
|
||||
|
|
@ -77,27 +78,94 @@ const translation = {
|
|||
},
|
||||
ragAPIRequestTooltip: 'Se refiere al número de llamadas API que invocan solo las capacidades de procesamiento de base de conocimientos de Dify.',
|
||||
receiptInfo: 'Solo el propietario del equipo y el administrador del equipo pueden suscribirse y ver la información de facturación.',
|
||||
priceTip: 'por espacio de trabajo/',
|
||||
teamMember_one: '{{count, número}} Miembro del Equipo',
|
||||
getStarted: 'Comenzar',
|
||||
apiRateLimitUnit: '{{count, número}}/día',
|
||||
freeTrialTipSuffix: 'No se requiere tarjeta de crédito',
|
||||
unlimitedApiRate: 'Sin límite de tasa de API',
|
||||
apiRateLimit: 'Límite de tasa de API',
|
||||
documentsTooltip: 'Cuota sobre el número de documentos importados desde la Fuente de Datos del Conocimiento.',
|
||||
comparePlanAndFeatures: 'Compara planes y características',
|
||||
cloud: 'Servicio en la nube',
|
||||
teamMember_other: '{{count,number}} Miembros del equipo',
|
||||
annualBilling: 'Facturación Anual',
|
||||
self: 'Autoalojado',
|
||||
freeTrialTip: 'prueba gratuita de 200 llamadas de OpenAI.',
|
||||
teamWorkspace: '{{count,number}} Espacio de Trabajo en Equipo',
|
||||
documents: '{{count,number}} Documentos de Conocimiento',
|
||||
documentsRequestQuota: '{{count,number}}/min Límite de tasa de solicitud de conocimiento',
|
||||
freeTrialTipPrefix: 'Regístrate y obtén un',
|
||||
apiRateLimitTooltip: 'El límite de tasa de la API se aplica a todas las solicitudes realizadas a través de la API de Dify, incluidos la generación de texto, las conversaciones de chat, las ejecuciones de flujo de trabajo y el procesamiento de documentos.',
|
||||
documentsRequestQuotaTooltip: 'Especifica el número total de acciones que un espacio de trabajo puede realizar por minuto dentro de la base de conocimientos, incluyendo la creación, eliminación, actualización de conjuntos de datos, carga de documentos, modificaciones, archivo y consultas a la base de conocimientos. Esta métrica se utiliza para evaluar el rendimiento de las solicitudes a la base de conocimientos. Por ejemplo, si un usuario de Sandbox realiza 10 pruebas consecutivas en un minuto, su espacio de trabajo será temporalmente restringido de realizar las siguientes acciones durante el siguiente minuto: creación de conjuntos de datos, eliminación, actualizaciones y carga o modificaciones de documentos.',
|
||||
},
|
||||
plans: {
|
||||
sandbox: {
|
||||
name: 'Sandbox',
|
||||
description: 'Prueba gratuita de 200 veces GPT',
|
||||
includesTitle: 'Incluye:',
|
||||
for: 'Prueba gratuita de capacidades básicas',
|
||||
},
|
||||
professional: {
|
||||
name: 'Profesional',
|
||||
description: 'Para individuos y pequeños equipos que desean desbloquear más poder de manera asequible.',
|
||||
includesTitle: 'Todo en el plan gratuito, más:',
|
||||
for: 'Para desarrolladores independientes/equipos pequeños',
|
||||
},
|
||||
team: {
|
||||
name: 'Equipo',
|
||||
description: 'Colabora sin límites y disfruta de un rendimiento de primera categoría.',
|
||||
includesTitle: 'Todo en el plan Profesional, más:',
|
||||
for: 'Para equipos de tamaño mediano',
|
||||
},
|
||||
enterprise: {
|
||||
name: 'Empresa',
|
||||
description: 'Obtén capacidades completas y soporte para sistemas críticos a gran escala.',
|
||||
includesTitle: 'Todo en el plan Equipo, más:',
|
||||
features: {
|
||||
0: 'Soluciones de implementación escalables de nivel empresarial',
|
||||
7: 'Actualizaciones y Mantenimiento por Dify Oficialmente',
|
||||
8: 'Soporte Técnico Profesional',
|
||||
3: 'Múltiples Espacios de Trabajo y Gestión Empresarial',
|
||||
1: 'Autorización de Licencia Comercial',
|
||||
2: 'Características Exclusivas de la Empresa',
|
||||
5: 'SLA negociados por Dify Partners',
|
||||
4: 'SSO',
|
||||
6: 'Seguridad y Controles Avanzados',
|
||||
},
|
||||
btnText: 'Contactar ventas',
|
||||
for: 'Para equipos de gran tamaño',
|
||||
price: 'Personalizado',
|
||||
priceTip: 'Facturación Anual Solo',
|
||||
},
|
||||
community: {
|
||||
features: {
|
||||
0: 'Todas las características principales se lanzaron bajo el repositorio público',
|
||||
2: 'Cumple con la Licencia de Código Abierto de Dify',
|
||||
1: 'Espacio de trabajo único',
|
||||
},
|
||||
includesTitle: 'Características gratuitas:',
|
||||
for: 'Para usuarios individuales, pequeños equipos o proyectos no comerciales',
|
||||
price: 'Gratis',
|
||||
btnText: 'Comienza con la Comunidad',
|
||||
name: 'Comunidad',
|
||||
description: 'Para usuarios individuales, pequeños equipos o proyectos no comerciales',
|
||||
},
|
||||
premium: {
|
||||
features: {
|
||||
0: 'Confiabilidad autogestionada por varios proveedores de nube',
|
||||
1: 'Espacio de trabajo único',
|
||||
3: 'Soporte prioritario por correo electrónico y chat',
|
||||
2: 'Personalización de logotipos y marcas de WebApp',
|
||||
},
|
||||
description: 'Para organizaciones y equipos de tamaño mediano',
|
||||
comingSoon: 'Soporte de Microsoft Azure y Google Cloud disponible próximamente',
|
||||
btnText: 'Obtén Premium en',
|
||||
priceTip: 'Basado en el Mercado de la Nube',
|
||||
price: 'Escalable',
|
||||
includesTitle: 'Todo de Community, además:',
|
||||
name: 'Premium',
|
||||
for: 'Para organizaciones y equipos de tamaño mediano',
|
||||
},
|
||||
},
|
||||
vectorSpace: {
|
||||
|
|
@ -107,12 +175,26 @@ const translation = {
|
|||
apps: {
|
||||
fullTipLine1: 'Actualiza tu plan para',
|
||||
fullTipLine2: 'crear más aplicaciones.',
|
||||
fullTip1des: 'Has alcanzado el límite de aplicaciones de construcción en este plan',
|
||||
fullTip2des: 'Se recomienda limpiar las aplicaciones inactivas para liberar espacio de uso, o contactarnos.',
|
||||
fullTip1: 'Actualiza para crear más aplicaciones',
|
||||
fullTip2: 'Límite de plan alcanzado',
|
||||
contactUs: 'Contáctanos',
|
||||
},
|
||||
annotatedResponse: {
|
||||
fullTipLine1: 'Actualiza tu plan para',
|
||||
fullTipLine2: 'anotar más conversaciones.',
|
||||
quotaTitle: 'Cuota de Respuesta Anotada',
|
||||
},
|
||||
usagePage: {
|
||||
buildApps: 'Construir aplicaciones',
|
||||
documentsUploadQuota: 'Cuota de carga de documentos',
|
||||
vectorSpace: 'Almacenamiento de Datos de Conocimiento',
|
||||
teamMembers: 'Miembros del equipo',
|
||||
annotationQuota: 'Cuota de anotación',
|
||||
vectorSpaceTooltip: 'Los documentos con el modo de indexación de alta calidad consumirán recursos de Almacenamiento de Datos de Conocimiento. Cuando el Almacenamiento de Datos de Conocimiento alcanza el límite, no se subirán nuevos documentos.',
|
||||
},
|
||||
teamMembers: 'Miembros del equipo',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ const translation = {
|
|||
in: 'en',
|
||||
viewDetails: 'Ver detalles',
|
||||
copied: 'Copiado',
|
||||
more: 'Más',
|
||||
downloadSuccess: 'Descarga completada.',
|
||||
downloadFailed: 'La descarga ha fallado. Por favor, inténtalo de nuevo más tarde.',
|
||||
format: 'Formato',
|
||||
},
|
||||
errorMsg: {
|
||||
fieldRequired: '{{field}} es requerido',
|
||||
|
|
@ -157,6 +161,9 @@ const translation = {
|
|||
community: 'Comunidad',
|
||||
about: 'Acerca de',
|
||||
logout: 'Cerrar sesión',
|
||||
support: 'Apoyo',
|
||||
compliance: 'Cumplimiento',
|
||||
github: 'GitHub',
|
||||
},
|
||||
settings: {
|
||||
accountGroup: 'CUENTA',
|
||||
|
|
@ -206,6 +213,9 @@ const translation = {
|
|||
feedbackTitle: 'Retroalimentación',
|
||||
feedbackLabel: '¿Cuéntanos por qué eliminaste tu cuenta?',
|
||||
feedbackPlaceholder: 'Opcional',
|
||||
workspaceIcon: 'Icono de espacio de trabajo',
|
||||
editWorkspaceInfo: 'Editar información del espacio de trabajo',
|
||||
workspaceName: 'Nombre del espacio de trabajo',
|
||||
},
|
||||
members: {
|
||||
team: 'Equipo',
|
||||
|
|
@ -547,6 +557,7 @@ const translation = {
|
|||
inputPlaceholder: 'Hablar con el bot',
|
||||
thinking: 'Pensamiento...',
|
||||
thought: 'Pensamiento',
|
||||
resend: 'Reenviar',
|
||||
},
|
||||
promptEditor: {
|
||||
placeholder: 'Escribe tu palabra de indicación aquí, ingresa \'{\' para insertar una variable, ingresa \'/\' para insertar un bloque de contenido de indicación',
|
||||
|
|
@ -637,6 +648,24 @@ const translation = {
|
|||
pagination: {
|
||||
perPage: 'Elementos por página',
|
||||
},
|
||||
theme: {
|
||||
auto: 'sistema',
|
||||
light: 'luz',
|
||||
theme: 'Tema',
|
||||
},
|
||||
compliance: {
|
||||
iso27001: 'Certificación ISO 27001:2022',
|
||||
gdpr: 'GDPR DPA',
|
||||
soc2Type1: 'Informe SOC 2 Tipo I',
|
||||
sandboxUpgradeTooltip: 'Solo disponible con un plan Profesional o de Equipo.',
|
||||
professionalUpgradeTooltip: 'Solo disponible con un plan de equipo o superior.',
|
||||
soc2Type2: 'Informe SOC 2 Tipo II',
|
||||
},
|
||||
imageInput: {
|
||||
supportedFormats: 'Soporta PNG, JPG, JPEG, WEBP y GIF',
|
||||
browse: 'navegar',
|
||||
dropImageHere: 'Deja tu imagen aquí, o',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue