@uploadista/flow-images-replicate 0.1.2 → 0.1.3-beta.11
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/dist/index.cjs +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
- package/src/image-ai-plugin.ts +51 -2
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`@uploadista/core/errors`),l=require(`@uploadista/core/flow`),u=require(`@uploadista/observability`),d=require(`effect`),f=require(`replicate`);f=s(f);const p=(e,t)=>{let n=typeof e==`string`,r=n?e:null,i=n?null:e.credentialProvider,a=n?!1:e.useCredentialProviderService,o=(n?t?.removeBackgroundModelId:e.removeBackgroundModelId)||`lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1`,s=(n?t?.describeImageModelId:e.describeImageModelId)||`zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1`,
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`@uploadista/core/errors`),l=require(`@uploadista/core/flow`),u=require(`@uploadista/observability`),d=require(`effect`),f=require(`replicate`);f=s(f);const p=(e,t)=>{let n=typeof e==`string`,r=n?e:null,i=n?null:e.credentialProvider,a=n?!1:e.useCredentialProviderService,o=(n?t?.removeBackgroundModelId:e.removeBackgroundModelId)||`lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1`,s=(n?t?.describeImageModelId:e.describeImageModelId)||`zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1`,f=e=>r?d.Effect.succeed(r):a?d.Effect.gen(function*(){let t=yield*d.Effect.serviceOption(l.CredentialProvider);if(d.Option.isNone(t))return yield*d.Effect.fail(c.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:Error(`Credential provider service not found`)}));{let n=yield*t.value.getCredential({clientId:e.clientId,serviceType:`replicate`});if(typeof n==`object`&&n&&`apiKey`in n&&typeof n.apiKey==`string`)return n.apiKey}return yield*d.Effect.fail(c.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:Error(`Invalid credential format from service`)}))}):i?d.Effect.gen(function*(){return(yield*i({...e,serviceType:`replicate`})).apiKey}):d.Effect.fail(c.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:Error(`No API credentials configured`)}));return d.Layer.succeed(l.ImageAiPlugin,l.ImageAiPlugin.of({removeBackground:(e,t)=>d.Effect.gen(function*(){let n=yield*f(t);return{outputUrl:(yield*d.Effect.tryPromise({try:async()=>{let t=new t.default({auth:n}),r={image:e};return console.log(`input`,r),await t.run(o,{input:r})},catch:e=>(console.log(`error`,e),c.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:e}))})).url()}}).pipe((0,u.withOperationSpan)(`ai`,`remove-background`,{"ai.provider":`replicate`,"ai.model":o,"ai.client_id":t.clientId})),describeImage:(e,t)=>d.Effect.gen(function*(){let n=yield*f(t);return yield*d.Effect.logInfo(`[Replicate describeImage] Starting with URL: ${e}`),{description:yield*d.Effect.tryPromise({try:async()=>{let t=new t.default({auth:n});console.log(`[Replicate describeImage] Calling Replicate API with model:`,s);let r=await t.run(s,{input:{image:e,top_k:50,top_p:1,caption:!1,question:`What is shown in the image?`,do_sample:!1,num_beams:1,temperature:1,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.`,length_penalty:1,max_new_tokens:768,repetition_penalty:1}});console.log(`[Replicate describeImage] Raw result type:`,typeof r),console.log(`[Replicate describeImage] Raw result:`,JSON.stringify(r,null,2));let i;if(typeof r==`string`)i=r;else if(Array.isArray(r)&&r.length>0)i=typeof r[0]==`string`?r[0]:String(r[0]);else if(r!=null)console.log(`[Replicate describeImage] Fallback: result is not string or array, stringifying`),i=String(r);else throw console.error(`[Replicate describeImage] ERROR: result is null or undefined`),Error(`Replicate returned empty or undefined response for image description. Result was: ${r}`);return console.log(`[Replicate describeImage] Final description:`,i.substring(0,100)),i},catch:e=>(console.error(`[Replicate describeImage] Caught error:`,e),c.UploadistaError.fromCode(`UNKNOWN_ERROR`,{cause:e}))})}}).pipe((0,u.withOperationSpan)(`ai`,`describe-image`,{"ai.provider":`replicate`,"ai.model":s,"ai.client_id":t.clientId}))}))};exports.imageAiPlugin=p;
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/image-ai-plugin.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/image-ai-plugin.ts"],"mappings":";;;;;KAUK,OAAA;AAAA,KAMA,oBAAA;EACH,MAAA;AAAA;AAAA,KAIG,kBAAA,IACH,OAAA,EAAS,cAAA;EAAmB,WAAA;AAAA,MACzB,MAAA,CAAO,MAAA,CAAO,oBAAA,EAAsB,eAAA;AAAA,KAGpC,YAAA;EAGC,kBAAA,GAAqB,kBAAA;EACrB,4BAAA;EACA,uBAAA,GAA0B,OAAA;EAC1B,oBAAA,GAAuB,OAAA;AAAA;;;;;;;;;;;;;;;;;;AAT2B;;;cAgC3C,aAAA,GACX,MAAA,EAAQ,YAAA,EACR,OAAA;EACE,uBAAA,GAA0B,OAAA;EAC1B,oBAAA,GAAuB,OAAA;AAAA,MACxB,KAAA,CAAA,KAAA,CAAA,aAAA"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/image-ai-plugin.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/image-ai-plugin.ts"],"mappings":";;;;;KAUK,OAAA;AAAA,KAMA,oBAAA;EACH,MAAA;AAAA;AAAA,KAIG,oBAAA,IACH,OAAA,EAAS,cAAA;EAAmB,WAAA;AAAA,MACzB,MAAA,CAAO,MAAA,CAAO,oBAAA,EAAsB,eAAA;AAAA,KAGpC,YAAA;EAGC,kBAAA,GAAqB,oBAAA;EACrB,4BAAA;EACA,uBAAA,GAA0B,OAAA;EAC1B,oBAAA,GAAuB,OAAA;AAAA;;;;;;;;;;;;;;;;;;AAT2B;;;cAgC3C,aAAA,GACX,MAAA,EAAQ,YAAA,EACR,OAAA;EACE,uBAAA,GAA0B,OAAA;EAC1B,oBAAA,GAAuB,OAAA;AAAA,MACxB,KAAA,CAAA,KAAA,CAAA,aAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{UploadistaError as e}from"@uploadista/core/errors";import{CredentialProvider as t,ImageAiPlugin as n}from"@uploadista/core/flow";import{withOperationSpan as r}from"@uploadista/observability";import{Effect as i,Layer as a,Option as o}from"effect";import s from"replicate";const c=(c,l)=>{let u=typeof c==`string`,d=u?c:null,f=u?null:c.credentialProvider,p=u?!1:c.useCredentialProviderService,m=(u?l?.removeBackgroundModelId:c.removeBackgroundModelId)||`lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1`,h=(u?l?.describeImageModelId:c.describeImageModelId)||`zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1`,g=n=>d?i.succeed(d):p?i.gen(function*(){let r=yield*i.serviceOption(t);if(o.isNone(r))return yield*i.fail(e.fromCode(`UNKNOWN_ERROR`,{cause:Error(`Credential provider service not found`)}));{let e=yield*r.value.getCredential({clientId:n.clientId,serviceType:`replicate`});if(typeof e==`object`&&e&&`apiKey`in e&&typeof e.apiKey==`string`)return e.apiKey}return yield*i.fail(e.fromCode(`UNKNOWN_ERROR`,{cause:Error(`Invalid credential format from service`)}))}):f?i.gen(function*(){return(yield*f({...n,serviceType:`replicate`})).apiKey}):i.fail(e.fromCode(`UNKNOWN_ERROR`,{cause:Error(`No API credentials configured`)}));return a.succeed(n,n.of({removeBackground:(t,n)=>i.gen(function*(){let r=yield*g(n);return{outputUrl:(yield*i.tryPromise({try:async()=>{let e=new s({auth:r}),n={image:t};return console.log(`input`,n),await e.run(m,{input:n})},catch:t=>(console.log(`error`,t),e.fromCode(`UNKNOWN_ERROR`,{cause:t}))})).url()}}).pipe(r(`ai`,`remove-background`,{"ai.provider":`replicate`,"ai.model":m,"ai.client_id":n.clientId})),describeImage:(t,n)=>i.gen(function*(){let r=yield*g(n);return{description:yield*i.tryPromise({try:async()=>
|
|
1
|
+
import{UploadistaError as e}from"@uploadista/core/errors";import{CredentialProvider as t,ImageAiPlugin as n}from"@uploadista/core/flow";import{withOperationSpan as r}from"@uploadista/observability";import{Effect as i,Layer as a,Option as o}from"effect";import s from"replicate";const c=(c,l)=>{let u=typeof c==`string`,d=u?c:null,f=u?null:c.credentialProvider,p=u?!1:c.useCredentialProviderService,m=(u?l?.removeBackgroundModelId:c.removeBackgroundModelId)||`lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1`,h=(u?l?.describeImageModelId:c.describeImageModelId)||`zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1`,g=n=>d?i.succeed(d):p?i.gen(function*(){let r=yield*i.serviceOption(t);if(o.isNone(r))return yield*i.fail(e.fromCode(`UNKNOWN_ERROR`,{cause:Error(`Credential provider service not found`)}));{let e=yield*r.value.getCredential({clientId:n.clientId,serviceType:`replicate`});if(typeof e==`object`&&e&&`apiKey`in e&&typeof e.apiKey==`string`)return e.apiKey}return yield*i.fail(e.fromCode(`UNKNOWN_ERROR`,{cause:Error(`Invalid credential format from service`)}))}):f?i.gen(function*(){return(yield*f({...n,serviceType:`replicate`})).apiKey}):i.fail(e.fromCode(`UNKNOWN_ERROR`,{cause:Error(`No API credentials configured`)}));return a.succeed(n,n.of({removeBackground:(t,n)=>i.gen(function*(){let r=yield*g(n);return{outputUrl:(yield*i.tryPromise({try:async()=>{let e=new s({auth:r}),n={image:t};return console.log(`input`,n),await e.run(m,{input:n})},catch:t=>(console.log(`error`,t),e.fromCode(`UNKNOWN_ERROR`,{cause:t}))})).url()}}).pipe(r(`ai`,`remove-background`,{"ai.provider":`replicate`,"ai.model":m,"ai.client_id":n.clientId})),describeImage:(t,n)=>i.gen(function*(){let r=yield*g(n);return yield*i.logInfo(`[Replicate describeImage] Starting with URL: ${t}`),{description:yield*i.tryPromise({try:async()=>{let e=new s({auth:r});console.log(`[Replicate describeImage] Calling Replicate API with model:`,h);let n=await e.run(h,{input:{image:t,top_k:50,top_p:1,caption:!1,question:`What is shown in the image?`,do_sample:!1,num_beams:1,temperature:1,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.`,length_penalty:1,max_new_tokens:768,repetition_penalty:1}});console.log(`[Replicate describeImage] Raw result type:`,typeof n),console.log(`[Replicate describeImage] Raw result:`,JSON.stringify(n,null,2));let i;if(typeof n==`string`)i=n;else if(Array.isArray(n)&&n.length>0)i=typeof n[0]==`string`?n[0]:String(n[0]);else if(n!=null)console.log(`[Replicate describeImage] Fallback: result is not string or array, stringifying`),i=String(n);else throw console.error(`[Replicate describeImage] ERROR: result is null or undefined`),Error(`Replicate returned empty or undefined response for image description. Result was: ${n}`);return console.log(`[Replicate describeImage] Final description:`,i.substring(0,100)),i},catch:t=>(console.error(`[Replicate describeImage] Caught error:`,t),e.fromCode(`UNKNOWN_ERROR`,{cause:t}))})}}).pipe(r(`ai`,`describe-image`,{"ai.provider":`replicate`,"ai.model":h,"ai.client_id":n.clientId}))}))};export{c as imageAiPlugin};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["CredentialProviderService"],"sources":["../src/image-ai-plugin.ts"],"sourcesContent":["import { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n CredentialProvider as CredentialProviderService,\n type ImageAiContext,\n ImageAiPlugin,\n} from \"@uploadista/core/flow\";\nimport { withOperationSpan } from \"@uploadista/observability\";\nimport { Effect, Layer, Option } from \"effect\";\nimport Replicate from \"replicate\";\n\ntype ModelId = `${string}/${string}` | `${string}/${string}:${string}`;\n\ntype RemoveBackgroundOutput = {\n url: () => string;\n};\n\ntype ReplicateCredentials = {\n apiKey: string;\n};\n\n// Credential provider function type\ntype CredentialProvider = (\n context: ImageAiContext & { serviceType: \"replicate\" },\n) => Effect.Effect<ReplicateCredentials, UploadistaError>;\n\n// Plugin configuration can be either a static API key or options with credential provider or service\ntype PluginConfig =\n | string\n | {\n credentialProvider?: CredentialProvider;\n useCredentialProviderService?: boolean;\n removeBackgroundModelId?: ModelId;\n describeImageModelId?: ModelId;\n };\n\n/**\n * Create the Replicate ImageAI plugin\n * Supports both static credentials (OSS) and dynamic credential providers (UploadistaCloud)\n *\n * @example\n * // Static credentials (OSS)\n * imageAiPlugin(process.env.REPLICATE_API_TOKEN)\n *\n * @example\n * // Dynamic credentials with function (UploadistaCloud)\n * imageAiPlugin({\n * credentialProvider: (context) => Effect.succeed({ apiKey: \"...\" })\n * })\n *\n * @example\n * // Dynamic credentials with Effect service (UploadistaCloud)\n * imageAiPlugin({\n * useCredentialProviderService: true\n * })\n */\nexport const imageAiPlugin = (\n config: PluginConfig,\n options?: {\n removeBackgroundModelId?: ModelId;\n describeImageModelId?: ModelId;\n },\n) => {\n // Parse configuration\n const isStatic = typeof config === \"string\";\n const staticApiKey = isStatic ? config : null;\n const credentialProvider = isStatic ? null : config.credentialProvider;\n const useCredentialProviderService = isStatic\n ? false\n : config.useCredentialProviderService;\n\n // Model IDs can come from either the config object or the options parameter\n const removeBackgroundModelId =\n (isStatic\n ? options?.removeBackgroundModelId\n : config.removeBackgroundModelId) ||\n \"lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1\";\n const describeImageModelId =\n (isStatic ? options?.describeImageModelId : config.describeImageModelId) ||\n \"zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1\";\n\n // Helper to get API token (either static, from provider function, or from service)\n const getApiToken = (context: ImageAiContext) => {\n if (staticApiKey) {\n return Effect.succeed(staticApiKey);\n }\n if (useCredentialProviderService) {\n return Effect.gen(function* () {\n const credentialProviderService = yield* Effect.serviceOption(\n CredentialProviderService,\n );\n\n if (Option.isNone(credentialProviderService)) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: new Error(\"Credential provider service not found\"),\n }),\n );\n } else {\n const credentials =\n yield* credentialProviderService.value.getCredential({\n clientId: context.clientId,\n serviceType: \"replicate\",\n });\n\n if (\n typeof credentials === \"object\" &&\n credentials !== null &&\n \"apiKey\" in credentials &&\n typeof credentials.apiKey === \"string\"\n ) {\n return credentials.apiKey;\n }\n }\n\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: new Error(\"Invalid credential format from service\"),\n }),\n );\n });\n }\n if (credentialProvider) {\n return Effect.gen(function* () {\n const credentials = yield* credentialProvider({\n ...context,\n serviceType: \"replicate\",\n });\n return credentials.apiKey;\n });\n }\n return Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: new Error(\"No API credentials configured\"),\n }),\n );\n };\n\n return Layer.succeed(\n ImageAiPlugin,\n ImageAiPlugin.of({\n removeBackground: (inputUrl, context) => {\n return Effect.gen(function* () {\n // Get API token (static or from credential provider)\n const apiToken = yield* getApiToken(context);\n\n const output = yield* Effect.tryPromise({\n try: async () => {\n const replicate = new Replicate({\n auth: apiToken,\n });\n\n const input = {\n image: inputUrl,\n };\n\n console.log(\"input\", input);\n\n return (await replicate.run(removeBackgroundModelId, {\n input,\n })) as RemoveBackgroundOutput;\n },\n catch: (error) => {\n console.log(\"error\", error);\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n return { outputUrl: output.url() };\n }).pipe(\n withOperationSpan(\"ai\", \"remove-background\", {\n \"ai.provider\": \"replicate\",\n \"ai.model\": removeBackgroundModelId,\n \"ai.client_id\": context.clientId,\n }),\n );\n },\n describeImage: (inputUrl, context) => {\n return Effect.gen(function* () {\n // Get API token (static or from credential provider)\n const apiToken = yield* getApiToken(context);\n\n const output = yield* Effect.tryPromise({\n try: async () => {\n const replicate = new Replicate({\n auth: apiToken,\n });\n\n return (await replicate.run(describeImageModelId, {\n input: {\n image: inputUrl,\n top_k: 50,\n top_p: 1,\n caption: false,\n question: \"What is shown in the image?\",\n do_sample: false,\n num_beams: 1,\n temperature: 1,\n system_prompt:\n \"A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\",\n length_penalty: 1,\n max_new_tokens: 768,\n repetition_penalty: 1,\n },\n })) as unknown as string;\n },\n catch: (error) => {\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n return { description: output };\n }).pipe(\n withOperationSpan(\"ai\", \"describe-image\", {\n \"ai.provider\": \"replicate\",\n \"ai.model\": describeImageModelId,\n \"ai.client_id\": context.clientId,\n }),\n );\n },\n }),\n );\n};\n"],"mappings":"sRAuDA,MAAa,GACX,EACA,IAIG,CAEH,IAAM,EAAW,OAAO,GAAW,SAC7B,EAAe,EAAW,EAAS,KACnC,EAAqB,EAAW,KAAO,EAAO,mBAC9C,EAA+B,EACjC,GACA,EAAO,6BAGL,GACH,EACG,GAAS,wBACT,EAAO,0BACX,sFACI,GACH,EAAW,GAAS,qBAAuB,EAAO,uBACnD,iFAGI,EAAe,GACf,EACK,EAAO,QAAQ,EAAa,CAEjC,EACK,EAAO,IAAI,WAAa,CAC7B,IAAM,EAA4B,MAAO,EAAO,cAC9CA,EACD,CAED,GAAI,EAAO,OAAO,EAA0B,CAC1C,OAAO,MAAO,EAAO,KACnB,EAAgB,SAAS,gBAAiB,CACxC,MAAW,MAAM,wCAAwC,CAC1D,CAAC,CACH,CACI,CACL,IAAM,EACJ,MAAO,EAA0B,MAAM,cAAc,CACnD,SAAU,EAAQ,SAClB,YAAa,YACd,CAAC,CAEJ,GACE,OAAO,GAAgB,UACvB,GACA,WAAY,GACZ,OAAO,EAAY,QAAW,SAE9B,OAAO,EAAY,OAIvB,OAAO,MAAO,EAAO,KACnB,EAAgB,SAAS,gBAAiB,CACxC,MAAW,MAAM,yCAAyC,CAC3D,CAAC,CACH,EACD,CAEA,EACK,EAAO,IAAI,WAAa,CAK7B,OAJoB,MAAO,EAAmB,CAC5C,GAAG,EACH,YAAa,YACd,CAAC,EACiB,QACnB,CAEG,EAAO,KACZ,EAAgB,SAAS,gBAAiB,CACxC,MAAW,MAAM,gCAAgC,CAClD,CAAC,CACH,CAGH,OAAO,EAAM,QACX,EACA,EAAc,GAAG,CACf,kBAAmB,EAAU,IACpB,EAAO,IAAI,WAAa,CAE7B,IAAM,EAAW,MAAO,EAAY,EAAQ,CAyB5C,MAAO,CAAE,WAvBM,MAAO,EAAO,WAAW,CACtC,IAAK,SAAY,CACf,IAAM,EAAY,IAAI,EAAU,CAC9B,KAAM,EACP,CAAC,CAEI,EAAQ,CACZ,MAAO,EACR,CAID,OAFA,QAAQ,IAAI,QAAS,EAAM,CAEnB,MAAM,EAAU,IAAI,EAAyB,CACnD,QACD,CAAC,EAEJ,MAAQ,IACN,QAAQ,IAAI,QAAS,EAAM,CACpB,EAAgB,SAAS,gBAAiB,CAC/C,MAAO,EACR,CAAC,EAEL,CAAC,EACyB,KAAK,CAAE,EAClC,CAAC,KACD,EAAkB,KAAM,oBAAqB,CAC3C,cAAe,YACf,WAAY,EACZ,eAAgB,EAAQ,SACzB,CAAC,CACH,CAEH,eAAgB,EAAU,IACjB,EAAO,IAAI,WAAa,CAE7B,IAAM,EAAW,MAAO,EAAY,EAAQ,CAgC5C,MAAO,CAAE,YA9BM,MAAO,EAAO,WAAW,CACtC,IAAK,SAKK,MAJU,IAAI,EAAU,CAC9B,KAAM,EACP,CAAC,CAEsB,IAAI,EAAsB,CAChD,MAAO,CACL,MAAO,EACP,MAAO,GACP,MAAO,EACP,QAAS,GACT,SAAU,8BACV,UAAW,GACX,UAAW,EACX,YAAa,EACb,cACE,6JACF,eAAgB,EAChB,eAAgB,IAChB,mBAAoB,EACrB,CACF,CAAC,CAEJ,MAAQ,GACC,EAAgB,SAAS,gBAAiB,CAC/C,MAAO,EACR,CAAC,CAEL,CAAC,CAC4B,EAC9B,CAAC,KACD,EAAkB,KAAM,iBAAkB,CACxC,cAAe,YACf,WAAY,EACZ,eAAgB,EAAQ,SACzB,CAAC,CACH,CAEJ,CAAC,CACH"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["CredentialProviderService"],"sources":["../src/image-ai-plugin.ts"],"sourcesContent":["import { UploadistaError } from \"@uploadista/core/errors\";\nimport {\n CredentialProvider as CredentialProviderService,\n type ImageAiContext,\n ImageAiPlugin,\n} from \"@uploadista/core/flow\";\nimport { withOperationSpan } from \"@uploadista/observability\";\nimport { Effect, Layer, Option } from \"effect\";\nimport Replicate from \"replicate\";\n\ntype ModelId = `${string}/${string}` | `${string}/${string}:${string}`;\n\ntype RemoveBackgroundOutput = {\n url: () => string;\n};\n\ntype ReplicateCredentials = {\n apiKey: string;\n};\n\n// Credential provider function type\ntype CredentialProvider = (\n context: ImageAiContext & { serviceType: \"replicate\" },\n) => Effect.Effect<ReplicateCredentials, UploadistaError>;\n\n// Plugin configuration can be either a static API key or options with credential provider or service\ntype PluginConfig =\n | string\n | {\n credentialProvider?: CredentialProvider;\n useCredentialProviderService?: boolean;\n removeBackgroundModelId?: ModelId;\n describeImageModelId?: ModelId;\n };\n\n/**\n * Create the Replicate ImageAI plugin\n * Supports both static credentials (OSS) and dynamic credential providers (UploadistaCloud)\n *\n * @example\n * // Static credentials (OSS)\n * imageAiPlugin(process.env.REPLICATE_API_TOKEN)\n *\n * @example\n * // Dynamic credentials with function (UploadistaCloud)\n * imageAiPlugin({\n * credentialProvider: (context) => Effect.succeed({ apiKey: \"...\" })\n * })\n *\n * @example\n * // Dynamic credentials with Effect service (UploadistaCloud)\n * imageAiPlugin({\n * useCredentialProviderService: true\n * })\n */\nexport const imageAiPlugin = (\n config: PluginConfig,\n options?: {\n removeBackgroundModelId?: ModelId;\n describeImageModelId?: ModelId;\n },\n) => {\n // Parse configuration\n const isStatic = typeof config === \"string\";\n const staticApiKey = isStatic ? config : null;\n const credentialProvider = isStatic ? null : config.credentialProvider;\n const useCredentialProviderService = isStatic\n ? false\n : config.useCredentialProviderService;\n\n // Model IDs can come from either the config object or the options parameter\n const removeBackgroundModelId =\n (isStatic\n ? options?.removeBackgroundModelId\n : config.removeBackgroundModelId) ||\n \"lucataco/remove-bg:95fcc2a26d3899cd6c2691c900465aaeff466285a65c14638cc5f36f34befaf1\";\n const describeImageModelId =\n (isStatic ? options?.describeImageModelId : config.describeImageModelId) ||\n \"zsxkib/blip-3:499bec581d8f64060fd695ec0c34d7595c6824c4118259aa8b0788e0d2d903e1\";\n\n // Helper to get API token (either static, from provider function, or from service)\n const getApiToken = (context: ImageAiContext) => {\n if (staticApiKey) {\n return Effect.succeed(staticApiKey);\n }\n if (useCredentialProviderService) {\n return Effect.gen(function* () {\n const credentialProviderService = yield* Effect.serviceOption(\n CredentialProviderService,\n );\n\n if (Option.isNone(credentialProviderService)) {\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: new Error(\"Credential provider service not found\"),\n }),\n );\n } else {\n const credentials =\n yield* credentialProviderService.value.getCredential({\n clientId: context.clientId,\n serviceType: \"replicate\",\n });\n\n if (\n typeof credentials === \"object\" &&\n credentials !== null &&\n \"apiKey\" in credentials &&\n typeof credentials.apiKey === \"string\"\n ) {\n return credentials.apiKey;\n }\n }\n\n return yield* Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: new Error(\"Invalid credential format from service\"),\n }),\n );\n });\n }\n if (credentialProvider) {\n return Effect.gen(function* () {\n const credentials = yield* credentialProvider({\n ...context,\n serviceType: \"replicate\",\n });\n return credentials.apiKey;\n });\n }\n return Effect.fail(\n UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: new Error(\"No API credentials configured\"),\n }),\n );\n };\n\n return Layer.succeed(\n ImageAiPlugin,\n ImageAiPlugin.of({\n removeBackground: (inputUrl, context) => {\n return Effect.gen(function* () {\n // Get API token (static or from credential provider)\n const apiToken = yield* getApiToken(context);\n\n const output = yield* Effect.tryPromise({\n try: async () => {\n const replicate = new Replicate({\n auth: apiToken,\n });\n\n const input = {\n image: inputUrl,\n };\n\n console.log(\"input\", input);\n\n return (await replicate.run(removeBackgroundModelId, {\n input,\n })) as RemoveBackgroundOutput;\n },\n catch: (error) => {\n console.log(\"error\", error);\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n return { outputUrl: output.url() };\n }).pipe(\n withOperationSpan(\"ai\", \"remove-background\", {\n \"ai.provider\": \"replicate\",\n \"ai.model\": removeBackgroundModelId,\n \"ai.client_id\": context.clientId,\n }),\n );\n },\n describeImage: (inputUrl, context) => {\n return Effect.gen(function* () {\n // Get API token (static or from credential provider)\n const apiToken = yield* getApiToken(context);\n\n yield* Effect.logInfo(\n `[Replicate describeImage] Starting with URL: ${inputUrl}`,\n );\n\n const output = yield* Effect.tryPromise({\n try: async () => {\n const replicate = new Replicate({\n auth: apiToken,\n });\n\n console.log(\n \"[Replicate describeImage] Calling Replicate API with model:\",\n describeImageModelId,\n );\n\n const result = await replicate.run(describeImageModelId, {\n input: {\n image: inputUrl,\n top_k: 50,\n top_p: 1,\n caption: false,\n question: \"What is shown in the image?\",\n do_sample: false,\n num_beams: 1,\n temperature: 1,\n system_prompt:\n \"A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.\",\n length_penalty: 1,\n max_new_tokens: 768,\n repetition_penalty: 1,\n },\n });\n\n console.log(\n \"[Replicate describeImage] Raw result type:\",\n typeof result,\n );\n console.log(\n \"[Replicate describeImage] Raw result:\",\n JSON.stringify(result, null, 2),\n );\n\n // Handle different response formats from Replicate\n // Some models return arrays, some return strings directly\n let description: string;\n if (typeof result === \"string\") {\n description = result;\n } else if (Array.isArray(result) && result.length > 0) {\n // Some models return output as an array\n description =\n typeof result[0] === \"string\" ? result[0] : String(result[0]);\n } else if (result != null) {\n // Fallback: stringify the result\n console.log(\n \"[Replicate describeImage] Fallback: result is not string or array, stringifying\",\n );\n description = String(result);\n } else {\n console.error(\n \"[Replicate describeImage] ERROR: result is null or undefined\",\n );\n throw new Error(\n `Replicate returned empty or undefined response for image description. Result was: ${result}`,\n );\n }\n\n console.log(\n \"[Replicate describeImage] Final description:\",\n description.substring(0, 100),\n );\n return description;\n },\n catch: (error) => {\n console.error(\"[Replicate describeImage] Caught error:\", error);\n return UploadistaError.fromCode(\"UNKNOWN_ERROR\", {\n cause: error,\n });\n },\n });\n return { description: output };\n }).pipe(\n withOperationSpan(\"ai\", \"describe-image\", {\n \"ai.provider\": \"replicate\",\n \"ai.model\": describeImageModelId,\n \"ai.client_id\": context.clientId,\n }),\n );\n },\n }),\n );\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uploadista/flow-images-replicate",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3-beta.11",
|
|
5
5
|
"description": "Replicate image AI processing service for Uploadista Flow",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Uploadista",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"replicate": "1.4.0",
|
|
18
|
-
"@uploadista/core": "0.1.
|
|
19
|
-
"@uploadista/observability": "0.1.
|
|
18
|
+
"@uploadista/core": "0.1.3-beta.11",
|
|
19
|
+
"@uploadista/observability": "0.1.3-beta.11"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"effect": "^3.0.0",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@effect/vitest": "0.27.0",
|
|
27
27
|
"@types/node": "24.10.9",
|
|
28
|
-
"effect": "3.19.
|
|
29
|
-
"tsdown": "0.
|
|
30
|
-
"vitest": "4.0.
|
|
31
|
-
"zod": "4.3.
|
|
32
|
-
"@uploadista/typescript-config": "0.1.
|
|
28
|
+
"effect": "3.19.15",
|
|
29
|
+
"tsdown": "0.20.1",
|
|
30
|
+
"vitest": "4.0.18",
|
|
31
|
+
"zod": "4.3.6",
|
|
32
|
+
"@uploadista/typescript-config": "0.1.3-beta.11"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsc --noEmit && tsdown",
|
package/src/image-ai-plugin.ts
CHANGED
|
@@ -180,13 +180,22 @@ export const imageAiPlugin = (
|
|
|
180
180
|
// Get API token (static or from credential provider)
|
|
181
181
|
const apiToken = yield* getApiToken(context);
|
|
182
182
|
|
|
183
|
+
yield* Effect.logInfo(
|
|
184
|
+
`[Replicate describeImage] Starting with URL: ${inputUrl}`,
|
|
185
|
+
);
|
|
186
|
+
|
|
183
187
|
const output = yield* Effect.tryPromise({
|
|
184
188
|
try: async () => {
|
|
185
189
|
const replicate = new Replicate({
|
|
186
190
|
auth: apiToken,
|
|
187
191
|
});
|
|
188
192
|
|
|
189
|
-
|
|
193
|
+
console.log(
|
|
194
|
+
"[Replicate describeImage] Calling Replicate API with model:",
|
|
195
|
+
describeImageModelId,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const result = await replicate.run(describeImageModelId, {
|
|
190
199
|
input: {
|
|
191
200
|
image: inputUrl,
|
|
192
201
|
top_k: 50,
|
|
@@ -202,9 +211,49 @@ export const imageAiPlugin = (
|
|
|
202
211
|
max_new_tokens: 768,
|
|
203
212
|
repetition_penalty: 1,
|
|
204
213
|
},
|
|
205
|
-
})
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
console.log(
|
|
217
|
+
"[Replicate describeImage] Raw result type:",
|
|
218
|
+
typeof result,
|
|
219
|
+
);
|
|
220
|
+
console.log(
|
|
221
|
+
"[Replicate describeImage] Raw result:",
|
|
222
|
+
JSON.stringify(result, null, 2),
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
// Handle different response formats from Replicate
|
|
226
|
+
// Some models return arrays, some return strings directly
|
|
227
|
+
let description: string;
|
|
228
|
+
if (typeof result === "string") {
|
|
229
|
+
description = result;
|
|
230
|
+
} else if (Array.isArray(result) && result.length > 0) {
|
|
231
|
+
// Some models return output as an array
|
|
232
|
+
description =
|
|
233
|
+
typeof result[0] === "string" ? result[0] : String(result[0]);
|
|
234
|
+
} else if (result != null) {
|
|
235
|
+
// Fallback: stringify the result
|
|
236
|
+
console.log(
|
|
237
|
+
"[Replicate describeImage] Fallback: result is not string or array, stringifying",
|
|
238
|
+
);
|
|
239
|
+
description = String(result);
|
|
240
|
+
} else {
|
|
241
|
+
console.error(
|
|
242
|
+
"[Replicate describeImage] ERROR: result is null or undefined",
|
|
243
|
+
);
|
|
244
|
+
throw new Error(
|
|
245
|
+
`Replicate returned empty or undefined response for image description. Result was: ${result}`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log(
|
|
250
|
+
"[Replicate describeImage] Final description:",
|
|
251
|
+
description.substring(0, 100),
|
|
252
|
+
);
|
|
253
|
+
return description;
|
|
206
254
|
},
|
|
207
255
|
catch: (error) => {
|
|
256
|
+
console.error("[Replicate describeImage] Caught error:", error);
|
|
208
257
|
return UploadistaError.fromCode("UNKNOWN_ERROR", {
|
|
209
258
|
cause: error,
|
|
210
259
|
});
|