nuxt-edge-ai 0.1.4 → 0.2.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 +2 -0
- package/dist/module.mjs +41 -1
- package/dist/runtime/client.d.ts +6 -1
- package/dist/runtime/client.js +30 -0
- package/dist/runtime/composables/useEdgeAI.d.ts +6 -1
- package/dist/runtime/composables/useEdgeAI.js +33 -14
- package/dist/runtime/plugin.d.ts +11 -1
- package/dist/runtime/plugin.js +30 -0
- package/dist/runtime/presets.js +77 -5
- package/dist/runtime/server/api/chat-completions.post.d.ts +1 -1
- package/dist/runtime/server/api/chat-completions.post.js +2 -1
- package/dist/runtime/server/api/classify.post.d.ts +2 -0
- package/dist/runtime/server/api/classify.post.js +14 -0
- package/dist/runtime/server/api/embed.post.d.ts +2 -0
- package/dist/runtime/server/api/embed.post.js +15 -0
- package/dist/runtime/server/api/fill-mask.post.d.ts +2 -0
- package/dist/runtime/server/api/fill-mask.post.js +15 -0
- package/dist/runtime/server/api/generate.post.d.ts +1 -1
- package/dist/runtime/server/api/generate.post.js +49 -2
- package/dist/runtime/server/api/summarize.post.d.ts +2 -0
- package/dist/runtime/server/api/summarize.post.js +15 -0
- package/dist/runtime/server/api/translate.post.d.ts +2 -0
- package/dist/runtime/server/api/translate.post.js +14 -0
- package/dist/runtime/server/utils/edge-ai-engine.d.ts +56 -1
- package/dist/runtime/server/utils/edge-ai-engine.js +222 -28
- package/dist/runtime/types.d.ts +109 -2
- package/package.json +78 -78
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
[](https://nuxt.com/)
|
|
7
7
|
[](https://github.com/otadk/nuxt-edge-ai/actions/workflows/ci.yml)
|
|
8
|
+
[](https://oosmetrics.com/repo/otadk/nuxt-edge-ai)
|
|
9
|
+
[](https://oosmetrics.com/repo/otadk/nuxt-edge-ai)
|
|
8
10
|
|
|
9
11
|
`nuxt-edge-ai` is a Nuxt module for building local-first AI applications with a real server-side WASM inference runtime and an optional remote API fallback.
|
|
10
12
|
|
package/dist/module.mjs
CHANGED
|
@@ -150,17 +150,52 @@ const module$1 = defineNuxtModule({
|
|
|
150
150
|
method: "post",
|
|
151
151
|
handler: resolver.resolve("./runtime/server/api/chat-completions.post")
|
|
152
152
|
});
|
|
153
|
+
addServerHandler({
|
|
154
|
+
route: `${routeBase}/classify`,
|
|
155
|
+
method: "post",
|
|
156
|
+
handler: resolver.resolve("./runtime/server/api/classify.post")
|
|
157
|
+
});
|
|
158
|
+
addServerHandler({
|
|
159
|
+
route: `${routeBase}/embed`,
|
|
160
|
+
method: "post",
|
|
161
|
+
handler: resolver.resolve("./runtime/server/api/embed.post")
|
|
162
|
+
});
|
|
163
|
+
addServerHandler({
|
|
164
|
+
route: `${routeBase}/summarize`,
|
|
165
|
+
method: "post",
|
|
166
|
+
handler: resolver.resolve("./runtime/server/api/summarize.post")
|
|
167
|
+
});
|
|
168
|
+
addServerHandler({
|
|
169
|
+
route: `${routeBase}/translate`,
|
|
170
|
+
method: "post",
|
|
171
|
+
handler: resolver.resolve("./runtime/server/api/translate.post")
|
|
172
|
+
});
|
|
173
|
+
addServerHandler({
|
|
174
|
+
route: `${routeBase}/fill-mask`,
|
|
175
|
+
method: "post",
|
|
176
|
+
handler: resolver.resolve("./runtime/server/api/fill-mask.post")
|
|
177
|
+
});
|
|
153
178
|
addTypeTemplate({
|
|
154
179
|
filename: "types/nuxt-edge-ai.d.ts",
|
|
155
180
|
getContents: () => `import type { NuxtApp } from '#app'
|
|
156
181
|
import type {
|
|
157
182
|
EdgeAIChatCompletionRequest,
|
|
158
183
|
EdgeAIChatCompletionResponse,
|
|
184
|
+
EdgeAIClassifyRequest,
|
|
185
|
+
EdgeAIClassifyResponse,
|
|
159
186
|
EdgeAIClientOptions,
|
|
187
|
+
EdgeAIEmbedRequest,
|
|
188
|
+
EdgeAIEmbedResponse,
|
|
189
|
+
EdgeAIFillMaskRequest,
|
|
190
|
+
EdgeAIFillMaskResponse,
|
|
160
191
|
EdgeAIGenerateRequest,
|
|
161
192
|
EdgeAIGenerateResponse,
|
|
162
193
|
EdgeAIHealthResponse,
|
|
163
|
-
EdgeAIPullResponse
|
|
194
|
+
EdgeAIPullResponse,
|
|
195
|
+
EdgeAISummarizeRequest,
|
|
196
|
+
EdgeAISummarizeResponse,
|
|
197
|
+
EdgeAITranslateRequest,
|
|
198
|
+
EdgeAITranslateResponse,
|
|
164
199
|
} from 'nuxt-edge-ai'
|
|
165
200
|
import type { EdgeAI } from 'nuxt-edge-ai'
|
|
166
201
|
|
|
@@ -179,6 +214,11 @@ declare module '#app' {
|
|
|
179
214
|
generate: (payload: EdgeAIGenerateRequest) => Promise<EdgeAIGenerateResponse>
|
|
180
215
|
chatCompletions: (payload: EdgeAIChatCompletionRequest) => Promise<EdgeAIChatCompletionResponse>
|
|
181
216
|
health: () => Promise<EdgeAIHealthResponse>
|
|
217
|
+
classify: (payload: EdgeAIClassifyRequest) => Promise<EdgeAIClassifyResponse>
|
|
218
|
+
embed: (payload: EdgeAIEmbedRequest) => Promise<EdgeAIEmbedResponse>
|
|
219
|
+
summarize: (payload: EdgeAISummarizeRequest) => Promise<EdgeAISummarizeResponse>
|
|
220
|
+
translate: (payload: EdgeAITranslateRequest) => Promise<EdgeAITranslateResponse>
|
|
221
|
+
fillMask: (payload: EdgeAIFillMaskRequest) => Promise<EdgeAIFillMaskResponse>
|
|
182
222
|
}
|
|
183
223
|
}
|
|
184
224
|
}
|
package/dist/runtime/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIHealthResponse, EdgeAIPullResponse, EdgeAIStreamCallbacks, EdgeAIStreamState, StreamPart } from './types.js';
|
|
1
|
+
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIClassifyRequest, EdgeAIClassifyResponse, EdgeAIEmbedRequest, EdgeAIEmbedResponse, EdgeAIFillMaskRequest, EdgeAIFillMaskResponse, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIHealthResponse, EdgeAIPullResponse, EdgeAIStreamCallbacks, EdgeAIStreamState, EdgeAISummarizeRequest, EdgeAISummarizeResponse, EdgeAITranslateRequest, EdgeAITranslateResponse, StreamPart } from './types.js';
|
|
2
2
|
export interface EdgeAIClientOptions {
|
|
3
3
|
baseURL: string;
|
|
4
4
|
apiKey?: string;
|
|
@@ -23,6 +23,11 @@ export declare class EdgeAI {
|
|
|
23
23
|
health(): Promise<EdgeAIHealthResponse>;
|
|
24
24
|
pull(): Promise<EdgeAIPullResponse>;
|
|
25
25
|
generate(payload: EdgeAIGenerateRequest): Promise<EdgeAIGenerateResponse>;
|
|
26
|
+
classify(payload: EdgeAIClassifyRequest): Promise<EdgeAIClassifyResponse>;
|
|
27
|
+
embed(payload: EdgeAIEmbedRequest): Promise<EdgeAIEmbedResponse>;
|
|
28
|
+
summarize(payload: EdgeAISummarizeRequest): Promise<EdgeAISummarizeResponse>;
|
|
29
|
+
translate(payload: EdgeAITranslateRequest): Promise<EdgeAITranslateResponse>;
|
|
30
|
+
fillMask(payload: EdgeAIFillMaskRequest): Promise<EdgeAIFillMaskResponse>;
|
|
26
31
|
private streamChatCompletion;
|
|
27
32
|
streamChatCompletionGenerator(payload: EdgeAIChatCompletionRequest): AsyncGenerator<string, EdgeAIStreamState, unknown>;
|
|
28
33
|
stop(state: EdgeAIStreamState): void;
|
package/dist/runtime/client.js
CHANGED
|
@@ -124,6 +124,36 @@ export class EdgeAI {
|
|
|
124
124
|
body: payload
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
|
+
classify(payload) {
|
|
128
|
+
return this.request("/classify", {
|
|
129
|
+
method: "POST",
|
|
130
|
+
body: payload
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
embed(payload) {
|
|
134
|
+
return this.request("/embed", {
|
|
135
|
+
method: "POST",
|
|
136
|
+
body: payload
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
summarize(payload) {
|
|
140
|
+
return this.request("/summarize", {
|
|
141
|
+
method: "POST",
|
|
142
|
+
body: payload
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
translate(payload) {
|
|
146
|
+
return this.request("/translate", {
|
|
147
|
+
method: "POST",
|
|
148
|
+
body: payload
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
fillMask(payload) {
|
|
152
|
+
return this.request("/fill-mask", {
|
|
153
|
+
method: "POST",
|
|
154
|
+
body: payload
|
|
155
|
+
});
|
|
156
|
+
}
|
|
127
157
|
// Streaming chat completion with callbacks
|
|
128
158
|
async streamChatCompletion(payload, callbacks) {
|
|
129
159
|
const abortController = new AbortController();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EdgeAI } from '../client.js';
|
|
2
|
-
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIHealthResponse, EdgeAIPullResponse } from '../types.js';
|
|
2
|
+
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIClassifyRequest, EdgeAIEmbedRequest, EdgeAIFillMaskRequest, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIHealthResponse, EdgeAIPullResponse, EdgeAISummarizeRequest, EdgeAITranslateRequest } from '../types.js';
|
|
3
3
|
export interface UseEdgeAIOptions {
|
|
4
4
|
onStreamStart?: () => void;
|
|
5
5
|
onStreamToken?: (token: string) => void;
|
|
@@ -29,6 +29,11 @@ export declare function useEdgeAI(options?: UseEdgeAIOptions): {
|
|
|
29
29
|
generate(payload: EdgeAIGenerateRequest): Promise<EdgeAIGenerateResponse>;
|
|
30
30
|
chatCompletions(payload: EdgeAIChatCompletionRequest): Promise<EdgeAIChatCompletionResponse>;
|
|
31
31
|
health(): Promise<EdgeAIHealthResponse>;
|
|
32
|
+
classify(payload: EdgeAIClassifyRequest): Promise<import("../types.js").EdgeAIClassifyResponse>;
|
|
33
|
+
embed(payload: EdgeAIEmbedRequest): Promise<import("../types.js").EdgeAIEmbedResponse>;
|
|
34
|
+
summarize(payload: EdgeAISummarizeRequest): Promise<import("../types.js").EdgeAISummarizeResponse>;
|
|
35
|
+
translate(payload: EdgeAITranslateRequest): Promise<import("../types.js").EdgeAITranslateResponse>;
|
|
36
|
+
fillMask(payload: EdgeAIFillMaskRequest): Promise<import("../types.js").EdgeAIFillMaskResponse>;
|
|
32
37
|
isLoading: import("vue").Ref<boolean, boolean>;
|
|
33
38
|
isStreaming: import("vue").Ref<boolean, boolean>;
|
|
34
39
|
streamedContent: import("vue").Ref<string, string>;
|
|
@@ -194,19 +194,17 @@ export function useEdgeAI(options = {}) {
|
|
|
194
194
|
model: payload.model || defaultModel
|
|
195
195
|
};
|
|
196
196
|
try {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
);
|
|
197
|
+
const fetchUrl = routeBase.startsWith("http") ? `${routeBase}/chat/completions` : new URL(`${routeBase}/chat/completions`, window.location.origin).toString();
|
|
198
|
+
const response = await fetch(fetchUrl, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: {
|
|
201
|
+
"content-type": "application/json",
|
|
202
|
+
"accept": "text/event-stream",
|
|
203
|
+
"x-vercel-ai-ui-message-stream": "v1"
|
|
204
|
+
},
|
|
205
|
+
body: JSON.stringify({ ...payload, stream: true }),
|
|
206
|
+
signal: abortController.value.signal
|
|
207
|
+
});
|
|
210
208
|
if (!response.ok) {
|
|
211
209
|
const errorText = await response.text();
|
|
212
210
|
throw new Error(`Stream request failed with ${response.status}: ${errorText}`);
|
|
@@ -263,10 +261,15 @@ export function useEdgeAI(options = {}) {
|
|
|
263
261
|
case "error": {
|
|
264
262
|
throw new Error(part.errorText || "Stream error");
|
|
265
263
|
}
|
|
264
|
+
default: {
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
266
267
|
}
|
|
267
268
|
}
|
|
268
269
|
}
|
|
269
|
-
if (done)
|
|
270
|
+
if (done) {
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
270
273
|
}
|
|
271
274
|
} finally {
|
|
272
275
|
reader.releaseLock();
|
|
@@ -311,6 +314,22 @@ export function useEdgeAI(options = {}) {
|
|
|
311
314
|
health() {
|
|
312
315
|
return edgeAIService.health();
|
|
313
316
|
},
|
|
317
|
+
// Task-specific methods
|
|
318
|
+
classify(payload) {
|
|
319
|
+
return edgeAIService.client.classify(payload);
|
|
320
|
+
},
|
|
321
|
+
embed(payload) {
|
|
322
|
+
return edgeAIService.client.embed(payload);
|
|
323
|
+
},
|
|
324
|
+
summarize(payload) {
|
|
325
|
+
return edgeAIService.client.summarize(payload);
|
|
326
|
+
},
|
|
327
|
+
translate(payload) {
|
|
328
|
+
return edgeAIService.client.translate(payload);
|
|
329
|
+
},
|
|
330
|
+
fillMask(payload) {
|
|
331
|
+
return edgeAIService.client.fillMask(payload);
|
|
332
|
+
},
|
|
314
333
|
// Streaming state (reactive refs)
|
|
315
334
|
isLoading,
|
|
316
335
|
isStreaming,
|
package/dist/runtime/plugin.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EdgeAI } from './client.js';
|
|
2
|
-
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIHealthResponse, EdgeAIPullResponse } from './types.js';
|
|
2
|
+
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIClassifyRequest, EdgeAIClassifyResponse, EdgeAIEmbedRequest, EdgeAIEmbedResponse, EdgeAIFillMaskRequest, EdgeAIFillMaskResponse, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIHealthResponse, EdgeAIPullResponse, EdgeAISummarizeRequest, EdgeAISummarizeResponse, EdgeAITranslateRequest, EdgeAITranslateResponse } from './types.js';
|
|
3
3
|
declare const _default: import("nuxt/app").Plugin<{
|
|
4
4
|
edgeAI: {
|
|
5
5
|
routeBase: string;
|
|
@@ -14,6 +14,11 @@ declare const _default: import("nuxt/app").Plugin<{
|
|
|
14
14
|
generate(payload: EdgeAIGenerateRequest): Promise<EdgeAIGenerateResponse>;
|
|
15
15
|
chatCompletions(payload: EdgeAIChatCompletionRequest): Promise<EdgeAIChatCompletionResponse>;
|
|
16
16
|
health(): Promise<EdgeAIHealthResponse>;
|
|
17
|
+
classify(payload: EdgeAIClassifyRequest): Promise<EdgeAIClassifyResponse>;
|
|
18
|
+
embed(payload: EdgeAIEmbedRequest): Promise<EdgeAIEmbedResponse>;
|
|
19
|
+
summarize(payload: EdgeAISummarizeRequest): Promise<EdgeAISummarizeResponse>;
|
|
20
|
+
translate(payload: EdgeAITranslateRequest): Promise<EdgeAITranslateResponse>;
|
|
21
|
+
fillMask(payload: EdgeAIFillMaskRequest): Promise<EdgeAIFillMaskResponse>;
|
|
17
22
|
};
|
|
18
23
|
}> & import("nuxt/app").ObjectPlugin<{
|
|
19
24
|
edgeAI: {
|
|
@@ -29,6 +34,11 @@ declare const _default: import("nuxt/app").Plugin<{
|
|
|
29
34
|
generate(payload: EdgeAIGenerateRequest): Promise<EdgeAIGenerateResponse>;
|
|
30
35
|
chatCompletions(payload: EdgeAIChatCompletionRequest): Promise<EdgeAIChatCompletionResponse>;
|
|
31
36
|
health(): Promise<EdgeAIHealthResponse>;
|
|
37
|
+
classify(payload: EdgeAIClassifyRequest): Promise<EdgeAIClassifyResponse>;
|
|
38
|
+
embed(payload: EdgeAIEmbedRequest): Promise<EdgeAIEmbedResponse>;
|
|
39
|
+
summarize(payload: EdgeAISummarizeRequest): Promise<EdgeAISummarizeResponse>;
|
|
40
|
+
translate(payload: EdgeAITranslateRequest): Promise<EdgeAITranslateResponse>;
|
|
41
|
+
fillMask(payload: EdgeAIFillMaskRequest): Promise<EdgeAIFillMaskResponse>;
|
|
32
42
|
};
|
|
33
43
|
}>;
|
|
34
44
|
export default _default;
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -44,6 +44,36 @@ export default defineNuxtPlugin(() => {
|
|
|
44
44
|
},
|
|
45
45
|
health() {
|
|
46
46
|
return $fetch(`${routeBase}/health`);
|
|
47
|
+
},
|
|
48
|
+
classify(payload) {
|
|
49
|
+
return $fetch(`${routeBase}/classify`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
body: payload
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
embed(payload) {
|
|
55
|
+
return $fetch(`${routeBase}/embed`, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: payload
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
summarize(payload) {
|
|
61
|
+
return $fetch(`${routeBase}/summarize`, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
body: payload
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
translate(payload) {
|
|
67
|
+
return $fetch(`${routeBase}/translate`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body: payload
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
fillMask(payload) {
|
|
73
|
+
return $fetch(`${routeBase}/fill-mask`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
body: payload
|
|
76
|
+
});
|
|
47
77
|
}
|
|
48
78
|
}
|
|
49
79
|
}
|
package/dist/runtime/presets.js
CHANGED
|
@@ -6,7 +6,7 @@ const defaultGeneration = {
|
|
|
6
6
|
repetitionPenalty: 1.05
|
|
7
7
|
};
|
|
8
8
|
export const builtinModelPresets = {
|
|
9
|
-
distilgpt2: {
|
|
9
|
+
"distilgpt2": {
|
|
10
10
|
label: "DistilGPT2",
|
|
11
11
|
description: "Small baseline text-generation model for quick smoke tests.",
|
|
12
12
|
model: {
|
|
@@ -18,6 +18,78 @@ export const builtinModelPresets = {
|
|
|
18
18
|
...defaultGeneration
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
},
|
|
22
|
+
"distilbert-sst2": {
|
|
23
|
+
label: "DistilBERT Sentiment",
|
|
24
|
+
description: "Sentiment analysis (positive/negative) using DistilBERT fine-tuned on SST-2.",
|
|
25
|
+
model: {
|
|
26
|
+
id: "Xenova/distilbert-base-uncased-finetuned-sst-2-english",
|
|
27
|
+
task: "text-classification",
|
|
28
|
+
allowRemote: true,
|
|
29
|
+
dtype: "fp32"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"minilm-l6-v2": {
|
|
33
|
+
label: "MiniLM Embedding",
|
|
34
|
+
description: "384-dimensional text embeddings using all-MiniLM-L6-v2. Ideal for semantic search and RAG.",
|
|
35
|
+
model: {
|
|
36
|
+
id: "Xenova/all-MiniLM-L6-v2",
|
|
37
|
+
task: "feature-extraction",
|
|
38
|
+
allowRemote: true,
|
|
39
|
+
dtype: "fp32"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"distilbart-cnn": {
|
|
43
|
+
label: "DistilBART Summarization",
|
|
44
|
+
description: "Text summarization using DistilBART fine-tuned on CNN/DailyMail.",
|
|
45
|
+
model: {
|
|
46
|
+
id: "Xenova/distilbart-cnn-6-6",
|
|
47
|
+
task: "summarization",
|
|
48
|
+
allowRemote: true,
|
|
49
|
+
dtype: "fp32",
|
|
50
|
+
generation: {
|
|
51
|
+
...defaultGeneration,
|
|
52
|
+
maxNewTokens: 128
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"opus-mt-en-zh": {
|
|
57
|
+
label: "Opus-MT en\u2192zh",
|
|
58
|
+
description: "English to Chinese translation using Helsinki-NLP Opus-MT.",
|
|
59
|
+
model: {
|
|
60
|
+
id: "Xenova/opus-mt-en-zh",
|
|
61
|
+
task: "translation",
|
|
62
|
+
allowRemote: true,
|
|
63
|
+
dtype: "fp32",
|
|
64
|
+
generation: {
|
|
65
|
+
...defaultGeneration,
|
|
66
|
+
maxNewTokens: 256
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"opus-mt-zh-en": {
|
|
71
|
+
label: "Opus-MT zh\u2192en",
|
|
72
|
+
description: "Chinese to English translation using Helsinki-NLP Opus-MT.",
|
|
73
|
+
model: {
|
|
74
|
+
id: "Xenova/opus-mt-zh-en",
|
|
75
|
+
task: "translation",
|
|
76
|
+
allowRemote: true,
|
|
77
|
+
dtype: "fp32",
|
|
78
|
+
generation: {
|
|
79
|
+
...defaultGeneration,
|
|
80
|
+
maxNewTokens: 256
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"bert-base-uncased": {
|
|
85
|
+
label: "BERT Fill-Mask",
|
|
86
|
+
description: "Masked token prediction using BERT base uncased. Use [MASK] token in your text.",
|
|
87
|
+
model: {
|
|
88
|
+
id: "Xenova/bert-base-uncased",
|
|
89
|
+
task: "fill-mask",
|
|
90
|
+
allowRemote: true,
|
|
91
|
+
dtype: "fp32"
|
|
92
|
+
}
|
|
21
93
|
}
|
|
22
94
|
};
|
|
23
95
|
export function resolveGenerationDefaults(defaults, overrides) {
|
|
@@ -30,11 +102,11 @@ export function resolveGenerationDefaults(defaults, overrides) {
|
|
|
30
102
|
};
|
|
31
103
|
}
|
|
32
104
|
export function mergeModelConfig(base, overrides) {
|
|
33
|
-
const
|
|
34
|
-
const
|
|
105
|
+
const resolvedId = overrides?.id || base?.id || builtinModelPresets.distilgpt2.model.id;
|
|
106
|
+
const resolvedTask = overrides?.task ?? base?.task ?? "text-generation";
|
|
35
107
|
return {
|
|
36
|
-
id:
|
|
37
|
-
task:
|
|
108
|
+
id: resolvedId,
|
|
109
|
+
task: resolvedTask,
|
|
38
110
|
localPath: overrides?.localPath ?? base?.localPath,
|
|
39
111
|
allowRemote: overrides?.allowRemote ?? base?.allowRemote ?? true,
|
|
40
112
|
dtype: overrides?.dtype ?? base?.dtype,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<import("../../types.js").EdgeAIChatCompletionResponse |
|
|
1
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<import("../../types.js").EdgeAIChatCompletionResponse | null>>;
|
|
2
2
|
export default _default;
|
|
@@ -21,6 +21,7 @@ export default defineEventHandler(async (event) => {
|
|
|
21
21
|
const wantsStreaming = body.stream === true || wantsEventStream;
|
|
22
22
|
if (wantsStreaming) {
|
|
23
23
|
const streamResponse = !body.stream || wantsUIMessageStream ? createEdgeAIChatCompletionStream(config, body) : createEdgeAIChatCompletionOpenAIStream(config, body);
|
|
24
|
+
event.node.res.statusCode = 200;
|
|
24
25
|
for (const [key, value] of Object.entries(streamResponse.headers)) {
|
|
25
26
|
event.node.res.setHeader(key, value);
|
|
26
27
|
}
|
|
@@ -35,7 +36,7 @@ export default defineEventHandler(async (event) => {
|
|
|
35
36
|
reader.releaseLock();
|
|
36
37
|
event.node.res.end();
|
|
37
38
|
}
|
|
38
|
-
return;
|
|
39
|
+
return null;
|
|
39
40
|
}
|
|
40
41
|
return createEdgeAIChatCompletion(config, body);
|
|
41
42
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { classifyEdgeAIText } from "../utils/edge-ai-engine.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const body = await readBody(event);
|
|
6
|
+
if (!body?.text?.trim()) {
|
|
7
|
+
throw createError({ statusCode: 400, statusMessage: "Text is required." });
|
|
8
|
+
}
|
|
9
|
+
const config = useRuntimeConfig().edgeAI;
|
|
10
|
+
return classifyEdgeAIText(config, {
|
|
11
|
+
text: body.text.trim(),
|
|
12
|
+
model: body.model
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { embedEdgeAIText } from "../utils/edge-ai-engine.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const body = await readBody(event);
|
|
6
|
+
if (!body?.texts || (Array.isArray(body.texts) ? body.texts.length === 0 : !body.texts.trim())) {
|
|
7
|
+
throw createError({ statusCode: 400, statusMessage: "Texts (string or string array) is required." });
|
|
8
|
+
}
|
|
9
|
+
const config = useRuntimeConfig().edgeAI;
|
|
10
|
+
return embedEdgeAIText(config, {
|
|
11
|
+
texts: body.texts,
|
|
12
|
+
pooling: body.pooling,
|
|
13
|
+
model: body.model
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { fillMaskEdgeAIText } from "../utils/edge-ai-engine.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const body = await readBody(event);
|
|
6
|
+
if (!body?.text?.trim()) {
|
|
7
|
+
throw createError({ statusCode: 400, statusMessage: "Text with [MASK] token is required." });
|
|
8
|
+
}
|
|
9
|
+
const config = useRuntimeConfig().edgeAI;
|
|
10
|
+
return fillMaskEdgeAIText(config, {
|
|
11
|
+
text: body.text.trim(),
|
|
12
|
+
model: body.model,
|
|
13
|
+
topK: body.topK
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<import("../../types.js").EdgeAIGenerateResponse>>;
|
|
1
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<import("../../types.js").EdgeAIGenerateResponse | import("../../types.js").EdgeAIClassifyResponse | import("../../types.js").EdgeAIEmbedResponse | import("../../types.js").EdgeAISummarizeResponse | import("../../types.js").EdgeAITranslateResponse | import("../../types.js").EdgeAIFillMaskResponse>>;
|
|
2
2
|
export default _default;
|
|
@@ -1,8 +1,56 @@
|
|
|
1
1
|
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
2
|
import { useRuntimeConfig } from "#imports";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
classifyEdgeAIText,
|
|
5
|
+
embedEdgeAIText,
|
|
6
|
+
fillMaskEdgeAIText,
|
|
7
|
+
generateEdgeAIText,
|
|
8
|
+
resolvePromptFromMessages,
|
|
9
|
+
summarizeEdgeAIText,
|
|
10
|
+
translateEdgeAIText
|
|
11
|
+
} from "../utils/edge-ai-engine.js";
|
|
4
12
|
export default defineEventHandler(async (event) => {
|
|
5
13
|
const body = await readBody(event);
|
|
14
|
+
const config = useRuntimeConfig().edgeAI;
|
|
15
|
+
if (body?.task && body.task !== "text-generation") {
|
|
16
|
+
switch (body.task) {
|
|
17
|
+
case "text-classification": {
|
|
18
|
+
const text = body.prompt?.trim();
|
|
19
|
+
if (!text) {
|
|
20
|
+
throw createError({ statusCode: 400, statusMessage: "Text (prompt) is required for classification." });
|
|
21
|
+
}
|
|
22
|
+
return classifyEdgeAIText(config, { text, model: body.model });
|
|
23
|
+
}
|
|
24
|
+
case "feature-extraction": {
|
|
25
|
+
const texts = body.prompt?.trim() || body.messages && resolvePromptFromMessages(body.messages);
|
|
26
|
+
if (!texts) {
|
|
27
|
+
throw createError({ statusCode: 400, statusMessage: "Text (prompt or messages) is required for embedding." });
|
|
28
|
+
}
|
|
29
|
+
return embedEdgeAIText(config, { texts, model: body.model });
|
|
30
|
+
}
|
|
31
|
+
case "summarization": {
|
|
32
|
+
const text = body.prompt?.trim();
|
|
33
|
+
if (!text) {
|
|
34
|
+
throw createError({ statusCode: 400, statusMessage: "Text (prompt) is required for summarization." });
|
|
35
|
+
}
|
|
36
|
+
return summarizeEdgeAIText(config, { text, model: body.model, generation: body.generation });
|
|
37
|
+
}
|
|
38
|
+
case "translation": {
|
|
39
|
+
const text = body.prompt?.trim();
|
|
40
|
+
if (!text) {
|
|
41
|
+
throw createError({ statusCode: 400, statusMessage: "Text (prompt) is required for translation." });
|
|
42
|
+
}
|
|
43
|
+
return translateEdgeAIText(config, { text, model: body.model });
|
|
44
|
+
}
|
|
45
|
+
case "fill-mask": {
|
|
46
|
+
const text = body.prompt?.trim();
|
|
47
|
+
if (!text) {
|
|
48
|
+
throw createError({ statusCode: 400, statusMessage: "Text (prompt) with [MASK] is required for fill-mask." });
|
|
49
|
+
}
|
|
50
|
+
return fillMaskEdgeAIText(config, { text, model: body.model });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
6
54
|
const prompt = body?.prompt?.trim();
|
|
7
55
|
const hasMessages = Array.isArray(body?.messages) && body.messages.length > 0;
|
|
8
56
|
if (!prompt && !hasMessages) {
|
|
@@ -11,7 +59,6 @@ export default defineEventHandler(async (event) => {
|
|
|
11
59
|
statusMessage: "Prompt or messages are required."
|
|
12
60
|
});
|
|
13
61
|
}
|
|
14
|
-
const config = useRuntimeConfig().edgeAI;
|
|
15
62
|
return generateEdgeAIText(config, {
|
|
16
63
|
prompt,
|
|
17
64
|
remote: body.remote,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { summarizeEdgeAIText } from "../utils/edge-ai-engine.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const body = await readBody(event);
|
|
6
|
+
if (!body?.text?.trim()) {
|
|
7
|
+
throw createError({ statusCode: 400, statusMessage: "Text is required." });
|
|
8
|
+
}
|
|
9
|
+
const config = useRuntimeConfig().edgeAI;
|
|
10
|
+
return summarizeEdgeAIText(config, {
|
|
11
|
+
text: body.text.trim(),
|
|
12
|
+
model: body.model,
|
|
13
|
+
generation: body.generation
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { translateEdgeAIText } from "../utils/edge-ai-engine.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const body = await readBody(event);
|
|
6
|
+
if (!body?.text?.trim()) {
|
|
7
|
+
throw createError({ statusCode: 400, statusMessage: "Text is required." });
|
|
8
|
+
}
|
|
9
|
+
const config = useRuntimeConfig().edgeAI;
|
|
10
|
+
return translateEdgeAIText(config, {
|
|
11
|
+
text: body.text.trim(),
|
|
12
|
+
model: body.model
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -1,4 +1,58 @@
|
|
|
1
|
-
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIHealthResponse, EdgeAIServerRuntimeConfig, EdgeAIPullResponse } from '../../types.js';
|
|
1
|
+
import type { EdgeAIChatCompletionRequest, EdgeAIChatCompletionResponse, EdgeAIChatCompletionStreamResponse, EdgeAIClassifyRequest, EdgeAIClassifyResponse, EdgeAIEmbedRequest, EdgeAIEmbedResponse, EdgeAIFillMaskRequest, EdgeAIFillMaskResponse, EdgeAIGenerateRequest, EdgeAIGenerateResponse, EdgeAIGenerationOptions, EdgeAIHealthResponse, EdgeAIModelInfo, EdgeAIRemoteMessage, EdgeAIRemoteConfig, EdgeAIServerRuntimeConfig, EdgeAISummarizeRequest, EdgeAISummarizeResponse, EdgeAITranslateRequest, EdgeAITranslateResponse, EdgeAIPullResponse } from '../../types.js';
|
|
2
|
+
interface RemoteChatCompletionResponse {
|
|
3
|
+
id?: string;
|
|
4
|
+
model?: string;
|
|
5
|
+
choices?: Array<{
|
|
6
|
+
message?: {
|
|
7
|
+
role?: string;
|
|
8
|
+
content?: string | Array<{
|
|
9
|
+
type?: string;
|
|
10
|
+
text?: string;
|
|
11
|
+
}>;
|
|
12
|
+
reasoning_details?: unknown;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
text?: string;
|
|
16
|
+
delta?: {
|
|
17
|
+
role?: string;
|
|
18
|
+
content?: string;
|
|
19
|
+
};
|
|
20
|
+
finish_reason?: string | null;
|
|
21
|
+
}>;
|
|
22
|
+
output_text?: string;
|
|
23
|
+
output?: Array<{
|
|
24
|
+
content?: Array<{
|
|
25
|
+
text?: string;
|
|
26
|
+
type?: string;
|
|
27
|
+
}>;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export declare function resolveLocalModelSource(config: EdgeAIServerRuntimeConfig, modelOverride?: string): EdgeAIModelInfo;
|
|
31
|
+
export declare function resolveRemoteModelSource(config: EdgeAIServerRuntimeConfig, modelOverride?: string): EdgeAIModelInfo;
|
|
32
|
+
export declare function resolveGenerationOptions(defaults?: EdgeAIGenerationOptions, overrides?: EdgeAIGenerateRequest['generation']): {
|
|
33
|
+
maxNewTokens: number;
|
|
34
|
+
temperature: number;
|
|
35
|
+
topP: number;
|
|
36
|
+
doSample: boolean;
|
|
37
|
+
repetitionPenalty: number;
|
|
38
|
+
};
|
|
39
|
+
export declare function extractGeneratedText(prompt: string, output: unknown): string;
|
|
40
|
+
export declare function extractTextFromMessageContent(content: unknown): string;
|
|
41
|
+
export declare function resolvePromptFromMessages(messages?: EdgeAIRemoteMessage[]): string;
|
|
42
|
+
export declare function resolvePrompt(input: EdgeAIGenerateRequest): string;
|
|
43
|
+
export declare function buildRemoteMessages(config: EdgeAIServerRuntimeConfig, input: EdgeAIGenerateRequest): EdgeAIRemoteMessage[];
|
|
44
|
+
export declare function buildAssistantMessage(payload: RemoteChatCompletionResponse, text: string): EdgeAIRemoteMessage;
|
|
45
|
+
export declare function estimateTokenCount(text: string): number;
|
|
46
|
+
export declare function toChatCompletionResponse(request: EdgeAIChatCompletionRequest, result: EdgeAIGenerateResponse): EdgeAIChatCompletionResponse;
|
|
47
|
+
export declare function toChatCompletionStreamChunk(id: string, model: string, delta: Partial<EdgeAIRemoteMessage>, finishReason?: 'stop' | null): EdgeAIChatCompletionStreamResponse;
|
|
48
|
+
export declare function resolveRemoteApiKey(config: EdgeAIRemoteConfig): string | undefined;
|
|
49
|
+
export declare function joinUrl(baseURL: string, path: string): string;
|
|
50
|
+
export declare function extractRemoteText(payload: RemoteChatCompletionResponse): string;
|
|
51
|
+
export declare function classifyEdgeAIText(config: EdgeAIServerRuntimeConfig, request: EdgeAIClassifyRequest): Promise<EdgeAIClassifyResponse>;
|
|
52
|
+
export declare function embedEdgeAIText(config: EdgeAIServerRuntimeConfig, request: EdgeAIEmbedRequest): Promise<EdgeAIEmbedResponse>;
|
|
53
|
+
export declare function summarizeEdgeAIText(config: EdgeAIServerRuntimeConfig, request: EdgeAISummarizeRequest): Promise<EdgeAISummarizeResponse>;
|
|
54
|
+
export declare function translateEdgeAIText(config: EdgeAIServerRuntimeConfig, request: EdgeAITranslateRequest): Promise<EdgeAITranslateResponse>;
|
|
55
|
+
export declare function fillMaskEdgeAIText(config: EdgeAIServerRuntimeConfig, request: EdgeAIFillMaskRequest): Promise<EdgeAIFillMaskResponse>;
|
|
2
56
|
export declare function getEdgeAIHealth(config: EdgeAIServerRuntimeConfig): Promise<EdgeAIHealthResponse>;
|
|
3
57
|
export declare function pullEdgeAIModel(config: EdgeAIServerRuntimeConfig): Promise<EdgeAIPullResponse>;
|
|
4
58
|
export declare function generateEdgeAIText(config: EdgeAIServerRuntimeConfig, input: EdgeAIGenerateRequest): Promise<EdgeAIGenerateResponse>;
|
|
@@ -11,3 +65,4 @@ export declare function createEdgeAIChatCompletionOpenAIStream(config: EdgeAISer
|
|
|
11
65
|
stream: ReadableStream<string>;
|
|
12
66
|
headers: Record<string, string>;
|
|
13
67
|
};
|
|
68
|
+
export {};
|