@@ -78,35 +78,42 @@ class RangeView {
78
78
}
79
79
}
80
80
81
+ interface Slice < T > {
82
+ value : T ;
83
+ length : number ;
84
+ }
85
+
81
86
/**
82
87
* Note: A good article about binary data in JS: https://javascript.info/arraybuffer-binary-arrays
83
88
*/
84
89
85
- function readVersionedSize ( view : DataView , byteOffset : number , version : Version , littleEndian : boolean ) : bigint {
90
+ function readVersionedSize ( view : DataView , byteOffset : number , version : Version , littleEndian : boolean ) : Slice < bigint > {
86
91
switch ( version ) {
87
92
case 1 : {
88
93
const n = view . getUint32 ( byteOffset , littleEndian ) ;
89
- return BigInt ( n ) ;
94
+ return { value : BigInt ( n ) , length : 4 } ;
90
95
}
91
96
case 2 :
92
97
case 3 : {
93
- return view . getBigUint64 ( byteOffset , littleEndian ) ;
98
+ return { value : view . getBigUint64 ( byteOffset , littleEndian ) , length : 8 } ;
94
99
}
95
100
}
96
101
}
97
102
98
- function readString ( view : DataView , offset : number , littleEndian : boolean ) : { value : string ; length : number } {
99
- const length = view . getBigUint64 ( offset , littleEndian ) ;
100
- const value = new TextDecoder ( ) . decode ( view . buffer . slice ( offset + 8 , offset + 8 + Number ( length ) ) ) ;
101
- return { value, length : 8 + Number ( length ) } ;
103
+ function readString ( view : DataView , offset : number , version : Version , littleEndian : boolean ) : Slice < string > {
104
+ const length = readVersionedSize ( view , offset , version , littleEndian ) ;
105
+ const off = length . length ;
106
+ const value = new TextDecoder ( ) . decode ( view . buffer . slice ( offset + off , offset + off + Number ( length . value ) ) ) ;
107
+ return { value, length : off + Number ( length . value ) } ;
102
108
}
103
109
104
110
function readMetadataValue (
105
111
view : DataView ,
106
112
type : GGUFValueType ,
107
113
offset : number ,
114
+ version : Version ,
108
115
littleEndian : boolean
109
- ) : { value : MetadataValue ; length : number } {
116
+ ) : Slice < MetadataValue > {
110
117
switch ( type ) {
111
118
case GGUFValueType . UINT8 :
112
119
return { value : view . getUint8 ( offset ) , length : 1 } ;
@@ -125,16 +132,16 @@ function readMetadataValue(
125
132
case GGUFValueType . BOOL :
126
133
return { value : view . getUint8 ( offset ) !== 0 , length : 1 } ;
127
134
case GGUFValueType . STRING :
128
- return readString ( view , offset , littleEndian ) ;
135
+ return readString ( view , offset , version , littleEndian ) ;
129
136
case GGUFValueType . ARRAY : {
130
137
const arrayType = view . getUint32 ( offset , littleEndian ) ;
131
- const arrayLength = view . getBigUint64 ( offset + 4 , littleEndian ) ;
132
- let length = 12 ;
138
+ const arrayLength = readVersionedSize ( view , offset + 4 , version , littleEndian ) ;
139
+ let length = 4 + arrayLength . length ;
133
140
const arrayValues : MetadataValue [ ] = [ ] ;
134
- for ( let i = 0 ; i < arrayLength ; i ++ ) {
135
- const { value , length : _length } = readMetadataValue ( view , arrayType , offset + length , littleEndian ) ;
136
- arrayValues . push ( value ) ;
137
- length += _length ;
141
+ for ( let i = 0 ; i < arrayLength . value ; i ++ ) {
142
+ const metadataValue = readMetadataValue ( view , arrayType , offset + length , version , littleEndian ) ;
143
+ arrayValues . push ( metadataValue . value ) ;
144
+ length += metadataValue . length ;
138
145
}
139
146
return { value : arrayValues , length } ;
140
147
}
@@ -187,22 +194,23 @@ export async function gguf(
187
194
if ( ! isVersion ( version ) ) {
188
195
throw new Error ( `not a valid gguf file: unsupported version "${ version } "` ) ;
189
196
}
190
- const tensorCount = readVersionedSize ( r . view , 8 , version , littleEndian ) ;
191
- const numKv = readVersionedSize ( r . view , 16 , version , littleEndian ) ;
192
-
197
+ // initial offset after header
198
+ let offset = 8 ;
199
+ const tensorCount = readVersionedSize ( r . view , offset , version , littleEndian ) ;
200
+ offset += tensorCount . length ;
201
+ const numKv = readVersionedSize ( r . view , offset , version , littleEndian ) ;
202
+ offset += numKv . length ;
193
203
const metadata : GGUFMetadata = {
194
204
version,
195
- tensor_count : tensorCount ,
196
- kv_count : numKv ,
205
+ tensor_count : tensorCount . value ,
206
+ kv_count : numKv . value ,
197
207
} ;
198
- // initial offset after header
199
- let offset = 24 ;
200
208
201
- for ( let i = 0 ; i < numKv ; i ++ ) {
209
+ for ( let i = 0 ; i < numKv . value ; i ++ ) {
202
210
await r . fetchChunkIfNeeded ( offset ) ;
203
211
204
212
// read key
205
- const keyResult = readString ( r . view , offset , littleEndian ) ;
213
+ const keyResult = readString ( r . view , offset , version , littleEndian ) ;
206
214
offset += keyResult . length ;
207
215
208
216
// read value type
@@ -217,7 +225,7 @@ export async function gguf(
217
225
while ( ! valueResult ) {
218
226
try {
219
227
// read value
220
- valueResult = readMetadataValue ( r . view , valueType , offset , littleEndian ) ;
228
+ valueResult = readMetadataValue ( r . view , valueType , offset , version , littleEndian ) ;
221
229
} catch ( err ) {
222
230
if ( err instanceof RangeError ) {
223
231
await r . fetchChunk ( ) ;
@@ -232,20 +240,21 @@ export async function gguf(
232
240
233
241
const tensorInfos : GGUFTensorInfo [ ] = [ ] ;
234
242
235
- for ( let i = 0 ; i < tensorCount ; i ++ ) {
243
+ for ( let i = 0 ; i < tensorCount . value ; i ++ ) {
236
244
await r . fetchChunkIfNeeded ( offset ) ;
237
245
238
246
// read tensor name
239
- const keyResult = readString ( r . view , offset , littleEndian ) ;
247
+ const keyResult = readString ( r . view , offset , version , littleEndian ) ;
240
248
offset += keyResult . length ;
241
249
242
250
const nDims = r . view . getUint32 ( offset , littleEndian ) ;
243
251
offset += 4 ;
244
252
245
253
const shape : bigint [ ] = [ ] ;
246
254
for ( let dim = 0 ; dim < nDims ; dim ++ ) {
247
- shape . push ( r . view . getBigUint64 ( offset , littleEndian ) ) ;
248
- offset += 8 ;
255
+ const shapeDim = readVersionedSize ( r . view , offset , version , littleEndian ) ;
256
+ shape . push ( shapeDim . value ) ;
257
+ offset += shapeDim . length ;
249
258
}
250
259
251
260
const type = r . view . getUint32 ( offset , littleEndian ) ;
0 commit comments