@webiny/ai-powerups 6.4.11 → 6.6.0-alpha.1

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 (239) hide show
  1. package/AiPowerups.js +2 -2
  2. package/AiPowerups.js.map +1 -1
  3. package/admin/Extension.js +11 -2
  4. package/admin/Extension.js.map +1 -1
  5. package/admin/features/compareEntryRevisions/CompareEntryRevisionsGateway.d.ts +12 -0
  6. package/admin/features/compareEntryRevisions/CompareEntryRevisionsGateway.js +46 -0
  7. package/admin/features/compareEntryRevisions/CompareEntryRevisionsGateway.js.map +1 -0
  8. package/admin/features/compareEntryRevisions/CompareEntryRevisionsRepository.d.ts +11 -0
  9. package/admin/features/compareEntryRevisions/CompareEntryRevisionsRepository.js +18 -0
  10. package/admin/features/compareEntryRevisions/CompareEntryRevisionsRepository.js.map +1 -0
  11. package/admin/features/compareEntryRevisions/CompareEntryRevisionsUseCase.d.ts +11 -0
  12. package/admin/features/compareEntryRevisions/CompareEntryRevisionsUseCase.js +18 -0
  13. package/admin/features/compareEntryRevisions/CompareEntryRevisionsUseCase.js.map +1 -0
  14. package/admin/features/compareEntryRevisions/abstractions.d.ts +32 -0
  15. package/admin/features/compareEntryRevisions/abstractions.js +7 -0
  16. package/admin/features/compareEntryRevisions/abstractions.js.map +1 -0
  17. package/admin/features/compareEntryRevisions/feature.d.ts +1 -0
  18. package/admin/features/compareEntryRevisions/feature.js +15 -0
  19. package/admin/features/compareEntryRevisions/feature.js.map +1 -0
  20. package/admin/features/compareEntryRevisions/index.d.ts +2 -0
  21. package/admin/features/compareEntryRevisions/index.js +2 -0
  22. package/admin/features/feature.js +2 -0
  23. package/admin/features/feature.js.map +1 -1
  24. package/admin/features/generateEntryContent/GenerateEntryContentGateway.d.ts +12 -0
  25. package/admin/features/generateEntryContent/GenerateEntryContentGateway.js +45 -0
  26. package/admin/features/generateEntryContent/GenerateEntryContentGateway.js.map +1 -0
  27. package/admin/features/generateEntryContent/GenerateEntryContentUseCase.d.ts +11 -0
  28. package/admin/features/generateEntryContent/GenerateEntryContentUseCase.js +18 -0
  29. package/admin/features/generateEntryContent/GenerateEntryContentUseCase.js.map +1 -0
  30. package/admin/features/generateEntryContent/abstractions.d.ts +24 -0
  31. package/admin/features/generateEntryContent/abstractions.js +6 -0
  32. package/admin/features/generateEntryContent/abstractions.js.map +1 -0
  33. package/admin/features/generateEntryContent/feature.d.ts +1 -0
  34. package/admin/features/generateEntryContent/feature.js +13 -0
  35. package/admin/features/generateEntryContent/feature.js.map +1 -0
  36. package/admin/features/generateEntryContent/index.d.ts +3 -0
  37. package/admin/features/generateEntryContent/index.js +2 -0
  38. package/admin/features/generatePageContent/GeneratePageContentGateway.js +2 -0
  39. package/admin/features/generatePageContent/GeneratePageContentGateway.js.map +1 -1
  40. package/admin/features/generatePageContent/abstractions.d.ts +1 -0
  41. package/admin/features/generatePageContent/abstractions.js.map +1 -1
  42. package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPage.d.ts +2 -2
  43. package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPage.js +3 -4
  44. package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPage.js.map +1 -1
  45. package/admin/presentation/AiPromptFormFactory/AiPromptFormFactory.d.ts +20 -0
  46. package/admin/presentation/AiPromptFormFactory/AiPromptFormFactory.js +108 -0
  47. package/admin/presentation/AiPromptFormFactory/AiPromptFormFactory.js.map +1 -0
  48. package/admin/presentation/AiPromptFormFactory/abstractions.d.ts +14 -0
  49. package/admin/presentation/AiPromptFormFactory/abstractions.js +5 -0
  50. package/admin/presentation/AiPromptFormFactory/abstractions.js.map +1 -0
  51. package/admin/presentation/AiPromptFormFactory/feature.d.ts +1 -0
  52. package/admin/presentation/AiPromptFormFactory/feature.js +11 -0
  53. package/admin/presentation/AiPromptFormFactory/feature.js.map +1 -0
  54. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDialog.d.ts +9 -0
  55. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDialog.js +118 -0
  56. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDialog.js.map +1 -0
  57. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDrawer.d.ts +9 -0
  58. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDrawer.js +72 -0
  59. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDrawer.js.map +1 -0
  60. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsMenuItem.d.ts +4 -0
  61. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsMenuItem.js +21 -0
  62. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsMenuItem.js.map +1 -0
  63. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsOverlays.d.ts +2 -0
  64. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsOverlays.js +17 -0
  65. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsOverlays.js.map +1 -0
  66. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsPresenter.d.ts +25 -0
  67. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsPresenter.js +90 -0
  68. package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsPresenter.js.map +1 -0
  69. package/admin/presentation/CmsCompareEntryRevisions/Extension.d.ts +2 -0
  70. package/admin/presentation/CmsCompareEntryRevisions/Extension.js +16 -0
  71. package/admin/presentation/CmsCompareEntryRevisions/Extension.js.map +1 -0
  72. package/admin/presentation/CmsCompareEntryRevisions/abstractions.d.ts +29 -0
  73. package/admin/presentation/CmsCompareEntryRevisions/abstractions.js +5 -0
  74. package/admin/presentation/CmsCompareEntryRevisions/abstractions.js.map +1 -0
  75. package/admin/presentation/CmsCompareEntryRevisions/feature.d.ts +3 -0
  76. package/admin/presentation/CmsCompareEntryRevisions/feature.js +17 -0
  77. package/admin/presentation/CmsCompareEntryRevisions/feature.js.map +1 -0
  78. package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.d.ts +4 -0
  79. package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.js +27 -0
  80. package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.js.map +1 -0
  81. package/admin/presentation/CmsContentGeneration/CmsGenerateContentDialog.d.ts +5 -0
  82. package/admin/presentation/CmsContentGeneration/CmsGenerateContentDialog.js +106 -0
  83. package/admin/presentation/CmsContentGeneration/CmsGenerateContentDialog.js.map +1 -0
  84. package/admin/presentation/CmsContentGeneration/CmsGenerateContentPresenter.d.ts +29 -0
  85. package/admin/presentation/CmsContentGeneration/CmsGenerateContentPresenter.js +120 -0
  86. package/admin/presentation/CmsContentGeneration/CmsGenerateContentPresenter.js.map +1 -0
  87. package/admin/presentation/CmsContentGeneration/Extension.d.ts +2 -0
  88. package/admin/presentation/CmsContentGeneration/Extension.js +27 -0
  89. package/admin/presentation/CmsContentGeneration/Extension.js.map +1 -0
  90. package/admin/presentation/CmsContentGeneration/abstractions.d.ts +20 -0
  91. package/admin/presentation/CmsContentGeneration/abstractions.js +5 -0
  92. package/admin/presentation/CmsContentGeneration/abstractions.js.map +1 -0
  93. package/admin/presentation/CmsContentGeneration/feature.d.ts +3 -0
  94. package/admin/presentation/CmsContentGeneration/feature.js +17 -0
  95. package/admin/presentation/CmsContentGeneration/feature.js.map +1 -0
  96. package/admin/presentation/CmsEntryWizard/CmsEntryWizard.d.ts +4 -0
  97. package/admin/presentation/CmsEntryWizard/CmsEntryWizard.js +113 -0
  98. package/admin/presentation/CmsEntryWizard/CmsEntryWizard.js.map +1 -0
  99. package/admin/presentation/CmsEntryWizard/CmsEntryWizardGate.d.ts +4 -0
  100. package/admin/presentation/CmsEntryWizard/CmsEntryWizardGate.js +19 -0
  101. package/admin/presentation/CmsEntryWizard/CmsEntryWizardGate.js.map +1 -0
  102. package/admin/presentation/CmsEntryWizard/Extension.d.ts +2 -0
  103. package/admin/presentation/CmsEntryWizard/Extension.js +10 -0
  104. package/admin/presentation/CmsEntryWizard/Extension.js.map +1 -0
  105. package/admin/presentation/ProjectsSettings.js +4 -4
  106. package/admin/presentation/ProjectsSettings.js.map +1 -1
  107. package/admin/presentation/ProvidersSettings.js +1 -1
  108. package/admin/presentation/ProvidersSettings.js.map +1 -1
  109. package/admin/presentation/WbContentGeneration/GenerateContentDialog.d.ts +2 -2
  110. package/admin/presentation/WbContentGeneration/GenerateContentDialog.js +2 -2
  111. package/admin/presentation/WbContentGeneration/GenerateContentDialog.js.map +1 -1
  112. package/admin/presentation/WbContentGeneration/GenerateContentPresenter.d.ts +4 -12
  113. package/admin/presentation/WbContentGeneration/GenerateContentPresenter.js +12 -94
  114. package/admin/presentation/WbContentGeneration/GenerateContentPresenter.js.map +1 -1
  115. package/api/Extension.js +13 -3
  116. package/api/Extension.js.map +1 -1
  117. package/api/features/AiChatProvider/PowerUpsAiChatProvider.d.ts +24 -0
  118. package/api/features/AiChatProvider/PowerUpsAiChatProvider.js +31 -0
  119. package/api/features/AiChatProvider/PowerUpsAiChatProvider.js.map +1 -0
  120. package/api/features/AiChatProvider/feature.d.ts +9 -0
  121. package/api/features/AiChatProvider/feature.js +11 -0
  122. package/api/features/AiChatProvider/feature.js.map +1 -0
  123. package/api/features/AiChatProvider/index.d.ts +2 -0
  124. package/api/features/AiChatProvider/index.js +2 -0
  125. package/api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.d.ts +36 -0
  126. package/api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.js +85 -0
  127. package/api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.js.map +1 -0
  128. package/api/features/AiImageEnrichment/AiImageEnrichmentTask.d.ts +10 -14
  129. package/api/features/AiImageEnrichment/AiImageEnrichmentTask.js +27 -100
  130. package/api/features/AiImageEnrichment/AiImageEnrichmentTask.js.map +1 -1
  131. package/api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.d.ts +18 -0
  132. package/api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.js +50 -0
  133. package/api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.js.map +1 -0
  134. package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.d.ts +19 -0
  135. package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.js +49 -0
  136. package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.js.map +1 -0
  137. package/api/features/AiImageEnrichment/abstractions.d.ts +60 -0
  138. package/api/features/AiImageEnrichment/abstractions.js +12 -0
  139. package/api/features/AiImageEnrichment/abstractions.js.map +1 -0
  140. package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.d.ts +12 -0
  141. package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.js +30 -0
  142. package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.js.map +1 -0
  143. package/api/features/AiImageEnrichment/errors.d.ts +26 -0
  144. package/api/features/AiImageEnrichment/errors.js +28 -0
  145. package/api/features/AiImageEnrichment/errors.js.map +1 -0
  146. package/api/features/AiImageEnrichment/feature.js +9 -0
  147. package/api/features/AiImageEnrichment/feature.js.map +1 -1
  148. package/api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.d.ts +6 -0
  149. package/api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.js +9 -0
  150. package/api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.js.map +1 -0
  151. package/api/features/AiImageEnrichment/readEnrichmentPartial.d.ts +8 -0
  152. package/api/features/AiImageEnrichment/readEnrichmentPartial.js +16 -0
  153. package/api/features/AiImageEnrichment/readEnrichmentPartial.js.map +1 -0
  154. package/api/features/AiImageEnrichment/streamEvents.d.ts +36 -0
  155. package/api/features/AiImageEnrichment/streamEvents.js +0 -0
  156. package/api/features/AiPromptContext/AiPromptContextBuilder.d.ts +8 -1
  157. package/api/features/AiPromptContext/AiPromptContextBuilder.js +46 -2
  158. package/api/features/AiPromptContext/AiPromptContextBuilder.js.map +1 -1
  159. package/api/features/AiPromptContext/abstractions.d.ts +3 -0
  160. package/api/features/AiPromptContext/abstractions.js +9 -1
  161. package/api/features/AiPromptContext/abstractions.js.map +1 -1
  162. package/api/features/AiPromptContext/index.d.ts +1 -1
  163. package/api/features/AiPromptContext/index.js +1 -1
  164. package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.d.ts +22 -0
  165. package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.js +136 -0
  166. package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.js.map +1 -0
  167. package/api/features/CmsCompareEntryRevisions/abstractions.d.ts +18 -0
  168. package/api/features/CmsCompareEntryRevisions/abstractions.js +5 -0
  169. package/api/features/CmsCompareEntryRevisions/abstractions.js.map +1 -0
  170. package/api/features/CmsCompareEntryRevisions/feature.d.ts +4 -0
  171. package/api/features/CmsCompareEntryRevisions/feature.js +11 -0
  172. package/api/features/CmsCompareEntryRevisions/feature.js.map +1 -0
  173. package/api/features/CmsCompareEntryRevisions/index.d.ts +2 -0
  174. package/api/features/CmsCompareEntryRevisions/index.js +2 -0
  175. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentTask.d.ts +33 -0
  176. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentTask.js +84 -0
  177. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentTask.js.map +1 -0
  178. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.d.ts +29 -0
  179. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.js +141 -0
  180. package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.js.map +1 -0
  181. package/api/features/CmsGenerateEntryContent/abstractions.d.ts +36 -0
  182. package/api/features/CmsGenerateEntryContent/abstractions.js +5 -0
  183. package/api/features/CmsGenerateEntryContent/abstractions.js.map +1 -0
  184. package/api/features/CmsGenerateEntryContent/buildPrompt.d.ts +2 -0
  185. package/api/features/CmsGenerateEntryContent/buildPrompt.js +61 -0
  186. package/api/features/CmsGenerateEntryContent/buildPrompt.js.map +1 -0
  187. package/api/features/CmsGenerateEntryContent/feature.d.ts +4 -0
  188. package/api/features/CmsGenerateEntryContent/feature.js +13 -0
  189. package/api/features/CmsGenerateEntryContent/feature.js.map +1 -0
  190. package/api/features/CmsGenerateEntryContent/index.d.ts +1 -0
  191. package/api/features/CmsGenerateEntryContent/index.js +1 -0
  192. package/api/features/CmsGenerateEntryContent/injectDynamicZoneTypenames.d.ts +2 -0
  193. package/api/features/CmsGenerateEntryContent/injectDynamicZoneTypenames.js +30 -0
  194. package/api/features/CmsGenerateEntryContent/injectDynamicZoneTypenames.js.map +1 -0
  195. package/api/features/CmsResolveImageTool/CmsResolveImageTool.d.ts +14 -0
  196. package/api/features/CmsResolveImageTool/CmsResolveImageTool.js +27 -0
  197. package/api/features/CmsResolveImageTool/CmsResolveImageTool.js.map +1 -0
  198. package/api/features/CmsResolveImageTool/feature.d.ts +4 -0
  199. package/api/features/CmsResolveImageTool/feature.js +11 -0
  200. package/api/features/CmsResolveImageTool/feature.js.map +1 -0
  201. package/api/features/GetSettings/GetSettingsUseCase.d.ts +1 -1
  202. package/api/features/GetSettings/index.d.ts +1 -0
  203. package/api/features/GetSettings/index.js +1 -0
  204. package/api/features/Providers/ProvidersHandler.d.ts +1 -3
  205. package/api/features/Providers/ProvidersHandler.js +2 -15
  206. package/api/features/Providers/ProvidersHandler.js.map +1 -1
  207. package/api/features/Providers/types.d.ts +2 -2
  208. package/api/features/WbGeneratePageContent/WbGeneratePageContentTask.d.ts +4 -3
  209. package/api/features/WbGeneratePageContent/WbGeneratePageContentTask.js +25 -15
  210. package/api/features/WbGeneratePageContent/WbGeneratePageContentTask.js.map +1 -1
  211. package/api/features/WbGeneratePageContent/WbGeneratePageContentUseCase.js +4 -3
  212. package/api/features/WbGeneratePageContent/WbGeneratePageContentUseCase.js.map +1 -1
  213. package/api/features/WbGeneratePageContent/abstractions.d.ts +1 -0
  214. package/api/features/WbGeneratePageContent/abstractions.js.map +1 -1
  215. package/api/features/WbTranslatePage/LexicalParser.d.ts +10 -0
  216. package/api/features/WbTranslatePage/LexicalParser.js +37 -0
  217. package/api/features/WbTranslatePage/LexicalParser.js.map +1 -0
  218. package/api/features/WbTranslatePage/WbTranslatePageDecorator.d.ts +27 -0
  219. package/api/features/WbTranslatePage/WbTranslatePageDecorator.js +134 -0
  220. package/api/features/WbTranslatePage/WbTranslatePageDecorator.js.map +1 -0
  221. package/api/features/WbTranslatePage/abstractions/LexicalParser.d.ts +7 -0
  222. package/api/features/WbTranslatePage/abstractions/LexicalParser.js +5 -0
  223. package/api/features/WbTranslatePage/abstractions/LexicalParser.js.map +1 -0
  224. package/api/features/WbTranslatePage/feature.d.ts +4 -0
  225. package/api/features/WbTranslatePage/feature.js +13 -0
  226. package/api/features/WbTranslatePage/feature.js.map +1 -0
  227. package/api/features/WbTranslatePage/index.d.ts +2 -0
  228. package/api/features/WbTranslatePage/index.js +2 -0
  229. package/api/graphql/BaseGraphQLSchema.d.ts +2 -2
  230. package/api/graphql/BaseGraphQLSchema.js +45 -6
  231. package/api/graphql/BaseGraphQLSchema.js.map +1 -1
  232. package/api/graphql/CmsCompareEntryRevisionsSchema.d.ts +8 -0
  233. package/api/graphql/CmsCompareEntryRevisionsSchema.js +68 -0
  234. package/api/graphql/CmsCompareEntryRevisionsSchema.js.map +1 -0
  235. package/exports/admin/ai-powerups.d.ts +1 -0
  236. package/exports/admin/ai-powerups.js +1 -0
  237. package/exports/api/ai-powerups.d.ts +2 -0
  238. package/exports/api/ai-powerups.js +2 -0
  239. package/package.json +33 -25
@@ -1 +1 @@
1
- {"version":3,"file":"api/features/AiImageEnrichment/AiImageEnrichmentTask.js","sources":["../../../../src/api/features/AiImageEnrichment/AiImageEnrichmentTask.ts"],"sourcesContent":["import { Output } from \"ai\";\nimport { z } from \"zod\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { Ai } from \"@webiny/api-core/features/ai/index.js\";\nimport { Encryption } from \"@webiny/api-core/features/encryption/index.js\";\nimport { GetFileUseCase } from \"@webiny/api-file-manager/features/file/GetFile/index.js\";\nimport { UpdateFileUseCase } from \"@webiny/api-file-manager/features/file/UpdateFile/index.js\";\nimport { GetSettingsUseCase as FmGetSettingsUseCase } from \"@webiny/api-file-manager/features/settings/GetSettings/abstractions.js\";\nimport { WebsocketService } from \"@webiny/api-websockets/features/WebsocketService/index.js\";\nimport { GetSettingsUseCase } from \"~/api/features/GetSettings/index.js\";\n\nexport const AI_IMAGE_ENRICHMENT_TASK_ID = \"fmAiImageEnrichment\";\n\nconst AI_PROMPT =\n \"Analyze this image and return up to 5 lowercase descriptive tags and one short sentence describing the image.\";\n\nconst aiOutputSchema = Output.object({\n schema: z.object({\n tags: z.array(z.string()),\n description: z.string()\n })\n});\n\nexport interface IAiImageEnrichmentTaskInput {\n fileId: string;\n}\n\nclass AiImageEnrichmentTaskImpl implements TaskDefinition.Interface<IAiImageEnrichmentTaskInput> {\n id = AI_IMAGE_ENRICHMENT_TASK_ID;\n title = \"File Manager - AI Image Enrichment\";\n description = \"Automatically enriches uploaded images with AI-generated tags and description.\";\n maxIterations = 1;\n isPrivate = true;\n databaseLogs = false;\n\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n constructor(\n private getFile: GetFileUseCase.Interface,\n private fmSettings: FmGetSettingsUseCase.Interface,\n private updateFile: UpdateFileUseCase.Interface,\n private ai: Ai.Interface,\n private getSettings: GetSettingsUseCase.Interface,\n private encryption: Encryption.Interface,\n private websocketService?: WebsocketService.Interface\n ) {}\n\n async run({\n input,\n controller\n }: TaskDefinition.RunParams<IAiImageEnrichmentTaskInput>): Promise<\n TaskDefinition.Result<IAiImageEnrichmentTaskInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const fileResult = await this.getFile.execute(input.fileId);\n if (fileResult.isFail()) {\n return controller.response.error({\n message: `File not found: ${input.fileId}`\n });\n }\n\n const file = fileResult.value;\n\n if (!file.type.startsWith(\"image/\")) {\n return controller.response.done(\"File is not an image; skipping AI enrichment.\");\n }\n\n const settingsResult = await this.fmSettings.execute();\n const srcPrefix = settingsResult.isOk() ? (settingsResult.value.srcPrefix ?? \"\") : \"\";\n const imageUrl = `${srcPrefix}${file.key}`;\n\n const aiSettingsResult = await this.getSettings.execute();\n\n if (aiSettingsResult.isFail()) {\n return controller.response.error({\n message: \"No AI provider configured. Add a provider in AI Power Ups settings.\"\n });\n }\n\n const aiSettings = aiSettingsResult.value;\n\n const firstProvider = aiSettings.providers.presets[0];\n\n if (!firstProvider) {\n return controller.response.done({\n message: \"No AI provider configured. Add a provider in AI Power Ups settings.\"\n });\n }\n\n let tags: string[] = [];\n let description = \"\";\n try {\n const aiResult = await this.ai.generateText({\n model: firstProvider.model,\n output: aiOutputSchema,\n connection: {\n sdkName: firstProvider.model.split(\"/\")[0],\n apiKey: await this.encryption.decrypt(firstProvider.apiKeyEncrypted)\n },\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n image: new URL(imageUrl)\n },\n {\n type: \"text\",\n text: AI_PROMPT\n }\n ]\n }\n ]\n });\n\n tags = aiResult.output.tags;\n description = aiResult.output.description;\n } catch (error) {\n console.log(\"error\", error.message);\n return controller.response.error({\n message: `AI enrichment failed: ${error instanceof Error ? error.message : String(error)}`\n });\n }\n\n const mergedTags = [...new Set([...file.tags, ...tags])];\n\n const updateResult = await this.updateFile.execute({\n id: file.id,\n tags: mergedTags,\n description\n });\n\n if (updateResult.isFail()) {\n return controller.response.error({\n message: `Failed to update file: ${updateResult.error.message}`\n });\n }\n\n if (this.websocketService) {\n const connectionsResult = await this.websocketService.listConnections();\n if (connectionsResult.isOk() && connectionsResult.value.length > 0) {\n await this.websocketService.sendToConnections(connectionsResult.value, {\n action: \"fm.file.enrichment\",\n data: {\n id: file.id,\n tags: mergedTags,\n description\n }\n });\n }\n }\n\n return controller.response.done(\"AI image enrichment completed successfully.\");\n }\n}\n\nexport const AiImageEnrichmentTask = TaskDefinition.createImplementation({\n implementation: AiImageEnrichmentTaskImpl,\n dependencies: [\n GetFileUseCase,\n FmGetSettingsUseCase,\n UpdateFileUseCase,\n Ai,\n GetSettingsUseCase,\n Encryption,\n [WebsocketService, { optional: true }]\n ]\n});\n"],"names":["AI_IMAGE_ENRICHMENT_TASK_ID","AI_PROMPT","aiOutputSchema","Output","z","AiImageEnrichmentTaskImpl","getFile","fmSettings","updateFile","ai","getSettings","encryption","websocketService","input","controller","fileResult","file","settingsResult","srcPrefix","imageUrl","aiSettingsResult","aiSettings","firstProvider","tags","description","aiResult","URL","error","console","Error","String","mergedTags","Set","updateResult","connectionsResult","AiImageEnrichmentTask","TaskDefinition","GetFileUseCase","FmGetSettingsUseCase","UpdateFileUseCase","Ai","GetSettingsUseCase","Encryption","WebsocketService"],"mappings":";;;;;;;;;;AAWO,MAAMA,8BAA8B;AAE3C,MAAMC,YACF;AAEJ,MAAMC,iBAAiBC,OAAO,MAAM,CAAC;IACjC,QAAQC,EAAE,MAAM,CAAC;QACb,MAAMA,EAAE,KAAK,CAACA,EAAE,MAAM;QACtB,aAAaA,EAAE,MAAM;IACzB;AACJ;AAMA,MAAMC;IAUF,YACYC,OAAiC,EACjCC,UAA0C,EAC1CC,UAAuC,EACvCC,EAAgB,EAChBC,WAAyC,EACzCC,UAAgC,EAChCC,gBAA6C,CACvD;aAPUN,OAAO,GAAPA;aACAC,UAAU,GAAVA;aACAC,UAAU,GAAVA;aACAC,EAAE,GAAFA;aACAC,WAAW,GAAXA;aACAC,UAAU,GAAVA;aACAC,gBAAgB,GAAhBA;aAhBZ,EAAE,GAAGZ;aACL,KAAK,GAAG;aACR,WAAW,GAAG;aACd,aAAa,GAAG;aAChB,SAAS,GAAG;aACZ,YAAY,GAAG;aAEC,WAAW,GAAG;YAAC;YAAsB;SAAmB;IAUrE;IAEH,MAAM,IAAI,EACNa,KAAK,EACLC,UAAU,EAC0C,EAEtD;QACE,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAGtC,MAAMC,aAAa,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAACF,MAAM,MAAM;QAC1D,IAAIE,WAAW,MAAM,IACjB,OAAOD,WAAW,QAAQ,CAAC,KAAK,CAAC;YAC7B,SAAS,CAAC,gBAAgB,EAAED,MAAM,MAAM,EAAE;QAC9C;QAGJ,MAAMG,OAAOD,WAAW,KAAK;QAE7B,IAAI,CAACC,KAAK,IAAI,CAAC,UAAU,CAAC,WACtB,OAAOF,WAAW,QAAQ,CAAC,IAAI,CAAC;QAGpC,MAAMG,iBAAiB,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;QACpD,MAAMC,YAAYD,eAAe,IAAI,KAAMA,eAAe,KAAK,CAAC,SAAS,IAAI,KAAM;QACnF,MAAME,WAAW,GAAGD,YAAYF,KAAK,GAAG,EAAE;QAE1C,MAAMI,mBAAmB,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO;QAEvD,IAAIA,iBAAiB,MAAM,IACvB,OAAON,WAAW,QAAQ,CAAC,KAAK,CAAC;YAC7B,SAAS;QACb;QAGJ,MAAMO,aAAaD,iBAAiB,KAAK;QAEzC,MAAME,gBAAgBD,WAAW,SAAS,CAAC,OAAO,CAAC,EAAE;QAErD,IAAI,CAACC,eACD,OAAOR,WAAW,QAAQ,CAAC,IAAI,CAAC;YAC5B,SAAS;QACb;QAGJ,IAAIS,OAAiB,EAAE;QACvB,IAAIC,cAAc;QAClB,IAAI;YACA,MAAMC,WAAW,MAAM,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC;gBACxC,OAAOH,cAAc,KAAK;gBAC1B,QAAQpB;gBACR,YAAY;oBACR,SAASoB,cAAc,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;oBAC1C,QAAQ,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAACA,cAAc,eAAe;gBACvE;gBACA,UAAU;oBACN;wBACI,MAAM;wBACN,SAAS;4BACL;gCACI,MAAM;gCACN,OAAO,IAAII,IAAIP;4BACnB;4BACA;gCACI,MAAM;gCACN,MAAMlB;4BACV;yBACH;oBACL;iBACH;YACL;YAEAsB,OAAOE,SAAS,MAAM,CAAC,IAAI;YAC3BD,cAAcC,SAAS,MAAM,CAAC,WAAW;QAC7C,EAAE,OAAOE,OAAO;YACZC,QAAQ,GAAG,CAAC,SAASD,MAAM,OAAO;YAClC,OAAOb,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAAS,CAAC,sBAAsB,EAAEa,iBAAiBE,QAAQF,MAAM,OAAO,GAAGG,OAAOH,QAAQ;YAC9F;QACJ;QAEA,MAAMI,aAAa;eAAI,IAAIC,IAAI;mBAAIhB,KAAK,IAAI;mBAAKO;aAAK;SAAE;QAExD,MAAMU,eAAe,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAC/C,IAAIjB,KAAK,EAAE;YACX,MAAMe;YACNP;QACJ;QAEA,IAAIS,aAAa,MAAM,IACnB,OAAOnB,WAAW,QAAQ,CAAC,KAAK,CAAC;YAC7B,SAAS,CAAC,uBAAuB,EAAEmB,aAAa,KAAK,CAAC,OAAO,EAAE;QACnE;QAGJ,IAAI,IAAI,CAAC,gBAAgB,EAAE;YACvB,MAAMC,oBAAoB,MAAM,IAAI,CAAC,gBAAgB,CAAC,eAAe;YACrE,IAAIA,kBAAkB,IAAI,MAAMA,kBAAkB,KAAK,CAAC,MAAM,GAAG,GAC7D,MAAM,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAACA,kBAAkB,KAAK,EAAE;gBACnE,QAAQ;gBACR,MAAM;oBACF,IAAIlB,KAAK,EAAE;oBACX,MAAMe;oBACNP;gBACJ;YACJ;QAER;QAEA,OAAOV,WAAW,QAAQ,CAAC,IAAI,CAAC;IACpC;AACJ;AAEO,MAAMqB,wBAAwBC,eAAe,oBAAoB,CAAC;IACrE,gBAAgB/B;IAChB,cAAc;QACVgC;QACAC;QACAC;QACAC;QACAC;QACAC;QACA;YAACC;YAAkB;gBAAE,UAAU;YAAK;SAAE;KACzC;AACL"}
1
+ {"version":3,"file":"api/features/AiImageEnrichment/AiImageEnrichmentTask.js","sources":["../../../../src/api/features/AiImageEnrichment/AiImageEnrichmentTask.ts"],"sourcesContent":["import { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { Ai } from \"@webiny/api-core/features/ai/index.js\";\nimport { ApplyImageEnrichmentUseCase, PrepareImageEnrichmentUseCase } from \"./abstractions.js\";\nimport { buildEnrichmentAiRequest } from \"./buildEnrichmentAiRequest.js\";\nimport { EnrichmentNotAnImageError } from \"./errors.js\";\n\nexport const AI_IMAGE_ENRICHMENT_TASK_ID = \"fmAiImageEnrichment\";\n\nexport interface IAiImageEnrichmentTaskInput {\n fileId: string;\n}\n\n/**\n * Background enrichment, triggered after a file is created. Shares its preparation and persistence\n * with the streaming HTTP route (`AiImageEnrichmentStreamRoute`); the only difference is that this\n * one waits for the whole AI response, because a background task has no one to stream to.\n */\nclass AiImageEnrichmentTaskImpl implements TaskDefinition.Interface<IAiImageEnrichmentTaskInput> {\n id = AI_IMAGE_ENRICHMENT_TASK_ID;\n title = \"File Manager - AI Image Enrichment\";\n description = \"Automatically enriches uploaded images with AI-generated tags and description.\";\n maxIterations = 1;\n isPrivate = true;\n databaseLogs = false;\n\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n constructor(\n private prepare: PrepareImageEnrichmentUseCase.Interface,\n private apply: ApplyImageEnrichmentUseCase.Interface,\n private ai: Ai.Interface\n ) {}\n\n async run({\n input,\n controller\n }: TaskDefinition.RunParams<IAiImageEnrichmentTaskInput>): Promise<\n TaskDefinition.Result<IAiImageEnrichmentTaskInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const preparedResult = await this.prepare.execute(input.fileId);\n if (preparedResult.isFail()) {\n const error = preparedResult.error;\n // A non-image isn't a failure — nothing to enrich, so the task is simply done.\n if (error instanceof EnrichmentNotAnImageError) {\n return controller.response.done(error.message);\n }\n return controller.response.error({ message: error.message });\n }\n\n const prepared = preparedResult.value;\n\n let tags: string[];\n let description: string;\n try {\n const request = buildEnrichmentAiRequest(prepared);\n const aiResult = await this.ai.generateText(request);\n\n tags = aiResult.output.tags;\n description = aiResult.output.description;\n } catch (error) {\n return controller.response.error({\n message: `AI enrichment failed: ${error instanceof Error ? error.message : String(error)}`\n });\n }\n\n const appliedResult = await this.apply.execute({\n fileId: prepared.fileId,\n tags,\n description\n });\n\n if (appliedResult.isFail()) {\n return controller.response.error({ message: appliedResult.error.message });\n }\n\n return controller.response.done(\"AI image enrichment completed successfully.\");\n }\n}\n\nexport const AiImageEnrichmentTask = TaskDefinition.createImplementation({\n implementation: AiImageEnrichmentTaskImpl,\n dependencies: [PrepareImageEnrichmentUseCase, ApplyImageEnrichmentUseCase, Ai]\n});\n"],"names":["AI_IMAGE_ENRICHMENT_TASK_ID","AiImageEnrichmentTaskImpl","prepare","apply","ai","input","controller","preparedResult","error","EnrichmentNotAnImageError","prepared","tags","description","request","buildEnrichmentAiRequest","aiResult","Error","String","appliedResult","AiImageEnrichmentTask","TaskDefinition","PrepareImageEnrichmentUseCase","ApplyImageEnrichmentUseCase","Ai"],"mappings":";;;;;AAMO,MAAMA,8BAA8B;AAW3C,MAAMC;IAUF,YACYC,OAAgD,EAChDC,KAA4C,EAC5CC,EAAgB,CAC1B;aAHUF,OAAO,GAAPA;aACAC,KAAK,GAALA;aACAC,EAAE,GAAFA;aAZZ,EAAE,GAAGJ;aACL,KAAK,GAAG;aACR,WAAW,GAAG;aACd,aAAa,GAAG;aAChB,SAAS,GAAG;aACZ,YAAY,GAAG;aAEC,WAAW,GAAG;YAAC;YAAsB;SAAmB;IAMrE;IAEH,MAAM,IAAI,EACNK,KAAK,EACLC,UAAU,EAC0C,EAEtD;QACE,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAGtC,MAAMC,iBAAiB,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAACF,MAAM,MAAM;QAC9D,IAAIE,eAAe,MAAM,IAAI;YACzB,MAAMC,QAAQD,eAAe,KAAK;YAElC,IAAIC,iBAAiBC,2BACjB,OAAOH,WAAW,QAAQ,CAAC,IAAI,CAACE,MAAM,OAAO;YAEjD,OAAOF,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAASE,MAAM,OAAO;YAAC;QAC9D;QAEA,MAAME,WAAWH,eAAe,KAAK;QAErC,IAAII;QACJ,IAAIC;QACJ,IAAI;YACA,MAAMC,UAAUC,yBAAyBJ;YACzC,MAAMK,WAAW,MAAM,IAAI,CAAC,EAAE,CAAC,YAAY,CAACF;YAE5CF,OAAOI,SAAS,MAAM,CAAC,IAAI;YAC3BH,cAAcG,SAAS,MAAM,CAAC,WAAW;QAC7C,EAAE,OAAOP,OAAO;YACZ,OAAOF,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAAS,CAAC,sBAAsB,EAAEE,iBAAiBQ,QAAQR,MAAM,OAAO,GAAGS,OAAOT,QAAQ;YAC9F;QACJ;QAEA,MAAMU,gBAAgB,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YAC3C,QAAQR,SAAS,MAAM;YACvBC;YACAC;QACJ;QAEA,IAAIM,cAAc,MAAM,IACpB,OAAOZ,WAAW,QAAQ,CAAC,KAAK,CAAC;YAAE,SAASY,cAAc,KAAK,CAAC,OAAO;QAAC;QAG5E,OAAOZ,WAAW,QAAQ,CAAC,IAAI,CAAC;IACpC;AACJ;AAEO,MAAMa,wBAAwBC,eAAe,oBAAoB,CAAC;IACrE,gBAAgBnB;IAChB,cAAc;QAACoB;QAA+BC;QAA6BC;KAAG;AAClF"}
@@ -0,0 +1,18 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
3
+ import { WebsocketsSendToIdentityUseCase } from "@webiny/api-websockets/features/SendToIdentity/abstractions.js";
4
+ import { IdentityContext } from "@webiny/api-core/exports/api/security.js";
5
+ import { ApplyImageEnrichmentUseCase as UseCaseAbstraction, type IApplyImageEnrichmentParams, type IAppliedImageEnrichment } from "./abstractions.js";
6
+ import type { ImageEnrichmentError } from "./errors.js";
7
+ export declare const FILE_ENRICHMENT_WEBSOCKET_ACTION = "fm.file.enrichment";
8
+ declare class ApplyImageEnrichmentUseCaseImpl implements UseCaseAbstraction.Interface {
9
+ private updateFile;
10
+ private identityContext;
11
+ private sendToIdentity;
12
+ constructor(updateFile: UpdateFileUseCase.Interface, identityContext: IdentityContext.Interface, sendToIdentity: WebsocketsSendToIdentityUseCase.Interface);
13
+ execute(params: IApplyImageEnrichmentParams): Promise<Result<IAppliedImageEnrichment, ImageEnrichmentError>>;
14
+ }
15
+ export declare const ApplyImageEnrichmentUseCase: typeof ApplyImageEnrichmentUseCaseImpl & {
16
+ __abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IApplyImageEnrichmentUseCase>;
17
+ };
18
+ export {};
@@ -0,0 +1,50 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
3
+ import { WebsocketsSendToIdentityUseCase } from "@webiny/api-websockets/features/SendToIdentity/abstractions.js";
4
+ import { IdentityContext } from "@webiny/api-core/exports/api/security.js";
5
+ import { ApplyImageEnrichmentUseCase } from "./abstractions.js";
6
+ import { EnrichmentPersistError } from "./errors.js";
7
+ const FILE_ENRICHMENT_WEBSOCKET_ACTION = "fm.file.enrichment";
8
+ class ApplyImageEnrichmentUseCaseImpl {
9
+ constructor(updateFile, identityContext, sendToIdentity){
10
+ this.updateFile = updateFile;
11
+ this.identityContext = identityContext;
12
+ this.sendToIdentity = sendToIdentity;
13
+ }
14
+ async execute(params) {
15
+ const { tags, description, fileId } = params;
16
+ const updateResult = await this.updateFile.execute({
17
+ id: fileId,
18
+ tags,
19
+ description
20
+ });
21
+ if (updateResult.isFail()) return Result.fail(new EnrichmentPersistError(updateResult.error.message));
22
+ const identity = this.identityContext.getIdentity();
23
+ await this.sendToIdentity.execute({
24
+ id: identity.id
25
+ }, {
26
+ action: FILE_ENRICHMENT_WEBSOCKET_ACTION,
27
+ data: {
28
+ id: fileId,
29
+ tags,
30
+ description
31
+ }
32
+ });
33
+ return Result.ok({
34
+ fileId,
35
+ tags,
36
+ description
37
+ });
38
+ }
39
+ }
40
+ const ApplyImageEnrichmentUseCase_ApplyImageEnrichmentUseCase = ApplyImageEnrichmentUseCase.createImplementation({
41
+ implementation: ApplyImageEnrichmentUseCaseImpl,
42
+ dependencies: [
43
+ UpdateFileUseCase,
44
+ IdentityContext,
45
+ WebsocketsSendToIdentityUseCase
46
+ ]
47
+ });
48
+ export { ApplyImageEnrichmentUseCase_ApplyImageEnrichmentUseCase as ApplyImageEnrichmentUseCase, FILE_ENRICHMENT_WEBSOCKET_ACTION };
49
+
50
+ //# sourceMappingURL=ApplyImageEnrichmentUseCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.js","sources":["../../../../src/api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { UpdateFileUseCase } from \"@webiny/api-file-manager/features/file/UpdateFile/index.js\";\nimport { WebsocketsSendToIdentityUseCase } from \"@webiny/api-websockets/features/SendToIdentity/abstractions.js\";\nimport { IdentityContext } from \"@webiny/api-core/exports/api/security.js\";\nimport {\n ApplyImageEnrichmentUseCase as UseCaseAbstraction,\n type IApplyImageEnrichmentParams,\n type IAppliedImageEnrichment\n} from \"./abstractions.js\";\nimport { EnrichmentPersistError } from \"./errors.js\";\nimport type { ImageEnrichmentError } from \"./errors.js\";\n\nexport const FILE_ENRICHMENT_WEBSOCKET_ACTION = \"fm.file.enrichment\";\n\nclass ApplyImageEnrichmentUseCaseImpl implements UseCaseAbstraction.Interface {\n constructor(\n private updateFile: UpdateFileUseCase.Interface,\n private identityContext: IdentityContext.Interface,\n private sendToIdentity: WebsocketsSendToIdentityUseCase.Interface\n ) {}\n\n async execute(\n params: IApplyImageEnrichmentParams\n ): Promise<Result<IAppliedImageEnrichment, ImageEnrichmentError>> {\n // Enrichment REPLACES both fields. Tags used to be merged into the file's existing ones while\n // the description was overwritten, which is an odd split: re-running would accumulate tags\n // forever, so a wrong tag from an earlier run could never be dropped by re-running.\n const { tags, description, fileId } = params;\n\n const updateResult = await this.updateFile.execute({\n id: fileId,\n tags,\n description\n });\n\n if (updateResult.isFail()) {\n return Result.fail(new EnrichmentPersistError(updateResult.error.message));\n }\n\n // Push to the identity's open sockets even when the caller is streaming: the browser tab that\n // triggered this isn't necessarily the only one showing the file, and the client-side list\n // cache updates off this message (see AiImageEnrichmentEventHandler in @webiny/app-file-manager).\n const identity = this.identityContext.getIdentity();\n await this.sendToIdentity.execute(\n { id: identity.id },\n {\n action: FILE_ENRICHMENT_WEBSOCKET_ACTION,\n data: { id: fileId, tags, description }\n }\n );\n\n return Result.ok({ fileId, tags, description });\n }\n}\n\nexport const ApplyImageEnrichmentUseCase = UseCaseAbstraction.createImplementation({\n implementation: ApplyImageEnrichmentUseCaseImpl,\n dependencies: [UpdateFileUseCase, IdentityContext, WebsocketsSendToIdentityUseCase]\n});\n"],"names":["FILE_ENRICHMENT_WEBSOCKET_ACTION","ApplyImageEnrichmentUseCaseImpl","updateFile","identityContext","sendToIdentity","params","tags","description","fileId","updateResult","Result","EnrichmentPersistError","identity","ApplyImageEnrichmentUseCase","UseCaseAbstraction","UpdateFileUseCase","IdentityContext","WebsocketsSendToIdentityUseCase"],"mappings":";;;;;;AAYO,MAAMA,mCAAmC;AAEhD,MAAMC;IACF,YACYC,UAAuC,EACvCC,eAA0C,EAC1CC,cAAyD,CACnE;aAHUF,UAAU,GAAVA;aACAC,eAAe,GAAfA;aACAC,cAAc,GAAdA;IACT;IAEH,MAAM,QACFC,MAAmC,EAC2B;QAI9D,MAAM,EAAEC,IAAI,EAAEC,WAAW,EAAEC,MAAM,EAAE,GAAGH;QAEtC,MAAMI,eAAe,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAC/C,IAAID;YACJF;YACAC;QACJ;QAEA,IAAIE,aAAa,MAAM,IACnB,OAAOC,OAAO,IAAI,CAAC,IAAIC,uBAAuBF,aAAa,KAAK,CAAC,OAAO;QAM5E,MAAMG,WAAW,IAAI,CAAC,eAAe,CAAC,WAAW;QACjD,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAC7B;YAAE,IAAIA,SAAS,EAAE;QAAC,GAClB;YACI,QAAQZ;YACR,MAAM;gBAAE,IAAIQ;gBAAQF;gBAAMC;YAAY;QAC1C;QAGJ,OAAOG,OAAO,EAAE,CAAC;YAAEF;YAAQF;YAAMC;QAAY;IACjD;AACJ;AAEO,MAAMM,0DAA8BC,4BAAAA,oBAAuC,CAAC;IAC/E,gBAAgBb;IAChB,cAAc;QAACc;QAAmBC;QAAiBC;KAAgC;AACvF"}
@@ -0,0 +1,19 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { Encryption } from "@webiny/api-core/features/encryption/index.js";
3
+ import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
4
+ import { GetFileContentsByIdUseCase } from "@webiny/api-file-manager/features/file/GetFileContentsById/abstractions.js";
5
+ import { PrepareImageEnrichmentUseCase as UseCaseAbstraction, type IPreparedImageEnrichment } from "./abstractions.js";
6
+ import { GetSettingsUseCase } from "../../../api/features/GetSettings/index.js";
7
+ import type { ImageEnrichmentError } from "./errors.js";
8
+ declare class PrepareImageEnrichmentUseCaseImpl implements UseCaseAbstraction.Interface {
9
+ private getFile;
10
+ private getFileContents;
11
+ private getSettings;
12
+ private encryption;
13
+ constructor(getFile: GetFileUseCase.Interface, getFileContents: GetFileContentsByIdUseCase.Interface, getSettings: GetSettingsUseCase.Interface, encryption: Encryption.Interface);
14
+ execute(fileId: string): Promise<Result<IPreparedImageEnrichment, ImageEnrichmentError>>;
15
+ }
16
+ export declare const PrepareImageEnrichmentUseCase: typeof PrepareImageEnrichmentUseCaseImpl & {
17
+ __abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IPrepareImageEnrichmentUseCase>;
18
+ };
19
+ export {};
@@ -0,0 +1,49 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { Encryption } from "@webiny/api-core/features/encryption/index.js";
3
+ import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
4
+ import { GetFileContentsByIdUseCase } from "@webiny/api-file-manager/features/file/GetFileContentsById/abstractions.js";
5
+ import { PrepareImageEnrichmentUseCase } from "./abstractions.js";
6
+ import { GetSettingsUseCase } from "../GetSettings/index.js";
7
+ import { EnrichmentFileContentsError, EnrichmentFileNotFoundError, EnrichmentNoProviderError, EnrichmentNotAnImageError } from "./errors.js";
8
+ class PrepareImageEnrichmentUseCaseImpl {
9
+ constructor(getFile, getFileContents, getSettings, encryption){
10
+ this.getFile = getFile;
11
+ this.getFileContents = getFileContents;
12
+ this.getSettings = getSettings;
13
+ this.encryption = encryption;
14
+ }
15
+ async execute(fileId) {
16
+ const fileResult = await this.getFile.execute(fileId);
17
+ if (fileResult.isFail()) return Result.fail(new EnrichmentFileNotFoundError(fileId));
18
+ const file = fileResult.value;
19
+ if (!file.type.startsWith("image/")) return Result.fail(new EnrichmentNotAnImageError(file.type));
20
+ const contentsResult = await this.getFileContents.execute(fileId);
21
+ if (contentsResult.isFail()) return Result.fail(new EnrichmentFileContentsError(contentsResult.error.message));
22
+ const aiSettingsResult = await this.getSettings.execute();
23
+ if (aiSettingsResult.isFail()) return Result.fail(new EnrichmentNoProviderError());
24
+ const firstProvider = aiSettingsResult.value.providers.presets[0];
25
+ if (!firstProvider) return Result.fail(new EnrichmentNoProviderError());
26
+ return Result.ok({
27
+ fileId: file.id,
28
+ imageBase64: contentsResult.value.buffer.toString("base64"),
29
+ imageMediaType: contentsResult.value.contentType,
30
+ model: firstProvider.model,
31
+ connection: {
32
+ sdkName: firstProvider.model.split("/")[0],
33
+ apiKey: await this.encryption.decrypt(firstProvider.apiKeyEncrypted)
34
+ }
35
+ });
36
+ }
37
+ }
38
+ const PrepareImageEnrichmentUseCase_PrepareImageEnrichmentUseCase = PrepareImageEnrichmentUseCase.createImplementation({
39
+ implementation: PrepareImageEnrichmentUseCaseImpl,
40
+ dependencies: [
41
+ GetFileUseCase,
42
+ GetFileContentsByIdUseCase,
43
+ GetSettingsUseCase,
44
+ Encryption
45
+ ]
46
+ });
47
+ export { PrepareImageEnrichmentUseCase_PrepareImageEnrichmentUseCase as PrepareImageEnrichmentUseCase };
48
+
49
+ //# sourceMappingURL=PrepareImageEnrichmentUseCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.js","sources":["../../../../src/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { Encryption } from \"@webiny/api-core/features/encryption/index.js\";\nimport { GetFileUseCase } from \"@webiny/api-file-manager/features/file/GetFile/index.js\";\nimport { GetFileContentsByIdUseCase } from \"@webiny/api-file-manager/features/file/GetFileContentsById/abstractions.js\";\nimport {\n PrepareImageEnrichmentUseCase as UseCaseAbstraction,\n type IPreparedImageEnrichment\n} from \"./abstractions.js\";\nimport { GetSettingsUseCase } from \"~/api/features/GetSettings/index.js\";\nimport {\n EnrichmentFileContentsError,\n EnrichmentFileNotFoundError,\n EnrichmentNoProviderError,\n EnrichmentNotAnImageError\n} from \"./errors.js\";\nimport type { ImageEnrichmentError } from \"./errors.js\";\n\nclass PrepareImageEnrichmentUseCaseImpl implements UseCaseAbstraction.Interface {\n constructor(\n private getFile: GetFileUseCase.Interface,\n private getFileContents: GetFileContentsByIdUseCase.Interface,\n private getSettings: GetSettingsUseCase.Interface,\n private encryption: Encryption.Interface\n ) {}\n\n async execute(fileId: string): Promise<Result<IPreparedImageEnrichment, ImageEnrichmentError>> {\n const fileResult = await this.getFile.execute(fileId);\n if (fileResult.isFail()) {\n return Result.fail(new EnrichmentFileNotFoundError(fileId));\n }\n\n const file = fileResult.value;\n\n if (!file.type.startsWith(\"image/\")) {\n return Result.fail(new EnrichmentNotAnImageError(file.type));\n }\n\n // Read the image bytes and send them to the AI as base64, NOT a URL. A URL forces the\n // provider to fetch the file — which fails for private/access-controlled files, leaks the\n // domain, and can't reach a non-public origin (e.g. local dev). base64 is a portable standard\n // that works on every setup. (Also resolves the AI-SDK \"image part\" deprecation.)\n const contentsResult = await this.getFileContents.execute(fileId);\n if (contentsResult.isFail()) {\n return Result.fail(new EnrichmentFileContentsError(contentsResult.error.message));\n }\n\n const aiSettingsResult = await this.getSettings.execute();\n if (aiSettingsResult.isFail()) {\n return Result.fail(new EnrichmentNoProviderError());\n }\n\n const firstProvider = aiSettingsResult.value.providers.presets[0];\n if (!firstProvider) {\n return Result.fail(new EnrichmentNoProviderError());\n }\n\n return Result.ok({\n fileId: file.id,\n imageBase64: contentsResult.value.buffer.toString(\"base64\"),\n imageMediaType: contentsResult.value.contentType,\n model: firstProvider.model,\n connection: {\n sdkName: firstProvider.model.split(\"/\")[0],\n apiKey: await this.encryption.decrypt(firstProvider.apiKeyEncrypted)\n }\n });\n }\n}\n\nexport const PrepareImageEnrichmentUseCase = UseCaseAbstraction.createImplementation({\n implementation: PrepareImageEnrichmentUseCaseImpl,\n dependencies: [GetFileUseCase, GetFileContentsByIdUseCase, GetSettingsUseCase, Encryption]\n});\n"],"names":["PrepareImageEnrichmentUseCaseImpl","getFile","getFileContents","getSettings","encryption","fileId","fileResult","Result","EnrichmentFileNotFoundError","file","EnrichmentNotAnImageError","contentsResult","EnrichmentFileContentsError","aiSettingsResult","EnrichmentNoProviderError","firstProvider","PrepareImageEnrichmentUseCase","UseCaseAbstraction","GetFileUseCase","GetFileContentsByIdUseCase","GetSettingsUseCase","Encryption"],"mappings":";;;;;;;AAiBA,MAAMA;IACF,YACYC,OAAiC,EACjCC,eAAqD,EACrDC,WAAyC,EACzCC,UAAgC,CAC1C;aAJUH,OAAO,GAAPA;aACAC,eAAe,GAAfA;aACAC,WAAW,GAAXA;aACAC,UAAU,GAAVA;IACT;IAEH,MAAM,QAAQC,MAAc,EAAmE;QAC3F,MAAMC,aAAa,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAACD;QAC9C,IAAIC,WAAW,MAAM,IACjB,OAAOC,OAAO,IAAI,CAAC,IAAIC,4BAA4BH;QAGvD,MAAMI,OAAOH,WAAW,KAAK;QAE7B,IAAI,CAACG,KAAK,IAAI,CAAC,UAAU,CAAC,WACtB,OAAOF,OAAO,IAAI,CAAC,IAAIG,0BAA0BD,KAAK,IAAI;QAO9D,MAAME,iBAAiB,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAACN;QAC1D,IAAIM,eAAe,MAAM,IACrB,OAAOJ,OAAO,IAAI,CAAC,IAAIK,4BAA4BD,eAAe,KAAK,CAAC,OAAO;QAGnF,MAAME,mBAAmB,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO;QACvD,IAAIA,iBAAiB,MAAM,IACvB,OAAON,OAAO,IAAI,CAAC,IAAIO;QAG3B,MAAMC,gBAAgBF,iBAAiB,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;QACjE,IAAI,CAACE,eACD,OAAOR,OAAO,IAAI,CAAC,IAAIO;QAG3B,OAAOP,OAAO,EAAE,CAAC;YACb,QAAQE,KAAK,EAAE;YACf,aAAaE,eAAe,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;YAClD,gBAAgBA,eAAe,KAAK,CAAC,WAAW;YAChD,OAAOI,cAAc,KAAK;YAC1B,YAAY;gBACR,SAASA,cAAc,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;gBAC1C,QAAQ,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAACA,cAAc,eAAe;YACvE;QACJ;IACJ;AACJ;AAEO,MAAMC,8DAAgCC,8BAAAA,oBAAuC,CAAC;IACjF,gBAAgBjB;IAChB,cAAc;QAACkB;QAAgBC;QAA4BC;QAAoBC;KAAW;AAC9F"}
@@ -0,0 +1,60 @@
1
+ import { Result } from "@webiny/feature/api";
2
+ import { z } from "zod";
3
+ import type { ImageEnrichmentError } from "./errors.js";
4
+ export declare const AI_ENRICHMENT_PROMPT = "Analyze this image and return up to 5 lowercase descriptive tags and one short sentence describing the image.";
5
+ /**
6
+ * The shape both entry points ask the model for. Exported as the bare zod schema rather than a
7
+ * ready-made `Output.object(...)`: the AI SDK's `Output` type can't be named in emitted declarations
8
+ * (TS4023), so each call site wraps this locally instead.
9
+ */
10
+ export declare const aiEnrichmentSchema: z.ZodObject<{
11
+ tags: z.ZodArray<z.ZodString>;
12
+ description: z.ZodString;
13
+ }, z.core.$strip>;
14
+ /** The enrichment result: what the model produces and what gets persisted. */
15
+ export interface IEnrichmentOutput {
16
+ tags: string[];
17
+ description: string;
18
+ }
19
+ /**
20
+ * Everything needed to run the AI call, gathered up front: the image bytes, the resolved provider,
21
+ * and the file's current tags (needed to merge rather than overwrite).
22
+ *
23
+ * Deliberately split from the AI call itself so both entry points share the same preparation and the
24
+ * same failure modes — and so the streaming route can answer with a real HTTP status code for
25
+ * anything knowable before the stream opens, instead of burying it in a 200 response.
26
+ */
27
+ export interface IPreparedImageEnrichment {
28
+ fileId: string;
29
+ imageBase64: string;
30
+ imageMediaType: string;
31
+ model: string;
32
+ connection: {
33
+ sdkName: string;
34
+ apiKey: string;
35
+ };
36
+ }
37
+ export interface IPrepareImageEnrichmentUseCase {
38
+ execute(fileId: string): Promise<Result<IPreparedImageEnrichment, ImageEnrichmentError>>;
39
+ }
40
+ export declare const PrepareImageEnrichmentUseCase: import("@webiny/di").Abstraction<IPrepareImageEnrichmentUseCase>;
41
+ export declare namespace PrepareImageEnrichmentUseCase {
42
+ type Interface = IPrepareImageEnrichmentUseCase;
43
+ }
44
+ export interface IApplyImageEnrichmentParams {
45
+ fileId: string;
46
+ tags: string[];
47
+ description: string;
48
+ }
49
+ export interface IAppliedImageEnrichment {
50
+ fileId: string;
51
+ tags: string[];
52
+ description: string;
53
+ }
54
+ export interface IApplyImageEnrichmentUseCase {
55
+ execute(params: IApplyImageEnrichmentParams): Promise<Result<IAppliedImageEnrichment, ImageEnrichmentError>>;
56
+ }
57
+ export declare const ApplyImageEnrichmentUseCase: import("@webiny/di").Abstraction<IApplyImageEnrichmentUseCase>;
58
+ export declare namespace ApplyImageEnrichmentUseCase {
59
+ type Interface = IApplyImageEnrichmentUseCase;
60
+ }
@@ -0,0 +1,12 @@
1
+ import { createAbstraction } from "@webiny/feature/api";
2
+ import { z } from "zod";
3
+ const AI_ENRICHMENT_PROMPT = "Analyze this image and return up to 5 lowercase descriptive tags and one short sentence describing the image.";
4
+ const aiEnrichmentSchema = z.object({
5
+ tags: z.array(z.string()),
6
+ description: z.string()
7
+ });
8
+ const PrepareImageEnrichmentUseCase = createAbstraction("PrepareImageEnrichmentUseCase");
9
+ const ApplyImageEnrichmentUseCase = createAbstraction("ApplyImageEnrichmentUseCase");
10
+ export { AI_ENRICHMENT_PROMPT, ApplyImageEnrichmentUseCase, PrepareImageEnrichmentUseCase, aiEnrichmentSchema };
11
+
12
+ //# sourceMappingURL=abstractions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AiImageEnrichment/abstractions.js","sources":["../../../../src/api/features/AiImageEnrichment/abstractions.ts"],"sourcesContent":["import { createAbstraction, Result } from \"@webiny/feature/api\";\nimport { z } from \"zod\";\nimport type { ImageEnrichmentError } from \"./errors.js\";\n\nexport const AI_ENRICHMENT_PROMPT =\n \"Analyze this image and return up to 5 lowercase descriptive tags and one short sentence describing the image.\";\n\n/**\n * The shape both entry points ask the model for. Exported as the bare zod schema rather than a\n * ready-made `Output.object(...)`: the AI SDK's `Output` type can't be named in emitted declarations\n * (TS4023), so each call site wraps this locally instead.\n */\nexport const aiEnrichmentSchema = z.object({\n tags: z.array(z.string()),\n description: z.string()\n});\n\n/** The enrichment result: what the model produces and what gets persisted. */\nexport interface IEnrichmentOutput {\n tags: string[];\n description: string;\n}\n\n/**\n * Everything needed to run the AI call, gathered up front: the image bytes, the resolved provider,\n * and the file's current tags (needed to merge rather than overwrite).\n *\n * Deliberately split from the AI call itself so both entry points share the same preparation and the\n * same failure modes — and so the streaming route can answer with a real HTTP status code for\n * anything knowable before the stream opens, instead of burying it in a 200 response.\n */\nexport interface IPreparedImageEnrichment {\n fileId: string;\n imageBase64: string;\n imageMediaType: string;\n model: string;\n connection: {\n sdkName: string;\n apiKey: string;\n };\n}\n\nexport interface IPrepareImageEnrichmentUseCase {\n execute(fileId: string): Promise<Result<IPreparedImageEnrichment, ImageEnrichmentError>>;\n}\n\nexport const PrepareImageEnrichmentUseCase = createAbstraction<IPrepareImageEnrichmentUseCase>(\n \"PrepareImageEnrichmentUseCase\"\n);\n\nexport namespace PrepareImageEnrichmentUseCase {\n export type Interface = IPrepareImageEnrichmentUseCase;\n}\n\nexport interface IApplyImageEnrichmentParams {\n fileId: string;\n tags: string[];\n description: string;\n}\n\nexport interface IAppliedImageEnrichment {\n fileId: string;\n tags: string[];\n description: string;\n}\n\nexport interface IApplyImageEnrichmentUseCase {\n execute(\n params: IApplyImageEnrichmentParams\n ): Promise<Result<IAppliedImageEnrichment, ImageEnrichmentError>>;\n}\n\nexport const ApplyImageEnrichmentUseCase = createAbstraction<IApplyImageEnrichmentUseCase>(\n \"ApplyImageEnrichmentUseCase\"\n);\n\nexport namespace ApplyImageEnrichmentUseCase {\n export type Interface = IApplyImageEnrichmentUseCase;\n}\n"],"names":["AI_ENRICHMENT_PROMPT","aiEnrichmentSchema","z","PrepareImageEnrichmentUseCase","createAbstraction","ApplyImageEnrichmentUseCase"],"mappings":";;AAIO,MAAMA,uBACT;AAOG,MAAMC,qBAAqBC,EAAE,MAAM,CAAC;IACvC,MAAMA,EAAE,KAAK,CAACA,EAAE,MAAM;IACtB,aAAaA,EAAE,MAAM;AACzB;AA+BO,MAAMC,gCAAgCC,kBACzC;AAyBG,MAAMC,8BAA8BD,kBACvC"}
@@ -0,0 +1,12 @@
1
+ import type { Ai } from "@webiny/api-core/features/ai/index.js";
2
+ import type { IPreparedImageEnrichment } from "./abstractions.js";
3
+ /**
4
+ * Builds the AI request both enrichment entry points send — the background task via `generateText`
5
+ * and the streaming route via `streamText`. Identical model, structured output, connection, and
6
+ * message payload; only the call differs.
7
+ *
8
+ * This is also where `Output.object(...)` lives rather than on `IPreparedImageEnrichment`: the AI
9
+ * SDK's `Output` type can't be named in emitted declarations (TS4023), so it has to be built inside a
10
+ * function body, not held on an exported interface.
11
+ */
12
+ export declare function buildEnrichmentAiRequest(prepared: IPreparedImageEnrichment): Ai.GenerateTextParams;
@@ -0,0 +1,30 @@
1
+ import { Output } from "ai";
2
+ import { AI_ENRICHMENT_PROMPT, aiEnrichmentSchema } from "./abstractions.js";
3
+ function buildEnrichmentAiRequest(prepared) {
4
+ return {
5
+ model: prepared.model,
6
+ output: Output.object({
7
+ schema: aiEnrichmentSchema
8
+ }),
9
+ connection: prepared.connection,
10
+ messages: [
11
+ {
12
+ role: "user",
13
+ content: [
14
+ {
15
+ type: "file",
16
+ data: prepared.imageBase64,
17
+ mediaType: prepared.imageMediaType
18
+ },
19
+ {
20
+ type: "text",
21
+ text: AI_ENRICHMENT_PROMPT
22
+ }
23
+ ]
24
+ }
25
+ ]
26
+ };
27
+ }
28
+ export { buildEnrichmentAiRequest };
29
+
30
+ //# sourceMappingURL=buildEnrichmentAiRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AiImageEnrichment/buildEnrichmentAiRequest.js","sources":["../../../../src/api/features/AiImageEnrichment/buildEnrichmentAiRequest.ts"],"sourcesContent":["import { Output } from \"ai\";\nimport type { Ai } from \"@webiny/api-core/features/ai/index.js\";\nimport { AI_ENRICHMENT_PROMPT, aiEnrichmentSchema } from \"./abstractions.js\";\nimport type { IPreparedImageEnrichment } from \"./abstractions.js\";\n\n/**\n * Builds the AI request both enrichment entry points send — the background task via `generateText`\n * and the streaming route via `streamText`. Identical model, structured output, connection, and\n * message payload; only the call differs.\n *\n * This is also where `Output.object(...)` lives rather than on `IPreparedImageEnrichment`: the AI\n * SDK's `Output` type can't be named in emitted declarations (TS4023), so it has to be built inside a\n * function body, not held on an exported interface.\n */\nexport function buildEnrichmentAiRequest(\n prepared: IPreparedImageEnrichment\n): Ai.GenerateTextParams {\n return {\n model: prepared.model,\n output: Output.object({ schema: aiEnrichmentSchema }),\n connection: prepared.connection,\n messages: [\n {\n role: \"user\",\n content: [\n {\n // Sent as base64, not a URL: a URL forces the provider to fetch the file,\n // which fails for private files and can't reach a non-public origin.\n type: \"file\",\n data: prepared.imageBase64,\n mediaType: prepared.imageMediaType\n },\n {\n type: \"text\",\n text: AI_ENRICHMENT_PROMPT\n }\n ]\n }\n ]\n };\n}\n"],"names":["buildEnrichmentAiRequest","prepared","Output","aiEnrichmentSchema","AI_ENRICHMENT_PROMPT"],"mappings":";;AAcO,SAASA,yBACZC,QAAkC;IAElC,OAAO;QACH,OAAOA,SAAS,KAAK;QACrB,QAAQC,OAAO,MAAM,CAAC;YAAE,QAAQC;QAAmB;QACnD,YAAYF,SAAS,UAAU;QAC/B,UAAU;YACN;gBACI,MAAM;gBACN,SAAS;oBACL;wBAGI,MAAM;wBACN,MAAMA,SAAS,WAAW;wBAC1B,WAAWA,SAAS,cAAc;oBACtC;oBACA;wBACI,MAAM;wBACN,MAAMG;oBACV;iBACH;YACL;SACH;IACL;AACJ"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Errors shared by every image-enrichment entry point (the background task and the streaming HTTP
3
+ * route). Each carries a `code` so callers can map it to their own transport: the task turns them
4
+ * into task results, the route into HTTP status codes.
5
+ */
6
+ export declare class EnrichmentFileNotFoundError extends Error {
7
+ readonly code: "ENRICHMENT_FILE_NOT_FOUND";
8
+ constructor(fileId: string);
9
+ }
10
+ export declare class EnrichmentNotAnImageError extends Error {
11
+ readonly code: "ENRICHMENT_NOT_AN_IMAGE";
12
+ constructor(type: string);
13
+ }
14
+ export declare class EnrichmentFileContentsError extends Error {
15
+ readonly code: "ENRICHMENT_FILE_CONTENTS_UNREADABLE";
16
+ constructor(reason: string);
17
+ }
18
+ export declare class EnrichmentNoProviderError extends Error {
19
+ readonly code: "ENRICHMENT_NO_AI_PROVIDER";
20
+ constructor();
21
+ }
22
+ export declare class EnrichmentPersistError extends Error {
23
+ readonly code: "ENRICHMENT_PERSIST_FAILED";
24
+ constructor(reason: string);
25
+ }
26
+ export type ImageEnrichmentError = EnrichmentFileNotFoundError | EnrichmentNotAnImageError | EnrichmentFileContentsError | EnrichmentNoProviderError | EnrichmentPersistError;
@@ -0,0 +1,28 @@
1
+ class EnrichmentFileNotFoundError extends Error {
2
+ constructor(fileId){
3
+ super(`File not found: ${fileId}`), this.code = "ENRICHMENT_FILE_NOT_FOUND";
4
+ }
5
+ }
6
+ class EnrichmentNotAnImageError extends Error {
7
+ constructor(type){
8
+ super(`File is not an image (received "${type}"); skipping AI enrichment.`), this.code = "ENRICHMENT_NOT_AN_IMAGE";
9
+ }
10
+ }
11
+ class EnrichmentFileContentsError extends Error {
12
+ constructor(reason){
13
+ super(`Unable to read file contents: ${reason}`), this.code = "ENRICHMENT_FILE_CONTENTS_UNREADABLE";
14
+ }
15
+ }
16
+ class EnrichmentNoProviderError extends Error {
17
+ constructor(){
18
+ super("No AI provider configured. Add a provider in AI Power Ups settings."), this.code = "ENRICHMENT_NO_AI_PROVIDER";
19
+ }
20
+ }
21
+ class EnrichmentPersistError extends Error {
22
+ constructor(reason){
23
+ super(`Failed to update file: ${reason}`), this.code = "ENRICHMENT_PERSIST_FAILED";
24
+ }
25
+ }
26
+ export { EnrichmentFileContentsError, EnrichmentFileNotFoundError, EnrichmentNoProviderError, EnrichmentNotAnImageError, EnrichmentPersistError };
27
+
28
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AiImageEnrichment/errors.js","sources":["../../../../src/api/features/AiImageEnrichment/errors.ts"],"sourcesContent":["/**\n * Errors shared by every image-enrichment entry point (the background task and the streaming HTTP\n * route). Each carries a `code` so callers can map it to their own transport: the task turns them\n * into task results, the route into HTTP status codes.\n */\nexport class EnrichmentFileNotFoundError extends Error {\n readonly code = \"ENRICHMENT_FILE_NOT_FOUND\" as const;\n\n constructor(fileId: string) {\n super(`File not found: ${fileId}`);\n }\n}\n\nexport class EnrichmentNotAnImageError extends Error {\n readonly code = \"ENRICHMENT_NOT_AN_IMAGE\" as const;\n\n constructor(type: string) {\n super(`File is not an image (received \"${type}\"); skipping AI enrichment.`);\n }\n}\n\nexport class EnrichmentFileContentsError extends Error {\n readonly code = \"ENRICHMENT_FILE_CONTENTS_UNREADABLE\" as const;\n\n constructor(reason: string) {\n super(`Unable to read file contents: ${reason}`);\n }\n}\n\nexport class EnrichmentNoProviderError extends Error {\n readonly code = \"ENRICHMENT_NO_AI_PROVIDER\" as const;\n\n constructor() {\n super(\"No AI provider configured. Add a provider in AI Power Ups settings.\");\n }\n}\n\nexport class EnrichmentPersistError extends Error {\n readonly code = \"ENRICHMENT_PERSIST_FAILED\" as const;\n\n constructor(reason: string) {\n super(`Failed to update file: ${reason}`);\n }\n}\n\nexport type ImageEnrichmentError =\n | EnrichmentFileNotFoundError\n | EnrichmentNotAnImageError\n | EnrichmentFileContentsError\n | EnrichmentNoProviderError\n | EnrichmentPersistError;\n"],"names":["EnrichmentFileNotFoundError","Error","fileId","EnrichmentNotAnImageError","type","EnrichmentFileContentsError","reason","EnrichmentNoProviderError","EnrichmentPersistError"],"mappings":"AAKO,MAAMA,oCAAoCC;IAG7C,YAAYC,MAAc,CAAE;QACxB,KAAK,CAAC,CAAC,gBAAgB,EAAEA,QAAQ,QAH5B,IAAI,GAAG;IAIhB;AACJ;AAEO,MAAMC,kCAAkCF;IAG3C,YAAYG,IAAY,CAAE;QACtB,KAAK,CAAC,CAAC,gCAAgC,EAAEA,KAAK,2BAA2B,CAAC,QAHrE,IAAI,GAAG;IAIhB;AACJ;AAEO,MAAMC,oCAAoCJ;IAG7C,YAAYK,MAAc,CAAE;QACxB,KAAK,CAAC,CAAC,8BAA8B,EAAEA,QAAQ,QAH1C,IAAI,GAAG;IAIhB;AACJ;AAEO,MAAMC,kCAAkCN;IAG3C,aAAc;QACV,KAAK,CAAC,6EAHD,IAAI,GAAG;IAIhB;AACJ;AAEO,MAAMO,+BAA+BP;IAGxC,YAAYK,MAAc,CAAE;QACxB,KAAK,CAAC,CAAC,uBAAuB,EAAEA,QAAQ,QAHnC,IAAI,GAAG;IAIhB;AACJ"}
@@ -1,11 +1,20 @@
1
1
  import { createFeature } from "@webiny/feature/api";
2
+ import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
2
3
  import { AiImageEnrichmentAfterCreateHandler } from "./AiImageEnrichmentAfterCreateHandler.js";
3
4
  import { AiImageEnrichmentTask } from "./AiImageEnrichmentTask.js";
5
+ import { AiImageEnrichmentStreamRouteDefinition } from "./AiImageEnrichmentStreamRoute.js";
6
+ import { PrepareImageEnrichmentUseCase } from "./PrepareImageEnrichmentUseCase.js";
7
+ import { ApplyImageEnrichmentUseCase } from "./ApplyImageEnrichmentUseCase.js";
4
8
  const AiImageEnrichmentFeature = createFeature({
5
9
  name: "AiPowerUps/AiImageEnrichment",
6
10
  register (container) {
11
+ const enabled = container.resolve(FeatureFlags).get().isEnabled("aiPowerups.fileManager.imageEnrichment");
12
+ if (!enabled) return;
13
+ container.register(PrepareImageEnrichmentUseCase);
14
+ container.register(ApplyImageEnrichmentUseCase);
7
15
  container.register(AiImageEnrichmentAfterCreateHandler);
8
16
  container.register(AiImageEnrichmentTask);
17
+ container.register(AiImageEnrichmentStreamRouteDefinition);
9
18
  }
10
19
  });
11
20
  export { AiImageEnrichmentFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"api/features/AiImageEnrichment/feature.js","sources":["../../../../src/api/features/AiImageEnrichment/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { AiImageEnrichmentAfterCreateHandler } from \"./AiImageEnrichmentAfterCreateHandler.js\";\nimport { AiImageEnrichmentTask } from \"./AiImageEnrichmentTask.js\";\n\nexport const AiImageEnrichmentFeature = createFeature({\n name: \"AiPowerUps/AiImageEnrichment\",\n register(container) {\n container.register(AiImageEnrichmentAfterCreateHandler);\n container.register(AiImageEnrichmentTask);\n }\n});\n"],"names":["AiImageEnrichmentFeature","createFeature","container","AiImageEnrichmentAfterCreateHandler","AiImageEnrichmentTask"],"mappings":";;;AAIO,MAAMA,2BAA2BC,cAAc;IAClD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;QACnBD,UAAU,QAAQ,CAACE;IACvB;AACJ"}
1
+ {"version":3,"file":"api/features/AiImageEnrichment/feature.js","sources":["../../../../src/api/features/AiImageEnrichment/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { FeatureFlags } from \"@webiny/api-core/features/featureFlags/abstractions.js\";\nimport { AiImageEnrichmentAfterCreateHandler } from \"./AiImageEnrichmentAfterCreateHandler.js\";\nimport { AiImageEnrichmentTask } from \"./AiImageEnrichmentTask.js\";\nimport { AiImageEnrichmentStreamRouteDefinition } from \"./AiImageEnrichmentStreamRoute.js\";\nimport { PrepareImageEnrichmentUseCase } from \"./PrepareImageEnrichmentUseCase.js\";\nimport { ApplyImageEnrichmentUseCase } from \"./ApplyImageEnrichmentUseCase.js\";\n\nexport const AiImageEnrichmentFeature = createFeature({\n name: \"AiPowerUps/AiImageEnrichment\",\n register(container) {\n // Register-time gate on the effective feature flags (userFlag && live WCP license). Valid at\n // register() time because the license is refreshed PRE-register (WcpLicenseLoader.load() in\n // registerApiRequestStack) and FeatureFlags reads that process cache — and it re-evaluates per\n // request since the child re-registers, so a license change takes effect on the next request.\n const enabled = container\n .resolve(FeatureFlags)\n .get()\n .isEnabled(\"aiPowerups.fileManager.imageEnrichment\");\n\n if (!enabled) {\n return;\n }\n\n container.register(PrepareImageEnrichmentUseCase);\n container.register(ApplyImageEnrichmentUseCase);\n\n // Automatic enrichment after a file is created.\n container.register(AiImageEnrichmentAfterCreateHandler);\n container.register(AiImageEnrichmentTask);\n\n // On-demand re-enrichment, streamed.\n container.register(AiImageEnrichmentStreamRouteDefinition);\n }\n});\n"],"names":["AiImageEnrichmentFeature","createFeature","container","enabled","FeatureFlags","PrepareImageEnrichmentUseCase","ApplyImageEnrichmentUseCase","AiImageEnrichmentAfterCreateHandler","AiImageEnrichmentTask","AiImageEnrichmentStreamRouteDefinition"],"mappings":";;;;;;;AAQO,MAAMA,2BAA2BC,cAAc;IAClD,MAAM;IACN,UAASC,SAAS;QAKd,MAAMC,UAAUD,UACX,OAAO,CAACE,cACR,GAAG,GACH,SAAS,CAAC;QAEf,IAAI,CAACD,SACD;QAGJD,UAAU,QAAQ,CAACG;QACnBH,UAAU,QAAQ,CAACI;QAGnBJ,UAAU,QAAQ,CAACK;QACnBL,UAAU,QAAQ,CAACM;QAGnBN,UAAU,QAAQ,CAACO;IACvB;AACJ"}
@@ -0,0 +1,6 @@
1
+ import type { ImageEnrichmentError } from "./errors.js";
2
+ /**
3
+ * Maps an enrichment failure to the HTTP status a transport should answer with. Lives next to the
4
+ * errors rather than in a route, so a second entry point can't invent a different mapping.
5
+ */
6
+ export declare function imageEnrichmentErrorStatusCode(error: ImageEnrichmentError): number;
@@ -0,0 +1,9 @@
1
+ import { EnrichmentFileNotFoundError, EnrichmentNotAnImageError } from "./errors.js";
2
+ function imageEnrichmentErrorStatusCode(error) {
3
+ if (error instanceof EnrichmentFileNotFoundError) return 404;
4
+ if (error instanceof EnrichmentNotAnImageError) return 400;
5
+ return 500;
6
+ }
7
+ export { imageEnrichmentErrorStatusCode };
8
+
9
+ //# sourceMappingURL=imageEnrichmentErrorStatusCode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.js","sources":["../../../../src/api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.ts"],"sourcesContent":["import { EnrichmentFileNotFoundError, EnrichmentNotAnImageError } from \"./errors.js\";\nimport type { ImageEnrichmentError } from \"./errors.js\";\n\n/**\n * Maps an enrichment failure to the HTTP status a transport should answer with. Lives next to the\n * errors rather than in a route, so a second entry point can't invent a different mapping.\n */\nexport function imageEnrichmentErrorStatusCode(error: ImageEnrichmentError): number {\n if (error instanceof EnrichmentFileNotFoundError) {\n return 404;\n }\n if (error instanceof EnrichmentNotAnImageError) {\n return 400;\n }\n return 500;\n}\n"],"names":["imageEnrichmentErrorStatusCode","error","EnrichmentFileNotFoundError","EnrichmentNotAnImageError"],"mappings":";AAOO,SAASA,+BAA+BC,KAA2B;IACtE,IAAIA,iBAAiBC,6BACjB,OAAO;IAEX,IAAID,iBAAiBE,2BACjB,OAAO;IAEX,OAAO;AACX"}
@@ -0,0 +1,8 @@
1
+ import type { IEnrichmentOutput } from "./abstractions.js";
2
+ /**
3
+ * Normalises one value from `streamText`'s `partialOutputStream`.
4
+ *
5
+ * Partial output is exactly that: mid-stream the tag array can hold holes/undefined entries and the
6
+ * description may not have arrived, so callers get only the values that are actually present.
7
+ */
8
+ export declare function readEnrichmentPartial(partial: unknown): IEnrichmentOutput;
@@ -0,0 +1,16 @@
1
+ function readEnrichmentPartial(partial) {
2
+ const value = partial ?? {};
3
+ const tags = [];
4
+ if (Array.isArray(value.tags)) {
5
+ for (const tag of value.tags)if ("string" == typeof tag && "" !== tag) tags.push(tag);
6
+ }
7
+ let description = "";
8
+ if ("string" == typeof value.description) description = value.description;
9
+ return {
10
+ tags,
11
+ description
12
+ };
13
+ }
14
+ export { readEnrichmentPartial };
15
+
16
+ //# sourceMappingURL=readEnrichmentPartial.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api/features/AiImageEnrichment/readEnrichmentPartial.js","sources":["../../../../src/api/features/AiImageEnrichment/readEnrichmentPartial.ts"],"sourcesContent":["import type { IEnrichmentOutput } from \"./abstractions.js\";\n\n/**\n * Normalises one value from `streamText`'s `partialOutputStream`.\n *\n * Partial output is exactly that: mid-stream the tag array can hold holes/undefined entries and the\n * description may not have arrived, so callers get only the values that are actually present.\n */\nexport function readEnrichmentPartial(partial: unknown): IEnrichmentOutput {\n const value = (partial ?? {}) as { tags?: unknown; description?: unknown };\n\n const tags: string[] = [];\n\n if (Array.isArray(value.tags)) {\n for (const tag of value.tags) {\n // Empty strings are dropped, not just non-strings: mid-stream the array can hold `\"\"`\n // for an entry the model has opened but not written into yet, which renders as a blank\n // chip.\n if (typeof tag === \"string\" && tag !== \"\") {\n tags.push(tag);\n }\n }\n }\n\n let description = \"\";\n\n if (typeof value.description === \"string\") {\n description = value.description;\n }\n\n return { tags, description };\n}\n"],"names":["readEnrichmentPartial","partial","value","tags","Array","tag","description"],"mappings":"AAQO,SAASA,sBAAsBC,OAAgB;IAClD,MAAMC,QAASD,WAAW,CAAC;IAE3B,MAAME,OAAiB,EAAE;IAEzB,IAAIC,MAAM,OAAO,CAACF,MAAM,IAAI,GACxB;QAAA,KAAK,MAAMG,OAAOH,MAAM,IAAI,CAIxB,IAAI,AAAe,YAAf,OAAOG,OAAoBA,AAAQ,OAARA,KAC3BF,KAAK,IAAI,CAACE;IAElB;IAGJ,IAAIC,cAAc;IAElB,IAAI,AAA6B,YAA7B,OAAOJ,MAAM,WAAW,EACxBI,cAAcJ,MAAM,WAAW;IAGnC,OAAO;QAAEC;QAAMG;IAAY;AAC/B"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Server-sent event payloads emitted by `AiImageEnrichmentStreamRoute` — this feature's stream
3
+ * protocol, not a shared one. The SSE wire format itself (`toSseFrame`) is transport-level and lives
4
+ * in `@webiny/event-handler-core`; what the events are called and what they carry is per feature,
5
+ * since the next streaming route will want a different set.
6
+ *
7
+ * A small domain protocol rather than the AI SDK's UI message stream: the client
8
+ * doesn't render a chat transcript, it renders a progressively-completing `{ tags, description }`
9
+ * object, which is exactly what `streamText`'s `partialOutputStream` produces. The admin app mirrors
10
+ * these types (it can't import an api-side package), so keep the two in sync.
11
+ */
12
+ export interface EnrichmentStreamStartEvent {
13
+ type: "start";
14
+ fileId: string;
15
+ model: string;
16
+ }
17
+ export interface EnrichmentStreamPartialEvent {
18
+ type: "partial";
19
+ tags: string[];
20
+ description: string;
21
+ }
22
+ export interface EnrichmentStreamDoneEvent {
23
+ type: "done";
24
+ fileId: string;
25
+ /**
26
+ * The model's final output. NOT persisted — the streaming route only proposes, and the client
27
+ * saves through the file's normal update path if the user accepts.
28
+ */
29
+ tags: string[];
30
+ description: string;
31
+ }
32
+ export interface EnrichmentStreamErrorEvent {
33
+ type: "error";
34
+ message: string;
35
+ }
36
+ export type EnrichmentStreamEvent = EnrichmentStreamStartEvent | EnrichmentStreamPartialEvent | EnrichmentStreamDoneEvent | EnrichmentStreamErrorEvent;
File without changes
@@ -1,10 +1,17 @@
1
1
  import { GetSettingsUseCase } from "../../../api/features/GetSettings/index.js";
2
+ import { GetFileContentsByIdUseCase } from "@webiny/api-file-manager/features/file/GetFileContentsById/index.js";
3
+ import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
4
+ import { TextExtractor } from "@webiny/api-core/features/ai/index.js";
2
5
  import { AiPromptContextBuilder as Abstraction, ProjectFileAssembler, type AiPromptContext, type AiPromptContextParams } from "./abstractions.js";
3
6
  declare class AiPromptContextBuilderImpl implements Abstraction.Interface {
4
7
  private getSettings;
5
8
  private fileAssembler;
6
- constructor(getSettings: GetSettingsUseCase.Interface, fileAssembler: ProjectFileAssembler.Interface);
9
+ private getFileContents;
10
+ private getFile;
11
+ private textExtractor;
12
+ constructor(getSettings: GetSettingsUseCase.Interface, fileAssembler: ProjectFileAssembler.Interface, getFileContents: GetFileContentsByIdUseCase.Interface, getFile: GetFileUseCase.Interface, textExtractor: TextExtractor.Interface);
7
13
  execute(params: AiPromptContextParams): Promise<AiPromptContext>;
14
+ private fetchAdditionalFiles;
8
15
  }
9
16
  export declare const AiPromptContextBuilder: typeof AiPromptContextBuilderImpl & {
10
17
  __abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IAiPromptContextBuilder>;