diff --git a/backend/apps/system/api/assistant.py b/backend/apps/system/api/assistant.py index 962a1f04..40aa8814 100644 --- a/backend/apps/system/api/assistant.py +++ b/backend/apps/system/api/assistant.py @@ -6,7 +6,7 @@ from apps.system.crud.assistant import get_assistant_info from apps.system.models.system_model import AssistantModel from apps.system.schemas.auth import CacheName, CacheNamespace from apps.system.schemas.system_schema import AssistantBase, AssistantDTO, AssistantValidator -from common.core.deps import SessionDep +from common.core.deps import SessionDep, Trans from common.core.security import create_access_token from common.core.sqlbot_cache import clear_cache from common.utils.time import get_timestamp @@ -15,7 +15,7 @@ from common.core.config import settings router = APIRouter(tags=["system/assistant"], prefix="/system/assistant") @router.get("/info/{id}") -async def info(request: Request, response: Response, session: SessionDep, id: int) -> AssistantModel: +async def info(request: Request, response: Response, session: SessionDep, trans: Trans, id: int) -> AssistantModel: if not id: raise Exception('miss assistant id') db_model = await get_assistant_info(session=session, assistant_id=id) @@ -26,7 +26,7 @@ async def info(request: Request, response: Response, session: SessionDep, id: in origin = request.headers.get("origin") or request.headers.get("referer") origin = origin.rstrip('/') if origin != db_model.domain: - raise RuntimeError("invalid domain [{origin}]") + raise RuntimeError(trans('i18n_embedded.invalid_origin', origin = origin or '')) return db_model @router.get("/validator", response_model=AssistantValidator) diff --git a/backend/locales/en.json b/backend/locales/en.json index 8d5860eb..e16612b5 100644 --- a/backend/locales/en.json +++ b/backend/locales/en.json @@ -32,5 +32,8 @@ "delete_default_error": "Cannot delete default model [{key}]!", "miss_default": "The default large language model has not been configured" }, - "i18n_ds_invalid": "Datasource Invalid" + "i18n_ds_invalid": "Datasource Invalid", + "i18n_embedded": { + "invalid_origin": "Domain verification failed [{origin}]" + } } \ No newline at end of file diff --git a/backend/locales/zh-CN.json b/backend/locales/zh-CN.json index 5eba5037..93da611a 100644 --- a/backend/locales/zh-CN.json +++ b/backend/locales/zh-CN.json @@ -33,5 +33,8 @@ "delete_default_error": "无法删除默认模型[{key}]!", "miss_default": "尚未配置默认大语言模型" }, - "i18n_ds_invalid": "数据源连接无效" + "i18n_ds_invalid": "数据源连接无效", + "i18n_embedded": { + "invalid_origin": "域名校验失败【{origin}】" + } } \ No newline at end of file diff --git a/frontend/public/assistant.js b/frontend/public/assistant.js index fd60c620..ef127fc5 100644 --- a/frontend/public/assistant.js +++ b/frontend/public/assistant.js @@ -455,6 +455,9 @@ fetch(url) .then((response) => response.json()) .then((res) => { + if (!res.data) { + throw new Error(res) + } const data = res.data const config_json = data.configuration let tempData = Object.assign(defaultData, { id, domain_url }) @@ -472,6 +475,9 @@ // postMessage the certificate to iframe } }) + .catch((e) => { + showMsg('嵌入失败', e.message) + }) } function getDomain(src) { return src.substring(0, src.indexOf('/assistant.js')) @@ -493,6 +499,109 @@ expposeGlobalMethods(id) }) } + + function showMsg(title, content) { + // 检查并创建容器(如果不存在) + let container = document.getElementById('messageContainer') + if (!container) { + container = document.createElement('div') + container.id = 'messageContainer' + container.style.position = 'fixed' + container.style.bottom = '20px' + container.style.right = '20px' + container.style.zIndex = '1000' + document.body.appendChild(container) + } else { + // 如果容器已存在,先移除旧弹窗 + const oldMessage = container.querySelector('div') + if (oldMessage) { + oldMessage.style.transform = 'translateX(120%)' + oldMessage.style.opacity = '0' + setTimeout(() => { + container.removeChild(oldMessage) + }, 300) + } + } + + // 创建弹窗元素 + const messageBox = document.createElement('div') + messageBox.style.width = '240px' + messageBox.style.minHeight = '100px' + messageBox.style.background = 'linear-gradient(135deg, #ff6b6b, #ff8e8e)' + messageBox.style.borderRadius = '8px' + messageBox.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)' + messageBox.style.padding = '15px' + messageBox.style.color = 'white' + messageBox.style.fontFamily = 'Arial, sans-serif' + messageBox.style.display = 'flex' + messageBox.style.flexDirection = 'column' + messageBox.style.transform = 'translateX(120%)' + messageBox.style.transition = 'transform 0.3s ease-out' + messageBox.style.opacity = '0' + messageBox.style.transition = 'opacity 0.3s ease, transform 0.3s ease' + messageBox.style.overflow = 'hidden' + + // 创建标题元素 + const titleElement = document.createElement('div') + titleElement.style.fontSize = '18px' + titleElement.style.fontWeight = 'bold' + titleElement.style.marginBottom = '10px' + titleElement.style.borderBottom = '1px solid rgba(255, 255, 255, 0.3)' + titleElement.style.paddingBottom = '8px' + titleElement.textContent = title + + // 创建内容元素 + const contentElement = document.createElement('div') + contentElement.style.fontSize = '14px' + contentElement.style.flexGrow = '1' + contentElement.style.overflow = 'auto' + contentElement.textContent = content + + // 组装元素 + messageBox.appendChild(titleElement) + messageBox.appendChild(contentElement) + + // 添加到容器 + container.appendChild(messageBox) + + // 触发显示动画 + setTimeout(() => { + messageBox.style.transform = 'translateX(0)' + messageBox.style.opacity = '1' + }, 10) + + // 3秒后自动隐藏 + setTimeout(() => { + messageBox.style.transform = 'translateX(120%)' + messageBox.style.opacity = '0' + setTimeout(() => { + container.removeChild(messageBox) + // 如果容器是空的,也移除容器 + if (container.children.length === 0) { + document.body.removeChild(container) + } + }, 300) + }, 5000) + } + + /* function hideMsg() { + const container = document.getElementById('messageContainer'); + if (container) { + const messageBox = container.querySelector('div'); + if (messageBox) { + messageBox.style.transform = 'translateX(120%)'; + messageBox.style.opacity = '0'; + setTimeout(() => { + container.removeChild(messageBox); + // 如果容器是空的,也移除容器 + if (container.children.length === 0) { + document.body.removeChild(container); + } + }, 300); + } + } + } */ + function updateParam(target_url, key, newValue) { try { const url = new URL(target_url)