mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-26 02:04:37 +08:00
feat: 聊天会话底部显示token消耗
This commit is contained in:
1 parent
f84eeb9b38
commit
dc71592980
11 files changed
+171
-25
No files matched your search
+59
-10
@@ -79,6 +79,15 @@ export interface AgentConfig {
|
||||
abortSignal?: AbortSignal
|
||||
}
|
||||
|
||||
/**
|
||||
* Token 使用量
|
||||
*/
|
||||
export interface TokenUsage {
|
||||
promptTokens: number
|
||||
completionTokens: number
|
||||
totalTokens: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent 流式响应 chunk
|
||||
*/
|
||||
@@ -97,6 +106,8 @@ export interface AgentStreamChunk {
|
||||
error?: string
|
||||
/** 是否完成 */
|
||||
isFinished?: boolean
|
||||
/** Token 使用量(type=done 时返回累计值) */
|
||||
usage?: TokenUsage
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,6 +120,8 @@ export interface AgentResult {
|
||||
toolsUsed: string[]
|
||||
/** 工具调用轮数 */
|
||||
toolRounds: number
|
||||
/** 总 Token 使用量(累计所有 LLM 调用) */
|
||||
totalUsage?: TokenUsage
|
||||
}
|
||||
|
||||
// ==================== 提示词配置类型 ====================
|
||||
@@ -235,6 +248,8 @@ export class Agent {
|
||||
private historyMessages: ChatMessage[] = []
|
||||
private chatType: 'group' | 'private' = 'group'
|
||||
private promptConfig?: PromptConfig
|
||||
/** 累计 Token 使用量 */
|
||||
private totalUsage: TokenUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 }
|
||||
|
||||
constructor(
|
||||
context: ToolContext,
|
||||
@@ -261,6 +276,17 @@ export class Agent {
|
||||
return this.abortSignal?.aborted ?? false
|
||||
}
|
||||
|
||||
/**
|
||||
* 累加 Token 使用量
|
||||
*/
|
||||
private addUsage(usage?: { promptTokens: number; completionTokens: number; totalTokens: number }): void {
|
||||
if (usage) {
|
||||
this.totalUsage.promptTokens += usage.promptTokens
|
||||
this.totalUsage.completionTokens += usage.completionTokens
|
||||
this.totalUsage.totalTokens += usage.totalTokens
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行对话(非流式)
|
||||
* @param userMessage 用户消息
|
||||
@@ -270,7 +296,7 @@ export class Agent {
|
||||
|
||||
// 检查是否已中止
|
||||
if (this.isAborted()) {
|
||||
return { content: '', toolsUsed: [], toolRounds: 0 }
|
||||
return { content: '', toolsUsed: [], toolRounds: 0, totalUsage: this.totalUsage }
|
||||
}
|
||||
|
||||
// 初始化消息(包含历史记录)
|
||||
@@ -294,6 +320,7 @@ export class Agent {
|
||||
content: '',
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,6 +330,9 @@ export class Agent {
|
||||
abortSignal: this.abortSignal,
|
||||
})
|
||||
|
||||
// 累加 Token 使用量
|
||||
this.addUsage(response.usage)
|
||||
|
||||
let toolCallsToProcess = response.tool_calls
|
||||
|
||||
// 如果没有标准 tool_calls,尝试 fallback 解析
|
||||
@@ -323,6 +353,7 @@ export class Agent {
|
||||
content: cleanContent,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -332,6 +363,7 @@ export class Agent {
|
||||
content: response.content,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,10 +381,12 @@ export class Agent {
|
||||
})
|
||||
|
||||
const finalResponse = await chat(this.messages, this.config.llmOptions)
|
||||
this.addUsage(finalResponse.usage)
|
||||
return {
|
||||
content: finalResponse.content,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,8 +400,8 @@ export class Agent {
|
||||
|
||||
// 检查是否已中止
|
||||
if (this.isAborted()) {
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
return { content: '', toolsUsed: [], toolRounds: 0 }
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
return { content: '', toolsUsed: [], toolRounds: 0, totalUsage: this.totalUsage }
|
||||
}
|
||||
|
||||
// 初始化消息(包含历史记录)
|
||||
@@ -387,11 +421,12 @@ export class Agent {
|
||||
while (this.toolRounds < this.config.maxToolRounds!) {
|
||||
// 每轮开始时检查是否中止
|
||||
if (this.isAborted()) {
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
return {
|
||||
content: finalContent,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,11 +443,12 @@ export class Agent {
|
||||
})) {
|
||||
// 每个 chunk 时检查是否中止
|
||||
if (this.isAborted()) {
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
return {
|
||||
content: finalContent + accumulatedContent,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
if (chunk.content) {
|
||||
@@ -444,6 +480,11 @@ export class Agent {
|
||||
toolCalls = chunk.tool_calls
|
||||
}
|
||||
|
||||
// 累加 Token 使用量(流式响应在最后一个 chunk 返回 usage)
|
||||
if (chunk.usage) {
|
||||
this.addUsage(chunk.usage)
|
||||
}
|
||||
|
||||
if (chunk.isFinished) {
|
||||
// 如果没有标准 tool_calls,尝试 fallback 解析
|
||||
if (chunk.finishReason !== 'tool_calls' || !toolCalls) {
|
||||
@@ -467,22 +508,24 @@ export class Agent {
|
||||
}
|
||||
finalContent = cleanContent
|
||||
aiLogger.info('Agent', 'AI 回复', finalContent)
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
return {
|
||||
content: finalContent,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有 tool_call 标签,正常完成
|
||||
finalContent = extractThinkingContent(accumulatedContent).cleanContent
|
||||
aiLogger.info('Agent', 'AI 回复', finalContent)
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
return {
|
||||
content: finalContent,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,11 +575,12 @@ export class Agent {
|
||||
|
||||
// 检查是否已中止
|
||||
if (this.isAborted()) {
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
return {
|
||||
content: finalContent,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,15 +595,19 @@ export class Agent {
|
||||
abortSignal: this.abortSignal,
|
||||
})) {
|
||||
if (this.isAborted()) {
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
break
|
||||
}
|
||||
if (chunk.content) {
|
||||
finalContent += chunk.content
|
||||
onChunk({ type: 'content', content: chunk.content })
|
||||
}
|
||||
// 累加 Token 使用量
|
||||
if (chunk.usage) {
|
||||
this.addUsage(chunk.usage)
|
||||
}
|
||||
if (chunk.isFinished) {
|
||||
onChunk({ type: 'done', isFinished: true })
|
||||
onChunk({ type: 'done', isFinished: true, usage: this.totalUsage })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,6 +615,7 @@ export class Agent {
|
||||
content: finalContent,
|
||||
toolsUsed: this.toolsUsed,
|
||||
toolRounds: this.toolRounds,
|
||||
totalUsage: this.totalUsage,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,8 @@ export class DeepSeekService implements ILLMService {
|
||||
temperature: options?.temperature ?? 0.7,
|
||||
max_tokens: options?.maxTokens ?? 2048,
|
||||
stream: true,
|
||||
// 启用流式响应中的 usage 统计
|
||||
stream_options: { include_usage: true },
|
||||
}
|
||||
|
||||
if (options?.tools && options.tools.length > 0) {
|
||||
@@ -265,6 +267,15 @@ export class DeepSeekService implements ILLMService {
|
||||
reason = 'tool_calls'
|
||||
}
|
||||
|
||||
// 解析 usage 信息
|
||||
const usage = parsed.usage
|
||||
? {
|
||||
promptTokens: parsed.usage.prompt_tokens,
|
||||
completionTokens: parsed.usage.completion_tokens,
|
||||
totalTokens: parsed.usage.total_tokens,
|
||||
}
|
||||
: undefined
|
||||
|
||||
// 如果有 tool_calls,返回它们
|
||||
if (toolCallsAccumulator.size > 0) {
|
||||
const toolCalls: ToolCall[] = Array.from(toolCallsAccumulator.values()).map((tc) => ({
|
||||
@@ -275,9 +286,9 @@ export class DeepSeekService implements ILLMService {
|
||||
arguments: tc.arguments,
|
||||
},
|
||||
}))
|
||||
yield { content: '', isFinished: true, finishReason: reason, tool_calls: toolCalls }
|
||||
yield { content: '', isFinished: true, finishReason: reason, tool_calls: toolCalls, usage }
|
||||
} else {
|
||||
yield { content: '', isFinished: true, finishReason: reason }
|
||||
yield { content: '', isFinished: true, finishReason: reason, usage }
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -396,6 +396,8 @@ export class GeminiService implements ILLMService {
|
||||
let buffer = ''
|
||||
// 用于累积工具调用(可能跨多个 chunk)
|
||||
const toolCallsAccumulator: ToolCall[] = []
|
||||
// 用于追踪最新的 usage 信息
|
||||
let latestUsage: { promptTokens: number; completionTokens: number; totalTokens: number } | undefined
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
@@ -445,19 +447,28 @@ export class GeminiService implements ILLMService {
|
||||
toolCallsAccumulator.push(...toolCalls)
|
||||
}
|
||||
|
||||
// 更新 usage 信息
|
||||
if (parsed.usageMetadata) {
|
||||
latestUsage = {
|
||||
promptTokens: parsed.usageMetadata.promptTokenCount || 0,
|
||||
completionTokens: parsed.usageMetadata.candidatesTokenCount || 0,
|
||||
totalTokens: parsed.usageMetadata.totalTokenCount || 0,
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否完成
|
||||
const finishReason = candidate?.finishReason
|
||||
if (finishReason) {
|
||||
aiLogger.info('Gemini', '流式响应完成', { finishReason, toolCallsCount: toolCallsAccumulator.length })
|
||||
aiLogger.info('Gemini', '流式响应完成', { finishReason, toolCallsCount: toolCallsAccumulator.length, usage: latestUsage })
|
||||
|
||||
if (toolCallsAccumulator.length > 0) {
|
||||
yield { content: '', isFinished: true, finishReason: 'tool_calls', tool_calls: toolCallsAccumulator }
|
||||
yield { content: '', isFinished: true, finishReason: 'tool_calls', tool_calls: toolCallsAccumulator, usage: latestUsage }
|
||||
} else {
|
||||
let reason: ChatStreamChunk['finishReason'] = 'stop'
|
||||
if (finishReason === 'MAX_TOKENS') {
|
||||
reason = 'length'
|
||||
}
|
||||
yield { content: '', isFinished: true, finishReason: reason }
|
||||
yield { content: '', isFinished: true, finishReason: reason, usage: latestUsage }
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -470,9 +481,9 @@ export class GeminiService implements ILLMService {
|
||||
|
||||
// 如果循环正常结束,发送完成信号
|
||||
if (toolCallsAccumulator.length > 0) {
|
||||
yield { content: '', isFinished: true, finishReason: 'tool_calls', tool_calls: toolCallsAccumulator }
|
||||
yield { content: '', isFinished: true, finishReason: 'tool_calls', tool_calls: toolCallsAccumulator, usage: latestUsage }
|
||||
} else {
|
||||
yield { content: '', isFinished: true, finishReason: 'stop' }
|
||||
yield { content: '', isFinished: true, finishReason: 'stop', usage: latestUsage }
|
||||
}
|
||||
} catch (error) {
|
||||
// 如果是中止错误,正常返回
|
||||
|
||||
@@ -162,6 +162,8 @@ export class OpenAICompatibleService implements ILLMService {
|
||||
temperature: options?.temperature ?? 0.7,
|
||||
max_tokens: options?.maxTokens ?? 2048,
|
||||
stream: true,
|
||||
// 启用流式响应中的 usage 统计(OpenAI API 兼容)
|
||||
stream_options: { include_usage: true },
|
||||
}
|
||||
|
||||
if (options?.tools && options.tools.length > 0) {
|
||||
@@ -290,6 +292,15 @@ export class OpenAICompatibleService implements ILLMService {
|
||||
reason = 'tool_calls'
|
||||
}
|
||||
|
||||
// 解析 usage 信息
|
||||
const usage = parsed.usage
|
||||
? {
|
||||
promptTokens: parsed.usage.prompt_tokens,
|
||||
completionTokens: parsed.usage.completion_tokens,
|
||||
totalTokens: parsed.usage.total_tokens,
|
||||
}
|
||||
: undefined
|
||||
|
||||
if (toolCallsAccumulator.size > 0) {
|
||||
const toolCalls: ToolCall[] = Array.from(toolCallsAccumulator.values()).map((tc) => ({
|
||||
id: tc.id,
|
||||
@@ -299,9 +310,9 @@ export class OpenAICompatibleService implements ILLMService {
|
||||
arguments: tc.arguments,
|
||||
},
|
||||
}))
|
||||
yield { content: '', isFinished: true, finishReason: reason, tool_calls: toolCalls }
|
||||
yield { content: '', isFinished: true, finishReason: reason, tool_calls: toolCalls, usage }
|
||||
} else {
|
||||
yield { content: '', isFinished: true, finishReason: reason }
|
||||
yield { content: '', isFinished: true, finishReason: reason, usage }
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -149,6 +149,8 @@ export class QwenService implements ILLMService {
|
||||
temperature: options?.temperature ?? 0.7,
|
||||
max_tokens: options?.maxTokens ?? 2048,
|
||||
stream: true,
|
||||
// 启用流式响应中的 usage 统计
|
||||
stream_options: { include_usage: true },
|
||||
}
|
||||
|
||||
if (options?.tools && options.tools.length > 0) {
|
||||
@@ -247,15 +249,24 @@ export class QwenService implements ILLMService {
|
||||
else if (finishReason === 'length') reason = 'length'
|
||||
else if (finishReason === 'tool_calls') reason = 'tool_calls'
|
||||
|
||||
// 解析 usage 信息
|
||||
const usage = parsed.usage
|
||||
? {
|
||||
promptTokens: parsed.usage.prompt_tokens,
|
||||
completionTokens: parsed.usage.completion_tokens,
|
||||
totalTokens: parsed.usage.total_tokens,
|
||||
}
|
||||
: undefined
|
||||
|
||||
if (toolCallsAccumulator.size > 0) {
|
||||
const toolCalls: ToolCall[] = Array.from(toolCallsAccumulator.values()).map((tc) => ({
|
||||
id: tc.id,
|
||||
type: 'function' as const,
|
||||
function: { name: tc.name, arguments: tc.arguments },
|
||||
}))
|
||||
yield { content: '', isFinished: true, finishReason: reason, tool_calls: toolCalls }
|
||||
yield { content: '', isFinished: true, finishReason: reason, tool_calls: toolCalls, usage }
|
||||
} else {
|
||||
yield { content: '', isFinished: true, finishReason: reason }
|
||||
yield { content: '', isFinished: true, finishReason: reason, usage }
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ export interface ChatStreamChunk {
|
||||
finishReason?: 'stop' | 'length' | 'error' | 'tool_calls'
|
||||
/** 流式过程中的 tool_calls(增量) */
|
||||
tool_calls?: ToolCall[]
|
||||
/** Token 使用量(通常在最后一个 chunk 中返回) */
|
||||
usage?: {
|
||||
promptTokens: number
|
||||
completionTokens: number
|
||||
totalTokens: number
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Function Calling 相关类型 ====================
|
||||
|
||||
@@ -445,6 +445,7 @@ export function registerAIHandlers({ win }: IpcContext): void {
|
||||
content: result.content,
|
||||
toolsUsed: result.toolsUsed,
|
||||
toolRounds: result.toolRounds,
|
||||
totalUsage: result.totalUsage,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -452,6 +453,7 @@ export function registerAIHandlers({ win }: IpcContext): void {
|
||||
toolsUsed: result.toolsUsed,
|
||||
toolRounds: result.toolRounds,
|
||||
contentLength: result.content.length,
|
||||
totalUsage: result.totalUsage,
|
||||
})
|
||||
} catch (error) {
|
||||
// 如果是中止错误,不报告为错误
|
||||
|
||||
Vendored
+12
@@ -294,6 +294,13 @@ interface LlmApi {
|
||||
) => Promise<{ success: boolean; error?: string }>
|
||||
}
|
||||
|
||||
// Token 使用量类型
|
||||
interface TokenUsage {
|
||||
promptTokens: number
|
||||
completionTokens: number
|
||||
totalTokens: number
|
||||
}
|
||||
|
||||
// Agent 相关类型
|
||||
interface AgentStreamChunk {
|
||||
type: 'content' | 'tool_start' | 'tool_result' | 'done' | 'error'
|
||||
@@ -303,12 +310,16 @@ interface AgentStreamChunk {
|
||||
toolResult?: unknown
|
||||
error?: string
|
||||
isFinished?: boolean
|
||||
/** Token 使用量(type=done 时返回累计值) */
|
||||
usage?: TokenUsage
|
||||
}
|
||||
|
||||
interface AgentResult {
|
||||
content: string
|
||||
toolsUsed: string[]
|
||||
toolRounds: number
|
||||
/** 总 Token 使用量(累计所有 LLM 调用) */
|
||||
totalUsage?: TokenUsage
|
||||
}
|
||||
|
||||
interface ToolContext {
|
||||
@@ -399,6 +410,7 @@ export {
|
||||
AgentResult,
|
||||
ToolContext,
|
||||
PromptConfig,
|
||||
TokenUsage,
|
||||
CacheDirectoryInfo,
|
||||
CacheInfo,
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
- **严禁**用于窃取、监控或分析未经授权的他人隐私。
|
||||
- **严禁**将分析结果用于骚扰、诈骗、人肉搜索或任何侵犯他人权益的行为。
|
||||
- **严禁**用于规避安全措施或网络渗透测试。
|
||||
- **禁止商用**:我们严禁任何个人或机构将本软件用于任何形式的商业盈利行为(如打包销售、提供有偿代分析服务等),因此产生的纠纷与损失由用户自行承担。
|
||||
- **禁止商用**:严禁任何个人或机构将本软件用于任何形式的商业盈利行为(如打包销售、提供有偿代分析服务等),因此产生的纠纷与损失由用户自行承担。
|
||||
|
||||
## 4. 风险警告
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ const {
|
||||
currentConversationId,
|
||||
currentToolStatus,
|
||||
toolsUsedInCurrentRound,
|
||||
sessionTokenUsage,
|
||||
sendMessage,
|
||||
loadConversation,
|
||||
startNewConversation,
|
||||
@@ -514,8 +515,18 @@ watch(
|
||||
</template>
|
||||
</UPopover>
|
||||
|
||||
<!-- 右侧:配置状态指示 -->
|
||||
<!-- 右侧:Token 使用量 + 配置状态指示 -->
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Token 使用量 -->
|
||||
<div
|
||||
v-if="sessionTokenUsage.totalTokens > 0"
|
||||
class="flex items-center gap-1.5 text-xs text-gray-400"
|
||||
title="本次会话累计 Token 使用量"
|
||||
>
|
||||
<UIcon name="i-heroicons-chart-bar-square" class="h-3.5 w-3.5" />
|
||||
<span>{{ sessionTokenUsage.totalTokens.toLocaleString() }} tokens</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!isCheckingConfig"
|
||||
class="flex items-center gap-1.5 text-xs transition-colors"
|
||||
|
||||
@@ -67,6 +67,13 @@ export interface ToolStatus {
|
||||
result?: unknown
|
||||
}
|
||||
|
||||
// Token 使用量类型
|
||||
export interface TokenUsage {
|
||||
promptTokens: number
|
||||
completionTokens: number
|
||||
totalTokens: number
|
||||
}
|
||||
|
||||
// 工具名称映射(英文 → 中文)
|
||||
const TOOL_DISPLAY_NAMES: Record<string, string> = {
|
||||
search_messages: '搜索聊天记录',
|
||||
@@ -105,6 +112,9 @@ export function useAIChat(
|
||||
const currentToolStatus = ref<ToolStatus | null>(null)
|
||||
const toolsUsedInCurrentRound = ref<string[]>([])
|
||||
|
||||
// Token 使用量(当前会话累计)
|
||||
const sessionTokenUsage = ref<TokenUsage>({ promptTokens: 0, completionTokens: 0, totalTokens: 0 })
|
||||
|
||||
// 中止控制
|
||||
let isAborted = false
|
||||
// 当前请求 ID,用于区分不同请求的响应
|
||||
@@ -339,9 +349,18 @@ export function useAIChat(
|
||||
break
|
||||
|
||||
case 'done':
|
||||
// 完成
|
||||
console.log('[AI] Agent 完成')
|
||||
// 完成 - 更新 Token 使用量
|
||||
console.log('[AI] Agent 完成', chunk.usage)
|
||||
currentToolStatus.value = null
|
||||
// 更新会话累计 Token(流式响应在最后一个 chunk 返回 usage)
|
||||
if (chunk.usage) {
|
||||
sessionTokenUsage.value = {
|
||||
promptTokens: sessionTokenUsage.value.promptTokens + chunk.usage.promptTokens,
|
||||
completionTokens: sessionTokenUsage.value.completionTokens + chunk.usage.completionTokens,
|
||||
totalTokens: sessionTokenUsage.value.totalTokens + chunk.usage.totalTokens,
|
||||
}
|
||||
console.log('[AI] Token 使用量更新:', sessionTokenUsage.value)
|
||||
}
|
||||
break
|
||||
|
||||
case 'error':
|
||||
@@ -506,6 +525,8 @@ export function useAIChat(
|
||||
messages.value = []
|
||||
sourceMessages.value = []
|
||||
currentKeywords.value = []
|
||||
// 重置 Token 计数
|
||||
sessionTokenUsage.value = { promptTokens: 0, completionTokens: 0, totalTokens: 0 }
|
||||
|
||||
if (welcomeMessage) {
|
||||
messages.value.push({
|
||||
@@ -573,6 +594,7 @@ export function useAIChat(
|
||||
currentConversationId,
|
||||
currentToolStatus,
|
||||
toolsUsedInCurrentRound,
|
||||
sessionTokenUsage,
|
||||
|
||||
// 方法
|
||||
sendMessage,
|
||||
|
||||
Reference in new issue
Block a user