@brickgale/caption-sync 1.0.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/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/components/Video.d.ts +29 -0
- package/dist/components/Video.d.ts.map +1 -0
- package/dist/components/Video.js +243 -0
- package/dist/components/Video.js.map +1 -0
- package/dist/config.d.ts +148 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +141 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/elevenlabs-provider.d.ts +13 -0
- package/dist/providers/elevenlabs-provider.d.ts.map +1 -0
- package/dist/providers/elevenlabs-provider.js +117 -0
- package/dist/providers/elevenlabs-provider.js.map +1 -0
- package/dist/providers/index.d.ts +30 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +47 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai-provider.d.ts +13 -0
- package/dist/providers/openai-provider.d.ts.map +1 -0
- package/dist/providers/openai-provider.js +85 -0
- package/dist/providers/openai-provider.js.map +1 -0
- package/dist/providers/transcription-provider.d.ts +37 -0
- package/dist/providers/transcription-provider.d.ts.map +1 -0
- package/dist/providers/transcription-provider.js +9 -0
- package/dist/providers/transcription-provider.js.map +1 -0
- package/dist/types/index.d.ts +106 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/caption-generator.d.ts +128 -0
- package/dist/utils/caption-generator.d.ts.map +1 -0
- package/dist/utils/caption-generator.js +400 -0
- package/dist/utils/caption-generator.js.map +1 -0
- package/dist/utils/transcription.d.ts +96 -0
- package/dist/utils/transcription.d.ts.map +1 -0
- package/dist/utils/transcription.js +280 -0
- package/dist/utils/transcription.js.map +1 -0
- package/dist/utils/video-renderer.d.ts +58 -0
- package/dist/utils/video-renderer.d.ts.map +1 -0
- package/dist/utils/video-renderer.js +153 -0
- package/dist/utils/video-renderer.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.transcribeAudio = transcribeAudio;
|
|
40
|
+
exports.transcribeAudioWithTimestamps = transcribeAudioWithTimestamps;
|
|
41
|
+
exports.sanitizeText = sanitizeText;
|
|
42
|
+
exports.compareTexts = compareTexts;
|
|
43
|
+
exports.generateCorrections = generateCorrections;
|
|
44
|
+
const openai_1 = __importDefault(require("openai"));
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const config_1 = require("../config");
|
|
47
|
+
/**
|
|
48
|
+
* Transcribe audio to text using OpenAI Whisper
|
|
49
|
+
*
|
|
50
|
+
* @param options - Transcription options
|
|
51
|
+
* @returns Transcribed text
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const text = await transcribeAudio({
|
|
56
|
+
* audioPath: './audio.mp3',
|
|
57
|
+
* openaiApiKey: process.env.OPENAI_API_KEY!,
|
|
58
|
+
* });
|
|
59
|
+
* console.log('Transcribed:', text);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
async function transcribeAudio(options) {
|
|
63
|
+
const { audioPath, openaiApiKey, language = config_1.TranscriptionConfig.LANGUAGE, } = options;
|
|
64
|
+
if (!openaiApiKey) {
|
|
65
|
+
throw new Error('OpenAI API key is required for transcription. Set OPENAI_API_KEY environment variable or pass it in options.');
|
|
66
|
+
}
|
|
67
|
+
if (!fs.existsSync(audioPath)) {
|
|
68
|
+
throw new Error(`Audio file not found: ${audioPath}`);
|
|
69
|
+
}
|
|
70
|
+
const openai = new openai_1.default({ apiKey: openaiApiKey });
|
|
71
|
+
try {
|
|
72
|
+
console.log('🎤 Transcribing audio with Whisper...');
|
|
73
|
+
const transcription = await openai.audio.transcriptions.create({
|
|
74
|
+
file: fs.createReadStream(audioPath),
|
|
75
|
+
model: config_1.TranscriptionConfig.MODEL,
|
|
76
|
+
language: language,
|
|
77
|
+
response_format: 'text',
|
|
78
|
+
});
|
|
79
|
+
console.log('✅ Transcription complete');
|
|
80
|
+
return transcription;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new Error(`Failed to transcribe audio: ${error}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Transcribe audio with word-level timestamps using OpenAI Whisper
|
|
88
|
+
*
|
|
89
|
+
* @param options - Transcription options
|
|
90
|
+
* @returns Array of words with timestamps
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const words = await transcribeAudioWithTimestamps({
|
|
95
|
+
* audioPath: './audio.mp3',
|
|
96
|
+
* openaiApiKey: process.env.OPENAI_API_KEY!,
|
|
97
|
+
* });
|
|
98
|
+
* console.log('First word:', words[0]);
|
|
99
|
+
* // { word: "Hello", start: 0.5, end: 0.8 }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
async function transcribeAudioWithTimestamps(options) {
|
|
103
|
+
const { audioPath, openaiApiKey, language = config_1.TranscriptionConfig.LANGUAGE, } = options;
|
|
104
|
+
if (!openaiApiKey) {
|
|
105
|
+
throw new Error('OpenAI API key is required for transcription. Set OPENAI_API_KEY environment variable or pass it in options.');
|
|
106
|
+
}
|
|
107
|
+
if (!fs.existsSync(audioPath)) {
|
|
108
|
+
throw new Error(`Audio file not found: ${audioPath}`);
|
|
109
|
+
}
|
|
110
|
+
const openai = new openai_1.default({ apiKey: openaiApiKey });
|
|
111
|
+
try {
|
|
112
|
+
console.log('🎤 Transcribing audio with word-level timestamps...');
|
|
113
|
+
const transcription = await openai.audio.transcriptions.create({
|
|
114
|
+
file: fs.createReadStream(audioPath),
|
|
115
|
+
model: config_1.TranscriptionConfig.MODEL,
|
|
116
|
+
language: language,
|
|
117
|
+
response_format: 'verbose_json',
|
|
118
|
+
timestamp_granularities: ['word'],
|
|
119
|
+
});
|
|
120
|
+
console.log('✅ Transcription with timestamps complete');
|
|
121
|
+
// Extract word-level timestamps
|
|
122
|
+
const result = transcription;
|
|
123
|
+
if (result.words && Array.isArray(result.words)) {
|
|
124
|
+
return result.words.map((w) => ({
|
|
125
|
+
word: w.word,
|
|
126
|
+
start: w.start,
|
|
127
|
+
end: w.end,
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
throw new Error('No word-level timestamps in response');
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
throw new Error(`Failed to transcribe audio with timestamps: ${error}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Sanitize text by removing unwanted characters
|
|
138
|
+
* Keeps only alphanumeric characters, spaces, and basic punctuation
|
|
139
|
+
*
|
|
140
|
+
* @param text - Text to sanitize
|
|
141
|
+
* @returns Sanitized text
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const clean = sanitizeText("Hello—world! [test]");
|
|
146
|
+
* // Returns: "Hello world! test"
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
function sanitizeText(text) {
|
|
150
|
+
// Remove unwanted characters (keep only alphanumeric and basic punctuation)
|
|
151
|
+
let sanitized = text.replace(config_1.TextSanitizationConfig.ALLOWED_PATTERN, '');
|
|
152
|
+
// Normalize whitespace
|
|
153
|
+
if (config_1.TextSanitizationConfig.NORMALIZE_WHITESPACE) {
|
|
154
|
+
sanitized = sanitized.replace(/\s+/g, ' ').trim();
|
|
155
|
+
}
|
|
156
|
+
return sanitized;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Calculate similarity between two texts (simple word-based comparison)
|
|
160
|
+
*
|
|
161
|
+
* @param text1 - First text
|
|
162
|
+
* @param text2 - Second text
|
|
163
|
+
* @returns Similarity score between 0 and 1
|
|
164
|
+
*/
|
|
165
|
+
function calculateSimilarity(text1, text2) {
|
|
166
|
+
const words1 = text1.toLowerCase().split(/\s+/);
|
|
167
|
+
const words2 = text2.toLowerCase().split(/\s+/);
|
|
168
|
+
const set1 = new Set(words1);
|
|
169
|
+
const set2 = new Set(words2);
|
|
170
|
+
const intersection = new Set([...set1].filter(word => set2.has(word)));
|
|
171
|
+
const union = new Set([...set1, ...set2]);
|
|
172
|
+
return union.size > 0 ? intersection.size / union.size : 0;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Find differences between two texts
|
|
176
|
+
*
|
|
177
|
+
* @param original - Original text
|
|
178
|
+
* @param transcribed - Transcribed text
|
|
179
|
+
* @returns Array of difference descriptions
|
|
180
|
+
*/
|
|
181
|
+
function findDifferences(original, transcribed) {
|
|
182
|
+
const differences = [];
|
|
183
|
+
const origWords = original.split(/\s+/);
|
|
184
|
+
const transWords = transcribed.split(/\s+/);
|
|
185
|
+
// Word count difference
|
|
186
|
+
if (origWords.length !== transWords.length) {
|
|
187
|
+
differences.push(`Word count: original has ${origWords.length}, transcribed has ${transWords.length}`);
|
|
188
|
+
}
|
|
189
|
+
// Find missing words
|
|
190
|
+
const origSet = new Set(origWords.map(w => w.toLowerCase()));
|
|
191
|
+
const transSet = new Set(transWords.map(w => w.toLowerCase()));
|
|
192
|
+
const missingInTrans = [...origSet].filter(w => !transSet.has(w));
|
|
193
|
+
const extraInTrans = [...transSet].filter(w => !origSet.has(w));
|
|
194
|
+
if (missingInTrans.length > 0) {
|
|
195
|
+
differences.push(`Missing in transcription: ${missingInTrans.slice(0, 5).join(', ')}${missingInTrans.length > 5 ? '...' : ''}`);
|
|
196
|
+
}
|
|
197
|
+
if (extraInTrans.length > 0) {
|
|
198
|
+
differences.push(`Extra in transcription: ${extraInTrans.slice(0, 5).join(', ')}${extraInTrans.length > 5 ? '...' : ''}`);
|
|
199
|
+
}
|
|
200
|
+
return differences;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Compare original script with transcribed audio
|
|
204
|
+
*
|
|
205
|
+
* @param originalText - Original script text
|
|
206
|
+
* @param transcribedText - Transcribed audio text
|
|
207
|
+
* @returns Comparison result with differences and similarity score
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const result = compareTexts(originalScript, transcribedText);
|
|
212
|
+
* console.log(`Similarity: ${(result.similarity * 100).toFixed(1)}%`);
|
|
213
|
+
* console.log('Differences:', result.differences);
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
function compareTexts(originalText, transcribedText) {
|
|
217
|
+
// Sanitize both texts
|
|
218
|
+
const sanitizedOriginal = sanitizeText(originalText);
|
|
219
|
+
const sanitizedTranscribed = sanitizeText(transcribedText);
|
|
220
|
+
// Calculate similarity
|
|
221
|
+
const similarity = calculateSimilarity(sanitizedOriginal, sanitizedTranscribed);
|
|
222
|
+
// Find differences
|
|
223
|
+
const differences = findDifferences(sanitizedOriginal, sanitizedTranscribed);
|
|
224
|
+
return {
|
|
225
|
+
original: originalText,
|
|
226
|
+
transcribed: transcribedText,
|
|
227
|
+
sanitizedOriginal,
|
|
228
|
+
sanitizedTranscribed,
|
|
229
|
+
differences,
|
|
230
|
+
similarity,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Generate corrected script based on transcription
|
|
235
|
+
*
|
|
236
|
+
* @param scriptPath - Path to original script file
|
|
237
|
+
* @param audioPath - Path to audio file
|
|
238
|
+
* @param openaiApiKey - OpenAI API key for transcription
|
|
239
|
+
* @returns Comparison result with corrections
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const result = await generateCorrections({
|
|
244
|
+
* scriptPath: './script.txt',
|
|
245
|
+
* audioPath: './audio.mp3',
|
|
246
|
+
* openaiApiKey: process.env.OPENAI_API_KEY!
|
|
247
|
+
* });
|
|
248
|
+
*
|
|
249
|
+
* console.log('Corrections needed:', result.differences);
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
async function generateCorrections(options) {
|
|
253
|
+
const { scriptPath, audioPath, openaiApiKey } = options;
|
|
254
|
+
// Read original script
|
|
255
|
+
const originalText = fs.readFileSync(scriptPath, 'utf-8');
|
|
256
|
+
// Transcribe audio
|
|
257
|
+
const transcribedText = await transcribeAudio({
|
|
258
|
+
audioPath,
|
|
259
|
+
openaiApiKey,
|
|
260
|
+
});
|
|
261
|
+
// Compare texts
|
|
262
|
+
const comparison = compareTexts(originalText, transcribedText);
|
|
263
|
+
// Print report
|
|
264
|
+
console.log('\n📊 Script Comparison Report');
|
|
265
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
266
|
+
console.log(`Similarity: ${(comparison.similarity * 100).toFixed(1)}%`);
|
|
267
|
+
console.log(`\nOriginal (sanitized):\n${comparison.sanitizedOriginal}`);
|
|
268
|
+
console.log(`\nTranscribed (sanitized):\n${comparison.sanitizedTranscribed}`);
|
|
269
|
+
if (comparison.differences.length > 0) {
|
|
270
|
+
console.log('\n⚠️ Differences found:');
|
|
271
|
+
comparison.differences.forEach((diff, index) => {
|
|
272
|
+
console.log(` ${index + 1}. ${diff}`);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
console.log('\n✅ No significant differences found');
|
|
277
|
+
}
|
|
278
|
+
return comparison;
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=transcription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcription.js","sourceRoot":"","sources":["../../src/lib/utils/transcription.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Caption, RenderVideoOptions, GenerateVideoOptions } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Render video using Remotion
|
|
4
|
+
*
|
|
5
|
+
* This function takes captions and an audio file, then renders them
|
|
6
|
+
* into a video using Remotion. The captions are temporarily saved to
|
|
7
|
+
* a file, then Remotion is invoked via CLI to render the final video.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Rendering configuration
|
|
10
|
+
* @param options.audioPath - Path to audio file
|
|
11
|
+
* @param options.captions - Array of captions with timing
|
|
12
|
+
* @param options.outputPath - Path for output video file
|
|
13
|
+
* @param options.compositionPath - Path to Remotion composition (default: src/index.ts)
|
|
14
|
+
* @param options.width - Video width (default: 1920)
|
|
15
|
+
* @param options.height - Video height (default: 1080)
|
|
16
|
+
* @param options.fps - Frame rate (default: 30)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { generateCaptions, renderVideo } from 'caption-sync';
|
|
21
|
+
*
|
|
22
|
+
* const captions = generateCaptions({
|
|
23
|
+
* scriptPath: './script.txt',
|
|
24
|
+
* audioPath: './audio.mp3'
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* await renderVideo({
|
|
28
|
+
* audioPath: './audio.mp3',
|
|
29
|
+
* captions,
|
|
30
|
+
* outputPath: './out/video.mp4'
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function renderVideo(options: RenderVideoOptions): void;
|
|
35
|
+
/**
|
|
36
|
+
* Generate captions and render video in one step
|
|
37
|
+
*
|
|
38
|
+
* This is a convenience function that combines caption generation
|
|
39
|
+
* and video rendering into a single operation.
|
|
40
|
+
*
|
|
41
|
+
* @param options - Combined options for caption generation and rendering
|
|
42
|
+
* @returns Array of generated captions
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* import { generateVideo } from 'caption-sync';
|
|
47
|
+
*
|
|
48
|
+
* const captions = await generateVideo({
|
|
49
|
+
* scriptPath: './script.txt',
|
|
50
|
+
* audioPath: './audio.mp3',
|
|
51
|
+
* outputPath: './out/video.mp4'
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* console.log(`Generated ${captions.length} captions`);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function generateVideo(options: GenerateVideoOptions): Promise<Caption[]>;
|
|
58
|
+
//# sourceMappingURL=video-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-renderer.d.ts","sourceRoot":"","sources":["../../src/lib/utils/video-renderer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,OAAO,EACP,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAGlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAkD7D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,OAAO,EAAE,CAAC,CAmCpB"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.renderVideo = renderVideo;
|
|
37
|
+
exports.generateVideo = generateVideo;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const child_process_1 = require("child_process");
|
|
41
|
+
const caption_generator_1 = require("./caption-generator");
|
|
42
|
+
/**
|
|
43
|
+
* Render video using Remotion
|
|
44
|
+
*
|
|
45
|
+
* This function takes captions and an audio file, then renders them
|
|
46
|
+
* into a video using Remotion. The captions are temporarily saved to
|
|
47
|
+
* a file, then Remotion is invoked via CLI to render the final video.
|
|
48
|
+
*
|
|
49
|
+
* @param options - Rendering configuration
|
|
50
|
+
* @param options.audioPath - Path to audio file
|
|
51
|
+
* @param options.captions - Array of captions with timing
|
|
52
|
+
* @param options.outputPath - Path for output video file
|
|
53
|
+
* @param options.compositionPath - Path to Remotion composition (default: src/index.ts)
|
|
54
|
+
* @param options.width - Video width (default: 1920)
|
|
55
|
+
* @param options.height - Video height (default: 1080)
|
|
56
|
+
* @param options.fps - Frame rate (default: 30)
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* import { generateCaptions, renderVideo } from 'caption-sync';
|
|
61
|
+
*
|
|
62
|
+
* const captions = generateCaptions({
|
|
63
|
+
* scriptPath: './script.txt',
|
|
64
|
+
* audioPath: './audio.mp3'
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* await renderVideo({
|
|
68
|
+
* audioPath: './audio.mp3',
|
|
69
|
+
* captions,
|
|
70
|
+
* outputPath: './out/video.mp4'
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function renderVideo(options) {
|
|
75
|
+
const { audioPath, captions, outputPath, compositionPath = 'src/index.tsx', width = 1080, height = 1920, fps = 30, } = options;
|
|
76
|
+
// Ensure output directory exists
|
|
77
|
+
const outputDir = path.dirname(outputPath);
|
|
78
|
+
if (!fs.existsSync(outputDir)) {
|
|
79
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
80
|
+
}
|
|
81
|
+
// Calculate duration from captions
|
|
82
|
+
const duration = captions.length > 0 ? Math.ceil(captions[captions.length - 1].end) : 10;
|
|
83
|
+
// Convert audio path to be relative to public/ directory for Remotion
|
|
84
|
+
// If the path is in public/, use relative path; otherwise use absolute
|
|
85
|
+
const absoluteAudioPath = path.resolve(audioPath);
|
|
86
|
+
const publicDir = path.join(process.cwd(), 'public');
|
|
87
|
+
let remotionAudioPath = absoluteAudioPath;
|
|
88
|
+
// Check if audio is in public/ directory
|
|
89
|
+
if (absoluteAudioPath.startsWith(publicDir + path.sep)) {
|
|
90
|
+
// Make it relative to public/ so staticFile() works
|
|
91
|
+
remotionAudioPath = path.relative(publicDir, absoluteAudioPath);
|
|
92
|
+
}
|
|
93
|
+
// Set environment variables for Remotion composition
|
|
94
|
+
// Pass captions as JSON string to avoid file I/O in composition
|
|
95
|
+
const env = {
|
|
96
|
+
...process.env,
|
|
97
|
+
REMOTION_AUDIO_PATH: remotionAudioPath,
|
|
98
|
+
REMOTION_CAPTIONS_JSON: JSON.stringify(captions),
|
|
99
|
+
REMOTION_DURATION: duration.toString(),
|
|
100
|
+
};
|
|
101
|
+
// Build remotion render command
|
|
102
|
+
const cmd = `npx remotion render ${compositionPath} Video "${outputPath}" --width=${width} --height=${height} --fps=${fps}`;
|
|
103
|
+
// Execute render
|
|
104
|
+
(0, child_process_1.execSync)(cmd, {
|
|
105
|
+
stdio: 'inherit',
|
|
106
|
+
env,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Generate captions and render video in one step
|
|
111
|
+
*
|
|
112
|
+
* This is a convenience function that combines caption generation
|
|
113
|
+
* and video rendering into a single operation.
|
|
114
|
+
*
|
|
115
|
+
* @param options - Combined options for caption generation and rendering
|
|
116
|
+
* @returns Array of generated captions
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* import { generateVideo } from 'caption-sync';
|
|
121
|
+
*
|
|
122
|
+
* const captions = await generateVideo({
|
|
123
|
+
* scriptPath: './script.txt',
|
|
124
|
+
* audioPath: './audio.mp3',
|
|
125
|
+
* outputPath: './out/video.mp4'
|
|
126
|
+
* });
|
|
127
|
+
*
|
|
128
|
+
* console.log(`Generated ${captions.length} captions`);
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
async function generateVideo(options) {
|
|
132
|
+
const { scriptPath, audioPath, outputPath, width, height, fps, placement, maxCharacters, useTranscription, openaiApiKey, } = options;
|
|
133
|
+
// Generate captions
|
|
134
|
+
const captions = await (0, caption_generator_1.generateCaptions)({
|
|
135
|
+
scriptPath,
|
|
136
|
+
audioPath,
|
|
137
|
+
maxCharacters,
|
|
138
|
+
useTranscription,
|
|
139
|
+
openaiApiKey,
|
|
140
|
+
});
|
|
141
|
+
// Render video
|
|
142
|
+
renderVideo({
|
|
143
|
+
audioPath,
|
|
144
|
+
captions,
|
|
145
|
+
outputPath,
|
|
146
|
+
width,
|
|
147
|
+
height,
|
|
148
|
+
fps,
|
|
149
|
+
placement,
|
|
150
|
+
});
|
|
151
|
+
return captions;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=video-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-renderer.js","sourceRoot":"","sources":["../../src/lib/utils/video-renderer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,kCAkDC;AAwBD,sCAqCC;AAzJD,uCAAyB;AACzB,2CAA6B;AAC7B,iDAAyC;AAMzC,2DAAuD;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,SAAgB,WAAW,CAAC,OAA2B;IACrD,MAAM,EACJ,SAAS,EACT,QAAQ,EACR,UAAU,EACV,eAAe,GAAG,eAAe,EACjC,KAAK,GAAG,IAAI,EACZ,MAAM,GAAG,IAAI,EACb,GAAG,GAAG,EAAE,GACT,GAAG,OAAO,CAAC;IAEZ,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,mCAAmC;IACnC,MAAM,QAAQ,GACZ,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1E,sEAAsE;IACtE,uEAAuE;IACvE,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IACrD,IAAI,iBAAiB,GAAG,iBAAiB,CAAC;IAE1C,yCAAyC;IACzC,IAAI,iBAAiB,CAAC,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,oDAAoD;QACpD,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAClE,CAAC;IAED,qDAAqD;IACrD,gEAAgE;IAChE,MAAM,GAAG,GAAG;QACV,GAAG,OAAO,CAAC,GAAG;QACd,mBAAmB,EAAE,iBAAiB;QACtC,sBAAsB,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;QAChD,iBAAiB,EAAE,QAAQ,CAAC,QAAQ,EAAE;KACvC,CAAC;IAEF,gCAAgC;IAChC,MAAM,GAAG,GAAG,uBAAuB,eAAe,WAAW,UAAU,aAAa,KAAK,aAAa,MAAM,UAAU,GAAG,EAAE,CAAC;IAE5H,iBAAiB;IACjB,IAAA,wBAAQ,EAAC,GAAG,EAAE;QACZ,KAAK,EAAE,SAAS;QAChB,GAAG;KACJ,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACI,KAAK,UAAU,aAAa,CACjC,OAA6B;IAE7B,MAAM,EACJ,UAAU,EACV,SAAS,EACT,UAAU,EACV,KAAK,EACL,MAAM,EACN,GAAG,EACH,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,GAAG,OAAO,CAAC;IAEZ,oBAAoB;IACpB,MAAM,QAAQ,GAAG,MAAM,IAAA,oCAAgB,EAAC;QACtC,UAAU;QACV,SAAS;QACT,aAAa;QACb,gBAAgB;QAChB,YAAY;KACb,CAAC,CAAC;IAEH,eAAe;IACf,WAAW,CAAC;QACV,SAAS;QACT,QAAQ;QACR,UAAU;QACV,KAAK;QACL,MAAM;QACN,GAAG;QACH,SAAS;KACV,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@brickgale/caption-sync",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Video generation with automatic caption timing using Remotion",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./types": {
|
|
14
|
+
"types": "./dist/types.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"video-generation",
|
|
24
|
+
"captions",
|
|
25
|
+
"remotion",
|
|
26
|
+
"automation",
|
|
27
|
+
"subtitles",
|
|
28
|
+
"video",
|
|
29
|
+
"react"
|
|
30
|
+
],
|
|
31
|
+
"author": "brickgale",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/brickgale/caption-sync.git"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/brickgale/caption-sync#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/brickgale/caption-sync/issues"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=20.6.0"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"generate": "node --env-file=.env -r ts-node/register src/cli/generate-video.ts",
|
|
49
|
+
"dev": "node --env-file=.env -r ts-node/register src/cli/dev-helper.ts",
|
|
50
|
+
"dev:studio": "remotion studio src/index.tsx",
|
|
51
|
+
"build": "remotion render src/index.tsx Video out/final.mp4",
|
|
52
|
+
"generate-captions": "node --env-file=.env -r ts-node/register src/cli/caption-generator.ts",
|
|
53
|
+
"verify-script": "node --env-file=.env -r ts-node/register src/cli/verify-script.ts",
|
|
54
|
+
"format": "prettier --write .",
|
|
55
|
+
"format:check": "prettier --check .",
|
|
56
|
+
"typecheck": "tsc --noEmit --project tsconfig.lib.json",
|
|
57
|
+
"compile": "tsc --project tsconfig.lib.json",
|
|
58
|
+
"prepublishOnly": "npm run compile"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@remotion/bundler": "^4.0.0",
|
|
62
|
+
"@remotion/cli": "^4.0.0",
|
|
63
|
+
"@types/form-data": "^2.2.1",
|
|
64
|
+
"form-data": "^4.0.5",
|
|
65
|
+
"openai": "^6.35.0",
|
|
66
|
+
"react": "^18.2.0",
|
|
67
|
+
"react-dom": "^18.2.0",
|
|
68
|
+
"remotion": "^4.0.0"
|
|
69
|
+
},
|
|
70
|
+
"overrides": {
|
|
71
|
+
"postcss": "^8.5.10"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@types/node": "^20.19.39",
|
|
75
|
+
"@types/react": "^18.2.0",
|
|
76
|
+
"prettier": "^3.2.0",
|
|
77
|
+
"ts-node": "^10.9.0",
|
|
78
|
+
"typescript": "^5.0.0"
|
|
79
|
+
}
|
|
80
|
+
}
|