ugcinc 4.26.0 → 4.27.0
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 +220 -0
- package/dist/automations/nodes/create-dm.d.ts +7 -2
- package/dist/automations/nodes/create-dm.js +26 -2
- package/dist/automations/nodes/index.d.ts +6 -3
- package/dist/automations/nodes/remotion-composition.d.ts +6 -6
- package/dist/cli.js +49 -8
- package/dist/content-skills.d.ts +1 -0
- package/dist/content-skills.js +10 -0
- package/dist/imessage-conversation.d.ts +907 -0
- package/dist/imessage-conversation.js +331 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -3
- package/dist/media-analysis.d.ts +272 -272
- package/dist/media.d.ts +11 -0
- package/dist/media.js +12 -0
- package/dist/render/compositions/IMessageDmComposition/types.d.ts +20 -20
- package/dist/render/types/remotion-composition.d.ts +16 -16
- package/dist/skills.js +2 -61
- package/dist/types.d.ts +1 -0
- package/package.json +8 -3
- package/skills/content-automation/SKILL.md +82 -0
- package/skills/content-automation/references/build-review.md +66 -0
- package/skills/media/SKILL.md +83 -0
- package/skills/media/references/tools.md +64 -0
package/dist/media.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { BaseClient } from './base';
|
|
|
2
2
|
import type { MatchTextStyleParams, SampleColorsParams, MeasureLayoutParams, TranscribeAudioParams, MeasureAudioLevelsParams, ExtractFramesParams, DetectScenesParams, ReadImageTextParams, ReadVideoTextParams, MediaAnalysisJob } from './media-analysis';
|
|
3
3
|
import type { ListProfilePostsParams, ListProfilePostsResult, DownloadSocialPostParams, DownloadSocialPostResult } from './social-acquisition';
|
|
4
4
|
import type { ApiResponse } from './types';
|
|
5
|
+
import type { IMessageConversationInput, IMessageConversationJob } from './imessage-conversation';
|
|
5
6
|
export interface UserMedia {
|
|
6
7
|
id: string;
|
|
7
8
|
org_id: string;
|
|
@@ -216,6 +217,16 @@ export declare class MediaClient extends BaseClient {
|
|
|
216
217
|
getMediaAnalysis(params: {
|
|
217
218
|
jobId: string;
|
|
218
219
|
}): Promise<ApiResponse<MediaAnalysisJob>>;
|
|
220
|
+
/** Queue a native 60fps iMessage video or a lossless PNG snapshot of the same authored scene. */
|
|
221
|
+
renderIMessageConversation(params: IMessageConversationInput): Promise<ApiResponse<IMessageConversationJob>>;
|
|
222
|
+
/** Poll an iMessage render owned by this organization. */
|
|
223
|
+
getIMessageConversation(params: {
|
|
224
|
+
jobId: string;
|
|
225
|
+
}): Promise<ApiResponse<IMessageConversationJob>>;
|
|
226
|
+
/** Request cooperative cancellation; poll until cancelled or another terminal state. */
|
|
227
|
+
cancelIMessageConversation(params: {
|
|
228
|
+
jobId: string;
|
|
229
|
+
}): Promise<ApiResponse<IMessageConversationJob>>;
|
|
219
230
|
private waitForAnalysis;
|
|
220
231
|
/** List a bounded page of TikTok/Instagram references; does not download media. */
|
|
221
232
|
listProfilePosts(params: ListProfilePostsParams): Promise<ApiResponse<ListProfilePostsResult>>;
|
package/dist/media.js
CHANGED
|
@@ -40,6 +40,18 @@ class MediaClient extends base_1.BaseClient {
|
|
|
40
40
|
async getMediaAnalysis(params) {
|
|
41
41
|
return this.post('/media/analysis/status', params);
|
|
42
42
|
}
|
|
43
|
+
/** Queue a native 60fps iMessage video or a lossless PNG snapshot of the same authored scene. */
|
|
44
|
+
async renderIMessageConversation(params) {
|
|
45
|
+
return this.post('/media/render/imessage', params);
|
|
46
|
+
}
|
|
47
|
+
/** Poll an iMessage render owned by this organization. */
|
|
48
|
+
async getIMessageConversation(params) {
|
|
49
|
+
return this.post('/media/render/imessage/status', params);
|
|
50
|
+
}
|
|
51
|
+
/** Request cooperative cancellation; poll until cancelled or another terminal state. */
|
|
52
|
+
async cancelIMessageConversation(params) {
|
|
53
|
+
return this.post('/media/render/imessage/cancel', params);
|
|
54
|
+
}
|
|
43
55
|
async waitForAnalysis(initial) {
|
|
44
56
|
let response = initial;
|
|
45
57
|
for (let attempt = 0; attempt < 180 && response.ok && ['pending', 'processing'].includes(response.data.status); attempt++) {
|
|
@@ -385,37 +385,37 @@ export declare const iMessageDmPropsSchema: z.ZodObject<{
|
|
|
385
385
|
groupWithPrevious: z.ZodOptional<z.ZodBoolean>;
|
|
386
386
|
}, "strip", z.ZodTypeAny, {
|
|
387
387
|
id: string;
|
|
388
|
-
text: string;
|
|
389
388
|
sender: "user" | "recipient";
|
|
389
|
+
text: string;
|
|
390
390
|
imageUrl?: string | undefined;
|
|
391
391
|
groupWithPrevious?: boolean | undefined;
|
|
392
392
|
}, {
|
|
393
393
|
id: string;
|
|
394
|
-
text: string;
|
|
395
394
|
sender: "user" | "recipient";
|
|
395
|
+
text: string;
|
|
396
396
|
imageUrl?: string | undefined;
|
|
397
397
|
groupWithPrevious?: boolean | undefined;
|
|
398
398
|
}>, "many">>;
|
|
399
399
|
dynamicCrop: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
400
400
|
cropVerticalCenter: z.ZodOptional<z.ZodBoolean>;
|
|
401
401
|
}, "strip", z.ZodTypeAny, {
|
|
402
|
-
width?: number | undefined;
|
|
403
|
-
height?: number | undefined;
|
|
404
|
-
backgroundColor?: string | undefined;
|
|
405
402
|
time?: string | undefined;
|
|
406
|
-
|
|
407
|
-
username?: string | undefined;
|
|
408
|
-
profilePicUrl?: string | undefined;
|
|
403
|
+
fps?: number | undefined;
|
|
409
404
|
messages?: {
|
|
410
405
|
id: string;
|
|
411
|
-
text: string;
|
|
412
406
|
sender: "user" | "recipient";
|
|
407
|
+
text: string;
|
|
413
408
|
imageUrl?: string | undefined;
|
|
414
409
|
groupWithPrevious?: boolean | undefined;
|
|
415
410
|
}[] | undefined;
|
|
416
|
-
dynamicCrop?: Record<string, any> | undefined;
|
|
417
|
-
fps?: number | undefined;
|
|
418
411
|
durationInFrames?: number | undefined;
|
|
412
|
+
width?: number | undefined;
|
|
413
|
+
height?: number | undefined;
|
|
414
|
+
backgroundColor?: string | undefined;
|
|
415
|
+
lightMode?: boolean | undefined;
|
|
416
|
+
username?: string | undefined;
|
|
417
|
+
profilePicUrl?: string | undefined;
|
|
418
|
+
dynamicCrop?: Record<string, any> | undefined;
|
|
419
419
|
showDebugOverlay?: boolean | undefined;
|
|
420
420
|
referenceImageUrl?: string | undefined;
|
|
421
421
|
showReferenceImage?: boolean | undefined;
|
|
@@ -582,23 +582,23 @@ export declare const iMessageDmPropsSchema: z.ZodObject<{
|
|
|
582
582
|
readReceiptLeft?: number | undefined;
|
|
583
583
|
readReceiptRight?: number | undefined;
|
|
584
584
|
}, {
|
|
585
|
-
width?: number | undefined;
|
|
586
|
-
height?: number | undefined;
|
|
587
|
-
backgroundColor?: string | undefined;
|
|
588
585
|
time?: string | undefined;
|
|
589
|
-
|
|
590
|
-
username?: string | undefined;
|
|
591
|
-
profilePicUrl?: string | undefined;
|
|
586
|
+
fps?: number | undefined;
|
|
592
587
|
messages?: {
|
|
593
588
|
id: string;
|
|
594
|
-
text: string;
|
|
595
589
|
sender: "user" | "recipient";
|
|
590
|
+
text: string;
|
|
596
591
|
imageUrl?: string | undefined;
|
|
597
592
|
groupWithPrevious?: boolean | undefined;
|
|
598
593
|
}[] | undefined;
|
|
599
|
-
dynamicCrop?: Record<string, any> | undefined;
|
|
600
|
-
fps?: number | undefined;
|
|
601
594
|
durationInFrames?: number | undefined;
|
|
595
|
+
width?: number | undefined;
|
|
596
|
+
height?: number | undefined;
|
|
597
|
+
backgroundColor?: string | undefined;
|
|
598
|
+
lightMode?: boolean | undefined;
|
|
599
|
+
username?: string | undefined;
|
|
600
|
+
profilePicUrl?: string | undefined;
|
|
601
|
+
dynamicCrop?: Record<string, any> | undefined;
|
|
602
602
|
showDebugOverlay?: boolean | undefined;
|
|
603
603
|
referenceImageUrl?: string | undefined;
|
|
604
604
|
showReferenceImage?: boolean | undefined;
|
|
@@ -8,18 +8,18 @@ export declare const remotionCompositionSchema: z.ZodObject<{
|
|
|
8
8
|
durationInFrames: z.ZodNumber;
|
|
9
9
|
inputProps: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
10
10
|
}, "strict", z.ZodTypeAny, {
|
|
11
|
+
fps: number;
|
|
12
|
+
durationInFrames: number;
|
|
11
13
|
width: number;
|
|
12
14
|
height: number;
|
|
13
15
|
source: string;
|
|
14
|
-
fps: number;
|
|
15
|
-
durationInFrames: number;
|
|
16
16
|
inputProps: Record<string, unknown>;
|
|
17
17
|
}, {
|
|
18
|
+
fps: number;
|
|
19
|
+
durationInFrames: number;
|
|
18
20
|
width: number;
|
|
19
21
|
height: number;
|
|
20
22
|
source: string;
|
|
21
|
-
fps: number;
|
|
22
|
-
durationInFrames: number;
|
|
23
23
|
inputProps: Record<string, unknown>;
|
|
24
24
|
}>;
|
|
25
25
|
export type RemotionCompositionInput = z.infer<typeof remotionCompositionSchema>;
|
|
@@ -29,12 +29,12 @@ export declare const remotionCompositionPortSchema: z.ZodObject<{
|
|
|
29
29
|
isArray: z.ZodBoolean;
|
|
30
30
|
required: z.ZodBoolean;
|
|
31
31
|
}, "strict", z.ZodTypeAny, {
|
|
32
|
-
type: "number" | "boolean" | "object" | "
|
|
32
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
33
33
|
id: string;
|
|
34
34
|
isArray: boolean;
|
|
35
35
|
required: boolean;
|
|
36
36
|
}, {
|
|
37
|
-
type: "number" | "boolean" | "object" | "
|
|
37
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
38
38
|
id: string;
|
|
39
39
|
isArray: boolean;
|
|
40
40
|
required: boolean;
|
|
@@ -54,22 +54,22 @@ export declare const remotionCompositionNodeSchema: z.ZodObject<{
|
|
|
54
54
|
isArray: z.ZodBoolean;
|
|
55
55
|
required: z.ZodBoolean;
|
|
56
56
|
}, "strict", z.ZodTypeAny, {
|
|
57
|
-
type: "number" | "boolean" | "object" | "
|
|
57
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
58
58
|
id: string;
|
|
59
59
|
isArray: boolean;
|
|
60
60
|
required: boolean;
|
|
61
61
|
}, {
|
|
62
|
-
type: "number" | "boolean" | "object" | "
|
|
62
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
63
63
|
id: string;
|
|
64
64
|
isArray: boolean;
|
|
65
65
|
required: boolean;
|
|
66
66
|
}>, "many">, {
|
|
67
|
-
type: "number" | "boolean" | "object" | "
|
|
67
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
68
68
|
id: string;
|
|
69
69
|
isArray: boolean;
|
|
70
70
|
required: boolean;
|
|
71
71
|
}[], {
|
|
72
|
-
type: "number" | "boolean" | "object" | "
|
|
72
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
73
73
|
id: string;
|
|
74
74
|
isArray: boolean;
|
|
75
75
|
required: boolean;
|
|
@@ -77,6 +77,8 @@ export declare const remotionCompositionNodeSchema: z.ZodObject<{
|
|
|
77
77
|
outputMode: z.ZodEnum<["single", "per-input"]>;
|
|
78
78
|
selectionMode: z.ZodNull;
|
|
79
79
|
}, "strict", z.ZodTypeAny, {
|
|
80
|
+
fps: number;
|
|
81
|
+
durationInFrames: number;
|
|
80
82
|
width: number;
|
|
81
83
|
height: number;
|
|
82
84
|
source: string;
|
|
@@ -84,28 +86,26 @@ export declare const remotionCompositionNodeSchema: z.ZodObject<{
|
|
|
84
86
|
selectionMode: null;
|
|
85
87
|
outputType: "video" | "image";
|
|
86
88
|
inputs: {
|
|
87
|
-
type: "number" | "boolean" | "object" | "
|
|
89
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
88
90
|
id: string;
|
|
89
91
|
isArray: boolean;
|
|
90
92
|
required: boolean;
|
|
91
93
|
}[];
|
|
92
|
-
fps: number;
|
|
93
|
-
durationInFrames: number;
|
|
94
94
|
inputProps: Record<string, unknown>;
|
|
95
95
|
}, {
|
|
96
|
+
fps: number;
|
|
97
|
+
durationInFrames: number;
|
|
96
98
|
width: number;
|
|
97
99
|
height: number;
|
|
98
100
|
source: string;
|
|
99
101
|
outputMode: "per-input" | "single";
|
|
100
102
|
selectionMode: null;
|
|
101
103
|
inputs: {
|
|
102
|
-
type: "number" | "boolean" | "object" | "
|
|
104
|
+
type: "number" | "boolean" | "object" | "text" | "video" | "image" | "audio";
|
|
103
105
|
id: string;
|
|
104
106
|
isArray: boolean;
|
|
105
107
|
required: boolean;
|
|
106
108
|
}[];
|
|
107
|
-
fps: number;
|
|
108
|
-
durationInFrames: number;
|
|
109
109
|
inputProps: Record<string, unknown>;
|
|
110
110
|
outputType?: "video" | "image" | undefined;
|
|
111
111
|
}>;
|
package/dist/skills.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.skillFiles = void 0;
|
|
4
|
+
const content_skills_1 = require("./content-skills");
|
|
4
5
|
const run = 'npx ugcinc';
|
|
5
6
|
exports.skillFiles = {
|
|
6
7
|
'accounts/SKILL.md': `---
|
|
@@ -152,67 +153,6 @@ ${run} retry_posts '{"postIds":["id1"]}'
|
|
|
152
153
|
- After creating a post, tell the user the post ID and scheduled time
|
|
153
154
|
- For failed posts, check status first to understand the error before retrying
|
|
154
155
|
- If $ARGUMENTS is provided, interpret it as a natural language request
|
|
155
|
-
`,
|
|
156
|
-
'media/SKILL.md': `---
|
|
157
|
-
name: media
|
|
158
|
-
description: Manage UGC Inc media library - list, import, and organize videos, images, audio, and text. Use when the user wants to upload media, import audio, or manage their library.
|
|
159
|
-
allowed-tools: Bash, Read
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
You manage UGC Inc media through the CLI. Run tools with:
|
|
163
|
-
\`\`\`bash
|
|
164
|
-
${run} <tool_name> '<json_params>'
|
|
165
|
-
\`\`\`
|
|
166
|
-
|
|
167
|
-
Auth: \`npx ugcinc auth <api_key> [--admin]\`. Only needed once. Use \`--admin\` for admin keys.
|
|
168
|
-
|
|
169
|
-
## Tools
|
|
170
|
-
|
|
171
|
-
### list_media
|
|
172
|
-
List all media (user media + social audio).
|
|
173
|
-
\`\`\`bash
|
|
174
|
-
${run} list_media
|
|
175
|
-
${run} list_media '{"tag":"campaign-1"}'
|
|
176
|
-
${run} list_media '{"ids":["id1","id2"]}'
|
|
177
|
-
\`\`\`
|
|
178
|
-
|
|
179
|
-
### list_social_audio
|
|
180
|
-
List social audio only.
|
|
181
|
-
\`\`\`bash
|
|
182
|
-
${run} list_social_audio
|
|
183
|
-
${run} list_social_audio '{"tag":"trending"}'
|
|
184
|
-
\`\`\`
|
|
185
|
-
|
|
186
|
-
### create_media_from_urls
|
|
187
|
-
Import media from URLs (videos, images already hosted somewhere).
|
|
188
|
-
\`\`\`bash
|
|
189
|
-
${run} create_media_from_urls '{"urls":["https://example.com/video.mp4"],"tag":"imported"}'
|
|
190
|
-
${run} create_media_from_urls '{"urls":["url1","url2"],"names":["Video 1","Video 2"]}'
|
|
191
|
-
\`\`\`
|
|
192
|
-
|
|
193
|
-
### import_text
|
|
194
|
-
Import text content as media.
|
|
195
|
-
\`\`\`bash
|
|
196
|
-
${run} import_text '{"texts":[{"content":"Hello world","name":"greeting","tag":"captions"}]}'
|
|
197
|
-
\`\`\`
|
|
198
|
-
|
|
199
|
-
### create_social_audio
|
|
200
|
-
Extract audio from a TikTok or Instagram URL.
|
|
201
|
-
\`\`\`bash
|
|
202
|
-
${run} create_social_audio '{"url":"https://www.tiktok.com/@user/video/123","tag":"trending"}'
|
|
203
|
-
\`\`\`
|
|
204
|
-
|
|
205
|
-
### delete_media
|
|
206
|
-
Delete media items (also removes from storage).
|
|
207
|
-
\`\`\`bash
|
|
208
|
-
${run} delete_media '{"ids":["id1","id2"]}'
|
|
209
|
-
\`\`\`
|
|
210
|
-
|
|
211
|
-
## Workflow tips
|
|
212
|
-
- Media types: video, image, audio, text, social_audio
|
|
213
|
-
- When importing audio from TikTok/Instagram, use \`create_social_audio\` not \`create_media_from_urls\`
|
|
214
|
-
- Tags help organize media - suggest tagging when importing
|
|
215
|
-
- If $ARGUMENTS is provided, interpret it as a natural language request
|
|
216
156
|
`,
|
|
217
157
|
'automations/SKILL.md': `---
|
|
218
158
|
name: automations
|
|
@@ -527,4 +467,5 @@ ${run} upsert_integration_key '{"provider":"openai","key":"sk-..."}'
|
|
|
527
467
|
- Mention when stats were last refreshed and offer to refresh if stale
|
|
528
468
|
- If $ARGUMENTS is provided, interpret it as a natural language request
|
|
529
469
|
`,
|
|
470
|
+
...content_skills_1.contentSkillFiles,
|
|
530
471
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export interface ErrorResponse {
|
|
|
18
18
|
retryable?: boolean;
|
|
19
19
|
}
|
|
20
20
|
export type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
|
|
21
|
+
export type { IMessageConversationInput, IMessageConversationSettings, IMessageTiming, IMessageConversationPlan, IMessageConversationJob } from './imessage-conversation';
|
|
21
22
|
export type { PublicPostFailureCode, PublicPostRecovery, PublicPostNextAction, PublicPostFailure } from './post-failure';
|
|
22
23
|
export type { ListProfilePostsParams, ListProfilePostsResult, DownloadSocialPostParams, DownloadSocialPostResult, SocialReferencePost, SocialReferenceAsset } from './social-acquisition';
|
|
23
24
|
export type { MatchTextStyleParams, MatchTextStyleResult, SampleColorsParams, MeasureLayoutParams, SampleColorsResult, MeasureLayoutResult, TranscribeAudioParams, MeasureAudioLevelsParams, AudioTranscriptResult, AudioLevelsResult, ReadImageTextParams, ReadVideoTextParams, ImageTextResult, VideoTextResult, ExtractFramesParams, DetectScenesParams, FramesResult, ScenesResult, MediaAnalysisResult, MediaAnalysisJob } from "./media-analysis";
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugcinc",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.27.0",
|
|
4
4
|
"description": "TypeScript/JavaScript client for the UGC Inc API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
|
+
"./imessage": {
|
|
9
|
+
"types": "./dist/imessage-conversation.d.ts",
|
|
10
|
+
"default": "./dist/imessage-conversation.js"
|
|
11
|
+
},
|
|
8
12
|
".": {
|
|
9
13
|
"types": "./dist/index.d.ts",
|
|
10
14
|
"default": "./dist/index.js"
|
|
@@ -23,7 +27,7 @@
|
|
|
23
27
|
}
|
|
24
28
|
},
|
|
25
29
|
"scripts": {
|
|
26
|
-
"build": "tsc",
|
|
30
|
+
"build": "node scripts/build-skills.cjs && tsc",
|
|
27
31
|
"prepublishOnly": "npm run build",
|
|
28
32
|
"test": "echo \"No tests specified\" && exit 0"
|
|
29
33
|
},
|
|
@@ -65,6 +69,7 @@
|
|
|
65
69
|
},
|
|
66
70
|
"files": [
|
|
67
71
|
"dist",
|
|
68
|
-
"README.md"
|
|
72
|
+
"README.md",
|
|
73
|
+
"skills"
|
|
69
74
|
]
|
|
70
75
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: content-automation
|
|
3
|
+
description: Turn reference social posts or a rough content idea into a reusable UGC Inc workflow, with editable inputs and reviewed visual/audio output. Use for developing and validating content formats rather than scheduling existing finished posts.
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Build the format the user wants and collaborate at the level they requested.
|
|
8
|
+
When they want to discuss, compare or review a specific artifact, do that before
|
|
9
|
+
making additional format decisions. Keep questions concise and ask only when a
|
|
10
|
+
missing answer prevents useful work. Do not impose a new per-video reference input
|
|
11
|
+
when the user wants a fixed reusable visual format.
|
|
12
|
+
|
|
13
|
+
Use the `media` skill for acquisition/inspection and the `automations` skill for
|
|
14
|
+
current workflow tool calls. Read [references/build-review.md](references/build-review.md)
|
|
15
|
+
when constructing or reviewing a workflow. Use only shipped tools/nodes discovered
|
|
16
|
+
through `npx ugcinc --list`, `list_node_types` and `get_node_type`.
|
|
17
|
+
|
|
18
|
+
## Understand and specify the format
|
|
19
|
+
|
|
20
|
+
Acquire a bounded set of real references and inspect full frames and changes over
|
|
21
|
+
time, including audio using available modalities. A contact sheet or transcript
|
|
22
|
+
alone cannot establish all animation/pacing/music details. State uninspected
|
|
23
|
+
parts instead of claiming playback. Distinguish reusable formats from variants;
|
|
24
|
+
several posts may use the same structure with different assets, copy or timing.
|
|
25
|
+
|
|
26
|
+
Write a compact spec: what the viewer sees first, the sequence/reveal, required
|
|
27
|
+
inputs, reusable assets/components, changing copy, audio source/timing and final
|
|
28
|
+
action/CTA if required by this format. Separate measured facts from inference
|
|
29
|
+
and user choices. Share a verified HTTPS reference/preview when the user needs
|
|
30
|
+
to identify the parts they want changed.
|
|
31
|
+
|
|
32
|
+
Classify assets by replacement behavior. A recognizable Mii, Wojak or other exact
|
|
33
|
+
meme image may need a static asset; an ordinary or newly generated face need not
|
|
34
|
+
be static just because it looks meme-like. Preserve a headshot's identity across
|
|
35
|
+
variants when requested, while making intended differences visibly meaningful.
|
|
36
|
+
|
|
37
|
+
## Build reusable production behavior
|
|
38
|
+
|
|
39
|
+
Separate layout, data/assets and motion. Expose the inputs a normal run needs:
|
|
40
|
+
asset pools/overrides, text pools, contact/destination, duration/timing and seed
|
|
41
|
+
where appropriate. Keep canonical outputs independent of an operator's laptop.
|
|
42
|
+
Implement procedural animations as reusable components rendered on demand;
|
|
43
|
+
do not substitute one pre-rendered clip when each run should vary. Randomness
|
|
44
|
+
must respect the intended visual roles and remain replayable from saved inputs.
|
|
45
|
+
|
|
46
|
+
Reuse existing nodes/compositions and actual public schemas. Analysis tools are
|
|
47
|
+
available as CLI/SDK operations; do not assume every one is a workflow node.
|
|
48
|
+
Validate the graph before executing. Prefer a reviewable output over publishing
|
|
49
|
+
or enabling recurring runs unless the user authorized those actions.
|
|
50
|
+
|
|
51
|
+
## Make the content work
|
|
52
|
+
|
|
53
|
+
- Keep the hierarchy clear: readable hook, focal content, then the intended CTA.
|
|
54
|
+
Give characters/subjects enough visual weight; align visible content within
|
|
55
|
+
its section instead of trusting transparent image bounds alone.
|
|
56
|
+
- Measure margins, spacing, text wrapping and overlap. Check at phone viewing
|
|
57
|
+
size, not only on a large canvas. Keep important text away from platform UI;
|
|
58
|
+
inspect the relevant target presentation rather than assuming universal margins.
|
|
59
|
+
- Use sampled reference colors and real render previews. Judge font, stroke,
|
|
60
|
+
kerning, line height and emoji spacing together. Treat text-style fitting as a
|
|
61
|
+
measured candidate, not proof of an exact font or pixel-perfect output.
|
|
62
|
+
- Match the reference post's actual audio excerpt, mix, start and duration when
|
|
63
|
+
requested. Preserve attribution separately. Empty transcription can mean music
|
|
64
|
+
or unrecognized speech, not silence. Keep visual reveals and audio timing coherent.
|
|
65
|
+
- Keep required CTA/contact copy present and legible across every requested
|
|
66
|
+
variant. Use the user's actual destination/formatting, not a number copied from
|
|
67
|
+
an old example. Vary copy intentionally without altering the required action.
|
|
68
|
+
- Test with real content and multiple asset/copy lengths. A composition that
|
|
69
|
+
works with one face or one short headline is not a validated reusable format.
|
|
70
|
+
Inspect early, changing and final states; a still cannot certify a full video.
|
|
71
|
+
|
|
72
|
+
## Deliver and describe the boundary
|
|
73
|
+
|
|
74
|
+
Provide the workflow, its normal inputs, replayable example parameters, verified
|
|
75
|
+
HTTPS previews, and any observed visual/audio limits. For videos verify decoding,
|
|
76
|
+
duration/dimensions/audio and byte-range playback; images need correct content
|
|
77
|
+
type and decoding. Do not use local/localhost/private URLs as deliverables.
|
|
78
|
+
|
|
79
|
+
SAM and automatic segmentation/overlay tracking are deferred. Use supplied
|
|
80
|
+
assets, user-supplied boxes/masks or honest visual analysis; do not claim recovered
|
|
81
|
+
source layers or automatic clean cutouts. If the runtime cannot inspect a media
|
|
82
|
+
modality, record that limit and do not certify the uninspected property.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Construct and review a reusable workflow
|
|
2
|
+
|
|
3
|
+
## Discover the real interface
|
|
4
|
+
|
|
5
|
+
`npx ugcinc list_node_types '{}'` lists current node metadata.
|
|
6
|
+
Use `get_node_type '{"nodeType":"..."}'` for the nodes you choose and read the
|
|
7
|
+
bundled `automations` skill for current tool parameters. These tools still need
|
|
8
|
+
a configured CLI key even when their own operation is local.
|
|
9
|
+
|
|
10
|
+
Connections live on the target node, not a separate edges array:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"nodes": [
|
|
15
|
+
{
|
|
16
|
+
"id": "target",
|
|
17
|
+
"type": "node-type-from-discovery",
|
|
18
|
+
"config": {},
|
|
19
|
+
"inputs": {
|
|
20
|
+
"actual-input-port": {
|
|
21
|
+
"sourceNodeId": "source",
|
|
22
|
+
"sourceOutputId": "actual-output-port"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use actual IDs/configuration returned by discovery, not these placeholders.
|
|
31
|
+
Configure dynamic interfaces before wiring them. Re-check ports after config
|
|
32
|
+
changes. Current validation requires a terminal outcome; inspect pass-through,
|
|
33
|
+
save-to-media and posting nodes to choose the intended behavior. Publishing is
|
|
34
|
+
not required just to make a reviewable workflow output.
|
|
35
|
+
|
|
36
|
+
For reusable sub-workflows, configure their input/output contracts explicitly
|
|
37
|
+
and inspect the Compose Workflow node's actual schema. For custom Remotion,
|
|
38
|
+
inspect `remotion-composition`; use its supported composition/props/import
|
|
39
|
+
contract. Do not invent an upload/register API or rely on arbitrary packages.
|
|
40
|
+
|
|
41
|
+
Validate using `validate_workflow` with the shape described by the installed
|
|
42
|
+
automation skill/tool. Execute only the intended single test scope, inspect its
|
|
43
|
+
status/output, and retain resolved inputs and seed. Saving a template or receiving
|
|
44
|
+
a run ID alone does not prove the output renders correctly.
|
|
45
|
+
|
|
46
|
+
## Review a representative run
|
|
47
|
+
|
|
48
|
+
Check the viewer's actual sequence: hook visibility, subject size, changing state,
|
|
49
|
+
text wrapping/CTA, transitions and finish. Compare the full frame before zooming
|
|
50
|
+
into details. Inspect multiple points around animation/text changes. Re-test a
|
|
51
|
+
longer caption and a different asset where those vary in normal runs.
|
|
52
|
+
|
|
53
|
+
Distinguish observed pixels/timestamps from estimates. Examples: sRGB sampling
|
|
54
|
+
does not recover design colors from compression, transcript word timestamps are
|
|
55
|
+
estimated, sampled OCR leaves gaps, and bounding boxes are not exact ink bounds.
|
|
56
|
+
Manually supplied boxes are allowed; describe how they were determined.
|
|
57
|
+
|
|
58
|
+
Preserve both soundtrack bytes and source attribution. Check whether music is
|
|
59
|
+
embedded or only attributed, whether the output repeats/truncates it, and whether
|
|
60
|
+
visual changes coincide with the intended moments. Do not invent beat detection,
|
|
61
|
+
audio separation, universal media comparison or other unavailable tools.
|
|
62
|
+
|
|
63
|
+
When revising content, name the concrete issue and inspect the changed output.
|
|
64
|
+
Keep reusable parameters instead of baking a correction into one reference
|
|
65
|
+
image. Report remaining defects plainly; avoid calling a draft production-ready
|
|
66
|
+
based only on successful API execution.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: media
|
|
3
|
+
description: Acquire TikTok and Instagram posts and inspect images, video and audio with UGC Inc tools. Use for reference analysis, OCR, frames, scenes, transcription, colors, layout, text-style fitting, or media-library management.
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Use the installed UGC Inc CLI:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx ugcinc --list
|
|
11
|
+
npx ugcinc <tool_name> '<json_params>'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Credentials come from `UGC_API_KEY` or existing UGC configuration. Use the user's
|
|
15
|
+
organization and a key with `content:analyze` for acquisition/analysis. If using
|
|
16
|
+
an admin key, pass the authorized `orgId` in the JSON parameters. Do not print
|
|
17
|
+
credentials, copy an administrator key to another user's machine, or change
|
|
18
|
+
organizations to bypass a denial. Confirm access with one small tool call.
|
|
19
|
+
If credentials already live in an app env file, set `UGC_ENV_FILE` to that file's
|
|
20
|
+
path so the CLI reads the existing key without duplicating its contents. Set
|
|
21
|
+
`UGC_ORG_ID` in that file or the process environment to scope calls to the user's
|
|
22
|
+
organization; an explicit JSON `orgId` takes priority.
|
|
23
|
+
|
|
24
|
+
Read [references/tools.md](references/tools.md) for request shapes, result fields
|
|
25
|
+
and limits. The CLI lists names/descriptions; the reference explains parameters.
|
|
26
|
+
|
|
27
|
+
## Choose the input and tools
|
|
28
|
+
|
|
29
|
+
- A profile URL: `list_profile_posts` discovers a bounded page; follow its cursor
|
|
30
|
+
only as needed. Listing does not download media or guarantee complete history.
|
|
31
|
+
- A post URL: `download_social_post` ingests its ordered assets into owned media.
|
|
32
|
+
Use returned asset URLs for analysis; the TikTok/Instagram HTML URL is not a
|
|
33
|
+
video file. Check complete/partial/failed status and failed assets.
|
|
34
|
+
- A direct media URL: use the corresponding inspection tool directly.
|
|
35
|
+
- Video: `detect_scenes`, `extract_frames`, `read_video_text`; audio tools accept
|
|
36
|
+
video too. Inspect multiple moments, including changes near the beginning/end.
|
|
37
|
+
- Image: `read_image_text`, `sample_colors`, `measure_layout` using supplied
|
|
38
|
+
boxes/masks, and `match_text_style` for a specified text crop.
|
|
39
|
+
- Audio: `transcribe_audio` and `measure_audio_levels`.
|
|
40
|
+
|
|
41
|
+
The SDK/CLI waits for processing automatically. Check both the outer response's
|
|
42
|
+
`ok` and the returned job's `status`. Analysis is usable when
|
|
43
|
+
`data.status === "completed"`; its content is `data.result`. If still pending or
|
|
44
|
+
processing, keep its job ID and use `get_media_analysis` rather than resubmitting.
|
|
45
|
+
Use bounded retries for retryable failures; report persistent errors/partial
|
|
46
|
+
coverage. A zero process exit code alone does not establish API success.
|
|
47
|
+
|
|
48
|
+
## Interpret evidence accurately
|
|
49
|
+
|
|
50
|
+
- Coordinates are display-oriented source pixels; times are source-relative
|
|
51
|
+
milliseconds. Use returned decoded timestamps, dimensions and coverage.
|
|
52
|
+
- OCR is English, may miss stylized text, and can be empty on unreadable input.
|
|
53
|
+
`fast` video OCR leaves uninspected intervals. `frame_scan` is bounded and
|
|
54
|
+
cannot inspect an arbitrarily long clip in one request.
|
|
55
|
+
- Speech timestamps are estimates; speaker labels/forced alignment are absent.
|
|
56
|
+
A transcript does not establish music, emotion, delivery or sound effects.
|
|
57
|
+
- Color sampling measures decoded sRGB pixels, not guaranteed design hex values.
|
|
58
|
+
Layout measurement does not detect objects or recover original layer files.
|
|
59
|
+
- Text-style matching returns supported UGC settings and visual residuals. Font
|
|
60
|
+
identity is unverified; inspect the preview before calling a fit accurate.
|
|
61
|
+
It has a restricted ASCII/font/style surface; the native TikTok renderer is a
|
|
62
|
+
separate bounded rendering capability, not proof that matching is exact.
|
|
63
|
+
- SAM/object segmentation, automatic overlay detection, element/mask tracking,
|
|
64
|
+
motion measurement, extraction, media comparison/alignment and semantic search
|
|
65
|
+
are not available through this tool set. Do not invent those calls or install
|
|
66
|
+
SAM. Existing OCR text tracks remain available.
|
|
67
|
+
|
|
68
|
+
## Review and share media
|
|
69
|
+
|
|
70
|
+
Open returned image/contact-sheet previews and review the relevant sequence.
|
|
71
|
+
When the agent runtime can consume audio/video, use it. Otherwise use the
|
|
72
|
+
available transcript, audio preview and level measurements and explicitly state
|
|
73
|
+
what was not listened to or inspected. Do not claim to have watched/listened
|
|
74
|
+
because an analysis request succeeded.
|
|
75
|
+
|
|
76
|
+
Share only verified browser-accessible HTTPS artifacts. Fetch without auth and
|
|
77
|
+
check status, content type and decoding; for video also check byte-range support.
|
|
78
|
+
Use the returned owned-media URLs. Local paths, localhost/private addresses and
|
|
79
|
+
expiring upstream CDN links are not deliverable previews. If an artifact needs
|
|
80
|
+
uploading, use the supported owned storage path; do not claim a file is hosted
|
|
81
|
+
because a media record was created for an arbitrary URL.
|
|
82
|
+
|
|
83
|
+
For building a reusable content format, use the `content-automation` skill.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# UGC media tool requests and results
|
|
2
|
+
|
|
3
|
+
Run `npx ugcinc TOOL 'JSON'`. Shell quoting varies on Windows; if the shell
|
|
4
|
+
changes the JSON, use a small Node script with `UGCClient` and its `media`
|
|
5
|
+
methods instead of repeatedly sending malformed requests. For example:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
const { UGCClient } = require('ugcinc');
|
|
9
|
+
const client = new UGCClient({
|
|
10
|
+
apiKey: process.env.UGC_API_KEY,
|
|
11
|
+
orgId: process.env.UGC_ORG_ID,
|
|
12
|
+
});
|
|
13
|
+
// Use admin:true only with an authorized administrator credential.
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Request URLs must be HTTPS. Analysis source URLs must not contain credentials
|
|
17
|
+
or fragments. Image operations support still PNG/JPEG/WebP, at most4096pixels
|
|
18
|
+
per side; the shared download limit is100MiB. Geometry must fit the actual
|
|
19
|
+
display-oriented source. Respect more restrictive operation limits below.
|
|
20
|
+
|
|
21
|
+
## Acquisition
|
|
22
|
+
|
|
23
|
+
| CLI tool / SDK method | Parameters | Result |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `list_profile_posts` / `media.listProfilePosts` | `{url, limit?, cursor?}`; TikTok/Instagram profile; limit1–50 | `data.posts`, profile metadata, continuation cursor. Follow the actual returned cursor, not a fabricated page number. |
|
|
26
|
+
| `download_social_post` / `media.downloadSocialPost` | `{url}`; canonical TikTok/Instagram post URL | `data.status`, `assets[]` in order, `failedAssets[]`, `manifestUrl`, post/sound metadata. Each asset has `url`, `mediaId`, dimensions, type, duration, audio presence and hash. Repeat the same URL to resume retryable partial imports. |
|
|
27
|
+
|
|
28
|
+
Embedded video audio remains attached. Photo assets have no embedded soundtrack;
|
|
29
|
+
sound attribution does not mean audio bytes were downloaded. Preserve sound
|
|
30
|
+
ID/link separately; never replace a post excerpt with the full sound-page track
|
|
31
|
+
and call them identical. Partial imports are not a complete carousel.
|
|
32
|
+
|
|
33
|
+
## Analysis
|
|
34
|
+
|
|
35
|
+
These return `{ok, data:{jobId,status,operation,result?,error?}}`. Use the completed
|
|
36
|
+
`data.result` fields listed below. Failure can occur after successful submission.
|
|
37
|
+
|
|
38
|
+
| CLI tool / SDK method | Parameters | Result content |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `extract_frames` / `media.extractFrames` | `{url,timestampsMs:[0,1500,3000],selection:"nearest",contactSheet:true}` OR `{url,range:{startMs,endMs,intervalMs}}`; choose exactly one selector, at most48samples | `frames[]` with requested/decoded time, source PTS, dimensions and URL; optional `contactSheet` with individual frame links; source metadata. |
|
|
41
|
+
| `detect_scenes` / `media.detectScenes` | `{url}` | `scenes[]` with start/end milliseconds, frame indexes, source PTS; no split MP4 exports. |
|
|
42
|
+
| `read_image_text` / `media.readImageText` | `{url}` | `regions[]` with text/rawText, polygons/boxes/confidence; inferred `lines[]`/reading order; `previewUrl`. |
|
|
43
|
+
| `read_video_text` / `media.readVideoText` | `{url,mode:"fast",intervalMs:1000,range?:{startMs,endMs}}` OR `{url,mode:"frame_scan",range?:{startMs,endMs}}` | `frames[]`, text `tracks[]` with observations/positions; explicit `coverage.inspected` and `uninspected`. Maximum240inspected frames and120seconds per request. `intervalMs` only applies to fast mode. |
|
|
44
|
+
| `transcribe_audio` / `media.transcribeAudio` | `{url,range?:{startMs,endMs},language?:"auto",timing?:"word",channel?:0}` | `status`, `text`, timed `segments[]` and estimated words, warnings, `audioPreviewUrl`. Range at most120seconds; timing `word` or `segment`; optional channel0/1. Empty/no-audio/no-speech states are distinct. |
|
|
45
|
+
| `measure_audio_levels` / `media.measureAudioLevels` | `{url,range?:{startMs,endMs},windowMs?:100,silenceThresholdDbfs?:-50}` | Native-channel RMS/sample peaks, loudness timeline/LUFS, silence, possible clipping, `previewUrl`. Windows20–5000ms, threshold−100to−10dBFS, range at most120seconds. |
|
|
46
|
+
| `sample_colors` / `media.sampleColors` | `{url,maxColors?:8,point?:{x,y},box?:{x,y,width,height},mask?}`; choose at most one selection | Observed RGBA point or palette/proportions, omitted mass, declared color policy, `previewUrl`. Palette1–32colors. |
|
|
47
|
+
| `measure_layout` / `media.measureLayout` | `{url,elements:[{id,box:{x,y,width,height}}]}`; each element may instead have `mask` | Margins, centers, spacing/alignment deltas, intersections/IoU and `previewUrl`.1–32unique IDs. Boxes are supplied, not automatically detected. |
|
|
48
|
+
| `match_text_style` / `media.matchTextStyle` | `{url,box:{x,y,width,height},text?}`; integer crop16–1536wide,16–512high; optional supplied text | `status`, candidates with real image-editor `element`/`previewConfig`, `maskIoU`, `foregroundMae`, `quality`, previews/comparison and warnings. Up to160printable ASCII characters/four lines; supported fonts Arial/TikTok/Apple. Missing/unsupported styles may be unavailable or approximations. |
|
|
49
|
+
| `get_media_analysis` / `media.getMediaAnalysis` | `{jobId}` | Current status/result in the current organization; use when automatic waiting returned pending/processing. |
|
|
50
|
+
|
|
51
|
+
Boxes are half-open source-pixel rectangles. For masks used by colors/layout:
|
|
52
|
+
`{width,height,counts}` uses row-major binary RLE, alternating background then
|
|
53
|
+
foreground. Counts must sum to width×height. This is not COCO's column-major
|
|
54
|
+
convention. Supply only masks you actually have; automatic segmentation is off.
|
|
55
|
+
|
|
56
|
+
## Existing media library
|
|
57
|
+
|
|
58
|
+
- `list_media({ids?,tag?})`, `list_social_audio({ids?,tag?})`.
|
|
59
|
+
- `create_media_from_urls({urls,names?,tag?,sourceIds?,useName?})` registers URLs;
|
|
60
|
+
it does not turn an inaccessible local file into a public upload.
|
|
61
|
+
- `import_text({texts:[{content,name?,tag?}]})`.
|
|
62
|
+
- `create_social_audio({url,tag?})` imports social audio separately; do not use it
|
|
63
|
+
as proof of the exact soundtrack/mix/offset in a downloaded reference video.
|
|
64
|
+
- `delete_media({ids})` removes media/storage; only use when deletion is requested.
|