Skip to content

Commit 71cf683

Browse files
committed
feat: 更新时间范围为14天和14小时,优化满意度计算逻辑
1 parent 0835ab7 commit 71cf683

File tree

5 files changed

+86
-41
lines changed

5 files changed

+86
-41
lines changed

docs/changelog/roadmap.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
## Bugs
99

1010
- [ ] 前端工具调用渲染出现问题
11-
- [ ] 智能体的加载状态有问题:(1)智能体加载没有动画;(2)切换对话和加载中,使用同一个loading状态。
1211

1312
## Next
1413

@@ -43,4 +42,5 @@
4342
- [x] v1 版本的 LangGraph 的工具渲染有问题
4443
- [x] upload 接口会阻塞主进程
4544
- [x] LightRAG 知识库查看不了解析后的文本,偶然出现,未复现
46-
- [x] LightRAG 知识库应该可以支持修改 LLM
45+
- [x] LightRAG 知识库应该可以支持修改 LLM
46+
- [x] 智能体的加载状态有问题:(1)智能体加载没有动画;(2)切换对话和加载中,使用同一个loading状态。

server/routers/dashboard_router.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ async def get_agent_analytics(
540540
or 0
541541
)
542542

543-
satisfaction_rate = round((positive_feedbacks / total_feedbacks * 100), 2) if total_feedbacks > 0 else 0
543+
satisfaction_rate = round((positive_feedbacks / total_feedbacks * 100), 2) if total_feedbacks > 0 else 100
544544

545545
agent_satisfaction.append(
546546
{"agent_id": agent_id, "satisfaction_rate": satisfaction_rate, "total_feedbacks": total_feedbacks}
@@ -624,7 +624,7 @@ async def get_dashboard_stats(
624624
like_count = db.query(func.count(MessageFeedback.id)).filter(MessageFeedback.rating == "like").scalar() or 0
625625

626626
# Calculate satisfaction rate
627-
satisfaction_rate = round((like_count / total_feedbacks * 100), 2) if total_feedbacks > 0 else 0
627+
satisfaction_rate = round((like_count / total_feedbacks * 100), 2) if total_feedbacks > 0 else 100
628628

629629
return {
630630
"total_conversations": total_conversations,
@@ -738,7 +738,7 @@ class TimeSeriesStats(BaseModel):
738738
@dashboard.get("/stats/calls/timeseries", response_model=TimeSeriesStats)
739739
async def get_call_timeseries_stats(
740740
type: str = "models", # models/agents/tokens/tools
741-
time_range: str = "7days", # 7hours/7days/7weeks
741+
time_range: str = "14days", # 14hours/14days/14weeks
742742
db: Session = Depends(get_db),
743743
current_user: User = Depends(get_admin_user),
744744
):
@@ -750,24 +750,24 @@ async def get_call_timeseries_stats(
750750
now = utc_now()
751751
local_now = shanghai_now()
752752

753-
if time_range == "7hours":
754-
intervals = 7
755-
# 包含当前小时:从6小时前开始
753+
if time_range == "14hours":
754+
intervals = 14
755+
# 包含当前小时:从13小时前开始
756756
start_time = now - timedelta(hours=intervals - 1)
757757
group_format = func.strftime("%Y-%m-%d %H:00", func.datetime(Message.created_at, "+8 hours"))
758758
base_local_time = ensure_shanghai(start_time)
759-
elif time_range == "7weeks":
760-
intervals = 7
761-
# 包含当前周:从6周前开始,并对齐到当周周一 00:00
759+
elif time_range == "14weeks":
760+
intervals = 14
761+
# 包含当前周:从13周前开始,并对齐到当周周一 00:00
762762
local_start = local_now - timedelta(weeks=intervals - 1)
763763
local_start = local_start - timedelta(days=local_start.weekday())
764764
local_start = local_start.replace(hour=0, minute=0, second=0, microsecond=0)
765765
start_time = local_start.astimezone(UTC)
766766
group_format = func.strftime("%Y-%W", func.datetime(Message.created_at, "+8 hours"))
767767
base_local_time = local_start
768-
else: # 7days (default)
769-
intervals = 7
770-
# 包含当前天:从6天前开始
768+
else: # 14days (default)
769+
intervals = 14
770+
# 包含当前天:从13天前开始
771771
start_time = now - timedelta(days=intervals - 1)
772772
group_format = func.strftime("%Y-%m-%d", func.datetime(Message.created_at, "+8 hours"))
773773
base_local_time = ensure_shanghai(start_time)
@@ -790,11 +790,11 @@ async def get_call_timeseries_stats(
790790
elif type == "agents":
791791
# 智能体调用统计(基于对话更新时间,按智能体分组)
792792
# 为对话创建独立的时间格式化器
793-
if time_range == "7hours":
793+
if time_range == "14hours":
794794
conv_group_format = func.strftime("%Y-%m-%d %H:00", func.datetime(Conversation.updated_at, "+8 hours"))
795-
elif time_range == "7weeks":
795+
elif time_range == "14weeks":
796796
conv_group_format = func.strftime("%Y-%W", func.datetime(Conversation.updated_at, "+8 hours"))
797-
else: # 7days
797+
else: # 14days
798798
conv_group_format = func.strftime("%Y-%m-%d", func.datetime(Conversation.updated_at, "+8 hours"))
799799

800800
query = (
@@ -855,11 +855,11 @@ async def get_call_timeseries_stats(
855855
elif type == "tools":
856856
# 工具调用统计(按工具名称分组)
857857
# 为工具调用创建独立的时间格式化器
858-
if time_range == "7hours":
858+
if time_range == "14hours":
859859
tool_group_format = func.strftime("%Y-%m-%d %H:00", func.datetime(ToolCall.created_at, "+8 hours"))
860-
elif time_range == "7weeks":
860+
elif time_range == "14weeks":
861861
tool_group_format = func.strftime("%Y-%W", func.datetime(ToolCall.created_at, "+8 hours"))
862-
else: # 7days
862+
else: # 14days
863863
tool_group_format = func.strftime("%Y-%m-%d", func.datetime(ToolCall.created_at, "+8 hours"))
864864

865865
query = (
@@ -908,7 +908,7 @@ def normalize_week_key(raw_key: str) -> str:
908908

909909
for result in results:
910910
date_key = result.date
911-
if time_range == "7weeks":
911+
if time_range == "14weeks":
912912
date_key = normalize_week_key(date_key)
913913
category = getattr(result, "category", "unknown")
914914
count = result.count
@@ -923,17 +923,17 @@ def normalize_week_key(raw_key: str) -> str:
923923
# 从起始点开始(北京时间)
924924
current_time = base_local_time
925925

926-
if time_range == "7hours":
926+
if time_range == "14hours":
927927
delta = timedelta(hours=1)
928-
elif time_range == "7weeks":
928+
elif time_range == "14weeks":
929929
delta = timedelta(weeks=1)
930930
else:
931931
delta = timedelta(days=1)
932932

933933
for i in range(intervals):
934-
if time_range == "7hours":
934+
if time_range == "14hours":
935935
date_key = current_time.strftime("%Y-%m-%d %H:00")
936-
elif time_range == "7weeks":
936+
elif time_range == "14weeks":
937937
iso_year, iso_week, _ = current_time.isocalendar()
938938
date_key = f"{iso_year}-{iso_week:02d}"
939939
else:

web/src/apis/dashboard_api.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ export const dashboardApi = {
123123
/**
124124
* 获取调用统计时间序列数据
125125
* @param {string} type - 数据类型 (models/agents/tokens/tools)
126-
* @param {string} timeRange - 时间范围 (7hours/7days/7weeks)
126+
* @param {string} timeRange - 时间范围 (14hours/14days/14weeks)
127127
* @returns {Promise<Object>} - 时间序列统计数据
128128
*/
129-
getCallTimeseries: (type = 'models', timeRange = '7days') => {
129+
getCallTimeseries: (type = 'models', timeRange = '14days') => {
130130
return apiAdminGet(`/api/dashboard/stats/calls/timeseries?type=${type}&time_range=${timeRange}`)
131131
}
132132
}

web/src/components/AgentChatComponent.vue

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,14 @@
4545
</div>
4646
</div>
4747

48-
<div v-if="isLoadingThreads || isLoadingMessages" class="chat-loading">
49-
<LoadingOutlined />
50-
<span>正在加载历史记录...</span>
48+
<!-- 加载状态:新建对话或加载消息 -->
49+
<div v-if="chatState.creatingNewChat" class="chat-loading">
50+
<div class="loading-spinner"></div>
51+
<span>正在创建新对话...</span>
52+
</div>
53+
<div v-else-if="isLoadingMessages" class="chat-loading">
54+
<div class="loading-spinner"></div>
55+
<span>正在加载消息...</span>
5156
</div>
5257

5358
<div v-else-if="!conversations.length" class="chat-examples">
@@ -304,7 +309,7 @@ const isStreaming = computed(() => {
304309
const threadState = currentThreadState.value;
305310
return threadState ? threadState.isStreaming : false;
306311
});
307-
const isProcessing = computed(() => isStreaming.value || chatState.creatingNewChat);
312+
const isProcessing = computed(() => isStreaming.value);
308313
const isSmallContainer = computed(() => uiState.containerWidth <= 520);
309314
const isMediumContainer = computed(() => uiState.containerWidth <= 768);
310315
@@ -1218,10 +1223,23 @@ watch(conversations, () => {
12181223
width: 100%;
12191224
z-index: 9;
12201225
animation: slideInUp 0.5s ease-out;
1226+
display: flex;
1227+
align-items: center;
1228+
justify-content: center;
1229+
gap: 12px;
12211230
12221231
span {
1223-
margin-left: 8px;
12241232
color: var(--gray-700);
1233+
font-size: 14px;
1234+
}
1235+
1236+
.loading-spinner {
1237+
width: 20px;
1238+
height: 20px;
1239+
border: 2px solid var(--gray-200);
1240+
border-top-color: var(--main-color);
1241+
border-radius: 50%;
1242+
animation: spin 0.8s linear infinite;
12251243
}
12261244
}
12271245

web/src/components/dashboard/CallStatsComponent.vue

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,40 @@ const props = defineProps({
5151
// state
5252
const callStatsData = ref(null)
5353
const callStatsLoading = ref(false)
54-
const callTimeRange = ref('7days')
54+
const callTimeRange = ref('14days')
5555
const callDataType = ref('models')
5656
const timeRangeOptions = [
57-
{ value: '7hours', label: '近7小时' },
58-
{ value: '7days', label: '近7天' },
59-
{ value: '7weeks', label: '近7周' },
57+
{ value: '14hours', label: '近14小时' },
58+
{ value: '14days', label: '近14天' },
59+
{ value: '14weeks', label: '近14周' },
6060
]
6161
const dataTypeOptions = [
6262
{ value: 'models', label: '模型调用' },
6363
{ value: 'agents', label: '智能体调用' },
6464
{ value: 'tokens', label: 'Token消耗' },
6565
{ value: 'tools', label: '工具调用' },
6666
]
67+
const isTokenView = computed(() => callDataType.value === 'tokens')
68+
69+
const formatTokenValue = (value) => {
70+
if (value === null || value === undefined || Number.isNaN(value)) {
71+
return '0M'
72+
}
73+
const millionValue = value / 1_000_000
74+
const absMillion = Math.abs(millionValue)
75+
const decimalPlaces = absMillion >= 100 ? 0 : absMillion >= 10 ? 1 : 2
76+
return `${millionValue.toFixed(decimalPlaces)}M`
77+
}
78+
79+
const formatValueForDisplay = (value) => {
80+
if (isTokenView.value) {
81+
return formatTokenValue(value)
82+
}
83+
if (typeof value === 'number') {
84+
return value.toLocaleString()
85+
}
86+
return (value ?? 0).toString()
87+
}
6788
6889
const switchTimeRange = (val) => {
6990
if (callTimeRange.value === val) return
@@ -131,9 +152,9 @@ const renderCallStatsChart = () => {
131152
132153
const xAxisData = data.map(item => {
133154
const date = item.date
134-
if (callTimeRange.value === '7hours') {
155+
if (callTimeRange.value === '14hours') {
135156
return date.split(' ')[1]
136-
} else if (callTimeRange.value === '7weeks') {
157+
} else if (callTimeRange.value === '14weeks') {
137158
return `${date.split('-')[1]}`
138159
} else {
139160
return date.split('-').slice(1).join('-')
@@ -171,7 +192,11 @@ const renderCallStatsChart = () => {
171192
type: 'value',
172193
axisLine: { show: false },
173194
axisTick: { show: false },
174-
axisLabel: { color: '#6b7280', fontSize: 12 },
195+
axisLabel: {
196+
color: '#6b7280',
197+
fontSize: 12,
198+
formatter: (value) => (isTokenView.value ? formatTokenValue(value) : value),
199+
},
175200
splitLine: { lineStyle: { color: '#f3f4f6' } }
176201
},
177202
tooltip: {
@@ -181,16 +206,18 @@ const renderCallStatsChart = () => {
181206
borderWidth: 1,
182207
textStyle: { color: '#374151', fontSize: 12 },
183208
formatter: (params) => {
209+
if (!params?.length) return ''
184210
let total = 0
185211
let result = `${params[0].name}<br/>`
186212
params.forEach(param => {
187213
total += param.value
188214
const truncatedName = truncateLegend(param.seriesName)
189215
result += `<span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${param.color}\"></span>`
190-
result += `${truncatedName}: ${param.value}<br/>`
216+
result += `${truncatedName}: ${formatValueForDisplay(param.value)}<br/>`
191217
})
192218
const labelMap = { models: '模型调用', agents: '智能体调用', tokens: 'Token消耗', tools: '工具调用' }
193-
return `<div style=\"font-weight:bold;margin-bottom:5px\">${labelMap[callDataType.value]}</div>${result}<strong>总计: ${total}</strong>`
219+
const formattedTotal = formatValueForDisplay(total)
220+
return `<div style=\"font-weight:bold;margin-bottom:5px\">${labelMap[callDataType.value]}</div>${result}<strong>总计: ${formattedTotal}</strong>`
194221
}
195222
},
196223
legend: {

0 commit comments

Comments
 (0)