Skip to content

Commit 07f1337

Browse files
committed
feat: add export Sample SQL
1 parent 58f4327 commit 07f1337

File tree

10 files changed

+204
-72
lines changed

10 files changed

+204
-72
lines changed

backend/apps/data_training/api/data_training.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
import asyncio
2+
import io
13
from typing import Optional
24

5+
import pandas as pd
36
from fastapi import APIRouter, Query
7+
from fastapi.responses import StreamingResponse
48

9+
from apps.chat.models.chat_model import AxisObj
10+
from apps.chat.task.llm import LLMService
511
from apps.data_training.curd.data_training import page_data_training, create_training, update_training, delete_training, \
6-
enable_training
12+
enable_training, get_all_data_training
713
from apps.data_training.models.data_training_model import DataTrainingInfo
814
from common.core.deps import SessionDep, CurrentUser, Trans
915

@@ -43,3 +49,44 @@ async def delete(session: SessionDep, id_list: list[int]):
4349
@router.get("/{id}/enable/{enabled}")
4450
async def enable(session: SessionDep, id: int, enabled: bool, trans: Trans):
4551
enable_training(session, id, enabled, trans)
52+
53+
54+
@router.get("/export")
55+
async def export_excel(session: SessionDep, trans: Trans, current_user: CurrentUser,
56+
word: Optional[str] = Query(None, description="搜索术语(可选)")):
57+
def inner():
58+
_list = get_all_data_training(session, word, oid=current_user.oid)
59+
60+
data_list = []
61+
for obj in _list:
62+
_data = {
63+
"question": obj.question,
64+
"description": obj.description,
65+
"datasource_name": obj.datasource_name,
66+
"advanced_application_name": obj.advanced_application_name,
67+
}
68+
data_list.append(_data)
69+
70+
fields = []
71+
fields.append(AxisObj(name=trans('i18n_data_training.data_training'), value='question'))
72+
fields.append(AxisObj(name=trans('i18n_data_training.problem_description'), value='description'))
73+
fields.append(AxisObj(name=trans('i18n_data_training.effective_data_sources'), value='datasource_name'))
74+
if current_user.oid == 1:
75+
fields.append(
76+
AxisObj(name=trans('i18n_data_training.advanced_application'), value='advanced_application_name'))
77+
78+
md_data, _fields_list = LLMService.convert_object_array_for_pandas(fields, data_list)
79+
80+
df = pd.DataFrame(md_data, columns=_fields_list)
81+
82+
buffer = io.BytesIO()
83+
84+
with pd.ExcelWriter(buffer, engine='xlsxwriter',
85+
engine_kwargs={'options': {'strings_to_numbers': False}}) as writer:
86+
df.to_excel(writer, sheet_name='Sheet1', index=False)
87+
88+
buffer.seek(0)
89+
return io.BytesIO(buffer.getvalue())
90+
91+
result = await asyncio.to_thread(inner)
92+
return StreamingResponse(result, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

backend/apps/data_training/curd/data_training.py

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,61 @@
1818
from common.utils.embedding_threads import run_save_data_training_embeddings
1919

2020

21-
def page_data_training(session: SessionDep, current_page: int = 1, page_size: int = 10, name: Optional[str] = None,
22-
oid: Optional[int] = 1):
23-
_list: List[DataTrainingInfoResult] = []
24-
25-
current_page = max(1, current_page)
26-
page_size = max(10, page_size)
27-
28-
total_count = 0
29-
total_pages = 0
30-
21+
def get_data_training_base_query(oid: int, name: Optional[str] = None):
22+
"""
23+
获取数据训练查询的基础查询结构
24+
"""
3125
if name and name.strip() != "":
3226
keyword_pattern = f"%{name.strip()}%"
3327
parent_ids_subquery = (
3428
select(DataTraining.id)
35-
.where(and_(DataTraining.question.ilike(keyword_pattern), DataTraining.oid == oid)) # LIKE查询条件
29+
.where(and_(DataTraining.question.ilike(keyword_pattern), DataTraining.oid == oid))
3630
)
3731
else:
3832
parent_ids_subquery = (
3933
select(DataTraining.id).where(and_(DataTraining.oid == oid))
4034
)
4135

36+
return parent_ids_subquery
37+
38+
39+
def build_data_training_query(session: SessionDep, oid: int, name: Optional[str] = None,
40+
paginate: bool = True, current_page: int = 1, page_size: int = 10):
41+
"""
42+
构建数据训练查询的通用方法
43+
"""
44+
parent_ids_subquery = get_data_training_base_query(oid, name)
45+
46+
# 计算总数
4247
count_stmt = select(func.count()).select_from(parent_ids_subquery.subquery())
4348
total_count = session.execute(count_stmt).scalar()
44-
total_pages = (total_count + page_size - 1) // page_size
4549

46-
if current_page > total_pages:
50+
if paginate:
51+
# 分页处理
52+
page_size = max(10, page_size)
53+
total_pages = (total_count + page_size - 1) // page_size
54+
current_page = max(1, min(current_page, total_pages)) if total_pages > 0 else 1
55+
56+
paginated_parent_ids = (
57+
parent_ids_subquery
58+
.order_by(DataTraining.create_time.desc())
59+
.offset((current_page - 1) * page_size)
60+
.limit(page_size)
61+
.subquery()
62+
)
63+
else:
64+
# 不分页,获取所有数据
65+
total_pages = 1
4766
current_page = 1
67+
page_size = total_count if total_count > 0 else 1
4868

49-
paginated_parent_ids = (
50-
parent_ids_subquery
51-
.order_by(DataTraining.create_time.desc())
52-
.offset((current_page - 1) * page_size)
53-
.limit(page_size)
54-
.subquery()
55-
)
69+
paginated_parent_ids = (
70+
parent_ids_subquery
71+
.order_by(DataTraining.create_time.desc())
72+
.subquery()
73+
)
5674

75+
# 构建主查询
5776
stmt = (
5877
select(
5978
DataTraining.id,
@@ -74,6 +93,14 @@ def page_data_training(session: SessionDep, current_page: int = 1, page_size: in
7493
.order_by(DataTraining.create_time.desc())
7594
)
7695

96+
return stmt, total_count, total_pages, current_page, page_size
97+
98+
99+
def execute_data_training_query(session: SessionDep, stmt) -> List[DataTrainingInfoResult]:
100+
"""
101+
执行查询并返回数据训练信息列表
102+
"""
103+
_list = []
77104
result = session.execute(stmt)
78105

79106
for row in result:
@@ -90,9 +117,34 @@ def page_data_training(session: SessionDep, current_page: int = 1, page_size: in
90117
advanced_application_name=row.advanced_application_name,
91118
))
92119

120+
return _list
121+
122+
123+
def page_data_training(session: SessionDep, current_page: int = 1, page_size: int = 10,
124+
name: Optional[str] = None, oid: Optional[int] = 1):
125+
"""
126+
分页查询数据训练(原方法保持不变)
127+
"""
128+
stmt, total_count, total_pages, current_page, page_size = build_data_training_query(
129+
session, oid, name, True, current_page, page_size
130+
)
131+
_list = execute_data_training_query(session, stmt)
132+
93133
return current_page, page_size, total_count, total_pages, _list
94134

95135

136+
def get_all_data_training(session: SessionDep, name: Optional[str] = None, oid: Optional[int] = 1):
137+
"""
138+
获取所有数据训练(不分页)
139+
"""
140+
stmt, total_count, total_pages, current_page, page_size = build_data_training_query(
141+
session, oid, name, False
142+
)
143+
_list = execute_data_training_query(session, stmt)
144+
145+
return _list
146+
147+
96148
def create_training(session: SessionDep, info: DataTrainingInfo, oid: int, trans: Trans):
97149
create_time = datetime.datetime.now()
98150
if info.datasource is None and info.advanced_application is None:

backend/locales/en.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@
5353
"datasource_cannot_be_none": "Datasource cannot be empty",
5454
"datasource_assistant_cannot_be_none": "Datasource or advanced application cannot both be empty",
5555
"data_training_not_exists": "This example does not exist",
56-
"exists_in_db": "This question already exists"
56+
"exists_in_db": "This question already exists",
57+
"data_training": "SQL Example Library",
58+
"problem_description": "Problem Description",
59+
"sample_sql": "Sample SQL",
60+
"effective_data_sources": "Effective Data Sources",
61+
"advanced_application": "Advanced Application"
5762
},
5863
"i18n_custom_prompt": {
5964
"exists_in_db": "Template name already exists",

backend/locales/ko-KR.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@
5353
"datasource_cannot_be_none": "데이터 소스는 비울 수 없습니다",
5454
"datasource_assistant_cannot_be_none": "데이터 소스와 고급 애플리케이션을 모두 비울 수 없습니다",
5555
"data_training_not_exists": "이 예시가 존재하지 않습니다",
56-
"exists_in_db": "이 질문이 이미 존재합니다"
56+
"exists_in_db": "이 질문이 이미 존재합니다",
57+
"data_training": "SQL 예시 라이브러리",
58+
"problem_description": "문제 설명",
59+
"sample_sql": "예시 SQL",
60+
"effective_data_sources": "유효 데이터 소스",
61+
"advanced_application": "고급 애플리케이션"
5762
},
5863
"i18n_custom_prompt": {
5964
"exists_in_db": "템플릿 이름이 이미 존재합니다",

backend/locales/zh-CN.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@
5353
"datasource_cannot_be_none": "数据源不能为空",
5454
"datasource_assistant_cannot_be_none": "数据源或高级应用不能都为空",
5555
"data_training_not_exists": "该示例不存在",
56-
"exists_in_db": "该问题已存在"
56+
"exists_in_db": "该问题已存在",
57+
"data_training": "SQL 示例库",
58+
"problem_description": "问题描述",
59+
"sample_sql": "示例 SQL",
60+
"effective_data_sources": "生效数据源",
61+
"advanced_application": "高级应用"
5762
},
5863
"i18n_custom_prompt": {
5964
"exists_in_db": "模版名称已存在",

frontend/src/api/training.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,10 @@ export const trainingApi = {
99
deleteEmbedded: (params: any) => request.delete('/system/data-training', { data: params }),
1010
getOne: (id: any) => request.get(`/system/data-training/${id}`),
1111
enable: (id: any, enabled: any) => request.get(`/system/data-training/${id}/enable/${enabled}`),
12+
export2Excel: (params: any) =>
13+
request.get(`/system/data-training/export`, {
14+
params,
15+
responseType: 'blob',
16+
requestOptions: { customError: true },
17+
}),
1218
}

frontend/src/i18n/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"training_data_items": "Do you want to delete the {msg} selected SQL Sample items?",
4141
"sql_statement": "SQL Statement",
4242
"edit_training_data": "Edit SQL Sample",
43+
"all_236_terms": "Export all {msg} sample SQL records?",
4344
"sales_this_year": "Do you want to delete the SQL Sample: {msg}?"
4445
},
4546
"professional": {

frontend/src/i18n/ko-KR.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"training_data_items": "선택된 {msg}개의 예제 SQL을 삭제하시겠습니까?",
4141
"sql_statement": "SQL 문",
4242
"edit_training_data": "예제 SQL 편집",
43+
"all_236_terms": "모든 {msg}개의 예시 SQL 기록을 내보내시겠습니까?",
4344
"sales_this_year": "예제 SQL을 삭제하시겠습니까: {msg}?"
4445
},
4546
"professional": {

frontend/src/i18n/zh-CN.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"training_data_items": "是否删除选中的 {msg} 条示例 SQL?",
4141
"sql_statement": "SQL 语句",
4242
"edit_training_data": "编辑示例 SQL",
43+
"all_236_terms": "是否导出全部 {msg} 条示例 SQL?",
4344
"sales_this_year": "是否删除示例 SQL:{msg}?"
4445
},
4546
"professional": {

0 commit comments

Comments
 (0)