diff --git a/README.md b/README.md index a952ba30..8bf9995b 100644 --- a/README.md +++ b/README.md @@ -15,17 +15,33 @@ SQLBot 是一款基于大模型和 RAG 的智能问数系统。SQLBot 的优势 ## 快速开始 -准备一台 Linux 机器,执行一键安装脚本: +### 安装部署 -``` -docker run -d --name=sqlbot --restart=always -p 8080:8080 -v ~/.sqlbot:/var/lib/postgresql/data -v ~/.python-packages:/opt/sqlbot/app/sandbox/python-packages registry.fit2cloud.com/sqlbot/sqlbot +准备一台 Linux 服务器,执行以下一键安装脚本。 +在运行 SQLBot 前,请确保已安装好 [Docker](https://docs.docker.com/get-docker/) 和 [Docker Compose](https://docs.docker.com/compose/install/)。 -# 用户名: admin -# 密码: SQLBot@123.. +```bash +# 创建目录 +mkdir -p /opt/sqlbot +cd /opt/sqlbot + +# 下载 docker-compose.yaml +curl -o docker-compose.yaml https://raw.githubusercontent.com/dataease/SQLBot/main/docker-compose.yaml + +# 启动服务 +docker compose up -d ``` 你也可以通过 [1Panel 应用商店](https://apps.fit2cloud.com/1panel) 快速部署 SQLBot; +### 访问方式 + +- 在浏览器中打开: http://<你的服务器IP>:8000/ +- 用户名: admin +- 密码: SQLBot@123456 + +### 联系我们 + 如你有更多问题,可以加入我们的技术交流群与我们交流。 TBD: 交流群二维码 diff --git a/backend/apps/ai_model/model_factory.py b/backend/apps/ai_model/model_factory.py index 7a65f873..0ba82c42 100644 --- a/backend/apps/ai_model/model_factory.py +++ b/backend/apps/ai_model/model_factory.py @@ -1,3 +1,4 @@ +from functools import lru_cache import json from abc import ABC, abstractmethod from typing import Optional, Dict, Any, Type @@ -21,6 +22,18 @@ class LLMConfig(BaseModel): api_key: Optional[str] = None api_base_url: Optional[str] = None additional_params: Dict[str, Any] = {} + class Config: + frozen = True + + def __hash__(self): + return hash(( + self.model_id, + self.model_type, + self.model_name, + self.api_key, + self.api_base_url, + frozenset(self.additional_params.items()) + )) class BaseLLM(ABC): @@ -66,6 +79,7 @@ class LLMFactory: } @classmethod + @lru_cache(maxsize=32) def create_llm(cls, config: LLMConfig) -> BaseLLM: llm_class = cls._llm_types.get(config.model_type) if not llm_class: diff --git a/backend/apps/system/api/aimodel.py b/backend/apps/system/api/aimodel.py index be5a46b9..d2127cde 100644 --- a/backend/apps/system/api/aimodel.py +++ b/backend/apps/system/api/aimodel.py @@ -27,12 +27,8 @@ async def check_llm(info: AiModelCreator, trans: Trans): additional_params=additional_params, ) llm_instance = LLMFactory.create_llm(config) - - res = llm_instance.llm.stream("who are you?") - - for chunk in res: + async for chunk in llm_instance.llm.astream("1+1=?"): if chunk and chunk.content: - SQLBotLogUtil.info(chunk) yield json.dumps({"content": chunk.content}) + "\n" except Exception as e: diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..d212c54e --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,62 @@ +services: + sqlbot: + image: dataease/sqlbot:v0.9.3 + container_name: sqlbot + restart: always + networks: + - sqlbot-network + ports: + - 8000:8000 + - 8001:8001 + environment: + # Database configuration + POSTGRES_SERVER: sqlbot-db + POSTGRES_PORT: 5432 + POSTGRES_DB: sqlbot + POSTGRES_USER: sqlbot + POSTGRES_PASSWORD: sqlbot + # Project basic settings + PROJECT_NAME: "SQLBot" + DEFAULT_PWD: "SQLBot@123456" + # MCP settings + MCP_IMAGE_PATH: /opt/sqlbot/images + MCP_IMAGE_HOST: http://localhost:3000 + SERVER_IMAGE_HOST: https://sqlbot.fit2cloud.cn/images/ + # Auth & Security + TOKEN_KEY: "X-SQLBOT-TOKEN" + ASSISTANT_TOKEN_KEY: "X-SQLBOT-ASSISTANT-TOKEN" + SECRET_KEY: y5txe1mRmS_JpOrUzFzHEu-kIQn3lf7ll0AOv9DQh0s + # CORS settings + BACKEND_CORS_ORIGINS: "http://localhost,http://localhost:5173,https://localhost,https://localhost:5173" + # Logging + LOG_LEVEL: "INFO" + LOG_DIR: "/opt/sqlbot/logs" + LOG_FORMAT: "%(asctime)s - %(name)s - %(levelname)s:%(lineno)d - %(message)s" + SQL_DEBUG: False + volumes: + - ./data/sqlbot/excel:/opt/sqlbot/data/excel + - ./data/sqlbot/images:/opt/sqlbot/images + - ./data/sqlbot/logs:/opt/sqlbot/logs + depends_on: + sqlbot-db: + condition: service_healthy + + sqlbot-db: + image: postgres:17.5 + container_name: sqlbot-db + restart: always + networks: + - sqlbot-network + volumes: + - ./data/postgresql:/var/lib/postgresql/data + environment: + POSTGRES_DB: sqlbot + POSTGRES_USER: sqlbot + POSTGRES_PASSWORD: sqlbot + healthcheck: + test: ["CMD-SHELL", "pg_isready"] + interval: 3s + timeout: 5s + retries: 5 +networks: + sqlbot-network: diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 7a27e4c2..22e37381 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -1,7 +1,7 @@ { "menu": { "Data Q&A": "Data Q&A", - "Data Connections": "Data Connections", + "Data Connections": "Data Sources", "Dashboard": "Dashboard", "AI Model Configuration": "AI Model Configuration" }, @@ -98,8 +98,8 @@ }, "qa": { "new_chat": "New Chat", - "start_sqlbot": "Start SQLBot", - "title": "Smart Data Query", + "start_sqlbot": "New Chat", + "title": "Data Q&A", "placeholder": "Please enter your question", "ask": "Ask", "loading": "Loading...", @@ -111,7 +111,7 @@ "select_datasource": "Select Data Source", "view_more": "View More", "selected_datasource": "Selected Data Source", - "empty_datasource": "No data sources available. Please create one before starting Smart Data Query!", + "empty_datasource": "No data sources available. Please create one before starting Data Q&A!", "datasource_not_exist": "Data source does not exist", "guess_u_ask": "You might want to ask:", "continue_to_ask": "Continue asking:", @@ -130,7 +130,7 @@ "copied": "Copied" }, "ds": { - "title": "Data Source", + "title": "Data Sources", "add": "Add Data Source", "delete": "Delete Data Source", "name": "Data Source Name", @@ -225,7 +225,7 @@ "search": "Search", "all_types": "All types", "new_data_source": "New data source", - "open_query": "Open query", + "open_query": "New Chat", "edit": "Edit", "source_connection_failed": "Data source connection failed", "confirm": "Confirm", @@ -365,7 +365,7 @@ "add_successfully": "Add successfully", "member_management": "Member management", "permission_configuration": "Permission configuration", - "set": "Set", + "set": "Settings", "operate_with_caution": "After deletion, the users under the workspace will be removed and all resources will be deleted. Please operate with caution." }, "permission": { diff --git a/frontend/src/views/system/model/Model.vue b/frontend/src/views/system/model/Model.vue index 0849c077..4088307c 100644 --- a/frontend/src/views/system/model/Model.vue +++ b/frontend/src/views/system/model/Model.vue @@ -35,7 +35,7 @@ const activeName = ref('') const activeType = ref('') const modelFormRef = ref() const cardRefs = ref([]) -// const showCardError = ref(true) // if you don`t want card mask error, just change this to false +const showCardError = ref(false) // if you don`t want card mask error, just change this to false reactive({ form: { id: '', @@ -71,8 +71,6 @@ const defaultModelListWithSearch = computed(() => { }) const modelCheckHandler = async (item: any) => { - console.log(item) - /** const response = await modelApi.check(item) const reader = response.body.getReader() const decoder = new TextDecoder() @@ -112,7 +110,6 @@ const modelCheckHandler = async (item: any) => { currentRef?.showErrorMask(checkMsg) } }) - */ } const duplicateName = async (item: any) => { const res = await modelApi.queryAll()