@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,102 @@
1
+ import { performance } from "node:perf_hooks";
2
+ function createCompletionBase(type, model, requestor, durationMs) {
3
+ return {
4
+ partitionKey: requestor,
5
+ id: crypto.randomUUID(),
6
+ type,
7
+ model,
8
+ createdAt: new Date().toISOString(),
9
+ durationMs,
10
+ usage: {},
11
+ };
12
+ }
13
+ async function waitForCompletion(adapter, videoId, apiKey, maxRetries, delayMs) {
14
+ for (let attempt = 0; attempt < maxRetries; attempt += 1) {
15
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
16
+ const result = await adapter.getVideoResult(videoId, {
17
+ apiKey,
18
+ traceId: crypto.randomUUID(),
19
+ });
20
+ if (result.state === "completed" && result.videoUrl) {
21
+ return result.videoUrl;
22
+ }
23
+ if (result.state === "failed") {
24
+ throw new Error("Video generation failed in provider adapter.");
25
+ }
26
+ }
27
+ throw new Error("Timed out waiting for provider video completion.");
28
+ }
29
+ export async function createVideoProviderPlatform(userId, props) {
30
+ const apiKey = props.apiKey.trim();
31
+ if (!apiKey) {
32
+ throw new Error("apiKey is required for createVideoProviderPlatform.");
33
+ }
34
+ const maxRetries = props.polling?.maxRetries ?? 20;
35
+ const delayMs = props.polling?.delayMs ?? 3000;
36
+ const chatWithAI = (_userId, _input, _context, _model) => {
37
+ return Promise.reject(new Error("Not implemented"));
38
+ };
39
+ const synthesizeSpeech = (_userId, _input, _voice, _context, _model) => {
40
+ return Promise.reject(new Error("Not implemented"));
41
+ };
42
+ const transcribeSpeech = (_userId, _input, _context, _model) => {
43
+ return Promise.reject(new Error("Not implemented"));
44
+ };
45
+ const generateImage = (_userId, _input, _context, _model) => {
46
+ return Promise.reject(new Error("Not implemented"));
47
+ };
48
+ const produceVideo = async (requestorId, prompt, image, _context, model) => {
49
+ const startedAt = performance.now();
50
+ const uploaded = await props.adapter.uploadImage(image, {
51
+ apiKey,
52
+ traceId: crypto.randomUUID(),
53
+ });
54
+ const generated = await props.adapter.generateVideo({
55
+ imageId: uploaded.imageId,
56
+ prompt,
57
+ ...props.defaultVideoRequest,
58
+ }, {
59
+ apiKey,
60
+ traceId: crypto.randomUUID(),
61
+ });
62
+ const videoUrl = await waitForCompletion(props.adapter, generated.videoId, apiKey, maxRetries, delayMs);
63
+ const durationMs = performance.now() - startedAt;
64
+ const base = createCompletionBase("video", model, requestorId, durationMs);
65
+ return {
66
+ ...base,
67
+ url: new URL(videoUrl),
68
+ };
69
+ };
70
+ const generateModel = (_userId, _input, _context, _model) => {
71
+ return Promise.reject(new Error("Not implemented"));
72
+ };
73
+ const checkBalance = async (requestorId) => {
74
+ const startedAt = performance.now();
75
+ const providerBalance = props.adapter.getBalance
76
+ ? await props.adapter.getBalance({
77
+ apiKey,
78
+ traceId: crypto.randomUUID(),
79
+ })
80
+ : {
81
+ monthlyCredit: 0,
82
+ packageCredit: 0,
83
+ };
84
+ const durationMs = performance.now() - startedAt;
85
+ const base = createCompletionBase("balanceCompletion", "", requestorId, durationMs);
86
+ return {
87
+ ...base,
88
+ balance: providerBalance.monthlyCredit + providerBalance.packageCredit,
89
+ };
90
+ };
91
+ const currentBalance = (await checkBalance(userId)).balance;
92
+ return {
93
+ chatWithAI,
94
+ synthesizeSpeech,
95
+ transcribeSpeech,
96
+ generateImage,
97
+ produceVideo,
98
+ generateModel,
99
+ checkBalance,
100
+ currentBalance,
101
+ };
102
+ }
@@ -1,4 +1,8 @@
1
- export default function Balance({ apiKey }: {
1
+ import type { VideoProviderAdapter } from "../../platform/video-provider-adapter.js";
2
+ export interface BalanceProps {
2
3
  apiKey: string;
3
- }): import("react/jsx-runtime").JSX.Element;
4
+ adapter: VideoProviderAdapter;
5
+ refreshMs?: number;
6
+ }
7
+ export default function Balance({ apiKey, adapter, refreshMs }: BalanceProps): import("react/jsx-runtime").JSX.Element;
4
8
  //# sourceMappingURL=balance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"balance.d.ts","sourceRoot":"","sources":["../../../src/components/pixelverse/balance.tsx"],"names":[],"mappings":"AAcA,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,2CAkD7D"}
1
+ {"version":3,"file":"balance.d.ts","sourceRoot":"","sources":["../../../src/components/pixelverse/balance.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAGtG,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,SAAkB,EAAE,EAAE,YAAY,2CAyCpF"}
@@ -6,41 +6,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.default = Balance;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const react_1 = require("react");
9
- const uuid_1 = require("uuid");
10
9
  const balance_module_css_1 = __importDefault(require("./balance.module.css"));
11
- function Balance({ apiKey }) {
10
+ function Balance({ apiKey, adapter, refreshMs = 600000 }) {
12
11
  const [balance, setBalance] = (0, react_1.useState)(null);
13
12
  const fetchBalance = async () => {
13
+ if (!adapter.getBalance) {
14
+ setBalance({ monthlyCredit: 0, packageCredit: 0 });
15
+ return;
16
+ }
14
17
  try {
15
- const response = await fetch("/pixelapi/openapi/v2/account/balance", {
16
- method: "GET",
17
- headers: {
18
- "API-KEY": apiKey,
19
- "AI-trace-ID": (0, uuid_1.v4)(),
20
- Accept: "application/json",
21
- "Content-Type": "application/json",
22
- },
23
- referrerPolicy: "no-referrer",
18
+ const value = await adapter.getBalance({
19
+ apiKey,
20
+ traceId: crypto.randomUUID(),
24
21
  });
25
- if (!response.ok) {
26
- console.error("Failed to fetch balance:", response.status, response.statusText);
27
- return;
28
- }
29
- const data = (await response.json());
30
- if (data?.Resp) {
31
- setBalance(data.Resp);
32
- }
22
+ setBalance(value);
33
23
  }
34
24
  catch (err) {
35
25
  console.error("fetchBalance() error", err);
36
26
  }
37
27
  };
38
28
  (0, react_1.useEffect)(() => {
39
- void fetchBalance(); // initial load
29
+ void fetchBalance();
40
30
  const intervalId = setInterval(() => {
41
31
  void fetchBalance();
42
- }, 600000);
32
+ }, refreshMs);
43
33
  return () => clearInterval(intervalId);
44
- }, [apiKey]);
45
- return ((0, jsx_runtime_1.jsx)("div", { className: balance_module_css_1.default.balance_container, children: balance ? ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("p", { children: ["Monthly Credit: ", balance.credit_monthly] }), (0, jsx_runtime_1.jsxs)("p", { children: ["Package Credit: ", balance.credit_package] })] })) : ((0, jsx_runtime_1.jsx)("p", { children: "Loading balance..." })) }));
34
+ }, [apiKey, adapter, refreshMs]);
35
+ return ((0, jsx_runtime_1.jsx)("div", { className: balance_module_css_1.default.balance_container, children: balance ? ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("p", { children: ["Monthly Credit: ", balance.monthlyCredit] }), (0, jsx_runtime_1.jsxs)("p", { children: ["Package Credit: ", balance.packageCredit] })] })) : ((0, jsx_runtime_1.jsx)("p", { children: "Loading balance..." })) }));
46
36
  }
@@ -1,3 +1,3 @@
1
1
  export * from "./balance.js";
2
- export * from "./pixelverseeditor.js";
2
+ export * from "./video-generation-editor.js";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/pixelverse/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/pixelverse/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,8BAA8B,CAAC"}
@@ -15,4 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./balance.js"), exports);
18
- __exportStar(require("./pixelverseeditor.js"), exports);
18
+ __exportStar(require("./video-generation-editor.js"), exports);
@@ -0,0 +1,10 @@
1
+ import type { VideoGenerationRequest, VideoProviderAdapter } from "../../platform/video-provider-adapter.js";
2
+ export interface VideoGenerationEditorProps {
3
+ apiKey: string;
4
+ adapter: VideoProviderAdapter;
5
+ onVideoGenerated?: (videoUrl: string) => void;
6
+ initialRequest?: Partial<Omit<VideoGenerationRequest, "imageId">>;
7
+ }
8
+ export declare function VideoGenerationEditor({ apiKey, adapter, onVideoGenerated, initialRequest, }: VideoGenerationEditorProps): import("react/jsx-runtime").JSX.Element;
9
+ export default VideoGenerationEditor;
10
+ //# sourceMappingURL=video-generation-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-generation-editor.d.ts","sourceRoot":"","sources":["../../../src/components/pixelverse/video-generation-editor.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,0CAA0C,CAAC;AAElD,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC,CAAC,CAAC;CACnE;AA8CD,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,OAAO,EACP,gBAAgB,EAChB,cAAc,GACf,EAAE,0BAA0B,2CAkG5B;AAED,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.VideoGenerationEditor = VideoGenerationEditor;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const react_1 = require("react");
9
+ const balance_js_1 = __importDefault(require("./balance.js"));
10
+ const defaultRequest = {
11
+ prompt: "",
12
+ model: "standard",
13
+ motionMode: "normal",
14
+ quality: "720p",
15
+ durationSeconds: 5,
16
+ watermark: false,
17
+ };
18
+ function toRequest(overrides) {
19
+ return {
20
+ ...defaultRequest,
21
+ ...overrides,
22
+ };
23
+ }
24
+ async function waitForVideoCompletion(adapter, videoId, apiKey, maxRetries = 20, delayMs = 3000) {
25
+ for (let attempt = 0; attempt < maxRetries; attempt += 1) {
26
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
27
+ const result = await adapter.getVideoResult(videoId, {
28
+ apiKey,
29
+ traceId: crypto.randomUUID(),
30
+ });
31
+ if (result.state === "completed" && result.videoUrl) {
32
+ return result.videoUrl;
33
+ }
34
+ if (result.state === "failed") {
35
+ throw new Error("Video generation failed.");
36
+ }
37
+ }
38
+ throw new Error("Timed out waiting for video generation result.");
39
+ }
40
+ function VideoGenerationEditor({ apiKey, adapter, onVideoGenerated, initialRequest, }) {
41
+ const [videoUrl, setVideoUrl] = (0, react_1.useState)("");
42
+ const [selectedFile, setSelectedFile] = (0, react_1.useState)(null);
43
+ const [loading, setLoading] = (0, react_1.useState)(false);
44
+ const [videoReady, setVideoReady] = (0, react_1.useState)(false);
45
+ const [request, setRequest] = (0, react_1.useState)(toRequest(initialRequest));
46
+ const handleFileChange = (event) => {
47
+ const file = event.target.files?.[0] ?? null;
48
+ setSelectedFile(file);
49
+ };
50
+ const handleRegenerate = () => {
51
+ void handleUploadProcess();
52
+ };
53
+ const handleUploadProcess = async () => {
54
+ if (!selectedFile) {
55
+ return;
56
+ }
57
+ setLoading(true);
58
+ setVideoReady(false);
59
+ try {
60
+ const uploaded = await adapter.uploadImage(selectedFile, {
61
+ apiKey,
62
+ traceId: crypto.randomUUID(),
63
+ });
64
+ const generated = await adapter.generateVideo({
65
+ ...request,
66
+ imageId: uploaded.imageId,
67
+ }, {
68
+ apiKey,
69
+ traceId: crypto.randomUUID(),
70
+ });
71
+ const generatedUrl = await waitForVideoCompletion(adapter, generated.videoId, apiKey);
72
+ setVideoUrl(generatedUrl);
73
+ setVideoReady(true);
74
+ onVideoGenerated?.(generatedUrl);
75
+ }
76
+ finally {
77
+ setLoading(false);
78
+ }
79
+ };
80
+ return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(balance_js_1.default, { apiKey: apiKey, adapter: adapter }), !videoReady && !selectedFile && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { children: "Drag/Drop or Click HERE to upload" }), (0, jsx_runtime_1.jsx)("input", { title: "Upload Image", type: "file", accept: ".jpg,.jpeg,.png,.webp", onChange: handleFileChange })] })), !videoReady ? ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("label", { children: ["Prompt", (0, jsx_runtime_1.jsx)("textarea", { value: request.prompt, onChange: (event) => setRequest((previous) => ({
81
+ ...previous,
82
+ prompt: event.target.value,
83
+ })) })] }) })) : null, loading && (0, jsx_runtime_1.jsx)("div", { children: "Loading..." }), !videoReady && selectedFile && !loading && ((0, jsx_runtime_1.jsx)("button", { onClick: handleUploadProcess, children: "Start Upload" })), videoReady && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("video", { src: videoUrl, controls: true }), (0, jsx_runtime_1.jsx)("button", { onClick: handleRegenerate, children: "Regenerate" })] }))] }));
84
+ }
85
+ exports.default = VideoGenerationEditor;
@@ -0,0 +1,60 @@
1
+ import { AICapability, type AIPlatform, type BalanceCompletion, type ChatCompletion, type ImageCompletion, type ModelCompletion, type SpeechCompletion, type TextCompletion, type VideoCompletion } from "./index.js";
2
+ export interface AdapterRequestContext {
3
+ userId: string;
4
+ providerId: string;
5
+ apiKey: string;
6
+ traceId: string;
7
+ }
8
+ export interface AdapterChatRequest extends AdapterRequestContext {
9
+ input: string;
10
+ context: string;
11
+ model: string;
12
+ }
13
+ export interface AdapterSynthesizeSpeechRequest extends AdapterRequestContext {
14
+ input: string;
15
+ voice: string;
16
+ context: string;
17
+ model: string;
18
+ }
19
+ export interface AdapterTranscribeSpeechRequest extends AdapterRequestContext {
20
+ input: Buffer;
21
+ context: string;
22
+ model: string;
23
+ }
24
+ export interface AdapterGenerateImageRequest extends AdapterRequestContext {
25
+ input: string;
26
+ context: string;
27
+ model: string;
28
+ }
29
+ export interface AdapterVideoRequest extends AdapterRequestContext {
30
+ input: string;
31
+ image: URL;
32
+ context: string;
33
+ model: string;
34
+ }
35
+ export interface AdapterGenerateModelRequest extends AdapterRequestContext {
36
+ input: string;
37
+ context: string;
38
+ model: string;
39
+ }
40
+ export interface AdapterBalanceRequest extends AdapterRequestContext {
41
+ }
42
+ export interface AICapabilityAdapter {
43
+ id: string;
44
+ capabilities: AICapability[];
45
+ canHandle?: (capabilities: AICapability[]) => Promise<boolean> | boolean;
46
+ chatWithAI?: (request: AdapterChatRequest) => Promise<ChatCompletion>;
47
+ synthesizeSpeech?: (request: AdapterSynthesizeSpeechRequest) => Promise<SpeechCompletion>;
48
+ transcribeSpeech?: (request: AdapterTranscribeSpeechRequest) => Promise<TextCompletion>;
49
+ generateImage?: (request: AdapterGenerateImageRequest) => Promise<ImageCompletion>;
50
+ produceVideo?: (request: AdapterVideoRequest) => Promise<VideoCompletion>;
51
+ generateModel?: (request: AdapterGenerateModelRequest) => Promise<ModelCompletion>;
52
+ checkBalance?: (request: AdapterBalanceRequest) => Promise<BalanceCompletion>;
53
+ }
54
+ export interface AdapterPlatformProps {
55
+ adapters: AICapabilityAdapter[];
56
+ apiKeys: Record<string, string>;
57
+ defaultAdapterByCapability?: Partial<Record<AICapability, string>>;
58
+ }
59
+ export declare function createAdapterPlatform(userId: string, props: AdapterPlatformProps): Promise<AIPlatform>;
60
+ //# sourceMappingURL=adapter-platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-platform.d.ts","sourceRoot":"","sources":["../../src/platform/adapter-platform.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAEnB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAmB,SAAQ,qBAAqB;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,8BAA+B,SAAQ,qBAAqB;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,8BAA+B,SAAQ,qBAAqB;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,2BAA4B,SAAQ,qBAAqB;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,GAAG,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,2BAA4B,SAAQ,qBAAqB;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;CAAG;AAEvE,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACzE,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACtE,gBAAgB,CAAC,EAAE,CACjB,OAAO,EAAE,8BAA8B,KACpC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CACjB,OAAO,EAAE,8BAA8B,KACpC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,2BAA2B,KACjC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC1E,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,2BAA2B,KACjC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;CACpE;AAyED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,UAAU,CAAC,CAoRrB"}
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAdapterPlatform = createAdapterPlatform;
4
+ const node_perf_hooks_1 = require("node:perf_hooks");
5
+ const index_js_1 = require("./index.js");
6
+ function createCompletionBase(type, model, requestor, durationMs) {
7
+ return {
8
+ partitionKey: requestor,
9
+ id: crypto.randomUUID(),
10
+ type,
11
+ model,
12
+ createdAt: new Date().toISOString(),
13
+ durationMs,
14
+ usage: {},
15
+ };
16
+ }
17
+ function createAdapterContext(requestorId, adapter, apiKey) {
18
+ return {
19
+ userId: requestorId,
20
+ providerId: adapter.id,
21
+ apiKey,
22
+ traceId: crypto.randomUUID(),
23
+ };
24
+ }
25
+ function requiresOperationalMethod(capability, adapter) {
26
+ switch (capability) {
27
+ case index_js_1.AICapability.Chat:
28
+ return typeof adapter.chatWithAI === "function";
29
+ case index_js_1.AICapability.Text:
30
+ return true;
31
+ case index_js_1.AICapability.Speech:
32
+ return (typeof adapter.synthesizeSpeech === "function" ||
33
+ typeof adapter.transcribeSpeech === "function");
34
+ case index_js_1.AICapability.Image:
35
+ return typeof adapter.generateImage === "function";
36
+ case index_js_1.AICapability.Video:
37
+ return typeof adapter.produceVideo === "function";
38
+ case index_js_1.AICapability.Balance:
39
+ return typeof adapter.checkBalance === "function";
40
+ case index_js_1.AICapability.Model:
41
+ return typeof adapter.generateModel === "function";
42
+ default:
43
+ return false;
44
+ }
45
+ }
46
+ async function createAdapterPlatform(userId, props) {
47
+ const adapterById = new Map();
48
+ for (const adapter of props.adapters) {
49
+ if (!adapter.id || adapter.id.trim().length === 0) {
50
+ throw new Error("Adapter id must be a non-empty string.");
51
+ }
52
+ if (adapterById.has(adapter.id)) {
53
+ throw new Error(`Duplicate adapter id "${adapter.id}" detected.`);
54
+ }
55
+ adapterById.set(adapter.id, adapter);
56
+ }
57
+ const resolveApiKey = (providerId) => {
58
+ const value = props.apiKeys[providerId];
59
+ if (typeof value !== "string") {
60
+ return undefined;
61
+ }
62
+ const trimmed = value.trim();
63
+ return trimmed.length > 0 ? trimmed : undefined;
64
+ };
65
+ const resolveAdapter = (capability, method, options) => {
66
+ const configuredId = props.defaultAdapterByCapability?.[capability];
67
+ const fail = (message) => {
68
+ if (options.required) {
69
+ throw new Error(message);
70
+ }
71
+ return undefined;
72
+ };
73
+ if (configuredId) {
74
+ const configured = adapterById.get(configuredId);
75
+ if (!configured) {
76
+ return fail(`Configured adapter "${configuredId}" for capability "${capability}" was not found.`);
77
+ }
78
+ if (!configured.capabilities.includes(capability)) {
79
+ return fail(`Configured adapter "${configuredId}" does not declare capability "${capability}".`);
80
+ }
81
+ if (typeof configured[method] !== "function") {
82
+ return fail(`Configured adapter "${configuredId}" does not implement "${method}" for capability "${capability}".`);
83
+ }
84
+ const apiKey = resolveApiKey(configured.id);
85
+ if (!apiKey) {
86
+ return fail(`Missing API key for configured adapter "${configured.id}".`);
87
+ }
88
+ return { adapter: configured, apiKey };
89
+ }
90
+ const fallback = props.adapters.find((candidate) => {
91
+ return (candidate.capabilities.includes(capability) &&
92
+ typeof candidate[method] === "function");
93
+ });
94
+ if (!fallback) {
95
+ return fail(`No adapter found for capability "${capability}" implementing "${method}".`);
96
+ }
97
+ const apiKey = resolveApiKey(fallback.id);
98
+ if (!apiKey) {
99
+ return fail(`Missing API key for adapter "${fallback.id}".`);
100
+ }
101
+ return { adapter: fallback, apiKey };
102
+ };
103
+ const canHandle = async (_requestorId, capabilities) => {
104
+ for (const capability of capabilities) {
105
+ const configuredId = props.defaultAdapterByCapability?.[capability];
106
+ const adapter = configuredId
107
+ ? adapterById.get(configuredId)
108
+ : props.adapters.find((candidate) => candidate.capabilities.includes(capability));
109
+ if (!adapter) {
110
+ return false;
111
+ }
112
+ if (!adapter.capabilities.includes(capability)) {
113
+ return false;
114
+ }
115
+ if (!resolveApiKey(adapter.id)) {
116
+ return false;
117
+ }
118
+ if (!requiresOperationalMethod(capability, adapter)) {
119
+ return false;
120
+ }
121
+ if (adapter.canHandle) {
122
+ const accepted = await adapter.canHandle([capability]);
123
+ if (!accepted) {
124
+ return false;
125
+ }
126
+ }
127
+ }
128
+ return true;
129
+ };
130
+ const chatWithAI = async (requestorId, input, context, model) => {
131
+ const resolved = resolveAdapter(index_js_1.AICapability.Chat, "chatWithAI", {
132
+ required: true,
133
+ });
134
+ return resolved.adapter.chatWithAI({
135
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
136
+ input,
137
+ context,
138
+ model,
139
+ });
140
+ };
141
+ const synthesizeSpeech = async (requestorId, input, voice, context, model) => {
142
+ const resolved = resolveAdapter(index_js_1.AICapability.Speech, "synthesizeSpeech", {
143
+ required: true,
144
+ });
145
+ return resolved.adapter.synthesizeSpeech({
146
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
147
+ input,
148
+ voice,
149
+ context,
150
+ model,
151
+ });
152
+ };
153
+ const transcribeSpeech = async (requestorId, input, context, model) => {
154
+ const resolved = resolveAdapter(index_js_1.AICapability.Speech, "transcribeSpeech", {
155
+ required: true,
156
+ });
157
+ return resolved.adapter.transcribeSpeech({
158
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
159
+ input,
160
+ context,
161
+ model,
162
+ });
163
+ };
164
+ const generateImage = async (requestorId, input, context, model) => {
165
+ const resolved = resolveAdapter(index_js_1.AICapability.Image, "generateImage", {
166
+ required: true,
167
+ });
168
+ return resolved.adapter.generateImage({
169
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
170
+ input,
171
+ context,
172
+ model,
173
+ });
174
+ };
175
+ const produceVideo = async (requestorId, input, image, context, model) => {
176
+ const resolved = resolveAdapter(index_js_1.AICapability.Video, "produceVideo", {
177
+ required: true,
178
+ });
179
+ return resolved.adapter.produceVideo({
180
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
181
+ input,
182
+ image,
183
+ context,
184
+ model,
185
+ });
186
+ };
187
+ const generateModel = async (requestorId, input, context, model) => {
188
+ const resolved = resolveAdapter(index_js_1.AICapability.Model, "generateModel", {
189
+ required: true,
190
+ });
191
+ return resolved.adapter.generateModel({
192
+ ...createAdapterContext(requestorId, resolved.adapter, resolved.apiKey),
193
+ input,
194
+ context,
195
+ model,
196
+ });
197
+ };
198
+ const checkBalance = async (requestorId) => {
199
+ const startedAt = node_perf_hooks_1.performance.now();
200
+ const resolved = resolveAdapter(index_js_1.AICapability.Balance, "checkBalance", {
201
+ required: false,
202
+ });
203
+ if (!resolved || !resolved.adapter.checkBalance) {
204
+ const durationMs = node_perf_hooks_1.performance.now() - startedAt;
205
+ const base = createCompletionBase("balanceCompletion", "", requestorId, durationMs);
206
+ return {
207
+ ...base,
208
+ balance: 0,
209
+ };
210
+ }
211
+ return resolved.adapter.checkBalance(createAdapterContext(requestorId, resolved.adapter, resolved.apiKey));
212
+ };
213
+ const currentBalance = (await checkBalance(userId)).balance;
214
+ return {
215
+ canHandle,
216
+ chatWithAI,
217
+ synthesizeSpeech,
218
+ transcribeSpeech,
219
+ generateImage,
220
+ produceVideo,
221
+ generateModel,
222
+ checkBalance,
223
+ currentBalance,
224
+ };
225
+ }
@@ -0,0 +1,15 @@
1
+ import { type AICapabilityAdapter } from "./index.js";
2
+ import { type HttpClientPolicy } from "./http-resilience.js";
3
+ export interface GeminiAdapterOptions {
4
+ id?: string;
5
+ baseUrl?: string;
6
+ fetchFn?: typeof fetch;
7
+ httpPolicy?: HttpClientPolicy;
8
+ defaultModels?: {
9
+ chat?: string;
10
+ image?: string;
11
+ model?: string;
12
+ };
13
+ }
14
+ export declare function createGeminiAdapter(options?: GeminiAdapterOptions): AICapabilityAdapter;
15
+ //# sourceMappingURL=gemini-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-adapter.d.ts","sourceRoot":"","sources":["../../src/platform/gemini-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,mBAAmB,EAKzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE9E,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAkLD,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CAyLrB"}