@transloadit/node 4.7.7 → 4.8.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 +97 -22
- package/dist/bearerToken.d.ts +1 -0
- package/dist/bearerToken.d.ts.map +1 -1
- package/dist/bearerToken.js +5 -3
- package/dist/bearerToken.js.map +1 -1
- package/dist/cli/commands/BaseCommand.d.ts +0 -1
- package/dist/cli/commands/BaseCommand.d.ts.map +1 -1
- package/dist/cli/commands/BaseCommand.js +7 -9
- package/dist/cli/commands/BaseCommand.js.map +1 -1
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +49 -29
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/generateIntentDocs.d.ts +5 -1
- package/dist/cli/generateIntentDocs.d.ts.map +1 -1
- package/dist/cli/generateIntentDocs.js +27 -9
- package/dist/cli/generateIntentDocs.js.map +1 -1
- package/dist/cli/helpers.d.ts +19 -4
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/helpers.js +232 -10
- package/dist/cli/helpers.js.map +1 -1
- package/dist/cli/intentCommandSpecs.d.ts.map +1 -1
- package/dist/cli/intentCommandSpecs.js +4 -6
- package/dist/cli/intentCommandSpecs.js.map +1 -1
- package/dist/cli/intentRuntime.d.ts.map +1 -1
- package/dist/cli/intentRuntime.js +4 -4
- package/dist/cli/intentRuntime.js.map +1 -1
- package/dist/cli/semanticIntents/imageDescribe.d.ts +3 -1
- package/dist/cli/semanticIntents/imageDescribe.d.ts.map +1 -1
- package/dist/cli/semanticIntents/imageDescribe.js +1 -1
- package/dist/cli/semanticIntents/imageDescribe.js.map +1 -1
- package/dist/cli/semanticIntents/imageGenerate.d.ts +94 -0
- package/dist/cli/semanticIntents/imageGenerate.d.ts.map +1 -0
- package/dist/cli/semanticIntents/imageGenerate.js +215 -0
- package/dist/cli/semanticIntents/imageGenerate.js.map +1 -0
- package/dist/cli/semanticIntents/index.d.ts +3 -1
- package/dist/cli/semanticIntents/index.d.ts.map +1 -1
- package/dist/cli/semanticIntents/index.js +2 -0
- package/dist/cli/semanticIntents/index.js.map +1 -1
- package/dist/cli/semanticIntents/markdownPdf.js +1 -1
- package/dist/cli/semanticIntents/markdownPdf.js.map +1 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/bearerToken.ts +14 -3
- package/src/cli/commands/BaseCommand.ts +7 -9
- package/src/cli/commands/auth.ts +66 -32
- package/src/cli/generateIntentDocs.ts +30 -9
- package/src/cli/helpers.ts +278 -13
- package/src/cli/intentCommandSpecs.ts +4 -9
- package/src/cli/intentRuntime.ts +8 -3
- package/src/cli/semanticIntents/imageDescribe.ts +4 -1
- package/src/cli/semanticIntents/imageGenerate.ts +254 -0
- package/src/cli/semanticIntents/index.ts +6 -1
- package/src/cli/semanticIntents/markdownPdf.ts +1 -1
- package/src/cli.ts +3 -2
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { basename } from 'node:path'
|
|
2
|
+
import type { IntentOptionDefinition, PreparedIntentInputs } from '../intentRuntime.ts'
|
|
3
|
+
import type { SemanticIntentDescriptor, SemanticIntentPresentation } from './index.ts'
|
|
4
|
+
import { parseOptionalEnumValue } from './parsing.ts'
|
|
5
|
+
|
|
6
|
+
const defaultImageGenerateModel = 'google/nano-banana-2'
|
|
7
|
+
const imageGenerateFormats = ['jpeg', 'jpg', 'png', 'gif', 'webp', 'svg'] as const
|
|
8
|
+
|
|
9
|
+
const imageGenerateOptionDefinitions = [
|
|
10
|
+
{
|
|
11
|
+
name: 'prompt',
|
|
12
|
+
kind: 'string',
|
|
13
|
+
propertyName: 'prompt',
|
|
14
|
+
optionFlags: '--prompt',
|
|
15
|
+
description: 'The prompt describing the desired image content.',
|
|
16
|
+
required: true,
|
|
17
|
+
exampleValue: JSON.stringify('A red bicycle in a studio'),
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'model',
|
|
21
|
+
kind: 'string',
|
|
22
|
+
propertyName: 'model',
|
|
23
|
+
optionFlags: '--model',
|
|
24
|
+
description: `The AI model to use for image generation. Defaults to ${defaultImageGenerateModel}.`,
|
|
25
|
+
required: false,
|
|
26
|
+
exampleValue: defaultImageGenerateModel,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'format',
|
|
30
|
+
kind: 'string',
|
|
31
|
+
propertyName: 'format',
|
|
32
|
+
optionFlags: '--format',
|
|
33
|
+
description: 'Format of the generated image.',
|
|
34
|
+
required: false,
|
|
35
|
+
exampleValue: 'jpg',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'seed',
|
|
39
|
+
kind: 'number',
|
|
40
|
+
propertyName: 'seed',
|
|
41
|
+
optionFlags: '--seed',
|
|
42
|
+
description: 'Seed for the random number generator.',
|
|
43
|
+
required: false,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'aspectRatio',
|
|
47
|
+
kind: 'string',
|
|
48
|
+
propertyName: 'aspectRatio',
|
|
49
|
+
optionFlags: '--aspect-ratio',
|
|
50
|
+
description: 'Aspect ratio of the generated image.',
|
|
51
|
+
required: false,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'height',
|
|
55
|
+
kind: 'number',
|
|
56
|
+
propertyName: 'height',
|
|
57
|
+
optionFlags: '--height',
|
|
58
|
+
description: 'Height of the generated image.',
|
|
59
|
+
required: false,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'width',
|
|
63
|
+
kind: 'number',
|
|
64
|
+
propertyName: 'width',
|
|
65
|
+
optionFlags: '--width',
|
|
66
|
+
description: 'Width of the generated image.',
|
|
67
|
+
required: false,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'style',
|
|
71
|
+
kind: 'string',
|
|
72
|
+
propertyName: 'style',
|
|
73
|
+
optionFlags: '--style',
|
|
74
|
+
description: 'Style of the generated image.',
|
|
75
|
+
required: false,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'numOutputs',
|
|
79
|
+
kind: 'number',
|
|
80
|
+
propertyName: 'numOutputs',
|
|
81
|
+
optionFlags: '--num-outputs',
|
|
82
|
+
description: 'Number of image variants to generate.',
|
|
83
|
+
required: false,
|
|
84
|
+
},
|
|
85
|
+
] as const satisfies readonly IntentOptionDefinition[]
|
|
86
|
+
|
|
87
|
+
const imageGenerateCommandPresentation = {
|
|
88
|
+
description: 'Generate images from text prompts',
|
|
89
|
+
details:
|
|
90
|
+
'Runs `/image/generate`. Without inputs, this is text-to-image. With one or more `--input` files, the inputs are bundled into a single assembly so the prompt can refer to them by filename.',
|
|
91
|
+
examples: [
|
|
92
|
+
[
|
|
93
|
+
'Generate an image from text',
|
|
94
|
+
'transloadit image generate --prompt "A red bicycle in a studio" --out output.png',
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
'Guide generation with one input image',
|
|
98
|
+
'transloadit image generate --input subject.jpg --prompt "Place subject.jpg on a magazine cover" --out output.png',
|
|
99
|
+
],
|
|
100
|
+
[
|
|
101
|
+
'Guide generation with multiple input images',
|
|
102
|
+
'transloadit image generate --input person1.jpg --input person2.jpg --input background.jpg --prompt "Place person1.jpg feeding person2.jpg in front of background.jpg" --out output.png',
|
|
103
|
+
],
|
|
104
|
+
] as Array<[string, string]>,
|
|
105
|
+
} as const satisfies SemanticIntentPresentation
|
|
106
|
+
|
|
107
|
+
function parseOptionalFormat(value: unknown): (typeof imageGenerateFormats)[number] | null {
|
|
108
|
+
return parseOptionalEnumValue({
|
|
109
|
+
flagName: '--format',
|
|
110
|
+
supportedValues: imageGenerateFormats,
|
|
111
|
+
value,
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function parseRequiredPrompt(value: unknown): string {
|
|
116
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
117
|
+
throw new Error('image generate requires --prompt')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return value
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function parseOptionalNumber(flagName: string, value: unknown): number | undefined {
|
|
124
|
+
if (value == null || value === '') {
|
|
125
|
+
return undefined
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const numericValue = typeof value === 'number' ? value : Number(String(value).trim())
|
|
129
|
+
if (Number.isNaN(numericValue)) {
|
|
130
|
+
throw new Error(`${flagName} must be a number`)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return numericValue
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function parseOptionalIntegerRange(
|
|
137
|
+
flagName: string,
|
|
138
|
+
value: unknown,
|
|
139
|
+
{ max, min }: { max: number; min: number },
|
|
140
|
+
): number | undefined {
|
|
141
|
+
const numericValue = parseOptionalNumber(flagName, value)
|
|
142
|
+
if (numericValue == null) {
|
|
143
|
+
return undefined
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!Number.isInteger(numericValue) || numericValue < min || numericValue > max) {
|
|
147
|
+
throw new Error(`${flagName} must be an integer between ${min} and ${max}`)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return numericValue
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function createImageGenerateStep(
|
|
154
|
+
rawValues: Record<string, unknown>,
|
|
155
|
+
context: { hasInputs: boolean },
|
|
156
|
+
): Record<string, unknown> {
|
|
157
|
+
const step: Record<string, unknown> = {
|
|
158
|
+
robot: '/image/generate',
|
|
159
|
+
result: true,
|
|
160
|
+
model: defaultImageGenerateModel,
|
|
161
|
+
prompt: parseRequiredPrompt(rawValues.prompt),
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (context.hasInputs) {
|
|
165
|
+
step.use = {
|
|
166
|
+
steps: [':original'],
|
|
167
|
+
bundle_steps: true,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const model = rawValues.model
|
|
172
|
+
if (typeof model === 'string' && model.trim() !== '') {
|
|
173
|
+
step.model = model
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const format = parseOptionalFormat(rawValues.format)
|
|
177
|
+
if (format != null) {
|
|
178
|
+
step.format = format
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const seed = parseOptionalNumber('--seed', rawValues.seed)
|
|
182
|
+
if (seed != null) {
|
|
183
|
+
step.seed = seed
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const aspectRatio = rawValues.aspectRatio
|
|
187
|
+
if (typeof aspectRatio === 'string' && aspectRatio.trim() !== '') {
|
|
188
|
+
step.aspect_ratio = aspectRatio
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const height = parseOptionalNumber('--height', rawValues.height)
|
|
192
|
+
if (height != null) {
|
|
193
|
+
step.height = height
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const width = parseOptionalNumber('--width', rawValues.width)
|
|
197
|
+
if (width != null) {
|
|
198
|
+
step.width = width
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const style = rawValues.style
|
|
202
|
+
if (typeof style === 'string' && style.trim() !== '') {
|
|
203
|
+
step.style = style
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const numOutputs = parseOptionalIntegerRange('--num-outputs', rawValues.numOutputs, {
|
|
207
|
+
min: 1,
|
|
208
|
+
max: 10,
|
|
209
|
+
})
|
|
210
|
+
if (numOutputs != null) {
|
|
211
|
+
step.num_outputs = numOutputs
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return step
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function ensureUniqueInputBasenames(preparedInputs: PreparedIntentInputs): PreparedIntentInputs {
|
|
218
|
+
const seenBasenames = new Map<string, string>()
|
|
219
|
+
|
|
220
|
+
for (const input of preparedInputs.inputs) {
|
|
221
|
+
const inputBasename = basename(input)
|
|
222
|
+
const previousInput = seenBasenames.get(inputBasename)
|
|
223
|
+
if (previousInput != null) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`image generate requires unique input basenames when prompts refer to files; found duplicate ${inputBasename} in ${previousInput} and ${input}`,
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
seenBasenames.set(inputBasename, input)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return preparedInputs
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export const imageGenerateSemanticIntentDescriptor = {
|
|
236
|
+
createStep: createImageGenerateStep,
|
|
237
|
+
execution: {
|
|
238
|
+
kind: 'dynamic-step',
|
|
239
|
+
handler: 'image-generate',
|
|
240
|
+
resultStepName: 'generate',
|
|
241
|
+
fields: imageGenerateOptionDefinitions,
|
|
242
|
+
},
|
|
243
|
+
inputPolicy: {
|
|
244
|
+
kind: 'optional',
|
|
245
|
+
field: 'prompt',
|
|
246
|
+
attachUseWhenInputsProvided: false,
|
|
247
|
+
},
|
|
248
|
+
outputDescription: 'Write the result to this path',
|
|
249
|
+
async prepareInputs(preparedInputs) {
|
|
250
|
+
return await Promise.resolve(ensureUniqueInputBasenames(preparedInputs))
|
|
251
|
+
},
|
|
252
|
+
presentation: imageGenerateCommandPresentation,
|
|
253
|
+
runnerKind: 'bundled',
|
|
254
|
+
} as const satisfies SemanticIntentDescriptor
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
PreparedIntentInputs,
|
|
6
6
|
} from '../intentRuntime.ts'
|
|
7
7
|
import { imageDescribeSemanticIntentDescriptor } from './imageDescribe.ts'
|
|
8
|
+
import { imageGenerateSemanticIntentDescriptor } from './imageGenerate.ts'
|
|
8
9
|
import {
|
|
9
10
|
markdownDocxSemanticIntentDescriptor,
|
|
10
11
|
markdownPdfSemanticIntentDescriptor,
|
|
@@ -17,7 +18,10 @@ export interface SemanticIntentPresentation {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export interface SemanticIntentDescriptor {
|
|
20
|
-
createStep: (
|
|
21
|
+
createStep: (
|
|
22
|
+
rawValues: Record<string, unknown>,
|
|
23
|
+
context: { hasInputs: boolean },
|
|
24
|
+
) => Record<string, unknown>
|
|
21
25
|
execution: IntentDynamicStepExecutionDefinition
|
|
22
26
|
inputPolicy: IntentInputPolicy
|
|
23
27
|
outputDescription: string
|
|
@@ -31,6 +35,7 @@ export interface SemanticIntentDescriptor {
|
|
|
31
35
|
|
|
32
36
|
const semanticIntentDescriptors: Record<string, SemanticIntentDescriptor> = {
|
|
33
37
|
'image-describe': imageDescribeSemanticIntentDescriptor,
|
|
38
|
+
'image-generate': imageGenerateSemanticIntentDescriptor,
|
|
34
39
|
'markdown-pdf': {
|
|
35
40
|
...markdownPdfSemanticIntentDescriptor,
|
|
36
41
|
},
|
package/src/cli.ts
CHANGED
|
@@ -4,8 +4,7 @@ import { realpathSync } from 'node:fs'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import process from 'node:process'
|
|
6
6
|
import { fileURLToPath } from 'node:url'
|
|
7
|
-
import '
|
|
8
|
-
import { createCli } from './cli/commands/index.ts'
|
|
7
|
+
import { loadProjectDotenvIntoProcessEnv } from './cli/helpers.ts'
|
|
9
8
|
import { ensureError } from './cli/types.ts'
|
|
10
9
|
|
|
11
10
|
const currentFile = realpathSync(fileURLToPath(import.meta.url))
|
|
@@ -26,6 +25,8 @@ export function shouldRunCli(invoked?: string): boolean {
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
export async function main(args = process.argv.slice(2)): Promise<void> {
|
|
28
|
+
loadProjectDotenvIntoProcessEnv()
|
|
29
|
+
const { createCli } = await import('./cli/commands/index.ts')
|
|
29
30
|
const cli = createCli()
|
|
30
31
|
const exitCode = await cli.run(args)
|
|
31
32
|
if (exitCode !== 0) {
|