mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
Merge remote-tracking branch 'origin/main'
# Conflicts: # frontend/src/views/dashboard/preview/SQPreviewShow.vue
This commit is contained in:
@@ -68,7 +68,7 @@ async def start_chat(session: SessionDep, current_user: CurrentUser, create_chat
|
||||
)
|
||||
|
||||
|
||||
@router.post("/question")
|
||||
@router.post("/question", operation_id="question")
|
||||
async def stream_sql(session: SessionDep, current_user: CurrentUser, request_question: ChatQuestion):
|
||||
"""Stream SQL analysis results
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ def get_table_schema(session: SessionDep, ds: CoreDatasource) -> str:
|
||||
db_name = table_objs[0].schema
|
||||
schema_str += f"【DB_ID】 {db_name}\n【Schema】\n"
|
||||
for obj in table_objs:
|
||||
schema_str += f"# Table: {db_name}.{obj.table.table_name}"
|
||||
schema_str += f"# Table: {db_name}.{obj.table.table_name}" if ds.type != "mysql" else f"# Table: {obj.table.table_name}"
|
||||
table_comment = ''
|
||||
if obj.table.custom_comment:
|
||||
table_comment = obj.table.custom_comment.strip()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
from fastapi import APIRouter
|
||||
from sqlmodel import select
|
||||
from sqlmodel import select
|
||||
|
||||
from apps.system.models.system_model import AiModelDetail
|
||||
from apps.system.schemas.system_schema import model_status
|
||||
from common.core.deps import SessionDep
|
||||
@@ -13,9 +13,9 @@ router = APIRouter(tags=["system/aimodel"], prefix="/system/aimodel")
|
||||
|
||||
@router.get("/pager/{pageNum}/{pageSize}", response_model=PaginatedResponse[AiModelDetail])
|
||||
async def pager(
|
||||
session: SessionDep,
|
||||
pageNum: int,
|
||||
pageSize: int
|
||||
session: SessionDep,
|
||||
pageNum: int,
|
||||
pageSize: int
|
||||
):
|
||||
pagination = PaginationParams(page=pageNum, size=pageSize)
|
||||
paginator = Paginator(session)
|
||||
@@ -24,19 +24,21 @@ async def pager(
|
||||
model=AiModelDetail,
|
||||
pagination=pagination,
|
||||
**filters)
|
||||
|
||||
|
||||
|
||||
@router.get("/{id}", response_model=AiModelDetail)
|
||||
async def get_model_by_id(
|
||||
session: SessionDep,
|
||||
id: int
|
||||
session: SessionDep,
|
||||
id: int
|
||||
):
|
||||
term = session.get(AiModelDetail, id)
|
||||
return term
|
||||
|
||||
|
||||
|
||||
@router.post("", response_model=AiModelDetail)
|
||||
async def add_model(
|
||||
session: SessionDep,
|
||||
creator: AiModelDetail
|
||||
session: SessionDep,
|
||||
creator: AiModelDetail
|
||||
):
|
||||
data = AiModelDetail.model_validate(creator)
|
||||
data.create_time = get_timestamp()
|
||||
@@ -44,10 +46,11 @@ async def add_model(
|
||||
session.commit()
|
||||
return creator
|
||||
|
||||
|
||||
@router.put("", response_model=AiModelDetail)
|
||||
async def update_terminology(
|
||||
session: SessionDep,
|
||||
model: AiModelDetail
|
||||
session: SessionDep,
|
||||
model: AiModelDetail
|
||||
):
|
||||
model.id = int(model.id)
|
||||
term = session.exec(select(AiModelDetail).where(AiModelDetail.id == model.id)).first()
|
||||
@@ -58,10 +61,11 @@ async def update_terminology(
|
||||
session.commit()
|
||||
return model
|
||||
|
||||
|
||||
@router.delete("/{id}", response_model=AiModelDetail)
|
||||
async def delete_terminology(
|
||||
session: SessionDep,
|
||||
id: int
|
||||
session: SessionDep,
|
||||
id: int
|
||||
):
|
||||
term = session.exec(select(AiModelDetail).where(AiModelDetail.id == id)).first()
|
||||
session.delete(term)
|
||||
@@ -69,7 +73,7 @@ async def delete_terminology(
|
||||
return {
|
||||
"message": f"AiModel with ID {id} deleted successfully."
|
||||
}
|
||||
|
||||
|
||||
|
||||
@router.patch("/status", response_model=dict)
|
||||
async def status(session: SessionDep, dto: model_status):
|
||||
@@ -83,4 +87,9 @@ async def status(session: SessionDep, dto: model_status):
|
||||
term.status = status
|
||||
session.add(term)
|
||||
session.commit()
|
||||
return {"message": f"AiModel with IDs {ids} updated successfully."}
|
||||
return {"message": f"AiModel with IDs {ids} updated successfully."}
|
||||
|
||||
|
||||
@router.get("/list", operation_id="get_model_list")
|
||||
async def get_model_list(session: SessionDep):
|
||||
return session.query(AiModelDetail).all()
|
||||
|
||||
@@ -22,7 +22,10 @@ wlist = [
|
||||
"*.eot",
|
||||
"*.otf",
|
||||
"/mcp",
|
||||
"/mcp/message"
|
||||
"/mcp/message",
|
||||
"/datasource/list",
|
||||
"/system/aimodel/list",
|
||||
"/chat/question"
|
||||
]
|
||||
|
||||
class WhitelistChecker:
|
||||
|
||||
+3
-2
@@ -49,7 +49,7 @@ mcp = FastApiMCP(
|
||||
app,
|
||||
name="SQLBot MCP Server",
|
||||
description="SQLBot MCP Server",
|
||||
include_operations=["get_datasource_list"]
|
||||
include_operations=["get_datasource_list", "get_model_list", "question"]
|
||||
)
|
||||
|
||||
mcp.mount(mcp_app)
|
||||
@@ -76,7 +76,7 @@ frontend_dist = os.path.abspath("../frontend/dist")
|
||||
if not os.path.exists(frontend_dist):
|
||||
logging.warning(f"The front-end build directory does not exist: {frontend_dist}")
|
||||
logging.warning("Please make sure you have built the front-end project")
|
||||
|
||||
|
||||
else:
|
||||
|
||||
@app.get("/", include_in_schema=False)
|
||||
@@ -92,3 +92,4 @@ if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
||||
# uvicorn.run("main:mcp_app", host="0.0.0.0", port=8001) # mcp server
|
||||
|
||||
@@ -46,19 +46,19 @@ template:
|
||||
您的任务是通过给定的问题和SQL生成 JSON 以进行数据可视化。
|
||||
请遵守以下规则:
|
||||
- 如果需要表格,则生成的 JSON 格式应为:
|
||||
{{"type":"table", "title": "标题", "columns": [{{"name":"中文字段名1", "value": "SQL 查询列 1(有别名用别名)"}}, {{"name": "中文字段名 2", "value": "SQL 查询列 2(有别名用别名)"}}]}}
|
||||
{{"type":"table", "title": "标题", "columns": [{{"name":"中文字段名1", "value": "SQL 查询列 1(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, {{"name": "中文字段名 2", "value": "SQL 查询列 2(有别名用别名,去掉外层的反引号、双引号、方括号)"}}]}}
|
||||
必须从 SQL 查询列中提取“columns”。
|
||||
- 如果需要柱状图,则生成的 JSON 格式应为:
|
||||
{{"type":"column", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名)"}}}}
|
||||
{{"type":"column", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}
|
||||
必须从 SQL 查询列中提取“x”和“y”。
|
||||
- 如果需要条形图,则生成的 JSON 格式应为:
|
||||
{{"type":"bar", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名)"}}}}
|
||||
{{"type":"bar", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称", "value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}
|
||||
必须从 SQL 查询列中提取“x”和“y”。
|
||||
- 如果需要折线图,则生成的 JSON 格式应为:
|
||||
{{"type":"line", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称","value": "SQL 查询 x 轴的列(有别名用别名)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名)"}}}}
|
||||
{{"type":"line", "title": "标题", "axis": {{"x": {{"name":"x轴的中文名称","value": "SQL 查询 x 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "y": {{"name":"y轴的中文名称","value": "SQL 查询 y 轴的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}
|
||||
其中“x”和“y”必须从SQL查询列中提取。
|
||||
- 如果需要饼图,则生成的 JSON 格式应为:
|
||||
{{"type":"pie", "title": "标题", "axis": {{"y": {{"值轴的中文名称","value":"SQL 查询数值的列(有别名用别名)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名)"}}}}
|
||||
{{"type":"pie", "title": "标题", "axis": {{"y": {{"值轴的中文名称","value":"SQL 查询数值的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}, "series": {{"name":"分类的中文名称","value":"SQL 查询分类的列(有别名用别名,去掉外层的反引号、双引号、方括号)"}}}}
|
||||
其中“column”必须从SQL查询列中提取。
|
||||
- 如果答案未知或者与生成JSON无关,则生成的 JSON 格式应为:
|
||||
{{"type":"error", "reason": "抱歉,我无法回答您的问题。"}}
|
||||
|
||||
@@ -149,7 +149,6 @@
|
||||
import {ref, computed, onMounted} from 'vue'
|
||||
import {useRouter, useRoute} from 'vue-router'
|
||||
import {useUserStore} from '@/stores/user'
|
||||
import folder from '@/assets/svg/folder.svg'
|
||||
import ds from '@/assets/svg/ds.svg'
|
||||
import dashboard from '@/assets/svg/dashboard.svg'
|
||||
import chat from '@/assets/svg/chat.svg'
|
||||
@@ -184,12 +183,12 @@ const sysRouterList = computed(() => {
|
||||
const showSubmenu = computed(() => {
|
||||
return route.path.includes('/system')
|
||||
})
|
||||
const workspace = ref('1')
|
||||
const options = [
|
||||
// const workspace = ref('1')
|
||||
/* const options = [
|
||||
{value: '1', label: 'Default workspace'},
|
||||
{value: '2', label: 'Workspace 2'},
|
||||
{value: '3', label: 'Workspace 3'}
|
||||
]
|
||||
] */
|
||||
const currentPageTitle = computed(() => {
|
||||
if (route.path.includes('/system')) {
|
||||
return 'System Settings'
|
||||
|
||||
@@ -8,7 +8,7 @@ import ds from "@/views/ds/index.vue";
|
||||
import DashboardEditor from "@/views/dashboard/editor/index.vue";
|
||||
import Dashboard from "@/views/dashboard/index.vue";
|
||||
import Model from "@/views/system/model/index.vue";
|
||||
import User from "@/views/system/user/index.vue";
|
||||
// import User from "@/views/system/user/index.vue";
|
||||
import { watchRouter } from "./watch";
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
|
||||
+18
-11
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
// import { ref } from 'vue'
|
||||
import { AuthApi } from '@/api/login'
|
||||
import { useCache } from '@/utils/useCache'
|
||||
import { i18n } from '@/i18n'
|
||||
@@ -17,18 +17,19 @@ interface UserState {
|
||||
language: string
|
||||
exp: number
|
||||
time: number
|
||||
[key: string]: string | number
|
||||
}
|
||||
|
||||
export const UserStore = defineStore('user', {
|
||||
state: (): UserState => {
|
||||
return {
|
||||
token: null,
|
||||
uid: null,
|
||||
name: null,
|
||||
oid: null,
|
||||
token: '',
|
||||
uid: '',
|
||||
name: '',
|
||||
oid: '',
|
||||
language: 'zh-CN',
|
||||
exp: null,
|
||||
time: null
|
||||
exp: 0,
|
||||
time: 0
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@@ -69,13 +70,19 @@ export const UserStore = defineStore('user', {
|
||||
const res: any = await AuthApi.info()
|
||||
const res_data = res || {}
|
||||
|
||||
const keys: string[] = ['uid', 'name', 'oid', 'language', 'exp', 'time']
|
||||
|
||||
const keys = ['uid', 'name', 'oid', 'language', 'exp', 'time'] as const
|
||||
|
||||
keys.forEach(key => {
|
||||
const dkey = key === 'uid' ? 'id' : key
|
||||
this[key] = res_data[dkey]
|
||||
wsCache.set('user.' + key, this[key])
|
||||
const value = res_data[dkey]
|
||||
if (key === 'exp' || key === 'time') {
|
||||
this[key] = Number(value)
|
||||
} else {
|
||||
this[key] = String(value)
|
||||
}
|
||||
wsCache.set('user.' + key, value)
|
||||
})
|
||||
|
||||
this.setLanguage(this.language)
|
||||
},
|
||||
setToken(token: string) {
|
||||
|
||||
@@ -75,7 +75,7 @@ onMounted(() => {
|
||||
</div>
|
||||
<div class="ds-row-container">
|
||||
<template v-for="(item, _index) in dsList" :key="_index">
|
||||
<DatasourceItemCard :ds="item" @click="selectDs(item)" v-if="_index<3 || item?.id===modelValue"
|
||||
<DatasourceItemCard :ds="item" @click="selectDs(item)"
|
||||
class="ds-card" :class="[item?.id===modelValue? 'ds-card-selected': '']"/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user