@uploadista/flow-images-replicate 0.0.3

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.
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @uploadista/flow-images-replicate@0.0.2 build /Users/denislaboureyras/Documents/uploadista/dev/uploadista-workspace/uploadista-sdk/packages/flow/images/replicate
4
+ > tsc -b
5
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 uploadista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,236 @@
1
+ # @uploadista/flow-images-replicate
2
+
3
+ AI-powered image operations for Uploadista flows. Use Replicate's ML models for advanced image manipulation.
4
+
5
+ ## Overview
6
+
7
+ Replicate integration enables AI image operations:
8
+
9
+ - **Background Removal**: AI-powered background removal
10
+ - **Upscaling**: Enhance image resolution
11
+ - **Style Transfer**: Apply artistic styles
12
+ - **Custom Models**: Use any Replicate model
13
+ - **Serverless**: No GPU infrastructure needed
14
+
15
+ Perfect for advanced image processing workflows.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @uploadista/flow-images-replicate
21
+ # or
22
+ pnpm add @uploadista/flow-images-replicate
23
+ ```
24
+
25
+ ### Prerequisites
26
+
27
+ - Replicate API token (get from replicate.com)
28
+ - Node.js 18+
29
+
30
+ ## Quick Start
31
+
32
+ ```typescript
33
+ import { imageAiPlugin } from "@uploadista/flow-images-replicate";
34
+
35
+ const flow = {
36
+ nodes: [
37
+ { id: "input", type: "input" },
38
+ {
39
+ id: "remove-bg",
40
+ type: "background-removal",
41
+ params: { model: "rembg" },
42
+ },
43
+ { id: "s3", type: "s3" },
44
+ { id: "output", type: "output" },
45
+ ],
46
+ };
47
+ ```
48
+
49
+ ## Features
50
+
51
+ - ✅ **AI Models**: Background removal, upscaling, effects
52
+ - ✅ **No GPU Needed**: Replicate handles compute
53
+ - ✅ **Serverless**: Pay per request
54
+ - ✅ **Webhook Support**: Async processing
55
+ - ✅ **Custom Models**: Use any Replicate model
56
+
57
+ ## Node Types
58
+
59
+ ### Background Removal
60
+
61
+ ```typescript
62
+ {
63
+ type: "remove-background",
64
+ params: {
65
+ model: "rembg", // AI model
66
+ returnFormat: "png",
67
+ },
68
+ }
69
+ ```
70
+
71
+ ### Upscaling
72
+
73
+ ```typescript
74
+ {
75
+ type: "upscale",
76
+ params: {
77
+ scale: 4, // 2x, 4x upscaling
78
+ model: "real-esrgan",
79
+ },
80
+ }
81
+ ```
82
+
83
+ ### Style Transfer
84
+
85
+ ```typescript
86
+ {
87
+ type: "style-transfer",
88
+ params: {
89
+ style: "oil-painting",
90
+ model: "arbitrary-style-transfer",
91
+ },
92
+ }
93
+ ```
94
+
95
+ ## Configuration
96
+
97
+ Set API token:
98
+
99
+ ```typescript
100
+ export const config = {
101
+ replicate: {
102
+ apiToken: process.env.REPLICATE_API_TOKEN,
103
+ },
104
+ };
105
+ ```
106
+
107
+ ## Use Cases
108
+
109
+ - Remove backgrounds from product photos
110
+ - Upscale low-resolution images
111
+ - Apply artistic effects
112
+ - Custom ML image processing
113
+ - Batch AI operations
114
+
115
+ ## Examples
116
+
117
+ ### Product Image Processing
118
+
119
+ ```typescript
120
+ const productFlow = {
121
+ nodes: [
122
+ { id: "input", type: "input" },
123
+ {
124
+ id: "remove-bg",
125
+ type: "remove-background",
126
+ params: { model: "rembg" },
127
+ },
128
+ {
129
+ id: "upscale",
130
+ type: "upscale",
131
+ params: { scale: 2, model: "real-esrgan" },
132
+ },
133
+ { id: "s3", type: "s3", params: { bucket: "products" } },
134
+ { id: "output", type: "output" },
135
+ ],
136
+ edges: [
137
+ { from: "input", to: "remove-bg" },
138
+ { from: "remove-bg", to: "upscale" },
139
+ { from: "upscale", to: "s3" },
140
+ { from: "s3", to: "output" },
141
+ ],
142
+ };
143
+ ```
144
+
145
+ ### Creative Effects
146
+
147
+ ```typescript
148
+ const creativeFlow = {
149
+ nodes: [
150
+ { id: "input", type: "input" },
151
+ {
152
+ id: "style",
153
+ type: "style-transfer",
154
+ params: {
155
+ style: "oil-painting",
156
+ model: "arbitrary-style-transfer",
157
+ },
158
+ },
159
+ { id: "upscale", type: "upscale", params: { scale: 2 } },
160
+ { id: "s3", type: "s3" },
161
+ { id: "output", type: "output" },
162
+ ],
163
+ };
164
+ ```
165
+
166
+ ## Performance
167
+
168
+ | Operation | Time |
169
+ |-----------|------|
170
+ | Background removal | 5-15s |
171
+ | Upscaling (2x) | 10-20s |
172
+ | Style transfer | 15-30s |
173
+ | Async webhook | Variable |
174
+
175
+ All operations asynchronous via webhook.
176
+
177
+ ## Cost
178
+
179
+ Replicate pricing (varies by model):
180
+ - Background removal: ~$0.001-0.002 per image
181
+ - Upscaling: ~$0.01-0.05 per image
182
+ - Style transfer: ~$0.02-0.10 per image
183
+
184
+ ## Best Practices
185
+
186
+ ### 1. Async Processing
187
+
188
+ ```typescript
189
+ // Use webhooks for long-running AI ops
190
+ {
191
+ type: "remove-background",
192
+ params: {
193
+ model: "rembg",
194
+ webhook: "https://yourapi.com/callbacks",
195
+ async: true,
196
+ },
197
+ }
198
+ ```
199
+
200
+ ### 2. Batch Operations
201
+
202
+ ```typescript
203
+ // Process multiple images in parallel
204
+ const batch = [image1, image2, image3];
205
+ const results = yield* Effect.all(
206
+ batch.map((img) => removeBackground(img))
207
+ );
208
+ ```
209
+
210
+ ### 3. Error Handling
211
+
212
+ ```typescript
213
+ // AI models may fail or timeout
214
+ yield* removeBackground(image).pipe(
215
+ Effect.catch((error) => {
216
+ // Fallback to standard processing
217
+ return standardBackgroundRemoval(image);
218
+ })
219
+ );
220
+ ```
221
+
222
+ ## Related Packages
223
+
224
+ - [@uploadista/flow-images-nodes](../nodes) - Base types
225
+ - [@uploadista/flow-images-sharp](../sharp) - Standard processing
226
+ - [@uploadista/server](../../servers/server) - Upload server
227
+
228
+ ## License
229
+
230
+ See [LICENSE](../../../LICENSE) in the main repository.
231
+
232
+ ## See Also
233
+
234
+ - [Replicate Documentation](https://replicate.com/docs) - Replicate API
235
+ - [FLOW_NODES.md](../FLOW_NODES.md) - All available nodes
236
+ - [Replicate Models](https://replicate.com/explore) - Available AI models
@@ -0,0 +1,42 @@
1
+ import { UploadistaError } from "@uploadista/core/errors";
2
+ import { type ImageAiContext, ImageAiPlugin } from "@uploadista/core/flow";
3
+ import { Effect, Layer } from "effect";
4
+ type ModelId = `${string}/${string}` | `${string}/${string}:${string}`;
5
+ type ReplicateCredentials = {
6
+ apiKey: string;
7
+ };
8
+ type CredentialProvider = (context: ImageAiContext & {
9
+ serviceType: "replicate";
10
+ }) => Effect.Effect<ReplicateCredentials, UploadistaError>;
11
+ type PluginConfig = string | {
12
+ credentialProvider?: CredentialProvider;
13
+ useCredentialProviderService?: boolean;
14
+ removeBackgroundModelId?: ModelId;
15
+ describeImageModelId?: ModelId;
16
+ };
17
+ /**
18
+ * Create the Replicate ImageAI plugin
19
+ * Supports both static credentials (OSS) and dynamic credential providers (SaaS)
20
+ *
21
+ * @example
22
+ * // Static credentials (OSS)
23
+ * imageAiPlugin(process.env.REPLICATE_API_TOKEN)
24
+ *
25
+ * @example
26
+ * // Dynamic credentials with function (SaaS)
27
+ * imageAiPlugin({
28
+ * credentialProvider: (context) => Effect.succeed({ apiKey: "..." })
29
+ * })
30
+ *
31
+ * @example
32
+ * // Dynamic credentials with Effect service (SaaS)
33
+ * imageAiPlugin({
34
+ * useCredentialProviderService: true
35
+ * })
36
+ */
37
+ export declare const imageAiPlugin: (config: PluginConfig, options?: {
38
+ removeBackgroundModelId?: ModelId;
39
+ describeImageModelId?: ModelId;
40
+ }) => Layer.Layer<ImageAiPlugin, never, never>;
41
+ export {};
42
+ //# sourceMappingURL=image-ai-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-ai-plugin.d.ts","sourceRoot":"","sources":["../src/image-ai-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAEL,KAAK,cAAc,EACnB,aAAa,EACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAG/C,KAAK,OAAO,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,GAAG,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;AAMvE,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,KAAK,kBAAkB,GAAG,CACxB,OAAO,EAAE,cAAc,GAAG;IAAE,WAAW,EAAE,WAAW,CAAA;CAAE,KACnD,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;AAG1D,KAAK,YAAY,GACb,MAAM,GACN;IACE,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEN;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,YAAY,EACpB,UAAU;IACR,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,6CAuJF,CAAC"}
@@ -0,0 +1,147 @@
1
+ import { UploadistaError } from "@uploadista/core/errors";
2
+ import { CredentialProvider as CredentialProviderService, ImageAiPlugin, } from "@uploadista/core/flow";
3
+ import { Effect, Layer, Option } from "effect";
4
+ import Replicate from "replicate";
5
+ /**
6
+ * Create the Replicate ImageAI plugin
7
+ * Supports both static credentials (OSS) and dynamic credential providers (SaaS)
8
+ *
9
+ * @example
10
+ * // Static credentials (OSS)
11
+ * imageAiPlugin(process.env.REPLICATE_API_TOKEN)
12
+ *
13
+ * @example
14
+ * // Dynamic credentials with function (SaaS)
15
+ * imageAiPlugin({
16
+ * credentialProvider: (context) => Effect.succeed({ apiKey: "..." })
17
+ * })
18
+ *
19
+ * @example
20
+ * // Dynamic credentials with Effect service (SaaS)
21
+ * imageAiPlugin({
22
+ * useCredentialProviderService: true
23
+ * })
24
+ */
25
+ export const imageAiPlugin = (config, options) => {
26
+ // Parse configuration
27
+ const isStatic = typeof config === "string";
28
+ const staticApiKey = isStatic ? config : null;
29
+ const credentialProvider = isStatic ? null : config.credentialProvider;
30
+ const useCredentialProviderService = isStatic
31
+ ? false
32
+ : config.useCredentialProviderService;
33
+ // Model IDs can come from either the config object or the options parameter
34
+ const removeBackgroundModelId = (isStatic
35
+ ? options?.removeBackgroundModelId
36
+ : config.removeBackgroundModelId) ||
37
+ "lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1";
38
+ const describeImageModelId = (isStatic ? options?.describeImageModelId : config.describeImageModelId) ||
39
+ "zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1";
40
+ // Helper to get API token (either static, from provider function, or from service)
41
+ const getApiToken = (context) => {
42
+ if (staticApiKey) {
43
+ return Effect.succeed(staticApiKey);
44
+ }
45
+ if (useCredentialProviderService) {
46
+ return Effect.gen(function* () {
47
+ const credentialProviderService = yield* Effect.serviceOption(CredentialProviderService);
48
+ if (Option.isNone(credentialProviderService)) {
49
+ return yield* Effect.fail(UploadistaError.fromCode("UNKNOWN_ERROR", {
50
+ cause: new Error("Credential provider service not found"),
51
+ }));
52
+ }
53
+ else {
54
+ const credentials = yield* credentialProviderService.value.getCredential({
55
+ clientId: context.clientId,
56
+ serviceType: "replicate",
57
+ });
58
+ if (typeof credentials === "object" &&
59
+ credentials !== null &&
60
+ "apiKey" in credentials &&
61
+ typeof credentials.apiKey === "string") {
62
+ return credentials.apiKey;
63
+ }
64
+ }
65
+ return yield* Effect.fail(UploadistaError.fromCode("UNKNOWN_ERROR", {
66
+ cause: new Error("Invalid credential format from service"),
67
+ }));
68
+ });
69
+ }
70
+ if (credentialProvider) {
71
+ return Effect.gen(function* () {
72
+ const credentials = yield* credentialProvider({
73
+ ...context,
74
+ serviceType: "replicate",
75
+ });
76
+ return credentials.apiKey;
77
+ });
78
+ }
79
+ return Effect.fail(UploadistaError.fromCode("UNKNOWN_ERROR", {
80
+ cause: new Error("No API credentials configured"),
81
+ }));
82
+ };
83
+ return Layer.succeed(ImageAiPlugin, ImageAiPlugin.of({
84
+ removeBackground: (inputUrl, context) => {
85
+ return Effect.gen(function* () {
86
+ // Get API token (static or from credential provider)
87
+ const apiToken = yield* getApiToken(context);
88
+ const output = yield* Effect.tryPromise({
89
+ try: async () => {
90
+ const replicate = new Replicate({
91
+ auth: apiToken,
92
+ });
93
+ const input = {
94
+ image: inputUrl,
95
+ };
96
+ console.log("input", input);
97
+ return (await replicate.run(removeBackgroundModelId, {
98
+ input,
99
+ }));
100
+ },
101
+ catch: (error) => {
102
+ console.log("error", error);
103
+ return UploadistaError.fromCode("UNKNOWN_ERROR", {
104
+ cause: error,
105
+ });
106
+ },
107
+ });
108
+ return { outputUrl: output.url() };
109
+ });
110
+ },
111
+ describeImage: (inputUrl, context) => {
112
+ return Effect.gen(function* () {
113
+ // Get API token (static or from credential provider)
114
+ const apiToken = yield* getApiToken(context);
115
+ const output = yield* Effect.tryPromise({
116
+ try: async () => {
117
+ const replicate = new Replicate({
118
+ auth: apiToken,
119
+ });
120
+ return (await replicate.run(describeImageModelId, {
121
+ input: {
122
+ image: inputUrl,
123
+ top_k: 50,
124
+ top_p: 1,
125
+ caption: false,
126
+ question: "What is shown in the image?",
127
+ do_sample: false,
128
+ num_beams: 1,
129
+ temperature: 1,
130
+ system_prompt: "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.",
131
+ length_penalty: 1,
132
+ max_new_tokens: 768,
133
+ repetition_penalty: 1,
134
+ },
135
+ }));
136
+ },
137
+ catch: (error) => {
138
+ return UploadistaError.fromCode("UNKNOWN_ERROR", {
139
+ cause: error,
140
+ });
141
+ },
142
+ });
143
+ return { description: output };
144
+ });
145
+ },
146
+ }));
147
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./image-ai-plugin";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./image-ai-plugin";
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@uploadista/flow-images-replicate",
3
+ "type": "module",
4
+ "version": "0.0.3",
5
+ "description": "Replicate image AI processing service for Uploadista Flow",
6
+ "license": "MIT",
7
+ "author": "Uploadista",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "dependencies": {
16
+ "replicate": "1.3.0",
17
+ "effect": "3.18.4",
18
+ "zod": "4.1.12",
19
+ "@uploadista/core": "0.0.3"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "24.8.1",
23
+ "@uploadista/typescript-config": "0.0.3"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -b",
27
+ "format": "biome format --write ./src",
28
+ "lint": "biome lint --write ./src",
29
+ "check": "biome check --write ./src"
30
+ }
31
+ }
@@ -0,0 +1,211 @@
1
+ import { UploadistaError } from "@uploadista/core/errors";
2
+ import {
3
+ CredentialProvider as CredentialProviderService,
4
+ type ImageAiContext,
5
+ ImageAiPlugin,
6
+ } from "@uploadista/core/flow";
7
+ import { Effect, Layer, Option } from "effect";
8
+ import Replicate from "replicate";
9
+
10
+ type ModelId = `${string}/${string}` | `${string}/${string}:${string}`;
11
+
12
+ type RemoveBackgroundOutput = {
13
+ url: () => string;
14
+ };
15
+
16
+ type ReplicateCredentials = {
17
+ apiKey: string;
18
+ };
19
+
20
+ // Credential provider function type
21
+ type CredentialProvider = (
22
+ context: ImageAiContext & { serviceType: "replicate" },
23
+ ) => Effect.Effect<ReplicateCredentials, UploadistaError>;
24
+
25
+ // Plugin configuration can be either a static API key or options with credential provider or service
26
+ type PluginConfig =
27
+ | string
28
+ | {
29
+ credentialProvider?: CredentialProvider;
30
+ useCredentialProviderService?: boolean;
31
+ removeBackgroundModelId?: ModelId;
32
+ describeImageModelId?: ModelId;
33
+ };
34
+
35
+ /**
36
+ * Create the Replicate ImageAI plugin
37
+ * Supports both static credentials (OSS) and dynamic credential providers (SaaS)
38
+ *
39
+ * @example
40
+ * // Static credentials (OSS)
41
+ * imageAiPlugin(process.env.REPLICATE_API_TOKEN)
42
+ *
43
+ * @example
44
+ * // Dynamic credentials with function (SaaS)
45
+ * imageAiPlugin({
46
+ * credentialProvider: (context) => Effect.succeed({ apiKey: "..." })
47
+ * })
48
+ *
49
+ * @example
50
+ * // Dynamic credentials with Effect service (SaaS)
51
+ * imageAiPlugin({
52
+ * useCredentialProviderService: true
53
+ * })
54
+ */
55
+ export const imageAiPlugin = (
56
+ config: PluginConfig,
57
+ options?: {
58
+ removeBackgroundModelId?: ModelId;
59
+ describeImageModelId?: ModelId;
60
+ },
61
+ ) => {
62
+ // Parse configuration
63
+ const isStatic = typeof config === "string";
64
+ const staticApiKey = isStatic ? config : null;
65
+ const credentialProvider = isStatic ? null : config.credentialProvider;
66
+ const useCredentialProviderService = isStatic
67
+ ? false
68
+ : config.useCredentialProviderService;
69
+
70
+ // Model IDs can come from either the config object or the options parameter
71
+ const removeBackgroundModelId =
72
+ (isStatic
73
+ ? options?.removeBackgroundModelId
74
+ : config.removeBackgroundModelId) ||
75
+ "lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1";
76
+ const describeImageModelId =
77
+ (isStatic ? options?.describeImageModelId : config.describeImageModelId) ||
78
+ "zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1";
79
+
80
+ // Helper to get API token (either static, from provider function, or from service)
81
+ const getApiToken = (context: ImageAiContext) => {
82
+ if (staticApiKey) {
83
+ return Effect.succeed(staticApiKey);
84
+ }
85
+ if (useCredentialProviderService) {
86
+ return Effect.gen(function* () {
87
+ const credentialProviderService = yield* Effect.serviceOption(
88
+ CredentialProviderService,
89
+ );
90
+
91
+ if (Option.isNone(credentialProviderService)) {
92
+ return yield* Effect.fail(
93
+ UploadistaError.fromCode("UNKNOWN_ERROR", {
94
+ cause: new Error("Credential provider service not found"),
95
+ }),
96
+ );
97
+ } else {
98
+ const credentials =
99
+ yield* credentialProviderService.value.getCredential({
100
+ clientId: context.clientId,
101
+ serviceType: "replicate",
102
+ });
103
+
104
+ if (
105
+ typeof credentials === "object" &&
106
+ credentials !== null &&
107
+ "apiKey" in credentials &&
108
+ typeof credentials.apiKey === "string"
109
+ ) {
110
+ return credentials.apiKey;
111
+ }
112
+ }
113
+
114
+ return yield* Effect.fail(
115
+ UploadistaError.fromCode("UNKNOWN_ERROR", {
116
+ cause: new Error("Invalid credential format from service"),
117
+ }),
118
+ );
119
+ });
120
+ }
121
+ if (credentialProvider) {
122
+ return Effect.gen(function* () {
123
+ const credentials = yield* credentialProvider({
124
+ ...context,
125
+ serviceType: "replicate",
126
+ });
127
+ return credentials.apiKey;
128
+ });
129
+ }
130
+ return Effect.fail(
131
+ UploadistaError.fromCode("UNKNOWN_ERROR", {
132
+ cause: new Error("No API credentials configured"),
133
+ }),
134
+ );
135
+ };
136
+
137
+ return Layer.succeed(
138
+ ImageAiPlugin,
139
+ ImageAiPlugin.of({
140
+ removeBackground: (inputUrl, context) => {
141
+ return Effect.gen(function* () {
142
+ // Get API token (static or from credential provider)
143
+ const apiToken = yield* getApiToken(context);
144
+
145
+ const output = yield* Effect.tryPromise({
146
+ try: async () => {
147
+ const replicate = new Replicate({
148
+ auth: apiToken,
149
+ });
150
+
151
+ const input = {
152
+ image: inputUrl,
153
+ };
154
+
155
+ console.log("input", input);
156
+
157
+ return (await replicate.run(removeBackgroundModelId, {
158
+ input,
159
+ })) as RemoveBackgroundOutput;
160
+ },
161
+ catch: (error) => {
162
+ console.log("error", error);
163
+ return UploadistaError.fromCode("UNKNOWN_ERROR", {
164
+ cause: error,
165
+ });
166
+ },
167
+ });
168
+ return { outputUrl: output.url() };
169
+ });
170
+ },
171
+ describeImage: (inputUrl, context) => {
172
+ return Effect.gen(function* () {
173
+ // Get API token (static or from credential provider)
174
+ const apiToken = yield* getApiToken(context);
175
+
176
+ const output = yield* Effect.tryPromise({
177
+ try: async () => {
178
+ const replicate = new Replicate({
179
+ auth: apiToken,
180
+ });
181
+
182
+ return (await replicate.run(describeImageModelId, {
183
+ input: {
184
+ image: inputUrl,
185
+ top_k: 50,
186
+ top_p: 1,
187
+ caption: false,
188
+ question: "What is shown in the image?",
189
+ do_sample: false,
190
+ num_beams: 1,
191
+ temperature: 1,
192
+ system_prompt:
193
+ "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.",
194
+ length_penalty: 1,
195
+ max_new_tokens: 768,
196
+ repetition_penalty: 1,
197
+ },
198
+ })) as unknown as string;
199
+ },
200
+ catch: (error) => {
201
+ return UploadistaError.fromCode("UNKNOWN_ERROR", {
202
+ cause: error,
203
+ });
204
+ },
205
+ });
206
+ return { description: output };
207
+ });
208
+ },
209
+ }),
210
+ );
211
+ };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./image-ai-plugin";
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "@uploadista/typescript-config/server.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "./",
5
+ "paths": {
6
+ "@/*": ["./src/*"]
7
+ },
8
+ "outDir": "./dist",
9
+ "rootDir": "./src",
10
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
11
+ "types": []
12
+ },
13
+ "include": ["src"]
14
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/image-ai-plugin.ts","./src/index.ts"],"version":"5.9.3"}