diff --git a/backend/apps/ai_model/model_factory.py b/backend/apps/ai_model/model_factory.py index 0ba82c42..66c93997 100644 --- a/backend/apps/ai_model/model_factory.py +++ b/backend/apps/ai_model/model_factory.py @@ -110,7 +110,7 @@ def get_default_config() -> LLMConfig: select(AiModelDetail).where(AiModelDetail.default_model == True) ).first() if not db_model: - raise ValueError("The system default model has not been set") + raise Exception("The system default model has not been set") additional_params = {} if db_model.config: diff --git a/backend/apps/system/api/aimodel.py b/backend/apps/system/api/aimodel.py index d2127cde..7c20f0d7 100644 --- a/backend/apps/system/api/aimodel.py +++ b/backend/apps/system/api/aimodel.py @@ -38,6 +38,33 @@ async def check_llm(info: AiModelCreator, trans: Trans): return StreamingResponse(generate(), media_type="application/x-ndjson") +@router.get("/default") +async def check_default(session: SessionDep, trans: Trans): + db_model = session.exec( + select(AiModelDetail).where(AiModelDetail.default_model == True) + ).first() + if not db_model: + raise Exception(trans('i18n_llm.miss_default')) + +@router.put("/default/{id}") +async def set_default(session: SessionDep, id: int): + db_model = session.get(AiModelDetail, id) + if not db_model: + raise ValueError(f"AiModelDetail with id {id} not found") + if db_model.default_model: + return + + try: + session.exec( + update(AiModelDetail).values(default_model=False) + ) + db_model.default_model = True + session.add(db_model) + session.commit() + except Exception as e: + session.rollback() + raise e + @router.get("", response_model=list[AiModelGridItem]) async def query( session: SessionDep, @@ -119,22 +146,5 @@ async def delete_model( session.delete(item) session.commit() -@router.put("/default/{id}") -async def set_default(session: SessionDep, id: int): - db_model = session.get(AiModelDetail, id) - if not db_model: - raise ValueError(f"AiModelDetail with id {id} not found") - if db_model.default_model: - return - try: - session.exec( - update(AiModelDetail).values(default_model=False) - ) - db_model.default_model = True - session.add(db_model) - session.commit() - except Exception as e: - session.rollback() - raise e \ No newline at end of file diff --git a/backend/locales/en.json b/backend/locales/en.json index ffe76fd3..b287e351 100644 --- a/backend/locales/en.json +++ b/backend/locales/en.json @@ -29,6 +29,7 @@ }, "i18n_llm": { "validate_error": "Validation failed [{msg}]", - "delete_default_error": "Cannot delete default model [{key}]!" + "delete_default_error": "Cannot delete default model [{key}]!", + "miss_default": "The default large language model has not been configured" } } \ No newline at end of file diff --git a/backend/locales/zh-CN.json b/backend/locales/zh-CN.json index 2a63da7f..20835e97 100644 --- a/backend/locales/zh-CN.json +++ b/backend/locales/zh-CN.json @@ -30,6 +30,7 @@ }, "i18n_llm": { "validate_error": "校验失败[{msg}]", - "delete_default_error": "无法删除默认模型[{key}]!" + "delete_default_error": "无法删除默认模型[{key}]!", + "miss_default": "尚未配置默认大语言模型" } } \ No newline at end of file diff --git a/frontend/src/api/chat.ts b/frontend/src/api/chat.ts index e28a5bf3..90df3be0 100644 --- a/frontend/src/api/chat.ts +++ b/frontend/src/api/chat.ts @@ -328,4 +328,5 @@ export const chatApi = { recommendQuestions: (record_id: number | undefined, controller?: AbortController) => { return request.fetchStream(`/chat/recommend_questions/${record_id}`, {}, controller) }, + checkLLMModel: () => request.get('/system/aimodel/default', { requestOptions: { silent: true } }), } diff --git a/frontend/src/entity/supplier.ts b/frontend/src/entity/supplier.ts index 7e0a1aa0..a01d19fa 100644 --- a/frontend/src/entity/supplier.ts +++ b/frontend/src/entity/supplier.ts @@ -22,7 +22,7 @@ export const supplierList: Array<{ }, { id: 2, - name: '千帆大模型I', + name: '千帆大模型', icon: icon_bdyzn_colorful, model_config: { 0: { diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index d0a28174..4ce6bb86 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -133,7 +133,8 @@ "no_time": "No Time", "rename_conversation_title": "Rename conversation title", "conversation_title": "Conversation title", - "copied": "Copied" + "copied": "Copied", + "ask_failed": "Q&A failed" }, "ds": { "title": "Data Sources", @@ -291,7 +292,10 @@ "del_default_tip": "Unable to delete the model: {msg}", "del_default_warn": "This model is the system default model. Please set another model as the system default before deleting this model.", "del_warn_tip": "Would you like to remove the model: {msg}?", - "check_failed": "Model is invalid [{msg}]" + "check_failed": "Model is invalid [{msg}]", + "default_miss": "The default llm has not been configured yet, so the q&a feature cannot be enabled, Please contact the administrator to configure it.", + "default_miss_admin": "The default llm has not been configured yet, so the q&a feature cannot be enabled.", + "to_config": "Go to configuration" }, "user": { "workspace": "Workspace", diff --git a/frontend/src/i18n/zh-CN.json b/frontend/src/i18n/zh-CN.json index cf92151f..909e3c4d 100644 --- a/frontend/src/i18n/zh-CN.json +++ b/frontend/src/i18n/zh-CN.json @@ -133,7 +133,8 @@ "no_time": "没有时间", "rename_conversation_title": "重命名对话标题", "conversation_title": "对话标题", - "copied": "已复制" + "copied": "已复制", + "ask_failed": "问数失败" }, "ds": { "title": "数据源", @@ -291,7 +292,10 @@ "del_default_tip": "无法删除模型: {msg}", "del_default_warn": "该模型为系统默认模型,请先设置其他模型为系统默认模型,再删除此模型。", "del_warn_tip": "是否删除模型: {msg}?", - "check_failed": "模型无效【{msg}】" + "check_failed": "模型无效【{msg}】", + "default_miss": "尚未配置默认大语言大模型,因此无法开启问数,请联系管理员配置。", + "default_miss_admin": "尚未配置默认大语言大模型,因此无法开启问数。", + "to_config": "去配置" }, "user": { "workspace": "工作空间", diff --git a/frontend/src/views/chat/ChatListContainer.vue b/frontend/src/views/chat/ChatListContainer.vue index 0e2c2104..68107b01 100644 --- a/frontend/src/views/chat/ChatListContainer.vue +++ b/frontend/src/views/chat/ChatListContainer.vue @@ -9,7 +9,9 @@ import ChatCreator from '@/views/chat/ChatCreator.vue' import { useAssistantStore } from '@/stores/assistant' import icon_sidebar_outlined from '@/assets/svg/icon_sidebar_outlined.svg' import icon_new_chat_outlined from '@/assets/svg/icon_new_chat_outlined.svg' - +import { useUserStore } from '@/stores/user' +import router from '@/router' +const userStore = useUserStore() const props = withDefaults( defineProps<{ inPopover?: boolean @@ -112,6 +114,33 @@ function goEmpty(func?: (...p: any[]) => void, ...params: any[]) { } const createNewChat = async () => { + try { + await chatApi.checkLLMModel() + } catch (error: any) { + console.error(error) + let errorMsg = t('model.default_miss') + let confirm_text = t('datasource.got_it') + if (userStore.isAdmin) { + errorMsg = t('model.default_miss_admin') + confirm_text = t('model.to_config') + } + ElMessageBox.confirm(t('qa.ask_failed'), { + confirmButtonType: 'primary', + tip: errorMsg, + showCancelButton: userStore.isAdmin, + confirmButtonText: confirm_text, + cancelButtonText: t('common.cancel'), + customClass: 'confirm-no_icon', + autofocus: false, + showClose: false, + callback: (val: string) => { + if (userStore.isAdmin && val === 'confirm') { + router.push('/system/model') + } + }, + }) + return + } goEmpty(doCreateNewChat) } diff --git a/frontend/src/views/chat/index.vue b/frontend/src/views/chat/index.vue index 5cc919d8..3354b877 100644 --- a/frontend/src/views/chat/index.vue +++ b/frontend/src/views/chat/index.vue @@ -356,7 +356,9 @@ import logo from '@/assets/LOGO.svg' import icon_send_filled from '@/assets/svg/icon_send_filled.svg' import { useAssistantStore } from '@/stores/assistant' import { onClickOutside } from '@vueuse/core' - +import { useUserStore } from '@/stores/user' +import router from '@/router' +const userStore = useUserStore() const props = defineProps<{ startChatDsId?: number }>() @@ -437,6 +439,33 @@ const createNewChatSimple = async () => { } const createNewChat = async () => { + try { + await chatApi.checkLLMModel() + } catch (error: any) { + console.error(error) + let errorMsg = t('model.default_miss') + let confirm_text = t('datasource.got_it') + if (userStore.isAdmin) { + errorMsg = t('model.default_miss_admin') + confirm_text = t('model.to_config') + } + ElMessageBox.confirm(t('qa.ask_failed'), { + confirmButtonType: 'primary', + tip: errorMsg, + showCancelButton: userStore.isAdmin, + confirmButtonText: confirm_text, + cancelButtonText: t('common.cancel'), + customClass: 'confirm-no_icon', + autofocus: false, + showClose: false, + callback: (val: string) => { + if (userStore.isAdmin && val === 'confirm') { + router.push('/system/model') + } + }, + }) + return + } goEmpty() if (isAssistant.value) { currentChat.value = new ChatInfo() diff --git a/frontend/src/views/ds/Datasource.vue b/frontend/src/views/ds/Datasource.vue index ef609561..a7ecefe7 100644 --- a/frontend/src/views/ds/Datasource.vue +++ b/frontend/src/views/ds/Datasource.vue @@ -18,7 +18,9 @@ import Card from './Card.vue' import DelMessageBox from './DelMessageBox.vue' import { dsTypeWithImg } from './js/ds-type' import { useI18n } from 'vue-i18n' - +import { useUserStore } from '@/stores/user' +import { chatApi } from '@/api/chat' +const userStore = useUserStore() interface Datasource { name: string num: string @@ -99,7 +101,34 @@ const handleEditDatasource = (res: any) => { }) } -const handleQuestion = (id: string) => { +const handleQuestion = async (id: string) => { + try { + await chatApi.checkLLMModel() + } catch (error: any) { + console.error(error) + let errorMsg = t('model.default_miss') + let confirm_text = t('datasource.got_it') + if (userStore.isAdmin) { + errorMsg = t('model.default_miss_admin') + confirm_text = t('model.to_config') + } + ElMessageBox.confirm(t('qa.ask_failed'), { + confirmButtonType: 'primary', + tip: errorMsg, + showCancelButton: userStore.isAdmin, + confirmButtonText: confirm_text, + cancelButtonText: t('common.cancel'), + customClass: 'confirm-no_icon', + autofocus: false, + showClose: false, + callback: (val: string) => { + if (userStore.isAdmin && val === 'confirm') { + router.push('/system/model') + } + }, + }) + return + } router.push({ path: '/chat/index', query: {