Fix issues with token counts
This commit is contained in:
parent
0cc30a28dc
commit
567845be06
|
@ -22,8 +22,9 @@ html {
|
||||||
|
|
||||||
--chatContentPaddingTop: 20px;
|
--chatContentPaddingTop: 20px;
|
||||||
--chatContentPaddingRight: 40px;
|
--chatContentPaddingRight: 40px;
|
||||||
--chatContentPaddingBottom: 130px;
|
--chatContentPaddingBottom: 110px;
|
||||||
--chatContentPaddingLeft: 40px;
|
--chatContentPaddingLeft: 40px;
|
||||||
|
--runningTotalLineHeight: 28px;
|
||||||
|
|
||||||
--chatInputPaddingTop: 0px;
|
--chatInputPaddingTop: 0px;
|
||||||
--chatInputPaddingRight: 60px;
|
--chatInputPaddingRight: 60px;
|
||||||
|
@ -31,6 +32,7 @@ html {
|
||||||
--chatInputPaddingLeft: 60px;
|
--chatInputPaddingLeft: 60px;
|
||||||
|
|
||||||
--BgColor: var(-BgColorLight);
|
--BgColor: var(-BgColorLight);
|
||||||
|
--running-totals: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
|
@ -371,7 +373,7 @@ aside.menu.main-menu .menu-expanse {
|
||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
height: var(--chatContentPaddingBottom) ;
|
height: calc(var(--chatContentPaddingBottom) + var(--runningTotalLineHeight) * var(--running-totals));
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-image: linear-gradient(180deg,hsla(0,0%,100%,0) 13.94%, var(--BgColorLight) 54.73%);
|
background-image: linear-gradient(180deg,hsla(0,0%,100%,0) 13.94%, var(--BgColorLight) 54.73%);
|
||||||
}
|
}
|
||||||
|
@ -419,7 +421,7 @@ aside.menu.main-menu .menu-expanse {
|
||||||
padding:
|
padding:
|
||||||
var(--chatContentPaddingTop)
|
var(--chatContentPaddingTop)
|
||||||
var(--chatContentPaddingRight)
|
var(--chatContentPaddingRight)
|
||||||
var(--chatContentPaddingBottom)
|
calc(var(--chatContentPaddingBottom) + var(--runningTotalLineHeight) * var(--running-totals))
|
||||||
var(--chatContentPaddingLeft) ;
|
var(--chatContentPaddingLeft) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -370,7 +370,7 @@
|
||||||
|
|
||||||
request.stream = opts.streaming
|
request.stream = opts.streaming
|
||||||
|
|
||||||
chatResponse.setPromptTokenCount(promptTokenCount)
|
chatResponse.setPromptTokenCount(promptTokenCount) // streaming needs this
|
||||||
|
|
||||||
const signal = controller.signal
|
const signal = controller.signal
|
||||||
|
|
||||||
|
@ -589,7 +589,7 @@
|
||||||
</script>
|
</script>
|
||||||
{#if chat}
|
{#if chat}
|
||||||
<ChatSettingsModal chatId={chatId} bind:show={showSettingsModal} />
|
<ChatSettingsModal chatId={chatId} bind:show={showSettingsModal} />
|
||||||
|
<div class="chat-page" style="--running-totals: {Object.entries(chat.usage || {}).length}">
|
||||||
<div class="chat-content">
|
<div class="chat-content">
|
||||||
<nav class="level chat-header">
|
<nav class="level chat-header">
|
||||||
<div class="level-left">
|
<div class="level-left">
|
||||||
|
@ -676,4 +676,5 @@
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Footer>
|
</Footer>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
|
@ -1,7 +1,7 @@
|
||||||
<script context="module" lang="ts">
|
<script context="module" lang="ts">
|
||||||
// TODO: Integrate API calls
|
// TODO: Integrate API calls
|
||||||
import { addMessage, saveChatStore, subtractRunningTotal, updateRunningTotal } from './Storage.svelte'
|
import { addMessage, getLatestKnownModel, saveChatStore, setLatestKnownModel, subtractRunningTotal, updateRunningTotal } from './Storage.svelte'
|
||||||
import type { Chat, ChatCompletionOpts, Message, Response, Usage } from './Types.svelte'
|
import type { Chat, ChatCompletionOpts, Message, Model, Response, Usage } from './Types.svelte'
|
||||||
import { encode } from 'gpt-tokenizer'
|
import { encode } from 'gpt-tokenizer'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ export class ChatCompletionResponse {
|
||||||
|
|
||||||
private offsetTotals: Usage
|
private offsetTotals: Usage
|
||||||
private isFill: boolean = false
|
private isFill: boolean = false
|
||||||
|
private didFill: boolean = false
|
||||||
|
|
||||||
private opts: ChatCompletionOpts
|
private opts: ChatCompletionOpts
|
||||||
private chat: Chat
|
private chat: Chat
|
||||||
|
@ -28,6 +29,16 @@ export class ChatCompletionResponse {
|
||||||
|
|
||||||
private error: string
|
private error: string
|
||||||
|
|
||||||
|
private model: Model
|
||||||
|
private lastModel: Model
|
||||||
|
|
||||||
|
private setModel = (model: Model) => {
|
||||||
|
if (!model) return
|
||||||
|
!this.model && setLatestKnownModel(this.chat.settings.model as Model, model)
|
||||||
|
this.lastModel = this.model || model
|
||||||
|
this.model = model
|
||||||
|
}
|
||||||
|
|
||||||
private finishResolver: (value: Message[]) => void
|
private finishResolver: (value: Message[]) => void
|
||||||
private errorResolver: (error: string) => void
|
private errorResolver: (error: string) => void
|
||||||
private finishPromise = new Promise<Message[]>((resolve, reject) => {
|
private finishPromise = new Promise<Message[]>((resolve, reject) => {
|
||||||
|
@ -49,11 +60,11 @@ export class ChatCompletionResponse {
|
||||||
const exitingMessage = this.messages[i]
|
const exitingMessage = this.messages[i]
|
||||||
const message = exitingMessage || choice.message
|
const message = exitingMessage || choice.message
|
||||||
if (exitingMessage) {
|
if (exitingMessage) {
|
||||||
if (this.isFill && choice.message.content.match(/^'(t|ll|ve|m|d|re)[^a-z]/i)) {
|
if (!this.didFill && this.isFill && choice.message.content.match(/^'(t|ll|ve|m|d|re)[^a-z]/i)) {
|
||||||
// deal with merging contractions since we've added an extra space to your fill message
|
// deal with merging contractions since we've added an extra space to your fill message
|
||||||
message.content.replace(/ $/, '')
|
message.content.replace(/ $/, '')
|
||||||
}
|
}
|
||||||
this.isFill = false
|
this.didFill = true
|
||||||
message.content += choice.message.content
|
message.content += choice.message.content
|
||||||
message.usage = message.usage || {
|
message.usage = message.usage || {
|
||||||
prompt_tokens: 0,
|
prompt_tokens: 0,
|
||||||
|
@ -61,8 +72,8 @@ export class ChatCompletionResponse {
|
||||||
total_tokens: 0
|
total_tokens: 0
|
||||||
} as Usage
|
} as Usage
|
||||||
message.usage.completion_tokens += response.usage.completion_tokens
|
message.usage.completion_tokens += response.usage.completion_tokens
|
||||||
message.usage.prompt_tokens += response.usage.prompt_tokens
|
message.usage.prompt_tokens = response.usage.prompt_tokens + (this.offsetTotals?.prompt_tokens || 0)
|
||||||
message.usage.total_tokens += response.usage.total_tokens
|
message.usage.total_tokens += response.usage.total_tokens + (this.offsetTotals?.total_tokens || 0)
|
||||||
} else {
|
} else {
|
||||||
message.content = choice.message.content
|
message.content = choice.message.content
|
||||||
message.usage = response.usage
|
message.usage = response.usage
|
||||||
|
@ -70,6 +81,7 @@ export class ChatCompletionResponse {
|
||||||
message.finish_reason = choice.finish_reason
|
message.finish_reason = choice.finish_reason
|
||||||
message.role = choice.message.role
|
message.role = choice.message.role
|
||||||
message.model = response.model
|
message.model = response.model
|
||||||
|
this.setModel(response.model)
|
||||||
this.messages[i] = message
|
this.messages[i] = message
|
||||||
if (this.opts.autoAddMessages) addMessage(this.chat.id, message)
|
if (this.opts.autoAddMessages) addMessage(this.chat.id, message)
|
||||||
})
|
})
|
||||||
|
@ -87,30 +99,30 @@ export class ChatCompletionResponse {
|
||||||
} as Message
|
} as Message
|
||||||
choice.delta?.role && (message.role = choice.delta.role)
|
choice.delta?.role && (message.role = choice.delta.role)
|
||||||
if (choice.delta?.content) {
|
if (choice.delta?.content) {
|
||||||
if (this.isFill && choice.delta.content.match(/^'(t|ll|ve|m|d|re)[^a-z]/i)) {
|
if (!this.didFill && this.isFill && choice.delta.content.match(/^'(t|ll|ve|m|d|re)[^a-z]/i)) {
|
||||||
// deal with merging contractions since we've added an extra space to your fill message
|
// deal with merging contractions since we've added an extra space to your fill message
|
||||||
message.content.replace(/([a-z]) $/i, '$1')
|
message.content.replace(/([a-z]) $/i, '$1')
|
||||||
}
|
}
|
||||||
this.isFill = false
|
this.didFill = true
|
||||||
message.content += choice.delta.content
|
message.content += choice.delta.content
|
||||||
}
|
}
|
||||||
completionTokenCount += encode(message.content).length
|
completionTokenCount += encode(message.content).length
|
||||||
message.usage = response.usage || {
|
|
||||||
prompt_tokens: this.promptTokenCount
|
|
||||||
} as Usage
|
|
||||||
message.model = response.model
|
message.model = response.model
|
||||||
|
this.setModel(response.model)
|
||||||
message.finish_reason = choice.finish_reason
|
message.finish_reason = choice.finish_reason
|
||||||
message.streaming = choice.finish_reason === null && !this.finished
|
message.streaming = choice.finish_reason === null && !this.finished
|
||||||
this.messages[i] = message
|
this.messages[i] = message
|
||||||
if (this.opts.autoAddMessages) addMessage(this.chat.id, message)
|
|
||||||
})
|
})
|
||||||
// total up the tokens
|
// total up the tokens
|
||||||
const totalTokens = this.promptTokenCount + completionTokenCount
|
const promptTokens = this.promptTokenCount + (this.offsetTotals?.prompt_tokens || 0)
|
||||||
|
const totalTokens = promptTokens + completionTokenCount
|
||||||
this.messages.forEach(m => {
|
this.messages.forEach(m => {
|
||||||
if (m.usage) {
|
m.usage = {
|
||||||
m.usage.completion_tokens = completionTokenCount
|
completion_tokens: completionTokenCount,
|
||||||
m.usage.total_tokens = totalTokens
|
total_tokens: totalTokens,
|
||||||
}
|
prompt_tokens: promptTokens
|
||||||
|
} as Usage
|
||||||
|
if (this.opts.autoAddMessages) addMessage(this.chat.id, m)
|
||||||
})
|
})
|
||||||
const finished = !this.messages.find(m => m.streaming)
|
const finished = !this.messages.find(m => m.streaming)
|
||||||
this.notifyMessageChange()
|
this.notifyMessageChange()
|
||||||
|
@ -167,12 +179,13 @@ export class ChatCompletionResponse {
|
||||||
this.messages.forEach(m => { m.streaming = false }) // make sure all are marked stopped
|
this.messages.forEach(m => { m.streaming = false }) // make sure all are marked stopped
|
||||||
saveChatStore()
|
saveChatStore()
|
||||||
const message = this.messages[0]
|
const message = this.messages[0]
|
||||||
|
const model = this.model || getLatestKnownModel(this.chat.settings.model as Model)
|
||||||
if (message) {
|
if (message) {
|
||||||
if (this.offsetTotals) {
|
if (this.isFill && this.lastModel === this.model && this.offsetTotals && model && message.usage) {
|
||||||
// Need to subtract some previous message totals before we add new combined message totals
|
// Need to subtract some previous message totals before we add new combined message totals
|
||||||
subtractRunningTotal(this.chat.id, this.offsetTotals, this.chat.settings.model as any)
|
subtractRunningTotal(this.chat.id, this.offsetTotals, model)
|
||||||
}
|
}
|
||||||
updateRunningTotal(this.chat.id, message.usage as any, message.model as any)
|
updateRunningTotal(this.chat.id, message.usage as Usage, model)
|
||||||
} else {
|
} else {
|
||||||
// If no messages it's probably because of an error or user initiated abort.
|
// If no messages it's probably because of an error or user initiated abort.
|
||||||
// We could miss counting the cost of the prompts sent.
|
// We could miss counting the cost of the prompts sent.
|
||||||
|
@ -186,7 +199,7 @@ export class ChatCompletionResponse {
|
||||||
completion_tokens: 0, // We have no idea if there are any to count
|
completion_tokens: 0, // We have no idea if there are any to count
|
||||||
total_tokens: this.promptTokenCount
|
total_tokens: this.promptTokenCount
|
||||||
}
|
}
|
||||||
updateRunningTotal(this.chat.id, usage as any, this.chat.settings.model as any)
|
updateRunningTotal(this.chat.id, usage as Usage, model)
|
||||||
}
|
}
|
||||||
this.notifyFinish()
|
this.notifyFinish()
|
||||||
if (this.error) {
|
if (this.error) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
import { errorNotice } from './Util.svelte'
|
import { errorNotice } from './Util.svelte'
|
||||||
|
|
||||||
export const chatsStorage = persisted('chats', [] as Chat[])
|
export const chatsStorage = persisted('chats', [] as Chat[])
|
||||||
|
export const latestModelMap = persisted('latestModelMap', {} as Record<Model, Model>) // What was returned when a model was requested
|
||||||
export const globalStorage = persisted('global', {} as GlobalSettings)
|
export const globalStorage = persisted('global', {} as GlobalSettings)
|
||||||
export const apiKeyStorage = persisted('apiKey', '' as string)
|
export const apiKeyStorage = persisted('apiKey', '' as string)
|
||||||
export let checkStateChange = writable(0) // Trigger for Chat
|
export let checkStateChange = writable(0) // Trigger for Chat
|
||||||
|
@ -462,5 +463,17 @@
|
||||||
}
|
}
|
||||||
return cname
|
return cname
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getLatestKnownModel = (model:Model) => {
|
||||||
|
const modelMapStore = get(latestModelMap)
|
||||||
|
return modelMapStore[model] || model
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const setLatestKnownModel = (requestedModel:Model, responseModel:Model) => {
|
||||||
|
const modelMapStore = get(latestModelMap)
|
||||||
|
modelMapStore[requestedModel] = responseModel
|
||||||
|
latestModelMap.set(modelMapStore)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue