@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.
- package/AiPowerups.js +2 -2
- package/AiPowerups.js.map +1 -1
- package/admin/Extension.js +11 -2
- package/admin/Extension.js.map +1 -1
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsGateway.d.ts +12 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsGateway.js +46 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsGateway.js.map +1 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsRepository.d.ts +11 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsRepository.js +18 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsRepository.js.map +1 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsUseCase.d.ts +11 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsUseCase.js +18 -0
- package/admin/features/compareEntryRevisions/CompareEntryRevisionsUseCase.js.map +1 -0
- package/admin/features/compareEntryRevisions/abstractions.d.ts +32 -0
- package/admin/features/compareEntryRevisions/abstractions.js +7 -0
- package/admin/features/compareEntryRevisions/abstractions.js.map +1 -0
- package/admin/features/compareEntryRevisions/feature.d.ts +1 -0
- package/admin/features/compareEntryRevisions/feature.js +15 -0
- package/admin/features/compareEntryRevisions/feature.js.map +1 -0
- package/admin/features/compareEntryRevisions/index.d.ts +2 -0
- package/admin/features/compareEntryRevisions/index.js +2 -0
- package/admin/features/feature.js +2 -0
- package/admin/features/feature.js.map +1 -1
- package/admin/features/generateEntryContent/GenerateEntryContentGateway.d.ts +12 -0
- package/admin/features/generateEntryContent/GenerateEntryContentGateway.js +45 -0
- package/admin/features/generateEntryContent/GenerateEntryContentGateway.js.map +1 -0
- package/admin/features/generateEntryContent/GenerateEntryContentUseCase.d.ts +11 -0
- package/admin/features/generateEntryContent/GenerateEntryContentUseCase.js +18 -0
- package/admin/features/generateEntryContent/GenerateEntryContentUseCase.js.map +1 -0
- package/admin/features/generateEntryContent/abstractions.d.ts +24 -0
- package/admin/features/generateEntryContent/abstractions.js +6 -0
- package/admin/features/generateEntryContent/abstractions.js.map +1 -0
- package/admin/features/generateEntryContent/feature.d.ts +1 -0
- package/admin/features/generateEntryContent/feature.js +13 -0
- package/admin/features/generateEntryContent/feature.js.map +1 -0
- package/admin/features/generateEntryContent/index.d.ts +3 -0
- package/admin/features/generateEntryContent/index.js +2 -0
- package/admin/features/generatePageContent/GeneratePageContentGateway.js +2 -0
- package/admin/features/generatePageContent/GeneratePageContentGateway.js.map +1 -1
- package/admin/features/generatePageContent/abstractions.d.ts +1 -0
- package/admin/features/generatePageContent/abstractions.js.map +1 -1
- package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPage.d.ts +2 -2
- package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPage.js +3 -4
- package/admin/presentation/AiPowerUpsSettings/AiPowerUpsSettingsPage.js.map +1 -1
- package/admin/presentation/AiPromptFormFactory/AiPromptFormFactory.d.ts +20 -0
- package/admin/presentation/AiPromptFormFactory/AiPromptFormFactory.js +108 -0
- package/admin/presentation/AiPromptFormFactory/AiPromptFormFactory.js.map +1 -0
- package/admin/presentation/AiPromptFormFactory/abstractions.d.ts +14 -0
- package/admin/presentation/AiPromptFormFactory/abstractions.js +5 -0
- package/admin/presentation/AiPromptFormFactory/abstractions.js.map +1 -0
- package/admin/presentation/AiPromptFormFactory/feature.d.ts +1 -0
- package/admin/presentation/AiPromptFormFactory/feature.js +11 -0
- package/admin/presentation/AiPromptFormFactory/feature.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDialog.d.ts +9 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDialog.js +118 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDialog.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDrawer.d.ts +9 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDrawer.js +72 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsDrawer.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsMenuItem.d.ts +4 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsMenuItem.js +21 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsMenuItem.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsOverlays.d.ts +2 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsOverlays.js +17 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsOverlays.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsPresenter.d.ts +25 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsPresenter.js +90 -0
- package/admin/presentation/CmsCompareEntryRevisions/CmsCompareEntryRevisionsPresenter.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/Extension.d.ts +2 -0
- package/admin/presentation/CmsCompareEntryRevisions/Extension.js +16 -0
- package/admin/presentation/CmsCompareEntryRevisions/Extension.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/abstractions.d.ts +29 -0
- package/admin/presentation/CmsCompareEntryRevisions/abstractions.js +5 -0
- package/admin/presentation/CmsCompareEntryRevisions/abstractions.js.map +1 -0
- package/admin/presentation/CmsCompareEntryRevisions/feature.d.ts +3 -0
- package/admin/presentation/CmsCompareEntryRevisions/feature.js +17 -0
- package/admin/presentation/CmsCompareEntryRevisions/feature.js.map +1 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.d.ts +4 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.js +27 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentButton.js.map +1 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentDialog.d.ts +5 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentDialog.js +106 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentDialog.js.map +1 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentPresenter.d.ts +29 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentPresenter.js +120 -0
- package/admin/presentation/CmsContentGeneration/CmsGenerateContentPresenter.js.map +1 -0
- package/admin/presentation/CmsContentGeneration/Extension.d.ts +2 -0
- package/admin/presentation/CmsContentGeneration/Extension.js +27 -0
- package/admin/presentation/CmsContentGeneration/Extension.js.map +1 -0
- package/admin/presentation/CmsContentGeneration/abstractions.d.ts +20 -0
- package/admin/presentation/CmsContentGeneration/abstractions.js +5 -0
- package/admin/presentation/CmsContentGeneration/abstractions.js.map +1 -0
- package/admin/presentation/CmsContentGeneration/feature.d.ts +3 -0
- package/admin/presentation/CmsContentGeneration/feature.js +17 -0
- package/admin/presentation/CmsContentGeneration/feature.js.map +1 -0
- package/admin/presentation/CmsEntryWizard/CmsEntryWizard.d.ts +4 -0
- package/admin/presentation/CmsEntryWizard/CmsEntryWizard.js +113 -0
- package/admin/presentation/CmsEntryWizard/CmsEntryWizard.js.map +1 -0
- package/admin/presentation/CmsEntryWizard/CmsEntryWizardGate.d.ts +4 -0
- package/admin/presentation/CmsEntryWizard/CmsEntryWizardGate.js +19 -0
- package/admin/presentation/CmsEntryWizard/CmsEntryWizardGate.js.map +1 -0
- package/admin/presentation/CmsEntryWizard/Extension.d.ts +2 -0
- package/admin/presentation/CmsEntryWizard/Extension.js +10 -0
- package/admin/presentation/CmsEntryWizard/Extension.js.map +1 -0
- package/admin/presentation/ProjectsSettings.js +4 -4
- package/admin/presentation/ProjectsSettings.js.map +1 -1
- package/admin/presentation/ProvidersSettings.js +1 -1
- package/admin/presentation/ProvidersSettings.js.map +1 -1
- package/admin/presentation/WbContentGeneration/GenerateContentDialog.d.ts +2 -2
- package/admin/presentation/WbContentGeneration/GenerateContentDialog.js +2 -2
- package/admin/presentation/WbContentGeneration/GenerateContentDialog.js.map +1 -1
- package/admin/presentation/WbContentGeneration/GenerateContentPresenter.d.ts +4 -12
- package/admin/presentation/WbContentGeneration/GenerateContentPresenter.js +12 -94
- package/admin/presentation/WbContentGeneration/GenerateContentPresenter.js.map +1 -1
- package/api/Extension.js +13 -3
- package/api/Extension.js.map +1 -1
- package/api/features/AiChatProvider/PowerUpsAiChatProvider.d.ts +24 -0
- package/api/features/AiChatProvider/PowerUpsAiChatProvider.js +31 -0
- package/api/features/AiChatProvider/PowerUpsAiChatProvider.js.map +1 -0
- package/api/features/AiChatProvider/feature.d.ts +9 -0
- package/api/features/AiChatProvider/feature.js +11 -0
- package/api/features/AiChatProvider/feature.js.map +1 -0
- package/api/features/AiChatProvider/index.d.ts +2 -0
- package/api/features/AiChatProvider/index.js +2 -0
- package/api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.d.ts +36 -0
- package/api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.js +85 -0
- package/api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.js.map +1 -0
- package/api/features/AiImageEnrichment/AiImageEnrichmentTask.d.ts +10 -14
- package/api/features/AiImageEnrichment/AiImageEnrichmentTask.js +27 -100
- package/api/features/AiImageEnrichment/AiImageEnrichmentTask.js.map +1 -1
- package/api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.d.ts +18 -0
- package/api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.js +50 -0
- package/api/features/AiImageEnrichment/ApplyImageEnrichmentUseCase.js.map +1 -0
- package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.d.ts +19 -0
- package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.js +49 -0
- package/api/features/AiImageEnrichment/PrepareImageEnrichmentUseCase.js.map +1 -0
- package/api/features/AiImageEnrichment/abstractions.d.ts +60 -0
- package/api/features/AiImageEnrichment/abstractions.js +12 -0
- package/api/features/AiImageEnrichment/abstractions.js.map +1 -0
- package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.d.ts +12 -0
- package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.js +30 -0
- package/api/features/AiImageEnrichment/buildEnrichmentAiRequest.js.map +1 -0
- package/api/features/AiImageEnrichment/errors.d.ts +26 -0
- package/api/features/AiImageEnrichment/errors.js +28 -0
- package/api/features/AiImageEnrichment/errors.js.map +1 -0
- package/api/features/AiImageEnrichment/feature.js +9 -0
- package/api/features/AiImageEnrichment/feature.js.map +1 -1
- package/api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.d.ts +6 -0
- package/api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.js +9 -0
- package/api/features/AiImageEnrichment/imageEnrichmentErrorStatusCode.js.map +1 -0
- package/api/features/AiImageEnrichment/readEnrichmentPartial.d.ts +8 -0
- package/api/features/AiImageEnrichment/readEnrichmentPartial.js +16 -0
- package/api/features/AiImageEnrichment/readEnrichmentPartial.js.map +1 -0
- package/api/features/AiImageEnrichment/streamEvents.d.ts +36 -0
- package/api/features/AiImageEnrichment/streamEvents.js +0 -0
- package/api/features/AiPromptContext/AiPromptContextBuilder.d.ts +8 -1
- package/api/features/AiPromptContext/AiPromptContextBuilder.js +46 -2
- package/api/features/AiPromptContext/AiPromptContextBuilder.js.map +1 -1
- package/api/features/AiPromptContext/abstractions.d.ts +3 -0
- package/api/features/AiPromptContext/abstractions.js +9 -1
- package/api/features/AiPromptContext/abstractions.js.map +1 -1
- package/api/features/AiPromptContext/index.d.ts +1 -1
- package/api/features/AiPromptContext/index.js +1 -1
- package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.d.ts +22 -0
- package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.js +136 -0
- package/api/features/CmsCompareEntryRevisions/CmsCompareEntryRevisionsUseCase.js.map +1 -0
- package/api/features/CmsCompareEntryRevisions/abstractions.d.ts +18 -0
- package/api/features/CmsCompareEntryRevisions/abstractions.js +5 -0
- package/api/features/CmsCompareEntryRevisions/abstractions.js.map +1 -0
- package/api/features/CmsCompareEntryRevisions/feature.d.ts +4 -0
- package/api/features/CmsCompareEntryRevisions/feature.js +11 -0
- package/api/features/CmsCompareEntryRevisions/feature.js.map +1 -0
- package/api/features/CmsCompareEntryRevisions/index.d.ts +2 -0
- package/api/features/CmsCompareEntryRevisions/index.js +2 -0
- package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentTask.d.ts +33 -0
- package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentTask.js +84 -0
- package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentTask.js.map +1 -0
- package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.d.ts +29 -0
- package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.js +141 -0
- package/api/features/CmsGenerateEntryContent/CmsGenerateEntryContentUseCase.js.map +1 -0
- package/api/features/CmsGenerateEntryContent/abstractions.d.ts +36 -0
- package/api/features/CmsGenerateEntryContent/abstractions.js +5 -0
- package/api/features/CmsGenerateEntryContent/abstractions.js.map +1 -0
- package/api/features/CmsGenerateEntryContent/buildPrompt.d.ts +2 -0
- package/api/features/CmsGenerateEntryContent/buildPrompt.js +61 -0
- package/api/features/CmsGenerateEntryContent/buildPrompt.js.map +1 -0
- package/api/features/CmsGenerateEntryContent/feature.d.ts +4 -0
- package/api/features/CmsGenerateEntryContent/feature.js +13 -0
- package/api/features/CmsGenerateEntryContent/feature.js.map +1 -0
- package/api/features/CmsGenerateEntryContent/index.d.ts +1 -0
- package/api/features/CmsGenerateEntryContent/index.js +1 -0
- package/api/features/CmsGenerateEntryContent/injectDynamicZoneTypenames.d.ts +2 -0
- package/api/features/CmsGenerateEntryContent/injectDynamicZoneTypenames.js +30 -0
- package/api/features/CmsGenerateEntryContent/injectDynamicZoneTypenames.js.map +1 -0
- package/api/features/CmsResolveImageTool/CmsResolveImageTool.d.ts +14 -0
- package/api/features/CmsResolveImageTool/CmsResolveImageTool.js +27 -0
- package/api/features/CmsResolveImageTool/CmsResolveImageTool.js.map +1 -0
- package/api/features/CmsResolveImageTool/feature.d.ts +4 -0
- package/api/features/CmsResolveImageTool/feature.js +11 -0
- package/api/features/CmsResolveImageTool/feature.js.map +1 -0
- package/api/features/GetSettings/GetSettingsUseCase.d.ts +1 -1
- package/api/features/GetSettings/index.d.ts +1 -0
- package/api/features/GetSettings/index.js +1 -0
- package/api/features/Providers/ProvidersHandler.d.ts +1 -3
- package/api/features/Providers/ProvidersHandler.js +2 -15
- package/api/features/Providers/ProvidersHandler.js.map +1 -1
- package/api/features/Providers/types.d.ts +2 -2
- package/api/features/WbGeneratePageContent/WbGeneratePageContentTask.d.ts +4 -3
- package/api/features/WbGeneratePageContent/WbGeneratePageContentTask.js +25 -15
- package/api/features/WbGeneratePageContent/WbGeneratePageContentTask.js.map +1 -1
- package/api/features/WbGeneratePageContent/WbGeneratePageContentUseCase.js +4 -3
- package/api/features/WbGeneratePageContent/WbGeneratePageContentUseCase.js.map +1 -1
- package/api/features/WbGeneratePageContent/abstractions.d.ts +1 -0
- package/api/features/WbGeneratePageContent/abstractions.js.map +1 -1
- package/api/features/WbTranslatePage/LexicalParser.d.ts +10 -0
- package/api/features/WbTranslatePage/LexicalParser.js +37 -0
- package/api/features/WbTranslatePage/LexicalParser.js.map +1 -0
- package/api/features/WbTranslatePage/WbTranslatePageDecorator.d.ts +27 -0
- package/api/features/WbTranslatePage/WbTranslatePageDecorator.js +134 -0
- package/api/features/WbTranslatePage/WbTranslatePageDecorator.js.map +1 -0
- package/api/features/WbTranslatePage/abstractions/LexicalParser.d.ts +7 -0
- package/api/features/WbTranslatePage/abstractions/LexicalParser.js +5 -0
- package/api/features/WbTranslatePage/abstractions/LexicalParser.js.map +1 -0
- package/api/features/WbTranslatePage/feature.d.ts +4 -0
- package/api/features/WbTranslatePage/feature.js +13 -0
- package/api/features/WbTranslatePage/feature.js.map +1 -0
- package/api/features/WbTranslatePage/index.d.ts +2 -0
- package/api/features/WbTranslatePage/index.js +2 -0
- package/api/graphql/BaseGraphQLSchema.d.ts +2 -2
- package/api/graphql/BaseGraphQLSchema.js +45 -6
- package/api/graphql/BaseGraphQLSchema.js.map +1 -1
- package/api/graphql/CmsCompareEntryRevisionsSchema.d.ts +8 -0
- package/api/graphql/CmsCompareEntryRevisionsSchema.js +68 -0
- package/api/graphql/CmsCompareEntryRevisionsSchema.js.map +1 -0
- package/exports/admin/ai-powerups.d.ts +1 -0
- package/exports/admin/ai-powerups.js +1 -0
- package/exports/api/ai-powerups.d.ts +2 -0
- package/exports/api/ai-powerups.js +2 -0
- package/package.json +33 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin/presentation/WbContentGeneration/GenerateContentPresenter.js","sources":["../../../../src/admin/presentation/WbContentGeneration/GenerateContentPresenter.ts"],"sourcesContent":["import { makeAutoObservable, computed, toJS, runInAction } from \"mobx\";\nimport { z } from \"zod\";\nimport pick from \"lodash/pick.js\";\nimport { FormModelFactory, FormModel, ToolRegistry, ToolPipelineRunner } from \"@webiny/app-admin\";\nimport { GenerateContentPresenter, type CreateElementsFn } from \"./abstractions.js\";\nimport { GeneratePageContentUseCase } from \"~/admin/features/generatePageContent/index.js\";\nimport { GetSettingsUseCase } from \"~/admin/features/settings/getSettings/abstractions.js\";\nimport type { IAiPowerUpsSettings } from \"~/admin/features/settings/shared/abstractions.js\";\n\nconst SUBMIT_TIMEOUT_MS = 300_000;\n\nclass GenerateContentPresenterImpl implements GenerateContentPresenter.Interface {\n private _loading = false;\n private _submitting = false;\n private _processing = false;\n private _timedOut = false;\n private _components: Record<string, any>[] = [];\n private _createElements: CreateElementsFn = () => {};\n private _form: FormModel.Interface | null = null;\n private _settings: IAiPowerUpsSettings | null = null;\n private _timeoutId: ReturnType<typeof setTimeout> | null = null;\n private _intervalId: ReturnType<typeof setInterval> | null = null;\n private _elapsedSeconds = 0;\n\n constructor(\n private toolRegistry: ToolRegistry.Interface,\n private pipelineRunner: ToolPipelineRunner.Interface,\n private generatePageContent: GeneratePageContentUseCase.Interface,\n private formModelFactory: FormModelFactory.Interface,\n private getSettings: GetSettingsUseCase.Interface\n ) {\n makeAutoObservable(this, { vm: computed }, { autoBind: true });\n }\n\n get vm(): GenerateContentPresenter.ViewModel {\n return {\n form: this._form ? this._form.vm : null,\n loading: this._loading,\n submitting: this._submitting,\n processing: this._processing,\n timedOut: this._timedOut,\n elapsedSeconds: this._elapsedSeconds\n };\n }\n\n async init(components: Record<string, any>[], createElements: CreateElementsFn): Promise<void> {\n this._components = components;\n this._createElements = createElements;\n\n this._loading = true;\n\n try {\n const settings = await this.getSettings.execute();\n runInAction(() => {\n this._settings = settings;\n this._form = this.buildForm();\n });\n } finally {\n runInAction(() => {\n this._loading = false;\n });\n }\n }\n\n async submit(): Promise<void> {\n if (!this._form) {\n return;\n }\n\n const data = await this._form.submit<{\n prompt: string;\n project?: string;\n includedFiles?: string[];\n readerPersona?: string;\n writerPersona?: string;\n }>();\n\n if (!data) {\n return;\n }\n\n runInAction(() => {\n this._submitting = true;\n this._timedOut = false;\n });\n\n this.startTimeout();\n\n try {\n const tools = this.toolRegistry.getTools().map(tool => ({\n name: tool.name,\n description: tool.description,\n inputSchema: pick(z.toJSONSchema(tool.inputSchema), [\"properties\", \"type\"]),\n outputSchema: pick(z.toJSONSchema(tool.outputSchema), [\"properties\", \"type\"])\n }));\n\n const excludedFileIds = this.computeExcludedFileIds(data.project, data.includedFiles);\n\n await this.generatePageContent.execute({\n prompt: data.prompt,\n components: toJS(this._components),\n tools,\n projectId: data.project || null,\n excludedFileIds,\n readerPersonaId: data.readerPersona || null,\n writerPersonaId: data.writerPersona || null\n });\n } catch {\n this.clearTimeout();\n runInAction(() => {\n this._submitting = false;\n });\n }\n }\n\n async processAiResponse(responseText: string): Promise<void> {\n this.clearTimeout();\n runInAction(() => {\n this._processing = true;\n this._submitting = false;\n });\n\n try {\n const aiResponseJson = JSON.parse(responseText);\n const resolved = await this.pipelineRunner.resolve(aiResponseJson);\n const items = Array.isArray(resolved) ? resolved : [resolved];\n\n await this._createElements(\n items.map((element: { component: string; inputs: Record<string, unknown> }) => ({\n componentName: element.component,\n parentId: \"root\",\n slot: \"children\",\n bindings: { inputs: element.inputs }\n }))\n );\n } finally {\n runInAction(() => {\n this._processing = false;\n });\n }\n }\n\n cancelPrompt(): void {\n this.clearTimeout();\n this._processing = false;\n this._submitting = false;\n }\n\n private startTimeout(): void {\n this.clearTimeout();\n this._elapsedSeconds = 0;\n this._intervalId = setInterval(() => {\n runInAction(() => {\n this._elapsedSeconds++;\n });\n }, 1000);\n this._timeoutId = setTimeout(() => {\n runInAction(() => {\n this._submitting = false;\n this._timedOut = true;\n });\n this.clearInterval();\n }, SUBMIT_TIMEOUT_MS);\n }\n\n private clearTimeout(): void {\n if (this._timeoutId !== null) {\n clearTimeout(this._timeoutId);\n this._timeoutId = null;\n }\n this.clearInterval();\n }\n\n private clearInterval(): void {\n if (this._intervalId !== null) {\n clearInterval(this._intervalId);\n this._intervalId = null;\n }\n }\n\n private buildForm() {\n return this.formModelFactory.create({\n fields: fields => ({\n project: fields\n .text()\n .label(\"Project\")\n .description(\"Select a predefined context to attach.\")\n .options(() => this.getProjectOptions())\n .afterChange((value, form) => {\n const projectId = value as string | undefined;\n const project = projectId\n ? this._settings?.projects?.presets?.find(p => p.id === projectId)\n : undefined;\n\n if (project?.defaultReaderPersonaId) {\n form.field(\"readerPersona\").setValue(project.defaultReaderPersonaId);\n }\n if (project?.defaultWriterPersonaId) {\n form.field(\"writerPersona\").setValue(project.defaultWriterPersonaId);\n }\n\n const fileIds = (project?.files ?? []).map(f => f.id);\n form.field(\"includedFiles\").setValue(fileIds);\n }),\n includedFiles: fields\n .text()\n .label(\"Files included\")\n .description(\"Uncheck files to exclude them from this generation only.\")\n .options(() => this.getProjectFileOptions())\n .renderer(\"checkboxes\")\n .list()\n .hiddenWhen(form => {\n const projectId = form.field(\"project\").as(\"text\").getValue();\n if (!projectId) {\n return true;\n }\n const project = this._settings?.projects?.presets?.find(\n p => p.id === projectId\n );\n return !project?.files || project.files.length === 0;\n }),\n readerPersona: fields\n .text()\n .label(\"Reader Persona\")\n .description(\"Select the target audience for the generated content.\")\n .options(() => this.getPersonaOptions(\"reader\")),\n writerPersona: fields\n .text()\n .label(\"Writer Persona\")\n .description(\"Select the writing style for the generated content.\")\n .options(() => this.getPersonaOptions(\"writer\")),\n prompt: fields\n .text()\n .label(\"Prompt\")\n .description(\"Describe the page content you want to generate.\")\n .required(\"Prompt is required\")\n .renderer(\"textarea\", { rows: 6 })\n }),\n layout: layout => [\n layout.row(\"project\"),\n layout.row(\"includedFiles\"),\n layout.row(\"readerPersona\"),\n layout.row(\"writerPersona\"),\n layout.row(\"prompt\")\n ]\n });\n }\n\n private getSelectedProject() {\n if (!this._form || !this._settings) {\n return undefined;\n }\n const projectId = this._form.field(\"project\").getValue<string>();\n if (!projectId) {\n return undefined;\n }\n return this._settings.projects?.presets?.find(p => p.id === projectId);\n }\n\n private getProjectFileOptions() {\n const project = this.getSelectedProject();\n const files = project?.files;\n if (!files || files.length === 0) {\n return [];\n }\n return files.map(f => ({\n label: f.name,\n value: f.id\n }));\n }\n\n private computeExcludedFileIds(projectId?: string, includedFiles?: string[]): string[] | null {\n if (!projectId) {\n return null;\n }\n const project = this._settings?.projects?.presets?.find(p => p.id === projectId);\n const allFileIds = (project?.files ?? []).map(f => f.id);\n if (allFileIds.length === 0) {\n return null;\n }\n const included = new Set(includedFiles ?? []);\n const excluded = allFileIds.filter(id => !included.has(id));\n return excluded.length > 0 ? excluded : null;\n }\n\n private getProjectOptions() {\n const presets = this._settings?.projects?.presets;\n if (!presets || presets.length === 0) {\n return [];\n }\n return presets.map(preset => ({\n label: preset.name,\n value: preset.id\n }));\n }\n\n private getPersonaOptions(type: \"reader\" | \"writer\") {\n const presets =\n type === \"reader\"\n ? this._settings?.readerPersonas?.presets\n : this._settings?.writerPersonas?.presets;\n\n if (!presets || presets.length === 0) {\n return [];\n }\n\n return presets.map(preset => ({\n label: preset.name,\n value: preset.id\n }));\n }\n}\n\nexport const GenerateContentPresenterRegistration = GenerateContentPresenter.createImplementation({\n implementation: GenerateContentPresenterImpl,\n dependencies: [\n ToolRegistry,\n ToolPipelineRunner,\n GeneratePageContentUseCase,\n FormModelFactory,\n GetSettingsUseCase\n ]\n});\n"],"names":["SUBMIT_TIMEOUT_MS","GenerateContentPresenterImpl","toolRegistry","pipelineRunner","generatePageContent","formModelFactory","getSettings","makeAutoObservable","computed","components","createElements","settings","runInAction","data","tools","tool","pick","z","excludedFileIds","toJS","responseText","aiResponseJson","JSON","resolved","items","Array","element","setInterval","setTimeout","clearTimeout","clearInterval","fields","value","form","projectId","project","p","undefined","fileIds","f","layout","files","includedFiles","allFileIds","included","Set","excluded","id","presets","preset","type","GenerateContentPresenterRegistration","GenerateContentPresenter","ToolRegistry","ToolPipelineRunner","GeneratePageContentUseCase","FormModelFactory","GetSettingsUseCase"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin/presentation/WbContentGeneration/GenerateContentPresenter.js","sources":["../../../../src/admin/presentation/WbContentGeneration/GenerateContentPresenter.ts"],"sourcesContent":["import { makeAutoObservable, computed, toJS, runInAction } from \"mobx\";\nimport { z } from \"zod\";\nimport pick from \"lodash/pick.js\";\nimport { ToolRegistry, ToolPipelineRunner } from \"@webiny/app-admin\";\nimport type { FormModel } from \"@webiny/app-admin\";\nimport type { FileValue } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport { GenerateContentPresenter, type CreateElementsFn } from \"./abstractions.js\";\nimport { GeneratePageContentUseCase } from \"~/admin/features/generatePageContent/index.js\";\nimport { AiPromptFormFactory } from \"~/admin/presentation/AiPromptFormFactory/abstractions.js\";\n\nconst SUBMIT_TIMEOUT_MS = 300_000;\n\nclass GenerateContentPresenterImpl implements GenerateContentPresenter.Interface {\n private _loading = false;\n private _submitting = false;\n private _processing = false;\n private _timedOut = false;\n private _components: Record<string, any>[] = [];\n private _createElements: CreateElementsFn = () => {};\n private _form: FormModel.Interface | null = null;\n private _timeoutId: ReturnType<typeof setTimeout> | null = null;\n private _intervalId: ReturnType<typeof setInterval> | null = null;\n private _elapsedSeconds = 0;\n\n constructor(\n private toolRegistry: ToolRegistry.Interface,\n private pipelineRunner: ToolPipelineRunner.Interface,\n private generatePageContent: GeneratePageContentUseCase.Interface,\n private formFactory: AiPromptFormFactory.Interface\n ) {\n makeAutoObservable(this, { vm: computed }, { autoBind: true });\n }\n\n get vm(): GenerateContentPresenter.ViewModel {\n return {\n form: this._form ? this._form.vm : null,\n loading: this._loading,\n submitting: this._submitting,\n processing: this._processing,\n timedOut: this._timedOut,\n elapsedSeconds: this._elapsedSeconds\n };\n }\n\n async init(components: Record<string, any>[], createElements: CreateElementsFn): Promise<void> {\n this._components = components;\n this._createElements = createElements;\n\n this._form = this.formFactory.createForm({\n promptDescription: \"Describe the page content you want to generate.\"\n });\n }\n\n async submit(): Promise<void> {\n if (!this._form) {\n return;\n }\n\n const data = await this._form.submit<{\n prompt: string;\n project?: string;\n includedFiles?: string[];\n readerPersona?: string;\n writerPersona?: string;\n additionalFiles?: FileValue[];\n }>();\n\n if (!data) {\n return;\n }\n\n runInAction(() => {\n this._submitting = true;\n this._timedOut = false;\n });\n\n this.startTimeout();\n\n try {\n const tools = this.toolRegistry.getTools().map(tool => ({\n name: tool.name,\n description: tool.description,\n inputSchema: pick(z.toJSONSchema(tool.inputSchema), [\"properties\", \"type\"]),\n outputSchema: pick(z.toJSONSchema(tool.outputSchema), [\"properties\", \"type\"])\n }));\n\n const excludedFileIds = this.formFactory.computeExcludedFileIds(this._form);\n const additionalFileIds = data.additionalFiles?.map(f => f.id) ?? null;\n\n await this.generatePageContent.execute({\n prompt: data.prompt,\n components: toJS(this._components),\n tools,\n projectId: data.project || null,\n excludedFileIds,\n readerPersonaId: data.readerPersona || null,\n writerPersonaId: data.writerPersona || null,\n additionalFileIds\n });\n } catch {\n this.clearTimeout();\n runInAction(() => {\n this._submitting = false;\n });\n }\n }\n\n async processAiResponse(responseText: string): Promise<void> {\n this.clearTimeout();\n runInAction(() => {\n this._processing = true;\n this._submitting = false;\n });\n\n try {\n const aiResponseJson = JSON.parse(responseText);\n const resolved = await this.pipelineRunner.resolve(aiResponseJson);\n const items = Array.isArray(resolved) ? resolved : [resolved];\n\n await this._createElements(\n items.map((element: { component: string; inputs: Record<string, unknown> }) => ({\n componentName: element.component,\n parentId: \"root\",\n slot: \"children\",\n bindings: { inputs: element.inputs }\n }))\n );\n } finally {\n runInAction(() => {\n this._processing = false;\n });\n }\n }\n\n cancelPrompt(): void {\n this.clearTimeout();\n this._processing = false;\n this._submitting = false;\n }\n\n private startTimeout(): void {\n this.clearTimeout();\n this._elapsedSeconds = 0;\n this._intervalId = setInterval(() => {\n runInAction(() => {\n this._elapsedSeconds++;\n });\n }, 1000);\n this._timeoutId = setTimeout(() => {\n runInAction(() => {\n this._submitting = false;\n this._timedOut = true;\n });\n this.clearInterval();\n }, SUBMIT_TIMEOUT_MS);\n }\n\n private clearTimeout(): void {\n if (this._timeoutId !== null) {\n clearTimeout(this._timeoutId);\n this._timeoutId = null;\n }\n this.clearInterval();\n }\n\n private clearInterval(): void {\n if (this._intervalId !== null) {\n clearInterval(this._intervalId);\n this._intervalId = null;\n }\n }\n}\n\nexport const GenerateContentPresenterRegistration = GenerateContentPresenter.createImplementation({\n implementation: GenerateContentPresenterImpl,\n dependencies: [\n ToolRegistry,\n ToolPipelineRunner,\n GeneratePageContentUseCase,\n AiPromptFormFactory\n ]\n});\n"],"names":["SUBMIT_TIMEOUT_MS","GenerateContentPresenterImpl","toolRegistry","pipelineRunner","generatePageContent","formFactory","makeAutoObservable","computed","components","createElements","data","runInAction","tools","tool","pick","z","excludedFileIds","additionalFileIds","f","toJS","responseText","aiResponseJson","JSON","resolved","items","Array","element","setInterval","setTimeout","clearTimeout","clearInterval","GenerateContentPresenterRegistration","GenerateContentPresenter","ToolRegistry","ToolPipelineRunner","GeneratePageContentUseCase","AiPromptFormFactory"],"mappings":"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"}
|
package/api/Extension.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createFeature } from "@webiny/feature/api";
|
|
2
|
-
import { WcpContext } from "@webiny/api-core/features/wcp/WcpContext/index.js";
|
|
3
2
|
import { BaseGraphQLSchema } from "./graphql/BaseGraphQLSchema.js";
|
|
4
3
|
import AiPowerUpsSettingsGraphQLMapper from "./graphql/AiPowerUpsSettingsGraphQLMapper.js";
|
|
5
4
|
import { AiPowerUpsSettingsCache } from "./features/shared/SettingsCache.js";
|
|
@@ -13,6 +12,12 @@ import { ProjectsFeature } from "./features/Projects/feature.js";
|
|
|
13
12
|
import { AiPromptContextFeature } from "./features/AiPromptContext/feature.js";
|
|
14
13
|
import { AiImageEnrichmentFeature } from "./features/AiImageEnrichment/feature.js";
|
|
15
14
|
import { ExtractFrontmatterFeature } from "./features/ExtractFrontmatter/feature.js";
|
|
15
|
+
import { CmsGenerateEntryContentFeature } from "./features/CmsGenerateEntryContent/feature.js";
|
|
16
|
+
import { CmsResolveImageToolFeature } from "./features/CmsResolveImageTool/feature.js";
|
|
17
|
+
import { AiChatProviderFeature } from "./features/AiChatProvider/index.js";
|
|
18
|
+
import { CmsCompareEntryRevisionsFeature } from "./features/CmsCompareEntryRevisions/feature.js";
|
|
19
|
+
import { WbTranslatePageFeature } from "./features/WbTranslatePage/feature.js";
|
|
20
|
+
import { CmsCompareEntryRevisionsSchema } from "./graphql/CmsCompareEntryRevisionsSchema.js";
|
|
16
21
|
const Extension = createFeature({
|
|
17
22
|
name: "AiPowerUps",
|
|
18
23
|
register (container) {
|
|
@@ -25,11 +30,16 @@ const Extension = createFeature({
|
|
|
25
30
|
ProjectsFeature.register(container);
|
|
26
31
|
AiPromptContextFeature.register(container);
|
|
27
32
|
WbGeneratePageContentFeature.register(container);
|
|
33
|
+
CmsGenerateEntryContentFeature.register(container);
|
|
34
|
+
CmsResolveImageToolFeature.register(container);
|
|
35
|
+
AiChatProviderFeature.register(container);
|
|
28
36
|
ExtractFrontmatterFeature.register(container);
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
AiImageEnrichmentFeature.register(container);
|
|
38
|
+
CmsCompareEntryRevisionsFeature.register(container);
|
|
39
|
+
WbTranslatePageFeature.register(container);
|
|
31
40
|
container.register(AiPowerUpsSettingsGraphQLMapper).inSingletonScope();
|
|
32
41
|
container.register(BaseGraphQLSchema);
|
|
42
|
+
container.register(CmsCompareEntryRevisionsSchema);
|
|
33
43
|
}
|
|
34
44
|
});
|
|
35
45
|
export { Extension };
|
package/api/Extension.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api/Extension.js","sources":["../../src/api/Extension.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport {
|
|
1
|
+
{"version":3,"file":"api/Extension.js","sources":["../../src/api/Extension.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { BaseGraphQLSchema } from \"./graphql/BaseGraphQLSchema.js\";\nimport AiPowerUpsSettingsGraphQLMapperImpl from \"./graphql/AiPowerUpsSettingsGraphQLMapper.js\";\nimport { AiPowerUpsSettingsCache } from \"./features/shared/SettingsCache.js\";\nimport { GetSettingsFeature } from \"./features/GetSettings/feature.js\";\nimport { UpdateSettingsFeature } from \"./features/UpdateSettings/feature.js\";\nimport { WbGeneratePageContentFeature } from \"./features/WbGeneratePageContent/feature.js\";\nimport { ProvidersFeature } from \"./features/Providers/feature.js\";\nimport { ReaderPersonasFeature } from \"./features/ReaderPersonas/feature.js\";\nimport { WriterPersonasFeature } from \"./features/WriterPersonas/feature.js\";\nimport { ProjectsFeature } from \"./features/Projects/feature.js\";\nimport { AiPromptContextFeature } from \"./features/AiPromptContext/feature.js\";\nimport { AiImageEnrichmentFeature } from \"./features/AiImageEnrichment/feature.js\";\nimport { ExtractFrontmatterFeature } from \"./features/ExtractFrontmatter/feature.js\";\nimport { CmsGenerateEntryContentFeature } from \"./features/CmsGenerateEntryContent/feature.js\";\nimport { CmsResolveImageToolFeature } from \"./features/CmsResolveImageTool/feature.js\";\nimport { AiChatProviderFeature } from \"./features/AiChatProvider/index.js\";\nimport { CmsCompareEntryRevisionsFeature } from \"./features/CmsCompareEntryRevisions/feature.js\";\nimport { WbTranslatePageFeature } from \"./features/WbTranslatePage/feature.js\";\nimport { CmsCompareEntryRevisionsSchema } from \"./graphql/CmsCompareEntryRevisionsSchema.js\";\n\nexport const Extension = createFeature({\n name: \"AiPowerUps\",\n register(container) {\n container.register(AiPowerUpsSettingsCache).inSingletonScope();\n\n GetSettingsFeature.register(container);\n UpdateSettingsFeature.register(container);\n ProvidersFeature.register(container);\n ReaderPersonasFeature.register(container);\n WriterPersonasFeature.register(container);\n ProjectsFeature.register(container);\n AiPromptContextFeature.register(container);\n WbGeneratePageContentFeature.register(container);\n CmsGenerateEntryContentFeature.register(container);\n CmsResolveImageToolFeature.register(container);\n AiChatProviderFeature.register(container);\n ExtractFrontmatterFeature.register(container);\n\n // Registered unconditionally. The WCP license gate lives inside the feature's\n // FileAfterCreate handler (trigger-time), because the license isn't loaded yet during this\n // register() phase — a register-time canUse* check reads NullLicense and is always false.\n AiImageEnrichmentFeature.register(container);\n\n CmsCompareEntryRevisionsFeature.register(container);\n WbTranslatePageFeature.register(container);\n\n container.register(AiPowerUpsSettingsGraphQLMapperImpl).inSingletonScope();\n container.register(BaseGraphQLSchema);\n container.register(CmsCompareEntryRevisionsSchema);\n }\n});\n"],"names":["Extension","createFeature","container","AiPowerUpsSettingsCache","GetSettingsFeature","UpdateSettingsFeature","ProvidersFeature","ReaderPersonasFeature","WriterPersonasFeature","ProjectsFeature","AiPromptContextFeature","WbGeneratePageContentFeature","CmsGenerateEntryContentFeature","CmsResolveImageToolFeature","AiChatProviderFeature","ExtractFrontmatterFeature","AiImageEnrichmentFeature","CmsCompareEntryRevisionsFeature","WbTranslatePageFeature","AiPowerUpsSettingsGraphQLMapperImpl","BaseGraphQLSchema","CmsCompareEntryRevisionsSchema"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBO,MAAMA,YAAYC,cAAc;IACnC,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,yBAAyB,gBAAgB;QAE5DC,mBAAmB,QAAQ,CAACF;QAC5BG,sBAAsB,QAAQ,CAACH;QAC/BI,iBAAiB,QAAQ,CAACJ;QAC1BK,sBAAsB,QAAQ,CAACL;QAC/BM,sBAAsB,QAAQ,CAACN;QAC/BO,gBAAgB,QAAQ,CAACP;QACzBQ,uBAAuB,QAAQ,CAACR;QAChCS,6BAA6B,QAAQ,CAACT;QACtCU,+BAA+B,QAAQ,CAACV;QACxCW,2BAA2B,QAAQ,CAACX;QACpCY,sBAAsB,QAAQ,CAACZ;QAC/Ba,0BAA0B,QAAQ,CAACb;QAKnCc,yBAAyB,QAAQ,CAACd;QAElCe,gCAAgC,QAAQ,CAACf;QACzCgB,uBAAuB,QAAQ,CAAChB;QAEhCA,UAAU,QAAQ,CAACiB,iCAAqC,gBAAgB;QACxEjB,UAAU,QAAQ,CAACkB;QACnBlB,UAAU,QAAQ,CAACmB;IACvB;AACJ"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AiChatProvider as Abstraction } from "@webiny/ai-chat/api/index.js";
|
|
2
|
+
import type { IAiChatProviderResolution } from "@webiny/ai-chat/api/index.js";
|
|
3
|
+
import { Encryption } from "@webiny/api-core/features/encryption/index.js";
|
|
4
|
+
import { GetSettingsUseCase } from "../../../api/features/GetSettings/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* Runs the assistant on the provider configured in AI Power-Ups settings.
|
|
7
|
+
*
|
|
8
|
+
* Overrides the environment-variable default so the model and its key are managed where every other
|
|
9
|
+
* AI feature in the project already manages them — in the admin UI, per tenant, with the key
|
|
10
|
+
* encrypted at rest. Same source `CmsGenerateEntryContent` and `CmsCompareEntryRevisions` read.
|
|
11
|
+
*
|
|
12
|
+
* Uses the FIRST configured provider, matching the other AI Power-Ups use cases. Picking per-feature
|
|
13
|
+
* providers is a settings design question, not something to invent here.
|
|
14
|
+
*/
|
|
15
|
+
declare class PowerUpsAiChatProviderImpl implements Abstraction.Interface {
|
|
16
|
+
private readonly getSettings;
|
|
17
|
+
private readonly encryption;
|
|
18
|
+
constructor(getSettings: GetSettingsUseCase.Interface, encryption: Encryption.Interface);
|
|
19
|
+
resolve(): Promise<IAiChatProviderResolution>;
|
|
20
|
+
}
|
|
21
|
+
export declare const PowerUpsAiChatProvider: typeof PowerUpsAiChatProviderImpl & {
|
|
22
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/ai-chat/api/abstractions").IAiChatProvider>;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AiChatProvider } from "@webiny/ai-chat/api/index.js";
|
|
2
|
+
import { Encryption } from "@webiny/api-core/features/encryption/index.js";
|
|
3
|
+
import { GetSettingsUseCase } from "../GetSettings/index.js";
|
|
4
|
+
class PowerUpsAiChatProviderImpl {
|
|
5
|
+
constructor(getSettings, encryption){
|
|
6
|
+
this.getSettings = getSettings;
|
|
7
|
+
this.encryption = encryption;
|
|
8
|
+
}
|
|
9
|
+
async resolve() {
|
|
10
|
+
const settingsResult = await this.getSettings.execute();
|
|
11
|
+
if (settingsResult.isFail()) throw new Error("Failed to load AI Power Ups settings.");
|
|
12
|
+
const provider = settingsResult.value.providers.presets[0];
|
|
13
|
+
if (!provider) throw new Error("No AI provider configured. Add one under Settings → AI Power-Ups → Providers.");
|
|
14
|
+
if (!provider.model) throw new Error(`The AI provider "${provider.name}" has no model selected. Pick one under Settings → AI Power-Ups → Providers.`);
|
|
15
|
+
if (!provider.apiKeyEncrypted) throw new Error(`The AI provider "${provider.name}" has no API key. Add one under Settings → AI Power-Ups → Providers.`);
|
|
16
|
+
return {
|
|
17
|
+
model: provider.model,
|
|
18
|
+
apiKey: await this.encryption.decrypt(provider.apiKeyEncrypted)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const PowerUpsAiChatProvider = AiChatProvider.createImplementation({
|
|
23
|
+
implementation: PowerUpsAiChatProviderImpl,
|
|
24
|
+
dependencies: [
|
|
25
|
+
GetSettingsUseCase,
|
|
26
|
+
Encryption
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
export { PowerUpsAiChatProvider };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=PowerUpsAiChatProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api/features/AiChatProvider/PowerUpsAiChatProvider.js","sources":["../../../../src/api/features/AiChatProvider/PowerUpsAiChatProvider.ts"],"sourcesContent":["import { AiChatProvider as Abstraction } from \"@webiny/ai-chat/api/index.js\";\nimport type { IAiChatProviderResolution } from \"@webiny/ai-chat/api/index.js\";\nimport { Encryption } from \"@webiny/api-core/features/encryption/index.js\";\nimport { GetSettingsUseCase } from \"~/api/features/GetSettings/index.js\";\n\n/**\n * Runs the assistant on the provider configured in AI Power-Ups settings.\n *\n * Overrides the environment-variable default so the model and its key are managed where every other\n * AI feature in the project already manages them — in the admin UI, per tenant, with the key\n * encrypted at rest. Same source `CmsGenerateEntryContent` and `CmsCompareEntryRevisions` read.\n *\n * Uses the FIRST configured provider, matching the other AI Power-Ups use cases. Picking per-feature\n * providers is a settings design question, not something to invent here.\n */\nclass PowerUpsAiChatProviderImpl implements Abstraction.Interface {\n constructor(\n private readonly getSettings: GetSettingsUseCase.Interface,\n private readonly encryption: Encryption.Interface\n ) {}\n\n async resolve(): Promise<IAiChatProviderResolution> {\n const settingsResult = await this.getSettings.execute();\n\n if (settingsResult.isFail()) {\n throw new Error(\"Failed to load AI Power Ups settings.\");\n }\n\n const provider = settingsResult.value.providers.presets[0];\n\n if (!provider) {\n throw new Error(\n \"No AI provider configured. Add one under Settings → AI Power-Ups → Providers.\"\n );\n }\n\n if (!provider.model) {\n throw new Error(\n `The AI provider \"${provider.name}\" has no model selected. Pick one under Settings → AI Power-Ups → Providers.`\n );\n }\n\n /*\n * A row can exist before a key is entered. Erroring here is deliberate: falling back to an\n * environment variable when a provider IS configured is what made the previous behaviour so\n * hard to reason about — the settings screen said one thing and the request used another.\n */\n if (!provider.apiKeyEncrypted) {\n throw new Error(\n `The AI provider \"${provider.name}\" has no API key. Add one under Settings → AI Power-Ups → Providers.`\n );\n }\n\n return {\n model: provider.model,\n apiKey: await this.encryption.decrypt(provider.apiKeyEncrypted)\n };\n }\n}\n\nexport const PowerUpsAiChatProvider = Abstraction.createImplementation({\n implementation: PowerUpsAiChatProviderImpl,\n dependencies: [GetSettingsUseCase, Encryption]\n});\n"],"names":["PowerUpsAiChatProviderImpl","getSettings","encryption","settingsResult","Error","provider","PowerUpsAiChatProvider","Abstraction","GetSettingsUseCase","Encryption"],"mappings":";;;AAeA,MAAMA;IACF,YACqBC,WAAyC,EACzCC,UAAgC,CACnD;aAFmBD,WAAW,GAAXA;aACAC,UAAU,GAAVA;IAClB;IAEH,MAAM,UAA8C;QAChD,MAAMC,iBAAiB,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO;QAErD,IAAIA,eAAe,MAAM,IACrB,MAAM,IAAIC,MAAM;QAGpB,MAAMC,WAAWF,eAAe,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;QAE1D,IAAI,CAACE,UACD,MAAM,IAAID,MACN;QAIR,IAAI,CAACC,SAAS,KAAK,EACf,MAAM,IAAID,MACN,CAAC,iBAAiB,EAAEC,SAAS,IAAI,CAAC,4EAA4E,CAAC;QASvH,IAAI,CAACA,SAAS,eAAe,EACzB,MAAM,IAAID,MACN,CAAC,iBAAiB,EAAEC,SAAS,IAAI,CAAC,oEAAoE,CAAC;QAI/G,OAAO;YACH,OAAOA,SAAS,KAAK;YACrB,QAAQ,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAACA,SAAS,eAAe;QAClE;IACJ;AACJ;AAEO,MAAMC,yBAAyBC,eAAAA,oBAAgC,CAAC;IACnE,gBAAgBP;IAChB,cAAc;QAACQ;QAAoBC;KAAW;AAClD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Points the admin AI assistant at the providers configured in AI Power-Ups.
|
|
3
|
+
*
|
|
4
|
+
* Registered after `AiChatFeature`'s environment default so this one wins.
|
|
5
|
+
*/
|
|
6
|
+
export declare const AiChatProviderFeature: {
|
|
7
|
+
name: string;
|
|
8
|
+
register(container: import("@webiny/di").Container): void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { PowerUpsAiChatProvider } from "./PowerUpsAiChatProvider.js";
|
|
3
|
+
const AiChatProviderFeature = createFeature({
|
|
4
|
+
name: "AiPowerUps/AiChatProvider",
|
|
5
|
+
register (container) {
|
|
6
|
+
container.register(PowerUpsAiChatProvider);
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
export { AiChatProviderFeature };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api/features/AiChatProvider/feature.js","sources":["../../../../src/api/features/AiChatProvider/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { PowerUpsAiChatProvider } from \"./PowerUpsAiChatProvider.js\";\n\n/**\n * Points the admin AI assistant at the providers configured in AI Power-Ups.\n *\n * Registered after `AiChatFeature`'s environment default so this one wins.\n */\nexport const AiChatProviderFeature = createFeature({\n name: \"AiPowerUps/AiChatProvider\",\n register(container) {\n container.register(PowerUpsAiChatProvider);\n }\n});\n"],"names":["AiChatProviderFeature","createFeature","container","PowerUpsAiChatProvider"],"mappings":";;AAQO,MAAMA,wBAAwBC,cAAc;IAC/C,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { HttpRouteDefinition, HttpRouteHandler } from "@webiny/event-handler-core";
|
|
2
|
+
import type { IHttpRequest, IHttpResponseBuilder } from "@webiny/event-handler-core";
|
|
3
|
+
import { Ai } from "@webiny/api-core/features/ai/index.js";
|
|
4
|
+
import { PrepareImageEnrichmentUseCase } from "./abstractions.js";
|
|
5
|
+
/**
|
|
6
|
+
* Re-runs AI enrichment for a single file, streaming the model's output to the caller as
|
|
7
|
+
* server-sent events. Read-only: the result is a proposal the caller can accept or discard.
|
|
8
|
+
*
|
|
9
|
+
* Preparation (file lookup, image read, provider resolution) happens BEFORE the response opens, so
|
|
10
|
+
* anything knowable up front — missing file, wrong type, no provider — comes back as a real status
|
|
11
|
+
* code. Only the AI call itself streams; once the first byte is out the status is committed to 200
|
|
12
|
+
* and failures can only be reported as an `error` event.
|
|
13
|
+
*/
|
|
14
|
+
declare class AiImageEnrichmentStreamRouteImpl implements HttpRouteHandler.Interface {
|
|
15
|
+
private prepare;
|
|
16
|
+
private ai;
|
|
17
|
+
constructor(prepare: PrepareImageEnrichmentUseCase.Interface, ai: Ai.Interface);
|
|
18
|
+
handle(request: IHttpRequest, response: IHttpResponseBuilder): Promise<IHttpResponseBuilder>;
|
|
19
|
+
private enrich;
|
|
20
|
+
}
|
|
21
|
+
export declare const AiImageEnrichmentStreamRoute: typeof AiImageEnrichmentStreamRouteImpl & {
|
|
22
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRoute>;
|
|
23
|
+
};
|
|
24
|
+
declare class AiImageEnrichmentStreamRouteDefinitionImpl implements HttpRouteDefinition.Interface {
|
|
25
|
+
readonly name = "ai-image-enrichment-stream";
|
|
26
|
+
readonly method = "POST";
|
|
27
|
+
readonly path = "/stream/fm/files/:fileId/enrich";
|
|
28
|
+
readonly handler: typeof AiImageEnrichmentStreamRouteImpl & {
|
|
29
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRoute>;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** What the router matches on. Zero dependencies, so building it costs nothing. */
|
|
33
|
+
export declare const AiImageEnrichmentStreamRouteDefinition: typeof AiImageEnrichmentStreamRouteDefinitionImpl & {
|
|
34
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/event-handler-core").IHttpRouteDefinition>;
|
|
35
|
+
};
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { HttpRouteDefinition, HttpRouteHandler, toSseFrame } from "@webiny/event-handler-core";
|
|
2
|
+
import { Ai } from "@webiny/api-core/features/ai/index.js";
|
|
3
|
+
import { PrepareImageEnrichmentUseCase } from "./abstractions.js";
|
|
4
|
+
import { buildEnrichmentAiRequest } from "./buildEnrichmentAiRequest.js";
|
|
5
|
+
import { readEnrichmentPartial } from "./readEnrichmentPartial.js";
|
|
6
|
+
import { imageEnrichmentErrorStatusCode } from "./imageEnrichmentErrorStatusCode.js";
|
|
7
|
+
class AiImageEnrichmentStreamRouteImpl {
|
|
8
|
+
constructor(prepare, ai){
|
|
9
|
+
this.prepare = prepare;
|
|
10
|
+
this.ai = ai;
|
|
11
|
+
}
|
|
12
|
+
async handle(request, response) {
|
|
13
|
+
const fileId = request.pathParameters.fileId;
|
|
14
|
+
if (!fileId) return response.status(400).json({
|
|
15
|
+
message: "Missing file ID."
|
|
16
|
+
});
|
|
17
|
+
const preparedResult = await this.prepare.execute(fileId);
|
|
18
|
+
if (preparedResult.isFail()) {
|
|
19
|
+
const error = preparedResult.error;
|
|
20
|
+
const statusCode = imageEnrichmentErrorStatusCode(error);
|
|
21
|
+
return response.status(statusCode).json({
|
|
22
|
+
message: error.message,
|
|
23
|
+
code: error.code
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const events = this.enrich(preparedResult.value);
|
|
27
|
+
return response.sse(events);
|
|
28
|
+
}
|
|
29
|
+
async *enrich(prepared) {
|
|
30
|
+
yield toSseFrame({
|
|
31
|
+
type: "start",
|
|
32
|
+
fileId: prepared.fileId,
|
|
33
|
+
model: prepared.model
|
|
34
|
+
});
|
|
35
|
+
let output = {
|
|
36
|
+
tags: [],
|
|
37
|
+
description: ""
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
const request = buildEnrichmentAiRequest(prepared);
|
|
41
|
+
const stream = await this.ai.streamText(request);
|
|
42
|
+
for await (const partial of stream.partialOutputStream){
|
|
43
|
+
output = readEnrichmentPartial(partial);
|
|
44
|
+
yield toSseFrame({
|
|
45
|
+
type: "partial",
|
|
46
|
+
...output
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
yield toSseFrame({
|
|
51
|
+
type: "error",
|
|
52
|
+
message: `AI enrichment failed: ${error instanceof Error ? error.message : String(error)}`
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
yield toSseFrame({
|
|
57
|
+
type: "done",
|
|
58
|
+
fileId: prepared.fileId,
|
|
59
|
+
tags: output.tags,
|
|
60
|
+
description: output.description
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const AiImageEnrichmentStreamRoute = HttpRouteHandler.createImplementation({
|
|
65
|
+
implementation: AiImageEnrichmentStreamRouteImpl,
|
|
66
|
+
dependencies: [
|
|
67
|
+
PrepareImageEnrichmentUseCase,
|
|
68
|
+
Ai
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
class AiImageEnrichmentStreamRouteDefinitionImpl {
|
|
72
|
+
constructor(){
|
|
73
|
+
this.name = "ai-image-enrichment-stream";
|
|
74
|
+
this.method = "POST";
|
|
75
|
+
this.path = "/stream/fm/files/:fileId/enrich";
|
|
76
|
+
this.handler = AiImageEnrichmentStreamRoute;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const AiImageEnrichmentStreamRouteDefinition = HttpRouteDefinition.createImplementation({
|
|
80
|
+
implementation: AiImageEnrichmentStreamRouteDefinitionImpl,
|
|
81
|
+
dependencies: []
|
|
82
|
+
});
|
|
83
|
+
export { AiImageEnrichmentStreamRoute, AiImageEnrichmentStreamRouteDefinition };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=AiImageEnrichmentStreamRoute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.js","sources":["../../../../src/api/features/AiImageEnrichment/AiImageEnrichmentStreamRoute.ts"],"sourcesContent":["import { HttpRouteDefinition, HttpRouteHandler, toSseFrame } from \"@webiny/event-handler-core\";\nimport type { IHttpRequest, IHttpResponseBuilder } from \"@webiny/event-handler-core\";\nimport { Ai } from \"@webiny/api-core/features/ai/index.js\";\nimport { PrepareImageEnrichmentUseCase } from \"./abstractions.js\";\nimport type { IPreparedImageEnrichment } from \"./abstractions.js\";\nimport { buildEnrichmentAiRequest } from \"./buildEnrichmentAiRequest.js\";\nimport { readEnrichmentPartial } from \"./readEnrichmentPartial.js\";\nimport { imageEnrichmentErrorStatusCode } from \"./imageEnrichmentErrorStatusCode.js\";\n\n/**\n * Re-runs AI enrichment for a single file, streaming the model's output to the caller as\n * server-sent events. Read-only: the result is a proposal the caller can accept or discard.\n *\n * Preparation (file lookup, image read, provider resolution) happens BEFORE the response opens, so\n * anything knowable up front — missing file, wrong type, no provider — comes back as a real status\n * code. Only the AI call itself streams; once the first byte is out the status is committed to 200\n * and failures can only be reported as an `error` event.\n */\nclass AiImageEnrichmentStreamRouteImpl implements HttpRouteHandler.Interface {\n constructor(\n private prepare: PrepareImageEnrichmentUseCase.Interface,\n private ai: Ai.Interface\n ) {}\n\n async handle(\n request: IHttpRequest,\n response: IHttpResponseBuilder\n ): Promise<IHttpResponseBuilder> {\n const fileId = request.pathParameters.fileId;\n\n if (!fileId) {\n return response.status(400).json({ message: \"Missing file ID.\" });\n }\n\n const preparedResult = await this.prepare.execute(fileId);\n\n if (preparedResult.isFail()) {\n const error = preparedResult.error;\n\n const statusCode = imageEnrichmentErrorStatusCode(error);\n\n return response.status(statusCode).json({ message: error.message, code: error.code });\n }\n\n const events = this.enrich(preparedResult.value);\n\n return response.sse(events);\n }\n\n private async *enrich(prepared: IPreparedImageEnrichment): AsyncGenerator<string> {\n yield toSseFrame({ type: \"start\", fileId: prepared.fileId, model: prepared.model });\n\n let output = { tags: [] as string[], description: \"\" };\n\n try {\n const request = buildEnrichmentAiRequest(prepared);\n const stream = await this.ai.streamText(request);\n\n for await (const partial of stream.partialOutputStream) {\n output = readEnrichmentPartial(partial);\n yield toSseFrame({ type: \"partial\", ...output });\n }\n } catch (error) {\n yield toSseFrame({\n type: \"error\",\n message: `AI enrichment failed: ${\n error instanceof Error ? error.message : String(error)\n }`\n });\n return;\n }\n\n // Nothing is persisted here. The route PROPOSES; the user accepts in the UI, and the save\n // goes through the file's normal update path. The upload-time task still applies\n // automatically — there is nobody to ask at that point.\n yield toSseFrame({\n type: \"done\",\n fileId: prepared.fileId,\n tags: output.tags,\n description: output.description\n });\n }\n}\n\nexport const AiImageEnrichmentStreamRoute = HttpRouteHandler.createImplementation({\n implementation: AiImageEnrichmentStreamRouteImpl,\n dependencies: [PrepareImageEnrichmentUseCase, Ai]\n});\n\nclass AiImageEnrichmentStreamRouteDefinitionImpl implements HttpRouteDefinition.Interface {\n readonly name = \"ai-image-enrichment-stream\";\n readonly method = \"POST\";\n readonly path = \"/stream/fm/files/:fileId/enrich\";\n readonly handler = AiImageEnrichmentStreamRoute;\n}\n\n/** What the router matches on. Zero dependencies, so building it costs nothing. */\nexport const AiImageEnrichmentStreamRouteDefinition = HttpRouteDefinition.createImplementation({\n implementation: AiImageEnrichmentStreamRouteDefinitionImpl,\n dependencies: []\n});\n"],"names":["AiImageEnrichmentStreamRouteImpl","prepare","ai","request","response","fileId","preparedResult","error","statusCode","imageEnrichmentErrorStatusCode","events","prepared","toSseFrame","output","buildEnrichmentAiRequest","stream","partial","readEnrichmentPartial","Error","String","AiImageEnrichmentStreamRoute","HttpRouteHandler","PrepareImageEnrichmentUseCase","Ai","AiImageEnrichmentStreamRouteDefinitionImpl","AiImageEnrichmentStreamRouteDefinition","HttpRouteDefinition"],"mappings":";;;;;;AAkBA,MAAMA;IACF,YACYC,OAAgD,EAChDC,EAAgB,CAC1B;aAFUD,OAAO,GAAPA;aACAC,EAAE,GAAFA;IACT;IAEH,MAAM,OACFC,OAAqB,EACrBC,QAA8B,EACD;QAC7B,MAAMC,SAASF,QAAQ,cAAc,CAAC,MAAM;QAE5C,IAAI,CAACE,QACD,OAAOD,SAAS,MAAM,CAAC,KAAK,IAAI,CAAC;YAAE,SAAS;QAAmB;QAGnE,MAAME,iBAAiB,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAACD;QAElD,IAAIC,eAAe,MAAM,IAAI;YACzB,MAAMC,QAAQD,eAAe,KAAK;YAElC,MAAME,aAAaC,+BAA+BF;YAElD,OAAOH,SAAS,MAAM,CAACI,YAAY,IAAI,CAAC;gBAAE,SAASD,MAAM,OAAO;gBAAE,MAAMA,MAAM,IAAI;YAAC;QACvF;QAEA,MAAMG,SAAS,IAAI,CAAC,MAAM,CAACJ,eAAe,KAAK;QAE/C,OAAOF,SAAS,GAAG,CAACM;IACxB;IAEA,OAAe,OAAOC,QAAkC,EAA0B;QAC9E,MAAMC,WAAW;YAAE,MAAM;YAAS,QAAQD,SAAS,MAAM;YAAE,OAAOA,SAAS,KAAK;QAAC;QAEjF,IAAIE,SAAS;YAAE,MAAM,EAAE;YAAc,aAAa;QAAG;QAErD,IAAI;YACA,MAAMV,UAAUW,yBAAyBH;YACzC,MAAMI,SAAS,MAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAACZ;YAExC,WAAW,MAAMa,WAAWD,OAAO,mBAAmB,CAAE;gBACpDF,SAASI,sBAAsBD;gBAC/B,MAAMJ,WAAW;oBAAE,MAAM;oBAAW,GAAGC,MAAM;gBAAC;YAClD;QACJ,EAAE,OAAON,OAAO;YACZ,MAAMK,WAAW;gBACb,MAAM;gBACN,SAAS,CAAC,sBAAsB,EAC5BL,iBAAiBW,QAAQX,MAAM,OAAO,GAAGY,OAAOZ,QAClD;YACN;YACA;QACJ;QAKA,MAAMK,WAAW;YACb,MAAM;YACN,QAAQD,SAAS,MAAM;YACvB,MAAME,OAAO,IAAI;YACjB,aAAaA,OAAO,WAAW;QACnC;IACJ;AACJ;AAEO,MAAMO,+BAA+BC,iBAAiB,oBAAoB,CAAC;IAC9E,gBAAgBrB;IAChB,cAAc;QAACsB;QAA+BC;KAAG;AACrD;AAEA,MAAMC;;aACO,IAAI,GAAG;aACP,MAAM,GAAG;aACT,IAAI,GAAG;aACP,OAAO,GAAGJ;;AACvB;AAGO,MAAMK,yCAAyCC,oBAAoB,oBAAoB,CAAC;IAC3F,gBAAgBF;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
|
|
2
2
|
import { Ai } from "@webiny/api-core/features/ai/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
|
|
5
|
-
import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
|
|
6
|
-
import { GetSettingsUseCase as FmGetSettingsUseCase } from "@webiny/api-file-manager/features/settings/GetSettings/abstractions.js";
|
|
7
|
-
import { WebsocketService } from "@webiny/api-websockets/features/WebsocketService/index.js";
|
|
8
|
-
import { GetSettingsUseCase } from "../../../api/features/GetSettings/index.js";
|
|
3
|
+
import { ApplyImageEnrichmentUseCase, PrepareImageEnrichmentUseCase } from "./abstractions.js";
|
|
9
4
|
export declare const AI_IMAGE_ENRICHMENT_TASK_ID = "fmAiImageEnrichment";
|
|
10
5
|
export interface IAiImageEnrichmentTaskInput {
|
|
11
6
|
fileId: string;
|
|
12
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Background enrichment, triggered after a file is created. Shares its preparation and persistence
|
|
10
|
+
* with the streaming HTTP route (`AiImageEnrichmentStreamRoute`); the only difference is that this
|
|
11
|
+
* one waits for the whole AI response, because a background task has no one to stream to.
|
|
12
|
+
*/
|
|
13
13
|
declare class AiImageEnrichmentTaskImpl implements TaskDefinition.Interface<IAiImageEnrichmentTaskInput> {
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
private updateFile;
|
|
14
|
+
private prepare;
|
|
15
|
+
private apply;
|
|
17
16
|
private ai;
|
|
18
|
-
private getSettings;
|
|
19
|
-
private encryption;
|
|
20
|
-
private websocketService?;
|
|
21
17
|
id: string;
|
|
22
18
|
title: string;
|
|
23
19
|
description: string;
|
|
@@ -25,10 +21,10 @@ declare class AiImageEnrichmentTaskImpl implements TaskDefinition.Interface<IAiI
|
|
|
25
21
|
isPrivate: boolean;
|
|
26
22
|
databaseLogs: boolean;
|
|
27
23
|
readonly selfCleanup: ("onAbort" | "onSuccess")[];
|
|
28
|
-
constructor(
|
|
24
|
+
constructor(prepare: PrepareImageEnrichmentUseCase.Interface, apply: ApplyImageEnrichmentUseCase.Interface, ai: Ai.Interface);
|
|
29
25
|
run({ input, controller }: TaskDefinition.RunParams<IAiImageEnrichmentTaskInput>): Promise<TaskDefinition.Result<IAiImageEnrichmentTaskInput>>;
|
|
30
26
|
}
|
|
31
27
|
export declare const AiImageEnrichmentTask: typeof AiImageEnrichmentTaskImpl & {
|
|
32
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskDefinition<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskInput, import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskOutput>>;
|
|
28
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/task/TaskDefinition/abstractions.js").ITaskDefinition<import("@webiny/api-core/features/task/TaskDefinition/abstractions.js").ITaskInput, import("@webiny/api-core/features/task/TaskDefinition/abstractions.js").ITaskOutput>>;
|
|
33
29
|
};
|
|
34
30
|
export {};
|
|
@@ -1,30 +1,14 @@
|
|
|
1
|
-
import { Output } from "ai";
|
|
2
|
-
import { z } from "zod";
|
|
3
1
|
import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
|
|
4
2
|
import { Ai } from "@webiny/api-core/features/ai/index.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { GetSettingsUseCase } from "@webiny/api-file-manager/features/settings/GetSettings/abstractions.js";
|
|
9
|
-
import { WebsocketService } from "@webiny/api-websockets/features/WebsocketService/index.js";
|
|
10
|
-
import { GetSettingsUseCase as index_js_GetSettingsUseCase } from "../GetSettings/index.js";
|
|
3
|
+
import { ApplyImageEnrichmentUseCase, PrepareImageEnrichmentUseCase } from "./abstractions.js";
|
|
4
|
+
import { buildEnrichmentAiRequest } from "./buildEnrichmentAiRequest.js";
|
|
5
|
+
import { EnrichmentNotAnImageError } from "./errors.js";
|
|
11
6
|
const AI_IMAGE_ENRICHMENT_TASK_ID = "fmAiImageEnrichment";
|
|
12
|
-
const AI_PROMPT = "Analyze this image and return up to 5 lowercase descriptive tags and one short sentence describing the image.";
|
|
13
|
-
const aiOutputSchema = Output.object({
|
|
14
|
-
schema: z.object({
|
|
15
|
-
tags: z.array(z.string()),
|
|
16
|
-
description: z.string()
|
|
17
|
-
})
|
|
18
|
-
});
|
|
19
7
|
class AiImageEnrichmentTaskImpl {
|
|
20
|
-
constructor(
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
23
|
-
this.updateFile = updateFile;
|
|
8
|
+
constructor(prepare, apply, ai){
|
|
9
|
+
this.prepare = prepare;
|
|
10
|
+
this.apply = apply;
|
|
24
11
|
this.ai = ai;
|
|
25
|
-
this.getSettings = getSettings;
|
|
26
|
-
this.encryption = encryption;
|
|
27
|
-
this.websocketService = websocketService;
|
|
28
12
|
this.id = AI_IMAGE_ENRICHMENT_TASK_ID;
|
|
29
13
|
this.title = "File Manager - AI Image Enrichment";
|
|
30
14
|
this.description = "Automatically enriches uploaded images with AI-generated tags and description.";
|
|
@@ -38,101 +22,44 @@ class AiImageEnrichmentTaskImpl {
|
|
|
38
22
|
}
|
|
39
23
|
async run({ input, controller }) {
|
|
40
24
|
if (controller.runtime.isAborted()) return controller.response.aborted();
|
|
41
|
-
const
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const settingsResult = await this.fmSettings.execute();
|
|
48
|
-
const srcPrefix = settingsResult.isOk() ? settingsResult.value.srcPrefix ?? "" : "";
|
|
49
|
-
const imageUrl = `${srcPrefix}${file.key}`;
|
|
50
|
-
const aiSettingsResult = await this.getSettings.execute();
|
|
51
|
-
if (aiSettingsResult.isFail()) return controller.response.error({
|
|
52
|
-
message: "No AI provider configured. Add a provider in AI Power Ups settings."
|
|
53
|
-
});
|
|
54
|
-
const aiSettings = aiSettingsResult.value;
|
|
55
|
-
const firstProvider = aiSettings.providers.presets[0];
|
|
56
|
-
if (!firstProvider) return controller.response.done({
|
|
57
|
-
message: "No AI provider configured. Add a provider in AI Power Ups settings."
|
|
58
|
-
});
|
|
59
|
-
let tags = [];
|
|
60
|
-
let description = "";
|
|
61
|
-
try {
|
|
62
|
-
const aiResult = await this.ai.generateText({
|
|
63
|
-
model: firstProvider.model,
|
|
64
|
-
output: aiOutputSchema,
|
|
65
|
-
connection: {
|
|
66
|
-
sdkName: firstProvider.model.split("/")[0],
|
|
67
|
-
apiKey: await this.encryption.decrypt(firstProvider.apiKeyEncrypted)
|
|
68
|
-
},
|
|
69
|
-
messages: [
|
|
70
|
-
{
|
|
71
|
-
role: "user",
|
|
72
|
-
content: [
|
|
73
|
-
{
|
|
74
|
-
type: "image",
|
|
75
|
-
image: new URL(imageUrl)
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
type: "text",
|
|
79
|
-
text: AI_PROMPT
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
}
|
|
83
|
-
]
|
|
25
|
+
const preparedResult = await this.prepare.execute(input.fileId);
|
|
26
|
+
if (preparedResult.isFail()) {
|
|
27
|
+
const error = preparedResult.error;
|
|
28
|
+
if (error instanceof EnrichmentNotAnImageError) return controller.response.done(error.message);
|
|
29
|
+
return controller.response.error({
|
|
30
|
+
message: error.message
|
|
84
31
|
});
|
|
32
|
+
}
|
|
33
|
+
const prepared = preparedResult.value;
|
|
34
|
+
let tags;
|
|
35
|
+
let description;
|
|
36
|
+
try {
|
|
37
|
+
const request = buildEnrichmentAiRequest(prepared);
|
|
38
|
+
const aiResult = await this.ai.generateText(request);
|
|
85
39
|
tags = aiResult.output.tags;
|
|
86
40
|
description = aiResult.output.description;
|
|
87
41
|
} catch (error) {
|
|
88
|
-
console.log("error", error.message);
|
|
89
42
|
return controller.response.error({
|
|
90
43
|
message: `AI enrichment failed: ${error instanceof Error ? error.message : String(error)}`
|
|
91
44
|
});
|
|
92
45
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
...tags
|
|
97
|
-
])
|
|
98
|
-
];
|
|
99
|
-
const updateResult = await this.updateFile.execute({
|
|
100
|
-
id: file.id,
|
|
101
|
-
tags: mergedTags,
|
|
46
|
+
const appliedResult = await this.apply.execute({
|
|
47
|
+
fileId: prepared.fileId,
|
|
48
|
+
tags,
|
|
102
49
|
description
|
|
103
50
|
});
|
|
104
|
-
if (
|
|
105
|
-
message:
|
|
51
|
+
if (appliedResult.isFail()) return controller.response.error({
|
|
52
|
+
message: appliedResult.error.message
|
|
106
53
|
});
|
|
107
|
-
if (this.websocketService) {
|
|
108
|
-
const connectionsResult = await this.websocketService.listConnections();
|
|
109
|
-
if (connectionsResult.isOk() && connectionsResult.value.length > 0) await this.websocketService.sendToConnections(connectionsResult.value, {
|
|
110
|
-
action: "fm.file.enrichment",
|
|
111
|
-
data: {
|
|
112
|
-
id: file.id,
|
|
113
|
-
tags: mergedTags,
|
|
114
|
-
description
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
54
|
return controller.response.done("AI image enrichment completed successfully.");
|
|
119
55
|
}
|
|
120
56
|
}
|
|
121
57
|
const AiImageEnrichmentTask = TaskDefinition.createImplementation({
|
|
122
58
|
implementation: AiImageEnrichmentTaskImpl,
|
|
123
59
|
dependencies: [
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Ai,
|
|
128
|
-
index_js_GetSettingsUseCase,
|
|
129
|
-
Encryption,
|
|
130
|
-
[
|
|
131
|
-
WebsocketService,
|
|
132
|
-
{
|
|
133
|
-
optional: true
|
|
134
|
-
}
|
|
135
|
-
]
|
|
60
|
+
PrepareImageEnrichmentUseCase,
|
|
61
|
+
ApplyImageEnrichmentUseCase,
|
|
62
|
+
Ai
|
|
136
63
|
]
|
|
137
64
|
});
|
|
138
65
|
export { AI_IMAGE_ENRICHMENT_TASK_ID, AiImageEnrichmentTask };
|