gpt-tokenizer 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -8
- package/cjs/GptEncoding.d.ts +33 -6
- package/cjs/GptEncoding.js +79 -34
- package/cjs/GptEncoding.js.map +1 -1
- package/cjs/GptEncoding.test.js +54 -0
- package/cjs/GptEncoding.test.js.map +1 -1
- package/cjs/encoding/cl100k_base.d.ts +3 -3
- package/cjs/encoding/cl100k_base.js +6 -4
- package/cjs/encoding/cl100k_base.js.map +1 -1
- package/cjs/encoding/p50k_base.d.ts +2 -2
- package/cjs/encoding/p50k_base.js +4 -4
- package/cjs/encoding/p50k_base.js.map +1 -1
- package/cjs/encoding/p50k_edit.d.ts +2 -2
- package/cjs/encoding/p50k_edit.js +4 -4
- package/cjs/encoding/p50k_edit.js.map +1 -1
- package/cjs/encoding/r50k_base.d.ts +2 -2
- package/cjs/encoding/r50k_base.js +4 -4
- package/cjs/encoding/r50k_base.js.map +1 -1
- package/cjs/mapping.d.ts +37 -0
- package/cjs/mapping.js +34 -2
- package/cjs/mapping.js.map +1 -1
- package/cjs/model/gpt-3.5-turbo-0301.d.ts +6 -0
- package/cjs/model/gpt-3.5-turbo-0301.js +38 -0
- package/cjs/model/gpt-3.5-turbo-0301.js.map +1 -0
- package/cjs/model/gpt-3.5-turbo.d.ts +6 -1
- package/cjs/model/gpt-3.5-turbo.js +21 -1
- package/cjs/model/gpt-3.5-turbo.js.map +1 -1
- package/cjs/model/gpt-4-0314.d.ts +6 -0
- package/cjs/model/gpt-4-0314.js +38 -0
- package/cjs/model/gpt-4-0314.js.map +1 -0
- package/cjs/model/gpt-4-32k-0314.d.ts +6 -0
- package/cjs/model/gpt-4-32k-0314.js +38 -0
- package/cjs/model/gpt-4-32k-0314.js.map +1 -0
- package/cjs/model/gpt-4-32k.d.ts +6 -0
- package/cjs/model/gpt-4-32k.js +38 -0
- package/cjs/model/gpt-4-32k.js.map +1 -0
- package/cjs/model/gpt-4.d.ts +6 -1
- package/cjs/model/gpt-4.js +21 -1
- package/cjs/model/gpt-4.js.map +1 -1
- package/cjs/modelParams.d.ts +5 -4
- package/cjs/modelParams.js +7 -4
- package/cjs/modelParams.js.map +1 -1
- package/cjs/specialTokens.d.ts +3 -0
- package/cjs/specialTokens.js +4 -1
- package/cjs/specialTokens.js.map +1 -1
- package/cjs/util.d.ts +2 -0
- package/cjs/util.js +19 -0
- package/cjs/util.js.map +1 -0
- package/dist/cl100k_base.js +1 -1
- package/dist/cl100k_base.js.map +1 -1
- package/dist/p50k_base.js +1 -1
- package/dist/p50k_base.js.map +1 -1
- package/dist/p50k_edit.js +1 -1
- package/dist/p50k_edit.js.map +1 -1
- package/dist/r50k_base.js +1 -1
- package/dist/r50k_base.js.map +1 -1
- package/esm/GptEncoding.d.ts +33 -6
- package/esm/GptEncoding.js +81 -36
- package/esm/GptEncoding.js.map +1 -1
- package/esm/GptEncoding.test.js +55 -1
- package/esm/GptEncoding.test.js.map +1 -1
- package/esm/codegen/generateByModel.js +19 -0
- package/esm/codegen/generateByModel.js.map +1 -0
- package/esm/{generateJsModels.js → codegen/generateJsEncodings.js} +4 -4
- package/esm/codegen/generateJsEncodings.js.map +1 -0
- package/esm/encoding/cl100k_base.d.ts +3 -3
- package/esm/encoding/cl100k_base.js +3 -3
- package/esm/encoding/cl100k_base.js.map +1 -1
- package/esm/encoding/p50k_base.d.ts +2 -2
- package/esm/encoding/p50k_base.js +1 -1
- package/esm/encoding/p50k_base.js.map +1 -1
- package/esm/encoding/p50k_edit.d.ts +2 -2
- package/esm/encoding/p50k_edit.js +1 -1
- package/esm/encoding/p50k_edit.js.map +1 -1
- package/esm/encoding/r50k_base.d.ts +2 -2
- package/esm/encoding/r50k_base.js +1 -1
- package/esm/encoding/r50k_base.js.map +1 -1
- package/esm/mapping.d.ts +37 -0
- package/esm/mapping.js +32 -0
- package/esm/mapping.js.map +1 -1
- package/esm/model/gpt-3.5-turbo-0301.d.ts +6 -0
- package/esm/model/gpt-3.5-turbo-0301.js +11 -0
- package/esm/model/gpt-3.5-turbo-0301.js.map +1 -0
- package/esm/model/gpt-3.5-turbo.d.ts +6 -1
- package/esm/model/gpt-3.5-turbo.js +10 -1
- package/esm/model/gpt-3.5-turbo.js.map +1 -1
- package/esm/model/gpt-4-0314.d.ts +6 -0
- package/esm/model/gpt-4-0314.js +11 -0
- package/esm/model/gpt-4-0314.js.map +1 -0
- package/esm/model/gpt-4-32k-0314.d.ts +6 -0
- package/esm/model/gpt-4-32k-0314.js +11 -0
- package/esm/model/gpt-4-32k-0314.js.map +1 -0
- package/esm/model/gpt-4-32k.d.ts +6 -0
- package/esm/model/gpt-4-32k.js +11 -0
- package/esm/model/gpt-4-32k.js.map +1 -0
- package/esm/model/gpt-4.d.ts +6 -1
- package/esm/model/gpt-4.js +10 -1
- package/esm/model/gpt-4.js.map +1 -1
- package/esm/modelParams.d.ts +5 -4
- package/esm/modelParams.js +6 -3
- package/esm/modelParams.js.map +1 -1
- package/esm/specialTokens.d.ts +3 -0
- package/esm/specialTokens.js +3 -0
- package/esm/specialTokens.js.map +1 -1
- package/esm/util.d.ts +2 -0
- package/esm/util.js +14 -0
- package/esm/util.js.map +1 -0
- package/package.json +8 -6
- package/src/GptEncoding.test.ts +78 -1
- package/src/GptEncoding.ts +125 -44
- package/src/__snapshots__/GptEncoding.test.ts.snap +811 -0
- package/src/codegen/generateByModel.ts +35 -0
- package/src/{generateJsModels.ts → codegen/generateJsEncodings.ts} +3 -3
- package/src/encoding/cl100k_base.ts +5 -1
- package/src/encoding/p50k_base.ts +1 -1
- package/src/encoding/p50k_edit.ts +1 -1
- package/src/encoding/r50k_base.ts +1 -1
- package/src/mapping.ts +42 -0
- package/src/model/gpt-3.5-turbo-0301.ts +32 -0
- package/src/model/gpt-3.5-turbo.ts +32 -1
- package/src/model/gpt-4-0314.ts +32 -0
- package/src/model/gpt-4-32k-0314.ts +32 -0
- package/src/model/gpt-4-32k.ts +32 -0
- package/src/model/gpt-4.ts +32 -1
- package/src/modelParams.ts +17 -10
- package/src/specialTokens.ts +3 -0
- package/src/util.ts +15 -0
- package/esm/generateByModel.js +0 -13
- package/esm/generateByModel.js.map +0 -1
- package/esm/generateJsModels.js.map +0 -1
- package/src/generateByModel.ts +0 -20
- /package/esm/{generateByModel.d.ts → codegen/generateByModel.d.ts} +0 -0
- /package/esm/{generateJsModels.d.ts → codegen/generateJsEncodings.d.ts} +0 -0
package/src/GptEncoding.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
2
|
import { BytePairEncodingCore } from './BytePairEncodingCore.js'
|
|
3
|
-
import { escapeRegExp } from './escapeRegExp.js'
|
|
4
3
|
import {
|
|
5
4
|
type EncodingName,
|
|
6
5
|
type ModelName,
|
|
6
|
+
chatModelParams,
|
|
7
7
|
modelToEncodingMap,
|
|
8
8
|
} from './mapping.js'
|
|
9
9
|
import {
|
|
10
|
+
type EncodingParams,
|
|
10
11
|
type GetMergeableRanksAsyncFn,
|
|
11
12
|
type GetMergeableRanksFn,
|
|
12
|
-
|
|
13
|
-
getModelParams,
|
|
13
|
+
getEncodingParams,
|
|
14
14
|
getModelParamsAsync,
|
|
15
15
|
} from './modelParams.js'
|
|
16
16
|
import {
|
|
@@ -19,10 +19,29 @@ import {
|
|
|
19
19
|
FimMiddle,
|
|
20
20
|
FimPrefix,
|
|
21
21
|
FimSuffix,
|
|
22
|
+
ImEnd,
|
|
23
|
+
ImSep,
|
|
24
|
+
ImStart,
|
|
22
25
|
} from './specialTokens.js'
|
|
23
26
|
import { endsWithIncompleteUtfPairSurrogate } from './utfUtil.js'
|
|
27
|
+
import { getMaxValueFromMap, getSpecialTokenRegex } from './util.js'
|
|
24
28
|
|
|
25
|
-
export const
|
|
29
|
+
export const ALL_SPECIAL_TOKENS = 'all'
|
|
30
|
+
|
|
31
|
+
export interface EncodeOptions {
|
|
32
|
+
allowedSpecial?: Set<string>
|
|
33
|
+
disallowedSpecial?: Set<string>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ChatMessage {
|
|
37
|
+
role?: 'system' | 'user' | 'assistant'
|
|
38
|
+
name?: string
|
|
39
|
+
content: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface EncodeChatOptions {
|
|
43
|
+
primeWithAssistantResponse?: string
|
|
44
|
+
}
|
|
26
45
|
|
|
27
46
|
export class GptEncoding {
|
|
28
47
|
static EndOfPrompt = EndOfPrompt
|
|
@@ -32,6 +51,7 @@ export class GptEncoding {
|
|
|
32
51
|
static FimSuffix = FimSuffix
|
|
33
52
|
|
|
34
53
|
decoder = new TextDecoder('utf8')
|
|
54
|
+
modelName?: ModelName
|
|
35
55
|
private bytePairEncodingCoreProcessor: BytePairEncodingCore
|
|
36
56
|
private specialTokenMapping: Map<string, number>
|
|
37
57
|
|
|
@@ -40,10 +60,11 @@ export class GptEncoding {
|
|
|
40
60
|
mergeableBytePairRanks,
|
|
41
61
|
specialTokenMapping,
|
|
42
62
|
expectedVocabularySize,
|
|
43
|
-
|
|
63
|
+
modelName,
|
|
64
|
+
}: EncodingParams) {
|
|
44
65
|
const maxTokenValue = Math.max(
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
getMaxValueFromMap(mergeableBytePairRanks),
|
|
67
|
+
getMaxValueFromMap(specialTokenMapping),
|
|
47
68
|
)
|
|
48
69
|
this.specialTokenMapping = specialTokenMapping
|
|
49
70
|
|
|
@@ -76,13 +97,14 @@ export class GptEncoding {
|
|
|
76
97
|
this.decodeGenerator = this.decodeGenerator.bind(this)
|
|
77
98
|
this.decodeAsyncGenerator = this.decodeAsyncGenerator.bind(this)
|
|
78
99
|
this.isWithinTokenLimit = this.isWithinTokenLimit.bind(this)
|
|
100
|
+
this.modelName = modelName
|
|
79
101
|
}
|
|
80
102
|
|
|
81
103
|
static getEncodingApi(
|
|
82
104
|
encodingName: EncodingName,
|
|
83
105
|
getMergeableRanks: GetMergeableRanksFn,
|
|
84
106
|
): GptEncoding {
|
|
85
|
-
const modelParams =
|
|
107
|
+
const modelParams = getEncodingParams(encodingName, getMergeableRanks)
|
|
86
108
|
return new GptEncoding(modelParams)
|
|
87
109
|
}
|
|
88
110
|
|
|
@@ -91,7 +113,8 @@ export class GptEncoding {
|
|
|
91
113
|
getMergeableRanks: GetMergeableRanksFn,
|
|
92
114
|
): GptEncoding {
|
|
93
115
|
const encodingName = modelToEncodingMap[modelName]
|
|
94
|
-
|
|
116
|
+
const modelParams = getEncodingParams(encodingName, getMergeableRanks)
|
|
117
|
+
return new GptEncoding({ ...modelParams, modelName })
|
|
95
118
|
}
|
|
96
119
|
|
|
97
120
|
static async getEncodingApiAsync(
|
|
@@ -110,43 +133,34 @@ export class GptEncoding {
|
|
|
110
133
|
getMergeableRanks: GetMergeableRanksAsyncFn,
|
|
111
134
|
): Promise<GptEncoding> {
|
|
112
135
|
const encodingName = modelToEncodingMap[modelName]
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
map.forEach((val) => {
|
|
119
|
-
max = Math.max(max, val)
|
|
120
|
-
})
|
|
121
|
-
return max
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
private static specialTokenRegex(tokens: Set<string>): RegExp {
|
|
125
|
-
const escapedTokens = [...tokens].map(escapeRegExp)
|
|
126
|
-
const inner = escapedTokens.join('|')
|
|
127
|
-
return new RegExp(`(${inner})`)
|
|
136
|
+
const modelParams = await getModelParamsAsync(
|
|
137
|
+
encodingName,
|
|
138
|
+
getMergeableRanks,
|
|
139
|
+
)
|
|
140
|
+
return new GptEncoding({ ...modelParams, modelName })
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
encodeGenerator(
|
|
131
144
|
lineToEncode: string,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
): Generator<number[], number> {
|
|
145
|
+
{
|
|
146
|
+
allowedSpecial = new Set<string>(),
|
|
147
|
+
disallowedSpecial = new Set<string>([ALL_SPECIAL_TOKENS]),
|
|
148
|
+
}: EncodeOptions = {},
|
|
149
|
+
): Generator<number[], number, undefined> {
|
|
137
150
|
const specialTokensSet = new Set<string>(this.specialTokenMapping.keys())
|
|
138
151
|
|
|
139
|
-
if (disallowedSpecial.has(
|
|
152
|
+
if (disallowedSpecial.has(ALL_SPECIAL_TOKENS)) {
|
|
140
153
|
disallowedSpecial = new Set<string>(specialTokensSet)
|
|
154
|
+
allowedSpecial.forEach((val) => disallowedSpecial.delete(val))
|
|
141
155
|
disallowedSpecial.forEach((val) => allowedSpecial.delete(val))
|
|
142
156
|
}
|
|
143
157
|
|
|
144
|
-
if (allowedSpecial.has(
|
|
158
|
+
if (allowedSpecial.has(ALL_SPECIAL_TOKENS)) {
|
|
145
159
|
allowedSpecial = specialTokensSet
|
|
146
160
|
}
|
|
147
161
|
|
|
148
162
|
if (disallowedSpecial.size > 0) {
|
|
149
|
-
const regexPattern =
|
|
163
|
+
const regexPattern = getSpecialTokenRegex(disallowedSpecial)
|
|
150
164
|
const match = lineToEncode.match(regexPattern)
|
|
151
165
|
if (match !== null) {
|
|
152
166
|
throw new Error(`Disallowed special token found: ${match[0]}`)
|
|
@@ -159,23 +173,90 @@ export class GptEncoding {
|
|
|
159
173
|
)
|
|
160
174
|
}
|
|
161
175
|
|
|
162
|
-
encode(
|
|
163
|
-
lineToEncode
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
176
|
+
encode(lineToEncode: string, encodeOptions: EncodeOptions = {}): number[] {
|
|
177
|
+
return [...this.encodeGenerator(lineToEncode, encodeOptions)].flat()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Progressively tokenizes an OpenAI chat.
|
|
182
|
+
* Warning: gpt-3.5-turbo and gpt-4 chat format may change over time.
|
|
183
|
+
* Returns tokens assuming the 'gpt-3.5-turbo-0301' / 'gpt-4-0314' format.
|
|
184
|
+
* Based on OpenAI's guidelines: https://github.com/openai/openai-python/blob/main/chatml.md
|
|
185
|
+
* Also mentioned in section 6 of this document: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
|
186
|
+
*/
|
|
187
|
+
*encodeChatGenerator(
|
|
188
|
+
chat: Iterable<ChatMessage>,
|
|
189
|
+
model = this.modelName,
|
|
190
|
+
): Generator<number[], void, undefined> {
|
|
191
|
+
if (!model) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
'Model name must be provided either during initialization or passed in to the method.',
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
const params = chatModelParams[model]
|
|
197
|
+
const chatStartToken = this.specialTokenMapping.get(ImStart)
|
|
198
|
+
const chatEndToken = this.specialTokenMapping.get(ImEnd)
|
|
199
|
+
|
|
200
|
+
if (!params || chatStartToken === undefined || chatEndToken === undefined) {
|
|
201
|
+
throw new Error(`Model '${model}' does not support chat.`)
|
|
202
|
+
}
|
|
203
|
+
const allowedSpecial = new Set([ImSep])
|
|
204
|
+
const { messageSeparator, roleSeparator } = params
|
|
205
|
+
const encodedMessageSeparator =
|
|
206
|
+
messageSeparator.length > 0 ? this.encode(messageSeparator) : []
|
|
207
|
+
const encodedRoleSeparator =
|
|
208
|
+
roleSeparator.length > 0
|
|
209
|
+
? this.encode(roleSeparator, { allowedSpecial })
|
|
210
|
+
: []
|
|
211
|
+
const nameCache = new Map<string, number[]>()
|
|
212
|
+
|
|
213
|
+
for (const { role = 'system', name = role, content } of chat) {
|
|
214
|
+
if (content === undefined) {
|
|
215
|
+
throw new Error('Content must be defined for all messages.')
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
yield [chatStartToken]
|
|
219
|
+
const encodedName = nameCache.get(name) ?? this.encode(name)
|
|
220
|
+
nameCache.set(name, encodedName)
|
|
221
|
+
yield encodedName
|
|
222
|
+
if (encodedRoleSeparator.length > 0) {
|
|
223
|
+
yield encodedRoleSeparator
|
|
224
|
+
}
|
|
225
|
+
yield* this.encodeGenerator(content)
|
|
226
|
+
yield [chatEndToken]
|
|
227
|
+
yield encodedMessageSeparator
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// every reply is primed with <|start|>assistant<|message|>
|
|
231
|
+
yield [chatStartToken]
|
|
232
|
+
yield* this.encodeGenerator('assistant')
|
|
233
|
+
if (encodedRoleSeparator.length > 0) {
|
|
234
|
+
yield encodedRoleSeparator
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Encodes a chat into a single array of tokens.
|
|
240
|
+
* Warning: gpt-3.5-turbo and gpt-4 chat format may change over time.
|
|
241
|
+
* Returns tokens assuming the 'gpt-3.5-turbo-0301' / 'gpt-4-0314' format.
|
|
242
|
+
* Based on OpenAI's guidelines: https://github.com/openai/openai-python/blob/main/chatml.md
|
|
243
|
+
* Also mentioned in section 6 of this document: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
|
244
|
+
*/
|
|
245
|
+
encodeChat(chat: readonly ChatMessage[], model = this.modelName): number[] {
|
|
246
|
+
return [...this.encodeChatGenerator(chat, model)].flat()
|
|
172
247
|
}
|
|
173
248
|
|
|
174
249
|
/**
|
|
175
250
|
* @returns {false | number} false if token limit is exceeded, otherwise the number of tokens
|
|
176
251
|
*/
|
|
177
|
-
isWithinTokenLimit(
|
|
178
|
-
|
|
252
|
+
isWithinTokenLimit(
|
|
253
|
+
input: string | Iterable<ChatMessage>,
|
|
254
|
+
tokenLimit: number,
|
|
255
|
+
): false | number {
|
|
256
|
+
const tokenGenerator =
|
|
257
|
+
typeof input === 'string'
|
|
258
|
+
? this.encodeGenerator(input)
|
|
259
|
+
: this.encodeChatGenerator(input)
|
|
179
260
|
let count = 0
|
|
180
261
|
for (const tokens of tokenGenerator) {
|
|
181
262
|
count += tokens.length
|