@bryan-gc/transcribe-cli 1.0.5 → 1.0.7
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/dist/components/App.d.ts +1 -1
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +7 -200
- package/dist/components/App.js.map +1 -1
- package/dist/components/AutoRecordApp.d.ts.map +1 -1
- package/dist/components/AutoRecordApp.js +9 -126
- package/dist/components/AutoRecordApp.js.map +1 -1
- package/dist/components/Header.d.ts +14 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +8 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/MicTest.d.ts.map +1 -1
- package/dist/components/MicTest.js +7 -89
- package/dist/components/MicTest.js.map +1 -1
- package/dist/hooks/useAutoRecord.d.ts +18 -0
- package/dist/hooks/useAutoRecord.d.ts.map +1 -0
- package/dist/hooks/useAutoRecord.js +110 -0
- package/dist/hooks/useAutoRecord.js.map +1 -0
- package/dist/hooks/useMicTest.d.ts +18 -0
- package/dist/hooks/useMicTest.d.ts.map +1 -0
- package/dist/hooks/useMicTest.js +105 -0
- package/dist/hooks/useMicTest.js.map +1 -0
- package/dist/hooks/useTranscriberApp.d.ts +36 -0
- package/dist/hooks/useTranscriberApp.d.ts.map +1 -0
- package/dist/hooks/useTranscriberApp.js +202 -0
- package/dist/hooks/useTranscriberApp.js.map +1 -0
- package/dist/utils/fileUtils.d.ts +22 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +51 -0
- package/dist/utils/fileUtils.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { useState, useRef, useCallback } from 'react';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { AudioRecorder } from '../audio/recorder.js';
|
|
4
|
+
import { listMicDevices } from '../audio/micDevices.js';
|
|
5
|
+
import { WhisperTranscriber } from '../transcriber/WhisperTranscriber.js';
|
|
6
|
+
import { extractTextFromSrt } from '../utils/srtParser.js';
|
|
7
|
+
import { copyTextToClipboard } from '../utils/clipboard.js';
|
|
8
|
+
import { ConfigManager } from '../config/configManager.js';
|
|
9
|
+
import { getTimestampPaths, loadGlossaryFiles, readGlossaryContent } from '../utils/fileUtils.js';
|
|
10
|
+
import { DEFAULT_DEVICE_ID, DEFAULT_DEVICE_LABEL, Encoding, LanguageCode, LANGUAGE_NAMES, AVAILABLE_LANGUAGES, TranscriptionFormat, ViewMode, MenuAction, } from '../constants.js';
|
|
11
|
+
export function useTranscriberApp(appConfig, exit) {
|
|
12
|
+
// ── State ──────────────────────────────────────────────────────────────────
|
|
13
|
+
const [viewMode, setViewMode] = useState(ViewMode.MAIN);
|
|
14
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
15
|
+
const [statusText, setStatusText] = useState('Ready to record.');
|
|
16
|
+
const [isRecording, setIsRecording] = useState(false);
|
|
17
|
+
const [isPaused, setIsPaused] = useState(false);
|
|
18
|
+
const [isTranscribing, setIsTranscribing] = useState(false);
|
|
19
|
+
const [transcriptionResult, setTranscriptionResult] = useState('');
|
|
20
|
+
const [clipboardEnabled, setClipboardEnabled] = useState(appConfig.autoCopy);
|
|
21
|
+
const [currentAudioPath, setCurrentAudioPath] = useState('');
|
|
22
|
+
const [currentSrtPath, setCurrentSrtPath] = useState('');
|
|
23
|
+
const [currentTextPath, setCurrentTextPath] = useState('');
|
|
24
|
+
const [activeLanguage, setActiveLanguage] = useState(AVAILABLE_LANGUAGES.includes(appConfig.selectedLanguage)
|
|
25
|
+
? appConfig.selectedLanguage
|
|
26
|
+
: LanguageCode.ENGLISH);
|
|
27
|
+
const initialGlossaries = loadGlossaryFiles(appConfig.basePath);
|
|
28
|
+
const [activeGlossary, setActiveGlossary] = useState(initialGlossaries[0] ?? '');
|
|
29
|
+
const initialMics = listMicDevices();
|
|
30
|
+
const fallbackMic = { id: DEFAULT_DEVICE_ID, label: DEFAULT_DEVICE_LABEL };
|
|
31
|
+
const savedMic = initialMics.find((m) => m.id === appConfig.selectedMicrophone);
|
|
32
|
+
const [activeMic, setActiveMic] = useState(savedMic ?? fallbackMic);
|
|
33
|
+
const [pendingMic, setPendingMic] = useState(savedMic ?? fallbackMic);
|
|
34
|
+
const [micDevices, setMicDevices] = useState(initialMics);
|
|
35
|
+
const [glossaryFiles, setGlossaryFiles] = useState(initialGlossaries);
|
|
36
|
+
const saveConfig = useCallback((updates) => {
|
|
37
|
+
const newConfig = { ...appConfig, ...updates };
|
|
38
|
+
ConfigManager.save(newConfig);
|
|
39
|
+
Object.assign(appConfig, updates); // mutate for current session ref
|
|
40
|
+
}, [appConfig]);
|
|
41
|
+
// ── Refs ───────────────────────────────────────────────────────────────────
|
|
42
|
+
const recorderRef = useRef(new AudioRecorder());
|
|
43
|
+
const transcriber = useRef(new WhisperTranscriber(appConfig.apiKey));
|
|
44
|
+
const recorder = recorderRef.current;
|
|
45
|
+
try {
|
|
46
|
+
recorder.setDevice(activeMic.id);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* recording in progress */
|
|
50
|
+
}
|
|
51
|
+
// ── Actions ────────────────────────────────────────────────────────────────
|
|
52
|
+
const handleAction = useCallback(async (actionId) => {
|
|
53
|
+
switch (actionId) {
|
|
54
|
+
case MenuAction.RECORD:
|
|
55
|
+
if (!isRecording) {
|
|
56
|
+
const p = getTimestampPaths(appConfig.basePath);
|
|
57
|
+
setCurrentAudioPath(p.audioPath);
|
|
58
|
+
setCurrentSrtPath(p.srtPath);
|
|
59
|
+
setCurrentTextPath(p.textPath);
|
|
60
|
+
recorder.start(p.audioPath);
|
|
61
|
+
setIsRecording(true);
|
|
62
|
+
setIsPaused(false);
|
|
63
|
+
setTranscriptionResult('');
|
|
64
|
+
setStatusText('🔴 Recording...');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (isPaused) {
|
|
68
|
+
recorder.resume();
|
|
69
|
+
setIsPaused(false);
|
|
70
|
+
setStatusText('🔴 Recording...');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
setStatusText('Already recording.');
|
|
74
|
+
break;
|
|
75
|
+
case MenuAction.PAUSE:
|
|
76
|
+
if (isRecording && !isPaused) {
|
|
77
|
+
recorder.pause();
|
|
78
|
+
setIsPaused(true);
|
|
79
|
+
setStatusText('⏸️ Paused');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
setStatusText('No active recording to pause.');
|
|
83
|
+
break;
|
|
84
|
+
case MenuAction.STOP:
|
|
85
|
+
if (isRecording) {
|
|
86
|
+
await recorder.stop();
|
|
87
|
+
setIsRecording(false);
|
|
88
|
+
setIsPaused(false);
|
|
89
|
+
setStatusText('⏹️ Stopped. File saved.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
setStatusText('No recording in progress.');
|
|
93
|
+
break;
|
|
94
|
+
case MenuAction.CHANGE_LANGUAGE:
|
|
95
|
+
setViewMode(ViewMode.LANGUAGES);
|
|
96
|
+
break;
|
|
97
|
+
case MenuAction.CHANGE_GLOSSARY:
|
|
98
|
+
setGlossaryFiles(loadGlossaryFiles(appConfig.basePath));
|
|
99
|
+
setViewMode(ViewMode.GLOSSARIES);
|
|
100
|
+
break;
|
|
101
|
+
case MenuAction.CHANGE_MICROPHONE: {
|
|
102
|
+
const fresh = listMicDevices();
|
|
103
|
+
setMicDevices(fresh);
|
|
104
|
+
setPendingMic(activeMic);
|
|
105
|
+
setViewMode(ViewMode.MICROPHONES);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case MenuAction.TOGGLE_CLIPBOARD:
|
|
109
|
+
setClipboardEnabled((prev) => {
|
|
110
|
+
const newValue = !prev;
|
|
111
|
+
saveConfig({ autoCopy: newValue });
|
|
112
|
+
return newValue;
|
|
113
|
+
});
|
|
114
|
+
break;
|
|
115
|
+
case MenuAction.TRANSCRIBE: {
|
|
116
|
+
if (isRecording) {
|
|
117
|
+
setStatusText('Please stop the recording before transcribing.');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (!currentAudioPath || !fs.existsSync(currentAudioPath)) {
|
|
121
|
+
setStatusText('No recent audio file found to transcribe.');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const glossaryPrompt = readGlossaryContent(appConfig.basePath, activeGlossary);
|
|
125
|
+
setIsTranscribing(true);
|
|
126
|
+
setStatusText(`⏳ Transcribing (${LANGUAGE_NAMES[activeLanguage]}${glossaryPrompt ? ' + glossary' : ''}) - Initializing...`);
|
|
127
|
+
try {
|
|
128
|
+
const srtContent = await transcriber.current.transcribe(currentAudioPath, activeLanguage, TranscriptionFormat.SRT, glossaryPrompt, (msg) => setStatusText(`⏳ Transcribing: ${msg}`));
|
|
129
|
+
setStatusText('⏳ Formatting text and saving files...');
|
|
130
|
+
fs.writeFileSync(currentSrtPath, srtContent, Encoding.UTF8);
|
|
131
|
+
const cleanText = extractTextFromSrt(srtContent);
|
|
132
|
+
fs.writeFileSync(currentTextPath, cleanText, Encoding.UTF8);
|
|
133
|
+
setTranscriptionResult(cleanText);
|
|
134
|
+
if (clipboardEnabled) {
|
|
135
|
+
copyTextToClipboard(cleanText);
|
|
136
|
+
setStatusText('✅ Transcription done — copied to clipboard.');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
setStatusText('✅ Transcription completed and saved.');
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
setStatusText(`❌ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
setIsTranscribing(false);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case MenuAction.QUIT:
|
|
150
|
+
if (isRecording)
|
|
151
|
+
await recorder.stop();
|
|
152
|
+
exit();
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}, [
|
|
156
|
+
isRecording,
|
|
157
|
+
isPaused,
|
|
158
|
+
currentAudioPath,
|
|
159
|
+
currentSrtPath,
|
|
160
|
+
currentTextPath,
|
|
161
|
+
activeLanguage,
|
|
162
|
+
activeGlossary,
|
|
163
|
+
activeMic,
|
|
164
|
+
clipboardEnabled,
|
|
165
|
+
recorder,
|
|
166
|
+
exit,
|
|
167
|
+
appConfig.basePath,
|
|
168
|
+
saveConfig,
|
|
169
|
+
]);
|
|
170
|
+
return {
|
|
171
|
+
state: {
|
|
172
|
+
viewMode,
|
|
173
|
+
selectedIndex,
|
|
174
|
+
statusText,
|
|
175
|
+
isRecording,
|
|
176
|
+
isPaused,
|
|
177
|
+
isTranscribing,
|
|
178
|
+
transcriptionResult,
|
|
179
|
+
clipboardEnabled,
|
|
180
|
+
currentTextPath,
|
|
181
|
+
activeLanguage,
|
|
182
|
+
activeGlossary,
|
|
183
|
+
activeMic,
|
|
184
|
+
pendingMic,
|
|
185
|
+
micDevices,
|
|
186
|
+
glossaryFiles,
|
|
187
|
+
recorder,
|
|
188
|
+
},
|
|
189
|
+
actions: {
|
|
190
|
+
setViewMode,
|
|
191
|
+
setSelectedIndex,
|
|
192
|
+
setStatusText,
|
|
193
|
+
setActiveLanguage,
|
|
194
|
+
setActiveGlossary,
|
|
195
|
+
setActiveMic,
|
|
196
|
+
setPendingMic,
|
|
197
|
+
handleAction,
|
|
198
|
+
saveConfig,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=useTranscriberApp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTranscriberApp.js","sourceRoot":"","sources":["../../src/hooks/useTranscriberApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAkB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,QAAQ,EACR,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB,MAAM,UAAU,iBAAiB,CAAC,SAAoB,EAAE,IAAgB;IACtE,8EAA8E;IAC9E,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAW,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IACjE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5D,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAE7E,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzD,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAE3D,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAClD,mBAAmB,CAAC,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC;QACtD,CAAC,CAAC,SAAS,CAAC,gBAAgB;QAC5B,CAAC,CAAC,YAAY,CAAC,OAAO,CACzB,CAAC;IAEF,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEjF,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,WAAW,GAAc,EAAE,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;IACtF,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAChF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAY,QAAQ,IAAI,WAAW,CAAC,CAAC;IAC/E,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAY,QAAQ,IAAI,WAAW,CAAC,CAAC;IACjF,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAc,WAAW,CAAC,CAAC;IACvE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAW,iBAAiB,CAAC,CAAC;IAEhF,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,OAA2B,EAAE,EAAE;QAC9B,MAAM,SAAS,GAAG,EAAE,GAAG,SAAS,EAAE,GAAG,OAAO,EAAE,CAAC;QAC/C,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,iCAAiC;IACtE,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,8EAA8E;IAC9E,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,kBAAkB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC;IACrC,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;IAED,8EAA8E;IAC9E,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,QAAoB,EAAE,EAAE;QAC7B,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,UAAU,CAAC,MAAM;gBACpB,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,MAAM,CAAC,GAAG,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;oBAChD,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;oBACjC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;oBAC7B,kBAAkB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;oBAC/B,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;oBAC5B,cAAc,CAAC,IAAI,CAAC,CAAC;oBACrB,WAAW,CAAC,KAAK,CAAC,CAAC;oBACnB,sBAAsB,CAAC,EAAE,CAAC,CAAC;oBAC3B,aAAa,CAAC,iBAAiB,CAAC,CAAC;oBACjC,OAAO;gBACT,CAAC;gBACD,IAAI,QAAQ,EAAE,CAAC;oBACb,QAAQ,CAAC,MAAM,EAAE,CAAC;oBAClB,WAAW,CAAC,KAAK,CAAC,CAAC;oBACnB,aAAa,CAAC,iBAAiB,CAAC,CAAC;oBACjC,OAAO;gBACT,CAAC;gBACD,aAAa,CAAC,oBAAoB,CAAC,CAAC;gBACpC,MAAM;YAER,KAAK,UAAU,CAAC,KAAK;gBACnB,IAAI,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACjB,WAAW,CAAC,IAAI,CAAC,CAAC;oBAClB,aAAa,CAAC,YAAY,CAAC,CAAC;oBAC5B,OAAO;gBACT,CAAC;gBACD,aAAa,CAAC,+BAA+B,CAAC,CAAC;gBAC/C,MAAM;YAER,KAAK,UAAU,CAAC,IAAI;gBAClB,IAAI,WAAW,EAAE,CAAC;oBAChB,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;oBACtB,cAAc,CAAC,KAAK,CAAC,CAAC;oBACtB,WAAW,CAAC,KAAK,CAAC,CAAC;oBACnB,aAAa,CAAC,0BAA0B,CAAC,CAAC;oBAC1C,OAAO;gBACT,CAAC;gBACD,aAAa,CAAC,2BAA2B,CAAC,CAAC;gBAC3C,MAAM;YAER,KAAK,UAAU,CAAC,eAAe;gBAC7B,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBAChC,MAAM;YAER,KAAK,UAAU,CAAC,eAAe;gBAC7B,gBAAgB,CAAC,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACxD,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;gBACjC,MAAM;YAER,KAAK,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC;gBAClC,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;gBAC/B,aAAa,CAAC,KAAK,CAAC,CAAC;gBACrB,aAAa,CAAC,SAAS,CAAC,CAAC;gBACzB,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;gBAClC,MAAM;YACR,CAAC;YAED,KAAK,UAAU,CAAC,gBAAgB;gBAC9B,mBAAmB,CAAC,CAAC,IAAI,EAAE,EAAE;oBAC3B,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC;oBACvB,UAAU,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;oBACnC,OAAO,QAAQ,CAAC;gBAClB,CAAC,CAAC,CAAC;gBACH,MAAM;YAER,KAAK,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;gBAC3B,IAAI,WAAW,EAAE,CAAC;oBAChB,aAAa,CAAC,gDAAgD,CAAC,CAAC;oBAChE,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,gBAAgB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;oBAC1D,aAAa,CAAC,2CAA2C,CAAC,CAAC;oBAC3D,OAAO;gBACT,CAAC;gBAED,MAAM,cAAc,GAAG,mBAAmB,CAAC,SAAS,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;gBAC/E,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACxB,aAAa,CACX,mBAAmB,cAAc,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,qBAAqB,CAC7G,CAAC;gBACF,IAAI,CAAC;oBACH,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,UAAU,CACrD,gBAAgB,EAChB,cAAc,EACd,mBAAmB,CAAC,GAAG,EACvB,cAAc,EACd,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,mBAAmB,GAAG,EAAE,CAAC,CACjD,CAAC;oBAEF,aAAa,CAAC,uCAAuC,CAAC,CAAC;oBACvD,EAAE,CAAC,aAAa,CAAC,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;oBAC5D,MAAM,SAAS,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;oBACjD,EAAE,CAAC,aAAa,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;oBAC5D,sBAAsB,CAAC,SAAS,CAAC,CAAC;oBAElC,IAAI,gBAAgB,EAAE,CAAC;wBACrB,mBAAmB,CAAC,SAAS,CAAC,CAAC;wBAC/B,aAAa,CAAC,6CAA6C,CAAC,CAAC;wBAC7D,OAAO;oBACT,CAAC;oBACD,aAAa,CAAC,sCAAsC,CAAC,CAAC;gBACxD,CAAC;gBAAC,OAAO,GAAY,EAAE,CAAC;oBACtB,aAAa,CAAC,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChF,CAAC;wBAAS,CAAC;oBACT,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,UAAU,CAAC,IAAI;gBAClB,IAAI,WAAW;oBAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACvC,IAAI,EAAE,CAAC;gBACP,MAAM;QACV,CAAC;IACH,CAAC,EACD;QACE,WAAW;QACX,QAAQ;QACR,gBAAgB;QAChB,cAAc;QACd,eAAe;QACf,cAAc;QACd,cAAc;QACd,SAAS;QACT,gBAAgB;QAChB,QAAQ;QACR,IAAI;QACJ,SAAS,CAAC,QAAQ;QAClB,UAAU;KACX,CACF,CAAC;IAEF,OAAO;QACL,KAAK,EAAE;YACL,QAAQ;YACR,aAAa;YACb,UAAU;YACV,WAAW;YACX,QAAQ;YACR,cAAc;YACd,mBAAmB;YACnB,gBAAgB;YAChB,eAAe;YACf,cAAc;YACd,cAAc;YACd,SAAS;YACT,UAAU;YACV,UAAU;YACV,aAAa;YACb,QAAQ;SACT;QACD,OAAO,EAAE;YACP,WAAW;YACX,gBAAgB;YAChB,aAAa;YACb,iBAAiB;YACjB,iBAAiB;YACjB,YAAY;YACZ,aAAa;YACb,YAAY;YACZ,UAAU;SACX;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates unique file paths for audio, srt, and text files based on the current timestamp.
|
|
3
|
+
*/
|
|
4
|
+
export declare function getTimestampPaths(basePath: string): {
|
|
5
|
+
audioPath: string;
|
|
6
|
+
srtPath: string;
|
|
7
|
+
textPath: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Loads the list of available glossary files from the configured directory.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loadGlossaryFiles(basePath: string): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Reads the content of a specific glossary file.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readGlossaryContent(basePath: string, filename: string): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Ensures at least one glossary is selected if available.
|
|
19
|
+
* Useful for automatic modes where a default might be needed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getInitialGlossary(basePath: string): string;
|
|
22
|
+
//# sourceMappingURL=fileUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileUtils.d.ts","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM;;;;EAYjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK1F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3D"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { DIR, EXT, Encoding, getPaths } from '../constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* Generates unique file paths for audio, srt, and text files based on the current timestamp.
|
|
6
|
+
*/
|
|
7
|
+
export function getTimestampPaths(basePath) {
|
|
8
|
+
const now = new Date();
|
|
9
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
10
|
+
const folder = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
|
|
11
|
+
const base = `${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
|
|
12
|
+
const tmpDir = path.resolve(basePath, DIR.TMP, folder);
|
|
13
|
+
if (!fs.existsSync(tmpDir))
|
|
14
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
15
|
+
return {
|
|
16
|
+
audioPath: path.join(tmpDir, `${base}${EXT.AUDIO}`),
|
|
17
|
+
srtPath: path.join(tmpDir, `${base}${EXT.SUBTITLES}`),
|
|
18
|
+
textPath: path.join(tmpDir, `${base}${EXT.TEXT}`),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Loads the list of available glossary files from the configured directory.
|
|
23
|
+
*/
|
|
24
|
+
export function loadGlossaryFiles(basePath) {
|
|
25
|
+
const dir = getPaths(basePath).GLOSSARIES_DIR;
|
|
26
|
+
if (!fs.existsSync(dir))
|
|
27
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
28
|
+
return fs
|
|
29
|
+
.readdirSync(dir)
|
|
30
|
+
.filter((f) => f.endsWith(EXT.GLOSSARY))
|
|
31
|
+
.sort();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reads the content of a specific glossary file.
|
|
35
|
+
*/
|
|
36
|
+
export function readGlossaryContent(basePath, filename) {
|
|
37
|
+
if (!filename)
|
|
38
|
+
return undefined;
|
|
39
|
+
const filepath = path.join(getPaths(basePath).GLOSSARIES_DIR, filename);
|
|
40
|
+
const content = fs.existsSync(filepath) ? fs.readFileSync(filepath, Encoding.UTF8).trim() : '';
|
|
41
|
+
return content || undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Ensures at least one glossary is selected if available.
|
|
45
|
+
* Useful for automatic modes where a default might be needed.
|
|
46
|
+
*/
|
|
47
|
+
export function getInitialGlossary(basePath) {
|
|
48
|
+
const files = loadGlossaryFiles(basePath);
|
|
49
|
+
return files[0] ?? '';
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=fileUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileUtils.js","sourceRoot":"","sources":["../../src/utils/fileUtils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bryan-gc/transcribe-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "CLI tool to record audio and transcribe it using OpenAI Whisper",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"@types/node": "^25.7.0",
|
|
42
42
|
"commander": "^14.0.3",
|
|
43
43
|
"ink": "^7.0.3",
|
|
44
|
+
"ink-spinner": "^5.0.0",
|
|
44
45
|
"openai": "^6.37.0",
|
|
45
46
|
"react": "^19.2.6",
|
|
46
47
|
"tsx": "^4.22.0",
|