Merge remote-tracking branch 'origin/main' into feat/knowledgebase-summaryIndex

This commit is contained in:
FFXN
2026-01-28 22:14:12 +08:00
59 changed files with 350 additions and 122 deletions

View File

@ -105,7 +105,6 @@ ignore_imports =
core.workflow.nodes.loop.loop_node -> core.app.workflow.node_factory
core.workflow.graph_engine.command_channels.redis_channel -> extensions.ext_redis
core.workflow.workflow_entry -> core.app.workflow.layers.observability
core.workflow.graph_engine.worker_management.worker_pool -> configs
core.workflow.nodes.agent.agent_node -> core.model_manager
core.workflow.nodes.agent.agent_node -> core.provider_manager
core.workflow.nodes.agent.agent_node -> core.tools.tool_manager

View File

@ -1,3 +1,4 @@
from .config import GraphEngineConfig
from .graph_engine import GraphEngine
__all__ = ["GraphEngine"]
__all__ = ["GraphEngine", "GraphEngineConfig"]

View File

@ -0,0 +1,14 @@
"""
GraphEngine configuration models.
"""
from pydantic import BaseModel
class GraphEngineConfig(BaseModel):
"""Configuration for GraphEngine worker pool scaling."""
min_workers: int = 1
max_workers: int = 5
scale_up_threshold: int = 3
scale_down_idle_time: float = 5.0

View File

@ -37,6 +37,7 @@ from .command_processing import (
PauseCommandHandler,
UpdateVariablesCommandHandler,
)
from .config import GraphEngineConfig
from .entities.commands import AbortCommand, PauseCommand, UpdateVariablesCommand
from .error_handler import ErrorHandler
from .event_management import EventHandler, EventManager
@ -70,10 +71,7 @@ class GraphEngine:
graph: Graph,
graph_runtime_state: GraphRuntimeState,
command_channel: CommandChannel,
min_workers: int | None = None,
max_workers: int | None = None,
scale_up_threshold: int | None = None,
scale_down_idle_time: float | None = None,
config: GraphEngineConfig,
) -> None:
"""Initialize the graph engine with all subsystems and dependencies."""
# stop event
@ -85,18 +83,12 @@ class GraphEngine:
self._graph_runtime_state.stop_event = self._stop_event
self._graph_runtime_state.configure(graph=cast("GraphProtocol", graph))
self._command_channel = command_channel
self._config = config
# Graph execution tracks the overall execution state
self._graph_execution = cast("GraphExecution", self._graph_runtime_state.graph_execution)
self._graph_execution.workflow_id = workflow_id
# === Worker Management Parameters ===
# Parameters for dynamic worker pool scaling
self._min_workers = min_workers
self._max_workers = max_workers
self._scale_up_threshold = scale_up_threshold
self._scale_down_idle_time = scale_down_idle_time
# === Execution Queues ===
self._ready_queue = cast(ReadyQueue, self._graph_runtime_state.ready_queue)
@ -167,10 +159,7 @@ class GraphEngine:
graph=self._graph,
layers=self._layers,
execution_context=execution_context,
min_workers=self._min_workers,
max_workers=self._max_workers,
scale_up_threshold=self._scale_up_threshold,
scale_down_idle_time=self._scale_down_idle_time,
config=self._config,
stop_event=self._stop_event,
)

View File

@ -10,11 +10,11 @@ import queue
import threading
from typing import final
from configs import dify_config
from core.workflow.context import IExecutionContext
from core.workflow.graph import Graph
from core.workflow.graph_events import GraphNodeEventBase
from ..config import GraphEngineConfig
from ..layers.base import GraphEngineLayer
from ..ready_queue import ReadyQueue
from ..worker import Worker
@ -38,11 +38,8 @@ class WorkerPool:
graph: Graph,
layers: list[GraphEngineLayer],
stop_event: threading.Event,
config: GraphEngineConfig,
execution_context: IExecutionContext | None = None,
min_workers: int | None = None,
max_workers: int | None = None,
scale_up_threshold: int | None = None,
scale_down_idle_time: float | None = None,
) -> None:
"""
Initialize the simple worker pool.
@ -52,23 +49,15 @@ class WorkerPool:
event_queue: Queue for worker events
graph: The workflow graph
layers: Graph engine layers for node execution hooks
config: GraphEngine worker pool configuration
execution_context: Optional execution context for context preservation
min_workers: Minimum number of workers
max_workers: Maximum number of workers
scale_up_threshold: Queue depth to trigger scale up
scale_down_idle_time: Seconds before scaling down idle workers
"""
self._ready_queue = ready_queue
self._event_queue = event_queue
self._graph = graph
self._execution_context = execution_context
self._layers = layers
# Scaling parameters with defaults
self._min_workers = min_workers or dify_config.GRAPH_ENGINE_MIN_WORKERS
self._max_workers = max_workers or dify_config.GRAPH_ENGINE_MAX_WORKERS
self._scale_up_threshold = scale_up_threshold or dify_config.GRAPH_ENGINE_SCALE_UP_THRESHOLD
self._scale_down_idle_time = scale_down_idle_time or dify_config.GRAPH_ENGINE_SCALE_DOWN_IDLE_TIME
self._config = config
# Worker management
self._workers: list[Worker] = []
@ -96,18 +85,18 @@ class WorkerPool:
if initial_count is None:
node_count = len(self._graph.nodes)
if node_count < 10:
initial_count = self._min_workers
initial_count = self._config.min_workers
elif node_count < 50:
initial_count = min(self._min_workers + 1, self._max_workers)
initial_count = min(self._config.min_workers + 1, self._config.max_workers)
else:
initial_count = min(self._min_workers + 2, self._max_workers)
initial_count = min(self._config.min_workers + 2, self._config.max_workers)
logger.debug(
"Starting worker pool: %d workers (nodes=%d, min=%d, max=%d)",
initial_count,
node_count,
self._min_workers,
self._max_workers,
self._config.min_workers,
self._config.max_workers,
)
# Create initial workers
@ -176,7 +165,7 @@ class WorkerPool:
Returns:
True if scaled up, False otherwise
"""
if queue_depth > self._scale_up_threshold and current_count < self._max_workers:
if queue_depth > self._config.scale_up_threshold and current_count < self._config.max_workers:
old_count = current_count
self._create_worker()
@ -185,7 +174,7 @@ class WorkerPool:
old_count,
len(self._workers),
queue_depth,
self._scale_up_threshold,
self._config.scale_up_threshold,
)
return True
return False
@ -204,7 +193,7 @@ class WorkerPool:
True if scaled down, False otherwise
"""
# Skip if we're at minimum or have no idle workers
if current_count <= self._min_workers or idle_count == 0:
if current_count <= self._config.min_workers or idle_count == 0:
return False
# Check if we have excess capacity
@ -222,10 +211,10 @@ class WorkerPool:
for worker in self._workers:
# Check if worker is idle and has exceeded idle time threshold
if worker.is_idle and worker.idle_duration >= self._scale_down_idle_time:
if worker.is_idle and worker.idle_duration >= self._config.scale_down_idle_time:
# Don't remove if it would leave us unable to handle the queue
remaining_workers = current_count - len(workers_to_remove) - 1
if remaining_workers >= self._min_workers and remaining_workers >= max(1, queue_depth // 2):
if remaining_workers >= self._config.min_workers and remaining_workers >= max(1, queue_depth // 2):
workers_to_remove.append((worker, worker.worker_id))
# Only remove one worker per check to avoid aggressive scaling
break
@ -242,7 +231,7 @@ class WorkerPool:
old_count,
len(self._workers),
len(workers_to_remove),
self._scale_down_idle_time,
self._config.scale_down_idle_time,
queue_depth,
active_count,
idle_count - len(workers_to_remove),
@ -286,6 +275,6 @@ class WorkerPool:
return {
"total_workers": len(self._workers),
"queue_depth": self._ready_queue.qsize(),
"min_workers": self._min_workers,
"max_workers": self._max_workers,
"min_workers": self._config.min_workers,
"max_workers": self._config.max_workers,
}

View File

@ -591,7 +591,7 @@ class IterationNode(LLMUsageTrackingMixin, Node[IterationNodeData]):
from core.app.workflow.node_factory import DifyNodeFactory
from core.workflow.entities import GraphInitParams
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.runtime import GraphRuntimeState
@ -640,6 +640,7 @@ class IterationNode(LLMUsageTrackingMixin, Node[IterationNodeData]):
graph=iteration_graph,
graph_runtime_state=graph_runtime_state_copy,
command_channel=InMemoryChannel(), # Use InMemoryChannel for sub-graphs
config=GraphEngineConfig(),
)
return graph_engine

View File

@ -416,7 +416,7 @@ class LoopNode(LLMUsageTrackingMixin, Node[LoopNodeData]):
from core.app.workflow.node_factory import DifyNodeFactory
from core.workflow.entities import GraphInitParams
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.runtime import GraphRuntimeState
@ -452,6 +452,7 @@ class LoopNode(LLMUsageTrackingMixin, Node[LoopNodeData]):
graph=loop_graph,
graph_runtime_state=graph_runtime_state_copy,
command_channel=InMemoryChannel(), # Use InMemoryChannel for sub-graphs
config=GraphEngineConfig(),
)
return graph_engine

View File

@ -14,7 +14,7 @@ from core.workflow.constants import ENVIRONMENT_VARIABLE_NODE_ID
from core.workflow.entities import GraphInitParams
from core.workflow.errors import WorkflowNodeRunFailedError
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_engine.layers import DebugLoggingLayer, ExecutionLimitsLayer
from core.workflow.graph_engine.protocols.command_channel import CommandChannel
@ -81,6 +81,12 @@ class WorkflowEntry:
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=command_channel,
config=GraphEngineConfig(
min_workers=dify_config.GRAPH_ENGINE_MIN_WORKERS,
max_workers=dify_config.GRAPH_ENGINE_MAX_WORKERS,
scale_up_threshold=dify_config.GRAPH_ENGINE_SCALE_UP_THRESHOLD,
scale_down_idle_time=dify_config.GRAPH_ENGINE_SCALE_DOWN_IDLE_TIME,
),
)
# Add debug logging layer when in debug mode

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import pytest
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_engine.layers.base import (
GraphEngineLayer,
@ -43,6 +43,7 @@ def test_layer_runtime_state_available_after_engine_layer() -> None:
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
layer = LayerForTest()

View File

@ -8,7 +8,7 @@ from core.variables import IntegerVariable, StringVariable
from core.workflow.entities.graph_init_params import GraphInitParams
from core.workflow.entities.pause_reason import SchedulingPause
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_engine.entities.commands import (
AbortCommand,
@ -67,6 +67,7 @@ def test_abort_command():
graph=mock_graph,
graph_runtime_state=shared_runtime_state, # Use shared instance
command_channel=command_channel,
config=GraphEngineConfig(),
)
# Send abort command before starting
@ -173,6 +174,7 @@ def test_pause_command():
graph=mock_graph,
graph_runtime_state=shared_runtime_state,
command_channel=command_channel,
config=GraphEngineConfig(),
)
pause_command = PauseCommand(reason="User requested pause")
@ -228,6 +230,7 @@ def test_update_variables_command_updates_pool():
graph=mock_graph,
graph_runtime_state=shared_runtime_state,
command_channel=command_channel,
config=GraphEngineConfig(),
)
update_command = UpdateVariablesCommand(

View File

@ -7,7 +7,7 @@ This test validates that:
"""
from core.workflow.enums import NodeType
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_events import (
GraphRunSucceededEvent,
@ -44,6 +44,7 @@ def test_streaming_output_with_blocking_equals_one():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Execute the workflow
@ -139,6 +140,7 @@ def test_streaming_output_with_blocking_not_equals_one():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Execute the workflow

View File

@ -11,7 +11,7 @@ from hypothesis import HealthCheck, given, settings
from hypothesis import strategies as st
from core.workflow.enums import ErrorStrategy
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_events import (
GraphRunPartialSucceededEvent,
@ -469,6 +469,7 @@ def test_layer_system_basic():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Add debug logging layer
@ -525,6 +526,7 @@ def test_layer_chaining():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Chain multiple layers
@ -572,6 +574,7 @@ def test_layer_error_handling():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Add faulty layer
@ -753,6 +756,7 @@ def test_graph_run_emits_partial_success_when_node_failure_recovered():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
events = list(engine.run())

View File

@ -566,7 +566,7 @@ class MockIterationNode(MockNodeMixin, IterationNode):
# Import dependencies
from core.workflow.entities import GraphInitParams
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.runtime import GraphRuntimeState
@ -623,6 +623,7 @@ class MockIterationNode(MockNodeMixin, IterationNode):
graph=iteration_graph,
graph_runtime_state=graph_runtime_state_copy,
command_channel=InMemoryChannel(), # Use InMemoryChannel for sub-graphs
config=GraphEngineConfig(),
)
return graph_engine
@ -641,7 +642,7 @@ class MockLoopNode(MockNodeMixin, LoopNode):
# Import dependencies
from core.workflow.entities import GraphInitParams
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.runtime import GraphRuntimeState
@ -685,6 +686,7 @@ class MockLoopNode(MockNodeMixin, LoopNode):
graph=loop_graph,
graph_runtime_state=graph_runtime_state_copy,
command_channel=InMemoryChannel(), # Use InMemoryChannel for sub-graphs
config=GraphEngineConfig(),
)
return graph_engine

View File

@ -17,7 +17,7 @@ from core.app.workflow.node_factory import DifyNodeFactory
from core.workflow.entities import GraphInitParams
from core.workflow.enums import NodeType, WorkflowNodeExecutionStatus
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_events import (
GraphRunSucceededEvent,
@ -123,6 +123,7 @@ def test_parallel_streaming_workflow():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Define LLM outputs

View File

@ -12,7 +12,7 @@ from unittest.mock import MagicMock, Mock, patch
from core.app.entities.app_invoke_entities import InvokeFrom
from core.workflow.entities.graph_init_params import GraphInitParams
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_events import (
GraphRunStartedEvent,
@ -41,6 +41,7 @@ class TestStopEventPropagation:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Verify stop_event was created
@ -84,6 +85,7 @@ class TestStopEventPropagation:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Set the stop_event before running
@ -131,6 +133,7 @@ class TestStopEventPropagation:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Initially not set
@ -155,6 +158,7 @@ class TestStopEventPropagation:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Verify WorkerPool has the stop_event
@ -174,6 +178,7 @@ class TestStopEventPropagation:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Verify Dispatcher has the stop_event
@ -311,6 +316,7 @@ class TestStopEventIntegration:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Set stop_event before running
@ -360,6 +366,7 @@ class TestStopEventIntegration:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# All nodes should share the same stop_event
@ -385,6 +392,7 @@ class TestStopEventTimeoutBehavior:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
dispatcher = engine._dispatcher
@ -411,6 +419,7 @@ class TestStopEventTimeoutBehavior:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
worker_pool = engine._worker_pool
@ -460,6 +469,7 @@ class TestStopEventResumeBehavior:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Simulate a previous execution that set stop_event
@ -490,6 +500,7 @@ class TestWorkerStopBehavior:
graph=mock_graph,
graph_runtime_state=runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
# Get the worker pool and check workers

View File

@ -32,7 +32,7 @@ from core.variables import (
)
from core.workflow.entities.graph_init_params import GraphInitParams
from core.workflow.graph import Graph
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_events import (
GraphEngineEvent,
@ -309,10 +309,12 @@ class TableTestRunner:
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
min_workers=self.graph_engine_min_workers,
max_workers=self.graph_engine_max_workers,
scale_up_threshold=self.graph_engine_scale_up_threshold,
scale_down_idle_time=self.graph_engine_scale_down_idle_time,
config=GraphEngineConfig(
min_workers=self.graph_engine_min_workers,
max_workers=self.graph_engine_max_workers,
scale_up_threshold=self.graph_engine_scale_up_threshold,
scale_down_idle_time=self.graph_engine_scale_down_idle_time,
),
)
# Execute and collect events

View File

@ -1,4 +1,4 @@
from core.workflow.graph_engine import GraphEngine
from core.workflow.graph_engine import GraphEngine, GraphEngineConfig
from core.workflow.graph_engine.command_channels import InMemoryChannel
from core.workflow.graph_events import (
GraphRunSucceededEvent,
@ -27,6 +27,7 @@ def test_tool_in_chatflow():
graph=graph,
graph_runtime_state=graph_runtime_state,
command_channel=InMemoryChannel(),
config=GraphEngineConfig(),
)
events = list(engine.run())

View File

@ -182,12 +182,12 @@ describe('Chat Message Loading Race Condition Prevention', () => {
// Update pagination anchor with oldest answer ID
const answerItems = chatItems.filter(item => item.isAnswer)
const oldestAnswer = answerItems[answerItems.length - 1]
const oldestAnswer = answerItems[0]
if (oldestAnswer?.id) {
oldestAnswerIdRef = oldestAnswer.id
}
expect(oldestAnswerIdRef).toBe('answer-2')
expect(oldestAnswerIdRef).toBe('answer-1')
})
it('should use pagination anchor in subsequent requests', () => {

View File

@ -321,7 +321,7 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
// Update pagination anchor ref with the oldest answer ID
const answerItems = allChatItems.filter(item => item.isAnswer)
const oldestAnswer = answerItems[answerItems.length - 1]
const oldestAnswer = answerItems[0]
if (oldestAnswer?.id)
oldestAnswerIdRef.current = oldestAnswer.id
}, [allChatItems, hasMore, detail?.model_config?.configs?.introduction])
@ -506,56 +506,18 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
}
}, [detail.id, hasMore, isLoading, timezone, t, appDetail, detail?.model_config?.configs?.introduction])
useEffect(() => {
const handleScroll = useCallback(() => {
const scrollableDiv = document.getElementById('scrollableDiv')
const outerDiv = scrollableDiv?.parentElement
const chatContainer = document.querySelector('.mx-1.mb-1.grow.overflow-auto') as HTMLElement
let scrollContainer: HTMLElement | null = null
if (outerDiv && outerDiv.scrollHeight > outerDiv.clientHeight) {
scrollContainer = outerDiv
}
else if (scrollableDiv && scrollableDiv.scrollHeight > scrollableDiv.clientHeight) {
scrollContainer = scrollableDiv
}
else if (chatContainer && chatContainer.scrollHeight > chatContainer.clientHeight) {
scrollContainer = chatContainer
}
else {
const possibleContainers = document.querySelectorAll('.overflow-auto, .overflow-y-auto')
for (let i = 0; i < possibleContainers.length; i++) {
const container = possibleContainers[i] as HTMLElement
if (container.scrollHeight > container.clientHeight) {
scrollContainer = container
break
}
}
}
if (!scrollContainer)
if (!scrollableDiv)
return
const clientHeight = scrollableDiv.clientHeight
const scrollHeight = scrollableDiv.scrollHeight
const currentScrollTop = scrollableDiv.scrollTop
// currentScrollTop is negative due to column-reverse flex direction
const isNearTop = Math.abs(currentScrollTop) > scrollHeight - clientHeight - 40
const handleScroll = () => {
const currentScrollTop = scrollContainer!.scrollTop
const isNearTop = currentScrollTop < 30
if (isNearTop && hasMore && !isLoading) {
loadMoreMessages()
}
}
scrollContainer.addEventListener('scroll', handleScroll, { passive: true })
const handleWheel = (e: WheelEvent) => {
if (e.deltaY < 0)
handleScroll()
}
scrollContainer.addEventListener('wheel', handleWheel, { passive: true })
return () => {
scrollContainer!.removeEventListener('scroll', handleScroll)
scrollContainer!.removeEventListener('wheel', handleWheel)
if (isNearTop && hasMore && !isLoading) {
loadMoreMessages()
}
}, [hasMore, isLoading, loadMoreMessages])
@ -690,19 +652,10 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
height: '100%',
overflow: 'auto',
}}
onScroll={handleScroll}
>
{/* Put the scroll bar always on the bottom */}
<div className="flex w-full flex-col-reverse" style={{ position: 'relative' }}>
{/* Loading state indicator - only shown when loading */}
{hasMore && isLoading && (
<div className="sticky left-0 right-0 top-0 z-10 bg-primary-50/40 py-3 text-center">
<div className="system-xs-regular text-text-tertiary">
{t('detail.loading', { ns: 'appLog' })}
...
</div>
</div>
)}
<Chat
config={{
appId: appDetail?.id,
@ -728,6 +681,14 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
switchSibling={switchSibling}
/>
</div>
{hasMore && (
<div className="py-3 text-center">
<div className="system-xs-regular text-text-tertiary">
{t('detail.loading', { ns: 'appLog' })}
...
</div>
</div>
)}
</div>
)}
</div>

View File

@ -31,6 +31,7 @@
"list.action.pause": "إيقاف مؤقت",
"list.action.resume": "استئناف",
"list.action.settings": "إعدادات التقطيع",
"list.action.summary": "إنشاء ملخص",
"list.action.sync": "مزامنة",
"list.action.unarchive": "إلغاء الأرشفة",
"list.action.uploadFile": "تحميل ملف جديد",
@ -75,6 +76,9 @@
"list.status.indexing": "فهرسة",
"list.status.paused": "متوقف مؤقتًا",
"list.status.queuing": "في الانتظار",
"list.summary.generating": "جارٍ الإنشاء...",
"list.summary.generatingSummary": "جارٍ إنشاء الملخص",
"list.summary.ready": "الملخص جاهز",
"list.table.header.action": "إجراء",
"list.table.header.chunkingMode": "وضع التقطيع",
"list.table.header.fileName": "الاسم",
@ -329,5 +333,7 @@
"segment.searchResults_one": "نتيجة",
"segment.searchResults_other": "نتائج",
"segment.searchResults_zero": "نتيجة",
"segment.summary": "ملخص",
"segment.summaryPlaceholder": "اكتب ملخصًا موجزًا لاسترجاع أفضل…",
"segment.vectorHash": "تجزئة المتجه: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "إعدادات الاسترجاع",
"form.save": "حفظ",
"form.searchModel": "نموذج البحث",
"form.summaryAutoGen": "إنشاء الملخص التلقائي",
"form.summaryAutoGenEnableTip": "بمجرد التمكين، سيتم إنشاء الملخصات تلقائيًا للمستندات المضافة حديثًا. يمكن لا يزال تلخيص المستندات الموجودة يدويًا.",
"form.summaryAutoGenTip": "يتم إنشاء الملخصات تلقائيًا للمستندات المضافة حديثًا. يمكن لا يزال تلخيص المستندات الموجودة يدويًا.",
"form.summaryInstructions": "تعليمات",
"form.summaryInstructionsPlaceholder": "صف القواعد أو الأسلوب للملخصات المُنشأة تلقائيًا…",
"form.summaryModel": "نموذج الملخص",
"form.upgradeHighQualityTip": "بمجرد الترقية إلى وضع الجودة العالية، لا يتوفر الرجوع إلى الوضع الاقتصادي",
"title": "إعدادات المعرفة"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Pause",
"list.action.resume": "Fortsetzen",
"list.action.settings": "Segment-Einstellungen",
"list.action.summary": "Zusammenfassung generieren",
"list.action.sync": "Synchronisieren",
"list.action.unarchive": "Archivierung aufheben",
"list.action.uploadFile": "Neue Datei hochladen",
@ -75,6 +76,9 @@
"list.status.indexing": "Indizierung",
"list.status.paused": "Pausiert",
"list.status.queuing": "In Warteschlange",
"list.summary.generating": "Wird generiert...",
"list.summary.generatingSummary": "Zusammenfassung wird generiert",
"list.summary.ready": "Zusammenfassung bereit",
"list.table.header.action": "AKTION",
"list.table.header.chunkingMode": "CHUNKING-MODUS",
"list.table.header.fileName": "DATEINAME",
@ -329,5 +333,7 @@
"segment.searchResults_one": "ERGEBNIS",
"segment.searchResults_other": "BEFUND",
"segment.searchResults_zero": "ERGEBNIS",
"segment.summary": "ZUSAMMENFASSUNG",
"segment.summaryPlaceholder": "Schreiben Sie eine kurze Zusammenfassung für bessere Abrufbarkeit…",
"segment.vectorHash": "Vektor-Hash: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Einstellungen für den Abruf",
"form.save": "Speichern",
"form.searchModel": "Modell suchen",
"form.summaryAutoGen": "Automatische Zusammenfassungserstellung",
"form.summaryAutoGenEnableTip": "Nach der Aktivierung werden Zusammenfassungen automatisch für neu hinzugefügte Dokumente generiert. Vorhandene Dokumente können weiterhin manuell zusammengefasst werden.",
"form.summaryAutoGenTip": "Zusammenfassungen werden automatisch für neu hinzugefügte Dokumente generiert. Vorhandene Dokumente können weiterhin manuell zusammengefasst werden.",
"form.summaryInstructions": "Anweisungen",
"form.summaryInstructionsPlaceholder": "Beschreiben Sie die Regeln oder den Stil für automatisch generierte Zusammenfassungen…",
"form.summaryModel": "Zusammenfassungsmodell",
"form.upgradeHighQualityTip": "Nach dem Upgrade auf den Modus \"Hohe Qualität\" ist das Zurücksetzen auf den Modus \"Wirtschaftlich\" nicht mehr möglich",
"title": "Wissenseinstellungen"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Pausa",
"list.action.resume": "Reanudar",
"list.action.settings": "Configuración de segmento",
"list.action.summary": "Generar resumen",
"list.action.sync": "Sincronizar",
"list.action.unarchive": "Desarchivar",
"list.action.uploadFile": "Subir nuevo archivo",
@ -75,6 +76,9 @@
"list.status.indexing": "Indexando",
"list.status.paused": "Pausado",
"list.status.queuing": "En cola",
"list.summary.generating": "Generando...",
"list.summary.generatingSummary": "Generando resumen",
"list.summary.ready": "Resumen listo",
"list.table.header.action": "ACCIÓN",
"list.table.header.chunkingMode": "MODO DE FRAGMENTACIÓN",
"list.table.header.fileName": "NOMBRE DEL ARCHIVO",
@ -329,5 +333,7 @@
"segment.searchResults_one": "RESULTADO",
"segment.searchResults_other": "RESULTADOS",
"segment.searchResults_zero": "RESULTADO",
"segment.summary": "RESUMEN",
"segment.summaryPlaceholder": "Escriba un breve resumen para una mejor recuperación…",
"segment.vectorHash": "Hash de vector: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Configuración de recuperación",
"form.save": "Guardar",
"form.searchModel": "Buscar modelo",
"form.summaryAutoGen": "Generación Automática de Resumen",
"form.summaryAutoGenEnableTip": "Una vez habilitado, los resúmenes se generarán automáticamente para documentos recién agregados. Los documentos existentes aún se pueden resumir manualmente.",
"form.summaryAutoGenTip": "Los resúmenes se generan automáticamente para documentos recién agregados. Los documentos existentes aún se pueden resumir manualmente.",
"form.summaryInstructions": "Instrucciones",
"form.summaryInstructionsPlaceholder": "Describa las reglas o el estilo para resúmenes generados automáticamente…",
"form.summaryModel": "Modelo de Resumen",
"form.upgradeHighQualityTip": "Una vez que se actualiza al modo de alta calidad, no está disponible volver al modo económico",
"title": "Configuración del conjunto de datos"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "مکث",
"list.action.resume": "ادامه",
"list.action.settings": "تنظیمات بخش‌بندی",
"list.action.summary": "ایجاد خلاصه",
"list.action.sync": "همگام‌سازی",
"list.action.unarchive": "خارج کردن از بایگانی",
"list.action.uploadFile": "بارگذاری فایل جدید",
@ -75,6 +76,9 @@
"list.status.indexing": "ایندکس‌سازی",
"list.status.paused": "متوقف شده",
"list.status.queuing": "در صف",
"list.summary.generating": "در حال ایجاد...",
"list.summary.generatingSummary": "در حال ایجاد خلاصه",
"list.summary.ready": "خلاصه آماده است",
"list.table.header.action": "اقدام",
"list.table.header.chunkingMode": "حالت تکه تکه کردن",
"list.table.header.fileName": "نام فایل",
@ -329,5 +333,7 @@
"segment.searchResults_one": "نتیجه",
"segment.searchResults_other": "نتیجه",
"segment.searchResults_zero": "نتیجه",
"segment.summary": "خلاصه",
"segment.summaryPlaceholder": "خلاصه‌ای کوتاه برای بازیابی بهتر بنویسید…",
"segment.vectorHash": "هش برداری: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "تنظیمات بازیابی",
"form.save": "ذخیره",
"form.searchModel": "جستجوی مدل",
"form.summaryAutoGen": "ایجاد خودکار خلاصه",
"form.summaryAutoGenEnableTip": "پس از فعال‌سازی، خلاصه‌ها به‌طور خودکار برای اسناد تازه اضافه‌شده ایجاد می‌شوند. اسناد موجود همچنان می‌توانند به‌صورت دستی خلاصه شوند.",
"form.summaryAutoGenTip": "خلاصه‌ها به‌طور خودکار برای اسناد تازه اضافه‌شده ایجاد می‌شوند. اسناد موجود همچنان می‌توانند به‌صورت دستی خلاصه شوند.",
"form.summaryInstructions": "دستورالعمل‌ها",
"form.summaryInstructionsPlaceholder": "قوانین یا سبک خلاصه‌های ایجاد شده خودکار را شرح دهید…",
"form.summaryModel": "مدل خلاصه",
"form.upgradeHighQualityTip": "پس از ارتقاء به حالت کیفیت بالا، بازگشت به حالت اقتصادی در دسترس نیست",
"title": "تنظیمات دانش"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Pause",
"list.action.resume": "Reprendre",
"list.action.settings": "Paramètres de segment",
"list.action.summary": "Générer un résumé",
"list.action.sync": "Synchroniser",
"list.action.unarchive": "Décompresser",
"list.action.uploadFile": "Télécharger un nouveau fichier",
@ -75,6 +76,9 @@
"list.status.indexing": "Indexation",
"list.status.paused": "En pause",
"list.status.queuing": "Mise en file d'attente",
"list.summary.generating": "Génération...",
"list.summary.generatingSummary": "Génération du résumé",
"list.summary.ready": "Résumé prêt",
"list.table.header.action": "ACTION",
"list.table.header.chunkingMode": "MODE DE MORCEAU",
"list.table.header.fileName": "NOM DU FICHIER",
@ -329,5 +333,7 @@
"segment.searchResults_one": "RÉSULTAT",
"segment.searchResults_other": "RÉSULTATS",
"segment.searchResults_zero": "RÉSULTAT",
"segment.summary": "RÉSUMÉ",
"segment.summaryPlaceholder": "Rédigez un bref résumé pour une meilleure récupération…",
"segment.vectorHash": "Vector hash: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Paramètres de récupération",
"form.save": "Enregistrer",
"form.searchModel": "Rechercher un modèle",
"form.summaryAutoGen": "Génération Auto de Résumé",
"form.summaryAutoGenEnableTip": "Une fois activé, les résumés seront générés automatiquement pour les documents nouvellement ajoutés. Les documents existants peuvent toujours être résumés manuellement.",
"form.summaryAutoGenTip": "Les résumés sont générés automatiquement pour les documents nouvellement ajoutés. Les documents existants peuvent toujours être résumés manuellement.",
"form.summaryInstructions": "Instructions",
"form.summaryInstructionsPlaceholder": "Décrivez les règles ou le style pour les résumés générés automatiquement…",
"form.summaryModel": "Modèle de Résumé",
"form.upgradeHighQualityTip": "Une fois la mise à niveau vers le mode Haute Qualité, il nest pas possible de revenir au mode Économique",
"title": "Paramètres de connaissance"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "रोकें",
"list.action.resume": "रिज़्यूमे",
"list.action.settings": "खंड सेटिंग्स",
"list.action.summary": "सारांश बनाएं",
"list.action.sync": "सिंक्रोनाइज़ करें",
"list.action.unarchive": "संग्रह से बाहर करें",
"list.action.uploadFile": "नई फाइल अपलोड करें",
@ -75,6 +76,9 @@
"list.status.indexing": "अनुक्रमण",
"list.status.paused": "रुका हुआ",
"list.status.queuing": "पंक्तिबद्ध",
"list.summary.generating": "बना रहे हैं...",
"list.summary.generatingSummary": "सारांश बना रहे हैं",
"list.summary.ready": "सारांश तैयार है",
"list.table.header.action": "क्रिया",
"list.table.header.chunkingMode": "चंकिंग मोड",
"list.table.header.fileName": "फाइल का नाम",
@ -329,5 +333,7 @@
"segment.searchResults_one": "परिणाम",
"segment.searchResults_other": "परिणाम",
"segment.searchResults_zero": "परिणाम",
"segment.summary": "सारांश",
"segment.summaryPlaceholder": "बेहतर पुनर्प्राप्ति के लिए संक्षिप्त सारांश लिखें…",
"segment.vectorHash": "वेक्टर हैश: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "पुनर्प्राप्ति सेटिंग्स",
"form.save": "सेवना",
"form.searchModel": "मॉडल खोजें",
"form.summaryAutoGen": "सारांश स्वतः निर्माण",
"form.summaryAutoGenEnableTip": "सक्षम होने पर, नए जोड़े गए दस्तावेज़ों के लिए सारांश स्वचालित रूप से बनाए जाएंगे। मौजूदा दस्तावेज़ों को अभी भी मैन्युअल रूप से सारांशित किया जा सकता है।",
"form.summaryAutoGenTip": "नए जोड़े गए दस्तावेज़ों के लिए सारांश स्वचालित रूप से बनाए जाते हैं। मौजूदा दस्तावेज़ों को अभी भी मैन्युअल रूप से सारांशित किया जा सकता है।",
"form.summaryInstructions": "निर्देश",
"form.summaryInstructionsPlaceholder": "स्वचालित रूप से बनाए गए सारांश के लिए नियम या शैली का वर्णन करें…",
"form.summaryModel": "सारांश मॉडल",
"form.upgradeHighQualityTip": "एक बार उच्च गुणवत्ता मोड में अपग्रेड करने के बाद, किफायती मोड में वापस जाना उपलब्ध नहीं है",
"title": "ज्ञान सेटिंग्ज"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Jeda",
"list.action.resume": "Melanjutkan",
"list.action.settings": "Pengaturan Chunking",
"list.action.summary": "Buat ringkasan",
"list.action.sync": "Sync",
"list.action.unarchive": "Batalkan arsip",
"list.action.uploadFile": "Unggah file baru",
@ -75,6 +76,9 @@
"list.status.indexing": "Pengindeksan",
"list.status.paused": "Berhenti",
"list.status.queuing": "Antrian",
"list.summary.generating": "Membuat...",
"list.summary.generatingSummary": "Membuat ringkasan",
"list.summary.ready": "Ringkasan siap",
"list.table.header.action": "PERBUATAN",
"list.table.header.chunkingMode": "CHUNKING MODE",
"list.table.header.fileName": "NAMA",
@ -329,5 +333,7 @@
"segment.searchResults_one": "HASIL",
"segment.searchResults_other": "HASIL",
"segment.searchResults_zero": "HASIL",
"segment.summary": "RINGKASAN",
"segment.summaryPlaceholder": "Tulis ringkasan singkat untuk pencarian yang lebih baik…",
"segment.vectorHash": "Hash vektor:"
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Pengaturan Pengambilan",
"form.save": "Simpan",
"form.searchModel": "Model pencarian",
"form.summaryAutoGen": "Pembuatan Ringkasan Otomatis",
"form.summaryAutoGenEnableTip": "Setelah diaktifkan, ringkasan akan dibuat secara otomatis untuk dokumen yang baru ditambahkan. Dokumen yang ada masih dapat diringkas secara manual.",
"form.summaryAutoGenTip": "Ringkasan dibuat secara otomatis untuk dokumen yang baru ditambahkan. Dokumen yang ada masih dapat diringkas secara manual.",
"form.summaryInstructions": "Instruksi",
"form.summaryInstructionsPlaceholder": "Jelaskan aturan atau gaya untuk ringkasan yang dibuat secara otomatis…",
"form.summaryModel": "Model Ringkasan",
"form.upgradeHighQualityTip": "Setelah memutakhirkan ke mode Kualitas Tinggi, kembali ke mode Ekonomis tidak tersedia",
"title": "Setelan pengetahuan"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Pausa",
"list.action.resume": "Riprendi",
"list.action.settings": "Impostazioni segmenti",
"list.action.summary": "Genera riepilogo",
"list.action.sync": "Sincronizza",
"list.action.unarchive": "Disarchivia",
"list.action.uploadFile": "Carica nuovo file",
@ -75,6 +76,9 @@
"list.status.indexing": "Indicizzazione",
"list.status.paused": "In pausa",
"list.status.queuing": "In coda",
"list.summary.generating": "Generazione...",
"list.summary.generatingSummary": "Generazione riepilogo",
"list.summary.ready": "Riepilogo pronto",
"list.table.header.action": "AZIONE",
"list.table.header.chunkingMode": "MODALITÀ DI SUDDIVISIONE IN BLOCCHI",
"list.table.header.fileName": "NOME FILE",
@ -329,5 +333,7 @@
"segment.searchResults_one": "RISULTATO",
"segment.searchResults_other": "RISULTATI",
"segment.searchResults_zero": "RISULTATO",
"segment.summary": "RIEPILOGO",
"segment.summaryPlaceholder": "Scrivi un breve riepilogo per un migliore recupero…",
"segment.vectorHash": "Hash del vettore: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Impostazioni di recupero",
"form.save": "Salva",
"form.searchModel": "Cerca modello",
"form.summaryAutoGen": "Generazione Automatica Riepilogo",
"form.summaryAutoGenEnableTip": "Una volta abilitato, i riepiloghi verranno generati automaticamente per i documenti appena aggiunti. I documenti esistenti possono ancora essere riassunti manualmente.",
"form.summaryAutoGenTip": "I riepiloghi vengono generati automaticamente per i documenti appena aggiunti. I documenti esistenti possono ancora essere riassunti manualmente.",
"form.summaryInstructions": "Istruzioni",
"form.summaryInstructionsPlaceholder": "Descrivi le regole o lo stile per i riepiloghi generati automaticamente…",
"form.summaryModel": "Modello di Riepilogo",
"form.upgradeHighQualityTip": "Una volta effettuato l'aggiornamento alla modalità Alta qualità, il ripristino della modalità Risparmio non è disponibile",
"title": "Impostazioni della Conoscenza"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "一時停止",
"list.action.resume": "再開",
"list.action.settings": "チャンク設定",
"list.action.summary": "要約を生成",
"list.action.sync": "同期",
"list.action.unarchive": "アーカイブ解除",
"list.action.uploadFile": "新しいファイルをアップロード",
@ -75,6 +76,9 @@
"list.status.indexing": "インデックス化中",
"list.status.paused": "一時停止中",
"list.status.queuing": "キューイング中",
"list.summary.generating": "生成中...",
"list.summary.generatingSummary": "要約を生成中",
"list.summary.ready": "要約が完成しました",
"list.table.header.action": "アクション",
"list.table.header.chunkingMode": "チャンキングモード",
"list.table.header.fileName": "ファイル名",
@ -329,5 +333,7 @@
"segment.searchResults_one": "検索結果",
"segment.searchResults_other": "検索結果",
"segment.searchResults_zero": "検索結果",
"segment.summary": "要約",
"segment.summaryPlaceholder": "より良い検索のために簡潔な要約を記入してください…",
"segment.vectorHash": "ベクトルハッシュ:"
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "検索設定",
"form.save": "保存",
"form.searchModel": "検索モデル",
"form.summaryAutoGen": "要約自動生成",
"form.summaryAutoGenEnableTip": "有効にすると、新しく追加されたドキュメントの要約が自動的に生成されます。既存のドキュメントは引き続き手動で要約できます。",
"form.summaryAutoGenTip": "新しく追加されたドキュメントの要約は自動的に生成されます。既存のドキュメントは引き続き手動で要約できます。",
"form.summaryInstructions": "指示",
"form.summaryInstructionsPlaceholder": "自動生成される要約のルールやスタイルを記述してください…",
"form.summaryModel": "要約モデル",
"form.upgradeHighQualityTip": "高品質モードにアップグレードすると、経済的モードには戻せません。",
"title": "ナレッジベースの設定"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "일시 중지",
"list.action.resume": "재개",
"list.action.settings": "세그먼트 설정",
"list.action.summary": "요약 생성",
"list.action.sync": "동기화",
"list.action.unarchive": "아카이브 해제",
"list.action.uploadFile": "새 파일 업로드",
@ -75,6 +76,9 @@
"list.status.indexing": "색인화 중",
"list.status.paused": "일시 중지됨",
"list.status.queuing": "대기 중",
"list.summary.generating": "생성 중...",
"list.summary.generatingSummary": "요약 생성 중",
"list.summary.ready": "요약 완료",
"list.table.header.action": "동작",
"list.table.header.chunkingMode": "청크 모드",
"list.table.header.fileName": "파일명",
@ -329,5 +333,7 @@
"segment.searchResults_one": "결과",
"segment.searchResults_other": "결과",
"segment.searchResults_zero": "결과",
"segment.summary": "요약",
"segment.summaryPlaceholder": "더 나은 검색을 위해 간단한 요약을 작성하세요…",
"segment.vectorHash": "벡터 해시: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "검색 설정",
"form.save": "저장",
"form.searchModel": "모델 검색",
"form.summaryAutoGen": "요약 자동 생성",
"form.summaryAutoGenEnableTip": "활성화하면 새로 추가된 문서에 대해 요약이 자동으로 생성됩니다. 기존 문서는 여전히 수동으로 요약할 수 있습니다.",
"form.summaryAutoGenTip": "새로 추가된 문서에 대해 요약이 자동으로 생성됩니다. 기존 문서는 여전히 수동으로 요약할 수 있습니다.",
"form.summaryInstructions": "지침",
"form.summaryInstructionsPlaceholder": "자동 생성 요약의 규칙이나 스타일을 설명하세요…",
"form.summaryModel": "요약 모델",
"form.upgradeHighQualityTip": "고품질 모드로 업그레이드한 후에는 경제적 모드로 되돌릴 수 없습니다.",
"title": "지식 설정"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Pauza",
"list.action.resume": "Wznów",
"list.action.settings": "Ustawienia segmentacji",
"list.action.summary": "Wygeneruj podsumowanie",
"list.action.sync": "Synchronizuj",
"list.action.unarchive": "Usuń z archiwum",
"list.action.uploadFile": "Wgraj nowy plik",
@ -75,6 +76,9 @@
"list.status.indexing": "Indeksowanie",
"list.status.paused": "Wstrzymane",
"list.status.queuing": "Oczekiwanie",
"list.summary.generating": "Generowanie...",
"list.summary.generatingSummary": "Generowanie podsumowania",
"list.summary.ready": "Podsumowanie gotowe",
"list.table.header.action": "AKCJA",
"list.table.header.chunkingMode": "TRYB CHUNKINGU",
"list.table.header.fileName": "NAZWA PLIKU",
@ -329,5 +333,7 @@
"segment.searchResults_one": "WYNIK",
"segment.searchResults_other": "WYNIKI",
"segment.searchResults_zero": "WYNIK",
"segment.summary": "PODSUMOWANIE",
"segment.summaryPlaceholder": "Napisz krótkie podsumowanie dla lepszego wyszukiwania…",
"segment.vectorHash": "Wektor hash: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Ustawienia pobierania",
"form.save": "Zapisz",
"form.searchModel": "Szukaj modelu",
"form.summaryAutoGen": "Automatyczne Generowanie Podsumowania",
"form.summaryAutoGenEnableTip": "Po włączeniu podsumowania będą generowane automatycznie dla nowo dodanych dokumentów. Istniejące dokumenty nadal mogą być podsumowywane ręcznie.",
"form.summaryAutoGenTip": "Podsumowania są generowane automatycznie dla nowo dodanych dokumentów. Istniejące dokumenty nadal mogą być podsumowywane ręcznie.",
"form.summaryInstructions": "Instrukcje",
"form.summaryInstructionsPlaceholder": "Opisz zasady lub styl dla automatycznie generowanych podsumowań…",
"form.summaryModel": "Model Podsumowania",
"form.upgradeHighQualityTip": "Po uaktualnieniu do trybu wysokiej jakości powrót do trybu ekonomicznego nie jest dostępny",
"title": "Ustawienia wiedzy"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Pausa",
"list.action.resume": "Retomar",
"list.action.settings": "Configurações de segmento",
"list.action.summary": "Gerar resumo",
"list.action.sync": "Sincronizar",
"list.action.unarchive": "Desarquivar",
"list.action.uploadFile": "Enviar novo arquivo",
@ -75,6 +76,9 @@
"list.status.indexing": "Indexando",
"list.status.paused": "Pausado",
"list.status.queuing": "Em fila",
"list.summary.generating": "Gerando...",
"list.summary.generatingSummary": "Gerando resumo",
"list.summary.ready": "Resumo pronto",
"list.table.header.action": "AÇÃO",
"list.table.header.chunkingMode": "MODO DE FRAGMENTAÇÃO",
"list.table.header.fileName": "NOME DO ARQUIVO",
@ -329,5 +333,7 @@
"segment.searchResults_one": "RESULTADO",
"segment.searchResults_other": "RESULTADOS",
"segment.searchResults_zero": "RESULTADO",
"segment.summary": "RESUMO",
"segment.summaryPlaceholder": "Escreva um breve resumo para melhor recuperação…",
"segment.vectorHash": "Hash do vetor: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Configurações de recuperação",
"form.save": "Salvar",
"form.searchModel": "Pesquisar modelo",
"form.summaryAutoGen": "Geração Automática de Resumo",
"form.summaryAutoGenEnableTip": "Uma vez ativado, resumos serão gerados automaticamente para documentos recém-adicionados. Documentos existentes ainda podem ser resumidos manualmente.",
"form.summaryAutoGenTip": "Resumos são gerados automaticamente para documentos recém-adicionados. Documentos existentes ainda podem ser resumidos manualmente.",
"form.summaryInstructions": "Instruções",
"form.summaryInstructionsPlaceholder": "Descreva as regras ou estilo para resumos gerados automaticamente…",
"form.summaryModel": "Modelo de Resumo",
"form.upgradeHighQualityTip": "Depois de atualizar para o modo de alta qualidade, reverter para o modo econômico não está disponível",
"title": "Configurações do conhecimento"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Pauză",
"list.action.resume": "Reia",
"list.action.settings": "Setări de segment",
"list.action.summary": "Generați rezumat",
"list.action.sync": "Sincronizează",
"list.action.unarchive": "Dezarhivează",
"list.action.uploadFile": "Încarcă un fișier nou",
@ -75,6 +76,9 @@
"list.status.indexing": "Indexare",
"list.status.paused": "Întrerupt",
"list.status.queuing": "În coadă",
"list.summary.generating": "Generare...",
"list.summary.generatingSummary": "Generare rezumat",
"list.summary.ready": "Rezumat gata",
"list.table.header.action": "ACȚIUNE",
"list.table.header.chunkingMode": "MOD DE FRAGMENTARE",
"list.table.header.fileName": "NUMELE FIȘIERULUI",
@ -329,5 +333,7 @@
"segment.searchResults_one": "REZULTAT",
"segment.searchResults_other": "REZULTATELE",
"segment.searchResults_zero": "REZULTAT",
"segment.summary": "REZUMAT",
"segment.summaryPlaceholder": "Scrieți un rezumat scurt pentru o recuperare mai bună…",
"segment.vectorHash": "Vector hash: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Setări de recuperare",
"form.save": "Salvare",
"form.searchModel": "Căutare model",
"form.summaryAutoGen": "Generare Automată Rezumat",
"form.summaryAutoGenEnableTip": "Odată activat, rezumatele vor fi generate automat pentru documentele nou adăugate. Documentele existente pot fi încă rezumate manual.",
"form.summaryAutoGenTip": "Rezumatele sunt generate automat pentru documentele nou adăugate. Documentele existente pot fi încă rezumate manual.",
"form.summaryInstructions": "Instrucțiuni",
"form.summaryInstructionsPlaceholder": "Descrieți regulile sau stilul pentru rezumatele generate automat…",
"form.summaryModel": "Model Rezumat",
"form.upgradeHighQualityTip": "După ce faceți upgrade la modul Înaltă calitate, revenirea la modul Economic nu este disponibilă",
"title": "Setări de cunoștințe"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Пауза",
"list.action.resume": "Возобновить",
"list.action.settings": "Настройки сегментации",
"list.action.summary": "Создать резюме",
"list.action.sync": "Синхронизировать",
"list.action.unarchive": "Разархивировать",
"list.action.uploadFile": "Загрузить новый файл",
@ -75,6 +76,9 @@
"list.status.indexing": "Индексация",
"list.status.paused": "Приостановлено",
"list.status.queuing": "В очереди",
"list.summary.generating": "Создание...",
"list.summary.generatingSummary": "Создание резюме",
"list.summary.ready": "Резюме готово",
"list.table.header.action": "ДЕЙСТВИЕ",
"list.table.header.chunkingMode": "РЕЖИМ ДРОБЛЕНИЯ",
"list.table.header.fileName": "НАЗВАНИЕ ФАЙЛА",
@ -329,5 +333,7 @@
"segment.searchResults_one": "РЕЗУЛЬТАТ",
"segment.searchResults_other": "РЕЗУЛЬТАТЫ",
"segment.searchResults_zero": "РЕЗУЛЬТАТ",
"segment.summary": "РЕЗЮМЕ",
"segment.summaryPlaceholder": "Напишите краткое резюме для лучшего поиска…",
"segment.vectorHash": "Векторный хэш: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Настройки извлечения",
"form.save": "Сохранить",
"form.searchModel": "Поиск модели",
"form.summaryAutoGen": "Автоматическое создание резюме",
"form.summaryAutoGenEnableTip": "После включения резюме будут автоматически генерироваться для вновь добавленных документов. Существующие документы по-прежнему можно резюмировать вручную.",
"form.summaryAutoGenTip": "Резюме автоматически генерируются для вновь добавленных документов. Существующие документы по-прежнему можно резюмировать вручную.",
"form.summaryInstructions": "Инструкции",
"form.summaryInstructionsPlaceholder": "Опишите правила или стиль для автоматически сгенерированных резюме…",
"form.summaryModel": "Модель резюме",
"form.upgradeHighQualityTip": "После обновления до режима «Высокое качество» возврат к экономичному режиму невозможен",
"title": "Настройки базы знаний"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Zaustavi",
"list.action.resume": "Nadaljuj",
"list.action.settings": "Nastavitve segmenta",
"list.action.summary": "Ustvari povzetek",
"list.action.sync": "Sinhroniziraj",
"list.action.unarchive": "Razveljavi arhiviranje",
"list.action.uploadFile": "Naloži novo datoteko",
@ -75,6 +76,9 @@
"list.status.indexing": "Indeksiranje",
"list.status.paused": "Zaustavljeno",
"list.status.queuing": "V čakalni vrsti",
"list.summary.generating": "Ustvarjanje...",
"list.summary.generatingSummary": "Ustvarjanje povzetka",
"list.summary.ready": "Povzetek pripravljen",
"list.table.header.action": "DEJANJE",
"list.table.header.chunkingMode": "NAČIN KOŠČENJA",
"list.table.header.fileName": "IME DATOTEKE",
@ -329,5 +333,7 @@
"segment.searchResults_one": "REZULTAT",
"segment.searchResults_other": "REZULTATI",
"segment.searchResults_zero": "REZULTAT",
"segment.summary": "POVZETEK",
"segment.summaryPlaceholder": "Napišite kratek povzetek za boljše iskanje…",
"segment.vectorHash": "Vektorski hash: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Nastavitve pridobivanja",
"form.save": "Shrani",
"form.searchModel": "Išči model",
"form.summaryAutoGen": "Samodejna Tvorba Povzetka",
"form.summaryAutoGenEnableTip": "Ko je omogočeno, bodo povzetki samodejno ustvarjeni za novo dodane dokumente. Obstoječe dokumente lahko še vedno povzamete ročno.",
"form.summaryAutoGenTip": "Povzetki so samodejno ustvarjeni za novo dodane dokumente. Obstoječe dokumente lahko še vedno povzamete ročno.",
"form.summaryInstructions": "Navodila",
"form.summaryInstructionsPlaceholder": "Opišite pravila ali slog za samodejno ustvarjene povzetke…",
"form.summaryModel": "Model Povzetka",
"form.upgradeHighQualityTip": "Ko nadgradite na način visoke kakovosti, vrnitev v ekonomični način ni na voljo",
"title": "Nastavitve znanja"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "หยุด",
"list.action.resume": "ดำเนิน",
"list.action.settings": "การตั้งค่ากลุ่ม",
"list.action.summary": "สร้างสรุป",
"list.action.sync": "ซิงค์",
"list.action.unarchive": "ยกเลิกการเก็บถาวร",
"list.action.uploadFile": "อัปโหลดไฟล์ใหม่",
@ -75,6 +76,9 @@
"list.status.indexing": "ดัชนี",
"list.status.paused": "หยุดชั่วคราว",
"list.status.queuing": "จัด คิว",
"list.summary.generating": "กำลังสร้าง...",
"list.summary.generatingSummary": "กำลังสร้างสรุป",
"list.summary.ready": "สรุปพร้อมแล้ว",
"list.table.header.action": "การเคลื่อนไหว",
"list.table.header.chunkingMode": "โหมดก้อน",
"list.table.header.fileName": "ชื่อไฟล์",
@ -329,5 +333,7 @@
"segment.searchResults_one": "ผล",
"segment.searchResults_other": "ผลลัพธ์",
"segment.searchResults_zero": "ผล",
"segment.summary": "สรุป",
"segment.summaryPlaceholder": "เขียนสรุปสั้นๆ เพื่อการค้นหาที่ดีขึ้น…",
"segment.vectorHash": "แฮชเวกเตอร์:"
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "การตั้งค่าการดึงข้อมูล",
"form.save": "ประหยัด",
"form.searchModel": "ค้นหารุ่น",
"form.summaryAutoGen": "สร้างสรุปอัตโนมัติ",
"form.summaryAutoGenEnableTip": "เมื่อเปิดใช้งาน สรุปจะถูกสร้างขึ้นโดยอัตโนมัติสำหรับเอกสารที่เพิ่มใหม่ เอกสารที่มีอยู่ยังคงสามารถสรุปด้วยตนเองได้",
"form.summaryAutoGenTip": "สรุปจะถูกสร้างขึ้นโดยอัตโนมัติสำหรับเอกสารที่เพิ่มใหม่ เอกสารที่มีอยู่ยังคงสามารถสรุปด้วยตนเองได้",
"form.summaryInstructions": "คำแนะนำ",
"form.summaryInstructionsPlaceholder": "อธิบายกฎหรือรูปแบบสำหรับการสรุปที่สร้างขึ้นอัตโนมัติ…",
"form.summaryModel": "โมเดลสรุป",
"form.upgradeHighQualityTip": "เมื่ออัปเกรดเป็นโหมดคุณภาพสูงแล้ว จะไม่สามารถเปลี่ยนกลับเป็นโหมดประหยัดได้",
"title": "การตั้งค่าความรู้"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Duraklat",
"list.action.resume": "Devam Et",
"list.action.settings": "Segment ayarları",
"list.action.summary": "Özet oluştur",
"list.action.sync": "Senkronize et",
"list.action.unarchive": "Arşivden Çıkar",
"list.action.uploadFile": "Yeni dosya yükle",
@ -75,6 +76,9 @@
"list.status.indexing": "Dizine Ekleniyor",
"list.status.paused": "Durduruldu",
"list.status.queuing": "Kuyrukta",
"list.summary.generating": "Oluşturuluyor...",
"list.summary.generatingSummary": "Özet oluşturuluyor",
"list.summary.ready": "Özet hazır",
"list.table.header.action": "EYLEM",
"list.table.header.chunkingMode": "PARÇALAMA MODU",
"list.table.header.fileName": "DOSYA ADI",
@ -329,5 +333,7 @@
"segment.searchResults_one": "SONUÇ",
"segment.searchResults_other": "SONUÇ -LARI",
"segment.searchResults_zero": "SONUÇ",
"segment.summary": "ÖZET",
"segment.summaryPlaceholder": "Daha iyi arama için kısa bir özet yazın…",
"segment.vectorHash": "Vektör hash: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Alma Ayarları",
"form.save": "Kaydet",
"form.searchModel": "Model Ara",
"form.summaryAutoGen": "Özet Otomatik Oluşturma",
"form.summaryAutoGenEnableTip": "Etkinleştirildiğinde, yeni eklenen belgeler için özetler otomatik olarak oluşturulacaktır. Mevcut belgeler hala manuel olarak özetlenebilir.",
"form.summaryAutoGenTip": "Yeni eklenen belgeler için özetler otomatik olarak oluşturulur. Mevcut belgeler hala manuel olarak özetlenebilir.",
"form.summaryInstructions": "Talimatlar",
"form.summaryInstructionsPlaceholder": "Otomatik oluşturulan özetler için kuralları veya stili açıklayın…",
"form.summaryModel": "Özet Modeli",
"form.upgradeHighQualityTip": "Yüksek Kalite moduna yükselttikten sonra Ekonomik moda geri dönülemez",
"title": "Bilgi ayarları"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Пауза",
"list.action.resume": "Продовжити",
"list.action.settings": "Налаштування сегмента",
"list.action.summary": "Створити резюме",
"list.action.sync": "Синхронізувати",
"list.action.unarchive": "Розархівувати",
"list.action.uploadFile": "Завантажити новий файл",
@ -75,6 +76,9 @@
"list.status.indexing": "Індексування",
"list.status.paused": "Призупинено",
"list.status.queuing": "В черзі",
"list.summary.generating": "Створення...",
"list.summary.generatingSummary": "Створення резюме",
"list.summary.ready": "Резюме готове",
"list.table.header.action": "ДІЯ",
"list.table.header.chunkingMode": "РЕЖИМ ФРАГМЕНТАЦІЇ",
"list.table.header.fileName": "НАЗВА ФАЙЛУ",
@ -329,5 +333,7 @@
"segment.searchResults_one": "РЕЗУЛЬТАТ",
"segment.searchResults_other": "РЕЗУЛЬТАТІВ",
"segment.searchResults_zero": "РЕЗУЛЬТАТ",
"segment.summary": "РЕЗЮМЕ",
"segment.summaryPlaceholder": "Напишіть короткий опис для кращого пошуку…",
"segment.vectorHash": "Векторний хеш: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Налаштування отримання",
"form.save": "Зберегти",
"form.searchModel": "Пошук моделі",
"form.summaryAutoGen": "Автоматичне створення резюме",
"form.summaryAutoGenEnableTip": "Після увімкнення резюме будуть автоматично генеруватися для нових документів. Існуючі документи все ще можна резюмувати вручну.",
"form.summaryAutoGenTip": "Резюме автоматично генеруються для нових документів. Існуючі документи все ще можна резюмувати вручну.",
"form.summaryInstructions": "Інструкції",
"form.summaryInstructionsPlaceholder": "Опишіть правила або стиль для автоматично згенерованих резюме…",
"form.summaryModel": "Модель резюме",
"form.upgradeHighQualityTip": "Після оновлення до режиму високої якості повернення до економного режиму недоступне",
"title": "Налаштування бази знань"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "Tạm dừng",
"list.action.resume": "Tiếp tục",
"list.action.settings": "Cài đặt phân đoạn",
"list.action.summary": "Tạo tóm tắt",
"list.action.sync": "Đồng bộ",
"list.action.unarchive": "Khôi phục",
"list.action.uploadFile": "Tải lên tệp mới",
@ -75,6 +76,9 @@
"list.status.indexing": "Đang lập chỉ mục",
"list.status.paused": "Tạm dừng",
"list.status.queuing": "Đang chờ",
"list.summary.generating": "Đang tạo...",
"list.summary.generatingSummary": "Đang tạo tóm tắt",
"list.summary.ready": "Tóm tắt đã sẵn sàng",
"list.table.header.action": "THAO TÁC",
"list.table.header.chunkingMode": "CHẾ ĐỘ CHUNKING",
"list.table.header.fileName": "TÊN TỆP",
@ -329,5 +333,7 @@
"segment.searchResults_one": "KẾT QUẢ",
"segment.searchResults_other": "KẾT QUẢ",
"segment.searchResults_zero": "KẾT QUẢ",
"segment.summary": "TÓM TẮT",
"segment.summaryPlaceholder": "Viết tóm tắt ngắn gọn để tìm kiếm tốt hơn…",
"segment.vectorHash": "Mã băm vector: "
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "Cài đặt truy xuất",
"form.save": "Lưu",
"form.searchModel": "Tìm kiếm mô hình",
"form.summaryAutoGen": "Tự động Tạo Tóm tắt",
"form.summaryAutoGenEnableTip": "Sau khi bật, tóm tắt sẽ được tạo tự động cho các tài liệu mới được thêm. Các tài liệu hiện có vẫn có thể được tóm tắt thủ công.",
"form.summaryAutoGenTip": "Tóm tắt được tạo tự động cho các tài liệu mới được thêm. Các tài liệu hiện có vẫn có thể được tóm tắt thủ công.",
"form.summaryInstructions": "Hướng dẫn",
"form.summaryInstructionsPlaceholder": "Mô tả các quy tắc hoặc phong cách cho tóm tắt được tạo tự động…",
"form.summaryModel": "Mô hình Tóm tắt",
"form.upgradeHighQualityTip": "Sau khi nâng cấp lên chế độ Chất lượng cao, không thể hoàn nguyên về chế độ Tiết kiệm",
"title": "Cài đặt Kiến thức"
}

View File

@ -31,6 +31,7 @@
"list.action.pause": "暫停",
"list.action.resume": "恢復",
"list.action.settings": "分段設定",
"list.action.summary": "產生摘要",
"list.action.sync": "同步",
"list.action.unarchive": "撤銷歸檔",
"list.action.uploadFile": "上傳新檔案",
@ -75,6 +76,9 @@
"list.status.indexing": "索引中",
"list.status.paused": "已暫停",
"list.status.queuing": "排隊中",
"list.summary.generating": "產生中...",
"list.summary.generatingSummary": "產生摘要中",
"list.summary.ready": "摘要已完成",
"list.table.header.action": "操作",
"list.table.header.chunkingMode": "分塊模式",
"list.table.header.fileName": "檔名",
@ -329,5 +333,7 @@
"segment.searchResults_one": "結果",
"segment.searchResults_other": "結果",
"segment.searchResults_zero": "結果",
"segment.summary": "摘要",
"segment.summaryPlaceholder": "撰寫簡短的摘要以便更好地檢索…",
"segment.vectorHash": "向量雜湊:"
}

View File

@ -39,6 +39,12 @@
"form.retrievalSettings": "檢索設置",
"form.save": "儲存",
"form.searchModel": "搜索模型",
"form.summaryAutoGen": "摘要自動產生",
"form.summaryAutoGenEnableTip": "啟用後,將自動為新添加的文件產生摘要。現有文件仍可手動摘要。",
"form.summaryAutoGenTip": "將自動為新添加的文件產生摘要。現有文件仍可手動摘要。",
"form.summaryInstructions": "指令",
"form.summaryInstructionsPlaceholder": "描述自動產生摘要的規則或風格…",
"form.summaryModel": "摘要模型",
"form.upgradeHighQualityTip": "升級到高品質模式后,無法恢復到經濟模式",
"title": "知識庫設定"
}