mediacript 1.0.0 → 1.0.2
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 +1 -1
- package/cli.mjs +13 -2
- package/dist/config/index.d.ts +22 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +119 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +226 -0
- package/dist/index.js.map +1 -0
- package/dist/transcript/groq.d.ts +9 -0
- package/dist/transcript/groq.d.ts.map +1 -0
- package/dist/transcript/groq.js +38 -0
- package/dist/transcript/groq.js.map +1 -0
- package/dist/transcript/index.d.ts +13 -0
- package/dist/transcript/index.d.ts.map +1 -0
- package/dist/transcript/index.js +50 -0
- package/dist/transcript/index.js.map +1 -0
- package/dist/transcript/openai.d.ts +8 -0
- package/dist/transcript/openai.d.ts.map +1 -0
- package/dist/transcript/openai.js +27 -0
- package/dist/transcript/openai.js.map +1 -0
- package/dist/types/index.d.ts +31 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/ffmpegCheck.d.ts +18 -0
- package/dist/utils/ffmpegCheck.d.ts.map +1 -0
- package/dist/utils/ffmpegCheck.js +74 -0
- package/dist/utils/ffmpegCheck.js.map +1 -0
- package/dist/utils/ffmpegOperations.d.ts +21 -0
- package/dist/utils/ffmpegOperations.d.ts.map +1 -0
- package/dist/utils/ffmpegOperations.js +117 -0
- package/dist/utils/ffmpegOperations.js.map +1 -0
- package/dist/utils/fileHelpers.d.ts +18 -0
- package/dist/utils/fileHelpers.d.ts.map +1 -0
- package/dist/utils/fileHelpers.js +59 -0
- package/dist/utils/fileHelpers.js.map +1 -0
- package/dist/workflow/state.d.ts +38 -0
- package/dist/workflow/state.d.ts.map +1 -0
- package/dist/workflow/state.js +119 -0
- package/dist/workflow/state.js.map +1 -0
- package/package.json +7 -1
- package/QUICK_START.md +0 -154
- package/src/config/index.ts +0 -136
- package/src/index.ts +0 -278
- package/src/transcript/groq.ts +0 -50
- package/src/transcript/index.ts +0 -60
- package/src/transcript/openai.ts +0 -34
- package/src/types/index.ts +0 -34
- package/src/utils/ffmpegCheck.ts +0 -78
- package/src/utils/ffmpegOperations.ts +0 -144
- package/src/utils/fileHelpers.ts +0 -60
- package/src/workflow/state.ts +0 -140
- package/tsconfig.json +0 -21
package/README.md
CHANGED
package/cli.mjs
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// Importa e executa o CLI compilado
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { dirname, join } from 'path'
|
|
6
|
+
import { pathToFileURL } from 'url'
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
9
|
+
const __dirname = dirname(__filename)
|
|
10
|
+
|
|
11
|
+
// Converte o caminho para URL file:// (necessário no Windows)
|
|
12
|
+
const indexPath = join(__dirname, 'dist', 'index.js')
|
|
13
|
+
const indexURL = pathToFileURL(indexPath).href
|
|
14
|
+
|
|
15
|
+
import(indexURL).catch((error) => {
|
|
16
|
+
console.error('Error loading CLI:', error)
|
|
6
17
|
process.exit(1)
|
|
7
18
|
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Config } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Carrega a configuração salva
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadConfig(): Config;
|
|
6
|
+
/**
|
|
7
|
+
* Salva a configuração
|
|
8
|
+
*/
|
|
9
|
+
export declare function saveConfig(config: Config): void;
|
|
10
|
+
/**
|
|
11
|
+
* Solicita as API keys ao usuário (interativo)
|
|
12
|
+
*/
|
|
13
|
+
export declare function promptApiKeys(): Promise<Config>;
|
|
14
|
+
/**
|
|
15
|
+
* Verifica se há pelo menos uma API key configurada
|
|
16
|
+
*/
|
|
17
|
+
export declare function hasApiKey(config: Config): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Obtém a configuração, solicitando ao usuário se necessário
|
|
20
|
+
*/
|
|
21
|
+
export declare function ensureConfig(): Promise<Config>;
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAwB1C;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAWnC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAe/C;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CA6BrD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CA2BpD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
/**
|
|
6
|
+
* Retorna o diretório de configuração baseado no sistema operacional
|
|
7
|
+
* Linux/Mac: ~/.config/ffmpeg-simple-converter
|
|
8
|
+
* Windows: %APPDATA%/ffmpeg-simple-converter
|
|
9
|
+
*/
|
|
10
|
+
function getConfigDir() {
|
|
11
|
+
const homeDir = os.homedir();
|
|
12
|
+
if (process.platform === 'win32') {
|
|
13
|
+
// Windows
|
|
14
|
+
const appData = process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming');
|
|
15
|
+
return path.join(appData, 'ffmpeg-simple-converter');
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// Linux/Mac
|
|
19
|
+
return path.join(homeDir, '.config', 'ffmpeg-simple-converter');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function getConfigFilePath() {
|
|
23
|
+
return path.join(getConfigDir(), 'config.json');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Carrega a configuração salva
|
|
27
|
+
*/
|
|
28
|
+
export function loadConfig() {
|
|
29
|
+
try {
|
|
30
|
+
const configPath = getConfigFilePath();
|
|
31
|
+
if (fs.existsSync(configPath)) {
|
|
32
|
+
const data = fs.readFileSync(configPath, 'utf-8');
|
|
33
|
+
return JSON.parse(data);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.warn('Erro ao carregar configuração:', error);
|
|
38
|
+
}
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Salva a configuração
|
|
43
|
+
*/
|
|
44
|
+
export function saveConfig(config) {
|
|
45
|
+
try {
|
|
46
|
+
const configDir = getConfigDir();
|
|
47
|
+
const configPath = getConfigFilePath();
|
|
48
|
+
// Cria o diretório se não existir
|
|
49
|
+
if (!fs.existsSync(configDir)) {
|
|
50
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
53
|
+
console.log(`✓ Configuração salva em: ${configPath}`);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error('Erro ao salvar configuração:', error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Solicita as API keys ao usuário (interativo)
|
|
61
|
+
*/
|
|
62
|
+
export async function promptApiKeys() {
|
|
63
|
+
console.log('\n🔑 Configure suas API keys (opcional - pressione Enter para pular)\n');
|
|
64
|
+
const answers = await inquirer.prompt([
|
|
65
|
+
{
|
|
66
|
+
type: 'input',
|
|
67
|
+
name: 'groqApiKey',
|
|
68
|
+
message: 'Groq API Key (recomendado - mais rápido):',
|
|
69
|
+
default: ''
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: 'input',
|
|
73
|
+
name: 'openaiApiKey',
|
|
74
|
+
message: 'OpenAI API Key:',
|
|
75
|
+
default: ''
|
|
76
|
+
}
|
|
77
|
+
]);
|
|
78
|
+
const config = {};
|
|
79
|
+
if (answers.groqApiKey.trim()) {
|
|
80
|
+
config.groqApiKey = answers.groqApiKey.trim();
|
|
81
|
+
}
|
|
82
|
+
if (answers.openaiApiKey.trim()) {
|
|
83
|
+
config.openaiApiKey = answers.openaiApiKey.trim();
|
|
84
|
+
}
|
|
85
|
+
return config;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Verifica se há pelo menos uma API key configurada
|
|
89
|
+
*/
|
|
90
|
+
export function hasApiKey(config) {
|
|
91
|
+
return !!(config.openaiApiKey || config.groqApiKey);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Obtém a configuração, solicitando ao usuário se necessário
|
|
95
|
+
*/
|
|
96
|
+
export async function ensureConfig() {
|
|
97
|
+
let config = loadConfig();
|
|
98
|
+
// Se não tem nenhuma API key, pergunta ao usuário
|
|
99
|
+
if (!hasApiKey(config)) {
|
|
100
|
+
console.log('\n⚠️ Nenhuma API key encontrada.');
|
|
101
|
+
const { shouldConfigure } = await inquirer.prompt([
|
|
102
|
+
{
|
|
103
|
+
type: 'confirm',
|
|
104
|
+
name: 'shouldConfigure',
|
|
105
|
+
message: 'Deseja configurar suas API keys agora?',
|
|
106
|
+
default: true
|
|
107
|
+
}
|
|
108
|
+
]);
|
|
109
|
+
if (shouldConfigure) {
|
|
110
|
+
const newConfig = await promptApiKeys();
|
|
111
|
+
if (hasApiKey(newConfig)) {
|
|
112
|
+
config = { ...config, ...newConfig };
|
|
113
|
+
saveConfig(config);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return config;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import { verifyFfmpeg } from './utils/ffmpegCheck.js';
|
|
4
|
+
import { ensureConfig, hasApiKey } from './config/index.js';
|
|
5
|
+
import { listMediaFiles, detectFileType } from './utils/fileHelpers.js';
|
|
6
|
+
import { convertVideo, extractAudio, convertAudio } from './utils/ffmpegOperations.js';
|
|
7
|
+
import { transcribeAudio, saveTranscription } from './transcript/index.js';
|
|
8
|
+
import { createWorkflowState, updateStepStatus, nextStep, printWorkflowProgress, saveWorkflowState, getCurrentStep } from './workflow/state.js';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
const WORKFLOW_OPTIONS = [
|
|
11
|
+
{
|
|
12
|
+
name: '🎬 Converter vídeo + Extrair áudio + Transcrever',
|
|
13
|
+
value: 'video-full',
|
|
14
|
+
steps: ['Converter vídeo', 'Extrair áudio', 'Transcrever áudio'],
|
|
15
|
+
requiresType: 'video'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: '🎬 Extrair áudio do vídeo + Transcrever',
|
|
19
|
+
value: 'video-extract-transcribe',
|
|
20
|
+
steps: ['Extrair áudio', 'Transcrever áudio'],
|
|
21
|
+
requiresType: 'video'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: '🎵 Converter áudio + Transcrever',
|
|
25
|
+
value: 'audio-convert-transcribe',
|
|
26
|
+
steps: ['Converter áudio', 'Transcrever áudio'],
|
|
27
|
+
requiresType: 'audio'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: '🎙️ Apenas transcrever áudio',
|
|
31
|
+
value: 'audio-transcribe',
|
|
32
|
+
steps: ['Transcrever áudio'],
|
|
33
|
+
requiresType: 'audio'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: '🎬 Apenas converter vídeo',
|
|
37
|
+
value: 'video-convert',
|
|
38
|
+
steps: ['Converter vídeo'],
|
|
39
|
+
requiresType: 'video'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: '🎵 Apenas converter áudio',
|
|
43
|
+
value: 'audio-convert',
|
|
44
|
+
steps: ['Converter áudio'],
|
|
45
|
+
requiresType: 'audio'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: '🎵 Apenas extrair áudio do vídeo',
|
|
49
|
+
value: 'video-extract',
|
|
50
|
+
steps: ['Extrair áudio'],
|
|
51
|
+
requiresType: 'video'
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
async function executeWorkflow(workflow, inputFile, config) {
|
|
55
|
+
const state = createWorkflowState(inputFile, workflow.steps);
|
|
56
|
+
const outputDir = path.dirname(inputFile);
|
|
57
|
+
console.log(`\n🚀 Iniciando workflow: ${workflow.name}`);
|
|
58
|
+
console.log(`📁 Arquivo de entrada: ${path.basename(inputFile)}\n`);
|
|
59
|
+
let currentFile = inputFile;
|
|
60
|
+
let audioFile;
|
|
61
|
+
let transcriptionFile;
|
|
62
|
+
for (let i = 0; i < state.steps.length; i++) {
|
|
63
|
+
const step = getCurrentStep(state);
|
|
64
|
+
if (!step)
|
|
65
|
+
break;
|
|
66
|
+
updateStepStatus(state, i, 'running');
|
|
67
|
+
console.log(`\n[${i + 1}/${state.steps.length}] ${step.name}...`);
|
|
68
|
+
try {
|
|
69
|
+
switch (step.name) {
|
|
70
|
+
case 'Converter vídeo':
|
|
71
|
+
currentFile = await convertVideo(currentFile, outputDir);
|
|
72
|
+
state.intermediateFiles.convertedVideo = currentFile;
|
|
73
|
+
updateStepStatus(state, i, 'completed', { outputFile: currentFile });
|
|
74
|
+
break;
|
|
75
|
+
case 'Extrair áudio':
|
|
76
|
+
audioFile = await extractAudio(currentFile, outputDir);
|
|
77
|
+
state.intermediateFiles.extractedAudio = audioFile;
|
|
78
|
+
currentFile = audioFile;
|
|
79
|
+
updateStepStatus(state, i, 'completed', { outputFile: audioFile });
|
|
80
|
+
break;
|
|
81
|
+
case 'Converter áudio':
|
|
82
|
+
audioFile = await convertAudio(currentFile, outputDir);
|
|
83
|
+
currentFile = audioFile;
|
|
84
|
+
updateStepStatus(state, i, 'completed', { outputFile: audioFile });
|
|
85
|
+
break;
|
|
86
|
+
case 'Transcrever áudio':
|
|
87
|
+
// Usa o arquivo de áudio atual ou o arquivo de entrada se for áudio
|
|
88
|
+
const fileToTranscribe = audioFile || currentFile;
|
|
89
|
+
// Verifica se há API key
|
|
90
|
+
if (!hasApiKey(config)) {
|
|
91
|
+
console.log('\n⚠️ Pulando transcrição - nenhuma API key configurada');
|
|
92
|
+
updateStepStatus(state, i, 'skipped');
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
const transcription = await transcribeAudio(fileToTranscribe, config);
|
|
96
|
+
if (transcription) {
|
|
97
|
+
transcriptionFile = saveTranscription(fileToTranscribe, transcription);
|
|
98
|
+
state.intermediateFiles.transcriptionText = transcriptionFile;
|
|
99
|
+
console.log(`✓ Transcrição salva: ${path.basename(transcriptionFile)}`);
|
|
100
|
+
updateStepStatus(state, i, 'completed', { outputFile: transcriptionFile });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw new Error('Falha ao transcrever áudio');
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Step desconhecido: ${step.name}`);
|
|
108
|
+
}
|
|
109
|
+
nextStep(state);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error(`\n❌ Erro no step "${step.name}":`, error.message);
|
|
113
|
+
updateStepStatus(state, i, 'failed', undefined, error.message);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Salva o estado final
|
|
118
|
+
saveWorkflowState(state, outputDir);
|
|
119
|
+
// Exibe resumo
|
|
120
|
+
printWorkflowProgress(state);
|
|
121
|
+
// Exibe arquivos gerados
|
|
122
|
+
console.log('\n📦 Arquivos gerados:');
|
|
123
|
+
if (state.intermediateFiles.convertedVideo) {
|
|
124
|
+
console.log(` • Vídeo: ${path.basename(state.intermediateFiles.convertedVideo)}`);
|
|
125
|
+
}
|
|
126
|
+
if (state.intermediateFiles.extractedAudio) {
|
|
127
|
+
console.log(` • Áudio: ${path.basename(state.intermediateFiles.extractedAudio)}`);
|
|
128
|
+
}
|
|
129
|
+
if (state.intermediateFiles.transcriptionText) {
|
|
130
|
+
console.log(` • Transcrição: ${path.basename(state.intermediateFiles.transcriptionText)}`);
|
|
131
|
+
}
|
|
132
|
+
console.log('');
|
|
133
|
+
}
|
|
134
|
+
async function main() {
|
|
135
|
+
console.log('🎬 FFmpeg Simple Converter - Workflow Multi-Step\n');
|
|
136
|
+
// Verifica o ffmpeg
|
|
137
|
+
const ffmpegInstalled = verifyFfmpeg();
|
|
138
|
+
if (!ffmpegInstalled) {
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
console.log('');
|
|
142
|
+
// Garante que há configuração (mesmo que sem API keys)
|
|
143
|
+
const config = await ensureConfig();
|
|
144
|
+
// Lista arquivos
|
|
145
|
+
const currentDir = process.cwd();
|
|
146
|
+
const mediaFiles = listMediaFiles(currentDir);
|
|
147
|
+
if (mediaFiles.length === 0) {
|
|
148
|
+
console.log('\n⚠️ Nenhum arquivo de mídia encontrado no diretório atual.');
|
|
149
|
+
console.log('Formatos suportados:');
|
|
150
|
+
console.log(' • Áudio: .ogg, .wav, .mp3, .m4a, .aac, .flac');
|
|
151
|
+
console.log(' • Vídeo: .mp4, .mov, .mkv, .webm, .avi\n');
|
|
152
|
+
process.exit(0);
|
|
153
|
+
}
|
|
154
|
+
console.log(`\n📁 Encontrados ${mediaFiles.length} arquivo(s) de mídia\n`);
|
|
155
|
+
// Seleção do arquivo
|
|
156
|
+
const { selectedFile } = await inquirer.prompt([
|
|
157
|
+
{
|
|
158
|
+
type: 'list',
|
|
159
|
+
name: 'selectedFile',
|
|
160
|
+
message: 'Selecione o arquivo:',
|
|
161
|
+
choices: mediaFiles.map((f) => ({
|
|
162
|
+
name: `${f.type === 'video' ? '🎬' : '🎵'} ${f.name}`,
|
|
163
|
+
value: f.fullPath
|
|
164
|
+
}))
|
|
165
|
+
}
|
|
166
|
+
]);
|
|
167
|
+
const fileType = detectFileType(selectedFile);
|
|
168
|
+
// Filtra workflows compatíveis com o tipo de arquivo
|
|
169
|
+
const availableWorkflows = WORKFLOW_OPTIONS.filter((w) => {
|
|
170
|
+
if (w.requiresType === 'any')
|
|
171
|
+
return true;
|
|
172
|
+
return w.requiresType === fileType;
|
|
173
|
+
});
|
|
174
|
+
// Marca workflows que requerem API key
|
|
175
|
+
const workflowChoices = availableWorkflows.map((w) => {
|
|
176
|
+
const requiresTranscription = w.steps.some(s => s.includes('Transcrever'));
|
|
177
|
+
const hasKey = hasApiKey(config);
|
|
178
|
+
let name = w.name;
|
|
179
|
+
if (requiresTranscription && !hasKey) {
|
|
180
|
+
name += ' ⚠️ (requer API key)';
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
name,
|
|
184
|
+
value: w.value
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
// Seleção do workflow
|
|
188
|
+
const { selectedWorkflow } = await inquirer.prompt([
|
|
189
|
+
{
|
|
190
|
+
type: 'list',
|
|
191
|
+
name: 'selectedWorkflow',
|
|
192
|
+
message: 'Selecione o que deseja fazer:',
|
|
193
|
+
choices: workflowChoices
|
|
194
|
+
}
|
|
195
|
+
]);
|
|
196
|
+
const workflow = availableWorkflows.find((w) => w.value === selectedWorkflow);
|
|
197
|
+
if (!workflow) {
|
|
198
|
+
console.error('❌ Workflow inválido');
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
// Aviso se workflow requer transcrição mas não há API key
|
|
202
|
+
const requiresTranscription = workflow.steps.some(s => s.includes('Transcrever'));
|
|
203
|
+
if (requiresTranscription && !hasApiKey(config)) {
|
|
204
|
+
console.log('\n⚠️ Este workflow inclui transcrição, mas nenhuma API key está configurada.');
|
|
205
|
+
console.log('A transcrição será pulada. Configure uma API key para habilitar transcrição.\n');
|
|
206
|
+
const { confirm } = await inquirer.prompt([
|
|
207
|
+
{
|
|
208
|
+
type: 'confirm',
|
|
209
|
+
name: 'confirm',
|
|
210
|
+
message: 'Continuar mesmo assim?',
|
|
211
|
+
default: true
|
|
212
|
+
}
|
|
213
|
+
]);
|
|
214
|
+
if (!confirm) {
|
|
215
|
+
process.exit(0);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Executa o workflow
|
|
219
|
+
await executeWorkflow(workflow, selectedFile, config);
|
|
220
|
+
}
|
|
221
|
+
// Executa
|
|
222
|
+
main().catch((error) => {
|
|
223
|
+
console.error('\n❌ Erro:', error.message);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcreve um arquivo de áudio usando Groq Whisper
|
|
3
|
+
* https://console.groq.com/docs/speech-to-text
|
|
4
|
+
* @param audioLocalFilePath - Caminho local do arquivo de áudio
|
|
5
|
+
* @param apiKey - API Key do Groq
|
|
6
|
+
* @returns Texto transcrito ou null em caso de erro
|
|
7
|
+
*/
|
|
8
|
+
export declare const groqTranscriptAudio: (audioLocalFilePath: string, apiKey: string) => Promise<string | null>;
|
|
9
|
+
//# sourceMappingURL=groq.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groq.d.ts","sourceRoot":"","sources":["../../src/transcript/groq.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,oBAAoB,MAAM,EAC1B,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAmCvB,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import FormData from 'form-data';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
/**
|
|
5
|
+
* Transcreve um arquivo de áudio usando Groq Whisper
|
|
6
|
+
* https://console.groq.com/docs/speech-to-text
|
|
7
|
+
* @param audioLocalFilePath - Caminho local do arquivo de áudio
|
|
8
|
+
* @param apiKey - API Key do Groq
|
|
9
|
+
* @returns Texto transcrito ou null em caso de erro
|
|
10
|
+
*/
|
|
11
|
+
export const groqTranscriptAudio = async (audioLocalFilePath, apiKey) => {
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
console.error('❌ Groq API Key não fornecida');
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const formData = new FormData();
|
|
18
|
+
// Add the file from local path
|
|
19
|
+
formData.append('file', fs.createReadStream(audioLocalFilePath));
|
|
20
|
+
formData.append('model', 'whisper-large-v3');
|
|
21
|
+
formData.append('response_format', 'verbose_json');
|
|
22
|
+
formData.append('temperature', '0');
|
|
23
|
+
// formData.append('language', 'pt')
|
|
24
|
+
const { data } = await axios.post('https://api.groq.com/openai/v1/audio/transcriptions', formData, {
|
|
25
|
+
timeout: 60000,
|
|
26
|
+
headers: {
|
|
27
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
28
|
+
...formData.getHeaders()
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return data?.text?.trim() || null;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error('Erro ao transcrever áudio com Groq:', error.response?.data || error.message);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=groq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groq.js","sourceRoot":"","sources":["../../src/transcript/groq.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACtC,kBAA0B,EAC1B,MAAc,EACU,EAAE;IAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAA;QAC7C,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAA;QAE/B,+BAA+B;QAC/B,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAAA;QAChE,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;QAC5C,QAAQ,CAAC,MAAM,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAA;QAClD,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,CAAA;QACnC,oCAAoC;QAEpC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAC/B,qDAAqD,EACrD,QAAQ,EACR;YACE,OAAO,EAAE,KAAK;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,MAAM,EAAE;gBACnC,GAAG,QAAQ,CAAC,UAAU,EAAE;aACzB;SACF,CACF,CAAA;QAED,OAAO,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,CAAA;IAEnC,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;QAC3F,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Config } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Transcreve um arquivo de áudio tentando primeiro Groq, depois OpenAI
|
|
4
|
+
* @param audioFilePath - Caminho do arquivo de áudio
|
|
5
|
+
* @param config - Configuração com API keys
|
|
6
|
+
* @returns Texto transcrito ou null
|
|
7
|
+
*/
|
|
8
|
+
export declare function transcribeAudio(audioFilePath: string, config: Config): Promise<string | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Salva a transcrição em arquivo
|
|
11
|
+
*/
|
|
12
|
+
export declare function saveTranscription(audioPath: string, transcription: string): string;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transcript/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAI1C;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAMlF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { groqTranscriptAudio } from './groq.js';
|
|
4
|
+
import { openaiTranscriptAudio } from './openai.js';
|
|
5
|
+
/**
|
|
6
|
+
* Transcreve um arquivo de áudio tentando primeiro Groq, depois OpenAI
|
|
7
|
+
* @param audioFilePath - Caminho do arquivo de áudio
|
|
8
|
+
* @param config - Configuração com API keys
|
|
9
|
+
* @returns Texto transcrito ou null
|
|
10
|
+
*/
|
|
11
|
+
export async function transcribeAudio(audioFilePath, config) {
|
|
12
|
+
console.log(`\n🎙️ Transcrevendo: ${path.basename(audioFilePath)}`);
|
|
13
|
+
// Tenta Groq primeiro (mais rápido e barato)
|
|
14
|
+
if (config.groqApiKey) {
|
|
15
|
+
console.log('📡 Tentando Groq Whisper (rápido)...');
|
|
16
|
+
const result = await groqTranscriptAudio(audioFilePath, config.groqApiKey);
|
|
17
|
+
if (result) {
|
|
18
|
+
console.log('✓ Transcrição concluída com Groq');
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
console.log('⚠️ Falha com Groq, tentando OpenAI...');
|
|
22
|
+
}
|
|
23
|
+
// Se Groq falhou ou não está configurado, tenta OpenAI
|
|
24
|
+
if (config.openaiApiKey) {
|
|
25
|
+
console.log('📡 Tentando OpenAI Whisper...');
|
|
26
|
+
const result = await openaiTranscriptAudio(audioFilePath, config.openaiApiKey);
|
|
27
|
+
if (result) {
|
|
28
|
+
console.log('✓ Transcrição concluída com OpenAI');
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Se chegou aqui, nenhum serviço funcionou
|
|
33
|
+
if (!config.groqApiKey && !config.openaiApiKey) {
|
|
34
|
+
console.error('❌ Nenhuma API key configurada para transcrição');
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.error('❌ Falha ao transcrever com todos os serviços disponíveis');
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Salva a transcrição em arquivo
|
|
43
|
+
*/
|
|
44
|
+
export function saveTranscription(audioPath, transcription) {
|
|
45
|
+
const outputFileName = path.basename(audioPath, path.extname(audioPath)) + '.txt';
|
|
46
|
+
const outputPath = path.join(path.dirname(audioPath), outputFileName);
|
|
47
|
+
fs.writeFileSync(outputPath, transcription, 'utf-8');
|
|
48
|
+
return outputPath;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transcript/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAAqB,EACrB,MAAc;IAGd,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;IAEpE,6CAA6C;IAC7C,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;QACnD,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;QAC1E,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;YAC/C,OAAO,MAAM,CAAA;QACf,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAA;IACvD,CAAC;IAED,uDAAuD;IACvD,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,aAAa,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;QAC9E,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;YACjD,OAAO,MAAM,CAAA;QACf,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAA;IACjE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAA;IAC3E,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,aAAqB;IACxE,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,CAAA;IACjF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC,CAAA;IAErE,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,aAAa,EAAE,OAAO,CAAC,CAAA;IACpD,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcreve um arquivo de áudio usando OpenAI Whisper
|
|
3
|
+
* @param audioLocalFilePath - Caminho local do arquivo de áudio
|
|
4
|
+
* @param apiKey - API Key da OpenAI
|
|
5
|
+
* @returns Texto transcrito ou null em caso de erro
|
|
6
|
+
*/
|
|
7
|
+
export declare const openaiTranscriptAudio: (audioLocalFilePath: string, apiKey: string) => Promise<string | null>;
|
|
8
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/transcript/openai.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,oBAAoB,MAAM,EAC1B,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAqBvB,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import OpenAI from 'openai';
|
|
3
|
+
/**
|
|
4
|
+
* Transcreve um arquivo de áudio usando OpenAI Whisper
|
|
5
|
+
* @param audioLocalFilePath - Caminho local do arquivo de áudio
|
|
6
|
+
* @param apiKey - API Key da OpenAI
|
|
7
|
+
* @returns Texto transcrito ou null em caso de erro
|
|
8
|
+
*/
|
|
9
|
+
export const openaiTranscriptAudio = async (audioLocalFilePath, apiKey) => {
|
|
10
|
+
if (!apiKey) {
|
|
11
|
+
console.error('❌ OpenAI API Key não fornecida');
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const openai = new OpenAI({ apiKey });
|
|
16
|
+
const transcription = await openai.audio.transcriptions.create({
|
|
17
|
+
file: fs.createReadStream(audioLocalFilePath),
|
|
18
|
+
model: 'whisper-1',
|
|
19
|
+
});
|
|
20
|
+
return transcription.text ?? null;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error('Erro ao transcrever áudio com OpenAI:', error.response?.data || error.message);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/transcript/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EACxC,kBAA0B,EAC1B,MAAc,EACU,EAAE;IAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;QAC/C,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QAErC,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC;YAC7D,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,kBAAkB,CAAC;YAC7C,KAAK,EAAE,WAAW;SACnB,CAAC,CAAA;QAEF,OAAO,aAAa,CAAC,IAAI,IAAI,IAAI,CAAA;IAEnC,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;QAC7F,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
openaiApiKey?: string;
|
|
3
|
+
groqApiKey?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface WorkflowStep {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
|
|
9
|
+
result?: any;
|
|
10
|
+
error?: string;
|
|
11
|
+
startTime?: number;
|
|
12
|
+
endTime?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface WorkflowState {
|
|
15
|
+
steps: WorkflowStep[];
|
|
16
|
+
currentStepIndex: number;
|
|
17
|
+
inputFile: string;
|
|
18
|
+
intermediateFiles: {
|
|
19
|
+
convertedVideo?: string;
|
|
20
|
+
extractedAudio?: string;
|
|
21
|
+
transcriptionText?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export type OperationType = 'convert-video' | 'extract-audio' | 'convert-audio' | 'transcribe';
|
|
25
|
+
export interface Operation {
|
|
26
|
+
type: OperationType;
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
requiresInput: 'video' | 'audio' | 'any';
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;IAClE,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,iBAAiB,EAAE;QACjB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,GAAG,YAAY,CAAA;AAE9F,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,CAAA;CACzC"}
|