@plasius/ai 1.1.4 → 1.1.6

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +22 -2
  2. package/README.md +101 -2
  3. package/dist/components/pixelverse/balance.d.ts +6 -2
  4. package/dist/components/pixelverse/balance.d.ts.map +1 -1
  5. package/dist/components/pixelverse/balance.js +13 -23
  6. package/dist/components/pixelverse/index.d.ts +1 -1
  7. package/dist/components/pixelverse/index.d.ts.map +1 -1
  8. package/dist/components/pixelverse/index.js +1 -1
  9. package/dist/components/pixelverse/video-generation-editor.d.ts +10 -0
  10. package/dist/components/pixelverse/video-generation-editor.d.ts.map +1 -0
  11. package/dist/components/pixelverse/video-generation-editor.js +79 -0
  12. package/dist/platform/adapter-platform.d.ts +60 -0
  13. package/dist/platform/adapter-platform.d.ts.map +1 -0
  14. package/dist/platform/adapter-platform.js +222 -0
  15. package/dist/platform/gemini-adapter.d.ts +15 -0
  16. package/dist/platform/gemini-adapter.d.ts.map +1 -0
  17. package/dist/platform/gemini-adapter.js +293 -0
  18. package/dist/platform/http-resilience.d.ts +19 -0
  19. package/dist/platform/http-resilience.d.ts.map +1 -0
  20. package/dist/platform/http-resilience.js +126 -0
  21. package/dist/platform/index.d.ts +22 -1
  22. package/dist/platform/index.d.ts.map +1 -1
  23. package/dist/platform/index.js +24 -0
  24. package/dist/platform/openai-adapter.d.ts +24 -0
  25. package/dist/platform/openai-adapter.d.ts.map +1 -0
  26. package/dist/platform/openai-adapter.js +398 -0
  27. package/dist/platform/video-provider-adapter.d.ts +54 -0
  28. package/dist/platform/video-provider-adapter.d.ts.map +1 -0
  29. package/dist/platform/video-provider-adapter.js +165 -0
  30. package/dist/platform/video-provider-platform.d.ts +13 -0
  31. package/dist/platform/video-provider-platform.d.ts.map +1 -0
  32. package/dist/platform/video-provider-platform.js +102 -0
  33. package/dist-cjs/components/pixelverse/balance.d.ts +6 -2
  34. package/dist-cjs/components/pixelverse/balance.d.ts.map +1 -1
  35. package/dist-cjs/components/pixelverse/balance.js +13 -23
  36. package/dist-cjs/components/pixelverse/index.d.ts +1 -1
  37. package/dist-cjs/components/pixelverse/index.d.ts.map +1 -1
  38. package/dist-cjs/components/pixelverse/index.js +1 -1
  39. package/dist-cjs/components/pixelverse/video-generation-editor.d.ts +10 -0
  40. package/dist-cjs/components/pixelverse/video-generation-editor.d.ts.map +1 -0
  41. package/dist-cjs/components/pixelverse/video-generation-editor.js +85 -0
  42. package/dist-cjs/platform/adapter-platform.d.ts +60 -0
  43. package/dist-cjs/platform/adapter-platform.d.ts.map +1 -0
  44. package/dist-cjs/platform/adapter-platform.js +225 -0
  45. package/dist-cjs/platform/gemini-adapter.d.ts +15 -0
  46. package/dist-cjs/platform/gemini-adapter.d.ts.map +1 -0
  47. package/dist-cjs/platform/gemini-adapter.js +296 -0
  48. package/dist-cjs/platform/http-resilience.d.ts +19 -0
  49. package/dist-cjs/platform/http-resilience.d.ts.map +1 -0
  50. package/dist-cjs/platform/http-resilience.js +129 -0
  51. package/dist-cjs/platform/index.d.ts +22 -1
  52. package/dist-cjs/platform/index.d.ts.map +1 -1
  53. package/dist-cjs/platform/index.js +30 -1
  54. package/dist-cjs/platform/openai-adapter.d.ts +24 -0
  55. package/dist-cjs/platform/openai-adapter.d.ts.map +1 -0
  56. package/dist-cjs/platform/openai-adapter.js +401 -0
  57. package/dist-cjs/platform/video-provider-adapter.d.ts +54 -0
  58. package/dist-cjs/platform/video-provider-adapter.d.ts.map +1 -0
  59. package/dist-cjs/platform/video-provider-adapter.js +168 -0
  60. package/dist-cjs/platform/video-provider-platform.d.ts +13 -0
  61. package/dist-cjs/platform/video-provider-platform.d.ts.map +1 -0
  62. package/dist-cjs/platform/video-provider-platform.js +105 -0
  63. package/docs/api-reference.md +59 -0
  64. package/docs/architecture.md +5 -1
  65. package/docs/providers.md +24 -6
  66. package/package.json +6 -6
  67. package/src/components/pixelverse/balance.tsx +22 -35
  68. package/src/components/pixelverse/index.ts +1 -1
  69. package/src/components/pixelverse/video-generation-editor.tsx +164 -0
  70. package/src/platform/adapter-platform.ts +440 -0
  71. package/src/platform/gemini-adapter.ts +391 -0
  72. package/src/platform/http-resilience.ts +198 -0
  73. package/src/platform/index.ts +68 -0
  74. package/src/platform/openai-adapter.ts +552 -0
  75. package/src/platform/video-provider-adapter.ts +303 -0
  76. package/src/platform/video-provider-platform.ts +208 -0
  77. package/dist/components/pixelverse/pixelverseeditor.d.ts +0 -16
  78. package/dist/components/pixelverse/pixelverseeditor.d.ts.map +0 -1
  79. package/dist/components/pixelverse/pixelverseeditor.js +0 -21
  80. package/dist/platform/openai.d.ts +0 -8
  81. package/dist/platform/openai.d.ts.map +0 -1
  82. package/dist/platform/openai.js +0 -61
  83. package/dist/platform/pixelverse.d.ts +0 -6
  84. package/dist/platform/pixelverse.d.ts.map +0 -1
  85. package/dist/platform/pixelverse.js +0 -196
  86. package/dist-cjs/components/pixelverse/pixelverseeditor.d.ts +0 -16
  87. package/dist-cjs/components/pixelverse/pixelverseeditor.d.ts.map +0 -1
  88. package/dist-cjs/components/pixelverse/pixelverseeditor.js +0 -27
  89. package/dist-cjs/platform/openai.d.ts +0 -8
  90. package/dist-cjs/platform/openai.d.ts.map +0 -1
  91. package/dist-cjs/platform/openai.js +0 -67
  92. package/dist-cjs/platform/pixelverse.d.ts +0 -6
  93. package/dist-cjs/platform/pixelverse.d.ts.map +0 -1
  94. package/dist-cjs/platform/pixelverse.js +0 -199
  95. package/src/components/pixelverse/pixelverseeditor.mocule.css +0 -0
  96. package/src/components/pixelverse/pixelverseeditor.tsx +0 -74
  97. package/src/platform/openai.ts +0 -123
  98. package/src/platform/pixelverse.ts +0 -309
@@ -0,0 +1,440 @@
1
+ import { performance } from "node:perf_hooks";
2
+
3
+ import {
4
+ AICapability,
5
+ type AIPlatform,
6
+ type BalanceCompletion,
7
+ type ChatCompletion,
8
+ type Completion,
9
+ type ImageCompletion,
10
+ type ModelCompletion,
11
+ type SpeechCompletion,
12
+ type TextCompletion,
13
+ type VideoCompletion,
14
+ } from "./index.js";
15
+
16
+ export interface AdapterRequestContext {
17
+ userId: string;
18
+ providerId: string;
19
+ apiKey: string;
20
+ traceId: string;
21
+ }
22
+
23
+ export interface AdapterChatRequest extends AdapterRequestContext {
24
+ input: string;
25
+ context: string;
26
+ model: string;
27
+ }
28
+
29
+ export interface AdapterSynthesizeSpeechRequest extends AdapterRequestContext {
30
+ input: string;
31
+ voice: string;
32
+ context: string;
33
+ model: string;
34
+ }
35
+
36
+ export interface AdapterTranscribeSpeechRequest extends AdapterRequestContext {
37
+ input: Buffer;
38
+ context: string;
39
+ model: string;
40
+ }
41
+
42
+ export interface AdapterGenerateImageRequest extends AdapterRequestContext {
43
+ input: string;
44
+ context: string;
45
+ model: string;
46
+ }
47
+
48
+ export interface AdapterVideoRequest extends AdapterRequestContext {
49
+ input: string;
50
+ image: URL;
51
+ context: string;
52
+ model: string;
53
+ }
54
+
55
+ export interface AdapterGenerateModelRequest extends AdapterRequestContext {
56
+ input: string;
57
+ context: string;
58
+ model: string;
59
+ }
60
+
61
+ export interface AdapterBalanceRequest extends AdapterRequestContext {}
62
+
63
+ export interface AICapabilityAdapter {
64
+ id: string;
65
+ capabilities: AICapability[];
66
+ canHandle?: (capabilities: AICapability[]) => Promise<boolean> | boolean;
67
+ chatWithAI?: (request: AdapterChatRequest) => Promise<ChatCompletion>;
68
+ synthesizeSpeech?: (
69
+ request: AdapterSynthesizeSpeechRequest
70
+ ) => Promise<SpeechCompletion>;
71
+ transcribeSpeech?: (
72
+ request: AdapterTranscribeSpeechRequest
73
+ ) => Promise<TextCompletion>;
74
+ generateImage?: (
75
+ request: AdapterGenerateImageRequest
76
+ ) => Promise<ImageCompletion>;
77
+ produceVideo?: (request: AdapterVideoRequest) => Promise<VideoCompletion>;
78
+ generateModel?: (
79
+ request: AdapterGenerateModelRequest
80
+ ) => Promise<ModelCompletion>;
81
+ checkBalance?: (request: AdapterBalanceRequest) => Promise<BalanceCompletion>;
82
+ }
83
+
84
+ export interface AdapterPlatformProps {
85
+ adapters: AICapabilityAdapter[];
86
+ apiKeys: Record<string, string>;
87
+ defaultAdapterByCapability?: Partial<Record<AICapability, string>>;
88
+ }
89
+
90
+ type AdapterOperationMethod =
91
+ | "chatWithAI"
92
+ | "synthesizeSpeech"
93
+ | "transcribeSpeech"
94
+ | "generateImage"
95
+ | "produceVideo"
96
+ | "generateModel"
97
+ | "checkBalance";
98
+
99
+ interface ResolvedAdapter {
100
+ adapter: AICapabilityAdapter;
101
+ apiKey: string;
102
+ }
103
+
104
+ function createCompletionBase(
105
+ type: string,
106
+ model: string,
107
+ requestor: string,
108
+ durationMs: number
109
+ ): Completion {
110
+ return {
111
+ partitionKey: requestor,
112
+ id: crypto.randomUUID(),
113
+ type,
114
+ model,
115
+ createdAt: new Date().toISOString(),
116
+ durationMs,
117
+ usage: {},
118
+ };
119
+ }
120
+
121
+ function createAdapterContext(
122
+ requestorId: string,
123
+ adapter: AICapabilityAdapter,
124
+ apiKey: string
125
+ ): AdapterRequestContext {
126
+ return {
127
+ userId: requestorId,
128
+ providerId: adapter.id,
129
+ apiKey,
130
+ traceId: crypto.randomUUID(),
131
+ };
132
+ }
133
+
134
+ function requiresOperationalMethod(
135
+ capability: AICapability,
136
+ adapter: AICapabilityAdapter
137
+ ): boolean {
138
+ switch (capability) {
139
+ case AICapability.Chat:
140
+ return typeof adapter.chatWithAI === "function";
141
+ case AICapability.Text:
142
+ return true;
143
+ case AICapability.Speech:
144
+ return (
145
+ typeof adapter.synthesizeSpeech === "function" ||
146
+ typeof adapter.transcribeSpeech === "function"
147
+ );
148
+ case AICapability.Image:
149
+ return typeof adapter.generateImage === "function";
150
+ case AICapability.Video:
151
+ return typeof adapter.produceVideo === "function";
152
+ case AICapability.Balance:
153
+ return typeof adapter.checkBalance === "function";
154
+ case AICapability.Model:
155
+ return typeof adapter.generateModel === "function";
156
+ default:
157
+ return false;
158
+ }
159
+ }
160
+
161
+ export async function createAdapterPlatform(
162
+ userId: string,
163
+ props: AdapterPlatformProps
164
+ ): Promise<AIPlatform> {
165
+ const adapterById = new Map<string, AICapabilityAdapter>();
166
+
167
+ for (const adapter of props.adapters) {
168
+ if (!adapter.id || adapter.id.trim().length === 0) {
169
+ throw new Error("Adapter id must be a non-empty string.");
170
+ }
171
+ if (adapterById.has(adapter.id)) {
172
+ throw new Error(`Duplicate adapter id "${adapter.id}" detected.`);
173
+ }
174
+ adapterById.set(adapter.id, adapter);
175
+ }
176
+
177
+ const resolveApiKey = (providerId: string): string | undefined => {
178
+ const value = props.apiKeys[providerId];
179
+ if (typeof value !== "string") {
180
+ return undefined;
181
+ }
182
+ const trimmed = value.trim();
183
+ return trimmed.length > 0 ? trimmed : undefined;
184
+ };
185
+
186
+ const resolveAdapter = (
187
+ capability: AICapability,
188
+ method: AdapterOperationMethod,
189
+ options: { required: boolean }
190
+ ): ResolvedAdapter | undefined => {
191
+ const configuredId = props.defaultAdapterByCapability?.[capability];
192
+
193
+ const fail = (message: string): undefined => {
194
+ if (options.required) {
195
+ throw new Error(message);
196
+ }
197
+ return undefined;
198
+ };
199
+
200
+ if (configuredId) {
201
+ const configured = adapterById.get(configuredId);
202
+ if (!configured) {
203
+ return fail(
204
+ `Configured adapter "${configuredId}" for capability "${capability}" was not found.`
205
+ );
206
+ }
207
+ if (!configured.capabilities.includes(capability)) {
208
+ return fail(
209
+ `Configured adapter "${configuredId}" does not declare capability "${capability}".`
210
+ );
211
+ }
212
+ if (typeof configured[method] !== "function") {
213
+ return fail(
214
+ `Configured adapter "${configuredId}" does not implement "${method}" for capability "${capability}".`
215
+ );
216
+ }
217
+ const apiKey = resolveApiKey(configured.id);
218
+ if (!apiKey) {
219
+ return fail(`Missing API key for configured adapter "${configured.id}".`);
220
+ }
221
+ return { adapter: configured, apiKey };
222
+ }
223
+
224
+ const fallback = props.adapters.find((candidate) => {
225
+ return (
226
+ candidate.capabilities.includes(capability) &&
227
+ typeof candidate[method] === "function"
228
+ );
229
+ });
230
+
231
+ if (!fallback) {
232
+ return fail(
233
+ `No adapter found for capability "${capability}" implementing "${method}".`
234
+ );
235
+ }
236
+
237
+ const apiKey = resolveApiKey(fallback.id);
238
+ if (!apiKey) {
239
+ return fail(`Missing API key for adapter "${fallback.id}".`);
240
+ }
241
+
242
+ return { adapter: fallback, apiKey };
243
+ };
244
+
245
+ const canHandle = async (
246
+ _requestorId: string,
247
+ capabilities: AICapability[]
248
+ ): Promise<boolean> => {
249
+ for (const capability of capabilities) {
250
+ const configuredId = props.defaultAdapterByCapability?.[capability];
251
+ const adapter = configuredId
252
+ ? adapterById.get(configuredId)
253
+ : props.adapters.find((candidate) =>
254
+ candidate.capabilities.includes(capability)
255
+ );
256
+
257
+ if (!adapter) {
258
+ return false;
259
+ }
260
+
261
+ if (!adapter.capabilities.includes(capability)) {
262
+ return false;
263
+ }
264
+
265
+ if (!resolveApiKey(adapter.id)) {
266
+ return false;
267
+ }
268
+
269
+ if (!requiresOperationalMethod(capability, adapter)) {
270
+ return false;
271
+ }
272
+
273
+ if (adapter.canHandle) {
274
+ const accepted = await adapter.canHandle([capability]);
275
+ if (!accepted) {
276
+ return false;
277
+ }
278
+ }
279
+ }
280
+
281
+ return true;
282
+ };
283
+
284
+ const chatWithAI = async (
285
+ requestorId: string,
286
+ input: string,
287
+ context: string,
288
+ model: string
289
+ ): Promise<ChatCompletion> => {
290
+ const resolved = resolveAdapter(AICapability.Chat, "chatWithAI", {
291
+ required: true,
292
+ }) as ResolvedAdapter;
293
+ return resolved.adapter.chatWithAI!(
294
+ {
295
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
296
+ input,
297
+ context,
298
+ model,
299
+ }
300
+ );
301
+ };
302
+
303
+ const synthesizeSpeech = async (
304
+ requestorId: string,
305
+ input: string,
306
+ voice: string,
307
+ context: string,
308
+ model: string
309
+ ): Promise<SpeechCompletion> => {
310
+ const resolved = resolveAdapter(AICapability.Speech, "synthesizeSpeech", {
311
+ required: true,
312
+ }) as ResolvedAdapter;
313
+ return resolved.adapter.synthesizeSpeech!(
314
+ {
315
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
316
+ input,
317
+ voice,
318
+ context,
319
+ model,
320
+ }
321
+ );
322
+ };
323
+
324
+ const transcribeSpeech = async (
325
+ requestorId: string,
326
+ input: Buffer,
327
+ context: string,
328
+ model: string
329
+ ): Promise<TextCompletion> => {
330
+ const resolved = resolveAdapter(AICapability.Speech, "transcribeSpeech", {
331
+ required: true,
332
+ }) as ResolvedAdapter;
333
+ return resolved.adapter.transcribeSpeech!(
334
+ {
335
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
336
+ input,
337
+ context,
338
+ model,
339
+ }
340
+ );
341
+ };
342
+
343
+ const generateImage = async (
344
+ requestorId: string,
345
+ input: string,
346
+ context: string,
347
+ model: string
348
+ ): Promise<ImageCompletion> => {
349
+ const resolved = resolveAdapter(AICapability.Image, "generateImage", {
350
+ required: true,
351
+ }) as ResolvedAdapter;
352
+ return resolved.adapter.generateImage!(
353
+ {
354
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
355
+ input,
356
+ context,
357
+ model,
358
+ }
359
+ );
360
+ };
361
+
362
+ const produceVideo = async (
363
+ requestorId: string,
364
+ input: string,
365
+ image: URL,
366
+ context: string,
367
+ model: string
368
+ ): Promise<VideoCompletion> => {
369
+ const resolved = resolveAdapter(AICapability.Video, "produceVideo", {
370
+ required: true,
371
+ }) as ResolvedAdapter;
372
+ return resolved.adapter.produceVideo!(
373
+ {
374
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
375
+ input,
376
+ image,
377
+ context,
378
+ model,
379
+ }
380
+ );
381
+ };
382
+
383
+ const generateModel = async (
384
+ requestorId: string,
385
+ input: string,
386
+ context: string,
387
+ model: string
388
+ ): Promise<ModelCompletion> => {
389
+ const resolved = resolveAdapter(AICapability.Model, "generateModel", {
390
+ required: true,
391
+ }) as ResolvedAdapter;
392
+ return resolved.adapter.generateModel!(
393
+ {
394
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
395
+ input,
396
+ context,
397
+ model,
398
+ }
399
+ );
400
+ };
401
+
402
+ const checkBalance = async (requestorId: string): Promise<BalanceCompletion> => {
403
+ const startedAt = performance.now();
404
+ const resolved = resolveAdapter(AICapability.Balance, "checkBalance", {
405
+ required: false,
406
+ });
407
+
408
+ if (!resolved || !resolved.adapter.checkBalance) {
409
+ const durationMs = performance.now() - startedAt;
410
+ const base = createCompletionBase(
411
+ "balanceCompletion",
412
+ "",
413
+ requestorId,
414
+ durationMs
415
+ );
416
+ return {
417
+ ...base,
418
+ balance: 0,
419
+ };
420
+ }
421
+
422
+ return resolved.adapter.checkBalance(
423
+ createAdapterContext(requestorId, resolved.adapter, resolved.apiKey)
424
+ );
425
+ };
426
+
427
+ const currentBalance = (await checkBalance(userId)).balance;
428
+
429
+ return {
430
+ canHandle,
431
+ chatWithAI,
432
+ synthesizeSpeech,
433
+ transcribeSpeech,
434
+ generateImage,
435
+ produceVideo,
436
+ generateModel,
437
+ checkBalance,
438
+ currentBalance,
439
+ };
440
+ }