Compare commits

...

17 Commits

Author SHA1 Message Date
9de3ecc4a8 Fix: rm field not allow check (#12240)
### What problem does this PR solve?

Remove not allowed field check.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-12-26 16:43:46 +08:00
c4a66204f0 Fix: Memory-related bug fixes (#12238)
### What problem does this PR solve?

Fix: Memory-related bug fixes
- Forget memory button text
- Adjust memory storage interface
### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-12-26 15:56:41 +08:00
3558a6c170 Fix: allow update memory type (#12237)
### What problem does this PR solve?

Allow update memory_type.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-12-26 15:26:56 +08:00
595fc4ccec Feat: Display the selected list of memories in the retrieval node. #4213 (#12235)
### What problem does this PR solve?

Feat: Display the selected list of memories in the retrieval node. #4213

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
2025-12-26 15:20:40 +08:00
3ad147d349 Update deploy_local_llm.mdx with vllm guide support (#12222)
### What problem does this PR solve?

vllm guide support

### Type of change

- [x] Documentation Update
2025-12-26 15:14:25 +08:00
d285d8cd97 Fix: memory (#12230)
### What problem does this PR solve?

Judge has attr memory_ids

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-12-26 14:42:47 +08:00
5714895291 Fix message duration (#12233)
### What problem does this PR solve?

As title

### Type of change

- [x] Refactoring

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2025-12-26 14:40:46 +08:00
a33936e8ff Fix small issues on UI (#12231)
### What problem does this PR solve?

As title

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2025-12-26 14:21:59 +08:00
9f8161d13e Fix memory config: user prompt text box (#12229)
### What problem does this PR solve?

As title

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2025-12-26 14:05:58 +08:00
a599a0f4bf Fix forget policy (#12228)
### What problem does this PR solve?

As title

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2025-12-26 13:54:15 +08:00
7498bc63a3 Fix: judge retrieval from (#12223)
### What problem does this PR solve?

Judge retrieval from in retrieval component, and fix bug in message
component

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-12-26 13:01:46 +08:00
894bf995bb Fix: Memory-related bug fixes (#12226)
### What problem does this PR solve?

Fix: bugs fix
- table -> Table
- memory delete fail
- memory copywriting modified

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-12-26 12:24:05 +08:00
52dbacc506 Feat: Preview the image at the bottom of the message #12076 (#12225)
### What problem does this PR solve?

Feat: Preview the image at the bottom of the message #12076

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
2025-12-26 12:11:19 +08:00
cbcbbc41af Feat: The agent can only retrieve content from the knowledge base or memory. #4213 (#12224)
### What problem does this PR solve?

Feat: The agent can only retrieve content from the knowledge base or
memory. #4213

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
2025-12-26 12:10:13 +08:00
6044314811 Fix text issue (#12221)
### What problem does this PR solve?

Fix several text issues.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2025-12-26 11:18:08 +08:00
5fb38ecc2a Fix: Can not select LLM in memory page (#12219)
### What problem does this PR solve?

Fix: Can not select LLM in memory page

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
2025-12-26 11:00:11 +08:00
73db759558 refactor: improve memory service date time consistency (#12144)
### What problem does this PR solve?

 improve memory service date time consistency

### Type of change

- [x] Refactoring
2025-12-26 09:54:38 +08:00
50 changed files with 674 additions and 220 deletions

View File

@ -427,7 +427,7 @@ class Message(ComponentBase):
logging.error(f"Error converting content to {self._param.output_format}: {e}") logging.error(f"Error converting content to {self._param.output_format}: {e}")
async def _save_to_memory(self, content): async def _save_to_memory(self, content):
if not self._param.memory_ids: if not hasattr(self._param, "memory_ids") or not self._param.memory_ids:
return True, "No memory selected." return True, "No memory selected."
message_dict = { message_dict = {

View File

@ -282,7 +282,11 @@ class Retrieval(ToolBase, ABC):
self.set_output("formalized_content", self._param.empty_response) self.set_output("formalized_content", self._param.empty_response)
return return
if self._param.kb_ids: if hasattr(self._param, "retrieval_from") and self._param.retrieval_from == "dataset":
return await self._retrieve_kb(kwargs["query"])
elif hasattr(self._param, "retrieval_from") and self._param.retrieval_from == "memory":
return await self._retrieve_memory(kwargs["query"])
elif self._param.kb_ids:
return await self._retrieve_kb(kwargs["query"]) return await self._retrieve_kb(kwargs["query"])
elif hasattr(self._param, "memory_ids") and self._param.memory_ids: elif hasattr(self._param, "memory_ids") and self._param.memory_ids:
return await self._retrieve_memory(kwargs["query"]) return await self._retrieve_memory(kwargs["query"])

View File

@ -21,11 +21,12 @@ from api.db import TenantPermission
from api.db.services.memory_service import MemoryService from api.db.services.memory_service import MemoryService
from api.db.services.user_service import UserTenantService from api.db.services.user_service import UserTenantService
from api.db.services.canvas_service import UserCanvasService from api.db.services.canvas_service import UserCanvasService
from api.utils.api_utils import validate_request, get_request_json, get_error_argument_result, get_json_result, \ from api.db.joint_services.memory_message_service import get_memory_size_cache, judge_system_prompt_is_default
not_allowed_parameters from api.utils.api_utils import validate_request, get_request_json, get_error_argument_result, get_json_result
from api.utils.memory_utils import format_ret_data_from_memory, get_memory_type_human from api.utils.memory_utils import format_ret_data_from_memory, get_memory_type_human
from api.constants import MEMORY_NAME_LIMIT, MEMORY_SIZE_LIMIT from api.constants import MEMORY_NAME_LIMIT, MEMORY_SIZE_LIMIT
from memory.services.messages import MessageService from memory.services.messages import MessageService
from memory.utils.prompt_util import PromptAssembler
from common.constants import MemoryType, RetCode, ForgettingPolicy from common.constants import MemoryType, RetCode, ForgettingPolicy
@ -68,7 +69,6 @@ async def create_memory():
@manager.route("/<memory_id>", methods=["PUT"]) # noqa: F821 @manager.route("/<memory_id>", methods=["PUT"]) # noqa: F821
@login_required @login_required
@not_allowed_parameters("id", "tenant_id", "memory_type", "storage_type", "embd_id")
async def update_memory(memory_id): async def update_memory(memory_id):
req = await get_request_json() req = await get_request_json()
update_dict = {} update_dict = {}
@ -88,6 +88,14 @@ async def update_memory(memory_id):
update_dict["permissions"] = req["permissions"] update_dict["permissions"] = req["permissions"]
if req.get("llm_id"): if req.get("llm_id"):
update_dict["llm_id"] = req["llm_id"] update_dict["llm_id"] = req["llm_id"]
if req.get("embd_id"):
update_dict["embd_id"] = req["embd_id"]
if req.get("memory_type"):
memory_type = set(req["memory_type"])
invalid_type = memory_type - {e.name.lower() for e in MemoryType}
if invalid_type:
return get_error_argument_result(f"Memory type '{invalid_type}' is not supported.")
update_dict["memory_type"] = list(memory_type)
# check memory_size valid # check memory_size valid
if req.get("memory_size"): if req.get("memory_size"):
if not 0 < int(req["memory_size"]) <= MEMORY_SIZE_LIMIT: if not 0 < int(req["memory_size"]) <= MEMORY_SIZE_LIMIT:
@ -123,6 +131,15 @@ async def update_memory(memory_id):
if not to_update: if not to_update:
return get_json_result(message=True, data=memory_dict) return get_json_result(message=True, data=memory_dict)
# check memory empty when update embd_id, memory_type
memory_size = get_memory_size_cache(memory_id, current_memory.tenant_id)
not_allowed_update = [f for f in ["embd_id", "memory_type"] if f in to_update and memory_size > 0]
if not_allowed_update:
return get_error_argument_result(f"Can't update {not_allowed_update} when memory isn't empty.")
if "memory_type" in to_update:
if "system_prompt" not in to_update and judge_system_prompt_is_default(current_memory.system_prompt, current_memory.memory_type):
# update old default prompt, assemble a new one
to_update["system_prompt"] = PromptAssembler.assemble_system_prompt({"memory_type": to_update["memory_type"]})
try: try:
MemoryService.update_memory(current_memory.tenant_id, memory_id, to_update) MemoryService.update_memory(current_memory.tenant_id, memory_id, to_update)

View File

@ -1189,7 +1189,7 @@ class Memory(DataBaseModel):
permissions = CharField(max_length=16, null=False, index=True, help_text="me|team", default="me") permissions = CharField(max_length=16, null=False, index=True, help_text="me|team", default="me")
description = TextField(null=True, help_text="description") description = TextField(null=True, help_text="description")
memory_size = IntegerField(default=5242880, null=False, index=False) memory_size = IntegerField(default=5242880, null=False, index=False)
forgetting_policy = CharField(max_length=32, null=False, default="fifo", index=False, help_text="lru|fifo") forgetting_policy = CharField(max_length=32, null=False, default="FIFO", index=False, help_text="LRU|FIFO")
temperature = FloatField(default=0.5, index=False) temperature = FloatField(default=0.5, index=False)
system_prompt = TextField(null=True, help_text="system prompt", index=False) system_prompt = TextField(null=True, help_text="system prompt", index=False)
user_prompt = TextField(null=True, help_text="user prompt", index=False) user_prompt = TextField(null=True, help_text="user prompt", index=False)

View File

@ -96,7 +96,7 @@ async def save_to_memory(memory_id: str, message_dict: dict):
current_memory_size = get_memory_size_cache(memory_id, tenant_id) current_memory_size = get_memory_size_cache(memory_id, tenant_id)
if new_msg_size + current_memory_size > memory.memory_size: if new_msg_size + current_memory_size > memory.memory_size:
size_to_delete = current_memory_size + new_msg_size - memory.memory_size size_to_delete = current_memory_size + new_msg_size - memory.memory_size
if memory.forgetting_policy == "fifo": if memory.forgetting_policy == "FIFO":
message_ids_to_delete, delete_size = MessageService.pick_messages_to_delete_by_fifo(memory_id, tenant_id, size_to_delete) message_ids_to_delete, delete_size = MessageService.pick_messages_to_delete_by_fifo(memory_id, tenant_id, size_to_delete)
MessageService.delete_message({"message_id": message_ids_to_delete}, tenant_id, memory_id) MessageService.delete_message({"message_id": message_ids_to_delete}, tenant_id, memory_id)
decrease_memory_size_cache(memory_id, delete_size) decrease_memory_size_cache(memory_id, delete_size)
@ -231,3 +231,8 @@ def init_memory_size_cache():
memory_size = memory_size_map.get(memory.id, 0) memory_size = memory_size_map.get(memory.id, 0)
set_memory_size_cache(memory.id, memory_size) set_memory_size_cache(memory.id, memory_size)
logging.info("Memory size cache init done.") logging.info("Memory size cache init done.")
def judge_system_prompt_is_default(system_prompt: str, memory_type: int|list[str]):
memory_type_list = memory_type if isinstance(memory_type, list) else get_memory_type_human(memory_type)
return system_prompt == PromptAssembler.assemble_system_prompt({"memory_type": memory_type_list})

View File

@ -117,6 +117,8 @@ class MemoryService(CommonService):
if len(memory_name) > MEMORY_NAME_LIMIT: if len(memory_name) > MEMORY_NAME_LIMIT:
return False, f"Memory name {memory_name} exceeds limit of {MEMORY_NAME_LIMIT}." return False, f"Memory name {memory_name} exceeds limit of {MEMORY_NAME_LIMIT}."
timestamp = current_timestamp()
format_time = get_format_time()
# build create dict # build create dict
memory_info = { memory_info = {
"id": get_uuid(), "id": get_uuid(),
@ -126,10 +128,10 @@ class MemoryService(CommonService):
"embd_id": embd_id, "embd_id": embd_id,
"llm_id": llm_id, "llm_id": llm_id,
"system_prompt": PromptAssembler.assemble_system_prompt({"memory_type": memory_type}), "system_prompt": PromptAssembler.assemble_system_prompt({"memory_type": memory_type}),
"create_time": current_timestamp(), "create_time": timestamp,
"create_date": get_format_time(), "create_date": format_time,
"update_time": current_timestamp(), "update_time": timestamp,
"update_date": get_format_time(), "update_date": format_time,
} }
obj = cls.model(**memory_info).save(force_insert=True) obj = cls.model(**memory_info).save(force_insert=True)
@ -147,6 +149,8 @@ class MemoryService(CommonService):
return 0 return 0
if "temperature" in update_dict and isinstance(update_dict["temperature"], str): if "temperature" in update_dict and isinstance(update_dict["temperature"], str):
update_dict["temperature"] = float(update_dict["temperature"]) update_dict["temperature"] = float(update_dict["temperature"])
if "memory_type" in update_dict and isinstance(update_dict["memory_type"], list):
update_dict["memory_type"] = calculate_memory_type(update_dict["memory_type"])
if "name" in update_dict: if "name" in update_dict:
update_dict["name"] = duplicate_name( update_dict["name"] = duplicate_name(
cls.query, cls.query,

View File

@ -171,7 +171,7 @@ class MemoryStorageType(StrEnum):
class ForgettingPolicy(StrEnum): class ForgettingPolicy(StrEnum):
FIFO = "fifo" FIFO = "FIFO"
# environment # environment

View File

@ -7,7 +7,7 @@ slug: /deploy_local_llm
import Tabs from '@theme/Tabs'; import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem'; import TabItem from '@theme/TabItem';
Deploy and run local models using Ollama, Xinference, or other frameworks. Deploy and run local models using Ollama, Xinference, VLLM SGLANG or other frameworks.
--- ---
@ -314,3 +314,41 @@ To enable IPEX-LLM accelerated Ollama in RAGFlow, you must also complete the con
3. [Update System Model Settings](#6-update-system-model-settings) 3. [Update System Model Settings](#6-update-system-model-settings)
4. [Update Chat Configuration](#7-update-chat-configuration) 4. [Update Chat Configuration](#7-update-chat-configuration)
### 5. Deploy VLLM
ubuntu 22.04/24.04
```bash
pip install vllm
```
### 5.1 RUN VLLM WITH BEST PRACTISE
```bash
nohup vllm serve /data/Qwen3-8B --served-model-name Qwen3-8B-FP8 --dtype auto --port 1025 --gpu-memory-utilization 0.90 --tool-call-parser hermes --enable-auto-tool-choice > /var/log/vllm_startup1.log 2>&1 &
```
you can get log info
```bash
tail -f -n 100 /var/log/vllm_startup1.log
```
when see the follow ,it means vllm engine is ready for access
```bash
Starting vLLM API server 0 on http://0.0.0.0:1025
Started server process [19177]
Application startup complete.
```
### 5.2 INTERGRATEING RAGFLOW WITH VLLM CHAT/EM/RERANK LLM WITH WEBUI
setting->model providers->search->vllm->add ,configure as follow:<br>
![add vllm](https://github.com/user-attachments/assets/6f1d9f1a-3507-465b-87a3-4427254fff86)
select vllm chat model as default llm model as follow:<br>
![chat](https://github.com/user-attachments/assets/05efbd4b-2c18-4c6b-8d1c-52bae712372d)
### 5.3 chat with vllm chat model
create chat->create conversations-chat as follow:<br>
![chat](https://github.com/user-attachments/assets/dc1885f6-23a9-48f1-8850-d5f59b5e8f67)

26
web/package-lock.json generated
View File

@ -90,6 +90,7 @@
"react-infinite-scroll-component": "^6.1.0", "react-infinite-scroll-component": "^6.1.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-pdf-highlighter": "^6.1.0", "react-pdf-highlighter": "^6.1.0",
"react-photo-view": "^1.2.7",
"react-resizable-panels": "^3.0.6", "react-resizable-panels": "^3.0.6",
"react-string-replace": "^1.1.1", "react-string-replace": "^1.1.1",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",
@ -30404,6 +30405,16 @@
} }
} }
}, },
"node_modules/react-photo-view": {
"version": "1.2.7",
"resolved": "https://registry.npmmirror.com/react-photo-view/-/react-photo-view-1.2.7.tgz",
"integrity": "sha512-MfOWVPxuibncRLaycZUNxqYU8D9IA+rbGDDaq6GM8RIoGJal592hEJoRAyRSI7ZxyyJNJTLMUWWL3UIXHJJOpw==",
"license": "Apache-2.0",
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz", "resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz",
@ -36191,6 +36202,21 @@
} }
} }
}, },
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/tinyrainbow": { "node_modules/tinyrainbow": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz",

View File

@ -103,6 +103,7 @@
"react-infinite-scroll-component": "^6.1.0", "react-infinite-scroll-component": "^6.1.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-pdf-highlighter": "^6.1.0", "react-pdf-highlighter": "^6.1.0",
"react-photo-view": "^1.2.7",
"react-resizable-panels": "^3.0.6", "react-resizable-panels": "^3.0.6",
"react-string-replace": "^1.1.1", "react-string-replace": "^1.1.1",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",

View File

@ -2,6 +2,7 @@ import { Toaster as Sonner } from '@/components/ui/sonner';
import { Toaster } from '@/components/ui/toaster'; import { Toaster } from '@/components/ui/toaster';
import i18n from '@/locales/config'; import i18n from '@/locales/config';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { configResponsive } from 'ahooks';
import { App, ConfigProvider, ConfigProviderProps, theme } from 'antd'; import { App, ConfigProvider, ConfigProviderProps, theme } from 'antd';
import pt_BR from 'antd/lib/locale/pt_BR'; import pt_BR from 'antd/lib/locale/pt_BR';
import deDE from 'antd/locale/de_DE'; import deDE from 'antd/locale/de_DE';
@ -24,7 +25,7 @@ import { TooltipProvider } from './components/ui/tooltip';
import { ThemeEnum } from './constants/common'; import { ThemeEnum } from './constants/common';
import storage from './utils/authorization-util'; import storage from './utils/authorization-util';
import { configResponsive } from 'ahooks'; import 'react-photo-view/dist/react-photo-view.css';
configResponsive({ configResponsive({
sm: 640, sm: 640,

View File

@ -91,13 +91,13 @@ export function ConfirmDeleteDialog({
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogFooter className="px-5 flex items-center gap-2"> <AlertDialogFooter className="px-5 flex items-center gap-2">
<AlertDialogCancel onClick={onCancel}> <AlertDialogCancel onClick={onCancel}>
{okButtonText || t('common.cancel')} {cancelButtonText || t('common.cancel')}
</AlertDialogCancel> </AlertDialogCancel>
<AlertDialogAction <AlertDialogAction
className="bg-state-error text-text-primary hover:text-text-primary hover:bg-state-error" className="bg-state-error text-text-primary hover:text-text-primary hover:bg-state-error"
onClick={onOk} onClick={onOk}
> >
{cancelButtonText || t('common.delete')} {okButtonText || t('common.delete')}
</AlertDialogAction> </AlertDialogAction>
</AlertDialogFooter> </AlertDialogFooter>
</AlertDialogContent> </AlertDialogContent>

View File

@ -7,8 +7,11 @@ import {
CarouselPrevious, CarouselPrevious,
} from '@/components/ui/carousel'; } from '@/components/ui/carousel';
import { IReferenceChunk } from '@/interfaces/database/chat'; import { IReferenceChunk } from '@/interfaces/database/chat';
import { api_host } from '@/utils/api';
import { isPlainObject } from 'lodash'; import { isPlainObject } from 'lodash';
import { RotateCw, ZoomIn, ZoomOut } from 'lucide-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { PhotoProvider, PhotoView } from 'react-photo-view';
import { extractNumbersFromMessageContent } from './utils'; import { extractNumbersFromMessageContent } from './utils';
type IProps = { type IProps = {
@ -36,6 +39,28 @@ function ImageCarousel({ images }: { images: ImageItem[] }) {
const buttonVisibilityClass = getButtonVisibilityClass(images.length); const buttonVisibilityClass = getButtonVisibilityClass(images.length);
return ( return (
<PhotoProvider
// className="[&_.PhotoView-Slider__toolbarIcon]:hidden"
toolbarRender={({ rotate, onRotate, scale, onScale }) => {
return (
<>
<RotateCw
className="mr-4 cursor-pointer text-text-disabled hover:text-text-primary"
onClick={() => onRotate(rotate + 90)}
/>
<ZoomIn
className="mr-4 cursor-pointer text-text-disabled hover:text-text-primary"
onClick={() => onScale(scale + 1)}
/>
<ZoomOut
className="cursor-pointer text-text-disabled hover:text-text-primary"
onClick={() => onScale(scale - 1)}
/>
{/* <X className="cursor-pointer text-text-disabled hover:text-text-primary" /> */}
</>
);
}}
>
<Carousel <Carousel
className="w-full" className="w-full"
opts={{ opts={{
@ -54,17 +79,20 @@ function ImageCarousel({ images }: { images: ImageItem[] }) {
@2xl:basis-1/6 @2xl:basis-1/6
" "
> >
<PhotoView src={`${api_host}/document/image/${id}`}>
<Image <Image
id={id} id={id}
className="h-40 w-full" className="h-40 w-full"
label={`Fig. ${(index + 1).toString()}`} label={`Fig. ${(index + 1).toString()}`}
/> />
</PhotoView>
</CarouselItem> </CarouselItem>
))} ))}
</CarouselContent> </CarouselContent>
<CarouselPrevious className={buttonVisibilityClass} /> <CarouselPrevious className={buttonVisibilityClass} />
<CarouselNext className={buttonVisibilityClass} /> <CarouselNext className={buttonVisibilityClass} />
</Carousel> </Carousel>
</PhotoProvider>
); );
} }

View File

@ -1,6 +1,6 @@
import { toast } from 'sonner'; import { toast } from 'sonner';
const duration = { duration: 1500 }; const duration = { duration: 2500 };
const message = { const message = {
success: (msg: string) => { success: (msg: string) => {

View File

@ -31,6 +31,7 @@ export interface ModalProps {
cancelButtonClassName?: string; cancelButtonClassName?: string;
disabled?: boolean; disabled?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;
zIndex?: number;
} }
export interface ModalType extends FC<ModalProps> { export interface ModalType extends FC<ModalProps> {
show: typeof modalIns.show; show: typeof modalIns.show;
@ -63,6 +64,7 @@ const Modal: ModalType = ({
cancelButtonClassName, cancelButtonClassName,
disabled = false, disabled = false,
style, style,
zIndex = 50,
}) => { }) => {
const sizeClasses = { const sizeClasses = {
small: 'max-w-md', small: 'max-w-md',
@ -172,6 +174,7 @@ const Modal: ModalType = ({
<DialogPrimitive.Overlay <DialogPrimitive.Overlay
className="fixed inset-0 z-[1000] bg-bg-card backdrop-blur-[1px] flex items-center justify-center p-4" className="fixed inset-0 z-[1000] bg-bg-card backdrop-blur-[1px] flex items-center justify-center p-4"
onClick={() => maskClosable && onOpenChange?.(false)} onClick={() => maskClosable && onOpenChange?.(false)}
style={{ zIndex: zIndex }}
> >
<DialogPrimitive.Content <DialogPrimitive.Content
className={cn( className={cn(

View File

@ -102,6 +102,7 @@ export const useShowDeleteConfirm = () => {
style: { style: {
width: '450px', width: '450px',
}, },
zIndex: 1000,
okButtonClassName: okButtonClassName:
'bg-state-error text-white hover:bg-state-error hover:text-white', 'bg-state-error text-white hover:bg-state-error hover:text-white',
onOk: async () => { onOk: async () => {

View File

@ -266,20 +266,19 @@ export const useRunDocument = () => {
mutationFn: async ({ mutationFn: async ({
documentIds, documentIds,
run, run,
shouldDelete, option,
}: { }: {
documentIds: string[]; documentIds: string[];
run: number; run: number;
shouldDelete: boolean; option?: { delete: boolean; apply_kb: boolean };
}) => { }) => {
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: [DocumentApiAction.FetchDocumentList], queryKey: [DocumentApiAction.FetchDocumentList],
}); });
const ret = await kbService.document_run({ const ret = await kbService.document_run({
doc_ids: documentIds, doc_ids: documentIds,
run, run,
delete: shouldDelete, ...option,
}); });
const code = get(ret, 'data.code'); const code = get(ret, 'data.code');
if (code === 0) { if (code === 0) {

View File

@ -79,7 +79,7 @@ export function Header() {
{ path: Routes.Chats, name: t('header.chat'), icon: MessageSquareText }, { path: Routes.Chats, name: t('header.chat'), icon: MessageSquareText },
{ path: Routes.Searches, name: t('header.search'), icon: Search }, { path: Routes.Searches, name: t('header.search'), icon: Search },
{ path: Routes.Agents, name: t('header.flow'), icon: Cpu }, { path: Routes.Agents, name: t('header.flow'), icon: Cpu },
{ path: Routes.Memories, name: t('header.Memories'), icon: Cpu }, { path: Routes.Memories, name: t('header.memories'), icon: Cpu },
{ path: Routes.Files, name: t('header.fileManager'), icon: File }, { path: Routes.Files, name: t('header.fileManager'), icon: File },
], ],
[t], [t],

View File

@ -417,7 +417,7 @@ Prozedurales Gedächtnis: Erlernte Fähigkeiten, Gewohnheiten und automatisierte
fileFilter: 'Dateifilter', fileFilter: 'Dateifilter',
setDefaultTip: '', setDefaultTip: '',
setDefault: 'Als Standard festlegen', setDefault: 'Als Standard festlegen',
eidtLinkDataPipeline: 'Ingestion-Pipeline bearbeiten', editLinkDataPipeline: 'Ingestion-Pipeline bearbeiten',
linkPipelineSetTip: linkPipelineSetTip:
'Verknüpfung der Ingestion-Pipeline mit diesem Datensatz verwalten', 'Verknüpfung der Ingestion-Pipeline mit diesem Datensatz verwalten',
default: 'Standard', default: 'Standard',
@ -900,7 +900,7 @@ Beispiel: general/v2/`,
Beispiel: https://fsn1.your-objectstorage.com`, Beispiel: https://fsn1.your-objectstorage.com`,
S3CompatibleAddressingStyleTip: `Erforderlich für S3-kompatible Storage Box. Geben Sie den S3-kompatiblen Adressierungsstil an. S3CompatibleAddressingStyleTip: `Erforderlich für S3-kompatible Storage Box. Geben Sie den S3-kompatiblen Adressierungsstil an.
Beispiel: Virtual Hosted Style`, Beispiel: Virtual Hosted Style`,
addDataSourceModalTital: 'Erstellen Sie Ihren {{name}} Connector', addDataSourceModalTitle: 'Erstellen Sie Ihren {{name}} Connector',
deleteSourceModalTitle: 'Datenquelle löschen', deleteSourceModalTitle: 'Datenquelle löschen',
deleteSourceModalContent: ` deleteSourceModalContent: `
<p>Sind Sie sicher, dass Sie diese Datenquellenverknüpfung löschen möchten?</p>`, <p>Sind Sie sicher, dass Sie diese Datenquellenverknüpfung löschen möchten?</p>`,
@ -1357,12 +1357,12 @@ Beispiel: Virtual Hosted Style`,
search: 'Suchen', search: 'Suchen',
communication: 'Kommunikation', communication: 'Kommunikation',
developer: 'Entwickler', developer: 'Entwickler',
typeCommandOrsearch: 'Geben Sie einen Befehl ein oder suchen Sie...', typeCommandORsearch: 'Geben Sie einen Befehl ein oder suchen Sie...',
builtIn: 'Eingebaut', builtIn: 'Eingebaut',
ExceptionDefaultValue: 'Ausnahme-Standardwert', ExceptionDefaultValue: 'Ausnahme-Standardwert',
exceptionMethod: 'Ausnahmemethode', exceptionMethod: 'Ausnahmemethode',
maxRounds: 'Maximale Reflexionsrunden', maxRounds: 'Maximale Reflexionsrunden',
delayEfterError: 'Verzögerung nach Fehler', delayAfterError: 'Verzögerung nach Fehler',
maxRetries: 'Maximale Wiederholungsrunden', maxRetries: 'Maximale Wiederholungsrunden',
advancedSettings: 'Erweiterte Einstellungen', advancedSettings: 'Erweiterte Einstellungen',
addTools: 'Tools hinzufügen', addTools: 'Tools hinzufügen',
@ -1882,7 +1882,7 @@ Beispiel: Virtual Hosted Style`,
}`, }`,
datatype: 'MIME-Typ der HTTP-Anfrage', datatype: 'MIME-Typ der HTTP-Anfrage',
insertVariableTip: 'Eingabe / Variablen einfügen', insertVariableTip: 'Eingabe / Variablen einfügen',
historyversion: 'Versionsverlauf', historyVersion: 'Versionsverlauf',
version: { version: {
created: 'Erstellt', created: 'Erstellt',
details: 'Versionsdetails', details: 'Versionsdetails',

View File

@ -99,7 +99,7 @@ export default {
search: 'Search', search: 'Search',
welcome: 'Welcome to', welcome: 'Welcome to',
dataset: 'Dataset', dataset: 'Dataset',
Memories: 'Memory', memories: 'Memory',
}, },
memories: { memories: {
llmTooltip: llmTooltip:
@ -112,6 +112,10 @@ export default {
Semantic Memory: General knowledge and facts about the user and world. Semantic Memory: General knowledge and facts about the user and world.
Episodic Memory: Time-stamped records of specific events and experiences. Episodic Memory: Time-stamped records of specific events and experiences.
Procedural Memory: Learned skills, habits, and automated procedures.`, Procedural Memory: Learned skills, habits, and automated procedures.`,
raw: 'raw',
semantic: 'semantic',
episodic: 'episodic',
procedural: 'procedural',
editName: 'Edit name', editName: 'Edit name',
memory: 'Memory', memory: 'Memory',
createMemory: 'Create memory', createMemory: 'Create memory',
@ -125,8 +129,9 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
}, },
memory: { memory: {
messages: { messages: {
forgetMessageTip: 'Are you sure you want to forget?',
messageDescription: messageDescription:
'Memory retrieval is configured with Similarity threshold, Keyword similarity weight, and Top N from Advanced Settings.', 'Memory extract is configured with Prompts and Temperature from Advanced Settings.',
copied: 'Copied!', copied: 'Copied!',
contentEmbed: 'Content embed', contentEmbed: 'Content embed',
content: 'Content', content: 'Content',
@ -145,17 +150,17 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
avatar: 'Avatar', avatar: 'Avatar',
description: 'Description', description: 'Description',
memorySize: 'Memory size', memorySize: 'Memory size',
advancedSettings: 'Advanced Settings', advancedSettings: 'Advanced settings',
permission: 'Permission', permission: 'Permission',
onlyMe: 'Only Me', onlyMe: 'Only me',
team: 'Team', team: 'Team',
storageType: 'Storage Type', storageType: 'Storage type',
storageTypePlaceholder: 'Please select storage type', storageTypePlaceholder: 'Please select storage type',
forgetPolicy: 'Forget Policy', forgetPolicy: 'Forget policy',
temperature: 'Temperature', temperature: 'Temperature',
systemPrompt: 'System Prompt', systemPrompt: 'System prompt',
systemPromptPlaceholder: 'Please enter system prompt', systemPromptPlaceholder: 'Please enter system prompt',
userPrompt: 'User Prompt', userPrompt: 'User prompt',
userPromptPlaceholder: 'Please enter user prompt', userPromptPlaceholder: 'Please enter user prompt',
}, },
sideBar: { sideBar: {
@ -166,7 +171,7 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
knowledgeList: { knowledgeList: {
welcome: 'Welcome back', welcome: 'Welcome back',
description: 'Which knowledge bases will you use today?', description: 'Which knowledge bases will you use today?',
createKnowledgeBase: 'Create Dataset', createKnowledgeBase: 'Create dataset',
name: 'Name', name: 'Name',
namePlaceholder: 'Please input name.', namePlaceholder: 'Please input name.',
doc: 'Docs', doc: 'Docs',
@ -216,6 +221,10 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
deleteSettingFieldWarn: `This field will be deleted; existing metadata won't be affected.`, deleteSettingFieldWarn: `This field will be deleted; existing metadata won't be affected.`,
deleteSettingValueWarn: `This value will be deleted; existing metadata won't be affected.`, deleteSettingValueWarn: `This value will be deleted; existing metadata won't be affected.`,
}, },
redoAll: 'Clear existing chunks',
applyAutoMetadataSettings: 'Apply global auto-metadata settings',
parseFileTip: 'Are you sure to parse?',
parseFile: 'Parse file',
emptyMetadata: 'No metadata', emptyMetadata: 'No metadata',
metadataField: 'Metadata field', metadataField: 'Metadata field',
systemAttribute: 'System attribute', systemAttribute: 'System attribute',
@ -364,11 +373,11 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
autoQuestions: 'Auto-question', autoQuestions: 'Auto-question',
autoQuestionsTip: `Automatically extract N questions for each chunk to increase their ranking for queries containing those questions. You can check or update the added questions for a chunk from the chunk list. This feature will not disrupt the chunking process if an error occurs, except that it may add an empty result to the original chunk. Be aware that extra tokens will be consumed by the indexing model specified in 'Configuration'. For details, see https://ragflow.io/docs/dev/autokeyword_autoquestion.`, autoQuestionsTip: `Automatically extract N questions for each chunk to increase their ranking for queries containing those questions. You can check or update the added questions for a chunk from the chunk list. This feature will not disrupt the chunking process if an error occurs, except that it may add an empty result to the original chunk. Be aware that extra tokens will be consumed by the indexing model specified in 'Configuration'. For details, see https://ragflow.io/docs/dev/autokeyword_autoquestion.`,
redo: 'Do you want to clear the existing {{chunkNum}} chunks?', redo: 'Do you want to clear the existing {{chunkNum}} chunks?',
setMetaData: 'Set meta data', setMetaData: 'Set metadata',
pleaseInputJson: 'Please enter JSON', pleaseInputJson: 'Please enter JSON',
documentMetaTips: `<p>The meta data is in Json format(it's not searchable). It will be added into prompt for LLM if any chunks of this document are included in the prompt.</p> documentMetaTips: `<p>The metadata is in Json format(it's not searchable). It will be added into prompt for LLM if any chunks of this document are included in the prompt.</p>
<p>Examples:</p> <p>Examples:</p>
<b>The meta data is:</b><br> <b>The metadata is:</b><br>
<code> <code>
{ {
"Author": "Alex Dowson", "Author": "Alex Dowson",
@ -401,14 +410,14 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
imageTableContextWindowTip: imageTableContextWindowTip:
'Captures N tokens of text above and below the image & table to provide richer background context.', 'Captures N tokens of text above and below the image & table to provide richer background context.',
autoMetadata: 'Auto metadata', autoMetadata: 'Auto metadata',
mineruOptions: 'MinerU Options', mineruOptions: 'MinerU options',
mineruParseMethod: 'Parse Method', mineruParseMethod: 'Parse method',
mineruParseMethodTip: mineruParseMethodTip:
'Method for parsing PDF: auto (automatic detection), txt (text extraction), ocr (optical character recognition)', 'Method for parsing PDF: auto (automatic detection), txt (text extraction), ocr (optical character recognition)',
mineruFormulaEnable: 'Formula Recognition', mineruFormulaEnable: 'Formula recognition',
mineruFormulaEnableTip: mineruFormulaEnableTip:
'Enable formula recognition. Note: This may not work correctly for Cyrillic documents.', 'Enable formula recognition. Note: This may not work correctly for Cyrillic documents.',
mineruTableEnable: 'Table Recognition', mineruTableEnable: 'Table recognition',
mineruTableEnableTip: 'Enable table recognition and extraction.', mineruTableEnableTip: 'Enable table recognition and extraction.',
overlappedPercent: 'Overlapped percent(%)', overlappedPercent: 'Overlapped percent(%)',
generationScopeTip: generationScopeTip:
@ -441,11 +450,11 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
fileFilter: 'File filter', fileFilter: 'File filter',
setDefaultTip: '', setDefaultTip: '',
setDefault: 'Set as default', setDefault: 'Set as default',
eidtLinkDataPipeline: 'Edit Ingestion pipeline', editLinkDataPipeline: 'Edit ingestion pipeline',
linkPipelineSetTip: 'Manage Ingestion pipeline linkage with this dataset', linkPipelineSetTip: 'Manage ingestion pipeline linkage with this dataset',
default: 'Default', default: 'Default',
dataPipeline: 'Ingestion pipeline', dataPipeline: 'Ingestion pipeline',
linkDataPipeline: 'Link Ingestion pipeline', linkDataPipeline: 'Link ingestion pipeline',
enableAutoGenerate: 'Enable auto generate', enableAutoGenerate: 'Enable auto generate',
teamPlaceholder: 'Please select a team.', teamPlaceholder: 'Please select a team.',
dataFlowPlaceholder: 'Please select a pipeline.', dataFlowPlaceholder: 'Please select a pipeline.',
@ -455,7 +464,7 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
manualSetup: 'Choose pipeline', manualSetup: 'Choose pipeline',
builtIn: 'Built-in', builtIn: 'Built-in',
titleDescription: titleDescription:
'Update your knowledge base configuration here, particularly the chunking method.', 'Update your memory configuration here, particularly the LLM and prompts.',
name: 'Knowledge base name', name: 'Knowledge base name',
photo: 'Knowledge base photo', photo: 'Knowledge base photo',
photoTip: 'You can upload a file with 4 MB', photoTip: 'You can upload a file with 4 MB',
@ -756,8 +765,8 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
maxTokens: 'Max tokens', maxTokens: 'Max tokens',
maxTokensMessage: 'Max tokens is required', maxTokensMessage: 'Max tokens is required',
maxTokensTip: `This sets the maximum length of the model's output, measured in the number of tokens (words or pieces of words). Defaults to 512. If disabled, you lift the maximum token limit, allowing the model to determine the number of tokens in its responses.`, maxTokensTip: `This sets the maximum length of the model's output, measured in the number of tokens (words or pieces of words). Defaults to 512. If disabled, you lift the maximum token limit, allowing the model to determine the number of tokens in its responses.`,
maxTokensInvalidMessage: 'Please enter a valid number for Max Tokens.', maxTokensInvalidMessage: 'Please enter a valid number for Max tokens.',
maxTokensMinMessage: 'Max Tokens cannot be less than 0.', maxTokensMinMessage: 'Max tokens cannot be less than 0.',
quote: 'Show quote', quote: 'Show quote',
quoteTip: 'Whether to display the original text as a reference.', quoteTip: 'Whether to display the original text as a reference.',
selfRag: 'Self-RAG', selfRag: 'Self-RAG',
@ -878,7 +887,7 @@ Example: general/v2/`,
Example: https://fsn1.your-objectstorage.com`, Example: https://fsn1.your-objectstorage.com`,
S3CompatibleAddressingStyleTip: `Required for S3 compatible Storage Box. Specify the S3-compatible addressing style. S3CompatibleAddressingStyleTip: `Required for S3 compatible Storage Box. Specify the S3-compatible addressing style.
Example: Virtual Hosted Style`, Example: Virtual Hosted Style`,
addDataSourceModalTital: 'Create your {{name}} connector', addDataSourceModalTitle: 'Create your {{name}} connector',
deleteSourceModalTitle: 'Delete data source', deleteSourceModalTitle: 'Delete data source',
deleteSourceModalContent: ` deleteSourceModalContent: `
<p>Are you sure you want to delete this data source link?</p>`, <p>Are you sure you want to delete this data source link?</p>`,
@ -970,10 +979,10 @@ Example: Virtual Hosted Style`,
avatarTip: 'This will be displayed on your profile.', avatarTip: 'This will be displayed on your profile.',
profileDescription: 'Update your photo and personal details here.', profileDescription: 'Update your photo and personal details here.',
maxTokens: 'Max tokens', maxTokens: 'Max tokens',
maxTokensMessage: 'Max Tokens is required', maxTokensMessage: 'Max tokens is required',
maxTokensTip: `This sets the maximum length of the model's output, measured in the number of tokens (words or pieces of words). Defaults to 512. If disabled, you lift the maximum token limit, allowing the model to determine the number of tokens in its responses.`, maxTokensTip: `This sets the maximum length of the model's output, measured in the number of tokens (words or pieces of words). Defaults to 512. If disabled, you lift the maximum token limit, allowing the model to determine the number of tokens in its responses.`,
maxTokensInvalidMessage: 'Please enter a valid number for Max Tokens.', maxTokensInvalidMessage: 'Please enter a valid number for Max tokens.',
maxTokensMinMessage: 'Max Tokens cannot be less than 0.', maxTokensMinMessage: 'Max tokens cannot be less than 0.',
password: 'Password', password: 'Password',
passwordDescription: passwordDescription:
'Please enter your current password to change your password.', 'Please enter your current password to change your password.',
@ -1322,12 +1331,12 @@ Example: Virtual Hosted Style`,
search: 'Search', search: 'Search',
communication: 'Communication', communication: 'Communication',
developer: 'Developer', developer: 'Developer',
typeCommandOrsearch: 'Type a command or search...', typeCommandORsearch: 'Type a command or search...',
builtIn: 'Built-in', builtIn: 'Built-in',
ExceptionDefaultValue: 'Exception default value', ExceptionDefaultValue: 'Exception default value',
exceptionMethod: 'Exception method', exceptionMethod: 'Exception method',
maxRounds: 'Max reflection rounds', maxRounds: 'Max reflection rounds',
delayEfterError: 'Delay after error', delayAfterError: 'Delay after error',
maxRetries: 'Max retry rounds', maxRetries: 'Max retry rounds',
advancedSettings: 'Advanced settings', advancedSettings: 'Advanced settings',
addTools: 'Add tools', addTools: 'Add tools',
@ -1834,7 +1843,7 @@ This delimiter is used to split the input text into several text pieces echo of
}`, }`,
datatype: 'MINE type of the HTTP request', datatype: 'MINE type of the HTTP request',
insertVariableTip: `Enter / Insert variables`, insertVariableTip: `Enter / Insert variables`,
historyversion: 'Version history', historyVersion: 'Version history',
version: { version: {
created: 'Created', created: 'Created',
details: 'Version details', details: 'Version details',
@ -2169,7 +2178,7 @@ Important structured information may include: names, dates, locations, events, k
agentStatus: 'Agent status:', agentStatus: 'Agent status:',
}, },
saveToMemory: 'Save to memory', saveToMemory: 'Save to memory',
memory: 'Memory', retrievalFrom: 'Retrieval from',
}, },
llmTools: { llmTools: {
bad_calculator: { bad_calculator: {
@ -2247,7 +2256,7 @@ Important structured information may include: names, dates, locations, events, k
dataflowParser: { dataflowParser: {
result: 'Result', result: 'Result',
parseSummary: 'Parse summary', parseSummary: 'Parse summary',
parseSummaryTip: 'Parserdeepdoc', parseSummaryTip: 'ParserDeepDoc',
parserMethod: 'Parser method', parserMethod: 'Parser method',
outputFormat: 'Output format', outputFormat: 'Output format',
rerunFromCurrentStep: 'Rerun from current step', rerunFromCurrentStep: 'Rerun from current step',
@ -2270,10 +2279,10 @@ Important structured information may include: names, dates, locations, events, k
<p>To keep them, please click Rerun to re-run the current stage.</p> `, <p>To keep them, please click Rerun to re-run the current stage.</p> `,
changeStepModalConfirmText: 'Switch Anyway', changeStepModalConfirmText: 'Switch Anyway',
changeStepModalCancelText: 'Cancel', changeStepModalCancelText: 'Cancel',
unlinkPipelineModalTitle: 'Unlink Ingestion pipeline', unlinkPipelineModalTitle: 'Unlink ingestion pipeline',
unlinkPipelineModalConfirmText: 'Unlink', unlinkPipelineModalConfirmText: 'Unlink',
unlinkPipelineModalContent: ` unlinkPipelineModalContent: `
<p>Once unlinked, this Dataset will no longer be connected to the current Ingestion pipeline.</p> <p>Once unlinked, this Dataset will no longer be connected to the current ingestion pipeline.</p>
<p>Files that are already being parsed will continue until completion</p> <p>Files that are already being parsed will continue until completion</p>
<p>Files that are not yet parsed will no longer be processed</p> <br/> <p>Files that are not yet parsed will no longer be processed</p> <br/>
<p>Are you sure you want to proceed?</p> `, <p>Are you sure you want to proceed?</p> `,
@ -2284,7 +2293,7 @@ Important structured information may include: names, dates, locations, events, k
}, },
datasetOverview: { datasetOverview: {
downloadTip: 'Files being downloaded from data sources. ', downloadTip: 'Files being downloaded from data sources. ',
processingTip: 'Files being processed by Ingestion pipeline.', processingTip: 'Files being processed by ingestion pipeline.',
totalFiles: 'Total files', totalFiles: 'Total files',
downloading: 'Downloading', downloading: 'Downloading',
downloadSuccessTip: 'Total successful downloads', downloadSuccessTip: 'Total successful downloads',

View File

@ -1191,7 +1191,7 @@ export default {
}`, }`,
datatype: 'Type MIME de la requête HTTP', datatype: 'Type MIME de la requête HTTP',
insertVariableTip: `Entrer / Insérer des variables`, insertVariableTip: `Entrer / Insérer des variables`,
historyversion: 'Historique des versions', historyVersion: 'Historique des versions',
version: { version: {
created: 'Créé', created: 'Créé',
details: 'Détails de la version', details: 'Détails de la version',

View File

@ -325,7 +325,7 @@ export default {
fileFilter: 'Filtro file', fileFilter: 'Filtro file',
setDefaultTip: '', setDefaultTip: '',
setDefault: 'Imposta come predefinito', setDefault: 'Imposta come predefinito',
eidtLinkDataPipeline: 'Modifica pipeline di ingestione', editLinkDataPipeline: 'Modifica pipeline di ingestione',
linkPipelineSetTip: linkPipelineSetTip:
'Gestisci il collegamento della pipeline di ingestione con questo dataset', 'Gestisci il collegamento della pipeline di ingestione con questo dataset',
default: 'Predefinito', default: 'Predefinito',

View File

@ -311,7 +311,7 @@ export default {
fileFilter: 'Фильтр файлов', fileFilter: 'Фильтр файлов',
setDefaultTip: '', setDefaultTip: '',
setDefault: 'Установить по умолчанию', setDefault: 'Установить по умолчанию',
eidtLinkDataPipeline: 'Редактировать пайплайн обработки', editLinkDataPipeline: 'Редактировать пайплайн обработки',
linkPipelineSetTip: linkPipelineSetTip:
'Управление связью пайплайна обработки с этим набором данных', 'Управление связью пайплайна обработки с этим набором данных',
default: 'По умолчанию', default: 'По умолчанию',
@ -722,7 +722,7 @@ export default {
Пример: https://fsn1.your-objectstorage.com`, Пример: https://fsn1.your-objectstorage.com`,
S3CompatibleAddressingStyleTip: `Требуется для S3 совместимого Storage Box. Укажите стиль адресации, совместимый с S3. S3CompatibleAddressingStyleTip: `Требуется для S3 совместимого Storage Box. Укажите стиль адресации, совместимый с S3.
Пример: Virtual Hosted Style`, Пример: Virtual Hosted Style`,
addDataSourceModalTital: 'Создайте ваш коннектор {{name}}', addDataSourceModalTitle: 'Создайте ваш коннектор {{name}}',
deleteSourceModalTitle: 'Удалить источник данных', deleteSourceModalTitle: 'Удалить источник данных',
deleteSourceModalContent: ` deleteSourceModalContent: `
<p>Вы уверены, что хотите удалить эту ссылку на источник данных?</p>`, <p>Вы уверены, что хотите удалить эту ссылку на источник данных?</p>`,
@ -1133,12 +1133,12 @@ export default {
search: 'Поиск', search: 'Поиск',
communication: 'Коммуникация', communication: 'Коммуникация',
developer: 'Разработчик', developer: 'Разработчик',
typeCommandOrsearch: 'Введите команду или поиск...', typeCommandORsearch: 'Введите команду или поиск...',
builtIn: 'Встроенный', builtIn: 'Встроенный',
ExceptionDefaultValue: 'Значение по умолчанию при исключении', ExceptionDefaultValue: 'Значение по умолчанию при исключении',
exceptionMethod: 'Метод обработки исключений', exceptionMethod: 'Метод обработки исключений',
maxRounds: 'Макс. раундов рефлексии', maxRounds: 'Макс. раундов рефлексии',
delayEfterError: 'Задержка после ошибки', delayAfterError: 'Задержка после ошибки',
maxRetries: 'Макс. попыток повтора', maxRetries: 'Макс. попыток повтора',
advancedSettings: 'Расширенные настройки', advancedSettings: 'Расширенные настройки',
addTools: 'Добавить инструменты', addTools: 'Добавить инструменты',
@ -1637,7 +1637,7 @@ export default {
}`, }`,
datatype: 'MIME тип HTTP запроса', datatype: 'MIME тип HTTP запроса',
insertVariableTip: `Введите / Вставьте переменные`, insertVariableTip: `Введите / Вставьте переменные`,
historyversion: 'История версий', historyVersion: 'История версий',
version: { version: {
created: 'Создано', created: 'Создано',
details: 'Детали версии', details: 'Детали версии',

View File

@ -93,17 +93,21 @@ export default {
search: '搜索', search: '搜索',
welcome: '欢迎来到', welcome: '欢迎来到',
dataset: '知识库', dataset: '知识库',
Memories: '记忆', memories: '记忆',
}, },
memories: { memories: {
llmTooltip: '分析对话内容,提取关键信息,并生成结构化的记忆摘要。', llmTooltip: '分析对话内容,提取关键信息,并生成结构化的记忆摘要。',
embeddingModelTooltip: embeddingModelTooltip:
'将文本转换为数值向量,用于语义相似度搜索和记忆检索。', '将文本转换为数值向量,用于语义相似度搜索和记忆检索。',
embeddingModelError: '记忆类型为必填项,且"原始"类型不可删除。', embeddingModelError: '记忆类型为必填项,且"row"类型不可删除。',
memoryTypeTooltip: `原始: 用户与代理之间的原始对话内容(默认必需)。 memoryTypeTooltip: `原始: 用户与代理之间的原始对话内容(默认必需)。
语义记忆: 关于用户和世界的通用知识和事实。 语义记忆: 关于用户和世界的通用知识和事实。
情景记忆: 带时间戳的特定事件和经历记录。 情景记忆: 带时间戳的特定事件和经历记录。
程序记忆: 学习的技能、习惯和自动化程序。`, 程序记忆: 学习的技能、习惯和自动化程序。`,
raw: '原始',
semantic: '语义',
episodic: '情景',
procedural: '程序',
editName: '编辑名称', editName: '编辑名称',
memory: '记忆', memory: '记忆',
createMemory: '创建记忆', createMemory: '创建记忆',
@ -117,8 +121,8 @@ export default {
}, },
memory: { memory: {
messages: { messages: {
messageDescription: forgetMessageTip: '确定遗忘吗?',
'记忆检索已在高级设置中配置相似度阈值、关键词相似度权重和前N个结果。', messageDescription: '记忆提取使用高级设置中的提示词和温度值进行配置。',
copied: '已复制!', copied: '已复制!',
contentEmbed: '内容嵌入', contentEmbed: '内容嵌入',
content: '内容', content: '内容',
@ -201,6 +205,10 @@ export default {
deleteSettingFieldWarn: `此字段将被删除;现有元数据不会受到影响。`, deleteSettingFieldWarn: `此字段将被删除;现有元数据不会受到影响。`,
deleteSettingValueWarn: `此值将被删除;现有元数据不会受到影响。`, deleteSettingValueWarn: `此值将被删除;现有元数据不会受到影响。`,
}, },
redoAll: '清除现有分块',
applyAutoMetadataSettings: '应用全局自动元数据设置',
parseFileTip: '您确定要解析吗?',
parseFile: '解析文件',
emptyMetadata: '无元数据', emptyMetadata: '无元数据',
localUpload: '本地上传', localUpload: '本地上传',
fileSize: '文件大小', fileSize: '文件大小',
@ -405,7 +413,7 @@ export default {
fileFilter: '正则匹配表达式', fileFilter: '正则匹配表达式',
setDefaultTip: '', setDefaultTip: '',
setDefault: '设置默认', setDefault: '设置默认',
eidtLinkDataPipeline: '编辑pipeline', editLinkDataPipeline: '编辑pipeline',
linkPipelineSetTip: '管理与此数据集的数据管道链接', linkPipelineSetTip: '管理与此数据集的数据管道链接',
default: '默认', default: '默认',
dataPipeline: 'Ingestion pipeline', dataPipeline: 'Ingestion pipeline',
@ -418,7 +426,7 @@ export default {
parseType: '解析方法', parseType: '解析方法',
manualSetup: '选择pipeline', manualSetup: '选择pipeline',
builtIn: '内置', builtIn: '内置',
titleDescription: '在这里更新您的知识库详细信息,尤其是切片方法。', titleDescription: '在这里更新您的记忆配置,特别是大语言模型和提示词。',
name: '知识库名称', name: '知识库名称',
photo: '知识库图片', photo: '知识库图片',
photoTip: '你可以上传4MB的文件', photoTip: '你可以上传4MB的文件',
@ -820,7 +828,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
'可选指定空间键以限制同步到特定空间。留空则同步所有可访问的空间。多个空间请用逗号分隔例如DEV,DOCS,HR', '可选指定空间键以限制同步到特定空间。留空则同步所有可访问的空间。多个空间请用逗号分隔例如DEV,DOCS,HR',
s3PrefixTip: `指定 S3 存储桶内的文件夹路径,用于读取文件。 s3PrefixTip: `指定 S3 存储桶内的文件夹路径,用于读取文件。
示例general/v2/`, 示例general/v2/`,
addDataSourceModalTital: '创建你的 {{name}} 链接', addDataSourceModalTitle: '创建你的 {{name}} 链接',
deleteSourceModalTitle: '删除数据源链接', deleteSourceModalTitle: '删除数据源链接',
deleteSourceModalContent: ` deleteSourceModalContent: `
<p>您确定要删除此数据源链接吗?</p>`, <p>您确定要删除此数据源链接吗?</p>`,
@ -1202,14 +1210,14 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
search: '搜索', search: '搜索',
communication: '通信', communication: '通信',
developer: '开发者', developer: '开发者',
typeCommandOrsearch: '输入命令或或搜索...', typeCommandORsearch: '输入命令或或搜索...',
builtIn: '内置', builtIn: '内置',
goto: '异常分支', goto: '异常分支',
comment: '默认值', comment: '默认值',
ExceptionDefaultValue: '异常处理默认值', ExceptionDefaultValue: '异常处理默认值',
exceptionMethod: '异常处理方法', exceptionMethod: '异常处理方法',
maxRounds: '最大反思轮数', maxRounds: '最大反思轮数',
delayEfterError: '错误后延迟', delayAfterError: '错误后延迟',
maxRetries: '最大重试轮数', maxRetries: '最大重试轮数',
advancedSettings: '高级设置', advancedSettings: '高级设置',
addTools: '添加工具', addTools: '添加工具',
@ -1246,7 +1254,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
dialog: '对话', dialog: '对话',
flow: '工作流', flow: '工作流',
noMoreData: '没有更多数据了', noMoreData: '没有更多数据了',
historyversion: '历史版本', historyVersion: '历史版本',
version: { version: {
details: '版本详情', details: '版本详情',
download: '下载', download: '下载',
@ -1970,7 +1978,7 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`,
agentStatus: '智能体状态:', agentStatus: '智能体状态:',
}, },
saveToMemory: '保存到Memory', saveToMemory: '保存到Memory',
memory: 'Memory', retrievalFrom: '检索来源',
}, },
footer: { footer: {
profile: 'All rights reserved @ React', profile: 'All rights reserved @ React',

View File

@ -1,13 +1,16 @@
import { NodeCollapsible } from '@/components/collapse'; import { NodeCollapsible } from '@/components/collapse';
import { RAGFlowAvatar } from '@/components/ragflow-avatar'; import { RAGFlowAvatar } from '@/components/ragflow-avatar';
import { useFetchKnowledgeList } from '@/hooks/use-knowledge-request'; import { useFetchKnowledgeList } from '@/hooks/use-knowledge-request';
import { IRetrievalNode } from '@/interfaces/database/flow'; import { useFetchAllMemoryList } from '@/hooks/use-memory-request';
import { BaseNode } from '@/interfaces/database/flow';
import { NodeProps, Position } from '@xyflow/react'; import { NodeProps, Position } from '@xyflow/react';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react'; import { memo } from 'react';
import { NodeHandleId } from '../../constant'; import { NodeHandleId, RetrievalFrom } from '../../constant';
import { RetrievalFormSchemaType } from '../../form/retrieval-form/next';
import { useGetVariableLabelOrTypeByValue } from '../../hooks/use-get-begin-query'; import { useGetVariableLabelOrTypeByValue } from '../../hooks/use-get-begin-query';
import { LabelCard } from './card';
import { CommonHandle, LeftEndHandle } from './handle'; import { CommonHandle, LeftEndHandle } from './handle';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';
@ -19,12 +22,17 @@ function InnerRetrievalNode({
data, data,
isConnectable = true, isConnectable = true,
selected, selected,
}: NodeProps<IRetrievalNode>) { }: NodeProps<BaseNode<RetrievalFormSchemaType>>) {
const knowledgeBaseIds: string[] = get(data, 'form.kb_ids', []); const knowledgeBaseIds: string[] = get(data, 'form.kb_ids', []);
const memoryIds: string[] = get(data, 'form.memory_ids', []);
const { list: knowledgeList } = useFetchKnowledgeList(true); const { list: knowledgeList } = useFetchKnowledgeList(true);
const { getLabel } = useGetVariableLabelOrTypeByValue({ nodeId: id }); const { getLabel } = useGetVariableLabelOrTypeByValue({ nodeId: id });
const isMemory = data.form?.retrieval_from === RetrievalFrom.Memory;
const memoryList = useFetchAllMemoryList();
return ( return (
<ToolBar selected={selected} id={id} label={data.label}> <ToolBar selected={selected} id={id} label={data.label}>
<NodeWrapper selected={selected} id={id}> <NodeWrapper selected={selected} id={id}>
@ -45,8 +53,22 @@ function InnerRetrievalNode({
[styles.nodeHeader]: knowledgeBaseIds.length > 0, [styles.nodeHeader]: knowledgeBaseIds.length > 0,
})} })}
></NodeHeader> ></NodeHeader>
<NodeCollapsible items={knowledgeBaseIds}> <NodeCollapsible items={isMemory ? memoryIds : knowledgeBaseIds}>
{(id) => { {(id) => {
if (isMemory) {
const item = memoryList.data?.find((y) => id === y.id);
return (
<LabelCard key={id} className="flex items-center gap-1.5">
<RAGFlowAvatar
className="size-6 rounded-lg"
avatar={item?.avatar ?? ''}
name={item ? item?.name : id}
/>
<span className="flex-1 truncate"> {item?.name}</span>
</LabelCard>
);
}
const item = knowledgeList.find((y) => id === y.id); const item = knowledgeList.find((y) => id === y.id);
const label = getLabel(id); const label = getLabel(id);

View File

@ -79,6 +79,11 @@ export const DataOperationsOperatorOptions = [
export const SwitchElseTo = 'end_cpn_ids'; export const SwitchElseTo = 'end_cpn_ids';
export enum RetrievalFrom {
Dataset = 'dataset',
Memory = 'memory',
}
export const initialRetrievalValues = { export const initialRetrievalValues = {
query: AgentGlobalsSysQueryWithBrace, query: AgentGlobalsSysQueryWithBrace,
top_n: 8, top_n: 8,
@ -91,6 +96,7 @@ export const initialRetrievalValues = {
use_kg: false, use_kg: false,
toc_enhance: false, toc_enhance: false,
cross_languages: [], cross_languages: [],
retrieval_from: RetrievalFrom.Dataset,
outputs: { outputs: {
formalized_content: { formalized_content: {
type: 'string', type: 'string',

View File

@ -242,7 +242,7 @@ function AgentForm({ node }: INextOperatorForm) {
name={`delay_after_error`} name={`delay_after_error`}
render={({ field }) => ( render={({ field }) => (
<FormItem className="flex-1"> <FormItem className="flex-1">
<FormLabel>{t('flow.delayEfterError')}</FormLabel> <FormLabel>{t('flow.delayAfterError')}</FormLabel>
<FormControl> <FormControl>
<NumberInput {...field} max={5} step={0.1}></NumberInput> <NumberInput {...field} max={5} step={0.1}></NumberInput>
</FormControl> </FormControl>

View File

@ -115,7 +115,7 @@ export function ToolCommand({ value, onChange }: ToolCommandProps) {
return ( return (
<Command> <Command>
<CommandInput placeholder={t('flow.typeCommandOrsearch')} /> <CommandInput placeholder={t('flow.typeCommandORsearch')} />
<CommandList> <CommandList>
<CommandEmpty>No results found.</CommandEmpty> <CommandEmpty>No results found.</CommandEmpty>
{Menus.map((x) => ( {Menus.map((x) => (

View File

@ -20,14 +20,20 @@ import {
FormLabel, FormLabel,
FormMessage, FormMessage,
} from '@/components/ui/form'; } from '@/components/ui/form';
import { Radio } from '@/components/ui/radio';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item'; import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useForm, useFormContext } from 'react-hook-form'; import {
UseFormReturn,
useForm,
useFormContext,
useWatch,
} from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { z } from 'zod'; import { z } from 'zod';
import { initialRetrievalValues } from '../../constant'; import { RetrievalFrom, initialRetrievalValues } from '../../constant';
import { useWatchFormChange } from '../../hooks/use-watch-form-change'; import { useWatchFormChange } from '../../hooks/use-watch-form-change';
import { INextOperatorForm } from '../../interface'; import { INextOperatorForm } from '../../interface';
import { FormWrapper } from '../components/form-wrapper'; import { FormWrapper } from '../components/form-wrapper';
@ -48,6 +54,7 @@ export const RetrievalPartialSchema = {
toc_enhance: z.boolean(), toc_enhance: z.boolean(),
...MetadataFilterSchema, ...MetadataFilterSchema,
memory_ids: z.array(z.string()).optional(), memory_ids: z.array(z.string()).optional(),
retrieval_from: z.string(),
}; };
export const FormSchema = z.object({ export const FormSchema = z.object({
@ -55,6 +62,44 @@ export const FormSchema = z.object({
...RetrievalPartialSchema, ...RetrievalPartialSchema,
}); });
export type RetrievalFormSchemaType = z.infer<typeof FormSchema>;
export function MemoryDatasetForm() {
const { t } = useTranslation();
const form = useFormContext();
const retrievalFrom = useWatch({
control: form.control,
name: 'retrieval_from',
});
return (
<>
<RAGFlowFormItem name="retrieval_from" label={t('flow.retrievalFrom')}>
<Radio.Group>
<Radio value={RetrievalFrom.Dataset}>
{t('knowledgeDetails.dataset')}
</Radio>
<Radio value={RetrievalFrom.Memory}>{t('header.memories')}</Radio>
</Radio.Group>
</RAGFlowFormItem>
{retrievalFrom === RetrievalFrom.Memory ? (
<MemoriesFormField label={t('header.memories')}></MemoriesFormField>
) : (
<KnowledgeBaseFormField showVariable></KnowledgeBaseFormField>
)}
</>
);
}
export function useHideKnowledgeGraphField(form: UseFormReturn<any>) {
const retrievalFrom = useWatch({
control: form.control,
name: 'retrieval_from',
});
return retrievalFrom === RetrievalFrom.Memory;
}
export function EmptyResponseField() { export function EmptyResponseField() {
const { t } = useTranslation(); const { t } = useTranslation();
const form = useFormContext(); const form = useFormContext();
@ -106,6 +151,8 @@ function RetrievalForm({ node }: INextOperatorForm) {
resolver: zodResolver(FormSchema), resolver: zodResolver(FormSchema),
}); });
const hideKnowledgeGraphField = useHideKnowledgeGraphField(form);
useWatchFormChange(node?.id, form); useWatchFormChange(node?.id, form);
return ( return (
@ -114,8 +161,7 @@ function RetrievalForm({ node }: INextOperatorForm) {
<RAGFlowFormItem name="query" label={t('flow.query')}> <RAGFlowFormItem name="query" label={t('flow.query')}>
<PromptEditor></PromptEditor> <PromptEditor></PromptEditor>
</RAGFlowFormItem> </RAGFlowFormItem>
<KnowledgeBaseFormField showVariable></KnowledgeBaseFormField> <MemoryDatasetForm></MemoryDatasetForm>
<MemoriesFormField label={t('flow.memory')}></MemoriesFormField>
<Collapse title={<div>{t('flow.advancedSettings')}</div>}> <Collapse title={<div>{t('flow.advancedSettings')}</div>}>
<FormContainer> <FormContainer>
<SimilaritySliderFormField <SimilaritySliderFormField
@ -123,12 +169,20 @@ function RetrievalForm({ node }: INextOperatorForm) {
isTooltipShown isTooltipShown
></SimilaritySliderFormField> ></SimilaritySliderFormField>
<TopNFormField></TopNFormField> <TopNFormField></TopNFormField>
{hideKnowledgeGraphField || (
<>
<RerankFormFields></RerankFormFields> <RerankFormFields></RerankFormFields>
<MetadataFilter canReference></MetadataFilter> <MetadataFilter canReference></MetadataFilter>
</>
)}
<EmptyResponseField></EmptyResponseField> <EmptyResponseField></EmptyResponseField>
{hideKnowledgeGraphField || (
<>
<CrossLanguageFormField name="cross_languages"></CrossLanguageFormField> <CrossLanguageFormField name="cross_languages"></CrossLanguageFormField>
<UseKnowledgeGraphFormField name="use_kg"></UseKnowledgeGraphFormField> <UseKnowledgeGraphFormField name="use_kg"></UseKnowledgeGraphFormField>
<TOCEnhanceFormField name="toc_enhance"></TOCEnhanceFormField> <TOCEnhanceFormField name="toc_enhance"></TOCEnhanceFormField>
</>
)}
</FormContainer> </FormContainer>
</Collapse> </Collapse>
<Output list={outputList}></Output> <Output list={outputList}></Output>

View File

@ -1,8 +1,6 @@
import { Collapse } from '@/components/collapse'; import { Collapse } from '@/components/collapse';
import { CrossLanguageFormField } from '@/components/cross-language-form-field'; import { CrossLanguageFormField } from '@/components/cross-language-form-field';
import { FormContainer } from '@/components/form-container'; import { FormContainer } from '@/components/form-container';
import { KnowledgeBaseFormField } from '@/components/knowledge-base-item';
import { MemoriesFormField } from '@/components/memories-form-field';
import { MetadataFilter } from '@/components/metadata-filter'; import { MetadataFilter } from '@/components/metadata-filter';
import { RerankFormFields } from '@/components/rerank'; import { RerankFormFields } from '@/components/rerank';
import { SimilaritySliderFormField } from '@/components/similarity-slider'; import { SimilaritySliderFormField } from '@/components/similarity-slider';
@ -18,7 +16,9 @@ import { DescriptionField } from '../../components/description-field';
import { FormWrapper } from '../../components/form-wrapper'; import { FormWrapper } from '../../components/form-wrapper';
import { import {
EmptyResponseField, EmptyResponseField,
MemoryDatasetForm,
RetrievalPartialSchema, RetrievalPartialSchema,
useHideKnowledgeGraphField,
} from '../../retrieval-form/next'; } from '../../retrieval-form/next';
import { useValues } from '../use-values'; import { useValues } from '../use-values';
import { useWatchFormChange } from '../use-watch-change'; import { useWatchFormChange } from '../use-watch-change';
@ -36,14 +36,15 @@ const RetrievalForm = () => {
resolver: zodResolver(FormSchema), resolver: zodResolver(FormSchema),
}); });
const hideKnowledgeGraphField = useHideKnowledgeGraphField(form);
useWatchFormChange(form); useWatchFormChange(form);
return ( return (
<Form {...form}> <Form {...form}>
<FormWrapper> <FormWrapper>
<DescriptionField></DescriptionField> <DescriptionField></DescriptionField>
<KnowledgeBaseFormField showVariable></KnowledgeBaseFormField> <MemoryDatasetForm></MemoryDatasetForm>
<MemoriesFormField label={t('flow.memory')}></MemoriesFormField>
<Collapse title={<div>{t('flow.advancedSettings')}</div>}> <Collapse title={<div>{t('flow.advancedSettings')}</div>}>
<FormContainer> <FormContainer>
<SimilaritySliderFormField <SimilaritySliderFormField
@ -51,12 +52,21 @@ const RetrievalForm = () => {
isTooltipShown isTooltipShown
></SimilaritySliderFormField> ></SimilaritySliderFormField>
<TopNFormField></TopNFormField> <TopNFormField></TopNFormField>
{hideKnowledgeGraphField || (
<>
<RerankFormFields></RerankFormFields> <RerankFormFields></RerankFormFields>
<MetadataFilter canReference></MetadataFilter> <MetadataFilter canReference></MetadataFilter>
</>
)}
<EmptyResponseField></EmptyResponseField> <EmptyResponseField></EmptyResponseField>
{hideKnowledgeGraphField || (
<>
<CrossLanguageFormField name="cross_languages"></CrossLanguageFormField> <CrossLanguageFormField name="cross_languages"></CrossLanguageFormField>
<UseKnowledgeGraphFormField name="use_kg"></UseKnowledgeGraphFormField> <UseKnowledgeGraphFormField name="use_kg"></UseKnowledgeGraphFormField>
<TOCEnhanceFormField name="toc_enhance"></TOCEnhanceFormField> <TOCEnhanceFormField name="toc_enhance"></TOCEnhanceFormField>
</>
)}
</FormContainer> </FormContainer>
</Collapse> </Collapse>
</FormWrapper> </FormWrapper>

View File

@ -246,7 +246,7 @@ export default function Agent() {
</Button> </Button>
<Button variant={'secondary'} onClick={showVersionDialog}> <Button variant={'secondary'} onClick={showVersionDialog}>
<History /> <History />
{t('flow.historyversion')} {t('flow.historyVersion')}
</Button> </Button>
{isPipeline || ( {isPipeline || (
<Button <Button

View File

@ -61,7 +61,7 @@ export function VersionDialog({
<DialogContent className="max-w-[60vw]"> <DialogContent className="max-w-[60vw]">
<DialogHeader> <DialogHeader>
<DialogTitle className="text-base"> <DialogTitle className="text-base">
{t('flow.historyversion')} {t('flow.historyVersion')}
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<section className="flex gap-8 relative"> <section className="flex gap-8 relative">

View File

@ -52,7 +52,7 @@ const LinkDataPipelineModal = ({
title={ title={
!isEdit !isEdit
? t('knowledgeConfiguration.linkDataPipeline') ? t('knowledgeConfiguration.linkDataPipeline')
: t('knowledgeConfiguration.eidtLinkDataPipeline') : t('knowledgeConfiguration.editLinkDataPipeline')
} }
open={open} open={open}
onOpenChange={setOpen} onOpenChange={setOpen}

View File

@ -23,6 +23,7 @@ import {
import { ManageMetadataModal } from '../components/metedata/manage-modal'; import { ManageMetadataModal } from '../components/metedata/manage-modal';
import { DatasetTable } from './dataset-table'; import { DatasetTable } from './dataset-table';
import Generate from './generate-button/generate'; import Generate from './generate-button/generate';
import { ReparseDialog } from './reparse-dialog';
import { useBulkOperateDataset } from './use-bulk-operate-dataset'; import { useBulkOperateDataset } from './use-bulk-operate-dataset';
import { useCreateEmptyDocument } from './use-create-empty-document'; import { useCreateEmptyDocument } from './use-create-empty-document';
import { useSelectDatasetFilters } from './use-select-filters'; import { useSelectDatasetFilters } from './use-select-filters';
@ -77,7 +78,12 @@ export default function Dataset() {
const { rowSelection, rowSelectionIsEmpty, setRowSelection, selectedCount } = const { rowSelection, rowSelectionIsEmpty, setRowSelection, selectedCount } =
useRowSelection(); useRowSelection();
const { list } = useBulkOperateDataset({ const {
list,
visible: reparseDialogVisible,
hideModal: hideReparseDialogModal,
handleRunClick: handleOperationIconClick,
} = useBulkOperateDataset({
documents, documents,
rowSelection, rowSelection,
setRowSelection, setRowSelection,
@ -207,6 +213,16 @@ export default function Dataset() {
otherData={metadataConfig.record} otherData={metadataConfig.record}
/> />
)} )}
{reparseDialogVisible && (
<ReparseDialog
// hidden={isZeroChunk || isRunning}
hidden={false}
handleOperationIconClick={handleOperationIconClick}
chunk_num={0}
visible={reparseDialogVisible}
hideModal={hideReparseDialogModal}
></ReparseDialog>
)}
</section> </section>
</> </>
); );

View File

@ -1,4 +1,3 @@
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
import { IconFontFill } from '@/components/icon-font'; import { IconFontFill } from '@/components/icon-font';
import { import {
DropdownMenu, DropdownMenu,
@ -19,6 +18,7 @@ import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { DocumentType, RunningStatus } from './constant'; import { DocumentType, RunningStatus } from './constant';
import { ParsingCard } from './parsing-card'; import { ParsingCard } from './parsing-card';
import { ReparseDialog } from './reparse-dialog';
import { UseChangeDocumentParserShowType } from './use-change-document-parser'; import { UseChangeDocumentParserShowType } from './use-change-document-parser';
import { useHandleRunDocumentByIds } from './use-run-document'; import { useHandleRunDocumentByIds } from './use-run-document';
import { UseSaveMetaShowType } from './use-save-meta'; import { UseSaveMetaShowType } from './use-save-meta';
@ -63,14 +63,20 @@ export function ParsingStatusCell({
} = record; } = record;
const operationIcon = IconMap[run]; const operationIcon = IconMap[run];
const p = Number((progress * 100).toFixed(2)); const p = Number((progress * 100).toFixed(2));
const { handleRunDocumentByIds } = useHandleRunDocumentByIds(id); const {
handleRunDocumentByIds,
visible: reparseDialogVisible,
showModal: showReparseDialogModal,
hideModal: hideReparseDialogModal,
} = useHandleRunDocumentByIds(id);
const isRunning = isParserRunning(run); const isRunning = isParserRunning(run);
const isZeroChunk = chunk_num === 0; const isZeroChunk = chunk_num === 0;
const handleOperationIconClick = const handleOperationIconClick = (option: {
(shouldDelete: boolean = false) => delete: boolean;
() => { apply_kb: boolean;
handleRunDocumentByIds(record.id, isRunning, shouldDelete); }) => {
handleRunDocumentByIds(record.id, isRunning, option);
}; };
const handleShowChangeParserModal = useCallback(() => { const handleShowChangeParserModal = useCallback(() => {
@ -129,23 +135,20 @@ export function ParsingStatusCell({
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Separator orientation="vertical" className="h-2.5" /> <Separator orientation="vertical" className="h-2.5" />
{!isParserRunning(run) && ( {!isParserRunning(run) && (
<ConfirmDeleteDialog // <ReparseDialog
title={t(`knowledgeDetails.redo`, { chunkNum: chunk_num })} // hidden={isZeroChunk || isRunning}
hidden={isZeroChunk || isRunning} // handleOperationIconClick={handleOperationIconClick}
onOk={handleOperationIconClick(true)} // chunk_num={chunk_num}
onCancel={handleOperationIconClick(false)} // >
>
<div <div
className="cursor-pointer flex items-center gap-3" className="cursor-pointer flex items-center gap-3"
onClick={ onClick={() => {
isZeroChunk || isRunning showReparseDialogModal();
? handleOperationIconClick(false) }}
: () => {}
}
> >
{!isParserRunning(run) && operationIcon} {!isParserRunning(run) && operationIcon}
</div> </div>
</ConfirmDeleteDialog> // {/* </ReparseDialog> */}
)} )}
{isParserRunning(run) ? ( {isParserRunning(run) ? (
<> <>
@ -158,11 +161,14 @@ export function ParsingStatusCell({
</div> </div>
<div <div
className="cursor-pointer flex items-center gap-3" className="cursor-pointer flex items-center gap-3"
onClick={ onClick={() => {
isZeroChunk || isRunning showReparseDialogModal();
? handleOperationIconClick(false) }}
: () => {} // onClick={
} // isZeroChunk || isRunning
// ? handleOperationIconClick(false)
// : () => {}
// }
> >
{operationIcon} {operationIcon}
</div> </div>
@ -175,6 +181,16 @@ export function ParsingStatusCell({
)} )}
</div> </div>
)} )}
{reparseDialogVisible && (
<ReparseDialog
// hidden={isZeroChunk || isRunning}
hidden={false}
handleOperationIconClick={handleOperationIconClick}
chunk_num={chunk_num}
visible={reparseDialogVisible}
hideModal={hideReparseDialogModal}
></ReparseDialog>
)}
</section> </section>
); );
} }

View File

@ -0,0 +1,154 @@
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
import {
DynamicForm,
DynamicFormRef,
FormFieldType,
} from '@/components/dynamic-form';
import { Checkbox } from '@/components/ui/checkbox';
import { DialogProps } from '@radix-ui/react-dialog';
import { t } from 'i18next';
import { useCallback, useState } from 'react';
export const ReparseDialog = ({
handleOperationIconClick,
chunk_num,
hidden = false,
visible = true,
hideModal,
children,
}: DialogProps & {
chunk_num: number;
handleOperationIconClick: (options: {
delete: boolean;
apply_kb: boolean;
}) => void;
visible: boolean;
hideModal: () => void;
hidden?: boolean;
}) => {
const [formInstance, setFormInstance] = useState<DynamicFormRef | null>(null);
const formCallbackRef = useCallback((node: DynamicFormRef | null) => {
if (node) {
setFormInstance(node);
console.log('Form instance assigned:', node);
} else {
console.log('Form instance removed');
}
}, []);
const handleCancel = useCallback(() => {
// handleOperationIconClick(false);
hideModal?.();
formInstance?.reset();
}, [formInstance]);
const handleSave = useCallback(async () => {
const instance = formInstance;
if (!instance) {
console.error('Form instance is null');
return;
}
const check = await instance.trigger();
if (check) {
instance.submit();
const formValues = instance.getValues();
console.log(formValues);
handleOperationIconClick({
delete: formValues.delete,
apply_kb: formValues.apply_kb,
});
}
}, [formInstance, handleOperationIconClick]);
// useEffect(() => {
// if (!hidden) {
// const timer = setTimeout(() => {
// if (!formInstance) {
// console.warn(
// 'Form ref is still null after component should be mounted',
// );
// } else {
// console.log('Form ref is properly set');
// }
// }, 1000);
// return () => clearTimeout(timer);
// }
// }, [hidden, formInstance]);
return (
<ConfirmDeleteDialog
title={t(`knowledgeDetails.parseFile`)}
onOk={() => handleSave()}
onCancel={() => handleCancel()}
hidden={hidden}
open={visible}
content={{
title: t(`knowledgeDetails.parseFileTip`),
node: (
<div>
<DynamicForm.Root
onSubmit={(data) => {
console.log('submit', data);
}}
ref={formCallbackRef}
fields={[
{
name: 'delete',
label: '',
type: FormFieldType.Checkbox,
render: (fieldProps) => (
<div className="flex items-center text-text-secondary p-5 border border-border-button rounded-lg">
<Checkbox
{...fieldProps}
onCheckedChange={(checked: boolean) => {
fieldProps.onChange(checked);
}}
/>
<span className="ml-2">
{chunk_num > 0
? t(`knowledgeDetails.redo`, { chunkNum: chunk_num })
: t('knowledgeDetails.redoAll')}
</span>
</div>
),
},
{
name: 'apply_kb',
label: '',
type: FormFieldType.Checkbox,
render: (fieldProps) => (
<div className="flex items-center text-text-secondary p-5 border border-border-button rounded-lg">
<Checkbox
{...fieldProps}
onCheckedChange={(checked: boolean) => {
fieldProps.onChange(checked);
}}
/>
<span className="ml-2">
{t('knowledgeDetails.applyAutoMetadataSettings')}
</span>
</div>
),
},
]}
>
{/* <DynamicForm.CancelButton
handleCancel={() => handleOperationIconClick(false)}
cancelText={t('common.cancel')}
/>
<DynamicForm.SavingButton
buttonText={t('common.confirm')}
submitFunc={handleSave}
/> */}
</DynamicForm.Root>
</div>
),
}}
>
{/* {children} */}
</ConfirmDeleteDialog>
);
};

View File

@ -1,3 +1,4 @@
import { useSetModalState } from '@/hooks/common-hooks';
import { import {
UseRowSelectionType, UseRowSelectionType,
useSelectedIds, useSelectedIds,
@ -30,9 +31,9 @@ export function useBulkOperateDataset({
const { runDocumentByIds } = useRunDocument(); const { runDocumentByIds } = useRunDocument();
const { setDocumentStatus } = useSetDocumentStatus(); const { setDocumentStatus } = useSetDocumentStatus();
const { removeDocument } = useRemoveDocument(); const { removeDocument } = useRemoveDocument();
const { visible, showModal, hideModal } = useSetModalState();
const runDocument = useCallback( const runDocument = useCallback(
(run: number) => { async (run: number, option?: { delete: boolean; apply_kb: boolean }) => {
const nonVirtualKeys = selectedRowKeys.filter( const nonVirtualKeys = selectedRowKeys.filter(
(x) => (x) =>
!documents.some((y) => x === y.id && y.type === DocumentType.Virtual), !documents.some((y) => x === y.id && y.type === DocumentType.Virtual),
@ -42,18 +43,22 @@ export function useBulkOperateDataset({
toast.error(t('Please select a non-empty file list')); toast.error(t('Please select a non-empty file list'));
return; return;
} }
runDocumentByIds({ await runDocumentByIds({
documentIds: nonVirtualKeys, documentIds: nonVirtualKeys,
run, run,
shouldDelete: false, option,
}); });
hideModal();
}, },
[documents, runDocumentByIds, selectedRowKeys, t], [documents, runDocumentByIds, selectedRowKeys, hideModal, t],
); );
const handleRunClick = useCallback(() => { const handleRunClick = useCallback(
runDocument(1); (option: { delete: boolean; apply_kb: boolean }) => {
}, [runDocument]); runDocument(1, option);
},
[runDocument],
);
const handleCancelClick = useCallback(() => { const handleCancelClick = useCallback(() => {
runDocument(2); runDocument(2);
@ -106,7 +111,7 @@ export function useBulkOperateDataset({
id: 'run', id: 'run',
label: t('knowledgeDetails.run'), label: t('knowledgeDetails.run'),
icon: <Play />, icon: <Play />,
onClick: handleRunClick, onClick: () => showModal(),
}, },
{ {
id: 'cancel', id: 'cancel',
@ -127,5 +132,5 @@ export function useBulkOperateDataset({
}, },
]; ];
return { list }; return { list, visible, hideModal, showModal, handleRunClick };
} }

View File

@ -1,3 +1,4 @@
import { useSetModalState } from '@/hooks/common-hooks';
import { useRunDocument } from '@/hooks/use-document-request'; import { useRunDocument } from '@/hooks/use-document-request';
import { useState } from 'react'; import { useState } from 'react';
@ -5,11 +6,11 @@ export const useHandleRunDocumentByIds = (id: string) => {
const { runDocumentByIds, loading } = useRunDocument(); const { runDocumentByIds, loading } = useRunDocument();
const [currentId, setCurrentId] = useState<string>(''); const [currentId, setCurrentId] = useState<string>('');
const isLoading = loading && currentId !== '' && currentId === id; const isLoading = loading && currentId !== '' && currentId === id;
const { visible, showModal, hideModal } = useSetModalState();
const handleRunDocumentByIds = async ( const handleRunDocumentByIds = async (
documentId: string, documentId: string,
isRunning: boolean, isRunning: boolean,
shouldDelete: boolean = false, option: { delete: boolean; apply_kb: boolean },
) => { ) => {
if (isLoading) { if (isLoading) {
return; return;
@ -19,16 +20,20 @@ export const useHandleRunDocumentByIds = (id: string) => {
await runDocumentByIds({ await runDocumentByIds({
documentIds: [documentId], documentIds: [documentId],
run: isRunning ? 2 : 1, run: isRunning ? 2 : 1,
shouldDelete, option,
}); });
setCurrentId(''); setCurrentId('');
} catch (error) { } catch (error) {
setCurrentId(''); setCurrentId('');
} }
hideModal();
}; };
return { return {
handleRunDocumentByIds, handleRunDocumentByIds,
loading: isLoading, loading: isLoading,
visible,
showModal,
hideModal,
}; };
}; };

View File

@ -10,6 +10,12 @@ export enum MemoryType {
Episodic = 'episodic', Episodic = 'episodic',
Procedural = 'procedural', Procedural = 'procedural',
} }
export const MemoryOptions = (t: TFunction) => [
{ label: t('memories.raw'), value: MemoryType.Raw },
{ label: t('memories.semantic'), value: MemoryType.Semantic },
{ label: t('memories.episodic'), value: MemoryType.Episodic },
{ label: t('memories.procedural'), value: MemoryType.Procedural },
];
export const createMemoryFields = (t: TFunction) => export const createMemoryFields = (t: TFunction) =>
[ [
{ {
@ -24,12 +30,7 @@ export const createMemoryFields = (t: TFunction) =>
type: FormFieldType.MultiSelect, type: FormFieldType.MultiSelect,
placeholder: t('memories.descriptionPlaceholder'), placeholder: t('memories.descriptionPlaceholder'),
tooltip: t('memories.memoryTypeTooltip'), tooltip: t('memories.memoryTypeTooltip'),
options: [ options: MemoryOptions(t),
{ label: 'Raw', value: MemoryType.Raw },
{ label: 'Semantic', value: MemoryType.Semantic },
{ label: 'Episodic', value: MemoryType.Episodic },
{ label: 'Procedural', value: MemoryType.Procedural },
],
required: true, required: true,
customValidate: (value) => { customValidate: (value) => {
if (!value.includes(MemoryType.Raw) || !value.length) { if (!value.includes(MemoryType.Raw) || !value.length) {

View File

@ -16,7 +16,7 @@ export interface MemoryListParams {
export type MemoryType = 'raw' | 'semantic' | 'episodic' | 'procedural'; export type MemoryType = 'raw' | 'semantic' | 'episodic' | 'procedural';
export type StorageType = 'table' | 'graph'; export type StorageType = 'table' | 'graph';
export type Permissions = 'me' | 'team'; export type Permissions = 'me' | 'team';
export type ForgettingPolicy = 'fifo' | 'lru'; export type ForgettingPolicy = 'FIFO' | 'LRU';
export interface ICreateMemoryProps { export interface ICreateMemoryProps {
name: string; name: string;
memory_type: MemoryType[]; memory_type: MemoryType[];

View File

@ -39,7 +39,7 @@ export default function MemoryMessage() {
messages={data?.messages?.message_list ?? []} messages={data?.messages?.message_list ?? []}
pagination={pagination} pagination={pagination}
setPagination={setPagination} setPagination={setPagination}
total={data?.messages?.total ?? 0} total={data?.messages?.total_count ?? 0}
// rowSelection={rowSelection} // rowSelection={rowSelection}
// setRowSelection={setRowSelection} // setRowSelection={setRowSelection}
// loading={loading} // loading={loading}

View File

@ -14,7 +14,7 @@ export interface IMessageInfo {
} }
export interface IMessageTableProps { export interface IMessageTableProps {
messages: { message_list: Array<IMessageInfo>; total: number }; messages: { message_list: Array<IMessageInfo>; total_count: number };
storage_type: string; storage_type: string;
} }

View File

@ -251,7 +251,9 @@ export function MemoryTable({
title={t('memory.messages.forgetMessage')} title={t('memory.messages.forgetMessage')}
open={showDeleteDialog} open={showDeleteDialog}
onOpenChange={setShowDeleteDialog} onOpenChange={setShowDeleteDialog}
okButtonText={t('common.confirm')}
content={{ content={{
title: t('memory.messages.forgetMessageTip'),
node: ( node: (
<ConfirmDeleteDialogNode <ConfirmDeleteDialogNode
// avatar={{ avatar: selectedMessage.avatar, name: selectedMessage.name }} // avatar={{ avatar: selectedMessage.avatar, name: selectedMessage.name }}

View File

@ -12,7 +12,7 @@ import { z } from 'zod';
export const advancedSettingsFormSchema = { export const advancedSettingsFormSchema = {
permissions: z.string().optional(), permissions: z.string().optional(),
storage_type: z.enum(['table', 'graph']).optional(), storage_type: z.enum(['table', 'graph']).optional(),
forgetting_policy: z.enum(['lru', 'fifo']).optional(), forgetting_policy: z.enum(['LRU', 'FIFO']).optional(),
temperature: z.number().optional(), temperature: z.number().optional(),
system_prompt: z.string().optional(), system_prompt: z.string().optional(),
user_prompt: z.string().optional(), user_prompt: z.string().optional(),
@ -20,7 +20,7 @@ export const advancedSettingsFormSchema = {
export const defaultAdvancedSettingsForm = { export const defaultAdvancedSettingsForm = {
permissions: 'me', permissions: 'me',
storage_type: 'table', storage_type: 'table',
forgetting_policy: 'fifo', forgetting_policy: 'FIFO',
temperature: 0.7, temperature: 0.7,
system_prompt: '', system_prompt: '',
user_prompt: '', user_prompt: '',
@ -80,8 +80,8 @@ export const AdvancedSettingsForm = () => {
horizontal: true, horizontal: true,
placeholder: t('memory.config.storageTypePlaceholder'), placeholder: t('memory.config.storageTypePlaceholder'),
options: [ options: [
{ label: 'table', value: 'table' }, { label: 'Table', value: 'table' },
// { label: 'graph', value: 'graph' }, // { label: 'Graph', value: 'graph' },
], ],
required: false, required: false,
}} }}
@ -94,8 +94,8 @@ export const AdvancedSettingsForm = () => {
horizontal: true, horizontal: true,
// placeholder: t('memory.config.storageTypePlaceholder'), // placeholder: t('memory.config.storageTypePlaceholder'),
options: [ options: [
// { label: 'lru', value: 'lru' }, // { label: 'LRU', value: 'LRU' },
{ label: 'fifo', value: 'fifo' }, { label: 'FIFO', value: 'fifo' },
], ],
required: false, required: false,
}} }}
@ -146,7 +146,7 @@ export const AdvancedSettingsForm = () => {
field={{ field={{
name: 'user_prompt', name: 'user_prompt',
label: t('memory.config.userPrompt'), label: t('memory.config.userPrompt'),
type: FormFieldType.Text, type: FormFieldType.Textarea,
horizontal: true, horizontal: true,
placeholder: t('memory.config.userPromptPlaceholder'), placeholder: t('memory.config.userPromptPlaceholder'),
required: false, required: false,

View File

@ -15,9 +15,9 @@ export const useUpdateMemoryConfig = () => {
try { try {
const params = omit(data, [ const params = omit(data, [
'id', 'id',
'memory_type', // 'memory_type',
'embd_id', // 'embd_id',
'storage_type', // 'storage_type',
]); ]);
res = await updateMemory({ res = await updateMemory({
// ...memoryDataTemp, // ...memoryDataTemp,

View File

@ -6,9 +6,9 @@ import { MainContainer } from '@/pages/dataset/dataset-setting/configuration-for
import { TopTitle } from '@/pages/dataset/dataset-title'; import { TopTitle } from '@/pages/dataset/dataset-title';
import { IMemory } from '@/pages/memories/interface'; import { IMemory } from '@/pages/memories/interface';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod'; import { z } from 'zod';
import { useFetchMemoryBaseConfiguration } from '../hooks/use-memory-setting'; import { useFetchMemoryBaseConfiguration } from '../hooks/use-memory-setting';
import { import {
@ -24,14 +24,15 @@ import {
memoryModelFormSchema, memoryModelFormSchema,
} from './memory-model-form'; } from './memory-model-form';
const MemoryMessageSchema = z.object({
id: z.string(),
...basicInfoSchema,
...memoryModelFormSchema,
...advancedSettingsFormSchema,
});
// type MemoryMessageForm = z.infer<typeof MemoryMessageSchema>; // type MemoryMessageForm = z.infer<typeof MemoryMessageSchema>;
export default function MemoryMessage() { export default function MemoryMessage() {
const { t } = useTranslation();
const MemoryMessageSchema = z.object({
id: z.string(),
...basicInfoSchema,
...memoryModelFormSchema(t),
...advancedSettingsFormSchema,
});
const form = useForm<IMemory>({ const form = useForm<IMemory>({
resolver: zodResolver(MemoryMessageSchema), resolver: zodResolver(MemoryMessageSchema),
defaultValues: { defaultValues: {
@ -57,12 +58,13 @@ export default function MemoryMessage() {
temperature: data?.temperature, temperature: data?.temperature,
system_prompt: data?.system_prompt || '', system_prompt: data?.system_prompt || '',
user_prompt: data?.user_prompt || '', user_prompt: data?.user_prompt || '',
forgetting_policy: data?.forgetting_policy || 'fifo', forgetting_policy: data?.forgetting_policy || 'FIFO',
storage_type: data?.storage_type || 'table', storage_type: data?.storage_type || 'Table',
permissions: data?.permissions || 'me', permissions: data?.permissions || 'me',
}); });
}, [data, form]); }, [data, form]);
const onSubmit = (data: IMemory) => { const onSubmit = (data: IMemory) => {
console.log('data', data);
onMemoryRenameOk(data); onMemoryRenameOk(data);
}; };
return ( return (
@ -74,7 +76,7 @@ export default function MemoryMessage() {
<div className="flex gap-14 flex-1 min-h-0"> <div className="flex gap-14 flex-1 min-h-0">
<Form {...form}> <Form {...form}>
<form onSubmit={form.handleSubmit(() => {})} className="space-y-6 "> <form onSubmit={form.handleSubmit(() => {})} className="space-y-6 ">
<div className="w-[768px] h-[calc(100vh-300px)] pr-1 overflow-y-auto scrollbar-auto"> <div className="w-[768px] h-[calc(100vh-300px)] pr-1 overflow-y-auto scrollbar-auto pb-4">
<MainContainer className="text-text-secondary !space-y-10"> <MainContainer className="text-text-secondary !space-y-10">
<div className="text-base font-medium text-text-primary"> <div className="text-base font-medium text-text-primary">
{t('knowledgeConfiguration.baseInfo')} {t('knowledgeConfiguration.baseInfo')}

View File

@ -1,25 +1,36 @@
import { FormFieldType, RenderField } from '@/components/dynamic-form'; import { FormFieldType, RenderField } from '@/components/dynamic-form';
import { useModelOptions } from '@/components/llm-setting-items/llm-form-field'; import { useModelOptions } from '@/components/llm-setting-items/llm-form-field';
import { EmbeddingSelect } from '@/pages/dataset/dataset-setting/configuration/common-item'; import { EmbeddingSelect } from '@/pages/dataset/dataset-setting/configuration/common-item';
import { MemoryType } from '@/pages/memories/constants'; import { MemoryOptions, MemoryType } from '@/pages/memories/constants';
import { TFunction } from 'i18next';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { z } from 'zod'; import { z } from 'zod';
import { useFetchMemoryMessageList } from '../memory-message/hook';
export const memoryModelFormSchema = { export const memoryModelFormSchema = (t: TFunction) => ({
embd_id: z.string(), embd_id: z.string(),
llm_id: z.string(), llm_id: z.string(),
memory_type: z.array(z.string()).optional(), memory_type: z.array(z.string()).superRefine((data, ctx) => {
if (!data.includes(MemoryType.Raw) || !data.length) {
ctx.addIssue({
// path: ['memory_type'],
message: t('memories.embeddingModelError'),
code: 'custom',
});
}
}),
memory_size: z.number().optional(), memory_size: z.number().optional(),
}; });
export const defaultMemoryModelForm = { export const defaultMemoryModelForm = {
embd_id: '', embd_id: '',
llm_id: '', llm_id: '',
memory_type: [MemoryType.Raw], memory_type: [],
memory_size: 0, memory_size: 0,
}; };
export const MemoryModelForm = () => { export const MemoryModelForm = () => {
const { modelOptions } = useModelOptions(); const { modelOptions } = useModelOptions();
const { t } = useTranslation(); const { t } = useTranslation();
const { data } = useFetchMemoryMessageList();
return ( return (
<> <>
<RenderField <RenderField
@ -33,7 +44,11 @@ export const MemoryModelForm = () => {
type: FormFieldType.Custom, type: FormFieldType.Custom,
disabled: true, disabled: true,
render: (field) => ( render: (field) => (
<EmbeddingSelect field={field} isEdit={false} disabled={true} /> <EmbeddingSelect
field={field}
isEdit={false}
disabled={data?.messages?.total_count > 0}
/>
), ),
tooltip: t('memories.embeddingModelTooltip'), tooltip: t('memories.embeddingModelTooltip'),
@ -47,6 +62,7 @@ export const MemoryModelForm = () => {
required: true, required: true,
horizontal: true, horizontal: true,
type: FormFieldType.Select, type: FormFieldType.Select,
disabled: data?.messages?.total_count > 0,
options: modelOptions as { value: string; label: string }[], options: modelOptions as { value: string; label: string }[],
tooltip: t('memories.llmTooltip'), tooltip: t('memories.llmTooltip'),
}} }}
@ -59,13 +75,14 @@ export const MemoryModelForm = () => {
horizontal: true, horizontal: true,
placeholder: t('memories.memoryTypePlaceholder'), placeholder: t('memories.memoryTypePlaceholder'),
tooltip: t('memories.memoryTypeTooltip'), tooltip: t('memories.memoryTypeTooltip'),
disabled: true, disabled: data?.messages?.total_count > 0,
options: [ options: MemoryOptions(t),
{ label: 'Raw', value: 'raw' }, customValidate: (value) => {
{ label: 'Semantic', value: 'semantic' }, if (!value.includes(MemoryType.Raw) || !value.length) {
{ label: 'Episodic', value: 'episodic' }, return t('memories.embeddingModelError');
{ label: 'Procedural', value: 'procedural' }, }
], return true;
},
required: true, required: true,
}} }}
/> />

View File

@ -42,7 +42,7 @@ const AddDataSourceModal = ({
title={ title={
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div className="size-6">{sourceData?.icon}</div> <div className="size-6">{sourceData?.icon}</div>
{t('setting.addDataSourceModalTital', { name: sourceData?.name })} {t('setting.addDataSourceModalTitle', { name: sourceData?.name })}
</div> </div>
} }
open={visible || false} open={visible || false}

View File

@ -34,7 +34,7 @@ const methods = {
} as const; } as const;
const memoryService = registerNextServer<keyof typeof methods>(methods); const memoryService = registerNextServer<keyof typeof methods>(methods);
export const updateMemoryById = (id: string, data: any) => { export const updateMemoryById = (id: string, data: any) => {
return request.put(updateMemorySetting(id), { data }); return request.put(updateMemorySetting(id), { ...data });
}; };
export const getMemoryDetailById = (id: string, data: any) => { export const getMemoryDetailById = (id: string, data: any) => {
return request.get(getMemoryDetail(id), { params: data }); return request.get(getMemoryDetail(id), { params: data });

View File

@ -239,7 +239,7 @@ export default {
createMemory: `${api_host}/memories`, createMemory: `${api_host}/memories`,
getMemoryList: `${api_host}/memories`, getMemoryList: `${api_host}/memories`,
getMemoryConfig: (id: string) => `${api_host}/memories/${id}/config`, getMemoryConfig: (id: string) => `${api_host}/memories/${id}/config`,
deleteMemory: (id: string) => `${api_host}/memory/rm/${id}`, deleteMemory: (id: string) => `${api_host}/memories/${id}`,
getMemoryDetail: (id: string) => `${api_host}/memories/${id}`, getMemoryDetail: (id: string) => `${api_host}/memories/${id}`,
updateMemorySetting: (id: string) => `${api_host}/memories/${id}`, updateMemorySetting: (id: string) => `${api_host}/memories/${id}`,
deleteMemoryMessage: (data: { memory_id: string; message_id: string }) => deleteMemoryMessage: (data: { memory_id: string; message_id: string }) =>