prompt-api-polyfill 1.3.0 → 1.4.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 +37 -2
- package/dist/backends/firebase.js +1 -1
- package/dist/backends/gemini.js +1 -1
- package/dist/backends/openai.js +1 -1
- package/dist/backends/transformers.js +91 -85
- package/dist/chunks/{defaults-CNQngzSd.js → defaults-_qJIFiOb.js} +5 -5
- package/dist/prompt-api-polyfill.js +51 -51
- package/dot_env.json +11 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -140,6 +140,17 @@ npm install prompt-api-polyfill
|
|
|
140
140
|
apiKey: 'dummy', // Required for now by the loader
|
|
141
141
|
device: 'webgpu', // 'webgpu' or 'cpu'
|
|
142
142
|
dtype: 'q4f16', // Quantization level
|
|
143
|
+
env: {
|
|
144
|
+
// Optional: Pass low-level Transformers.js environment overrides
|
|
145
|
+
allowRemoteModels: true,
|
|
146
|
+
backends: {
|
|
147
|
+
onnx: {
|
|
148
|
+
wasm: {
|
|
149
|
+
wasmPaths: 'https://cdn.example.com/wasm-assets/',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
143
154
|
};
|
|
144
155
|
|
|
145
156
|
if (!('LanguageModel' in window)) {
|
|
@@ -169,7 +180,7 @@ including:
|
|
|
169
180
|
- `prompt()` and `promptStreaming()`
|
|
170
181
|
- Multimodal inputs (text, image, audio)
|
|
171
182
|
- `append()` and `measureContextUsage()`
|
|
172
|
-
- Quota handling via `
|
|
183
|
+
- Quota handling via `oncontextoverflow`
|
|
173
184
|
- `clone()` and `destroy()`
|
|
174
185
|
|
|
175
186
|
A simplified version of how it is wired up:
|
|
@@ -225,6 +236,17 @@ This repo ships with a template file:
|
|
|
225
236
|
// For Transformers.js:
|
|
226
237
|
"device": "webgpu",
|
|
227
238
|
"dtype": "q4f16",
|
|
239
|
+
// Optional library-level overrides:
|
|
240
|
+
"env": {
|
|
241
|
+
"allowRemoteModels": true,
|
|
242
|
+
"backends": {
|
|
243
|
+
"onnx": {
|
|
244
|
+
"wasm": {
|
|
245
|
+
"wasmPaths": "https://cdn.example.com/wasm-assets/",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
},
|
|
228
250
|
}
|
|
229
251
|
```
|
|
230
252
|
|
|
@@ -281,7 +303,17 @@ Then open `.env.json` and fill in the values.
|
|
|
281
303
|
"apiKey": "dummy",
|
|
282
304
|
"modelName": "onnx-community/gemma-3-1b-it-ONNX-GQA",
|
|
283
305
|
"device": "webgpu",
|
|
284
|
-
"dtype": "q4f16"
|
|
306
|
+
"dtype": "q4f16",
|
|
307
|
+
"env": {
|
|
308
|
+
"allowRemoteModels": false,
|
|
309
|
+
"backends": {
|
|
310
|
+
"onnx": {
|
|
311
|
+
"wasm": {
|
|
312
|
+
"wasmPaths": "https://cdn.example.com/wasm-assets/"
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
285
317
|
}
|
|
286
318
|
```
|
|
287
319
|
|
|
@@ -304,6 +336,9 @@ Then open `.env.json` and fill in the values.
|
|
|
304
336
|
|
|
305
337
|
- `device`: **Transformers.js only**. Either `"webgpu"` or `"cpu"`.
|
|
306
338
|
- `dtype`: **Transformers.js only**. Quantization level (e.g., `"q4f16"`).
|
|
339
|
+
- `env` (optional): **Transformers.js only**. A flexible object to override
|
|
340
|
+
[Transformers.js environment variables](https://huggingface.co/docs/transformers.js/api/env).
|
|
341
|
+
This is useful for specifying local `wasmPaths` or proxy settings.
|
|
307
342
|
|
|
308
343
|
- `modelName` (optional): The model ID to use. If not provided, the polyfill
|
|
309
344
|
uses the defaults defined in [`backends/defaults.js`](backends/defaults.js).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { initializeApp as Fe } from "firebase/app";
|
|
2
2
|
import { VertexAIBackend as ze, GoogleAIBackend as Ue, getAI as je, getGenerativeModel as Ve, InferenceMode as We } from "firebase/ai";
|
|
3
|
-
import { P as Ke, D as Ge } from "../chunks/defaults-
|
|
3
|
+
import { P as Ke, D as Ge } from "../chunks/defaults-_qJIFiOb.js";
|
|
4
4
|
const qe = () => {
|
|
5
5
|
};
|
|
6
6
|
const be = function(t) {
|
package/dist/backends/gemini.js
CHANGED
package/dist/backends/openai.js
CHANGED
|
@@ -1,68 +1,74 @@
|
|
|
1
|
-
import { pipeline as z, TextStreamer as C } from "@huggingface/transformers";
|
|
2
|
-
import { P as
|
|
3
|
-
class
|
|
1
|
+
import { env as j, pipeline as z, TextStreamer as C } from "@huggingface/transformers";
|
|
2
|
+
import { P as $, D as y } from "../chunks/defaults-_qJIFiOb.js";
|
|
3
|
+
class I extends $ {
|
|
4
4
|
#e;
|
|
5
5
|
#t;
|
|
6
|
-
#
|
|
7
|
-
#n;
|
|
6
|
+
#i;
|
|
8
7
|
#o;
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
#n;
|
|
9
|
+
constructor(o = {}) {
|
|
10
|
+
if (super(o.modelName || y.transformers.modelName), this.#i = o.device || y.transformers.device, this.#o = o.dtype || y.transformers.dtype, o.env) {
|
|
11
|
+
const t = (n, a) => {
|
|
12
|
+
for (const [l, e] of Object.entries(a))
|
|
13
|
+
e && typeof e == "object" && !Array.isArray(e) && n[l] && typeof n[l] == "object" ? t(n[l], e) : n[l] = e;
|
|
14
|
+
};
|
|
15
|
+
t(j, o.env);
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
18
|
/**
|
|
13
19
|
* Loaded models can be large, so we initialize them lazily.
|
|
14
20
|
* @param {EventTarget} [monitorTarget] - The event target to dispatch download progress events to.
|
|
15
21
|
* @returns {Promise<Object>} The generator.
|
|
16
22
|
*/
|
|
17
|
-
async #s(
|
|
23
|
+
async #s(o) {
|
|
18
24
|
if (!this.#e) {
|
|
19
|
-
const t = /* @__PURE__ */ new Map(),
|
|
20
|
-
dtype: this.#
|
|
25
|
+
const t = /* @__PURE__ */ new Map(), n = await M(this.modelName, {
|
|
26
|
+
dtype: this.#o
|
|
21
27
|
});
|
|
22
|
-
for (const { path: e, size:
|
|
23
|
-
t.set(e, { loaded: 0, total:
|
|
24
|
-
const
|
|
25
|
-
if (!
|
|
28
|
+
for (const { path: e, size: r } of n)
|
|
29
|
+
t.set(e, { loaded: 0, total: r });
|
|
30
|
+
const a = (e) => {
|
|
31
|
+
if (!o)
|
|
26
32
|
return;
|
|
27
|
-
const
|
|
28
|
-
c <=
|
|
33
|
+
const r = 1 / 65536, c = Math.floor(e / r) * r;
|
|
34
|
+
c <= o.__lastProgressLoaded || (o.dispatchEvent(
|
|
29
35
|
new ProgressEvent("downloadprogress", {
|
|
30
36
|
loaded: c,
|
|
31
37
|
total: 1,
|
|
32
38
|
lengthComputable: !0
|
|
33
39
|
})
|
|
34
|
-
),
|
|
40
|
+
), o.__lastProgressLoaded = c);
|
|
35
41
|
}, l = (e) => {
|
|
36
42
|
if (e.status === "initiate")
|
|
37
43
|
if (t.has(e.file)) {
|
|
38
|
-
const
|
|
39
|
-
e.total && (
|
|
44
|
+
const r = t.get(e.file);
|
|
45
|
+
e.total && (r.total = e.total);
|
|
40
46
|
} else
|
|
41
47
|
t.set(e.file, { loaded: 0, total: e.total || 0 });
|
|
42
48
|
else if (e.status === "progress")
|
|
43
49
|
t.has(e.file) && (t.get(e.file).loaded = e.loaded);
|
|
44
50
|
else if (e.status === "done") {
|
|
45
51
|
if (t.has(e.file)) {
|
|
46
|
-
const
|
|
47
|
-
|
|
52
|
+
const r = t.get(e.file);
|
|
53
|
+
r.loaded = r.total;
|
|
48
54
|
}
|
|
49
55
|
} else if (e.status === "ready") {
|
|
50
|
-
|
|
56
|
+
a(1);
|
|
51
57
|
return;
|
|
52
58
|
}
|
|
53
59
|
if (e.status === "progress" || e.status === "done") {
|
|
54
|
-
let
|
|
60
|
+
let r = 0, c = 0;
|
|
55
61
|
for (const { loaded: f, total: d } of t.values())
|
|
56
|
-
|
|
62
|
+
r += f, c += d;
|
|
57
63
|
if (c > 0) {
|
|
58
|
-
const f =
|
|
59
|
-
|
|
64
|
+
const f = r / c;
|
|
65
|
+
a(Math.min(f, 0.9999));
|
|
60
66
|
}
|
|
61
67
|
}
|
|
62
68
|
};
|
|
63
|
-
|
|
64
|
-
device: this.#
|
|
65
|
-
dtype: this.#
|
|
69
|
+
a(0), this.#e = await z("text-generation", this.modelName, {
|
|
70
|
+
device: this.#i,
|
|
71
|
+
dtype: this.#o,
|
|
66
72
|
progress_callback: l
|
|
67
73
|
}), this.#t = this.#e.tokenizer;
|
|
68
74
|
}
|
|
@@ -73,9 +79,9 @@ class D extends j {
|
|
|
73
79
|
* @param {Object} options - LanguageModel options.
|
|
74
80
|
* @returns {string} 'available' or 'unavailable'.
|
|
75
81
|
*/
|
|
76
|
-
static availability(
|
|
77
|
-
if (
|
|
78
|
-
for (const t of
|
|
82
|
+
static availability(o) {
|
|
83
|
+
if (o?.expectedInputs && Array.isArray(o.expectedInputs)) {
|
|
84
|
+
for (const t of o.expectedInputs)
|
|
79
85
|
if (t.type === "audio" || t.type === "image")
|
|
80
86
|
return "unavailable";
|
|
81
87
|
}
|
|
@@ -88,55 +94,55 @@ class D extends j {
|
|
|
88
94
|
* @param {EventTarget} [monitorTarget] - The event target to dispatch download progress events to.
|
|
89
95
|
* @returns {Promise<Object>} The generator.
|
|
90
96
|
*/
|
|
91
|
-
async createSession(
|
|
92
|
-
return
|
|
97
|
+
async createSession(o, t, n) {
|
|
98
|
+
return o.responseConstraint && console.warn(
|
|
93
99
|
"The `responseConstraint` flag isn't supported by the Transformers.js backend and was ignored."
|
|
94
|
-
), await this.#s(
|
|
100
|
+
), await this.#s(n), this.generationConfig = {
|
|
95
101
|
max_new_tokens: 512,
|
|
96
102
|
// Default limit
|
|
97
103
|
temperature: t.generationConfig?.temperature ?? 1,
|
|
98
104
|
top_p: 1,
|
|
99
105
|
do_sample: t.generationConfig?.temperature !== 0,
|
|
100
106
|
return_full_text: !1
|
|
101
|
-
}, this.#
|
|
107
|
+
}, this.#n = t.systemInstruction, this.#e;
|
|
102
108
|
}
|
|
103
|
-
async generateContent(
|
|
104
|
-
const t = await this.#s(),
|
|
109
|
+
async generateContent(o) {
|
|
110
|
+
const t = await this.#s(), n = this.#r(o), a = this.#t.apply_chat_template(n, {
|
|
105
111
|
tokenize: !1,
|
|
106
112
|
add_generation_prompt: !0
|
|
107
|
-
}), e = (await t(
|
|
113
|
+
}), e = (await t(a, {
|
|
108
114
|
...this.generationConfig,
|
|
109
115
|
add_special_tokens: !1
|
|
110
|
-
}))[0].generated_text,
|
|
111
|
-
return { text: e, usage:
|
|
116
|
+
}))[0].generated_text, r = await this.countTokens(o);
|
|
117
|
+
return { text: e, usage: r };
|
|
112
118
|
}
|
|
113
|
-
async generateContentStream(
|
|
114
|
-
const t = await this.#s(),
|
|
119
|
+
async generateContentStream(o) {
|
|
120
|
+
const t = await this.#s(), n = this.#r(o), a = this.#t.apply_chat_template(n, {
|
|
115
121
|
tokenize: !1,
|
|
116
122
|
add_generation_prompt: !0
|
|
117
123
|
}), l = [];
|
|
118
|
-
let e,
|
|
119
|
-
const f = (
|
|
120
|
-
l.push(
|
|
124
|
+
let e, r = new Promise((i) => e = i), c = !1;
|
|
125
|
+
const f = (i) => {
|
|
126
|
+
l.push(i), e && (e(), e = null);
|
|
121
127
|
}, d = new C(this.#t, {
|
|
122
128
|
skip_prompt: !0,
|
|
123
129
|
skip_special_tokens: !0,
|
|
124
130
|
callback_function: f
|
|
125
131
|
});
|
|
126
|
-
return t(
|
|
132
|
+
return t(a, {
|
|
127
133
|
...this.generationConfig,
|
|
128
134
|
add_special_tokens: !1,
|
|
129
135
|
streamer: d
|
|
130
136
|
}).then(() => {
|
|
131
137
|
c = !0, e && (e(), e = null);
|
|
132
|
-
}).catch((
|
|
133
|
-
console.error("[Transformers.js] Generation error:",
|
|
138
|
+
}).catch((i) => {
|
|
139
|
+
console.error("[Transformers.js] Generation error:", i), c = !0, e && (e(), e = null);
|
|
134
140
|
}), (async function* () {
|
|
135
141
|
for (; ; ) {
|
|
136
|
-
for (l.length === 0 && !c && (e || (
|
|
137
|
-
const
|
|
142
|
+
for (l.length === 0 && !c && (e || (r = new Promise((i) => e = i)), await r); l.length > 0; ) {
|
|
143
|
+
const i = l.shift();
|
|
138
144
|
yield {
|
|
139
|
-
text: () =>
|
|
145
|
+
text: () => i,
|
|
140
146
|
usageMetadata: { totalTokenCount: 0 }
|
|
141
147
|
};
|
|
142
148
|
}
|
|
@@ -145,67 +151,67 @@ class D extends j {
|
|
|
145
151
|
}
|
|
146
152
|
})();
|
|
147
153
|
}
|
|
148
|
-
async countTokens(
|
|
154
|
+
async countTokens(o) {
|
|
149
155
|
await this.#s();
|
|
150
|
-
const t = this.#r(
|
|
156
|
+
const t = this.#r(o);
|
|
151
157
|
return this.#t.apply_chat_template(t, {
|
|
152
158
|
tokenize: !0,
|
|
153
159
|
add_generation_prompt: !1,
|
|
154
160
|
return_tensor: !1
|
|
155
161
|
}).length;
|
|
156
162
|
}
|
|
157
|
-
#r(
|
|
158
|
-
const t =
|
|
159
|
-
let
|
|
160
|
-
const l =
|
|
161
|
-
return { role:
|
|
163
|
+
#r(o) {
|
|
164
|
+
const t = o.map((n) => {
|
|
165
|
+
let a = n.role === "model" ? "assistant" : n.role === "system" ? "system" : "user";
|
|
166
|
+
const l = n.parts.map((e) => e.text).join("");
|
|
167
|
+
return { role: a, content: l };
|
|
162
168
|
});
|
|
163
|
-
if (this.#
|
|
164
|
-
const
|
|
165
|
-
if (
|
|
166
|
-
const
|
|
167
|
-
(e,
|
|
169
|
+
if (this.#n && !t.some((n) => n.role === "system") && t.unshift({ role: "system", content: this.#n }), this.modelName.toLowerCase().includes("gemma")) {
|
|
170
|
+
const n = t.findIndex((a) => a.role === "system");
|
|
171
|
+
if (n !== -1) {
|
|
172
|
+
const a = t[n], l = t.findIndex(
|
|
173
|
+
(e, r) => e.role === "user" && r > n
|
|
168
174
|
);
|
|
169
|
-
l !== -1 ? (t[l].content =
|
|
175
|
+
l !== -1 ? (t[l].content = a.content + `
|
|
170
176
|
|
|
171
|
-
` + t[l].content, t.splice(
|
|
177
|
+
` + t[l].content, t.splice(n, 1)) : (a.content += `
|
|
172
178
|
|
|
173
|
-
`,
|
|
179
|
+
`, a.role = "user");
|
|
174
180
|
}
|
|
175
181
|
}
|
|
176
182
|
return t;
|
|
177
183
|
}
|
|
178
184
|
}
|
|
179
|
-
async function
|
|
180
|
-
const { dtype: t = "q8", branch:
|
|
181
|
-
let
|
|
182
|
-
const l = `transformers_model_files_${g}_${t}_${
|
|
185
|
+
async function M(g, o = {}) {
|
|
186
|
+
const { dtype: t = "q8", branch: n = "main" } = o;
|
|
187
|
+
let a = null;
|
|
188
|
+
const l = `transformers_model_files_${g}_${t}_${n}`;
|
|
183
189
|
try {
|
|
184
190
|
const s = localStorage.getItem(l);
|
|
185
191
|
if (s) {
|
|
186
|
-
|
|
187
|
-
const { timestamp: p, files: u } =
|
|
192
|
+
a = JSON.parse(s);
|
|
193
|
+
const { timestamp: p, files: u } = a, v = 1440 * 60 * 1e3;
|
|
188
194
|
if (Date.now() - p < v)
|
|
189
195
|
return u;
|
|
190
196
|
}
|
|
191
197
|
} catch (s) {
|
|
192
198
|
console.warn("Failed to read from localStorage cache:", s);
|
|
193
199
|
}
|
|
194
|
-
const e = `https://huggingface.co/api/models/${g}/tree/${
|
|
195
|
-
let
|
|
200
|
+
const e = `https://huggingface.co/api/models/${g}/tree/${n}?recursive=true`;
|
|
201
|
+
let r;
|
|
196
202
|
try {
|
|
197
|
-
if (
|
|
198
|
-
throw new Error(`Manifest fetch failed: ${
|
|
203
|
+
if (r = await fetch(e), !r.ok)
|
|
204
|
+
throw new Error(`Manifest fetch failed: ${r.status}`);
|
|
199
205
|
} catch (s) {
|
|
200
|
-
if (
|
|
206
|
+
if (a)
|
|
201
207
|
return console.warn(
|
|
202
208
|
"Failed to fetch manifest from network, falling back to cached data (expired):",
|
|
203
209
|
s
|
|
204
|
-
),
|
|
210
|
+
), a.files;
|
|
205
211
|
throw s;
|
|
206
212
|
}
|
|
207
|
-
const c = await
|
|
208
|
-
|
|
213
|
+
const c = await r.json(), f = new Map(c.map((s) => [s.path, s.size])), d = [], h = (s) => f.has(s), i = (s) => h(s) ? (d.push({ path: s, size: f.get(s) }), !0) : !1;
|
|
214
|
+
i("config.json"), i("generation_config.json"), i("preprocessor_config.json"), h("tokenizer.json") ? (i("tokenizer.json"), i("tokenizer_config.json")) : (i("tokenizer_config.json"), i("special_tokens_map.json"), i("vocab.json"), i("merges.txt"), i("vocab.txt"));
|
|
209
215
|
const w = "onnx";
|
|
210
216
|
let m = [];
|
|
211
217
|
t === "fp32" ? m = [""] : t === "quantized" ? m = ["_quantized"] : (m = [`_${t}`], t === "q8" && m.push(""));
|
|
@@ -228,11 +234,11 @@ async function $(g, n = {}) {
|
|
|
228
234
|
(s) => s.includes("decoder_model_merged")
|
|
229
235
|
), b = _.filter((s) => !(x && s.includes("decoder_model") && !s.includes("merged")));
|
|
230
236
|
for (const s of b) {
|
|
231
|
-
|
|
237
|
+
i(s);
|
|
232
238
|
const p = `${s}_data`;
|
|
233
|
-
if (
|
|
239
|
+
if (i(p)) {
|
|
234
240
|
let u = 1;
|
|
235
|
-
for (;
|
|
241
|
+
for (; i(`${p}_${u}`); )
|
|
236
242
|
u++;
|
|
237
243
|
}
|
|
238
244
|
}
|
|
@@ -250,5 +256,5 @@ async function $(g, n = {}) {
|
|
|
250
256
|
return d;
|
|
251
257
|
}
|
|
252
258
|
export {
|
|
253
|
-
|
|
259
|
+
I as default
|
|
254
260
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class a {
|
|
2
2
|
#e;
|
|
3
3
|
/**
|
|
4
4
|
* @param {string} modelName - The name of the model.
|
|
@@ -49,9 +49,9 @@ class r {
|
|
|
49
49
|
throw new Error("Not implemented");
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
const
|
|
52
|
+
const r = {
|
|
53
53
|
firebase: { modelName: "gemini-2.5-flash-lite" },
|
|
54
|
-
gemini: { modelName: "gemini-2.
|
|
54
|
+
gemini: { modelName: "gemini-2.5-flash-lite" },
|
|
55
55
|
openai: { modelName: "gpt-4o" },
|
|
56
56
|
transformers: {
|
|
57
57
|
modelName: "onnx-community/gemma-3-1b-it-ONNX-GQA",
|
|
@@ -60,6 +60,6 @@ const a = {
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
export {
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
r as D,
|
|
64
|
+
a as P
|
|
65
65
|
};
|
|
@@ -283,7 +283,7 @@ async function C(s, t = globalThis) {
|
|
|
283
283
|
}
|
|
284
284
|
return e;
|
|
285
285
|
}
|
|
286
|
-
class
|
|
286
|
+
class d extends EventTarget {
|
|
287
287
|
#o;
|
|
288
288
|
#f;
|
|
289
289
|
#r;
|
|
@@ -302,16 +302,16 @@ class h extends EventTarget {
|
|
|
302
302
|
get contextWindow() {
|
|
303
303
|
return 1e6;
|
|
304
304
|
}
|
|
305
|
-
get
|
|
305
|
+
get oncontextoverflow() {
|
|
306
306
|
return this.#c;
|
|
307
307
|
}
|
|
308
|
-
set
|
|
308
|
+
set oncontextoverflow(t) {
|
|
309
309
|
this.#c && this.removeEventListener(
|
|
310
|
-
"
|
|
310
|
+
"contextoverflow",
|
|
311
311
|
this.#c
|
|
312
|
-
), this.#c = t, typeof t == "function" && this.addEventListener("
|
|
312
|
+
), this.#c = t, typeof t == "function" && this.addEventListener("contextoverflow", t);
|
|
313
313
|
}
|
|
314
|
-
static #
|
|
314
|
+
static #h(t) {
|
|
315
315
|
try {
|
|
316
316
|
if (!t || !t.document || t.document.defaultView !== t)
|
|
317
317
|
throw new Error();
|
|
@@ -326,13 +326,13 @@ class h extends EventTarget {
|
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
#a() {
|
|
329
|
-
h
|
|
329
|
+
d.#h(this.#t);
|
|
330
330
|
}
|
|
331
331
|
static async availability(t = {}) {
|
|
332
332
|
const e = this.__window || globalThis;
|
|
333
|
-
h
|
|
333
|
+
d.#h(e);
|
|
334
334
|
try {
|
|
335
|
-
await
|
|
335
|
+
await d.#w(t, e);
|
|
336
336
|
} catch (o) {
|
|
337
337
|
if (o instanceof RangeError) {
|
|
338
338
|
if (o.message.includes("language tag"))
|
|
@@ -348,23 +348,23 @@ class h extends EventTarget {
|
|
|
348
348
|
}
|
|
349
349
|
return "unavailable";
|
|
350
350
|
}
|
|
351
|
-
return (await
|
|
351
|
+
return (await d.#p(e)).availability(t);
|
|
352
352
|
}
|
|
353
353
|
static #x = A;
|
|
354
|
-
static #
|
|
355
|
-
for (const r of
|
|
354
|
+
static #d(t = globalThis) {
|
|
355
|
+
for (const r of d.#x) {
|
|
356
356
|
const o = t[r.config] || globalThis[r.config];
|
|
357
357
|
if (o && o.apiKey)
|
|
358
358
|
return { ...r, configValue: o };
|
|
359
359
|
}
|
|
360
|
-
const e =
|
|
360
|
+
const e = d.#x.map((r) => `window.${r.config}`).join(", ");
|
|
361
361
|
throw new (t.DOMException || globalThis.DOMException)(
|
|
362
362
|
`Prompt API Polyfill: No backend configuration found. Please set one of: ${e}.`,
|
|
363
363
|
"NotSupportedError"
|
|
364
364
|
);
|
|
365
365
|
}
|
|
366
366
|
static async #p(t = globalThis) {
|
|
367
|
-
const e =
|
|
367
|
+
const e = d.#d(t);
|
|
368
368
|
return I(e.path);
|
|
369
369
|
}
|
|
370
370
|
static async #w(t = {}, e = globalThis) {
|
|
@@ -372,13 +372,13 @@ class h extends EventTarget {
|
|
|
372
372
|
for (const o of t.expectedInputs) {
|
|
373
373
|
if (o.type !== "text" && o.type !== "image" && o.type !== "audio")
|
|
374
374
|
throw new TypeError(`Invalid input type: ${o.type}`);
|
|
375
|
-
o.languages &&
|
|
375
|
+
o.languages && d.#y(o.languages);
|
|
376
376
|
}
|
|
377
377
|
if (t.expectedOutputs)
|
|
378
378
|
for (const o of t.expectedOutputs) {
|
|
379
379
|
if (o.type !== "text")
|
|
380
380
|
throw new RangeError(`Unsupported output type: ${o.type}`);
|
|
381
|
-
o.languages &&
|
|
381
|
+
o.languages && d.#y(o.languages);
|
|
382
382
|
}
|
|
383
383
|
const r = t.expectedInputs ? ["text", ...t.expectedInputs.map((o) => o.type)] : ["text"];
|
|
384
384
|
if (t.initialPrompts && Array.isArray(t.initialPrompts)) {
|
|
@@ -434,7 +434,7 @@ class h extends EventTarget {
|
|
|
434
434
|
}
|
|
435
435
|
static async create(t = {}) {
|
|
436
436
|
const e = this.__window || globalThis;
|
|
437
|
-
if (h
|
|
437
|
+
if (d.#h(e), await d.#w(t, e), t.signal?.aborted)
|
|
438
438
|
throw t.signal.reason || new (e.DOMException || globalThis.DOMException)(
|
|
439
439
|
"Aborted",
|
|
440
440
|
"AbortError"
|
|
@@ -455,8 +455,8 @@ class h extends EventTarget {
|
|
|
455
455
|
"Aborted",
|
|
456
456
|
"AbortError"
|
|
457
457
|
);
|
|
458
|
-
const o =
|
|
459
|
-
|
|
458
|
+
const o = d.#d(e), n = await d.#p(e), i = new n(o.configValue), c = { ...t };
|
|
459
|
+
d.#g(
|
|
460
460
|
c.responseConstraint,
|
|
461
461
|
e
|
|
462
462
|
);
|
|
@@ -471,16 +471,16 @@ class h extends EventTarget {
|
|
|
471
471
|
), p = c.initialPrompts.filter(
|
|
472
472
|
(f) => f.role !== "system"
|
|
473
473
|
);
|
|
474
|
-
w.length > 0 && (a.systemInstruction = w.map((f) => typeof f.content == "string" ? f.content : Array.isArray(f.content) ? f.content.filter((
|
|
474
|
+
w.length > 0 && (a.systemInstruction = w.map((f) => typeof f.content == "string" ? f.content : Array.isArray(f.content) ? f.content.filter((h) => h.type === "text").map((h) => h.value || h.text || "").join(`
|
|
475
475
|
`) : "").join(`
|
|
476
476
|
`)), l = await C(p, e);
|
|
477
477
|
for (const f of c.initialPrompts) {
|
|
478
478
|
if (typeof f.content != "string")
|
|
479
479
|
continue;
|
|
480
|
-
const
|
|
480
|
+
const h = d.#E([
|
|
481
481
|
{ text: f.content }
|
|
482
482
|
]);
|
|
483
|
-
if (
|
|
483
|
+
if (h === "QuotaExceededError" || h === "contextoverflow") {
|
|
484
484
|
const E = e.QuotaExceededError || e.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, u = new E(
|
|
485
485
|
"The initial prompts are too large, they exceed the quota.",
|
|
486
486
|
"QuotaExceededError"
|
|
@@ -489,7 +489,7 @@ class h extends EventTarget {
|
|
|
489
489
|
value: 22,
|
|
490
490
|
configurable: !0
|
|
491
491
|
});
|
|
492
|
-
const g =
|
|
492
|
+
const g = h === "QuotaExceededError" ? 1e7 : 5e5;
|
|
493
493
|
throw u.requested = g, u.quota = 1e6, u;
|
|
494
494
|
}
|
|
495
495
|
}
|
|
@@ -518,10 +518,10 @@ class h extends EventTarget {
|
|
|
518
518
|
lengthComputable: !0
|
|
519
519
|
})
|
|
520
520
|
), x.__lastProgressLoaded = f;
|
|
521
|
-
} catch (
|
|
522
|
-
console.error("Error dispatching downloadprogress events:",
|
|
521
|
+
} catch (h) {
|
|
522
|
+
console.error("Error dispatching downloadprogress events:", h);
|
|
523
523
|
}
|
|
524
|
-
return await new Promise((
|
|
524
|
+
return await new Promise((h) => setTimeout(h, 0)), !t.signal?.aborted;
|
|
525
525
|
};
|
|
526
526
|
if (!await b(0))
|
|
527
527
|
throw t.signal.reason || new (e.DOMException || globalThis.DOMException)(
|
|
@@ -573,7 +573,7 @@ class h extends EventTarget {
|
|
|
573
573
|
"Aborted",
|
|
574
574
|
"AbortError"
|
|
575
575
|
);
|
|
576
|
-
const e = JSON.parse(JSON.stringify(this.#r)), r = { ...this.#s, ...t }, o = await
|
|
576
|
+
const e = JSON.parse(JSON.stringify(this.#r)), r = { ...this.#s, ...t }, o = await d.#p(this.#t), n = d.#d(this.#t), i = new o(n.configValue), c = await i.createSession(
|
|
577
577
|
r,
|
|
578
578
|
this.#e
|
|
579
579
|
);
|
|
@@ -609,7 +609,7 @@ class h extends EventTarget {
|
|
|
609
609
|
if (typeof t == "object" && t !== null && !Array.isArray(t) && Object.keys(t).length === 0)
|
|
610
610
|
return "[object Object]";
|
|
611
611
|
if (e.responseConstraint) {
|
|
612
|
-
|
|
612
|
+
d.#g(
|
|
613
613
|
e.responseConstraint,
|
|
614
614
|
this.#t
|
|
615
615
|
);
|
|
@@ -652,15 +652,15 @@ class h extends EventTarget {
|
|
|
652
652
|
}), c = (async () => {
|
|
653
653
|
const a = this.#u(o);
|
|
654
654
|
if (a === "QuotaExceededError") {
|
|
655
|
-
const f = this.#t && this.#t.QuotaExceededError || this.#t && this.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException,
|
|
655
|
+
const f = this.#t && this.#t.QuotaExceededError || this.#t && this.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, h = new f(
|
|
656
656
|
"The prompt is too large, it exceeds the quota.",
|
|
657
657
|
"QuotaExceededError"
|
|
658
658
|
);
|
|
659
|
-
Object.defineProperty(
|
|
659
|
+
Object.defineProperty(h, "code", { value: 22, configurable: !0 });
|
|
660
660
|
const E = 1e7;
|
|
661
|
-
throw
|
|
662
|
-
} else if (a === "
|
|
663
|
-
return this.dispatchEvent(new Event("
|
|
661
|
+
throw h.requested = E, h.quota = this.contextWindow, h;
|
|
662
|
+
} else if (a === "contextoverflow")
|
|
663
|
+
return this.dispatchEvent(new Event("contextoverflow")), "Mock response for quota overflow test.";
|
|
664
664
|
const l = [...this.#r, n];
|
|
665
665
|
this.#e.systemInstruction && l.unshift({
|
|
666
666
|
role: "system",
|
|
@@ -670,13 +670,13 @@ class h extends EventTarget {
|
|
|
670
670
|
l
|
|
671
671
|
);
|
|
672
672
|
if (y > this.contextWindow) {
|
|
673
|
-
const f = this.#t && this.#t.QuotaExceededError || this.#t && this.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException,
|
|
673
|
+
const f = this.#t && this.#t.QuotaExceededError || this.#t && this.#t.DOMException || globalThis.QuotaExceededError || globalThis.DOMException, h = new f(
|
|
674
674
|
`The prompt is too large (${y} tokens), it exceeds the quota of ${this.contextWindow} tokens.`,
|
|
675
675
|
"QuotaExceededError"
|
|
676
676
|
);
|
|
677
|
-
throw Object.defineProperty(
|
|
677
|
+
throw Object.defineProperty(h, "code", { value: 22, configurable: !0 }), h.requested = y, h.quota = this.contextWindow, h;
|
|
678
678
|
}
|
|
679
|
-
y > this.contextWindow && this.dispatchEvent(new Event("
|
|
679
|
+
y > this.contextWindow && this.dispatchEvent(new Event("contextoverflow"));
|
|
680
680
|
const x = [...this.#r, n];
|
|
681
681
|
let b;
|
|
682
682
|
try {
|
|
@@ -737,7 +737,7 @@ class h extends EventTarget {
|
|
|
737
737
|
o && o.addEventListener("abort", c);
|
|
738
738
|
try {
|
|
739
739
|
if (e.responseConstraint) {
|
|
740
|
-
|
|
740
|
+
d.#g(
|
|
741
741
|
e.responseConstraint,
|
|
742
742
|
r.#t
|
|
743
743
|
);
|
|
@@ -767,8 +767,8 @@ class h extends EventTarget {
|
|
|
767
767
|
});
|
|
768
768
|
const O = 1e7;
|
|
769
769
|
throw g.requested = O, g.quota = r.contextWindow, g;
|
|
770
|
-
} else if (x === "
|
|
771
|
-
r.dispatchEvent(new Event("
|
|
770
|
+
} else if (x === "contextoverflow") {
|
|
771
|
+
r.dispatchEvent(new Event("contextoverflow")), n.enqueue("Mock response for quota overflow test."), n.close();
|
|
772
772
|
return;
|
|
773
773
|
}
|
|
774
774
|
const b = [...r.#r, y];
|
|
@@ -789,7 +789,7 @@ class h extends EventTarget {
|
|
|
789
789
|
configurable: !0
|
|
790
790
|
}), g.requested = m, g.quota = r.contextWindow, g;
|
|
791
791
|
}
|
|
792
|
-
m > r.contextWindow && r.dispatchEvent(new Event("
|
|
792
|
+
m > r.contextWindow && r.dispatchEvent(new Event("contextoverflow"));
|
|
793
793
|
const w = [...r.#r, y];
|
|
794
794
|
let p;
|
|
795
795
|
try {
|
|
@@ -797,20 +797,20 @@ class h extends EventTarget {
|
|
|
797
797
|
} catch (u) {
|
|
798
798
|
throw r.#m(u, l), u;
|
|
799
799
|
}
|
|
800
|
-
let f = "",
|
|
800
|
+
let f = "", h = !1, E = "";
|
|
801
801
|
for await (const u of p) {
|
|
802
802
|
if (i) {
|
|
803
803
|
typeof p.return == "function" && await p.return();
|
|
804
804
|
return;
|
|
805
805
|
}
|
|
806
806
|
let g = u.text();
|
|
807
|
-
if (a && !
|
|
807
|
+
if (a && !h) {
|
|
808
808
|
E += g;
|
|
809
809
|
const O = E.match(/^\s*{\s*"Rating"\s*:\s*/);
|
|
810
810
|
if (O)
|
|
811
|
-
g = E.slice(O[0].length),
|
|
811
|
+
g = E.slice(O[0].length), h = !0, E = "";
|
|
812
812
|
else if (E.length > 50)
|
|
813
|
-
g = E,
|
|
813
|
+
g = E, h = !0, E = "";
|
|
814
814
|
else
|
|
815
815
|
continue;
|
|
816
816
|
}
|
|
@@ -857,7 +857,7 @@ class h extends EventTarget {
|
|
|
857
857
|
this.#i = i || 0;
|
|
858
858
|
} catch {
|
|
859
859
|
}
|
|
860
|
-
this.#i > this.contextWindow && this.dispatchEvent(new Event("
|
|
860
|
+
this.#i > this.contextWindow && this.dispatchEvent(new Event("contextoverflow"));
|
|
861
861
|
}
|
|
862
862
|
async measureContextUsage(t) {
|
|
863
863
|
if (this.#a(), this.#n)
|
|
@@ -873,7 +873,7 @@ class h extends EventTarget {
|
|
|
873
873
|
"InvalidStateError"
|
|
874
874
|
);
|
|
875
875
|
const r = this.#u(e);
|
|
876
|
-
return r === "QuotaExceededError" ? 1e7 : r === "
|
|
876
|
+
return r === "QuotaExceededError" ? 1e7 : r === "contextoverflow" ? 5e5 : await this.#o.countTokens([
|
|
877
877
|
{ role: "user", parts: e }
|
|
878
878
|
]) || 0;
|
|
879
879
|
} catch {
|
|
@@ -884,13 +884,13 @@ class h extends EventTarget {
|
|
|
884
884
|
}
|
|
885
885
|
// Volkswagen mode detection to avoid cloud costs for WPT tests.
|
|
886
886
|
#u(t) {
|
|
887
|
-
return
|
|
887
|
+
return d.#E(t);
|
|
888
888
|
}
|
|
889
889
|
static #E(t) {
|
|
890
890
|
if (t.length !== 1 || !t[0].text)
|
|
891
891
|
return null;
|
|
892
892
|
const e = t[0].text;
|
|
893
|
-
return typeof e != "string" || !e.startsWith("Please write a sentence in English.") ? null : e.length > 1e7 ? "QuotaExceededError" : e.length > 5e4 ? "
|
|
893
|
+
return typeof e != "string" || !e.startsWith("Please write a sentence in English.") ? null : e.length > 1e7 ? "QuotaExceededError" : e.length > 5e4 ? "contextoverflow" : null;
|
|
894
894
|
}
|
|
895
895
|
static #g(t, e) {
|
|
896
896
|
if (t)
|
|
@@ -1003,7 +1003,7 @@ const D = (s) => {
|
|
|
1003
1003
|
try {
|
|
1004
1004
|
if (!s || s.LanguageModel?.__isPolyfill)
|
|
1005
1005
|
return;
|
|
1006
|
-
const t = class extends
|
|
1006
|
+
const t = class extends d {
|
|
1007
1007
|
};
|
|
1008
1008
|
t.__window = s, t.__isPolyfill = !0, s.LanguageModel = t, s.DOMException && (s.QuotaExceededError = s.DOMException);
|
|
1009
1009
|
} catch {
|
|
@@ -1037,9 +1037,9 @@ globalThis.document?.documentElement && (P.observe(globalThis.document.documentE
|
|
|
1037
1037
|
}), globalThis.document.querySelectorAll("iframe").forEach((s) => {
|
|
1038
1038
|
D(s.contentWindow);
|
|
1039
1039
|
}));
|
|
1040
|
-
(!("LanguageModel" in globalThis) || globalThis.__FORCE_PROMPT_API_POLYFILL__) && (globalThis.LanguageModel =
|
|
1040
|
+
(!("LanguageModel" in globalThis) || globalThis.__FORCE_PROMPT_API_POLYFILL__) && (globalThis.LanguageModel = d, d.__isPolyfill = !0, console.log(
|
|
1041
1041
|
"Polyfill: window.LanguageModel is now backed by the Prompt API polyfill."
|
|
1042
1042
|
));
|
|
1043
1043
|
export {
|
|
1044
|
-
|
|
1044
|
+
d as LanguageModel
|
|
1045
1045
|
};
|
package/dot_env.json
CHANGED
|
@@ -7,5 +7,15 @@
|
|
|
7
7
|
"reCaptchaSiteKey": "",
|
|
8
8
|
"useLimitedUseAppCheckTokens": true,
|
|
9
9
|
"device": "webgpu",
|
|
10
|
-
"dtype": "q4f16"
|
|
10
|
+
"dtype": "q4f16",
|
|
11
|
+
"env": {
|
|
12
|
+
"allowRemoteModels": true,
|
|
13
|
+
"backends": {
|
|
14
|
+
"onnx": {
|
|
15
|
+
"wasm": {
|
|
16
|
+
"wasmPaths": ""
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
11
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prompt-api-polyfill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Polyfill for the Prompt API (`LanguageModel`) backed by Firebase AI Logic, Gemini API, OpenAI API, or Transformers.js.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/prompt-api-polyfill.js",
|
|
@@ -47,7 +47,9 @@
|
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"prettier": "^3.8.1",
|
|
49
49
|
"prettier-plugin-curly": "^0.4.1",
|
|
50
|
-
"vite": "^7.3.1"
|
|
50
|
+
"vite": "^7.3.1",
|
|
51
|
+
"node-gyp": "^12.2.0",
|
|
52
|
+
"node-addon-api": "^8.5.0"
|
|
51
53
|
},
|
|
52
54
|
"dependencies": {
|
|
53
55
|
"@google/genai": "^1.42.0",
|