Skip to content

Commit 3d8c13d

Browse files
authored
Release/v1.7.9.3
Release/v1.7.9.3
2 parents 38e304b + 058af63 commit 3d8c13d

132 files changed

Lines changed: 11762 additions & 5083 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
globs: frontend/app/**,frontend/components/**
3+
alwaysApply: false
4+
---
5+
# Frontend UI Standards Rules
6+
7+
## Principle
8+
Use Ant Design as primary UI library with minimal Tailwind CSS. Prioritize mature Ant Design solutions for responsive layouts. Avoid secondary encapsulation unless necessary.
9+
10+
## Technology Usage Guidelines
11+
- **Ant Design**: Forms, data display, complex interactions (`<Button>`, `<Modal>`, `<Form>`)
12+
- **Tailwind CSS**: Spacing, layout, simple styling (`className="flex items-center gap-2 text-sm"`)
13+
- **Inline Styles**: Special cases (`style={{ fontSize: "48px" }}`)
14+
- **Override AntD**: Use `<style jsx global>` when necessary
15+
16+
## Layout Standards
17+
18+
### Global Layout
19+
Use Header, Sider, Footer, Content structure. Reference: https://ant.design/components/layout-cn
20+
21+
```tsx
22+
const { Header, Footer, Sider, Content } = Layout;
23+
24+
<Layout>
25+
<Header>Header</Header>
26+
<Layout>
27+
<Sider width="25%">Sider</Sider>
28+
<Content>Content</Content>
29+
</Layout>
30+
<Footer>Footer</Footer>
31+
</Layout>
32+
```
33+
34+
### Responsive Grid
35+
Use AntD Grid for responsive layouts. Reference: https://ant.design/components/grid-cn
36+
37+
```tsx
38+
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
39+
<Col span={6}>col-6</Col>
40+
<Col span={6}>col-6</Col>
41+
<Col span={6}>col-6</Col>
42+
<Col span={6}>col-6</Col>
43+
</Row>
44+
```
45+
46+
### Flex Layout
47+
Use AntD Flex for component alignment. Reference: https://ant.design/components/flex-cn
48+
49+
```tsx
50+
<Flex vertical className="h-full overflow-hidden">
51+
<Row><Col>Content 1</Col></Row>
52+
<Row><Col>Content 2</Col></Row>
53+
<Row className="flex:1 min-h-0">
54+
<Col><Flex className="h-full overflow-hidden">...</Flex></Col>
55+
</Row>
56+
</Flex>
57+
```
58+
59+
## Component Standards
60+
61+
### Modals
62+
1. **Complex Modal**: For reusable modals with custom content
63+
2. **Simple Modal**: Use `useConfirmModal` for one-time confirmations
64+
65+
#### Modal Standards
66+
- Use `centered` for positioning
67+
- Confirm buttons: `type="primary" danger={true}`
68+
- i18n keys: `common.cancel`, `common.confirm`
69+
- Icon: `<ExclamationCircleFilled />` aligned with title
70+
71+
```tsx
72+
// Complex modal
73+
<Modal
74+
open={isOpen}
75+
centered
76+
okButtonProps={{ type: "primary", danger: true }}
77+
okText={t("common.confirm")}
78+
>
79+
<div className="flex items-start gap-4">
80+
<ExclamationCircleFilled style={{ color: token.colorWarning, fontSize: '22px' }} />
81+
<div>
82+
<div className="font-medium">{t("title")}</div>
83+
<div className="text-sm">{t("content")}</div>
84+
</div>
85+
</div>
86+
</Modal>
87+
88+
// Simple modal
89+
const { confirm } = useConfirmModal();
90+
confirm({
91+
title: t("delete.confirmTitle"),
92+
content: t("delete.confirmContent"),
93+
onOk: () => { /* ... */ }
94+
});
95+
```
96+
97+
### Icon Library
98+
- **Primary**: `lucide-react` for consistency
99+
- **Fallback**: `@ant-design/icons` when lucide-react lacks icons
100+
101+
```tsx
102+
import { ExternalLink } from "lucide-react";
103+
import { PlusOutlined } from '@ant-design/icons';
104+
105+
<ExternalLink />
106+
<PlusOutlined />
107+
```
108+
109+
## i18n Usage
110+
111+
```tsx
112+
import { useTranslation, Trans } from "react-i18next";
113+
114+
// Simple text
115+
t("common.confirm")
116+
117+
// HTML content
118+
<Trans
119+
i18nKey="modal.description"
120+
values={{ title }}
121+
components={{ strong: <strong /> }}
122+
/>
123+
```

backend/agents/create_agent_info.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ async def create_agent_config(
150150
tenant_id=tenant_id, user_id=user_id)
151151
if knowledge_info_list:
152152
for knowledge_info in knowledge_info_list:
153+
if knowledge_info.get('knowledge_sources') != 'elasticsearch':
154+
continue
153155
knowledge_name = knowledge_info.get("index_name")
154156
try:
155157
message = ElasticSearchService().get_summary(index_name=knowledge_name)
@@ -239,13 +241,22 @@ async def create_tool_config_list(agent_id, tenant_id, user_id):
239241
knowledge_info_list = get_selected_knowledge_list(
240242
tenant_id=tenant_id, user_id=user_id)
241243
index_names = [knowledge_info.get(
242-
"index_name") for knowledge_info in knowledge_info_list]
244+
"index_name") for knowledge_info in knowledge_info_list if knowledge_info.get('knowledge_sources') == 'elasticsearch']
243245
tool_config.metadata = {
244246
"index_names": index_names,
245247
"vdb_core": get_vector_db_core(),
246248
"embedding_model": get_embedding_model(tenant_id=tenant_id),
247249
"name_resolver": build_knowledge_name_mapping(tenant_id=tenant_id, user_id=user_id),
248250
}
251+
elif tool_config.class_name == "DataMateSearchTool":
252+
knowledge_info_list = get_selected_knowledge_list(
253+
tenant_id=tenant_id, user_id=user_id)
254+
index_names = [knowledge_info.get(
255+
"index_name") for knowledge_info in knowledge_info_list if
256+
knowledge_info.get('knowledge_sources') == 'datamate']
257+
tool_config.metadata = {
258+
"index_names": index_names,
259+
}
249260
elif tool_config.class_name == "AnalyzeTextFileTool":
250261
tool_config.metadata = {
251262
"llm_model": get_llm_model(tenant_id=tenant_id),

backend/apps/config_app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from apps.agent_app import agent_config_router as agent_router
88
from apps.config_sync_app import router as config_sync_router
9+
from apps.datamate_app import router as datamate_router
910
from apps.vectordatabase_app import router as vectordatabase_router
1011
from apps.file_management_app import file_management_config_router as file_manager_router
1112
from apps.image_app import router as proxy_router
@@ -43,6 +44,7 @@
4344
app.include_router(config_sync_router)
4445
app.include_router(agent_router)
4546
app.include_router(vectordatabase_router)
47+
app.include_router(datamate_router)
4648
app.include_router(voice_router)
4749
app.include_router(file_manager_router)
4850
app.include_router(proxy_router)

backend/apps/config_sync_app.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ async def save_config(config: GlobalConfig, authorization: Optional[str] = Heade
2727
)
2828
except Exception as e:
2929
logger.error(f"Failed to save configuration: {str(e)}")
30-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Failed to save configuration.")
30+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
31+
detail="Failed to save configuration.")
3132

3233

3334
@router.get("/load_config")
@@ -49,4 +50,5 @@ async def load_config(authorization: Optional[str] = Header(None), request: Requ
4950
)
5051
except Exception as e:
5152
logger.error(f"Failed to load configuration: {str(e)}")
52-
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Failed to load configuration.")
53+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
54+
detail="Failed to load configuration.")

backend/apps/datamate_app.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import logging
2+
from typing import Optional
3+
4+
from fastapi import APIRouter, Header, HTTPException, Path
5+
from fastapi.responses import JSONResponse
6+
from http import HTTPStatus
7+
8+
from services.datamate_service import (
9+
sync_datamate_knowledge_bases_and_create_records,
10+
fetch_datamate_knowledge_base_file_list
11+
)
12+
from utils.auth_utils import get_current_user_id
13+
14+
router = APIRouter(prefix="/datamate")
15+
logger = logging.getLogger("datamate_app")
16+
17+
18+
@router.post("/sync_datamate_knowledges")
19+
async def sync_datamate_knowledges(
20+
authorization: Optional[str] = Header(None)
21+
):
22+
"""Sync DataMate knowledge bases and create knowledge records in local database."""
23+
try:
24+
user_id, tenant_id = get_current_user_id(authorization)
25+
26+
return await sync_datamate_knowledge_bases_and_create_records(
27+
tenant_id=tenant_id,
28+
user_id=user_id
29+
)
30+
except Exception as e:
31+
raise HTTPException(
32+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=f"Error syncing DataMate knowledge bases and creating records: {str(e)}")
33+
34+
35+
@router.get("/{knowledge_base_id}/files")
36+
async def get_datamate_knowledge_base_files_endpoint(
37+
knowledge_base_id: str = Path(...,
38+
description="ID of the DataMate knowledge base"),
39+
authorization: Optional[str] = Header(None)
40+
):
41+
"""Get all files from a DataMate knowledge base."""
42+
try:
43+
user_id, tenant_id = get_current_user_id(authorization)
44+
result = await fetch_datamate_knowledge_base_file_list(knowledge_base_id, tenant_id)
45+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
46+
except Exception as e:
47+
raise HTTPException(
48+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=f"Error fetching DataMate knowledge base files: {str(e)}")

backend/apps/tenant_config_app.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastapi.responses import JSONResponse
77

88
from consts.const import DEPLOYMENT_VERSION, APP_VERSION
9+
from consts.model import UpdateKnowledgeListRequest
910
from services.tenant_config_service import get_selected_knowledge_list, update_selected_knowledge
1011
from utils.auth_utils import get_current_user_id
1112

@@ -61,16 +62,37 @@ def load_knowledge_list(
6162
@router.post("/update_knowledge_list")
6263
def update_knowledge_list(
6364
authorization: Optional[str] = Header(None),
64-
knowledge_list: List[str] = Body(None)
65+
request: UpdateKnowledgeListRequest = Body(...)
6566
):
6667
try:
6768
user_id, tenant_id = get_current_user_id(authorization)
69+
70+
# Convert grouped request to flat lists
71+
knowledge_list = []
72+
knowledge_sources = []
73+
74+
if request.nexent:
75+
knowledge_list.extend(request.nexent)
76+
knowledge_sources.extend(["nexent"] * len(request.nexent))
77+
78+
if request.datamate:
79+
knowledge_list.extend(request.datamate)
80+
knowledge_sources.extend(["datamate"] * len(request.datamate))
81+
6882
result = update_selected_knowledge(
69-
tenant_id=tenant_id, user_id=user_id, index_name_list=knowledge_list)
83+
tenant_id=tenant_id, user_id=user_id, index_name_list=knowledge_list, knowledge_sources=knowledge_sources)
7084
if result:
85+
# Get updated knowledge base information
86+
selected_knowledge_info = get_selected_knowledge_list(
87+
tenant_id=tenant_id, user_id=user_id)
88+
89+
content = {"selectedKbNames": [item["index_name"] for item in selected_knowledge_info],
90+
"selectedKbModels": [item["embedding_model_name"] for item in selected_knowledge_info],
91+
"selectedKbSources": [item["knowledge_sources"] for item in selected_knowledge_info]}
92+
7193
return JSONResponse(
7294
status_code=HTTPStatus.OK,
73-
content={"message": "update success", "status": "success"}
95+
content={"content": content, "message": "update success", "status": "success"}
7496
)
7597
else:
7698
raise HTTPException(

backend/apps/user_management_app.py

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from consts.exceptions import NoInviteCodeException, IncorrectInviteCodeException, UserRegistrationException
1212
from services.user_management_service import get_authorized_client, validate_token, \
1313
check_auth_service_health, signup_user, signup_user_with_invitation, signin_user, refresh_user_token, \
14-
get_session_by_authorization, revoke_regular_user, get_user_info, get_permissions_by_role
14+
get_session_by_authorization, revoke_regular_user, get_user_info
1515
from consts.exceptions import UnauthorizedError
1616
from utils.auth_utils import get_current_user_id
1717

@@ -287,32 +287,3 @@ async def revoke_user_account(request: Request):
287287
logging.error(f"User revoke failed: {str(e)}")
288288
raise HTTPException(
289289
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="User revoke failed")
290-
291-
292-
@router.get("/role_permissions/{user_role}")
293-
async def get_role_permissions(user_role: str):
294-
"""
295-
Get all permissions for a specific user role.
296-
297-
Args:
298-
user_role (str): User role to query permissions for (SU, ADMIN, DEV, USER)
299-
300-
Returns:
301-
JSONResponse: Permissions data with success message
302-
"""
303-
try:
304-
permissions_data = await get_permissions_by_role(user_role)
305-
306-
return JSONResponse(status_code=HTTPStatus.OK, content={
307-
"message": permissions_data["message"],
308-
"data": {
309-
"user_role": permissions_data["user_role"],
310-
"permissions": permissions_data["permissions"],
311-
"total_permissions": permissions_data["total_permissions"]
312-
}
313-
})
314-
except Exception as e:
315-
logging.error(
316-
f"Failed to get role permissions for role {user_role}: {str(e)}")
317-
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
318-
detail=f"Failed to retrieve permissions for role {user_role}")

backend/consts/const.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# Vector database providers
1515
class VectorDatabaseType(str, Enum):
1616
ELASTICSEARCH = "elasticsearch"
17+
DATAMATE = "datamate"
1718

1819

1920
# Elasticsearch Configuration
@@ -23,7 +24,6 @@ class VectorDatabaseType(str, Enum):
2324
ES_USERNAME = "elastic"
2425
ELASTICSEARCH_SERVICE = os.getenv("ELASTICSEARCH_SERVICE")
2526

26-
2727
# Data Processing Service Configuration
2828
DATA_PROCESS_SERVICE = os.getenv("DATA_PROCESS_SERVICE")
2929
CLIP_MODEL_PATH = os.getenv("CLIP_MODEL_PATH")
@@ -253,6 +253,7 @@ class VectorDatabaseType(str, Enum):
253253
TENANT_NAME = "TENANT_NAME"
254254
TENANT_ID = "TENANT_ID"
255255
DEFAULT_GROUP_ID = "DEFAULT_GROUP_ID"
256+
DATAMATE_URL = "DATAMATE_URL"
256257

257258
# Task Status Constants
258259
TASK_STATUS = {
@@ -293,4 +294,4 @@ class VectorDatabaseType(str, Enum):
293294
MODEL_ENGINE_ENABLED = os.getenv("MODEL_ENGINE_ENABLED")
294295

295296
# APP Version
296-
APP_VERSION = "v1.7.9.2"
297+
APP_VERSION = "v1.7.9.3"

backend/consts/model.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ class AppConfig(BaseModel):
106106
iconType: str
107107
customIconUrl: Optional[str] = None
108108
avatarUri: Optional[str] = None
109-
modelEngineEnabled: bool = True
109+
modelEngineEnabled: bool = False
110+
datamateUrl: Optional[str] = None
110111

111112

112113
class GlobalConfig(BaseModel):
@@ -460,6 +461,14 @@ class MCPConfigRequest(BaseModel):
460461
..., description="Dictionary of MCP server configurations")
461462

462463

464+
class UpdateKnowledgeListRequest(BaseModel):
465+
"""Request model for updating user's selected knowledge base list grouped by source"""
466+
nexent: Optional[List[str]] = Field(
467+
None, description="List of knowledge base index names from nexent source")
468+
datamate: Optional[List[str]] = Field(
469+
None, description="List of knowledge base index names from datamate source")
470+
471+
463472
# Tenant Management Data Models
464473
# ---------------------------------------------------------------------------
465474
class TenantCreateRequest(BaseModel):

0 commit comments

Comments
 (0)