@ossy/media-tasks 1.40.2 → 3.0.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/README.md +30 -9
- package/package.json +4 -4
- package/src/{resize-common-web.resource.js → resize-common-web.schema.js} +1 -1
- package/src/resize-common-web.task.js +23 -23
- package/src/{visual-content-descriptors.resource.js → visual-content-descriptors.schema.js} +1 -1
- package/src/visual-content-descriptors.task.js +7 -7
package/README.md
CHANGED
|
@@ -2,14 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
Changestream-triggered media processing tasks for the Ossy platform.
|
|
4
4
|
|
|
5
|
-
Tasks in this package are registered with `TaskService.RegisterTask()` at API startup and fire automatically when matching events
|
|
5
|
+
Tasks in this package are registered with `TaskService.RegisterTask()` at API startup and fire automatically when matching ADR 0008 resource events appear on the event store change stream.
|
|
6
6
|
|
|
7
7
|
## Tasks
|
|
8
8
|
|
|
9
|
-
| Task | Trigger | Description |
|
|
10
|
-
|
|
11
|
-
|
|
|
12
|
-
|
|
|
9
|
+
| Task id | Trigger | Description |
|
|
10
|
+
|---------|---------|-------------|
|
|
11
|
+
| `@ossy/media-tasks/tasks/resize-common-web` | `@ossy/platform/schema/file` `Created` (`content.ContentType: image/*`) | Generates common web thumbnail and gallery sizes using `sharp` |
|
|
12
|
+
| `@ossy/media-tasks/tasks/visual-content-descriptors` | `@ossy/platform/schema/file` `Created` (`image/*`, `video/*`) | Uses GPT-4o to generate title, description, tags, and alt text |
|
|
13
|
+
|
|
14
|
+
## Schemas
|
|
15
|
+
|
|
16
|
+
Task outcome schemas live in `src/*.schema.js` and are auto-discovered at build time:
|
|
17
|
+
|
|
18
|
+
| Schema | Id |
|
|
19
|
+
|--------|----|
|
|
20
|
+
| Resize Common Web | `@ossy/media-tasks/schema/resize-common-web` |
|
|
21
|
+
| Visual Content Descriptors | `@ossy/media-tasks/schema/visual-content-descriptors` |
|
|
22
|
+
|
|
23
|
+
These describe optional task-run documents; handlers are implemented in the matching `*.task.js` files.
|
|
13
24
|
|
|
14
25
|
## Task contract
|
|
15
26
|
|
|
@@ -17,12 +28,22 @@ Each `*.task.js` file exports:
|
|
|
17
28
|
|
|
18
29
|
```js
|
|
19
30
|
export const metadata = {
|
|
20
|
-
id: 'my-task',
|
|
21
|
-
triggers: [{
|
|
31
|
+
id: '@ossy/media-tasks/tasks/my-task',
|
|
32
|
+
triggers: [{ type, event, match?, location? }],
|
|
22
33
|
}
|
|
23
34
|
|
|
24
|
-
export
|
|
35
|
+
export async function run ({ event, sdk }) { ... }
|
|
25
36
|
```
|
|
26
37
|
|
|
27
|
-
- `
|
|
38
|
+
- `metadata.id` — canonical task id (`@ossy/<package>/tasks/…`)
|
|
39
|
+
- `triggers[].type` — resource schema id to watch (e.g. `@ossy/platform/schema/file`)
|
|
40
|
+
- `triggers[].event` — lifecycle event name (`Created`, `Patched`, …)
|
|
41
|
+
- `triggers[].match` — optional field matcher on `event.payload` (e.g. `{ 'content.ContentType': 'image/*' }`)
|
|
42
|
+
- `event` — the raw eventstore `fullDocument` (`resourceId`, `type`, `event`, `payload`, …)
|
|
28
43
|
- `sdk` — platform SDK instance (passed from API startup; `null` during local dev if unconfigured)
|
|
44
|
+
|
|
45
|
+
## Dependencies
|
|
46
|
+
|
|
47
|
+
- **`sharp`** (peer) — image resizing in `resize-common-web`
|
|
48
|
+
- **`openai`** (peer) — GPT-4o vision in `visual-content-descriptors`
|
|
49
|
+
- **`@ossy/platform`** — `StorageClient.load` for reading uploaded file bytes (provided at runtime by the platform server)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/media-tasks",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Changestream-triggered media processing tasks (image resize, AI descriptors)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"typecheck": "echo \"No TypeScript in media-tasks package\" && exit 0"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@ossy/observability": "^
|
|
19
|
-
"@ossy/resources": "^
|
|
18
|
+
"@ossy/observability": "^3.0.1",
|
|
19
|
+
"@ossy/resources": "^3.0.1"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"openai": ">=4",
|
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
],
|
|
33
33
|
"author": "Ossy <yourfriends@ossy.se> (https://ossy.se)",
|
|
34
34
|
"license": "MIT",
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "4a70ec216448680d2fddc57b2a8a0077489720ae"
|
|
36
36
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createLogger } from '@ossy/observability'
|
|
2
|
+
import { StorageClient } from '@ossy/platform'
|
|
2
3
|
import { GetResource } from '@ossy/resources'
|
|
3
4
|
|
|
4
5
|
const log = createLogger('media-tasks')
|
|
@@ -13,47 +14,46 @@ const Sizes = [
|
|
|
13
14
|
]
|
|
14
15
|
|
|
15
16
|
export const metadata = {
|
|
16
|
-
id: 'resize-common-web',
|
|
17
|
+
id: '@ossy/media-tasks/tasks/resize-common-web',
|
|
17
18
|
triggers: [
|
|
18
19
|
{
|
|
19
|
-
|
|
20
|
+
type: '@ossy/platform/schema/file',
|
|
20
21
|
event: 'Created',
|
|
21
|
-
|
|
22
|
+
match: { 'content.ContentType': 'image/*' },
|
|
22
23
|
},
|
|
23
24
|
],
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export async function run ({ event, sdk }) {
|
|
27
28
|
const { default: sharp } = await import('sharp')
|
|
28
|
-
const resourceId = event.
|
|
29
|
+
const resourceId = event.resourceId
|
|
29
30
|
|
|
30
|
-
log.info(`[resize-common-web] starting for resource ${resourceId}`)
|
|
31
|
+
log.info(`[media-tasks/tasks/resize-common-web] starting for resource ${resourceId}`)
|
|
31
32
|
|
|
32
|
-
const resource = await sdk.invoke(GetResource, {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const resource = await sdk.invoke(GetResource, { resourceId })
|
|
34
|
+
const key = resource?.content?.Key
|
|
35
|
+
if (!key) {
|
|
36
|
+
throw new Error(`[media-tasks/tasks/resize-common-web] missing storage key for ${resourceId}`)
|
|
37
|
+
}
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
const { buffer: sourceBuffer, exists } = await StorageClient.load(key)
|
|
40
|
+
if (!exists || !sourceBuffer) {
|
|
41
|
+
throw new Error(`[media-tasks/tasks/resize-common-web] missing file bytes for ${resourceId}`)
|
|
42
|
+
}
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
log.info(`[media-tasks/tasks/resize-common-web] Resizing ${resourceId}`)
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
for (const { width, height, name } of Sizes) {
|
|
47
|
+
const resizedBuffer = await sharp(sourceBuffer).resize(width, height).toBuffer()
|
|
48
|
+
const mime = resource.content?.ContentType ?? 'image/jpeg'
|
|
49
|
+
const file = new File([new Uint8Array(resizedBuffer)], name, { type: mime })
|
|
43
50
|
|
|
44
|
-
log.info(`[resize-common-web] Uploading ${name} for ${resourceId}`)
|
|
51
|
+
log.info(`[media-tasks/tasks/resize-common-web] Uploading ${name} for ${resourceId}`)
|
|
45
52
|
try {
|
|
46
|
-
|
|
47
|
-
await sdk.resources.uploadNamedVersion({
|
|
48
|
-
id: resourceId,
|
|
49
|
-
name: name,
|
|
50
|
-
file: file,
|
|
51
|
-
})
|
|
53
|
+
await sdk.resources.uploadNamedVersion({ id: resourceId, name, file })
|
|
52
54
|
} catch (error) {
|
|
53
|
-
log.error(`[resize-common-web] Error uploading ${name} for ${resourceId}`, undefined, error)
|
|
55
|
+
log.error(`[media-tasks/tasks/resize-common-web] Error uploading ${name} for ${resourceId}`, undefined, error)
|
|
54
56
|
throw error
|
|
55
57
|
}
|
|
56
|
-
|
|
57
|
-
log.info(`[resize-common-web] Uploaded ${name} for ${resourceId}`)
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -2,25 +2,25 @@ import { GetResource, UpdateResourceName, UpdateResourceContent } from '@ossy/re
|
|
|
2
2
|
import { OpenAi } from './openai.integration.js'
|
|
3
3
|
|
|
4
4
|
export const metadata = {
|
|
5
|
-
id: 'visual-content-descriptors',
|
|
5
|
+
id: '@ossy/media-tasks/tasks/visual-content-descriptors',
|
|
6
6
|
triggers: [
|
|
7
7
|
{
|
|
8
|
-
|
|
8
|
+
type: '@ossy/platform/schema/file',
|
|
9
9
|
event: 'Created',
|
|
10
|
-
|
|
10
|
+
match: { 'content.ContentType': 'image/*' },
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
|
-
|
|
13
|
+
type: '@ossy/platform/schema/file',
|
|
14
14
|
event: 'Created',
|
|
15
|
-
|
|
15
|
+
match: { 'content.ContentType': 'video/*' },
|
|
16
16
|
},
|
|
17
17
|
],
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export async function run ({ event, sdk }) {
|
|
21
|
-
const resourceId = event.
|
|
21
|
+
const resourceId = event.resourceId
|
|
22
22
|
|
|
23
|
-
const resource = await sdk.invoke(GetResource, {
|
|
23
|
+
const resource = await sdk.invoke(GetResource, { resourceId })
|
|
24
24
|
const visualContentDescriptors = await OpenAi.getVisualContentDescriptors(resource.content.src)
|
|
25
25
|
|
|
26
26
|
await sdk.invoke(UpdateResourceName, { id: resource.id, name: visualContentDescriptors.title })
|