This commit is contained in:
dataeaseShu
2025-07-31 10:02:54 +08:00
12 changed files with 104 additions and 83 deletions
+16 -8
View File
@@ -111,7 +111,8 @@ class AiModelQuestion(BaseModel):
sub_query: Optional[list[dict]] = None
def sql_sys_question(self):
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question, lang=self.lang)
return get_sql_template()['system'].format(engine=self.engine, schema=self.db_schema, question=self.question,
lang=self.lang)
def sql_user_question(self):
return get_sql_template()['user'].format(engine=self.engine, schema=self.db_schema, question=self.question,
@@ -153,22 +154,29 @@ class AiModelQuestion(BaseModel):
def filter_user_question(self):
return get_permissions_template()['user'].format(sql=self.sql, filter=self.filter)
def dynamic_sys_question(self):
def dynamic_sys_question(self):
return get_dynamic_template()['system'].format(lang=self.lang, engine=self.engine)
def dynamic_user_question(self):
def dynamic_user_question(self):
return get_dynamic_template()['user'].format(sql=self.sql, sub_query=self.sub_query)
class ChatQuestion(AiModelQuestion):
question: str = Body(description='用户提问')
chat_id: int = Body(description='会话ID')
question: str
chat_id: int
class ChatMcp(ChatQuestion):
token: str = Body(description='token')
token: str
class ChatStart(BaseModel):
username: str = Body(description='用户名')
password: str = Body(description='密码')
class McpQuestion(BaseModel):
question: str = Body(description='用户提问')
chat_id: int = Body(description='会话ID')
token: str = Body(description='token')
+1 -1
View File
@@ -1032,7 +1032,7 @@ class LLMService:
def validate_history_ds(self):
_ds = self.ds
if not self.current_assistant:
current_ds = self.session.exec(CoreDatasource, _ds.id)
current_ds = self.session.get(CoreDatasource, _ds.id)
if not current_ds:
raise Exception('ds is invalid')
else:
+4 -3
View File
@@ -12,7 +12,7 @@ from pydantic import ValidationError
from sqlmodel import select
from apps.chat.api.chat import create_chat
from apps.chat.models.chat_model import ChatMcp, CreateChat, ChatStart
from apps.chat.models.chat_model import ChatMcp, CreateChat, ChatStart, McpQuestion
from apps.chat.task.llm import LLMService
from apps.system.crud.user import authenticate
from apps.system.crud.user import get_db_user
@@ -76,7 +76,7 @@ async def mcp_start(session: SessionDep, chat: ChatStart):
@router.post("/mcp_question", operation_id="mcp_question")
async def mcp_question(session: SessionDep, chat: ChatMcp):
async def mcp_question(session: SessionDep, chat: McpQuestion):
try:
payload = jwt.decode(
chat.token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
@@ -105,8 +105,9 @@ async def mcp_question(session: SessionDep, chat: ChatMcp):
if session_user.status != 1:
raise HTTPException(status_code=400, detail="Inactive user")
mcp_chat = ChatMcp(token=chat.token, chat_id=chat.chat_id, question=chat.question)
# ask
llm_service = LLMService(session_user, chat)
llm_service = LLMService(session_user, mcp_chat)
llm_service.init_record()
return StreamingResponse(llm_service.run_task(False), media_type="text/event-stream")
+22 -22
View File
@@ -104,28 +104,28 @@ export class Bar extends BaseG2Chart {
return { name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}` }
}
},
labels: [
{
text: (data: any) => {
const value = data[y[0].value]
if (value === undefined || value === null) {
return ''
}
return `${value}${_data.isPercent ? '%' : ''}`
},
position: (data: any) => {
if (data[y[0].value] < 0) {
return 'left'
}
return 'right'
},
transform: [
{ type: 'contrastReverse' },
{ type: 'exceedAdjust' },
{ type: 'overlapHide' },
],
},
],
// labels: [
// {
// text: (data: any) => {
// const value = data[y[0].value]
// if (value === undefined || value === null) {
// return ''
// }
// return `${value}${_data.isPercent ? '%' : ''}`
// },
// position: (data: any) => {
// if (data[y[0].value] < 0) {
// return 'left'
// }
// return 'right'
// },
// transform: [
// { type: 'contrastReverse' },
// { type: 'exceedAdjust' },
// { type: 'overlapHide' },
// ],
// },
// ],
} as G2Spec
if (series.length > 0) {
@@ -93,28 +93,28 @@ export class Column extends BaseG2Chart {
return { name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}` }
}
},
labels: [
{
text: (data: any) => {
const value = data[y[0].value]
if (value === undefined || value === null) {
return ''
}
return `${value}${_data.isPercent ? '%' : ''}`
},
position: (data: any) => {
if (data[y[0].value] < 0) {
return 'bottom'
}
return 'top'
},
transform: [
{ type: 'contrastReverse' },
{ type: 'exceedAdjust' },
{ type: 'overlapHide' },
],
},
],
// labels: [
// {
// text: (data: any) => {
// const value = data[y[0].value]
// if (value === undefined || value === null) {
// return ''
// }
// return `${value}${_data.isPercent ? '%' : ''}`
// },
// position: (data: any) => {
// if (data[y[0].value] < 0) {
// return 'bottom'
// }
// return 'top'
// },
// transform: [
// { type: 'contrastReverse' },
// { type: 'exceedAdjust' },
// { type: 'overlapHide' },
// ],
// },
// ],
} as G2Spec
if (series.length > 0) {
@@ -59,26 +59,26 @@ export class Line extends BaseG2Chart {
encode: {
shape: 'smooth',
},
labels: [
{
text: (data: any) => {
const value = data[y[0].value]
if (value === undefined || value === null) {
return ''
}
return `${value}${_data.isPercent ? '%' : ''}`
},
style: {
dx: -10,
dy: -12,
},
transform: [
{ type: 'contrastReverse' },
{ type: 'exceedAdjust' },
{ type: 'overlapHide' },
],
},
],
// labels: [
// {
// text: (data: any) => {
// const value = data[y[0].value]
// if (value === undefined || value === null) {
// return ''
// }
// return `${value}${_data.isPercent ? '%' : ''}`
// },
// style: {
// dx: -10,
// dy: -12,
// },
// transform: [
// { type: 'contrastReverse' },
// { type: 'exceedAdjust' },
// { type: 'overlapHide' },
// ],
// },
// ],
tooltip: (data) => {
if (series.length > 0) {
return {
@@ -95,6 +95,9 @@ export class Line extends BaseG2Chart {
style: {
fill: 'white',
},
encode: {
size: 1.5,
},
tooltip: false,
},
],
@@ -1232,7 +1232,7 @@ defineExpose({
<component
:is="findComponent(item.component)"
:ref="'shape_component_' + item.id"
class="sq-component slot-component dragHandle"
class="sq-component slot-component"
:class="{ 'sq-component-hidden': item.component !== 'SQTab' }"
:config-item="item"
:view-info="canvasViewInfo[item.id]"
@@ -80,7 +80,7 @@ const doDeleteComponent = (e: MouseEvent) => {
right: 12px;
top: 12px;
display: flex;
z-index: 1;
z-index: 11;
cursor: pointer !important;
}
@@ -237,6 +237,7 @@ defineExpose({
:component-data="tabItem.componentData"
:canvas-view-info="canvasViewInfo"
:base-matrix-count="tabBaseMatrixCount"
:canvas-id="tabItem.name"
></SQPreview>
<DashboardEditor
v-else
@@ -97,6 +97,7 @@ function selectChange(value: boolean, viewInfo: any) {
}
const getData = (record: any) => {
const recordData = record.data
if (record?.predict_record_id !== undefined && record?.predict_record_id !== null) {
let _list = []
if (record?.predict_data && typeof record?.predict_data === 'string') {
@@ -121,13 +122,15 @@ const getData = (record: any) => {
return _list
}
if (record.data && record.data.length > 0) {
return concat(record.data, _list)
if (recordData.data && recordData.data.length > 0) {
recordData.data = concat(recordData.data, _list)
} else {
recordData.data = _list
}
return _list
return recordData
} else {
return record.data
return recordData
}
}
@@ -142,7 +145,7 @@ function adaptorChartInfoList(chatInfo: ChatInfo) {
(record?.sql || record?.chart)) ||
(record?.predict_record_id !== undefined &&
record?.predict_record_id !== null &&
data.length > 0)
data.data.length > 0)
) {
const recordeInfo = { id: chatInfo.id + '_' + record.id, data: data, chart: {} }
const chartBaseInfo = JSON.parse(record.chart)
+3
View File
@@ -86,6 +86,9 @@ function getLineOptions(baseOptions, axis, data) {
style: {
fill: 'white',
},
encode: {
size: 1.5,
},
tooltip: false,
},
],
+2
View File
@@ -2,5 +2,7 @@ SSR_PATH=/opt/sqlbot/g2-ssr
APP_PATH=/opt/sqlbot/app
nohup node $SSR_PATH/app.js &
nohup uvicorn main:mcp_app --host 0.0.0.0 --port 8001 &
cd $APP_PATH
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1 --proxy-headers