diff --git a/CHANGE_LOG.md b/CHANGE_LOG.md index d1b9b6a..8d1069b 100644 --- a/CHANGE_LOG.md +++ b/CHANGE_LOG.md @@ -22,6 +22,7 @@ - Remove unnecessary features to improve performance. - Optimize UI details and unify global icon styles. Replace react-icons with MingCute Icon. - Optimize OpenAI/Azure API to return error messages in a more user-friendly format +- Upgrade gpt-tokens dependency ## v0.7.1 diff --git a/CHANGE_LOG.zh_CN.md b/CHANGE_LOG.zh_CN.md index 31dbcf8..bb4e883 100644 --- a/CHANGE_LOG.zh_CN.md +++ b/CHANGE_LOG.zh_CN.md @@ -22,6 +22,7 @@ - 删减部分多余功能,提升性能 - 优化 UI 细节,统一全局图标样式。将 react-icons 替换为 MingCute Icon - 优化 OpenAI/Azure 接口返回错误格式 +- 升级 gpt-tokens 依赖 ## v0.7.1 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ca0a4f..0732b96 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,8 +102,8 @@ dependencies: specifier: 10.12.17 version: 10.12.17(react-dom@18.2.0)(react@18.2.0) gpt-tokens: - specifier: 1.0.9 - version: 1.0.9 + specifier: 1.0.10 + version: 1.0.10 js-tiktoken: specifier: 1.0.7 version: 1.0.7 @@ -1492,10 +1492,6 @@ packages: to-fast-properties: 2.0.0 dev: false - /@dqbd/tiktoken@1.0.7: - resolution: {integrity: sha512-bhR5k5W+8GLzysjk8zTMVygQZsgvf7W1F0IlL4ZQ5ugjo5rCyiwGM5d8DYriXspytfu98tv59niang3/T+FoDw==} - dev: false - /@emotion/babel-plugin@11.11.0: resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: @@ -5033,11 +5029,11 @@ packages: get-intrinsic: 1.2.0 dev: false - /gpt-tokens@1.0.9: - resolution: {integrity: sha512-t7qNMDaYJevTgy1HyvFV746eh8L1LFjY7WhgdqCZPOLOVTuNdCZTXq7FLjxOGj3YYh0wyALrlpnoCKi8hKigLQ==} + /gpt-tokens@1.0.10: + resolution: {integrity: sha512-DNWfqhu+ZAbjTUT76Xc5UBE+e7L0WejsrbiJy+/zgvA2C4697OFN6TLfQY7zaWlay8bNUKqLzbStz0VI0thDtQ==} dependencies: - '@dqbd/tiktoken': 1.0.7 decimal.js: 10.4.3 + js-tiktoken: 1.0.7 dev: false /graceful-fs@4.2.11: diff --git a/src/lib/gpt-tokens.ts b/src/lib/gpt-tokens.ts index 33be7a5..e88b64f 100644 --- a/src/lib/gpt-tokens.ts +++ b/src/lib/gpt-tokens.ts @@ -1,4 +1,4 @@ -import { Tiktoken, getEncoding, encodingForModel } from "js-tiktoken"; +import { encodingForModel, getEncoding, Tiktoken } from "js-tiktoken"; import Decimal from "decimal.js"; /** @@ -30,12 +30,27 @@ export class GPTTokens { constructor(options: { model: supportModelType; messages: MessageItem[]; - debug?: boolean; plus?: boolean; }) { - const { debug = false, model, messages, plus = false } = options; + const { model, messages, plus = false } = options; + + if (model === "gpt-3.5-turbo") + this.warning( + `${model} may update over time. Returning num tokens assuming gpt-3.5-turbo-0613` + ); + if (model === "gpt-3.5-turbo-16k") + this.warning( + `${model} may update over time. Returning num tokens assuming gpt-3.5-turbo-16k-0613` + ); + if (model === "gpt-4") + this.warning( + `${model} may update over time. Returning num tokens assuming gpt-4-0613` + ); + if (model === "gpt-4-32k") + this.warning( + `${model} may update over time. Returning num tokens assuming gpt-4-32k-0613` + ); - this.debug = debug; this.model = model; this.plus = plus; this.messages = messages; @@ -45,8 +60,6 @@ export class GPTTokens { public readonly model; public readonly messages; - private readonly debug!: boolean; - // https://openai.com/pricing/ // gpt-3.5-turbo // $0.002 / 1K tokens @@ -98,7 +111,7 @@ export class GPTTokens { .toNumber(); // Used Tokens - public get usedTokens(): number { + public get usedTokens() { return this.num_tokens_from_messages(this.messages, this.model); } @@ -150,30 +163,18 @@ export class GPTTokens { price = promptUSD.add(completionUSD).toNumber(); } - if (this.plus) { - if ( - [ - "gpt-3.5-turbo", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-16k-0613", - ].includes(this.model) - ) { - price = new Decimal(price).mul(0.75).toNumber(); - } - } - - return price; + return this.plus && this.model.startsWith("gpt-3.5-turbo") + ? new Decimal(price).mul(0.75).toNumber() + : price; } - private get promptUsedTokens(): number { + private get promptUsedTokens() { const messages = this.messages.filter((item) => item.role !== "assistant"); return this.num_tokens_from_messages(messages, this.model); } - private get completionUsedTokens(): number { + private get completionUsedTokens() { const messages = this.messages.filter((item) => item.role === "assistant"); return this.num_tokens_from_messages(messages, this.model); @@ -184,9 +185,7 @@ export class GPTTokens { * @param message The message to print. Will be prefixed with "Warning: ". * @returns void */ - private warning(message: string): void { - if (!this.debug) return; - + private warning(message: string) { console.warn("Warning:", message); } @@ -200,29 +199,23 @@ export class GPTTokens { private num_tokens_from_messages( messages: MessageItem[], model: supportModelType - ): number { + ) { let encoding!: Tiktoken; let tokens_per_message!: number; let tokens_per_name!: number; let num_tokens = 0; - let modelType!: "gpt-3.5-turbo" | "gpt-4"; - if ( - [ - "gpt-3.5-turbo", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-16k-0613", - ].includes(model) - ) { - modelType = "gpt-3.5-turbo"; + if (["gpt-3.5-turbo-0301"].includes(model)) { tokens_per_message = 4; tokens_per_name = -1; } if ( [ + "gpt-3.5-turbo", + "gpt-3.5-turbo-0613", + "gpt-3.5-turbo-16k", + "gpt-3.5-turbo-16k-0613", "gpt-4", "gpt-4-0314", "gpt-4-0613", @@ -231,13 +224,12 @@ export class GPTTokens { "gpt-4-32k-0613", ].includes(model) ) { - modelType = "gpt-4"; tokens_per_message = 3; tokens_per_name = 1; } try { - encoding = encodingForModel(modelType); + encoding = encodingForModel(model); } catch (e) { this.warning("model not found. Using cl100k_base encoding."); @@ -259,6 +251,7 @@ export class GPTTokens { // Supplementary // encoding.free() + // every reply is primed with <|start|>assistant<|message|> return num_tokens + 3; } } diff --git a/src/locales/en.json b/src/locales/en.json index bf92fbf..73eca21 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -285,10 +285,10 @@ }, "zLog": { "full-log": "Click to view the full update log", - "title": "v0.7.1 Released 🔥🔥", - "text1": "Added Azure TTS feature, supporting conversion of conversation replies into voice (Premium).", - "text2": "Improve the display of error messages returned by OpenAI", - "text3": "Optimize some internationalization content", - "text4": "Other details optimizations" + "title": "v0.7.2 Released 🔥🔥", + "text1": "New: Support for automatic playback with Azure TTS (Premium)", + "text2": "Optimization: After actively switching language models, subsequent new sessions will use the same model", + "text3": "Unified global icon style", + "text4": "Refactored a large number of module codes to improve performance" } } \ No newline at end of file diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index be8f04e..e9e3d2e 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -285,10 +285,10 @@ }, "zLog": { "full-log": "点击查看完整更新日志", - "title": "v0.7.1 版本发布 🔥🔥", - "text1": "新增 Azure TTS 功能,支持将会话回复的内容转换为语音(Premium)", - "text2": "完善 OpenAI 返回报错信息的展示", - "text3": "优化部分国际化内容", - "text4": "其它细节优化" + "title": "v0.7.2 版本发布 🔥🔥", + "text1": "新增:支持Azure TTS自动播放(Premium)", + "text2": "优化:主动切换语言模型后,后续新建会话时会沿用该模型", + "text3": "统一全局图标风格", + "text4": "重构大量模块代码,提升性能表现" } } \ No newline at end of file