Skip to content

Commit 5b66185

Browse files
authored
🐛 Friendly error messages when adding a model
2 parents a1f6d64 + d76fe0f commit 5b66185

File tree

9 files changed

+133
-52
lines changed

9 files changed

+133
-52
lines changed

backend/apps/model_managment_app.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ async def create_model(request: ModelRequest, authorization: Optional[str] = Hea
7373
except ValueError as e:
7474
logging.error(f"Failed to create model: {str(e)}")
7575
raise HTTPException(status_code=HTTPStatus.CONFLICT,
76-
detail="Failed to create model: name conflict")
76+
detail=str(e))
7777
except Exception as e:
7878
logging.error(f"Failed to create model: {str(e)}")
7979
raise HTTPException(
80-
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Failed to create model")
80+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
8181

8282

8383
@router.post("/provider/create")
@@ -103,7 +103,7 @@ async def create_provider_model(request: ProviderModelRequest, authorization: Op
103103
except Exception as e:
104104
logging.error(f"Failed to create provider model: {str(e)}")
105105
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
106-
detail="Failed to create provider model")
106+
detail=str(e))
107107

108108

109109
@router.post("/provider/batch_create")
@@ -129,7 +129,7 @@ async def batch_create_models(request: BatchCreateModelsRequest, authorization:
129129
except Exception as e:
130130
logging.error(f"Failed to batch create models: {str(e)}")
131131
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
132-
detail="Failed to batch create models")
132+
detail=str(e))
133133

134134

135135
@router.post("/provider/list")
@@ -153,7 +153,7 @@ async def get_provider_list(request: ProviderModelRequest, authorization: Option
153153
except Exception as e:
154154
logging.error(f"Failed to get provider list: {str(e)}")
155155
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
156-
detail="Failed to get provider list")
156+
detail=str(e))
157157

158158

159159
@router.post("/update")
@@ -179,11 +179,11 @@ async def update_single_model(request: dict, authorization: Optional[str] = Head
179179
except ValueError as e:
180180
logging.error(f"Failed to update model: {str(e)}")
181181
raise HTTPException(status_code=HTTPStatus.CONFLICT,
182-
detail="Failed to update model: name conflict")
182+
detail=str(e))
183183
except Exception as e:
184184
logging.error(f"Failed to update model: {str(e)}")
185185
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
186-
detail="Failed to update model")
186+
detail=str(e))
187187

188188

189189
@router.post("/batch_update")
@@ -203,7 +203,7 @@ async def batch_update_models(request: List[dict], authorization: Optional[str]
203203
except Exception as e:
204204
logging.error(f"Failed to batch update models: {str(e)}")
205205
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
206-
detail="Failed to batch update models")
206+
detail=str(e))
207207

208208

209209
@router.post("/delete")
@@ -230,11 +230,11 @@ async def delete_model(display_name: str = Query(..., embed=True), authorization
230230
except LookupError as e:
231231
logging.error(f"Failed to delete model: {str(e)}")
232232
raise HTTPException(status_code=HTTPStatus.NOT_FOUND,
233-
detail="Failed to delete model: model not found")
233+
detail=str(e))
234234
except Exception as e:
235235
logging.error(f"Failed to delete model: {str(e)}")
236236
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
237-
detail="Failed to delete model")
237+
detail=str(e))
238238

239239

240240
@router.get("/list")
@@ -256,7 +256,7 @@ async def get_model_list(authorization: Optional[str] = Header(None)):
256256
except Exception as e:
257257
logging.error(f"Failed to list models: {str(e)}")
258258
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
259-
detail="Failed to retrieve model list")
259+
detail=str(e))
260260

261261

262262
@router.get("/llm_list")
@@ -272,7 +272,7 @@ async def get_llm_model_list(authorization: Optional[str] = Header(None)):
272272
except Exception as e:
273273
logging.error(f"Failed to retrieve LLM list: {str(e)}")
274274
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
275-
detail="Failed to retrieve LLM list")
275+
detail=str(e))
276276

277277

278278
@router.post("/healthcheck")
@@ -296,15 +296,15 @@ async def check_model_health(
296296
except LookupError as e:
297297
logging.error(f"Failed to check model connectivity: {str(e)}")
298298
raise HTTPException(status_code=HTTPStatus.NOT_FOUND,
299-
detail="Model configuration not found")
299+
detail=str(e))
300300
except ValueError as e:
301301
logging.error(f"Invalid model configuration: {str(e)}")
302302
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
303-
detail="Invalid model configuration")
303+
detail=str(e))
304304
except Exception as e:
305305
logging.error(f"Failed to check model connectivity: {str(e)}")
306306
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
307-
detail="Failed to check model connectivity")
307+
detail=str(e))
308308

309309

310310
@router.post("/temporary_healthcheck")
@@ -324,4 +324,4 @@ async def check_temporary_model_health(request: ModelRequest):
324324
except Exception as e:
325325
logging.error(f"Failed to verify model connectivity: {str(e)}")
326326
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
327-
detail="Failed to verify model connectivity")
327+
detail=str(e))

backend/services/model_health_service.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ async def verify_model_config_connectivity(model_config: dict):
201201
Args:
202202
model_config: Model configuration dictionary, containing necessary connection parameters
203203
Returns:
204-
dict: Contains the result of the connectivity test
204+
dict: Contains the result of the connectivity test and error message if failed
205205
"""
206206
try:
207207
model_name = model_config.get("model_name", "")
@@ -214,23 +214,34 @@ async def verify_model_config_connectivity(model_config: dict):
214214
connectivity = await _perform_connectivity_check(
215215
model_name, model_type, model_base_url, model_api_key
216216
)
217+
218+
if not connectivity:
219+
return {
220+
"connectivity": False,
221+
"model_name": model_name,
222+
"error": f"Failed to connect to model '{model_name}' at {model_base_url}. Please verify the URL, API key, and network connection."
223+
}
224+
225+
return {
226+
"connectivity": True,
227+
"model_name": model_name,
228+
}
217229
except ValueError as e:
218-
logger.warning(f"UNCONNECTED: {model_name}; Base URL: {model_base_url}; API Key: {model_api_key}; Error: {str(e)}")
230+
error_msg = str(e)
231+
logger.warning(f"UNCONNECTED: {model_name}; Base URL: {model_base_url}; API Key: {model_api_key}; Error: {error_msg}")
219232
return {
220233
"connectivity": False,
221-
"model_name": model_name
234+
"model_name": model_name,
235+
"error": error_msg
222236
}
223237

224-
return {
225-
"connectivity": connectivity,
226-
"model_name": model_name,
227-
}
228-
229238
except Exception as e:
230-
logger.error(f"Failed to check connectivity of models: {str(e)}")
239+
error_msg = str(e)
240+
logger.error(f"Failed to check connectivity of models: {error_msg}")
231241
return {
232242
"connectivity": False,
233-
"model_name": model_config.get("model_name", "UNKNOWN_MODEL")
243+
"model_name": model_config.get("model_name", "UNKNOWN_MODEL"),
244+
"error": f"Connection verification failed: {error_msg}"
234245
}
235246

236247

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

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,22 +160,31 @@ export const ModelAddDialog = ({ isOpen, onClose, onSuccess }: ModelAddDialogPro
160160
const result = await modelService.verifyModelConfigConnectivity(config)
161161

162162
// Set connectivity status
163-
let connectivityMessage = ''
164163
if (result.connectivity) {
165-
connectivityMessage = t('model.dialog.connectivity.status.available')
164+
setConnectivityStatus({
165+
status: "available",
166+
message: t('model.dialog.connectivity.status.available')
167+
})
166168
} else {
167-
connectivityMessage = t('model.dialog.connectivity.status.unavailable')
169+
// Set status to unavailable
170+
setConnectivityStatus({
171+
status: "unavailable",
172+
message: t('model.dialog.connectivity.status.unavailable')
173+
})
174+
// Show detailed error message using message.error (same as add failure)
175+
if (result.error) {
176+
message.error(result.error)
177+
}
168178
}
169-
setConnectivityStatus({
170-
status: result.connectivity ? "available" : "unavailable",
171-
message: connectivityMessage
172-
})
173179

174180
} catch (error) {
181+
const errorMessage = error instanceof Error ? error.message : String(error)
175182
setConnectivityStatus({
176183
status: "unavailable",
177184
message: t('model.dialog.connectivity.status.unavailable')
178185
})
186+
// Show error message using message.error (same as add failure)
187+
message.error(errorMessage || t('model.dialog.connectivity.status.unavailable'))
179188
} finally {
180189
setVerifyingConnectivity(false)
181190
}
@@ -237,6 +246,12 @@ export const ModelAddDialog = ({ isOpen, onClose, onSuccess }: ModelAddDialogPro
237246

238247
// Handle adding a model
239248
const handleAddModel = async () => {
249+
// Check connectivity status before adding
250+
if (!form.isBatchImport && connectivityStatus.status !== 'available') {
251+
message.warning(t('model.dialog.error.connectivityRequired'))
252+
return
253+
}
254+
240255
setLoading(true)
241256
if (form.isBatchImport) {
242257
await handleBatchAddModel()
@@ -760,7 +775,7 @@ export const ModelAddDialog = ({ isOpen, onClose, onSuccess }: ModelAddDialogPro
760775
<Button
761776
type="primary"
762777
onClick={handleAddModel}
763-
disabled={!isFormValid()}
778+
disabled={!isFormValid() || (!form.isBatchImport && connectivityStatus.status !== 'available')}
764779
loading={loading}
765780
>
766781
{t('model.dialog.button.add')}

frontend/public/locales/en/common.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@
556556
"model.dialog.warning.incompleteForm": "Please complete the model configuration information first",
557557
"model.dialog.status.verifying": "Verifying model connectivity...",
558558
"model.dialog.success.connectivityVerified": "Model connectivity verification successful!",
559+
"model.dialog.error.connectivityRequired": "Please verify model connectivity and ensure connection is successful before adding the model",
559560
"model.dialog.error.addFailed": "Failed to add model: {{error}}",
560561
"model.dialog.error.addFailedLog": "Failed to add model",
561562
"model.dialog.error.noModelsFetched": "Please check your API key and network connectivity",

frontend/public/locales/zh/common.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@
556556
"model.dialog.help.content.batchImport": "请填写提供商的基本信息,API Key和提供商名称为必填项,其他字段为可选项。详细配置方法请参考[模型配置](https://modelengine-group.github.io/nexent/zh/user-guide/model-configuration.html)。",
557557
"model.dialog.warning.incompleteForm": "请先填写完整的模型配置信息",
558558
"model.dialog.status.verifying": "正在验证模型连通性...",
559+
"model.dialog.error.connectivityRequired": "请先验证模型连通性且确保连接成功后再添加模型",
559560
"model.dialog.error.addFailed": "添加模型失败:{{error}}",
560561
"model.dialog.error.addFailedLog": "添加模型失败",
561562
"model.dialog.error.noModelsFetched": "请检查相关API Key以及网络连通性",

frontend/services/modelService.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export const modelService = {
153153

154154
if (response.status !== 200) {
155155
throw new ModelError(
156-
result.message || "添加自定义模型失败",
156+
result.detail || result.message || "添加自定义模型失败",
157157
response.status
158158
);
159159
}
@@ -186,7 +186,7 @@ export const modelService = {
186186

187187
if (response.status !== 200) {
188188
throw new ModelError(
189-
result.message || "添加自定义模型失败",
189+
result.detail || result.message || "添加自定义模型失败",
190190
response.status
191191
);
192192
}
@@ -218,7 +218,7 @@ export const modelService = {
218218

219219
if (response.status !== 200) {
220220
throw new ModelError(
221-
result.message || "添加自定义模型失败",
221+
result.detail || result.message || "添加自定义模型失败",
222222
response.status
223223
);
224224
}
@@ -252,7 +252,7 @@ export const modelService = {
252252
log.log("getProviderSelectedModalList result", result);
253253
if (response.status !== 200) {
254254
throw new ModelError(
255-
result.message || "获取模型列表失败",
255+
result.detail || result.message || "获取模型列表失败",
256256
response.status
257257
);
258258
}
@@ -290,7 +290,7 @@ export const modelService = {
290290
const result = await response.json();
291291
if (response.status !== 200) {
292292
throw new ModelError(
293-
result.message || "Failed to update the custom model",
293+
result.detail || result.message || "Failed to update the custom model",
294294
response.status
295295
);
296296
}
@@ -322,7 +322,7 @@ export const modelService = {
322322
const result = await response.json();
323323
if (response.status !== 200) {
324324
throw new ModelError(
325-
result.message || "Failed to update the custom model",
325+
result.detail || result.message || "Failed to update the custom model",
326326
response.status
327327
);
328328
}
@@ -346,7 +346,7 @@ export const modelService = {
346346
const result = await response.json();
347347
if (response.status !== 200) {
348348
throw new ModelError(
349-
result.message || "删除自定义模型失败",
349+
result.detail || result.message || "删除自定义模型失败",
350350
response.status
351351
);
352352
}
@@ -419,12 +419,14 @@ export const modelService = {
419419
return {
420420
connectivity: result.data.connectivity,
421421
model_name: result.data.model_name || "UNKNOWN_MODEL",
422+
error: result.data.connectivity ? undefined : result.data.error || result.detail || result.message,
422423
};
423424
}
424425

425426
return {
426427
connectivity: false,
427428
model_name: result.data?.model_name || "UNKNOWN_MODEL",
429+
error: result.detail || result.message || "Connection verification failed",
428430
};
429431
} catch (error) {
430432
if (error instanceof Error && error.name === "AbortError") {
@@ -435,6 +437,7 @@ export const modelService = {
435437
return {
436438
connectivity: false,
437439
model_name: "UNKNOWN_MODEL",
440+
error: error instanceof Error ? error.message : String(error),
438441
};
439442
}
440443
},

frontend/types/modelConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export interface GlobalConfig {
8888
export interface ModelValidationResponse {
8989
connectivity: boolean;
9090
model_name: string;
91+
error?: string; // Error message when connectivity fails
9192
}
9293

9394
// Model engine check result interface

0 commit comments

Comments
 (0)