Skip to content

Commit 3fa2bae

Browse files
ulleodataeaseShu
authored andcommitted
improve: improve chart data export
1 parent 460e7f6 commit 3fa2bae

File tree

8 files changed

+89
-43
lines changed

8 files changed

+89
-43
lines changed

backend/apps/chat/api/chat.py

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
from apps.chat.curd.chat import list_chats, get_chat_with_records, create_chat, rename_chat, \
1212
delete_chat, get_chat_chart_data, get_chat_predict_data, get_chat_with_records_with_data, get_chat_record_by_id, \
13-
format_json_data, format_json_list_data
14-
from apps.chat.models.chat_model import CreateChat, ChatRecord, RenameChat, ChatQuestion, ExcelData
13+
format_json_data, format_json_list_data, get_chart_config
14+
from apps.chat.models.chat_model import CreateChat, ChatRecord, RenameChat, ChatQuestion, AxisObj
1515
from apps.chat.task.llm import LLMService
1616
from common.core.deps import CurrentAssistant, SessionDep, CurrentUser, Trans
1717

@@ -42,19 +42,19 @@ def inner():
4242
return await asyncio.to_thread(inner)
4343

4444

45-
@router.get("/record/{chart_record_id}/data")
46-
async def chat_record_data(session: SessionDep, chart_record_id: int):
45+
@router.get("/record/{chat_record_id}/data")
46+
async def chat_record_data(session: SessionDep, chat_record_id: int):
4747
def inner():
48-
data = get_chat_chart_data(chart_record_id=chart_record_id, session=session)
48+
data = get_chat_chart_data(chat_record_id=chat_record_id, session=session)
4949
return format_json_data(data)
5050

5151
return await asyncio.to_thread(inner)
5252

5353

54-
@router.get("/record/{chart_record_id}/predict_data")
55-
async def chat_predict_data(session: SessionDep, chart_record_id: int):
54+
@router.get("/record/{chat_record_id}/predict_data")
55+
async def chat_predict_data(session: SessionDep, chat_record_id: int):
5656
def inner():
57-
data = get_chat_predict_data(chart_record_id=chart_record_id, session=session)
57+
data = get_chat_predict_data(chat_record_id=chat_record_id, session=session)
5858
return format_json_list_data(data)
5959

6060
return await asyncio.to_thread(inner)
@@ -203,17 +203,49 @@ def _err(_e: Exception):
203203
return StreamingResponse(llm_service.await_result(), media_type="text/event-stream")
204204

205205

206-
@router.post("/excel/export")
207-
async def export_excel(excel_data: ExcelData, trans: Trans):
208-
def inner():
206+
@router.get("/record/{chat_record_id}/excel/export")
207+
async def export_excel(session: SessionDep, chat_record_id: int, trans: Trans):
208+
chat_record = session.get(ChatRecord, chat_record_id)
209+
if not chat_record:
210+
raise HTTPException(
211+
status_code=500,
212+
detail=f"ChatRecord with id {chat_record_id} not found"
213+
)
214+
215+
is_predict_data = chat_record.predict_record_id is not None
216+
217+
_origin_data = format_json_data(get_chat_chart_data(chat_record_id=chat_record_id, session=session))
218+
219+
_base_field = _origin_data.get('fields')
220+
_data = _origin_data.get('data')
221+
222+
if not _data:
223+
raise HTTPException(
224+
status_code=500,
225+
detail=trans("i18n_excel_export.data_is_empty")
226+
)
227+
228+
chart_info = get_chart_config(session, chat_record_id)
209229

210-
if not excel_data.data:
211-
raise HTTPException(
212-
status_code=500,
213-
detail=trans("i18n_excel_export.data_is_empty")
214-
)
230+
_title = chart_info.get('title') if chart_info.get('title') else 'Excel'
231+
232+
fields = []
233+
if chart_info.get('columns') and len(chart_info.get('columns')) > 0:
234+
for column in chart_info.get('columns'):
235+
fields.append(AxisObj(name=column.get('name'), value=column.get('value')))
236+
if chart_info.get('axis'):
237+
for _type in ['x', 'y', 'series']:
238+
if chart_info.get('axis').get(_type):
239+
column = chart_info.get('axis').get(_type)
240+
fields.append(AxisObj(name=column.get('name'), value=column.get('value')))
241+
242+
_predict_data = []
243+
if is_predict_data:
244+
_predict_data = format_json_list_data(get_chat_predict_data(chat_record_id=chat_record_id, session=session))
245+
246+
def inner():
215247

216-
data, _fields_list, col_formats = LLMService.format_pd_data(excel_data.axis, excel_data.data)
248+
data, _fields_list, col_formats = LLMService.format_pd_data(fields, _data + _predict_data)
217249

218250
df = pd.DataFrame(data, columns=_fields_list)
219251

backend/apps/chat/curd/chat.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,23 @@ def get_chart_config(session: SessionDep, chart_record_id: int):
7070
pass
7171
return {}
7272

73+
def format_chart_fields(chart_info: dict):
74+
fields = []
75+
if chart_info.get('columns') and len(chart_info.get('columns')) > 0:
76+
for column in chart_info.get('columns'):
77+
column_str = column.get('value')
78+
if column.get('value') != column.get('name'):
79+
column_str = column_str + '(' + column.get('name') + ')'
80+
fields.append(column_str)
81+
if chart_info.get('axis'):
82+
for _type in ['x', 'y', 'series']:
83+
if chart_info.get('axis').get(_type):
84+
column = chart_info.get('axis').get(_type)
85+
column_str = column.get('value')
86+
if column.get('value') != column.get('name'):
87+
column_str = column_str + '(' + column.get('name') + ')'
88+
fields.append(column_str)
89+
return fields
7390

7491
def get_last_execute_sql_error(session: SessionDep, chart_id: int):
7592
stmt = select(ChatRecord.error).where(and_(ChatRecord.chat_id == chart_id)).order_by(
@@ -117,8 +134,8 @@ def format_json_list_data(origin_data: list[dict]):
117134
return data
118135

119136

120-
def get_chat_chart_data(session: SessionDep, chart_record_id: int):
121-
stmt = select(ChatRecord.data).where(and_(ChatRecord.id == chart_record_id))
137+
def get_chat_chart_data(session: SessionDep, chat_record_id: int):
138+
stmt = select(ChatRecord.data).where(and_(ChatRecord.id == chat_record_id))
122139
res = session.execute(stmt)
123140
for row in res:
124141
try:
@@ -128,8 +145,8 @@ def get_chat_chart_data(session: SessionDep, chart_record_id: int):
128145
return {}
129146

130147

131-
def get_chat_predict_data(session: SessionDep, chart_record_id: int):
132-
stmt = select(ChatRecord.predict_data).where(and_(ChatRecord.id == chart_record_id))
148+
def get_chat_predict_data(session: SessionDep, chat_record_id: int):
149+
stmt = select(ChatRecord.predict_data).where(and_(ChatRecord.id == chat_record_id))
133150
res = session.execute(stmt)
134151
for row in res:
135152
try:

backend/apps/chat/task/llm.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
save_select_datasource_answer, save_recommend_question_answer, \
3030
get_old_questions, save_analysis_predict_record, rename_chat, get_chart_config, \
3131
get_chat_chart_data, list_generate_sql_logs, list_generate_chart_logs, start_log, end_log, \
32-
get_last_execute_sql_error, format_json_data
32+
get_last_execute_sql_error, format_json_data, format_chart_fields
3333
from apps.chat.models.chat_model import ChatQuestion, ChatRecord, Chat, RenameChat, ChatLog, OperationEnum, \
3434
ChatFinishStep, AxisObj
3535
from apps.data_training.curd.data_training import get_training_template
@@ -214,22 +214,7 @@ def set_record(self, record: ChatRecord):
214214

215215
def get_fields_from_chart(self, _session: Session):
216216
chart_info = get_chart_config(_session, self.record.id)
217-
fields = []
218-
if chart_info.get('columns') and len(chart_info.get('columns')) > 0:
219-
for column in chart_info.get('columns'):
220-
column_str = column.get('value')
221-
if column.get('value') != column.get('name'):
222-
column_str = column_str + '(' + column.get('name') + ')'
223-
fields.append(column_str)
224-
if chart_info.get('axis'):
225-
for _type in ['x', 'y', 'series']:
226-
if chart_info.get('axis').get(_type):
227-
column = chart_info.get('axis').get(_type)
228-
column_str = column.get('value')
229-
if column.get('value') != column.get('name'):
230-
column_str = column_str + '(' + column.get('name') + ')'
231-
fields.append(column_str)
232-
return fields
217+
return format_chart_fields(chart_info)
233218

234219
def generate_analysis(self, _session: Session):
235220
fields = self.get_fields_from_chart(_session)

frontend/src/api/chat.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,8 @@ export const chatApi = {
332332
return request.fetchStream(`/chat/recommend_questions/${record_id}`, {}, controller)
333333
},
334334
checkLLMModel: () => request.get('/system/aimodel/default', { requestOptions: { silent: true } }),
335-
export2Excel: (data: any) =>
336-
request.post('/chat/excel/export', data, {
335+
export2Excel: (record_id: number | undefined) =>
336+
request.get(`/chat/record/${record_id}/excel/export`, {
337337
responseType: 'blob',
338338
requestOptions: { customError: true },
339339
}),

frontend/src/views/chat/answer/ChartAnswer.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import BaseAnswer from './BaseAnswer.vue'
33
import { Chat, chatApi, ChatInfo, type ChatMessage, ChatRecord, questionApi } from '@/api/chat.ts'
44
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
55
import ChartBlock from '@/views/chat/chat-block/ChartBlock.vue'
6+
67
const props = withDefaults(
78
defineProps<{
9+
recordId?: number
810
chatList?: Array<ChatInfo>
911
currentChatId?: number
1012
currentChat?: ChatInfo
@@ -13,6 +15,7 @@ const props = withDefaults(
1315
reasoningName: 'sql_answer' | 'chart_answer' | Array<'sql_answer' | 'chart_answer'>
1416
}>(),
1517
{
18+
recordId: undefined,
1619
chatList: () => [],
1720
currentChatId: undefined,
1821
currentChat: () => new ChatInfo(),
@@ -229,6 +232,7 @@ function getChatData(recordId?: number) {
229232
emits('scrollBottom')
230233
})
231234
}
235+
232236
function stop() {
233237
stopFlag.value = true
234238
_loading.value = false
@@ -250,7 +254,7 @@ defineExpose({ sendMessage, index: () => index.value, stop })
250254

251255
<template>
252256
<BaseAnswer v-if="message" :message="message" :reasoning-name="reasoningName" :loading="_loading">
253-
<ChartBlock style="margin-top: 6px" :message="message" />
257+
<ChartBlock style="margin-top: 6px" :message="message" :record-id="recordId" />
254258
<slot></slot>
255259
<template #tool>
256260
<slot name="tool"></slot>

frontend/src/views/chat/answer/PredictAnswer.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@ import { chatApi, ChatInfo, type ChatMessage, ChatRecord } from '@/api/chat.ts'
44
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
55
import MdComponent from '@/views/chat/component/MdComponent.vue'
66
import ChartBlock from '@/views/chat/chat-block/ChartBlock.vue'
7+
78
const props = withDefaults(
89
defineProps<{
10+
recordId?: number
911
chatList?: Array<ChatInfo>
1012
currentChatId?: number
1113
currentChat?: ChatInfo
1214
message?: ChatMessage
1315
loading?: boolean
1416
}>(),
1517
{
18+
recordId: undefined,
1619
chatList: () => [],
1720
currentChatId: undefined,
1821
currentChat: () => new ChatInfo(),
@@ -257,6 +260,7 @@ defineExpose({ sendMessage, index: () => index.value, chatList: () => _chatList,
257260
v-if="message.record?.predict_data?.length > 0 && message.record?.data"
258261
ref="chartBlockRef"
259262
style="margin-top: 12px"
263+
:record-id="recordId"
260264
:message="message"
261265
is-predict
262266
/>

frontend/src/views/chat/chat-block/ChartBlock.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ import { chatApi } from '@/api/chat'
2828
2929
const props = withDefaults(
3030
defineProps<{
31+
recordId?: number
3132
message: ChatMessage
3233
isPredict?: boolean
3334
chatType?: ChartTypes
3435
enlarge?: boolean
3536
}>(),
3637
{
38+
recordId: undefined,
3739
isPredict: false,
3840
chatType: undefined,
3941
enlarge: false,
@@ -240,10 +242,10 @@ function copyText() {
240242
const exportRef = ref()
241243
242244
function exportToExcel() {
243-
if (chartRef.value) {
245+
if (chartRef.value && props.recordId) {
244246
loading.value = true
245247
chatApi
246-
.export2Excel({ ...chartRef.value?.getExcelData(), name: chartObject.value.title })
248+
.export2Excel(props.recordId)
247249
.then((res) => {
248250
const blob = new Blob([res], {
249251
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',

frontend/src/views/chat/index.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@
246246
:chat-list="chatList"
247247
:current-chat="currentChat"
248248
:current-chat-id="currentChatId"
249+
:record-id="message.record?.id"
249250
:loading="isTyping"
250251
:message="message"
251252
:reasoning-name="['sql_answer', 'chart_answer']"
@@ -358,6 +359,7 @@
358359
:chat-list="chatList"
359360
:current-chat="currentChat"
360361
:current-chat-id="currentChatId"
362+
:record-id="message.record?.id"
361363
:loading="isTyping"
362364
:message="message"
363365
@scroll-bottom="scrollToBottom"

0 commit comments

Comments
 (0)