This commit is contained in:
dataeaseShu
2025-07-30 17:32:04 +08:00
8 changed files with 27 additions and 23 deletions
+1 -8
View File
@@ -32,16 +32,9 @@ TBD: 交流群二维码
## UI 展示
<table style="border-collapse: collapse; border: 1px solid black;">
<tr>
<td style="padding: 5px;background-color:#fff;"><img src= "TBD" alt="SQLBot Demo1" /></td>
<td style="padding: 5px;background-color:#fff;"><img src= "TBD" alt="SQLBot Demo2" /></td>
<img alt="q&a" src="https://github.com/user-attachments/assets/55526514-52f3-4cfe-98ec-08a986259280" />
</tr>
<tr>
<td style="padding: 5px;background-color:#fff;"><img src= "TBD" alt="SQLBot Demo3" /></td>
<td style="padding: 5px;background-color:#fff;"><img src= "TBD" alt="SQLBot Demo4" /></td>
</tr>
</table>
## Star History
+2
View File
@@ -700,6 +700,8 @@ class LLMService:
def check_save_chart(self, res: str) -> Dict[str, Any]:
json_str = extract_nested_json(res)
if json_str is None:
raise Exception("Cannot parse chart config from answer")
data = orjson.loads(json_str)
chart: Dict[str, Any] = {}
+2
View File
@@ -26,6 +26,8 @@ def get_user_by_account(*, session: Session, account: str) -> BaseUserDTO | None
@cache(namespace=CacheNamespace.AUTH_INFO, cacheName=CacheName.USER_INFO, keyExpression="user_id")
async def get_user_info(*, session: Session, user_id: int) -> UserInfoDTO | None:
db_user: UserModel = get_db_user(session = session, user_id = user_id)
if not db_user:
return None
userInfo = UserInfoDTO.model_validate(db_user.model_dump())
userInfo.isAdmin = userInfo.id == 1 and userInfo.account == 'admin'
if userInfo.isAdmin:
+16 -12
View File
@@ -13,9 +13,11 @@ from apps.system.schemas.system_schema import AssistantHeader, UserInfoDTO
from common.core import security
from common.core.config import settings
from common.core.schemas import TokenPayload
from common.utils.locale import I18n
from common.utils.utils import SQLBotLogUtil
from common.utils.whitelist import whiteUtils
from fastapi.security.utils import get_authorization_scheme_param
from common.core.deps import get_i18n
class TokenMiddleware(BaseHTTPMiddleware):
@@ -29,6 +31,7 @@ class TokenMiddleware(BaseHTTPMiddleware):
return await call_next(request)
assistantTokenKey = settings.ASSISTANT_TOKEN_KEY
assistantToken = request.headers.get(assistantTokenKey)
trans = await get_i18n(request)
#if assistantToken and assistantToken.lower().startswith("assistant "):
if assistantToken:
validator: tuple[any] = await self.validateAssistant(assistantToken)
@@ -36,20 +39,23 @@ class TokenMiddleware(BaseHTTPMiddleware):
request.state.current_user = validator[1]
request.state.assistant = validator[2]
return await call_next(request)
return JSONResponse(f"Unauthorized:[{validator[1]}]", status_code=401, headers={"Access-Control-Allow-Origin": "*"})
message = trans('i18n_permission.authenticate_invalid', msg = validator[1])
return JSONResponse(message, status_code=401, headers={"Access-Control-Allow-Origin": "*"})
#validate pass
tokenkey = settings.TOKEN_KEY
token = request.headers.get(tokenkey)
validate_pass, data = await self.validateToken(token)
validate_pass, data = await self.validateToken(token, trans)
if validate_pass:
request.state.current_user = data
return await call_next(request)
return JSONResponse(f"Unauthorized:[{data}]", status_code=401, headers={"Access-Control-Allow-Origin": "*"})
message = trans('i18n_permission.authenticate_invalid', msg = data)
return JSONResponse(message, status_code=401, headers={"Access-Control-Allow-Origin": "*"})
def is_options(self, request: Request):
return request.method == "OPTIONS"
async def validateToken(self, token: Optional[str]):
async def validateToken(self, token: Optional[str], trans: I18n):
if not token:
return False, f"Miss Token[{settings.TOKEN_KEY}]!"
schema, param = get_authorization_scheme_param(token)
@@ -63,17 +69,15 @@ class TokenMiddleware(BaseHTTPMiddleware):
with Session(engine) as session:
session_user = await get_user_info(session = session, user_id = token_data.id)
if not session_user:
raise Exception(f"User not found with id: {token_data.id}")
message = trans('i18n_not_exist', msg = trans('i18n_user.account'))
raise Exception(message)
session_user = UserInfoDTO.model_validate(session_user)
if session_user.status != 1:
raise Exception(f"User is not active!")
message = trans('i18n_login.user_disable', msg = trans('i18n_concat_admin'))
raise Exception(message)
if not session_user.oid or session_user.oid == 0:
raise Exception(f"User default space is not set!")
""" if token_data.oid != session_user.oid:
raise HTTPException(
status_code=401,
detail="Default space has been changed, please login again!"
) """
message = trans('i18n_login.no_associated_ws', msg = trans('i18n_concat_admin'))
raise Exception(message)
return True, session_user
except Exception as e:
SQLBotLogUtil.exception(f"Token validation error: {str(e)}")
+2 -1
View File
@@ -24,7 +24,8 @@
},
"i18n_permission": {
"only_admin": "Only administrators can call this!",
"no_permission": "No permission to access {url}{msg}"
"no_permission": "No permission to access {url}{msg}",
"authenticate_invalid": "Authenticate invalid [{msg}]"
},
"i18n_llm": {
"validate_error": "Validation failed [{msg}]",
+2 -1
View File
@@ -24,7 +24,8 @@
},
"i18n_permission": {
"only_admin": "仅支持管理员调用!",
"no_permission": "无权调用{url}{msg}"
"no_permission": "无权调用{url}{msg}",
"authenticate_invalid": "认证无效【{msg}】"
},
"i18n_llm": {
+1 -1
View File
@@ -182,7 +182,7 @@ class HttpService {
setTimeout(() => {
wsCache.delete('user.token')
window.location.reload()
}, 1000)
}, 2000)
return
// break
case 403:
@@ -760,6 +760,7 @@ const saveHandler = () => {
:name="ele.name"
:type="ele.type"
:type-name="ele.type_name"
:description="ele.description"
:is-private="dsForm.private_list.includes(ele.id)"
:num="ele.num"
@active="handleActive(ele)"