Skip to content

Commit ce5dd69

Browse files
committed
feat: add chat log step display
#324 #742
1 parent 6bb748a commit ce5dd69

File tree

13 files changed

+141
-39
lines changed

13 files changed

+141
-39
lines changed

backend/apps/chat/api/chat.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ def inner():
9898

9999
return await asyncio.to_thread(inner)
100100

101+
@router.get("/record/{chat_record_id}/usage", summary=f"{PLACEHOLDER_PREFIX}get_record_usage")
102+
async def chat_record_usage(session: SessionDep, current_user: CurrentUser, chat_record_id: int):
103+
def inner():
104+
return get_chat_log_history(session, chat_record_id, current_user, True)
105+
106+
return await asyncio.to_thread(inner)
107+
101108

102109
""" @router.post("/rename", response_model=str, summary=f"{PLACEHOLDER_PREFIX}rename_chat")
103110
@system_log(LogConfig(

backend/apps/chat/curd/chat.py

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -514,14 +514,15 @@ def format_record(record: ChatRecordResult):
514514
return _dict
515515

516516

517-
def get_chat_log_history(session: SessionDep, chat_record_id: int, current_user: CurrentUser) -> ChatLogHistory:
517+
def get_chat_log_history(session: SessionDep, chat_record_id: int, current_user: CurrentUser, without_steps: bool = False) -> ChatLogHistory:
518518
"""
519519
获取ChatRecord的详细历史记录
520520
521521
Args:
522522
session: 数据库会话
523523
chat_record_id: ChatRecord的ID
524524
current_user: 当前用户
525+
without_steps
525526
526527
Returns:
527528
ChatLogHistory: 包含历史步骤和时间信息的对象
@@ -536,23 +537,15 @@ def get_chat_log_history(session: SessionDep, chat_record_id: int, current_user:
536537

537538
# 2. 查询与该ChatRecord相关的所有ChatLog记录
538539
chat_logs = session.query(ChatLog).filter(
539-
ChatLog.pid == chat_record_id
540+
ChatLog.pid == chat_record_id,
541+
ChatLog.operate != OperationEnum.GENERATE_RECOMMENDED_QUESTIONS
540542
).order_by(ChatLog.start_time).all()
541543

542544
# 3. 计算总的时间和token信息
543545
total_tokens = 0
544546
steps = []
545547

546548
for log in chat_logs:
547-
# 计算单条记录的耗时
548-
duration = None
549-
if log.start_time and log.finish_time:
550-
try:
551-
time_diff = log.finish_time - log.start_time
552-
duration = time_diff.total_seconds()
553-
except Exception:
554-
duration = None
555-
556549
# 计算单条记录的token消耗
557550
log_tokens = 0
558551
if log.token_usage is not None:
@@ -567,16 +560,46 @@ def get_chat_log_history(session: SessionDep, chat_record_id: int, current_user:
567560
# 累加到总token消耗
568561
total_tokens += log_tokens
569562

570-
# 创建ChatLogHistoryItem
571-
history_item = ChatLogHistoryItem(
572-
start_time=log.start_time,
573-
finish_time=log.finish_time,
574-
duration=duration,
575-
total_tokens=log_tokens,
576-
operate=log.operate,
577-
local_operation=log.local_operation
578-
)
579-
steps.append(history_item)
563+
if not without_steps:
564+
# 计算单条记录的耗时
565+
duration = None
566+
if log.start_time and log.finish_time:
567+
try:
568+
time_diff = log.finish_time - log.start_time
569+
duration = round(time_diff.total_seconds(), 2)
570+
except Exception:
571+
duration = None
572+
573+
# 获取操作类型的枚举名称
574+
operate_name = None
575+
if log.operate:
576+
# 如果是OperationEnum枚举实例
577+
if isinstance(log.operate, OperationEnum):
578+
operate_name = log.operate.name
579+
# 如果是字符串,尝试从枚举值获取名称
580+
elif isinstance(log.operate, str):
581+
try:
582+
# 通过枚举值找到对应的枚举实例
583+
for enum_item in OperationEnum:
584+
if enum_item.value == log.operate:
585+
operate_name = enum_item.name
586+
break
587+
except Exception:
588+
operate_name = log.operate
589+
else:
590+
operate_name = str(log.operate)
591+
592+
# 创建ChatLogHistoryItem
593+
history_item = ChatLogHistoryItem(
594+
start_time=log.start_time,
595+
finish_time=log.finish_time,
596+
duration=duration,
597+
total_tokens=log_tokens,
598+
operate=operate_name,
599+
local_operation=log.local_operation
600+
)
601+
602+
steps.append(history_item)
580603

581604
# 4. 计算总耗时(使用ChatRecord的时间)
582605
total_duration = None

backend/apps/chat/models/chat_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class ChatLogHistoryItem(BaseModel):
193193
finish_time: Optional[datetime] = None
194194
duration: Optional[float] = None # 耗时字段(单位:秒)
195195
total_tokens: Optional[int] = None # token总消耗
196-
operate: Optional[OperationEnum] = None
196+
operate: Optional[str] = None
197197
local_operation: Optional[bool] = False
198198

199199
class ChatLogHistory(BaseModel):

backend/apps/swagger/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
"get_chart_data": "Get Chart Data",
143143
"get_chart_predict_data": "Get Chart Prediction Data",
144144
"get_record_log": "Get Chart Record Log",
145+
"get_record_usage": "Get Chart Record Token Usage & Duration",
145146
"rename_chat": "Rename Chat",
146147
"delete_chat": "Delete Chat",
147148
"start_chat": "Create Chat",

backend/apps/swagger/locales/zh.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
"get_chart_data": "获取图表数据",
143143
"get_chart_predict_data": "获取图表预测数据",
144144
"get_record_log": "获取对话日志",
145+
"get_record_usage": "获取对话Token使用量及耗时",
145146
"rename_chat": "重命名对话",
146147
"delete_chat": "删除对话",
147148
"start_chat": "创建对话",

frontend/src/api/chat.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { request } from '@/utils/request'
22
import { getDate } from '@/utils/utils.ts'
3+
import { i18n } from '@/i18n'
4+
5+
const { t } = i18n.global
36

47
export const questionApi = {
58
pager: (pageNumber: number, pageSize: number) =>
@@ -320,7 +323,7 @@ export class ChatLogHistoryItem {
320323
this.finish_time = getDate(finish_time)
321324
this.duration = duration
322325
this.total_tokens = total_tokens
323-
this.operate = operate
326+
this.operate = t('chat.log.' + operate)
324327
this.local_operation = !!local_operation
325328
}
326329
}
@@ -441,6 +444,9 @@ export const chatApi = {
441444
get_chart_log_history: (record_id?: number): Promise<any> => {
442445
return request.get(`/chat/record/${record_id}/log`)
443446
},
447+
get_chart_usage: (record_id?: number): Promise<any> => {
448+
return request.get(`/chat/record/${record_id}/usage`)
449+
},
444450
startChat: (data: any): Promise<ChatInfo> => {
445451
return request.post('/chat/start', data)
446452
},

frontend/src/i18n/en.json

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,22 @@
709709
"exec-sql-err": "Execute SQL failed",
710710
"no_data": "No Data",
711711
"loading_data": "Loading ...",
712-
"show_error_detail": "Show error info"
712+
"show_error_detail": "Show error info",
713+
"log": {
714+
"GENERATE_SQL": "Generate SQL",
715+
"GENERATE_CHART": "Generate Chart Structure",
716+
"ANALYSIS": "Analyze",
717+
"PREDICT_DATA": "Predict",
718+
"GENERATE_SQL_WITH_PERMISSIONS": "Apply Row Permissions to SQL",
719+
"CHOOSE_DATASOURCE": "Match Datasource",
720+
"GENERATE_DYNAMIC_SQL": "Generate Dynamic SQL",
721+
"CHOOSE_TABLE": "Match Data Table (Schema)",
722+
"FILTER_TERMS": "Match Terms",
723+
"FILTER_SQL_EXAMPLE": "Match SQL Examples",
724+
"FILTER_CUSTOM_PROMPT": "Match Custom Prompts",
725+
"EXECUTE_SQL": "Execute SQL",
726+
"GENERATE_PICTURE": "Generate Picture"
727+
}
713728
},
714729
"about": {
715730
"title": "About",
@@ -874,4 +889,4 @@
874889
"to_doc": "View API",
875890
"trigger_limit": "Supports up to {0} API Keys"
876891
}
877-
}
892+
}

frontend/src/i18n/ko-KR.json

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,22 @@
709709
"exec-sql-err": "SQL 실행 실패",
710710
"no_data": "데이터가 없습니다",
711711
"loading_data": "로딩 중 ...",
712-
"show_error_detail": "구체적인 정보 보기"
712+
"show_error_detail": "구체적인 정보 보기",
713+
"log": {
714+
"GENERATE_SQL": "SQL 생성",
715+
"GENERATE_CHART": "차트 구조 생성",
716+
"ANALYSIS": "분석",
717+
"PREDICT_DATA": "예측",
718+
"GENERATE_SQL_WITH_PERMISSIONS": "SQL에 행 권한 적용",
719+
"CHOOSE_DATASOURCE": "데이터 소스 매칭",
720+
"GENERATE_DYNAMIC_SQL": "동적 SQL 생성",
721+
"CHOOSE_TABLE": "데이터 테이블 매칭 (스키마)",
722+
"FILTER_TERMS": "용어 매칭",
723+
"FILTER_SQL_EXAMPLE": "SQL 예시 매칭",
724+
"FILTER_CUSTOM_PROMPT": "사용자 정의 프롬프트 매칭",
725+
"EXECUTE_SQL": "SQL 실행",
726+
"GENERATE_PICTURE": "이미지 생성"
727+
}
713728
},
714729
"about": {
715730
"title": "정보",
@@ -874,4 +889,4 @@
874889
"to_doc": "API 보기",
875890
"trigger_limit": "최대 {0}개의 API 키 생성 지원"
876891
}
877-
}
892+
}

frontend/src/i18n/zh-CN.json

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,22 @@
709709
"exec-sql-err": "执行SQL失败",
710710
"no_data": "暂无数据",
711711
"loading_data": "加载中...",
712-
"show_error_detail": "查看具体信息"
712+
"show_error_detail": "查看具体信息",
713+
"log": {
714+
"GENERATE_SQL": "生成 SQL",
715+
"GENERATE_CHART": "生成图表结构",
716+
"ANALYSIS": "分析",
717+
"PREDICT_DATA": "预测",
718+
"GENERATE_SQL_WITH_PERMISSIONS": "拼接 SQL 行权限",
719+
"CHOOSE_DATASOURCE": "匹配数据源",
720+
"GENERATE_DYNAMIC_SQL": "生成动态 SQL",
721+
"CHOOSE_TABLE": "匹配数据表 (Schema)",
722+
"FILTER_TERMS": "匹配术语",
723+
"FILTER_SQL_EXAMPLE": "匹配 SQL 示例",
724+
"FILTER_CUSTOM_PROMPT": "匹配自定义提示词",
725+
"EXECUTE_SQL": "执行 SQL",
726+
"GENERATE_PICTURE": "生成图片"
727+
}
713728
},
714729
"about": {
715730
"title": "关于",
@@ -874,4 +889,4 @@
874889
"to_doc": "查看 API",
875890
"trigger_limit": "最多支持创建 {0} 个 API Key"
876891
}
877-
}
892+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ const sendMessage = async () => {
158158
break
159159
case 'error':
160160
currentRecord.error = data.content
161-
emits('error')
161+
emits('error', currentRecord.id)
162162
break
163163
case 'analysis-result':
164164
analysis_answer += data.content

0 commit comments

Comments
 (0)