|
2 | 2 | import io |
3 | 3 | import traceback |
4 | 4 |
|
5 | | -import numpy as np |
6 | 5 | import orjson |
7 | 6 | import pandas as pd |
8 | 7 | from fastapi import APIRouter, HTTPException |
9 | 8 | from fastapi.responses import StreamingResponse |
10 | 9 | from sqlalchemy import and_, select |
11 | 10 |
|
12 | 11 | from apps.chat.curd.chat import list_chats, get_chat_with_records, create_chat, rename_chat, \ |
13 | | - delete_chat, get_chat_chart_data, get_chat_predict_data, get_chat_with_records_with_data, get_chat_record_by_id |
| 12 | + 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 |
14 | 14 | from apps.chat.models.chat_model import CreateChat, ChatRecord, RenameChat, ChatQuestion, ExcelData |
15 | 15 | from apps.chat.task.llm import LLMService |
16 | 16 | from common.core.deps import CurrentAssistant, SessionDep, CurrentUser, Trans |
@@ -45,15 +45,17 @@ def inner(): |
45 | 45 | @router.get("/record/get/{chart_record_id}/data") |
46 | 46 | async def chat_record_data(session: SessionDep, chart_record_id: int): |
47 | 47 | def inner(): |
48 | | - return get_chat_chart_data(chart_record_id=chart_record_id, session=session) |
| 48 | + data = get_chat_chart_data(chart_record_id=chart_record_id, session=session) |
| 49 | + return format_json_data(data) |
49 | 50 |
|
50 | 51 | return await asyncio.to_thread(inner) |
51 | 52 |
|
52 | 53 |
|
53 | 54 | @router.get("/record/get/{chart_record_id}/predict_data") |
54 | 55 | async def chat_predict_data(session: SessionDep, chart_record_id: int): |
55 | 56 | def inner(): |
56 | | - return get_chat_predict_data(chart_record_id=chart_record_id, session=session) |
| 57 | + data = get_chat_predict_data(chart_record_id=chart_record_id, session=session) |
| 58 | + return format_json_data(data) |
57 | 59 |
|
58 | 60 | return await asyncio.to_thread(inner) |
59 | 61 |
|
@@ -211,21 +213,53 @@ def inner(): |
211 | 213 | detail=trans("i18n_excel_export.data_is_empty") |
212 | 214 | ) |
213 | 215 |
|
| 216 | + # 预处理数据并记录每列的格式类型 |
| 217 | + col_formats = {} # 格式类型:'text'(文本)、'number'(数字)、'default'(默认) |
| 218 | + for field_idx, field in enumerate(excel_data.axis): |
| 219 | + _fields_list.append(field.name) |
| 220 | + col_formats[field_idx] = 'default' # 默认不特殊处理 |
| 221 | + |
214 | 222 | for _data in excel_data.data: |
215 | 223 | _row = [] |
216 | | - for field in excel_data.axis: |
217 | | - _row.append(_data.get(field.value)) |
| 224 | + for field_idx, field in enumerate(excel_data.axis): |
| 225 | + value = _data.get(field.value) |
| 226 | + if value is not None: |
| 227 | + # 检查是否为数字且需要特殊处理 |
| 228 | + if isinstance(value, (int, float)): |
| 229 | + # 整数且超过15位 → 转字符串并标记为文本列 |
| 230 | + if isinstance(value, int) and len(str(abs(value))) > 15: |
| 231 | + value = str(value) |
| 232 | + col_formats[field_idx] = 'text' |
| 233 | + # 小数且超过15位有效数字 → 转字符串并标记为文本列 |
| 234 | + elif isinstance(value, float): |
| 235 | + decimal_str = format(value, '.16f').rstrip('0').rstrip('.') |
| 236 | + if len(decimal_str) > 15: |
| 237 | + value = str(value) |
| 238 | + col_formats[field_idx] = 'text' |
| 239 | + # 其他数字列标记为数字格式(避免科学记数法) |
| 240 | + elif col_formats[field_idx] != 'text': |
| 241 | + col_formats[field_idx] = 'number' |
| 242 | + _row.append(value) |
218 | 243 | data.append(_row) |
219 | | - for field in excel_data.axis: |
220 | | - _fields_list.append(field.name) |
221 | | - df = pd.DataFrame(np.array(data), columns=_fields_list) |
| 244 | + |
| 245 | + df = pd.DataFrame(data, columns=_fields_list) |
222 | 246 |
|
223 | 247 | buffer = io.BytesIO() |
224 | 248 |
|
225 | 249 | with pd.ExcelWriter(buffer, engine='xlsxwriter', |
226 | | - engine_kwargs={'options': {'strings_to_numbers': True}}) as writer: |
| 250 | + engine_kwargs={'options': {'strings_to_numbers': False}}) as writer: |
227 | 251 | df.to_excel(writer, sheet_name='Sheet1', index=False) |
228 | 252 |
|
| 253 | + # 获取 xlsxwriter 的工作簿和工作表对象 |
| 254 | + workbook = writer.book |
| 255 | + worksheet = writer.sheets['Sheet1'] |
| 256 | + |
| 257 | + for col_idx, fmt_type in col_formats.items(): |
| 258 | + if fmt_type == 'text': |
| 259 | + worksheet.set_column(col_idx, col_idx, None, workbook.add_format({'num_format': '@'})) |
| 260 | + elif fmt_type == 'number': |
| 261 | + worksheet.set_column(col_idx, col_idx, None, workbook.add_format({'num_format': '0'})) |
| 262 | + |
229 | 263 | buffer.seek(0) |
230 | 264 | return io.BytesIO(buffer.getvalue()) |
231 | 265 |
|
|
0 commit comments