fix: 增加对话token显示,token消耗统计
This commit is contained in:
@@ -111,52 +111,55 @@ watch(
|
||||
// 封装数据处理逻辑
|
||||
function handleDataChunk(chunk: AnyObject) {
|
||||
try {
|
||||
const reasoningChunk = chunk.choices?.[0].delta.reasoning_content;
|
||||
if (reasoningChunk) {
|
||||
// 开始思考链状态
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinkingStatus = 'thinking';
|
||||
bubbleItems.value[bubbleItems.value.length - 1].loading = true;
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinlCollapse = true;
|
||||
if (bubbleItems.value.length) {
|
||||
bubbleItems.value[bubbleItems.value.length - 1].reasoning_content += reasoningChunk;
|
||||
}
|
||||
// 安全获取 delta 和 content
|
||||
const delta = chunk.choices?.[0]?.delta;
|
||||
const reasoningChunk = delta?.reasoning_content;
|
||||
const parsedChunk = delta?.content;
|
||||
|
||||
// usage 处理(可以移动到 startSSE 里也可以写这里)
|
||||
if (chunk.usage) {
|
||||
const { prompt_tokens, completion_tokens, total_tokens } = chunk.usage;
|
||||
const latest = bubbleItems.value[bubbleItems.value.length - 1];
|
||||
latest.tokenUsage = {
|
||||
prompt: prompt_tokens,
|
||||
completion: completion_tokens,
|
||||
total: total_tokens,
|
||||
};
|
||||
}
|
||||
|
||||
if (reasoningChunk) {
|
||||
const latest = bubbleItems.value[bubbleItems.value.length - 1];
|
||||
latest.thinkingStatus = 'thinking';
|
||||
latest.loading = true;
|
||||
latest.thinlCollapse = true;
|
||||
latest.reasoning_content += reasoningChunk;
|
||||
}
|
||||
|
||||
// 另一种思考中形式,content中有 <think></think> 的格式
|
||||
// 一开始匹配到 <think> 开始,匹配到 </think> 结束,并处理标签中的内容为思考内容
|
||||
const parsedChunk = chunk.choices?.[0].delta.content;
|
||||
if (parsedChunk) {
|
||||
const thinkStart = parsedChunk.includes('<think>');
|
||||
const thinkEnd = parsedChunk.includes('</think>');
|
||||
if (thinkStart) {
|
||||
|
||||
if (thinkStart)
|
||||
isThinking = true;
|
||||
}
|
||||
if (thinkEnd) {
|
||||
if (thinkEnd)
|
||||
isThinking = false;
|
||||
}
|
||||
|
||||
const latest = bubbleItems.value[bubbleItems.value.length - 1];
|
||||
|
||||
if (isThinking) {
|
||||
// 开始思考链状态
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinkingStatus = 'thinking';
|
||||
bubbleItems.value[bubbleItems.value.length - 1].loading = true;
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinlCollapse = true;
|
||||
if (bubbleItems.value.length) {
|
||||
bubbleItems.value[bubbleItems.value.length - 1].reasoning_content += parsedChunk
|
||||
.replace('<think>', '')
|
||||
.replace('</think>', '');
|
||||
}
|
||||
latest.thinkingStatus = 'thinking';
|
||||
latest.loading = true;
|
||||
latest.thinlCollapse = true;
|
||||
latest.reasoning_content += parsedChunk.replace('<think>', '').replace('</think>', '');
|
||||
}
|
||||
else {
|
||||
// 结束 思考链状态
|
||||
bubbleItems.value[bubbleItems.value.length - 1].thinkingStatus = 'end';
|
||||
bubbleItems.value[bubbleItems.value.length - 1].loading = false;
|
||||
if (bubbleItems.value.length) {
|
||||
bubbleItems.value[bubbleItems.value.length - 1].content += parsedChunk;
|
||||
}
|
||||
latest.thinkingStatus = 'end';
|
||||
latest.loading = false;
|
||||
latest.content += parsedChunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// 这里如果使用了中断,会有报错,可以忽略不管
|
||||
console.error('解析数据时出错:', err);
|
||||
}
|
||||
}
|
||||
@@ -308,8 +311,9 @@ function copy(item: any) {
|
||||
<div class="footer-wrapper">
|
||||
<div class="footer-container">
|
||||
<div class="footer-time">
|
||||
{{ item.creationTime }}
|
||||
|
||||
<span v-if="item.creationTime "> {{ item.creationTime }}</span>
|
||||
<span v-if="((item.role === 'ai' || item.role === 'assistant') && item?.tokenUsage?.total) " class="footer-token">
|
||||
{{ ((item.role === 'ai' || item.role === 'assistant') && item?.tokenUsage?.total) ? `token:${item?.tokenUsage?.total}` : '' }}</span>
|
||||
<el-button icon="DocumentCopy" size="small" circle @click="copy(item)" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -421,4 +425,41 @@ function copy(item: any) {
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
.footer-time {
|
||||
font-size: 12px;
|
||||
margin-top: 3px;
|
||||
.footer-token {
|
||||
background: rgba(1, 183, 86, 0.53);
|
||||
padding: 0 4px;
|
||||
margin: 0 2px;
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-container {
|
||||
:deep(.el-button + .el-button) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
padding: 12px;
|
||||
background: linear-gradient(to right, #fdfcfb 0%, #ffd1ab 100%);
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.loading-container span {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user