Compare commits

..

2 Commits

7 changed files with 8 additions and 102 deletions

View File

@@ -1,6 +1,3 @@
from sqlalchemy import case, func, select
from sqlmodel import col
from astrbot.api import sp, star
from astrbot.api.event import AstrMessageEvent, MessageEventResult
from astrbot.core import logger
@@ -10,7 +7,6 @@ from astrbot.core.agent.runners.deerflow.constants import (
DEERFLOW_THREAD_ID_KEY,
)
from astrbot.core.agent.runners.deerflow.deerflow_api_client import DeerFlowAPIClient
from astrbot.core.db.po import ProviderStat
from astrbot.core.utils.active_event_registry import active_event_registry
from .utils.rst_scene import RstScene
@@ -250,62 +246,3 @@ class ConversationCommands:
f"✅ Switched to new conversation: {cid[:4]}"
),
)
async def stats(self, message: AstrMessageEvent) -> None:
"""Show token usage statistics for the current conversation."""
umo = message.unified_msg_origin
cid = await self.context.conversation_manager.get_curr_conversation_id(umo)
if not cid:
message.set_result(
MessageEventResult().message(
"❌ You are not in a conversation. Use /new to create one."
),
)
return
db = self.context.get_db()
async with db.get_db() as session:
result = await session.execute(
select(
func.count(case((col(ProviderStat.id).is_not(None), 1))).label(
"record_count",
),
func.coalesce(func.sum(ProviderStat.token_input_other), 0).label(
"total_input_other",
),
func.coalesce(func.sum(ProviderStat.token_input_cached), 0).label(
"total_input_cached",
),
func.coalesce(func.sum(ProviderStat.token_output), 0).label(
"total_output",
),
).where(
col(ProviderStat.agent_type) == "internal",
col(ProviderStat.conversation_id) == cid,
)
)
stats = result.one()
if stats.record_count == 0:
message.set_result(
MessageEventResult().message(
"📊 No stats available for this conversation yet."
),
)
return
total_input_other = stats.total_input_other
total_input_cached = stats.total_input_cached
total_output = stats.total_output
total_tokens = total_input_other + total_input_cached + total_output
ret = (
f"📊 Conversation Token usage (ID: {cid[:8]}...)\n"
f"Total: {total_tokens:,}\n"
f"Input (cached): {total_input_cached:,}\n"
f"Input (other): {total_input_other:,}\n"
f"Output: {total_output:,}\n"
)
message.set_result(MessageEventResult().message(ret))

View File

@@ -47,11 +47,6 @@ class Main(star.Star):
"""Create new conversation"""
await self.conversation_c.new_conv(message)
@filter.command("stats")
async def stats(self, message: AstrMessageEvent) -> None:
"""Show token usage statistics for the current conversation"""
await self.conversation_c.stats(message)
@filter.permission_type(filter.PermissionType.ADMIN)
@filter.command("provider")
async def provider(

View File

@@ -293,15 +293,6 @@
/>
</template>
<v-card class="stats-card" elevation="4">
<div
v-if="cachedInputTokens(messageContent(msg).agentStats) > 0"
class="stats-row"
>
<span>{{ tm("stats.cachedTokens") }}</span>
<strong>{{
cachedInputTokens(messageContent(msg).agentStats)
}}</strong>
</div>
<div class="stats-row">
<span>{{ tm("stats.inputTokens") }}</span>
<strong>{{ inputTokens(messageContent(msg).agentStats) }}</strong>
@@ -859,17 +850,13 @@ function formatTime(value: string) {
function inputTokens(stats: any) {
const usage = stats?.token_usage || {};
return usage.input_other || 0;
return (usage.input_other || 0) + (usage.input_cached || 0);
}
function outputTokens(stats: any) {
return stats?.token_usage?.output || 0;
}
function cachedInputTokens(stats: any) {
return stats?.token_usage?.input_cached || 0;
}
function agentDuration(stats: any) {
const directDuration = readPositiveNumber(stats, [
"duration",

View File

@@ -185,15 +185,6 @@
/>
</template>
<v-card class="stats-card" elevation="4">
<div
v-if="cachedInputTokens(messageContent(msg).agentStats) > 0"
class="stats-row"
>
<span>{{ tm("stats.cachedTokens") }}</span>
<strong>{{
cachedInputTokens(messageContent(msg).agentStats)
}}</strong>
</div>
<div class="stats-row">
<span>{{ tm("stats.inputTokens") }}</span>
<strong>{{
@@ -521,17 +512,13 @@ function formatTime(value: string) {
function inputTokens(stats: any) {
const usage = stats?.token_usage || {};
return usage.input_other || 0;
return (usage.input_other || 0) + (usage.input_cached || 0);
}
function outputTokens(stats: any) {
return stats?.token_usage?.output || 0;
}
function cachedInputTokens(stats: any) {
return stats?.token_usage?.input_cached || 0;
}
function agentDuration(stats: any) {
const directDuration = readPositiveNumber(stats, [
"duration",

View File

@@ -137,9 +137,9 @@
},
"stats": {
"tokens": "Tokens",
"inputTokens": "Input (other)",
"inputTokens": "Input Tokens",
"outputTokens": "Output Tokens",
"cachedTokens": "Input (cached)",
"cachedTokens": "Cached Tokens",
"duration": "Duration",
"ttft": "Time to First Token"
},

View File

@@ -137,9 +137,9 @@
},
"stats": {
"tokens": "Токены",
"inputTokens": "Входящие (прочие)",
"inputTokens": "Входящие",
"outputTokens": "Исходящие",
"cachedTokens": "Входящие (кэш)",
"cachedTokens": "Кэшированные",
"duration": "Время",
"ttft": "Время до первого токена"
},

View File

@@ -137,9 +137,9 @@
},
"stats": {
"tokens": "Token",
"inputTokens": "输入(其他)",
"inputTokens": "输入 Token",
"outputTokens": "输出 Token",
"cachedTokens": "输入(缓存)",
"cachedTokens": "缓存 Token",
"duration": "耗时",
"ttft": "首字时间"
},