11import type { MetadataValue , Version , GGUFMetadata , GGUFTensorInfo , GGUFParseOutput } from "./types" ;
22import { GGUFValueType } from "./types" ;
3+ import { isBackend } from "./utils/isBackend" ;
34import { promisesQueue } from "./utils/promisesQueue" ;
45
56export type { MetadataBaseValue , MetadataValue , Version , GGUFMetadata , GGUFTensorInfo , GGUFParseOutput } from "./types" ;
@@ -49,7 +50,7 @@ const HTTP_TOTAL_MAX_SIZE = 50 * 10 ** 6; /// 50MB
4950 * Internal stateful instance to fetch ranges of HTTP data when needed
5051 */
5152class RangeView {
52- private chunk : number ;
53+ protected chunk : number ;
5354 private buffer : ArrayBuffer ;
5455 private dataView : DataView ;
5556
@@ -58,7 +59,7 @@ class RangeView {
5859 }
5960
6061 constructor (
61- public url : string ,
62+ public uri : string ,
6263 private params ?: {
6364 /**
6465 * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
@@ -81,7 +82,7 @@ class RangeView {
8182 const range = [ this . chunk * HTTP_CHUNK_SIZE , ( this . chunk + 1 ) * HTTP_CHUNK_SIZE - 1 ] ;
8283 const buf = new Uint8Array (
8384 await (
84- await ( this . params ?. fetch ?? fetch ) ( this . url , {
85+ await ( this . params ?. fetch ?? fetch ) ( this . uri , {
8586 headers : {
8687 ...( this . params ?. additionalFetchHeaders ?? { } ) ,
8788 Range : `bytes=${ range [ 0 ] } -${ range [ 1 ] } ` ,
@@ -128,6 +129,23 @@ class RangeView {
128129 }
129130}
130131
132+ /**
133+ * Internal stateful instance to read ranges of local file when needed.
134+ * Only usable in with nodejs FS API.
135+ */
136+ class RangeViewLocalFile extends RangeView {
137+ /**
138+ * Read a new chunk from local file system.
139+ */
140+ override async fetchChunk ( ) : Promise < void > {
141+ const { FileBlob } = await import ( "./utils/FileBlob" ) ;
142+ const blob = await FileBlob . create ( this . uri ) ;
143+ const range = [ this . chunk * HTTP_CHUNK_SIZE , ( this . chunk + 1 ) * HTTP_CHUNK_SIZE - 1 ] ;
144+ const buffer = await blob . slice ( range [ 0 ] , range [ 1 ] ) . arrayBuffer ( ) ;
145+ this . appendBuffer ( new Uint8Array ( buffer ) ) ;
146+ }
147+ }
148+
131149interface Slice < T > {
132150 value : T ;
133151 length : number ;
@@ -205,38 +223,57 @@ function readMetadataValue(
205223}
206224
207225export async function gguf (
208- url : string ,
226+ uri : string ,
209227 params : {
210228 /**
211229 * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
212230 */
213231 fetch ?: typeof fetch ;
214232 additionalFetchHeaders ?: Record < string , string > ;
215233 computeParametersCount : true ;
234+ allowLocalFile ?: boolean ;
216235 }
217236) : Promise < GGUFParseOutput & { parameterCount : number } > ;
218237export async function gguf (
219- url : string ,
238+ uri : string ,
220239 params ?: {
221240 /**
222241 * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
223242 */
224243 fetch ?: typeof fetch ;
225244 additionalFetchHeaders ?: Record < string , string > ;
245+ allowLocalFile ?: boolean ;
226246 }
227247) : Promise < GGUFParseOutput > ;
228248export async function gguf (
229- url : string ,
249+ uri : string ,
230250 params ?: {
231251 /**
232252 * Custom fetch function to use instead of the default one, for example to use a proxy or edit headers.
233253 */
234254 fetch ?: typeof fetch ;
235255 additionalFetchHeaders ?: Record < string , string > ;
236256 computeParametersCount ?: boolean ;
257+ allowLocalFile ?: boolean ;
237258 }
238259) : Promise < GGUFParseOutput & { parameterCount ?: number } > {
239- const r = new RangeView ( url , params ) ;
260+ let r : RangeView ;
261+ if ( isBackend ) {
262+ /// On backend, we switch between remote/local file based on protocol
263+ if ( uri . match ( / ^ h t t p s ? : \/ \/ / ) ) {
264+ r = new RangeView ( uri , params ) ;
265+ } else if ( params ?. allowLocalFile ) {
266+ r = new RangeViewLocalFile ( uri , params ) ;
267+ } else {
268+ throw new Error ( "Access to local file is not enabled, please set allowLocalFile to true" ) ;
269+ }
270+ } else {
271+ /// On frontend, we only allow using remote file
272+ if ( params ?. allowLocalFile ) {
273+ throw new Error ( "allowLocalFile cannot be used on browser" ) ;
274+ }
275+ r = new RangeView ( uri , params ) ;
276+ }
240277 await r . fetchChunk ( ) ;
241278
242279 const checkBuffer = ( buffer : Uint8Array , header : Uint8Array ) => {
@@ -377,7 +414,7 @@ export async function ggufAllShards(
377414
378415 const PARALLEL_DOWNLOADS = 20 ;
379416 const shards = await promisesQueue (
380- urls . map ( ( shardUrl ) => ( ) => gguf ( shardUrl , { computeParametersCount : true } ) ) ,
417+ urls . map ( ( shardUrl ) => ( ) => gguf ( shardUrl , { ... params , computeParametersCount : true } ) ) ,
381418 PARALLEL_DOWNLOADS
382419 ) ;
383420 return {
0 commit comments