Skip to content

Commit 1b94a1d

Browse files
committed
♻️ Improvement: Now embedding model in sdk will automatically retry up to 3 times when connection timeout
♻️ Improvement: Warn the user trying to proceed to next config page when embedding model has not connected yet ♻️ Improvement: Warn the user trying to modify the embedding config (from non-empty state to other state) ♻️ Improvement: Warn the user trying to proceed to next config page when embedding model has not set (regardless of multi-embedding model) ♻️ Refactor: add EmbedderCheckModal.tsx to manage all warning modals in model config page 🐛 Bug fix: Next.js warning in the home page: Instance created by `useForm` is not connected to any Form element.
1 parent 9a0072c commit 1b94a1d

File tree

14 files changed

+3288
-2179
lines changed

14 files changed

+3288
-2179
lines changed

backend/services/config_sync_service.py

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from typing import Optional
23

34
from consts.const import (
45
APP_DESCRIPTION,
@@ -25,7 +26,14 @@
2526
logger = logging.getLogger("config_sync_service")
2627

2728

28-
def handle_model_config(tenant_id: str, user_id: str, config_key: str, model_id: int, tenant_config_dict: dict) -> None:
29+
def _parse_optional_int(value) -> Optional[int]:
30+
try:
31+
return int(value)
32+
except (ValueError, TypeError):
33+
return None
34+
35+
36+
def handle_model_config(tenant_id: str, user_id: str, config_key: str, model_id: Optional[int], tenant_config_dict: dict) -> None:
2937
"""
3038
Handle model configuration updates, deletions, and settings operations
3139
@@ -36,30 +44,28 @@ def handle_model_config(tenant_id: str, user_id: str, config_key: str, model_id:
3644
model_id: Model ID
3745
tenant_config_dict: Tenant configuration dictionary
3846
"""
39-
if not model_id and config_key in tenant_config_dict:
40-
tenant_config_manager.delete_single_config(tenant_id, config_key)
41-
elif config_key in tenant_config_dict:
42-
try:
43-
existing_model_id = int(
44-
tenant_config_dict[config_key]) if tenant_config_dict[config_key] else None
45-
if existing_model_id == model_id:
46-
tenant_config_manager.update_single_config(
47-
tenant_id, config_key)
48-
else:
49-
tenant_config_manager.delete_single_config(
50-
tenant_id, config_key)
51-
if model_id:
52-
tenant_config_manager.set_single_config(
53-
user_id, tenant_id, config_key, model_id)
54-
except (ValueError, TypeError):
47+
# Delete the config if the model_id is None
48+
if model_id is None:
49+
if config_key in tenant_config_dict:
5550
tenant_config_manager.delete_single_config(tenant_id, config_key)
56-
if model_id:
57-
tenant_config_manager.set_single_config(
58-
user_id, tenant_id, config_key, model_id)
59-
else:
60-
if model_id:
61-
tenant_config_manager.set_single_config(
62-
user_id, tenant_id, config_key, model_id)
51+
return
52+
53+
# If the config key does not exist, set directly
54+
if config_key not in tenant_config_dict:
55+
tenant_config_manager.set_single_config(
56+
user_id, tenant_id, config_key, model_id)
57+
return
58+
59+
current_model_id = _parse_optional_int(tenant_config_dict.get(config_key))
60+
61+
if current_model_id == model_id:
62+
tenant_config_manager.update_single_config(tenant_id, config_key)
63+
return
64+
65+
# Delete the config first, then set the new value
66+
tenant_config_manager.delete_single_config(tenant_id, config_key)
67+
tenant_config_manager.set_single_config(
68+
user_id, tenant_id, config_key, model_id)
6369

6470

6571
async def save_config_impl(config, tenant_id, user_id):
@@ -90,16 +96,12 @@ async def save_config_impl(config, tenant_id, user_id):
9096
if not model_config:
9197
continue
9298

93-
model_name = model_config.get("modelName")
9499
model_display_name = model_config.get("displayName")
95100

96101
config_key = get_env_key(model_type) + "_ID"
97102
model_id = get_model_id_by_display_name(
98103
model_display_name, tenant_id)
99104

100-
if not model_name:
101-
continue
102-
103105
handle_model_config(tenant_id, user_id, config_key,
104106
model_id, tenant_config_dict)
105107

frontend/app/[locale]/setup/modelSetup/components/appConfig.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,8 @@ export const AppConfigSection: React.FC = () => {
502502
style={{ display: "none" }}
503503
accept="image/*"
504504
onChange={handleFileUpload}
505+
title={t('appConfig.icon.uploadHint')}
506+
placeholder={t('appConfig.icon.uploadHint')}
505507
/>
506508

507509
<div className="text-xs text-gray-500 mt-2">
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
"use client";
2+
3+
import { useTranslation } from "react-i18next";
4+
import { Modal, Button } from "antd";
5+
import { WarningFilled } from "@ant-design/icons";
6+
7+
interface EmbedderCheckModalProps {
8+
// Existing empty selection warning modal
9+
emptyWarningOpen: boolean;
10+
onEmptyOk: () => void;
11+
onEmptyCancel: () => void;
12+
13+
// New connectivity warning modal
14+
connectivityWarningOpen: boolean;
15+
onConnectivityOk: () => void;
16+
onConnectivityCancel: () => void;
17+
18+
// New modify embedding confirmation modal
19+
modifyWarningOpen: boolean;
20+
onModifyOk: () => void;
21+
onModifyCancel: () => void;
22+
}
23+
24+
export default function EmbedderCheckModal(props: EmbedderCheckModalProps) {
25+
const { t } = useTranslation();
26+
const {
27+
emptyWarningOpen,
28+
onEmptyOk,
29+
onEmptyCancel,
30+
connectivityWarningOpen,
31+
onConnectivityOk,
32+
onConnectivityCancel,
33+
modifyWarningOpen,
34+
onModifyOk,
35+
onModifyCancel,
36+
} = props;
37+
38+
return (
39+
<>
40+
{/* Existing empty embedding selection warning */}
41+
<Modal
42+
title={t("embedding.emptyWarningModal.title")}
43+
open={emptyWarningOpen}
44+
onCancel={onEmptyCancel}
45+
centered
46+
footer={
47+
<div className="flex justify-end mt-6 gap-4">
48+
<Button onClick={onEmptyOk}>
49+
{t("embedding.emptyWarningModal.ok_continue")}
50+
</Button>
51+
<Button type="primary" onClick={onEmptyCancel}>
52+
{t("embedding.emptyWarningModal.cancel")}
53+
</Button>
54+
</div>
55+
}
56+
>
57+
<div className="py-2">
58+
<div className="flex items-center">
59+
<WarningFilled
60+
className="text-yellow-500 mt-1 mr-2"
61+
style={{ fontSize: "48px" }}
62+
/>
63+
<div className="ml-3 mt-2">
64+
<div>{t("embedding.emptyWarningModal.content")}</div>
65+
<div />
66+
<div className="mt-2 text-xs opacity-70">
67+
{t("embedding.emptyWarningModal.tip")}
68+
</div>
69+
</div>
70+
</div>
71+
</div>
72+
</Modal>
73+
74+
{/* New connectivity check warning */}
75+
<Modal
76+
title={t("embedding.unavaliableWarningModal.title")}
77+
open={connectivityWarningOpen}
78+
onCancel={onConnectivityCancel}
79+
centered
80+
footer={
81+
<div className="flex justify-end mt-6 gap-4">
82+
<Button onClick={onConnectivityOk}>
83+
{t("embedding.unavaliableWarningModal.ok")}
84+
</Button>
85+
<Button type="primary" onClick={onConnectivityCancel}>
86+
{t("embedding.unavaliableWarningModal.cancel")}
87+
</Button>
88+
</div>
89+
}
90+
>
91+
<div className="py-2">
92+
<div className="flex items-center">
93+
<WarningFilled
94+
className="text-yellow-500 mt-1 mr-2"
95+
style={{ fontSize: "48px" }}
96+
/>
97+
<div className="ml-3 mt-2">
98+
<div className="text-sm leading-6">
99+
{t("embedding.unavaliableWarningModal.content")}
100+
</div>
101+
<div className="mt-2 text-xs opacity-70">
102+
{t("embedding.unavaliableWarningModal.tip")}
103+
</div>
104+
</div>
105+
</div>
106+
</div>
107+
</Modal>
108+
109+
{/* New modify embedding confirmation warning */}
110+
<Modal
111+
title={t("embedding.modifyWarningModal.title")}
112+
open={modifyWarningOpen}
113+
onCancel={onModifyCancel}
114+
centered
115+
footer={
116+
<div className="flex justify-end mt-6 gap-4">
117+
<Button onClick={onModifyOk}>
118+
{t("embedding.modifyWarningModal.ok_proceed")}
119+
</Button>
120+
<Button type="primary" onClick={onModifyCancel}>
121+
{t("embedding.modifyWarningModal.cancel")}
122+
</Button>
123+
</div>
124+
}
125+
>
126+
<div className="py-2">
127+
<div className="flex items-center">
128+
<WarningFilled
129+
className="text-yellow-500 mt-1 mr-2"
130+
style={{ fontSize: "48px" }}
131+
/>
132+
<div className="ml-3 mt-2">
133+
<div className="text-sm leading-6">
134+
{t("embedding.modifyWarningModal.content")}
135+
</div>
136+
</div>
137+
</div>
138+
</div>
139+
</Modal>
140+
</>
141+
);
142+
}
143+
144+

frontend/app/[locale]/setup/modelSetup/components/model/ModelAddDialog.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ export const ModelAddDialog = ({ isOpen, onClose, onSuccess }: ModelAddDialogPro
516516
{/* Connectivity verification area */}
517517
{!form.isBatchImport && (
518518
<div className="p-3 bg-gray-50 border border-gray-200 rounded-md">
519-
<div className="flex items-center justify-between mb-1">
519+
<div className="flex items-center justify-between">
520520
<div className="flex items-center">
521521
<span className="text-sm font-medium text-gray-700">{t('model.dialog.connectivity.title')}</span>
522522
{connectivityStatus.status && (
@@ -537,7 +537,6 @@ export const ModelAddDialog = ({ isOpen, onClose, onSuccess }: ModelAddDialogPro
537537
size="small"
538538
type="default"
539539
onClick={handleVerifyConnectivity}
540-
loading={verifyingConnectivity}
541540
disabled={!isFormValid() || verifyingConnectivity}
542541
>
543542
{verifyingConnectivity ? t('model.dialog.button.verifying') : t('model.dialog.button.verify')}

0 commit comments

Comments
 (0)