@strapi/upload 5.52.0 → 5.52.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/dist/admin/future/components/TruncatedText.js +76 -0
- package/dist/admin/future/components/TruncatedText.js.map +1 -0
- package/dist/admin/future/components/TruncatedText.mjs +74 -0
- package/dist/admin/future/components/TruncatedText.mjs.map +1 -0
- package/dist/admin/future/hooks/useTracking.js +57 -0
- package/dist/admin/future/hooks/useTracking.js.map +1 -0
- package/dist/admin/future/hooks/useTracking.mjs +53 -0
- package/dist/admin/future/hooks/useTracking.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +9 -6
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +9 -6
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +21 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +21 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +3 -4
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +4 -5
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.js +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +21 -38
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +23 -40
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.js +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +5 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +6 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/utils/selection.js +17 -0
- package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs +17 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -1
- package/dist/admin/future/services/api.js +7 -8
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +7 -8
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +11 -23
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +11 -23
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.js +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
- package/dist/admin/src/future/components/TruncatedText.d.ts +32 -0
- package/dist/admin/src/future/hooks/useTracking.d.ts +29 -0
- package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +5 -3
- package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +5 -4
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +2 -0
- package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +10 -0
- package/dist/admin/src/future/services/api.d.ts +6 -7
- package/dist/server/controllers/admin-file.js +27 -9
- package/dist/server/controllers/admin-file.js.map +1 -1
- package/dist/server/controllers/admin-file.mjs +27 -9
- package/dist/server/controllers/admin-file.mjs.map +1 -1
- package/dist/server/controllers/admin-upload.js +24 -8
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/admin-upload.mjs +24 -8
- package/dist/server/controllers/admin-upload.mjs.map +1 -1
- package/dist/server/routes/admin.js +41 -21
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +41 -21
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/services/ai-metadata.js.map +1 -1
- package/dist/server/services/ai-metadata.mjs.map +1 -1
- package/dist/server/src/controllers/admin-file.d.ts +29 -8
- package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-upload.d.ts +20 -4
- package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +4 -4
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/routes/admin.d.ts.map +1 -1
- package/dist/server/src/services/ai-metadata.d.ts +2 -2
- package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
- package/dist/shared/contracts/ai-metadata-jobs.d.ts +10 -32
- package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -1
- package/dist/shared/contracts/files.d.ts +10 -10
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-metadata.js","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { UnstableGenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = UnstableGenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai-metadata.js","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { GenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = GenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-metadata.mjs","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { UnstableGenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = UnstableGenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai-metadata.mjs","sources":["../../../server/src/services/ai-metadata.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { z } from 'zod';\nimport { InputFile, File } from '../types';\nimport { Settings } from '../controllers/validation/admin/settings';\nimport { getService } from '../utils';\nimport { buildFormDataFromFiles } from '../utils/images';\nimport { AI_METADATA_CHUNK_SIZE, AI_METADATA_SUPPORTED_IMAGE_TYPES } from '../constants';\n\nimport { isAIMetadataSupportedMime } from '../../../shared/constants';\n\nimport type { GenerateAIMetadata } from '../../../shared/contracts/files';\n\nexport type AIMetadataFileResult = GenerateAIMetadata.FileResult;\n\n/**\n * Supported image types for AI metadata generation. Lives in `shared/` so the\n * admin panel gates the bulk action on exactly what the provider accepts.\n */\nconst SUPPORTED_IMAGE_TYPES = AI_METADATA_SUPPORTED_IMAGE_TYPES;\n\nconst isSupportedImage = (file: File): boolean => isAIMetadataSupportedMime(file.mime);\n\nconst chunk = <T>(items: T[], size: number): T[][] => {\n const chunks: T[][] = [];\n\n for (let i = 0; i < items.length; i += size) {\n chunks.push(items.slice(i, i + size));\n }\n\n return chunks;\n};\n\nconst createAIMetadataService = ({ strapi }: { strapi: Core.Strapi }) => {\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return {\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings: Settings = await strapi.plugin('upload').service('upload').getSettings();\n return settings.aiMetadata ?? true;\n },\n\n async countImagesWithoutMetadata() {\n const imagesWithoutMetadataCountPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n const totalImagesPromise = strapi.db.query('plugin::upload.file').count({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n },\n });\n\n const [imagesWithoutMetadataCount, totalImages] = await Promise.all([\n imagesWithoutMetadataCountPromise,\n totalImagesPromise,\n ]);\n\n return { imagesWithoutMetadataCount, totalImages };\n },\n\n /**\n * Update files with AI-generated metadata\n * Shared logic used by both upload flow and retroactive processing\n */\n async updateFilesWithAIMetadata(\n files: File[],\n metadataResults: Array<{ altText: string; caption: string } | null>,\n user: { id: string | number }\n ) {\n const uploadService = strapi.plugin('upload').service('upload');\n\n await Promise.all(\n files.map(async (file, index) => {\n const aiMetadata = metadataResults[index];\n if (aiMetadata) {\n // Only update fields that are missing (null or empty string)\n const updateData: { alternativeText?: string; caption?: string } = {};\n\n if (!file.alternativeText || file.alternativeText === '') {\n updateData.alternativeText = aiMetadata.altText;\n }\n\n if (!file.caption || file.caption === '') {\n updateData.caption = aiMetadata.caption;\n }\n\n // Only update if there are fields to update\n if (Object.keys(updateData).length > 0) {\n await uploadService.updateFileInfo(file.id, updateData, { user });\n\n // Update in-memory file object (needed for upload flow response)\n if (updateData.alternativeText !== undefined) {\n file.alternativeText = updateData.alternativeText;\n }\n if (updateData.caption !== undefined) {\n file.caption = updateData.caption;\n }\n }\n }\n })\n );\n },\n\n /**\n * Process existing files with job tracking for progress updates\n */\n async processExistingFiles(jobId: number, user: { id: string | number }): Promise<void> {\n const jobService = getService('aiMetadataJobs');\n\n try {\n // Mark as processing\n await jobService.updateJob(jobId, { status: 'processing' });\n\n // Query all images without metadata\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: {\n mime: {\n $in: SUPPORTED_IMAGE_TYPES,\n },\n $or: [\n { alternativeText: { $null: true } },\n { alternativeText: '' },\n { caption: { $null: true } },\n { caption: '' },\n ],\n },\n });\n\n if (files.length === 0) {\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n return;\n }\n\n // Process all files at once\n const metadataResults = await this.processFiles(files);\n await this.updateFilesWithAIMetadata(files, metadataResults, user);\n\n // Mark as completed\n await jobService.updateJob(jobId, {\n status: 'completed',\n completedAt: new Date(),\n });\n } catch (error) {\n strapi.log.error('AI metadata job failed', {\n jobId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n await jobService.updateJob(jobId, {\n status: 'failed',\n completedAt: new Date(),\n });\n }\n },\n\n /**\n * Generate AI metadata for an explicit selection of files, synchronously.\n *\n * Unlike `processExistingFiles`, this does not create a job and does not\n * filter on missing metadata — the selection is what the user asked for.\n * Existing alt text / captions are still preserved by\n * `updateFilesWithAIMetadata`, so a file that already has both is reported\n * as `success` without being modified.\n *\n * Images are processed in sequential chunks so one failing chunk only\n * affects its own files; every other chunk still runs.\n *\n * @experimental\n */\n async generateForFiles(\n fileIds: Array<number | string>,\n user: { id: string | number }\n ): Promise<AIMetadataFileResult[]> {\n // `yup.strapiID()` accepts both numbers and numeric strings without\n // coercing, so normalise here — otherwise a request sending `[\"1\"]`\n // would never match the numeric ids coming back from the database.\n const normalisedIds = fileIds.map(Number);\n const uniqueIds = [...new Set(normalisedIds)];\n\n const files: File[] = await strapi.db.query('plugin::upload.file').findMany({\n where: { id: { $in: uniqueIds } },\n });\n\n const filesById = new Map(files.map((file) => [file.id, file]));\n\n // Keyed by input id so the response order matches the request order.\n const resultsById = new Map<number, AIMetadataFileResult>();\n const images: File[] = [];\n\n uniqueIds.forEach((id) => {\n const file = filesById.get(id);\n\n if (!file) {\n resultsById.set(id, { id, status: 'error', error: 'File not found' });\n return;\n }\n\n // Only the formats the AI provider understands are sent; anything else\n // (non-images, but also exotic image formats like SVG or TIFF) is\n // reported as skipped rather than failed.\n if (!isSupportedImage(file)) {\n resultsById.set(id, { id, status: 'skipped' });\n return;\n }\n\n images.push(file);\n });\n\n for (const imageChunk of chunk(images, AI_METADATA_CHUNK_SIZE)) {\n try {\n const metadataResults = await this.processFiles(imageChunk);\n await this.updateFilesWithAIMetadata(imageChunk, metadataResults, user);\n\n imageChunk.forEach((file, index) => {\n resultsById.set(file.id, {\n id: file.id,\n status: metadataResults[index] ? 'success' : 'error',\n ...(metadataResults[index]\n ? {}\n : { error: 'AI metadata generation returned no result' }),\n });\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'AI metadata generation failed';\n\n strapi.log.error('AI metadata generation failed for a chunk of files', {\n fileIds: imageChunk.map((file) => file.id),\n message,\n });\n\n imageChunk.forEach((file) => {\n resultsById.set(file.id, { id: file.id, status: 'error', error: message });\n });\n }\n }\n\n return normalisedIds.map(\n (id) => resultsById.get(id) ?? { id, status: 'error', error: 'File not processed' }\n );\n },\n\n /**\n * Processes provided files for AI metadata generation\n */\n async processFiles(files: File[]): Promise<Array<{ altText: string; caption: string } | null>> {\n if (!(await this.isEnabled()) || !aiServerUrl) {\n throw new Error('AI Metadata service is not enabled');\n }\n\n // Filter for image files only and track their original positions\n // We need to maintain the original indices so we can map AI results back correctly\n const imageFiles = files\n .map((file, index) => ({ file, originalIndex: index }))\n .filter(({ file }) => file.mime?.startsWith('image/'));\n\n // Convert filtered image files to InputFile format (uses thumbnails when available)\n const imageInputFiles = imageFiles.map(({ file }) => {\n const thumbnail = (file.formats as any)?.thumbnail;\n return {\n filepath: thumbnail?.url || file.url || '',\n mimetype: file.mime,\n originalFilename: file.name,\n size: thumbnail?.size || file.size,\n provider: file.provider,\n } as InputFile;\n });\n const createEmptyMetadataResults = (): Array<{ altText: string; caption: string } | null> =>\n Array.from({ length: files.length }, () => null);\n\n // If no image files, return sparse array with all nulls to avoid calling the AI server\n // This maintains the same array length as input files for proper index alignment\n if (imageFiles.length === 0) {\n return createEmptyMetadataResults();\n }\n\n const formData = await buildFormDataFromFiles(\n imageInputFiles,\n strapi.config.get('server.absoluteUrl'),\n strapi.log\n );\n\n let token: string;\n try {\n const tokenData = await strapi.ai.admin.getAiToken();\n token = tokenData.token;\n } catch (error) {\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for media metadata generation', {\n aiServerUrl,\n imageCount: imageFiles.length,\n });\n\n const res = await fetch(`${aiServerUrl}/media-library/generate-metadata`, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const errorText = await res.text();\n throw Error(`AI metadata generation failed`, { cause: errorText });\n }\n\n const responseSchema = z.object({\n results: z.array(\n z.object({\n altText: z.string(),\n caption: z.string(),\n })\n ),\n });\n\n const { results } = responseSchema.parse(await res.json());\n strapi.log.http(`AI generated metadata successfully for ${results.length} files`);\n\n // Create sparse array with results at original indices\n // Example: files=[img1, pdf, img2] -> imageFiles=[{img1, index:0}, {img2, index:2}]\n // AI results=[meta1, meta2] -> sparse=[meta1, null, meta2]\n // This ensures metadata[i] corresponds to files[i], with null for non-images\n return imageFiles.reduce((sparseResults, { originalIndex }, resultIndex) => {\n sparseResults[originalIndex] = results[resultIndex];\n return sparseResults;\n }, createEmptyMetadataResults());\n },\n };\n};\n\nexport { createAIMetadataService };\n"],"names":["SUPPORTED_IMAGE_TYPES","AI_METADATA_SUPPORTED_IMAGE_TYPES","isSupportedImage","file","isAIMetadataSupportedMime","mime","chunk","items","size","chunks","i","length","push","slice","createAIMetadataService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","isEnabled","ai","admin","settings","plugin","service","getSettings","aiMetadata","countImagesWithoutMetadata","imagesWithoutMetadataCountPromise","db","query","count","where","$in","$or","alternativeText","$null","caption","totalImagesPromise","imagesWithoutMetadataCount","totalImages","Promise","all","updateFilesWithAIMetadata","files","metadataResults","user","uploadService","map","index","updateData","altText","Object","keys","updateFileInfo","id","undefined","processExistingFiles","jobId","jobService","getService","updateJob","status","findMany","completedAt","Date","processFiles","error","log","Error","message","String","generateForFiles","fileIds","normalisedIds","Number","uniqueIds","Set","filesById","Map","resultsById","images","forEach","get","set","imageChunk","AI_METADATA_CHUNK_SIZE","imageFiles","originalIndex","filter","startsWith","imageInputFiles","thumbnail","formats","filepath","url","mimetype","originalFilename","name","provider","createEmptyMetadataResults","Array","from","formData","buildFormDataFromFiles","config","token","tokenData","getAiToken","cause","http","imageCount","res","fetch","method","body","headers","Authorization","ok","errorText","text","responseSchema","z","object","results","array","string","parse","json","reduce","sparseResults","resultIndex"],"mappings":";;;;;AAcA;;;AAGC,IACD,MAAMA,qBAAAA,GAAwBC,iCAAAA;AAE9B,MAAMC,gBAAAA,GAAmB,CAACC,IAAAA,GAAwBC,yBAAAA,CAA0BD,KAAKE,IAAI,CAAA;AAErF,MAAMC,KAAAA,GAAQ,CAAIC,KAAAA,EAAYC,IAAAA,GAAAA;AAC5B,IAAA,MAAMC,SAAgB,EAAE;IAExB,IAAK,IAAIC,IAAI,CAAA,EAAGA,CAAAA,GAAIH,MAAMI,MAAM,EAAED,KAAKF,IAAAA,CAAM;AAC3CC,QAAAA,MAAAA,CAAOG,IAAI,CAACL,KAAAA,CAAMM,KAAK,CAACH,GAAGA,CAAAA,GAAIF,IAAAA,CAAAA,CAAAA;AACjC,IAAA;IAEA,OAAOC,MAAAA;AACT,CAAA;AAEA,MAAMK,uBAAAA,GAA0B,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAClE,IAAA,MAAMC,WAAAA,GAAcC,OAAAA,CAAQC,GAAG,CAACC,aAAa,IAAI,kCAAA;IAEjD,OAAO;QACL,MAAMC,SAAAA,CAAAA,GAAAA;AACJ,YAAA,IAAIL,OAAOM,EAAE,CAACC,KAAK,CAACF,SAAS,OAAO,KAAA,EAAO;gBACzC,OAAO,KAAA;AACT,YAAA;YACA,MAAMG,QAAAA,GAAqB,MAAMR,MAAAA,CAAOS,MAAM,CAAC,QAAA,CAAA,CAAUC,OAAO,CAAC,QAAA,CAAA,CAAUC,WAAW,EAAA;YACtF,OAAOH,QAAAA,CAASI,UAAU,IAAI,IAAA;AAChC,QAAA,CAAA;QAEA,MAAMC,0BAAAA,CAAAA,GAAAA;YACJ,MAAMC,iCAAAA,GAAoCd,OAAOe,EAAE,CAACC,KAAK,CAAC,qBAAA,CAAA,CAAuBC,KAAK,CAAC;gBACrFC,KAAAA,EAAO;oBACL5B,IAAAA,EAAM;wBACJ6B,GAAAA,EAAKlC;AACP,qBAAA;oBACAmC,GAAAA,EAAK;AACH,wBAAA;4BAAEC,eAAAA,EAAiB;gCAAEC,KAAAA,EAAO;AAAK;AAAE,yBAAA;AACnC,wBAAA;4BAAED,eAAAA,EAAiB;AAAG,yBAAA;AACtB,wBAAA;4BAAEE,OAAAA,EAAS;gCAAED,KAAAA,EAAO;AAAK;AAAE,yBAAA;AAC3B,wBAAA;4BAAEC,OAAAA,EAAS;AAAG;AACf;AACH;AACF,aAAA,CAAA;YAEA,MAAMC,kBAAAA,GAAqBxB,OAAOe,EAAE,CAACC,KAAK,CAAC,qBAAA,CAAA,CAAuBC,KAAK,CAAC;gBACtEC,KAAAA,EAAO;oBACL5B,IAAAA,EAAM;wBACJ6B,GAAAA,EAAKlC;AACP;AACF;AACF,aAAA,CAAA;AAEA,YAAA,MAAM,CAACwC,0BAAAA,EAA4BC,WAAAA,CAAY,GAAG,MAAMC,OAAAA,CAAQC,GAAG,CAAC;AAClEd,gBAAAA,iCAAAA;AACAU,gBAAAA;AACD,aAAA,CAAA;YAED,OAAO;AAAEC,gBAAAA,0BAAAA;AAA4BC,gBAAAA;AAAY,aAAA;AACnD,QAAA,CAAA;AAEA;;;AAGC,QACD,MAAMG,yBAAAA,CAAAA,CACJC,KAAa,EACbC,eAAmE,EACnEC,IAA6B,EAAA;AAE7B,YAAA,MAAMC,gBAAgBjC,MAAAA,CAAOS,MAAM,CAAC,QAAA,CAAA,CAAUC,OAAO,CAAC,QAAA,CAAA;AAEtD,YAAA,MAAMiB,QAAQC,GAAG,CACfE,MAAMI,GAAG,CAAC,OAAO9C,IAAAA,EAAM+C,KAAAA,GAAAA;gBACrB,MAAMvB,UAAAA,GAAamB,eAAe,CAACI,KAAAA,CAAM;AACzC,gBAAA,IAAIvB,UAAAA,EAAY;;AAEd,oBAAA,MAAMwB,aAA6D,EAAC;AAEpE,oBAAA,IAAI,CAAChD,IAAAA,CAAKiC,eAAe,IAAIjC,IAAAA,CAAKiC,eAAe,KAAK,EAAA,EAAI;wBACxDe,UAAAA,CAAWf,eAAe,GAAGT,UAAAA,CAAWyB,OAAO;AACjD,oBAAA;AAEA,oBAAA,IAAI,CAACjD,IAAAA,CAAKmC,OAAO,IAAInC,IAAAA,CAAKmC,OAAO,KAAK,EAAA,EAAI;wBACxCa,UAAAA,CAAWb,OAAO,GAAGX,UAAAA,CAAWW,OAAO;AACzC,oBAAA;;AAGA,oBAAA,IAAIe,OAAOC,IAAI,CAACH,UAAAA,CAAAA,CAAYxC,MAAM,GAAG,CAAA,EAAG;AACtC,wBAAA,MAAMqC,cAAcO,cAAc,CAACpD,IAAAA,CAAKqD,EAAE,EAAEL,UAAAA,EAAY;AAAEJ,4BAAAA;AAAK,yBAAA,CAAA;;wBAG/D,IAAII,UAAAA,CAAWf,eAAe,KAAKqB,SAAAA,EAAW;4BAC5CtD,IAAAA,CAAKiC,eAAe,GAAGe,UAAAA,CAAWf,eAAe;AACnD,wBAAA;wBACA,IAAIe,UAAAA,CAAWb,OAAO,KAAKmB,SAAAA,EAAW;4BACpCtD,IAAAA,CAAKmC,OAAO,GAAGa,UAAAA,CAAWb,OAAO;AACnC,wBAAA;AACF,oBAAA;AACF,gBAAA;AACF,YAAA,CAAA,CAAA,CAAA;AAEJ,QAAA,CAAA;AAEA;;AAEC,QACD,MAAMoB,oBAAAA,CAAAA,CAAqBC,KAAa,EAAEZ,IAA6B,EAAA;AACrE,YAAA,MAAMa,aAAaC,UAAAA,CAAW,gBAAA,CAAA;YAE9B,IAAI;;gBAEF,MAAMD,UAAAA,CAAWE,SAAS,CAACH,KAAAA,EAAO;oBAAEI,MAAAA,EAAQ;AAAa,iBAAA,CAAA;;gBAGzD,MAAMlB,KAAAA,GAAgB,MAAM9B,MAAAA,CAAOe,EAAE,CAACC,KAAK,CAAC,qBAAA,CAAA,CAAuBiC,QAAQ,CAAC;oBAC1E/B,KAAAA,EAAO;wBACL5B,IAAAA,EAAM;4BACJ6B,GAAAA,EAAKlC;AACP,yBAAA;wBACAmC,GAAAA,EAAK;AACH,4BAAA;gCAAEC,eAAAA,EAAiB;oCAAEC,KAAAA,EAAO;AAAK;AAAE,6BAAA;AACnC,4BAAA;gCAAED,eAAAA,EAAiB;AAAG,6BAAA;AACtB,4BAAA;gCAAEE,OAAAA,EAAS;oCAAED,KAAAA,EAAO;AAAK;AAAE,6BAAA;AAC3B,4BAAA;gCAAEC,OAAAA,EAAS;AAAG;AACf;AACH;AACF,iBAAA,CAAA;gBAEA,IAAIO,KAAAA,CAAMlC,MAAM,KAAK,CAAA,EAAG;oBACtB,MAAMiD,UAAAA,CAAWE,SAAS,CAACH,KAAAA,EAAO;wBAChCI,MAAAA,EAAQ,WAAA;AACRE,wBAAAA,WAAAA,EAAa,IAAIC,IAAAA;AACnB,qBAAA,CAAA;AACA,oBAAA;AACF,gBAAA;;AAGA,gBAAA,MAAMpB,eAAAA,GAAkB,MAAM,IAAI,CAACqB,YAAY,CAACtB,KAAAA,CAAAA;AAChD,gBAAA,MAAM,IAAI,CAACD,yBAAyB,CAACC,OAAOC,eAAAA,EAAiBC,IAAAA,CAAAA;;gBAG7D,MAAMa,UAAAA,CAAWE,SAAS,CAACH,KAAAA,EAAO;oBAChCI,MAAAA,EAAQ,WAAA;AACRE,oBAAAA,WAAAA,EAAa,IAAIC,IAAAA;AACnB,iBAAA,CAAA;AACF,YAAA,CAAA,CAAE,OAAOE,KAAAA,EAAO;AACdrD,gBAAAA,MAAAA,CAAOsD,GAAG,CAACD,KAAK,CAAC,wBAAA,EAA0B;AACzCT,oBAAAA,KAAAA;AACAS,oBAAAA,KAAAA,EAAOA,KAAAA,YAAiBE,KAAAA,GAAQF,KAAAA,CAAMG,OAAO,GAAGC,MAAAA,CAAOJ,KAAAA;AACzD,iBAAA,CAAA;gBAEA,MAAMR,UAAAA,CAAWE,SAAS,CAACH,KAAAA,EAAO;oBAChCI,MAAAA,EAAQ,QAAA;AACRE,oBAAAA,WAAAA,EAAa,IAAIC,IAAAA;AACnB,iBAAA,CAAA;AACF,YAAA;AACF,QAAA,CAAA;AAEA;;;;;;;;;;;;;AAaC,QACD,MAAMO,gBAAAA,CAAAA,CACJC,OAA+B,EAC/B3B,IAA6B,EAAA;;;;YAK7B,MAAM4B,aAAAA,GAAgBD,OAAAA,CAAQzB,GAAG,CAAC2B,MAAAA,CAAAA;AAClC,YAAA,MAAMC,SAAAA,GAAY;AAAI,gBAAA,GAAA,IAAIC,GAAAA,CAAIH,aAAAA;AAAe,aAAA;YAE7C,MAAM9B,KAAAA,GAAgB,MAAM9B,MAAAA,CAAOe,EAAE,CAACC,KAAK,CAAC,qBAAA,CAAA,CAAuBiC,QAAQ,CAAC;gBAC1E/B,KAAAA,EAAO;oBAAEuB,EAAAA,EAAI;wBAAEtB,GAAAA,EAAK2C;AAAU;AAAE;AAClC,aAAA,CAAA;AAEA,YAAA,MAAME,YAAY,IAAIC,GAAAA,CAAInC,MAAMI,GAAG,CAAC,CAAC9C,IAAAA,GAAS;AAACA,oBAAAA,IAAAA,CAAKqD,EAAE;AAAErD,oBAAAA;AAAK,iBAAA,CAAA,CAAA;;AAG7D,YAAA,MAAM8E,cAAc,IAAID,GAAAA,EAAAA;AACxB,YAAA,MAAME,SAAiB,EAAE;YAEzBL,SAAAA,CAAUM,OAAO,CAAC,CAAC3B,EAAAA,GAAAA;gBACjB,MAAMrD,IAAAA,GAAO4E,SAAAA,CAAUK,GAAG,CAAC5B,EAAAA,CAAAA;AAE3B,gBAAA,IAAI,CAACrD,IAAAA,EAAM;oBACT8E,WAAAA,CAAYI,GAAG,CAAC7B,EAAAA,EAAI;AAAEA,wBAAAA,EAAAA;wBAAIO,MAAAA,EAAQ,OAAA;wBAASK,KAAAA,EAAO;AAAiB,qBAAA,CAAA;AACnE,oBAAA;AACF,gBAAA;;;;gBAKA,IAAI,CAAClE,iBAAiBC,IAAAA,CAAAA,EAAO;oBAC3B8E,WAAAA,CAAYI,GAAG,CAAC7B,EAAAA,EAAI;AAAEA,wBAAAA,EAAAA;wBAAIO,MAAAA,EAAQ;AAAU,qBAAA,CAAA;AAC5C,oBAAA;AACF,gBAAA;AAEAmB,gBAAAA,MAAAA,CAAOtE,IAAI,CAACT,IAAAA,CAAAA;AACd,YAAA,CAAA,CAAA;AAEA,YAAA,KAAK,MAAMmF,UAAAA,IAAchF,KAAAA,CAAM4E,MAAAA,EAAQK,sBAAAA,CAAAA,CAAyB;gBAC9D,IAAI;AACF,oBAAA,MAAMzC,eAAAA,GAAkB,MAAM,IAAI,CAACqB,YAAY,CAACmB,UAAAA,CAAAA;AAChD,oBAAA,MAAM,IAAI,CAAC1C,yBAAyB,CAAC0C,YAAYxC,eAAAA,EAAiBC,IAAAA,CAAAA;oBAElEuC,UAAAA,CAAWH,OAAO,CAAC,CAAChF,IAAAA,EAAM+C,KAAAA,GAAAA;AACxB+B,wBAAAA,WAAAA,CAAYI,GAAG,CAAClF,IAAAA,CAAKqD,EAAE,EAAE;AACvBA,4BAAAA,EAAAA,EAAIrD,KAAKqD,EAAE;AACXO,4BAAAA,MAAAA,EAAQjB,eAAe,CAACI,KAAAA,CAAM,GAAG,SAAA,GAAY,OAAA;AAC7C,4BAAA,GAAIJ,eAAe,CAACI,KAAAA,CAAM,GACtB,EAAC,GACD;gCAAEkB,KAAAA,EAAO;;AACf,yBAAA,CAAA;AACF,oBAAA,CAAA,CAAA;AACF,gBAAA,CAAA,CAAE,OAAOA,KAAAA,EAAO;AACd,oBAAA,MAAMG,OAAAA,GAAUH,KAAAA,YAAiBE,KAAAA,GAAQF,KAAAA,CAAMG,OAAO,GAAG,+BAAA;AAEzDxD,oBAAAA,MAAAA,CAAOsD,GAAG,CAACD,KAAK,CAAC,oDAAA,EAAsD;AACrEM,wBAAAA,OAAAA,EAASY,WAAWrC,GAAG,CAAC,CAAC9C,IAAAA,GAASA,KAAKqD,EAAE,CAAA;AACzCe,wBAAAA;AACF,qBAAA,CAAA;oBAEAe,UAAAA,CAAWH,OAAO,CAAC,CAAChF,IAAAA,GAAAA;AAClB8E,wBAAAA,WAAAA,CAAYI,GAAG,CAAClF,IAAAA,CAAKqD,EAAE,EAAE;AAAEA,4BAAAA,EAAAA,EAAIrD,KAAKqD,EAAE;4BAAEO,MAAAA,EAAQ,OAAA;4BAASK,KAAAA,EAAOG;AAAQ,yBAAA,CAAA;AAC1E,oBAAA,CAAA,CAAA;AACF,gBAAA;AACF,YAAA;YAEA,OAAOI,aAAAA,CAAc1B,GAAG,CACtB,CAACO,KAAOyB,WAAAA,CAAYG,GAAG,CAAC5B,EAAAA,CAAAA,IAAO;AAAEA,oBAAAA,EAAAA;oBAAIO,MAAAA,EAAQ,OAAA;oBAASK,KAAAA,EAAO;AAAqB,iBAAA,CAAA;AAEtF,QAAA,CAAA;AAEA;;QAGA,MAAMD,cAAatB,KAAa,EAAA;AAC9B,YAAA,IAAI,CAAE,MAAM,IAAI,CAACzB,SAAS,EAAA,IAAO,CAACJ,WAAAA,EAAa;AAC7C,gBAAA,MAAM,IAAIsD,KAAAA,CAAM,oCAAA,CAAA;AAClB,YAAA;;;AAIA,YAAA,MAAMkB,aAAa3C,KAAAA,CAChBI,GAAG,CAAC,CAAC9C,IAAAA,EAAM+C,SAAW;AAAE/C,oBAAAA,IAAAA;oBAAMsF,aAAAA,EAAevC;iBAAM,CAAA,CAAA,CACnDwC,MAAM,CAAC,CAAC,EAAEvF,IAAI,EAAE,GAAKA,IAAAA,CAAKE,IAAI,EAAEsF,UAAAA,CAAW,QAAA,CAAA,CAAA;;AAG9C,YAAA,MAAMC,kBAAkBJ,UAAAA,CAAWvC,GAAG,CAAC,CAAC,EAAE9C,IAAI,EAAE,GAAA;gBAC9C,MAAM0F,SAAAA,GAAa1F,IAAAA,CAAK2F,OAAO,EAAUD,SAAAA;gBACzC,OAAO;AACLE,oBAAAA,QAAAA,EAAUF,SAAAA,EAAWG,GAAAA,IAAO7F,IAAAA,CAAK6F,GAAG,IAAI,EAAA;AACxCC,oBAAAA,QAAAA,EAAU9F,KAAKE,IAAI;AACnB6F,oBAAAA,gBAAAA,EAAkB/F,KAAKgG,IAAI;oBAC3B3F,IAAAA,EAAMqF,SAAAA,EAAWrF,IAAAA,IAAQL,IAAAA,CAAKK,IAAI;AAClC4F,oBAAAA,QAAAA,EAAUjG,KAAKiG;AACjB,iBAAA;AACF,YAAA,CAAA,CAAA;AACA,YAAA,MAAMC,0BAAAA,GAA6B,IACjCC,KAAAA,CAAMC,IAAI,CAAC;AAAE5F,oBAAAA,MAAAA,EAAQkC,MAAMlC;AAAO,iBAAA,EAAG,IAAM,IAAA,CAAA;;;YAI7C,IAAI6E,UAAAA,CAAW7E,MAAM,KAAK,CAAA,EAAG;gBAC3B,OAAO0F,0BAAAA,EAAAA;AACT,YAAA;YAEA,MAAMG,QAAAA,GAAW,MAAMC,sBAAAA,CACrBb,eAAAA,EACA7E,MAAAA,CAAO2F,MAAM,CAACtB,GAAG,CAAC,oBAAA,CAAA,EAClBrE,MAAAA,CAAOsD,GAAG,CAAA;YAGZ,IAAIsC,KAAAA;YACJ,IAAI;AACF,gBAAA,MAAMC,YAAY,MAAM7F,MAAAA,CAAOM,EAAE,CAACC,KAAK,CAACuF,UAAU,EAAA;AAClDF,gBAAAA,KAAAA,GAAQC,UAAUD,KAAK;AACzB,YAAA,CAAA,CAAE,OAAOvC,KAAAA,EAAO;gBACd,MAAM,IAAIE,MAAM,6BAAA,EAA+B;oBAC7CwC,KAAAA,EAAO1C,KAAAA,YAAiBE,QAAQF,KAAAA,GAAQX;AAC1C,iBAAA,CAAA;AACF,YAAA;AAEA1C,YAAAA,MAAAA,CAAOsD,GAAG,CAAC0C,IAAI,CAAC,oDAAA,EAAsD;AACpE/F,gBAAAA,WAAAA;AACAgG,gBAAAA,UAAAA,EAAYxB,WAAW7E;AACzB,aAAA,CAAA;AAEA,YAAA,MAAMsG,MAAM,MAAMC,KAAAA,CAAM,GAAGlG,WAAAA,CAAY,gCAAgC,CAAC,EAAE;gBACxEmG,MAAAA,EAAQ,MAAA;gBACRC,IAAAA,EAAMZ,QAAAA;gBACNa,OAAAA,EAAS;oBACPC,aAAAA,EAAe,CAAC,OAAO,EAAEX,KAAAA,CAAAA;AAC3B;AACF,aAAA,CAAA;YAEA,IAAI,CAACM,GAAAA,CAAIM,EAAE,EAAE;gBACX,MAAMC,SAAAA,GAAY,MAAMP,GAAAA,CAAIQ,IAAI,EAAA;AAChC,gBAAA,MAAMnD,KAAAA,CAAM,CAAC,6BAA6B,CAAC,EAAE;oBAAEwC,KAAAA,EAAOU;AAAU,iBAAA,CAAA;AAClE,YAAA;YAEA,MAAME,cAAAA,GAAiBC,CAAAA,CAAEC,MAAM,CAAC;AAC9BC,gBAAAA,OAAAA,EAASF,CAAAA,CAAEG,KAAK,CACdH,CAAAA,CAAEC,MAAM,CAAC;AACPxE,oBAAAA,OAAAA,EAASuE,EAAEI,MAAM,EAAA;AACjBzF,oBAAAA,OAAAA,EAASqF,EAAEI,MAAM;AACnB,iBAAA,CAAA;AAEJ,aAAA,CAAA;YAEA,MAAM,EAAEF,OAAO,EAAE,GAAGH,eAAeM,KAAK,CAAC,MAAMf,GAAAA,CAAIgB,IAAI,EAAA,CAAA;YACvDlH,MAAAA,CAAOsD,GAAG,CAAC0C,IAAI,CAAC,CAAC,uCAAuC,EAAEc,OAAAA,CAAQlH,MAAM,CAAC,MAAM,CAAC,CAAA;;;;;YAMhF,OAAO6E,UAAAA,CAAW0C,MAAM,CAAC,CAACC,eAAe,EAAE1C,aAAa,EAAE,EAAE2C,WAAAA,GAAAA;AAC1DD,gBAAAA,aAAa,CAAC1C,aAAAA,CAAc,GAAGoC,OAAO,CAACO,WAAAA,CAAY;gBACnD,OAAOD,aAAAA;YACT,CAAA,EAAG9B,0BAAAA,EAAAA,CAAAA;AACL,QAAA;AACF,KAAA;AACF;;;;"}
|
|
@@ -3,18 +3,39 @@ declare const _default: {
|
|
|
3
3
|
find(ctx: Context): Promise<any>;
|
|
4
4
|
findOne(ctx: Context): Promise<void>;
|
|
5
5
|
destroy(ctx: Context): Promise<void>;
|
|
6
|
-
getAIMetadataCount(ctx: Context): Promise<any>;
|
|
7
|
-
generateAIMetadata(ctx: Context): Promise<any>;
|
|
8
6
|
/**
|
|
9
|
-
*
|
|
7
|
+
* `GET /upload/ai-metadata-jobs/pending-count`
|
|
8
|
+
*
|
|
9
|
+
* How many images a backfill job would have to process, i.e. those still
|
|
10
|
+
* missing AI metadata, alongside the total image count.
|
|
11
|
+
*/
|
|
12
|
+
getAIMetadataPendingCount(ctx: Context): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* `POST /upload/ai-metadata-jobs`
|
|
10
15
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
16
|
+
* Create a backfill job that generates AI metadata for every image still
|
|
17
|
+
* missing it, and return the job so the client can poll it. Processing runs
|
|
18
|
+
* detached from this request; see `generateAIMetadata` for the synchronous
|
|
19
|
+
* counterpart that works on an explicit selection.
|
|
20
|
+
*/
|
|
21
|
+
createAIMetadataJob(ctx: Context): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* `POST /upload/actions/generate-ai-metadata`
|
|
24
|
+
*
|
|
25
|
+
* Generate AI metadata for the explicit selection of files in the body,
|
|
26
|
+
* synchronously: the request resolves once every file has been processed and
|
|
27
|
+
* reports the outcome per file, so a single bad id or a non-image in the
|
|
28
|
+
* selection never fails the whole batch.
|
|
29
|
+
*
|
|
30
|
+
* For the whole-library backfill, see `createAIMetadataJob`.
|
|
31
|
+
*/
|
|
32
|
+
generateAIMetadata(ctx: Context): Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* `GET /upload/ai-metadata-jobs/latest`
|
|
14
35
|
*
|
|
15
|
-
*
|
|
36
|
+
* The most recent still-active backfill job, so a client that reloads mid-run
|
|
37
|
+
* can pick the progress bar back up. 404s when nothing is running.
|
|
16
38
|
*/
|
|
17
|
-
unstable_generateAIMetadata(ctx: Context): Promise<any>;
|
|
18
39
|
getLatestAIMetadataJob(ctx: Context): Promise<any>;
|
|
19
40
|
};
|
|
20
41
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-file.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;cAQjB,OAAO;iBAuCJ,OAAO;iBAiBP,OAAO;
|
|
1
|
+
{"version":3,"file":"admin-file.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;cAQjB,OAAO;iBAuCJ,OAAO;iBAiBP,OAAO;IAmB1B;;;;;OAKG;mCACkC,OAAO;IAwC5C;;;;;;;OAOG;6BAC4B,OAAO;IA4DtC;;;;;;;;;OASG;4BAC2B,OAAO;IA2BrC;;;;;OAKG;gCAC+B,OAAO;;AAzO3C,wBAuPE"}
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import type { Context } from 'koa';
|
|
2
2
|
declare const _default: {
|
|
3
3
|
bulkUpdateFileInfo(ctx: Context): Promise<void>;
|
|
4
|
+
/**
|
|
5
|
+
* `PUT /upload/files/:id`
|
|
6
|
+
*
|
|
7
|
+
* Update the editable metadata (`fileInfo`) of an existing file. Also reached
|
|
8
|
+
* through the `POST /upload` multiplexer, which delegates here with the id in
|
|
9
|
+
* `ctx.query` — hence the dual read below, route params winning.
|
|
10
|
+
*/
|
|
4
11
|
updateFileInfo(ctx: Context): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* `POST /upload/files/:id/replace`
|
|
14
|
+
*
|
|
15
|
+
* Replace the binary content of an existing file. Also reached through the
|
|
16
|
+
* `POST /upload` multiplexer, which delegates here with the id in `ctx.query`
|
|
17
|
+
* — hence the dual read below, route params winning.
|
|
18
|
+
*/
|
|
5
19
|
replaceFile(ctx: Context): Promise<void>;
|
|
6
20
|
uploadFiles(ctx: Context): Promise<any>;
|
|
7
21
|
/**
|
|
8
|
-
*
|
|
22
|
+
* `POST /upload/files`
|
|
23
|
+
*
|
|
9
24
|
* Upload a single file and return the created File.
|
|
10
25
|
*
|
|
11
26
|
* Accepts one file per request (multipart `files` + `fileInfo`) and returns a
|
|
@@ -13,9 +28,10 @@ declare const _default: {
|
|
|
13
28
|
* generation inline — that responsibility is decoupled and will be handled by a
|
|
14
29
|
* background job. Auth and permission checks mirror `POST /upload`.
|
|
15
30
|
*/
|
|
16
|
-
|
|
31
|
+
uploadFile(ctx: Context): Promise<any>;
|
|
17
32
|
/**
|
|
18
|
-
*
|
|
33
|
+
* `POST /upload/actions/upload-from-urls`
|
|
34
|
+
*
|
|
19
35
|
* Upload files from URLs with SSE streaming for per-file progress
|
|
20
36
|
*
|
|
21
37
|
* Accepts JSON body with URLs and fetches them server-side.
|
|
@@ -26,7 +42,7 @@ declare const _default: {
|
|
|
26
42
|
* - file:error — when a URL fetch or upload fails
|
|
27
43
|
* - stream:complete — final summary with all results
|
|
28
44
|
*/
|
|
29
|
-
|
|
45
|
+
uploadFromUrls(ctx: Context): Promise<any>;
|
|
30
46
|
upload(ctx: Context): Promise<void>;
|
|
31
47
|
};
|
|
32
48
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-upload.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-upload.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;4BAWH,OAAO;
|
|
1
|
+
{"version":3,"file":"admin-upload.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/admin-upload.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;4BAWH,OAAO;IA+BrC;;;;;;OAMG;wBACuB,OAAO;IA8BjC;;;;;;OAMG;qBACoB,OAAO;qBA4DP,OAAO;IA0E9B;;;;;;;;;OASG;oBACmB,OAAO;IAsE7B;;;;;;;;;;;;OAYG;wBACuB,OAAO;gBAmIf,OAAO;;AAlb3B,wBAkcE"}
|
|
@@ -3,9 +3,9 @@ export declare const controllers: {
|
|
|
3
3
|
find(ctx: import("koa").Context): Promise<any>;
|
|
4
4
|
findOne(ctx: import("koa").Context): Promise<void>;
|
|
5
5
|
destroy(ctx: import("koa").Context): Promise<void>;
|
|
6
|
-
|
|
6
|
+
getAIMetadataPendingCount(ctx: import("koa").Context): Promise<any>;
|
|
7
|
+
createAIMetadataJob(ctx: import("koa").Context): Promise<any>;
|
|
7
8
|
generateAIMetadata(ctx: import("koa").Context): Promise<any>;
|
|
8
|
-
unstable_generateAIMetadata(ctx: import("koa").Context): Promise<any>;
|
|
9
9
|
getLatestAIMetadataJob(ctx: import("koa").Context): Promise<any>;
|
|
10
10
|
};
|
|
11
11
|
'admin-folder': {
|
|
@@ -28,8 +28,8 @@ export declare const controllers: {
|
|
|
28
28
|
updateFileInfo(ctx: import("koa").Context): Promise<void>;
|
|
29
29
|
replaceFile(ctx: import("koa").Context): Promise<void>;
|
|
30
30
|
uploadFiles(ctx: import("koa").Context): Promise<any>;
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
uploadFile(ctx: import("koa").Context): Promise<any>;
|
|
32
|
+
uploadFromUrls(ctx: import("koa").Context): Promise<any>;
|
|
33
33
|
upload(ctx: import("koa").Context): Promise<void>;
|
|
34
34
|
};
|
|
35
35
|
'content-api': ({ strapi }: {
|
|
@@ -64,9 +64,9 @@ declare const _default: () => {
|
|
|
64
64
|
find(ctx: import("koa").Context): Promise<any>;
|
|
65
65
|
findOne(ctx: import("koa").Context): Promise<void>;
|
|
66
66
|
destroy(ctx: import("koa").Context): Promise<void>;
|
|
67
|
-
|
|
67
|
+
getAIMetadataPendingCount(ctx: import("koa").Context): Promise<any>;
|
|
68
|
+
createAIMetadataJob(ctx: import("koa").Context): Promise<any>;
|
|
68
69
|
generateAIMetadata(ctx: import("koa").Context): Promise<any>;
|
|
69
|
-
unstable_generateAIMetadata(ctx: import("koa").Context): Promise<any>;
|
|
70
70
|
getLatestAIMetadataJob(ctx: import("koa").Context): Promise<any>;
|
|
71
71
|
};
|
|
72
72
|
'admin-folder': {
|
|
@@ -89,8 +89,8 @@ declare const _default: () => {
|
|
|
89
89
|
updateFileInfo(ctx: import("koa").Context): Promise<void>;
|
|
90
90
|
replaceFile(ctx: import("koa").Context): Promise<void>;
|
|
91
91
|
uploadFiles(ctx: import("koa").Context): Promise<any>;
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
uploadFile(ctx: import("koa").Context): Promise<any>;
|
|
93
|
+
uploadFromUrls(ctx: import("koa").Context): Promise<any>;
|
|
94
94
|
upload(ctx: import("koa").Context): Promise<void>;
|
|
95
95
|
};
|
|
96
96
|
'content-api': ({ strapi }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../../server/src/routes/admin.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../../server/src/routes/admin.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;CAoTlB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Core } from '@strapi/types';
|
|
2
2
|
import { File } from '../types';
|
|
3
|
-
import type {
|
|
4
|
-
export type AIMetadataFileResult =
|
|
3
|
+
import type { GenerateAIMetadata } from '../../../shared/contracts/files';
|
|
4
|
+
export type AIMetadataFileResult = GenerateAIMetadata.FileResult;
|
|
5
5
|
declare const createAIMetadataService: ({ strapi }: {
|
|
6
6
|
strapi: Core.Strapi;
|
|
7
7
|
}) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-metadata.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAa,IAAI,EAAE,MAAM,UAAU,CAAC;AAQ3C,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"ai-metadata.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAa,IAAI,EAAE,MAAM,UAAU,CAAC;AAQ3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,UAAU,CAAC;AAoBjE,QAAA,MAAM,uBAAuB,GAAI,YAAY;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE;;;;;;IA2ChE;;;OAGG;qCAEM,IAAI,EAAE,mBACI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,QAC7D;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE;IAoC/B;;OAEG;gCAC+B,MAAM,QAAQ;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDvF;;;;;;;;;;;;;OAaG;8BAEQ,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,QACzB;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAqElC;;OAEG;wBACuB,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAuFjG,CAAC;AAEF,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
|
|
@@ -8,46 +8,24 @@ export interface AIMetadataJob {
|
|
|
8
8
|
completedAt?: Date;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* GET /upload/
|
|
11
|
+
* GET /upload/ai-metadata-jobs/latest
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* The most recent still-active backfill job. 404s when nothing is running, so
|
|
14
|
+
* there is no `null` on the wire — callers get an error response instead.
|
|
14
15
|
*/
|
|
15
16
|
export declare namespace GetLatestAIMetadataJob {
|
|
16
17
|
interface Request {
|
|
17
18
|
query?: {};
|
|
18
19
|
}
|
|
19
20
|
interface Response {
|
|
20
|
-
data: AIMetadataJob
|
|
21
|
+
data: AIMetadataJob;
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
|
-
* POST /upload/
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* The other two job endpoints — `POST /upload/ai-metadata-jobs` and
|
|
26
|
+
* `GET /upload/ai-metadata-jobs/pending-count` — are declared in `./files.ts`
|
|
27
|
+
* as `CreateAIMetadataJob` and `GetAIMetadataPendingCount`. They used to be
|
|
28
|
+
* duplicated here under different names and with response shapes that had
|
|
29
|
+
* drifted from what the controllers actually return; `./files.ts` is the one
|
|
30
|
+
* that matched, so it is the single source of truth for both.
|
|
27
31
|
*/
|
|
28
|
-
export declare namespace StartAIMetadataJob {
|
|
29
|
-
interface Request {
|
|
30
|
-
body?: {};
|
|
31
|
-
}
|
|
32
|
-
interface Response {
|
|
33
|
-
data: {
|
|
34
|
-
jobId: number;
|
|
35
|
-
status: string;
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* GET /upload/actions/generate-ai-metadata/count
|
|
41
|
-
*
|
|
42
|
-
* Return count of images without metadata
|
|
43
|
-
*/
|
|
44
|
-
export declare namespace GetAIMetadataCount {
|
|
45
|
-
interface Request {
|
|
46
|
-
query?: {};
|
|
47
|
-
}
|
|
48
|
-
interface Response {
|
|
49
|
-
data: {
|
|
50
|
-
count: number;
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-metadata-jobs.d.ts","sourceRoot":"","sources":["../../../shared/contracts/ai-metadata-jobs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC9C,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED
|
|
1
|
+
{"version":3,"file":"ai-metadata-jobs.d.ts","sourceRoot":"","sources":["../../../shared/contracts/ai-metadata-jobs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC9C,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,CAAC,OAAO,WAAW,sBAAsB,CAAC;IAC9C,UAAiB,OAAO;QACtB,KAAK,CAAC,EAAE,EAAE,CAAC;KACZ;IAED,UAAiB,QAAQ;QACvB,IAAI,EAAE,aAAa,CAAC;KACrB;CACF;AAED;;;;;;;GAOG"}
|
|
@@ -201,12 +201,12 @@ export declare namespace CreateFile {
|
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
/**
|
|
204
|
-
* POST /upload/
|
|
204
|
+
* POST /upload/files - Upload a single file
|
|
205
205
|
*
|
|
206
206
|
* Accepts one file per request (multipart `files` + `fileInfo`) and returns the
|
|
207
207
|
* single created `File`. Does not run inline AI metadata generation.
|
|
208
208
|
*/
|
|
209
|
-
export declare namespace
|
|
209
|
+
export declare namespace UploadFile {
|
|
210
210
|
interface Request {
|
|
211
211
|
body: FormData;
|
|
212
212
|
}
|
|
@@ -216,7 +216,7 @@ export declare namespace UnstableCreateFile {
|
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
/**
|
|
219
|
-
* POST /upload/
|
|
219
|
+
* POST /upload/actions/upload-from-urls - Stream upload files with partial success support
|
|
220
220
|
*
|
|
221
221
|
* Still used by the URL upload flow (`uploadFromUrls`).
|
|
222
222
|
*/
|
|
@@ -234,7 +234,7 @@ export declare namespace CreateFilesStream {
|
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
236
|
/**
|
|
237
|
-
* POST /upload/
|
|
237
|
+
* POST /upload/actions/upload-from-urls - SSE streaming event types
|
|
238
238
|
*
|
|
239
239
|
* The endpoint streams Server-Sent Events as each file is processed.
|
|
240
240
|
* The final `stream:complete` event carries the same shape as CreateFilesStream.Response.
|
|
@@ -306,9 +306,9 @@ export declare namespace BulkUpdateFiles {
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
/**
|
|
309
|
-
* GET /upload/
|
|
309
|
+
* GET /upload/ai-metadata-jobs/pending-count - Get count of images without metadata
|
|
310
310
|
*/
|
|
311
|
-
export declare namespace
|
|
311
|
+
export declare namespace GetAIMetadataPendingCount {
|
|
312
312
|
interface Request {
|
|
313
313
|
query: {};
|
|
314
314
|
}
|
|
@@ -321,9 +321,9 @@ export declare namespace GetAIMetadataCount {
|
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
/**
|
|
324
|
-
* POST /upload/
|
|
324
|
+
* POST /upload/ai-metadata-jobs - Create a backfill job over every image missing metadata
|
|
325
325
|
*/
|
|
326
|
-
export declare namespace
|
|
326
|
+
export declare namespace CreateAIMetadataJob {
|
|
327
327
|
interface Request {
|
|
328
328
|
body: {};
|
|
329
329
|
}
|
|
@@ -339,14 +339,14 @@ export declare namespace GenerateAIMetadata {
|
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
341
|
/**
|
|
342
|
-
* POST /upload/
|
|
342
|
+
* POST /upload/actions/generate-ai-metadata - Generate AI metadata for selected files
|
|
343
343
|
*
|
|
344
344
|
* Synchronous (no job): generates and persists alt text / caption for the given
|
|
345
345
|
* files and reports the outcome per file. Non-images are `skipped`; ids that no
|
|
346
346
|
* longer exist and files whose generation failed are reported as `error` rather
|
|
347
347
|
* than failing the whole request.
|
|
348
348
|
*/
|
|
349
|
-
export declare namespace
|
|
349
|
+
export declare namespace GenerateAIMetadata {
|
|
350
350
|
type FileStatus = 'success' | 'skipped' | 'error';
|
|
351
351
|
interface FileResult {
|
|
352
352
|
id: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../shared/contracts/files.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../shared/contracts/files.ts"],"names":[],"mappings":"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"}
|