Skip to content

Commit 195a595

Browse files
only keep tiny-en and tiny models, and tiny model accept all language and translate into english automatically
1 parent 69f274d commit 195a595

File tree

9 files changed

+894
-807
lines changed

9 files changed

+894
-807
lines changed
-57 MB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Entry not found

src/components/api/returnAPI.tsx

Lines changed: 204 additions & 178 deletions
Large diffs are not rendered by default.
Lines changed: 152 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,168 @@
1-
// HACK: moving global variables from index.html to here for loadRemote
2-
3-
let dbVersion = 1
4-
let dbName = 'whisper.ggerganov.com';
5-
let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB
6-
7-
// fetch a remote file from remote URL using the Fetch API
8-
async function fetchRemote(url, cbProgress, cbPrint) {
9-
cbPrint('fetchRemote: downloading with fetch()...');
10-
11-
const response = await fetch(
12-
url,
13-
{
14-
method: 'GET',
15-
}
16-
);
1+
// Robust, silent caching + URL fallbacks for Whisper model binaries
2+
3+
var dbVersion = 1;
4+
var dbName = 'whisper.ggerganov.com';
5+
var _indexedDB =
6+
(window.indexedDB ||
7+
window.mozIndexedDB ||
8+
window.webkitIndexedDB ||
9+
window.msIndexedDB);
10+
11+
// --- tiny helpers -----------------------------------------------------------
12+
13+
function log(cbPrint, msg){ try { cbPrint && cbPrint(msg); } catch(_){} }
14+
15+
function isValidModelBytes(buf, contentType) {
16+
if (!buf) return false;
17+
// Reject obvious HTML/JSON or tiny payloads (typical CRA index.html ~2–5 KB)
18+
if (buf.byteLength < 4096) return false;
19+
if (!contentType) return true;
20+
const ct = String(contentType).toLowerCase();
21+
if (ct.includes('text/html')) return false;
22+
if (ct.includes('json')) return false;
23+
return true;
24+
}
1725

18-
if (!response.ok) {
19-
cbPrint('fetchRemote: failed to fetch ' + url);
20-
return;
26+
// Fetch bytes from a URL (no prompt, no cache), return Uint8Array or null
27+
async function fetchBytes(url, cbProgress, cbPrint) {
28+
log(cbPrint, 'fetchRemote: GET ' + url);
29+
const res = await fetch(url, { cache: 'no-cache', method: 'GET' });
30+
if (!res.ok) {
31+
log(cbPrint, 'fetchRemote: HTTP ' + res.status + ' @ ' + url);
32+
return null;
33+
}
34+
const totalHdr = res.headers.get('content-length');
35+
const total = totalHdr ? parseInt(totalHdr, 10) : undefined;
36+
37+
// If stream not available, do arrayBuffer directly
38+
if (!res.body || !res.body.getReader) {
39+
const buf = await res.arrayBuffer();
40+
if (!isValidModelBytes(buf, res.headers.get('content-type'))) return null;
41+
cbProgress && cbProgress(1);
42+
return new Uint8Array(buf);
43+
}
44+
45+
const reader = res.body.getReader();
46+
let received = 0, chunks = [], lastReport = -1;
47+
48+
while (true) {
49+
const { value, done } = await reader.read();
50+
if (done) break;
51+
chunks.push(value);
52+
received += value.length;
53+
if (total) {
54+
const frac = received / total;
55+
cbProgress && cbProgress(frac);
56+
const bucket = Math.round(frac * 10);
57+
if (bucket !== lastReport) {
58+
log(cbPrint, 'fetchRemote: fetching ' + (bucket * 10) + '% ...');
59+
lastReport = bucket;
60+
}
2161
}
62+
}
63+
64+
// Concat
65+
const out = new Uint8Array(received);
66+
let pos = 0;
67+
for (let i = 0; i < chunks.length; i++) {
68+
out.set(chunks[i], pos);
69+
pos += chunks[i].length;
70+
}
71+
72+
// Final sanity
73+
const ct = res.headers.get('content-type');
74+
if (!isValidModelBytes(out, ct)) return null;
75+
if (!total) { cbProgress && cbProgress(1); }
76+
77+
return out;
78+
}
2279

23-
const contentLength = response.headers.get('content-length');
24-
const total = parseInt(contentLength, 10);
25-
const reader = response.body.getReader();
26-
27-
var chunks = [];
28-
var receivedLength = 0;
29-
var progressLast = -1;
80+
// IDB helpers
81+
function idbGet(db, key) {
82+
return new Promise(resolve => {
83+
try {
84+
const tx = db.transaction(['models'], 'readonly');
85+
const os = tx.objectStore('models');
86+
const rq = os.get(key);
87+
rq.onsuccess = () => resolve(rq.result || null);
88+
rq.onerror = () => resolve(null);
89+
} catch (_) { resolve(null); }
90+
});
91+
}
3092

31-
while (true) {
32-
const { done, value } = await reader.read();
93+
function idbPut(db, key, bytes, cbPrint) {
94+
return new Promise(resolve => {
95+
try {
96+
const tx = db.transaction(['models'], 'readwrite');
97+
const os = tx.objectStore('models');
98+
const rq = os.put(bytes, key);
99+
rq.onsuccess = () => { log(cbPrint, 'loadRemote: stored in IDB: ' + key); resolve(true); };
100+
rq.onerror = () => { log(cbPrint, 'loadRemote: IDB put failed (non-fatal)'); resolve(false); };
101+
} catch (e) {
102+
log(cbPrint, 'loadRemote: IDB exception: ' + e);
103+
resolve(false);
104+
}
105+
});
106+
}
33107

34-
if (done) {
35-
break;
36-
}
108+
function openDB(cbPrint) {
109+
return new Promise(resolve => {
110+
const rq = _indexedDB.open(dbName, dbVersion);
111+
rq.onupgradeneeded = (ev) => {
112+
const db = ev.target.result;
113+
if (!db.objectStoreNames.contains('models')) {
114+
db.createObjectStore('models', { autoIncrement: false });
115+
log(cbPrint, 'loadRemote: created IDB store');
116+
}
117+
};
118+
rq.onsuccess = () => resolve(rq.result);
119+
rq.onerror = () => resolve(null);
120+
rq.onblocked = () => resolve(null);
121+
rq.onabort = () => resolve(null);
122+
});
123+
}
37124

38-
chunks.push(value);
39-
receivedLength += value.length;
125+
// --- PUBLIC: try a list of URLs, use cache per-URL, stop on first good one ---
126+
export async function loadRemoteWithFallbacks(urls, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) {
127+
try {
128+
if (navigator.storage?.estimate) {
129+
const est = await navigator.storage.estimate();
130+
log(cbPrint, 'loadRemote: storage quota: ' + est.quota + ' bytes');
131+
log(cbPrint, 'loadRemote: storage usage: ' + est.usage + ' bytes');
132+
}
133+
} catch (_) {}
40134

41-
if (contentLength) {
42-
cbProgress(receivedLength/total);
135+
// De-dup & filter falsy
136+
const list = Array.from(new Set((urls || []).filter(Boolean)));
137+
if (!list.length) { cbCancel && cbCancel(); return; }
43138

44-
var progressCur = Math.round((receivedLength / total) * 10);
45-
if (progressCur != progressLast) {
46-
cbPrint('fetchRemote: fetching ' + 10*progressCur + '% ...');
47-
progressLast = progressCur;
48-
}
49-
}
50-
}
139+
const db = await openDB(cbPrint);
51140

52-
var position = 0;
53-
var chunksAll = new Uint8Array(receivedLength);
141+
for (let i = 0; i < list.length; i++) {
142+
const url = list[i];
54143

55-
for (var chunk of chunks) {
56-
chunksAll.set(chunk, position);
57-
position += chunk.length;
144+
// 1) Cache hit?
145+
if (db) {
146+
const cached = await idbGet(db, url);
147+
if (cached && cached.byteLength > 4096) {
148+
log(cbPrint, `loadRemote: cache hit for ${url}`);
149+
cbReady && cbReady(dst, cached instanceof Uint8Array ? cached : new Uint8Array(cached));
150+
return;
151+
}
58152
}
59153

60-
return chunksAll;
61-
}
62-
63-
// load remote data
64-
// - check if the data is already in the IndexedDB
65-
// - if not, fetch it from the remote URL and store it in the IndexedDB
66-
export function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) {
67-
if (!navigator.storage || !navigator.storage.estimate) {
68-
cbPrint('loadRemote: navigator.storage.estimate() is not supported');
154+
log(cbPrint, `loadRemote: cache miss; downloading ~${size_mb} MB`);
155+
const bytes = await fetchBytes(url, cbProgress, cbPrint);
156+
if (bytes && bytes.byteLength > 4096) {
157+
if (db) { await idbPut(db, url, bytes, cbPrint); }
158+
cbReady && cbReady(dst, bytes);
159+
return;
69160
} else {
70-
// query the storage quota and print it
71-
navigator.storage.estimate().then(function (estimate) {
72-
cbPrint('loadRemote: storage quota: ' + estimate.quota + ' bytes');
73-
cbPrint('loadRemote: storage usage: ' + estimate.usage + ' bytes');
74-
});
161+
log(cbPrint, `fetchWithFallbacks: "${url}" did not look like a model, trying next...`);
75162
}
163+
}
76164

77-
// check if the data is already in the IndexedDB
78-
var rq = indexedDB.open(dbName, dbVersion);
79-
80-
rq.onupgradeneeded = function (event) {
81-
var db = event.target.result;
82-
if (db.version == 1) {
83-
var os = db.createObjectStore('models', { autoIncrement: false });
84-
cbPrint('loadRemote: created IndexedDB ' + db.name + ' version ' + db.version);
85-
} else {
86-
// clear the database
87-
var os = event.currentTarget.transaction.objectStore('models');
88-
os.clear();
89-
cbPrint('loadRemote: cleared IndexedDB ' + db.name + ' version ' + db.version);
90-
}
91-
};
92-
93-
rq.onsuccess = function (event) {
94-
var db = event.target.result;
95-
var tx = db.transaction(['models'], 'readonly');
96-
var os = tx.objectStore('models');
97-
var rq = os.get(url);
98-
99-
rq.onsuccess = function (event) {
100-
if (rq.result) {
101-
cbPrint('loadRemote: "' + url + '" is already in the IndexedDB');
102-
cbReady(dst, rq.result);
103-
} else {
104-
// data is not in the IndexedDB
105-
cbPrint('loadRemote: "' + url + '" is not in the IndexedDB');
106-
107-
// alert and ask the user to confirm
108-
if (!confirm(
109-
'You are about to download ' + size_mb + ' MB of data.\n' +
110-
'The model data will be cached in the browser for future use.\n\n' +
111-
'Press OK to continue.')) {
112-
cbCancel();
113-
return;
114-
}
115-
116-
fetchRemote(url, cbProgress, cbPrint).then(function (data) {
117-
if (data) {
118-
// store the data in the IndexedDB
119-
var rq = indexedDB.open(dbName, dbVersion);
120-
rq.onsuccess = function (event) {
121-
var db = event.target.result;
122-
var tx = db.transaction(['models'], 'readwrite');
123-
var os = tx.objectStore('models');
124-
125-
var rq = null;
126-
try {
127-
var rq = os.put(data, url);
128-
} catch (e) {
129-
cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB: \n' + e);
130-
cbCancel();
131-
return;
132-
}
133-
134-
rq.onsuccess = function (event) {
135-
cbPrint('loadRemote: "' + url + '" stored in the IndexedDB');
136-
cbReady(dst, data);
137-
};
138-
139-
rq.onerror = function (event) {
140-
cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB');
141-
cbCancel();
142-
};
143-
};
144-
}
145-
});
146-
}
147-
};
148-
149-
rq.onerror = function (event) {
150-
cbPrint('loadRemote: failed to get data from the IndexedDB');
151-
cbCancel();
152-
};
153-
};
154-
155-
rq.onerror = function (event) {
156-
cbPrint('loadRemote: failed to open IndexedDB');
157-
cbCancel();
158-
};
159-
160-
rq.onblocked = function (event) {
161-
cbPrint('loadRemote: failed to open IndexedDB: blocked');
162-
cbCancel();
163-
};
164-
165-
rq.onabort = function (event) {
166-
cbPrint('loadRemote: failed to open IndexedDB: abort');
167-
cbCancel();
168-
};
165+
// All failed
166+
log(cbPrint, 'loadRemote: all fetch attempts failed');
167+
cbCancel && cbCancel();
169168
}

0 commit comments

Comments
 (0)