mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 09:17:06 +08:00
Merge branch 'main' of https://github.com/dataease/SQLBot
This commit is contained in:
@@ -8,7 +8,7 @@ from fastapi import APIRouter, HTTPException
|
||||
from fastapi.responses import StreamingResponse
|
||||
|
||||
from apps.chat.curd.chat import list_chats, get_chat_with_records, create_chat, rename_chat, \
|
||||
delete_chat, get_chat_chart_data, get_chat_predict_data
|
||||
delete_chat, get_chat_chart_data, get_chat_predict_data, get_chat_with_records_with_data
|
||||
from apps.chat.models.chat_model import CreateChat, ChatRecord, RenameChat, ChatQuestion, ExcelData
|
||||
from apps.chat.task.llm import LLMService
|
||||
from common.core.deps import CurrentAssistant, SessionDep, CurrentUser
|
||||
@@ -33,6 +33,18 @@ async def get_chat(session: SessionDep, current_user: CurrentUser, chart_id: int
|
||||
)
|
||||
|
||||
|
||||
@router.get("/get/with_data/{chart_id}")
|
||||
async def get_chat_with_data(session: SessionDep, current_user: CurrentUser, chart_id: int, current_assistant: CurrentAssistant):
|
||||
try:
|
||||
return get_chat_with_records_with_data(chart_id=chart_id, session=session, current_user=current_user,
|
||||
current_assistant=current_assistant)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/record/get/{chart_record_id}/data")
|
||||
async def chat_record_data(session: SessionDep, chart_record_id: int):
|
||||
try:
|
||||
@@ -205,7 +217,8 @@ async def export_excel(excel_data: ExcelData):
|
||||
|
||||
buffer = io.BytesIO()
|
||||
|
||||
with pd.ExcelWriter(buffer, engine='xlsxwriter', engine_kwargs={'options': {'strings_to_numbers': True}}) as writer:
|
||||
with pd.ExcelWriter(buffer, engine='xlsxwriter',
|
||||
engine_kwargs={'options': {'strings_to_numbers': True}}) as writer:
|
||||
df.to_excel(writer, sheet_name='Sheet1', index=False)
|
||||
|
||||
buffer.seek(0)
|
||||
|
||||
@@ -67,8 +67,13 @@ def get_chat_predict_data(session: SessionDep, chart_record_id: int):
|
||||
return {}
|
||||
|
||||
|
||||
def get_chat_with_records_with_data(session: SessionDep, chart_id: int, current_user: CurrentUser,
|
||||
current_assistant: CurrentAssistant) -> ChatInfo:
|
||||
return get_chat_with_records(session, chart_id, current_user, current_assistant, True)
|
||||
|
||||
|
||||
def get_chat_with_records(session: SessionDep, chart_id: int, current_user: CurrentUser,
|
||||
current_assistant: CurrentAssistant) -> ChatInfo:
|
||||
current_assistant: CurrentAssistant, with_data: bool = False) -> ChatInfo:
|
||||
chat = session.get(Chat, chart_id)
|
||||
if not chat:
|
||||
raise Exception(f"Chat with id {chart_id} not found")
|
||||
@@ -96,18 +101,39 @@ def get_chat_with_records(session: SessionDep, chart_id: int, current_user: Curr
|
||||
ChatRecord.recommended_question, ChatRecord.first_chat,
|
||||
ChatRecord.finish, ChatRecord.error).where(
|
||||
and_(ChatRecord.create_by == current_user.id, ChatRecord.chat_id == chart_id)).order_by(ChatRecord.create_time)
|
||||
if with_data:
|
||||
stmt = select(ChatRecord.id, ChatRecord.chat_id, ChatRecord.create_time, ChatRecord.finish_time,
|
||||
ChatRecord.question, ChatRecord.sql_answer, ChatRecord.sql,
|
||||
ChatRecord.chart_answer, ChatRecord.chart, ChatRecord.analysis, ChatRecord.predict,
|
||||
ChatRecord.datasource_select_answer, ChatRecord.analysis_record_id, ChatRecord.predict_record_id,
|
||||
ChatRecord.recommended_question, ChatRecord.first_chat,
|
||||
ChatRecord.finish, ChatRecord.error, ChatRecord.data, ChatRecord.predict_data).where(
|
||||
and_(ChatRecord.create_by == current_user.id, ChatRecord.chat_id == chart_id)).order_by(
|
||||
ChatRecord.create_time)
|
||||
|
||||
result = session.execute(stmt).all()
|
||||
record_list: list[ChatRecord] = []
|
||||
for row in result:
|
||||
record_list.append(
|
||||
ChatRecord(id=row.id, chat_id=row.chat_id, create_time=row.create_time, finish_time=row.finish_time,
|
||||
question=row.question, sql_answer=row.sql_answer, sql=row.sql,
|
||||
chart_answer=row.chart_answer, chart=row.chart,
|
||||
analysis=row.analysis, predict=row.predict,
|
||||
datasource_select_answer=row.datasource_select_answer,
|
||||
analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id,
|
||||
recommended_question=row.recommended_question, first_chat=row.first_chat,
|
||||
finish=row.finish, error=row.error))
|
||||
if not with_data:
|
||||
record_list.append(
|
||||
ChatRecord(id=row.id, chat_id=row.chat_id, create_time=row.create_time, finish_time=row.finish_time,
|
||||
question=row.question, sql_answer=row.sql_answer, sql=row.sql,
|
||||
chart_answer=row.chart_answer, chart=row.chart,
|
||||
analysis=row.analysis, predict=row.predict,
|
||||
datasource_select_answer=row.datasource_select_answer,
|
||||
analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id,
|
||||
recommended_question=row.recommended_question, first_chat=row.first_chat,
|
||||
finish=row.finish, error=row.error))
|
||||
else:
|
||||
record_list.append(
|
||||
ChatRecord(id=row.id, chat_id=row.chat_id, create_time=row.create_time, finish_time=row.finish_time,
|
||||
question=row.question, sql_answer=row.sql_answer, sql=row.sql,
|
||||
chart_answer=row.chart_answer, chart=row.chart,
|
||||
analysis=row.analysis, predict=row.predict,
|
||||
datasource_select_answer=row.datasource_select_answer,
|
||||
analysis_record_id=row.analysis_record_id, predict_record_id=row.predict_record_id,
|
||||
recommended_question=row.recommended_question, first_chat=row.first_chat,
|
||||
finish=row.finish, error=row.error, data=row.data, predict_data=row.predict_data))
|
||||
|
||||
result = list(map(format_record, record_list))
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ async def query(
|
||||
AiModelDetail.default_model)
|
||||
if keyword is not None:
|
||||
statement = statement.where(AiModelDetail.name.like(f"%{keyword}%"))
|
||||
statement = statement.order_by(AiModelDetail.create_time.asc())
|
||||
statement = statement.order_by(AiModelDetail.default_model.desc(), AiModelDetail.name, AiModelDetail.create_time)
|
||||
items = session.exec(statement).all()
|
||||
return items
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ async def validator(session: SessionDep, id: int, virtual: Optional[int] = Query
|
||||
|
||||
@router.get("", response_model=list[AssistantModel])
|
||||
async def query(session: SessionDep):
|
||||
list_result = session.exec(select(AssistantModel).order_by(AssistantModel.create_time.asc())).all()
|
||||
list_result = session.exec(select(AssistantModel).order_by(AssistantModel.name, AssistantModel.create_time)).all()
|
||||
return list_result
|
||||
|
||||
@router.post("")
|
||||
|
||||
@@ -59,7 +59,7 @@ async def pager(
|
||||
select(UserModel, UserWsModel.oid.label('ws_oid'))
|
||||
.join(UserWsModel, UserModel.id == UserWsModel.uid, isouter=True)
|
||||
.where(UserModel.id.in_(uid_list))
|
||||
.order_by(UserModel.create_time)
|
||||
.order_by(UserModel.account, UserModel.create_time)
|
||||
)
|
||||
user_workspaces = session.exec(stmt).all()
|
||||
merged = defaultdict(list)
|
||||
|
||||
@@ -32,7 +32,7 @@ async def option_pager(
|
||||
stmt = select(UserModel.id, UserModel.account, UserModel.name).where(
|
||||
~exists().where(UserWsModel.uid == UserModel.id, UserWsModel.oid == oid),
|
||||
UserModel.id != 1
|
||||
).order_by(UserModel.create_time.asc())
|
||||
).order_by(UserModel.account, UserModel.create_time)
|
||||
|
||||
if keyword:
|
||||
keyword_pattern = f"%{keyword}%"
|
||||
@@ -97,7 +97,7 @@ async def pager(
|
||||
).where(
|
||||
UserWsModel.oid == workspace_id,
|
||||
UserModel.id != 1
|
||||
).order_by(UserModel.create_time.asc())
|
||||
).order_by(UserModel.account, UserModel.create_time)
|
||||
|
||||
if keyword:
|
||||
keyword_pattern = f"%{keyword}%"
|
||||
|
||||
@@ -46,13 +46,13 @@ def authenticate(*, session: Session, account: str, password: str) -> BaseUserDT
|
||||
|
||||
async def user_ws_options(session: Session, uid: int, trans: Optional[I18n] = None) -> list[UserWs]:
|
||||
if uid == 1:
|
||||
stmt = select(WorkspaceModel.id, WorkspaceModel.name).order_by(WorkspaceModel.create_time)
|
||||
stmt = select(WorkspaceModel.id, WorkspaceModel.name).order_by(WorkspaceModel.name, WorkspaceModel.create_time)
|
||||
else:
|
||||
stmt = select(WorkspaceModel.id, WorkspaceModel.name).join(
|
||||
UserWsModel, UserWsModel.oid == WorkspaceModel.id
|
||||
).where(
|
||||
UserWsModel.uid == uid,
|
||||
).order_by(WorkspaceModel.create_time)
|
||||
).order_by(WorkspaceModel.name, WorkspaceModel.create_time)
|
||||
result = session.exec(stmt)
|
||||
if not trans:
|
||||
return result.all()
|
||||
|
||||
Vendored
+1
@@ -6,6 +6,7 @@
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {
|
||||
const ElButton: typeof import('element-plus-secondary/es')['ElButton']
|
||||
const ElMessage: typeof import('element-plus-secondary/es')['ElMessage']
|
||||
const ElMessageBox: typeof import('element-plus-secondary/es')['ElMessageBox']
|
||||
const LicenseGenerator: any
|
||||
|
||||
@@ -301,6 +301,9 @@ export const chatApi = {
|
||||
get: (id: number): Promise<ChatInfo> => {
|
||||
return request.get(`/chat/get/${id}`)
|
||||
},
|
||||
get_with_Data: (id: number): Promise<ChatInfo> => {
|
||||
return request.get(`/chat/get/with_data/${id}`)
|
||||
},
|
||||
get_chart_data: (record_id?: number): Promise<any> => {
|
||||
return request.get(`/chat/record/get/${record_id}/data`)
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ export const supplierList: Array<{
|
||||
],
|
||||
model_options: [
|
||||
{ name: 'qwen-plus' },
|
||||
{ name: 'qwen-plus-latest' },
|
||||
/* { name: 'qwen-plus-latest' }, */
|
||||
{ name: 'qwen-max' },
|
||||
{ name: 'qwen-max-latest' },
|
||||
{ name: 'qwen-turbo' },
|
||||
@@ -47,10 +47,10 @@ export const supplierList: Array<{
|
||||
{ name: 'qwen-omni-turbo' },
|
||||
/* { name: 'qwen-omni-turbo-realtime' },
|
||||
{ name: 'qwen-omni-turbo-realtime-latest' }, */
|
||||
{ name: 'qvq-max' },
|
||||
/* { name: 'qvq-max' },
|
||||
{ name: 'qvq-max-latest' },
|
||||
{ name: 'qvq-plus' },
|
||||
{ name: 'qvq-plus-latest' },
|
||||
{ name: 'qvq-plus-latest' }, */
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -73,7 +73,10 @@ export const supplierList: Array<{
|
||||
model_config: {
|
||||
0: {
|
||||
api_domain: 'https://api.deepseek.com',
|
||||
model_options: [{ name: 'deepseek-chat' }, { name: 'deepseek-reasoner' }],
|
||||
model_options: [
|
||||
{ name: 'deepseek-chat' },
|
||||
/* { name: 'deepseek-reasoner' } */
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -87,11 +90,11 @@ export const supplierList: Array<{
|
||||
common_args: [{ key: 'temperature', val: 1.0, type: 'number', range: '[0, 2]' }],
|
||||
model_options: [
|
||||
{ name: 'hunyuan-turbos-latest' },
|
||||
{ name: 'hunyuan-turbos-longtext-128k-20250325' },
|
||||
{ name: 'hunyuan-large' },
|
||||
/* { name: 'hunyuan-turbos-longtext-128k-20250325' },
|
||||
{ name: 'hunyuan-large' }, */
|
||||
{ name: 'hunyuan-standard-256K' },
|
||||
{ name: 'hunyuan-standard' },
|
||||
{ name: 'hunyuan-lite' },
|
||||
/* { name: 'hunyuan-lite' }, */
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -103,13 +106,16 @@ export const supplierList: Array<{
|
||||
model_config: {
|
||||
0: {
|
||||
api_domain: 'https://spark-api-open.xf-yun.com/v1/',
|
||||
common_args: [{ key: 'temperature', val: 1.0, type: 'number', range: '[0, 2]' }],
|
||||
common_args: [
|
||||
{ key: 'temperature', val: 1.0, type: 'number', range: '[0, 2]' },
|
||||
{ key: 'max_tokens', val: 4096, type: 'number', range: '[1, 32768]' },
|
||||
],
|
||||
model_options: [
|
||||
{
|
||||
name: '4.0Ultra',
|
||||
args: [{ key: 'max_tokens', val: 32768, type: 'number', range: '[1, 32768]' }],
|
||||
},
|
||||
{
|
||||
/* {
|
||||
name: 'generalv3.5',
|
||||
args: [{ key: 'max_tokens', val: 4096, type: 'number', range: '[1, 8192]' }],
|
||||
},
|
||||
@@ -128,7 +134,7 @@ export const supplierList: Array<{
|
||||
{
|
||||
name: 'lite',
|
||||
args: [{ key: 'max_tokens', val: 4096, type: 'number', range: '[1, 4096]' }],
|
||||
},
|
||||
}, */
|
||||
{
|
||||
name: 'x1',
|
||||
args: [
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"or": "Or"
|
||||
},
|
||||
"dashboard": {
|
||||
"open_dashboard": "Open Dashboard",
|
||||
"add_dashboard_name_tips": "Please Input Dashboard Name",
|
||||
"existing_dashboard": "Existing Dashboard",
|
||||
"add_success": "Add Success",
|
||||
@@ -537,6 +538,7 @@
|
||||
"data_predict": "Data Prediction",
|
||||
"ds_is_invalid": "Datasource is invalid",
|
||||
"error": "Error",
|
||||
"no_data": "No Data",
|
||||
"show_error_detail": "Show error info"
|
||||
},
|
||||
"about": {
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"or": "或者"
|
||||
},
|
||||
"dashboard": {
|
||||
"open_dashboard": "打开仪表板",
|
||||
"add_dashboard_name_tips": "请输入仪表板名称",
|
||||
"existing_dashboard": "存量仪表板",
|
||||
"add_success": "添加成功",
|
||||
@@ -537,6 +538,7 @@
|
||||
"data_predict": "数据预测",
|
||||
"ds_is_invalid": "数据源无效",
|
||||
"error": "错误",
|
||||
"no_data": "暂无数据",
|
||||
"show_error_detail": "查看具体信息"
|
||||
},
|
||||
"about": {
|
||||
|
||||
@@ -230,3 +230,62 @@ strong {
|
||||
height: 1px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.sq-message-success {
|
||||
border: 1px solid #34c724 !important;
|
||||
background: #f0fbef !important;
|
||||
|
||||
.ed-message__icon {
|
||||
color: #34c724
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.sq-message-export {
|
||||
min-width: 20px !important;
|
||||
padding: 16px 20px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0px 4px 8px 0px #1f23291a;
|
||||
|
||||
& > p {
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0px;
|
||||
text-align: left;
|
||||
color: #1f2329;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.m50-export {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
padding: 2px 4px;
|
||||
|
||||
&:hover {
|
||||
background: var(--primary10, #3370ff1a);
|
||||
}
|
||||
}
|
||||
|
||||
.ed-message__closeBtn {
|
||||
margin-left: 28px;
|
||||
position: relative;
|
||||
margin-right: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translateY(0);
|
||||
color: #646a73;
|
||||
}
|
||||
|
||||
.ed-message__icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import ChartComponent from '@/views/chat/component/ChartComponent.vue'
|
||||
import type { ChatMessage } from '@/api/chat.ts'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import type { ChartTypes } from '@/views/chat/component/BaseChart.ts'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps<{
|
||||
id?: number | string
|
||||
@@ -11,6 +12,8 @@ const props = defineProps<{
|
||||
data: Array<{ [key: string]: any }>
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const chartObject = computed<{
|
||||
type: ChartTypes
|
||||
title: string
|
||||
@@ -91,7 +94,7 @@ defineExpose({
|
||||
:series="series"
|
||||
:data="data"
|
||||
/>
|
||||
<el-empty v-else description="No Data" />
|
||||
<el-empty v-else :description="t('chat.no_data')" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { onMounted, reactive, ref, h } from 'vue'
|
||||
import { ElButton, ElMessage } from 'element-plus-secondary'
|
||||
import {
|
||||
findNextComponentIndex,
|
||||
saveDashboardResourceTarget,
|
||||
@@ -18,7 +19,7 @@ const optInit = (viewInfo: any) => {
|
||||
resourceDialogShow.value = true
|
||||
state.viewInfo = viewInfo
|
||||
}
|
||||
|
||||
const curOptDashboardId = ref(null)
|
||||
const state = reactive({
|
||||
dashboardList: [] as SQTreeNode[],
|
||||
viewInfo: null,
|
||||
@@ -123,16 +124,55 @@ const saveResourcePrepare = () => {
|
||||
}
|
||||
|
||||
const saveResource = (params: any, commonParams: any) => {
|
||||
saveDashboardResourceTarget(params, commonParams, function () {
|
||||
saveDashboardResourceTarget(params, commonParams, (res: any) => {
|
||||
const messageTips = t('dashboard.add_success')
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: messageTips,
|
||||
})
|
||||
curOptDashboardId.value = res?.id
|
||||
openMessageLoading(messageTips, 'success', callbackExportSuc)
|
||||
resetForm()
|
||||
})
|
||||
}
|
||||
|
||||
const callbackExportSuc = () => {
|
||||
// do open dashboard
|
||||
const url = `#/canvas?resourceId=${curOptDashboardId.value}`
|
||||
window.open(url, '_self')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
const openMessageLoading = (text: string, type = 'success', cb: Function) => {
|
||||
// success error loading
|
||||
const customClass = `sq-message-${type || 'success'} sq-message-export`
|
||||
ElMessage({
|
||||
// @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
message: h('p', null, [
|
||||
h(
|
||||
'span',
|
||||
{
|
||||
title: t(text),
|
||||
class: 'ellipsis m50-export',
|
||||
},
|
||||
t(text)
|
||||
),
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
text: true,
|
||||
size: 'small',
|
||||
class: 'btn-text',
|
||||
onClick: () => {
|
||||
cb()
|
||||
},
|
||||
},
|
||||
t('dashboard.open_dashboard')
|
||||
),
|
||||
]),
|
||||
type,
|
||||
showClose: true,
|
||||
duration: 0,
|
||||
customClass,
|
||||
})
|
||||
}
|
||||
|
||||
const initDashboardList = () => {
|
||||
state.dashboardList = []
|
||||
const params = {}
|
||||
|
||||
@@ -169,7 +169,7 @@ function onClickHistory(chat: Chat) {
|
||||
currentChatId.value = chat.id
|
||||
loading.value = true
|
||||
chatApi
|
||||
.get(chat.id)
|
||||
.get_with_Data(chat.id)
|
||||
.then((res) => {
|
||||
const info = chatApi.toChatInfo(res)
|
||||
if (info) {
|
||||
|
||||
@@ -116,8 +116,8 @@ export const saveDashboardResourceTarget = (params: any, commonParams: any, call
|
||||
canvas_style_data: JSON.stringify(commonParams.canvasStyleData),
|
||||
canvas_view_info: JSON.stringify(commonParams.canvasViewInfo),
|
||||
}
|
||||
dashboardApi.update_canvas(requestParams).then(() => {
|
||||
callBack()
|
||||
dashboardApi.update_canvas(requestParams).then((res: any) => {
|
||||
callBack(res)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user