diff --git a/.typos.toml b/.typos.toml
new file mode 100644
index 00000000..bb9c4600
--- /dev/null
+++ b/.typos.toml
@@ -0,0 +1,5 @@
+[default.extend-words]
+[default.extend-identifiers]
+maintain_column_froms = "maintain_column_froms"
+[files]
+extend-exclude = ["frontend/public", "backend/alembic/versions"]
diff --git a/backend/apps/chat/task/llm.py b/backend/apps/chat/task/llm.py
index 060bacc9..e5d3a083 100644
--- a/backend/apps/chat/task/llm.py
+++ b/backend/apps/chat/task/llm.py
@@ -296,7 +296,7 @@ class LLMService:
# get schema
if self.ds and not self.chat_question.db_schema:
- self.chat_question.db_schema = get_table_schema(session=self.session, ds=self.ds)
+ self.chat_question.db_schema = get_table_schema(session=self.session, current_user=self.current_user, ds=self.ds)
guess_msg: List[Union[BaseMessage, dict[str, Any]]] = []
guess_msg.append(SystemMessage(content=self.chat_question.guess_sys_question()))
@@ -726,7 +726,7 @@ def run_task(llm_service: LLMService, in_chat: bool = True):
yield orjson.dumps({'id': llm_service.ds.id, 'datasource_name': llm_service.ds.name,
'engine_type': llm_service.ds.type_name, 'type': 'datasource'}).decode() + '\n\n'
- llm_service.chat_question.db_schema = get_table_schema(session=llm_service.session, ds=llm_service.ds)
+ llm_service.chat_question.db_schema = get_table_schema(session=llm_service.session, current_user=llm_service.current_user, ds=llm_service.ds)
# generate sql
sql_res = llm_service.generate_sql()
diff --git a/backend/apps/datasource/api/datasource.py b/backend/apps/datasource/api/datasource.py
index b0921673..6e2761f5 100644
--- a/backend/apps/datasource/api/datasource.py
+++ b/backend/apps/datasource/api/datasource.py
@@ -9,7 +9,7 @@ from fastapi import APIRouter, File, UploadFile, HTTPException
from apps.db.engine import create_table, get_data_engine, insert_data
from common.core.deps import SessionDep, CurrentUser
from ..crud.datasource import get_datasource_list, check_status, create_ds, update_ds, delete_ds, getTables, getFields, \
- execSql, update_table_and_fields, getTablesByDs, chooseTables, preview, updateTable, updateField, get_ds
+ execSql, update_table_and_fields, getTablesByDs, chooseTables, preview, updateTable, updateField, get_ds, fieldEnum
from ..crud.field import get_fields_by_table_id
from ..crud.table import get_tables_by_ds_id
from ..models.datasource import CoreDatasource, CreateDatasource, TableObj, CoreTable, CoreField
@@ -103,6 +103,11 @@ async def edit_local(session: SessionDep, id: int, data: TableObj):
return preview(session, id, data)
+@router.post("/fieldEnum/{id}")
+async def field_enum(session: SessionDep, id: int):
+ return fieldEnum(session, id)
+
+
@router.post("/uploadExcel")
async def upload_excel(session: SessionDep, file: UploadFile = File(...)):
ALLOWED_EXTENSIONS = {"xlsx", "xls", "csv"}
diff --git a/backend/apps/datasource/crud/datasource.py b/backend/apps/datasource/crud/datasource.py
index 9430a79f..f2a31b82 100644
--- a/backend/apps/datasource/crud/datasource.py
+++ b/backend/apps/datasource/crud/datasource.py
@@ -9,9 +9,9 @@ from sqlbot_xpack.permissions.models.ds_rules import DsRules
from sqlmodel import select
from apps.datasource.utils.utils import aes_decrypt
+from apps.db.constant import DB
from apps.db.db import get_engine, get_tables, get_fields, exec_sql
-from apps.db.engine import get_engine_config
-from apps.db.engine import get_engine_conn
+from apps.db.engine import get_engine_config, get_engine_conn
from apps.db.type import db_type_relation
from common.core.deps import SessionDep, CurrentUser
from common.utils.utils import deepcopy_ignore_extra
@@ -245,6 +245,23 @@ def preview(session: SessionDep, id: int, data: TableObj):
return exec_sql(ds, sql)
+def fieldEnum(session: SessionDep, id: int):
+ field = session.query(CoreField).filter(CoreField.id == id).first()
+ if field is None:
+ return []
+ table = session.query(CoreTable).filter(CoreTable.id == field.table_id).first()
+ if table is None:
+ return []
+ ds = session.query(CoreDatasource).filter(CoreDatasource.id == table.ds_id).first()
+ if ds is None:
+ return []
+
+ db = DB.get_db(ds.type)
+ sql = f"""SELECT DISTINCT {db.prefix}{field.field_name}{db.suffix} FROM {db.prefix}{table.table_name}{db.suffix}"""
+ res = exec_sql(ds, sql)
+ return [item.get(res.get('fields')[0]) for item in res.get('data')]
+
+
def updateNum(session: SessionDep, ds: CoreDatasource):
all_tables = get_tables(ds)
selected_tables = get_tables_by_ds_id(session, ds.id)
diff --git a/backend/apps/db/constant.py b/backend/apps/db/constant.py
new file mode 100644
index 00000000..51126272
--- /dev/null
+++ b/backend/apps/db/constant.py
@@ -0,0 +1,24 @@
+# Author: Junjun
+# Date: 2025/7/16
+
+from enum import Enum
+
+
+class DB(Enum):
+ mysql = ('mysql', '`', '`')
+ sqlServer = ('sqlServer', '[', ']')
+ pg = ('pg', '"', '"')
+ excel = ('excel', '"', '"')
+ oracle = ('oracle', '"', '"')
+
+ def __init__(self, type, prefix, suffix):
+ self.type = type
+ self.prefix = prefix
+ self.suffix = suffix
+
+ @classmethod
+ def get_db(cls, type):
+ for db in cls:
+ if db.type == type:
+ return db
+ raise ValueError(f"Invalid db type: {type}")
diff --git a/backend/apps/system/api/workspace.py b/backend/apps/system/api/workspace.py
index ee67bfd3..8725cffc 100644
--- a/backend/apps/system/api/workspace.py
+++ b/backend/apps/system/api/workspace.py
@@ -3,7 +3,7 @@ from fastapi import APIRouter, Query
from sqlmodel import exists, or_, select
from apps.system.models.system_model import UserWsModel, WorkspaceBase, WorkspaceEditor, WorkspaceModel
from apps.system.models.user import UserModel
-from apps.system.schemas.system_schema import UserWsBase, UserWsDTO, UserWsOption, WorkspaceUser
+from apps.system.schemas.system_schema import UserWsBase, UserWsDTO, UserWsEditor, UserWsOption, WorkspaceUser
from common.core.deps import CurrentUser, SessionDep, Trans
from common.core.pagination import Paginator
from common.core.schemas import PaginatedResponse, PaginationParams
@@ -42,6 +42,29 @@ async def option_pager(
stmt=stmt,
pagination=pagination,
)
+
+@router.get("/uws/option", response_model=UserWsOption)
+async def option_user(
+ session: SessionDep,
+ current_user: CurrentUser,
+ keyword: str = Query(description="搜索关键字")
+ ):
+ if (not current_user.isAdmin) and current_user.weight == 0:
+ raise RuntimeError("no permission to execute this api")
+ oid = current_user.oid
+
+ stmt = select(UserModel.id, UserModel.account, UserModel.name).where(
+ ~exists().where(UserWsModel.uid == UserModel.id, UserWsModel.oid == oid)
+ )
+
+ if keyword:
+ stmt = stmt.where(
+ or_(
+ UserModel.account == int(keyword),
+ UserModel.name == keyword,
+ )
+ )
+ return session.exec(stmt).first()
@router.get("/uws/pager/{pageNum}/{pageSize}", response_model=PaginatedResponse[WorkspaceUser])
async def pager(
@@ -95,6 +118,20 @@ async def create(session: SessionDep, creator: UserWsDTO):
session.add_all(db_model_list)
session.commit()
+@router.put("/uws")
+async def edit(session: SessionDep, editor: UserWsEditor):
+ if not editor.oid or not editor.uid:
+ raise RuntimeError("param [oid, uid] miss")
+ db_model = session.exec(select(UserWsModel).where(UserWsModel.uid == editor.uid, UserWsModel.oid == editor.oid)).first()
+ if not db_model:
+ raise RuntimeError("uws not exist")
+ if editor.weight == db_model.weight:
+ return
+
+ db_model.weight = editor.weight
+ session.add(db_model)
+ session.commit()
+
@router.delete("/uws")
async def delete(session: SessionDep, dto: UserWsBase):
db_model_list: list[UserWsModel] = session.exec(select(UserWsModel).where(UserWsModel.uid.in_(dto.uid_list), UserWsModel.oid == dto.oid)).all()
diff --git a/backend/apps/system/schemas/system_schema.py b/backend/apps/system/schemas/system_schema.py
index 9ca08457..8b1f3b99 100644
--- a/backend/apps/system/schemas/system_schema.py
+++ b/backend/apps/system/schemas/system_schema.py
@@ -50,7 +50,11 @@ class UserWsBase(BaseModel):
oid: int
class UserWsDTO(UserWsBase):
weight: int = 0
-
+
+class UserWsEditor(BaseModel):
+ uid: int
+ oid: int
+ weight: int = 0
class UserInfoDTO(UserEditor):
language: str = "zh-CN"
diff --git a/frontend/src/assets/svg/icon_new_chat_outlined.svg b/frontend/src/assets/svg/icon_new_chat_outlined.svg
index c1ff4c6f..3bb65ed6 100644
--- a/frontend/src/assets/svg/icon_new_chat_outlined.svg
+++ b/frontend/src/assets/svg/icon_new_chat_outlined.svg
@@ -1,4 +1 @@
-
+
\ No newline at end of file
diff --git a/frontend/src/views/chat/index.vue b/frontend/src/views/chat/index.vue
index 65446265..b91f96b4 100644
--- a/frontend/src/views/chat/index.vue
+++ b/frontend/src/views/chat/index.vue
@@ -72,11 +72,14 @@
v-if="currentChatId === undefined"
size="large"
type="primary"
+ class="greeting-btn"
@click="createNewChat"
>
-