beast-agent 2.3.1 → 2.3.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/package.json +1 -1
- package/src/main.js +47 -0
- package/src/preload.js +2 -0
- package/src/renderer/i18n.js +4 -2
- package/src/renderer/renderer.js +38 -2
package/package.json
CHANGED
package/src/main.js
CHANGED
|
@@ -5778,6 +5778,53 @@ ipcMain.handle('stt:transcribe', async (_e, b64, lang, priority) => {
|
|
|
5778
5778
|
});
|
|
5779
5779
|
|
|
5780
5780
|
ipcMain.handle('stt:lang:get', () => settings.sttLang || 'tr');
|
|
5781
|
+
|
|
5782
|
+
/* STT DURUMU: ayarlar ekranı için — model indirildi mi/in-progress mi,
|
|
5783
|
+
hangi motor, ne kadar disk */
|
|
5784
|
+
ipcMain.handle('stt:status', () => {
|
|
5785
|
+
const provider = sttProvider();
|
|
5786
|
+
const model = sttModelName();
|
|
5787
|
+
const out = { provider, engineLabel: sttEngineLabel(), model };
|
|
5788
|
+
if (provider !== 'local') { out.state = 'cloud'; return out; }
|
|
5789
|
+
const dir = path.join(APP_DIR, 'models', ...model.split('/'));
|
|
5790
|
+
let files = [];
|
|
5791
|
+
try {
|
|
5792
|
+
files = fs.readdirSync(dir, { recursive: true, withFileTypes: true })
|
|
5793
|
+
.filter((d) => d.isFile())
|
|
5794
|
+
.map((d) => path.join(d.parentPath || d.path, d.name));
|
|
5795
|
+
} catch {}
|
|
5796
|
+
let bytes = 0;
|
|
5797
|
+
let tmp = 0;
|
|
5798
|
+
let onnx = 0;
|
|
5799
|
+
let hasConfig = false;
|
|
5800
|
+
for (const p of files) {
|
|
5801
|
+
try {
|
|
5802
|
+
bytes += fs.statSync(p).size;
|
|
5803
|
+
if (/\.tmp/i.test(p)) tmp++;
|
|
5804
|
+
else if (/\.onnx$/i.test(p)) onnx++;
|
|
5805
|
+
else if (/config\.json$/i.test(p)) hasConfig = true;
|
|
5806
|
+
} catch {}
|
|
5807
|
+
}
|
|
5808
|
+
let state;
|
|
5809
|
+
if (sttPipeline) state = 'ready';
|
|
5810
|
+
else if (sttLoading) state = 'loading';
|
|
5811
|
+
else if (hasConfig && onnx >= 2 && tmp === 0) state = 'downloaded';
|
|
5812
|
+
else if (files.length) state = 'partial';
|
|
5813
|
+
else state = 'missing';
|
|
5814
|
+
out.state = state;
|
|
5815
|
+
out.mb = Math.round(bytes / (1024 * 1024));
|
|
5816
|
+
out.onnx = onnx;
|
|
5817
|
+
out.tmp = tmp;
|
|
5818
|
+
return out;
|
|
5819
|
+
});
|
|
5820
|
+
|
|
5821
|
+
/* istenirse modeli şimdi indir/yükle (bloklamaz — arka planda) */
|
|
5822
|
+
ipcMain.handle('stt:prefetch', () => {
|
|
5823
|
+
ensureStt()
|
|
5824
|
+
.then(() => waLog('STT prefetch: hazır'))
|
|
5825
|
+
.catch((e) => waLog('STT prefetch hata: ' + String((e && e.message) || e)));
|
|
5826
|
+
return { ok: true, loading: true };
|
|
5827
|
+
});
|
|
5781
5828
|
ipcMain.handle('stt:lang:set', (_e, lang) => {
|
|
5782
5829
|
const v = ['auto', 'tr', 'en'].includes(String(lang)) ? String(lang) : 'tr';
|
|
5783
5830
|
settings.sttLang = v;
|
package/src/preload.js
CHANGED
|
@@ -53,6 +53,8 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
53
53
|
approvalRespond: (id, ok, always) => ipcRenderer.invoke('approval:respond', { id, ok, always }),
|
|
54
54
|
sttTranscribe: (b64, lang, priority) => ipcRenderer.invoke('stt:transcribe', b64, lang, priority),
|
|
55
55
|
sttLangGet: () => ipcRenderer.invoke('stt:lang:get'),
|
|
56
|
+
sttStatus: () => ipcRenderer.invoke('stt:status'),
|
|
57
|
+
sttPrefetchNow: () => ipcRenderer.invoke('stt:prefetch'),
|
|
56
58
|
sttLangSet: (lang) => ipcRenderer.invoke('stt:lang:set', lang),
|
|
57
59
|
updateStatus: () => ipcRenderer.invoke('update:status'),
|
|
58
60
|
updateCheck: () => ipcRenderer.invoke('update:check'),
|
package/src/renderer/i18n.js
CHANGED
|
@@ -214,7 +214,8 @@
|
|
|
214
214
|
tts_sub: 'Açık olursa WhatsApp cevapları metnin yanı sıra sesli not olarak da gönderilir.',
|
|
215
215
|
tts_active: 'Aktif',
|
|
216
216
|
tts_save: 'TTS Kaydet',
|
|
217
|
-
tts_test: 'Test sesi çal',
|
|
217
|
+
tts_test: 'Test sesi çal',
|
|
218
|
+
stt_download_now: 'Şimdi indir / hazırla',
|
|
218
219
|
tts_note: 'Edge TTS: ücretsiz yerel motor — anahtar gerekmez (Ahmet/Emel vb.). OpenAI motoru: uyumlu speech API (tts-1, tts-1-hd; sesler alloy, echo, fable, onyx, nova, shimmer).',
|
|
219
220
|
tts_engine: 'Motor',
|
|
220
221
|
tts_edge_voice: 'Edge sesi',
|
|
@@ -789,7 +790,8 @@
|
|
|
789
790
|
tts_sub: 'When on, WhatsApp replies are also sent as voice notes alongside text.',
|
|
790
791
|
tts_active: 'Active',
|
|
791
792
|
tts_save: 'Save TTS',
|
|
792
|
-
tts_test: 'Play test sound',
|
|
793
|
+
tts_test: 'Play test sound',
|
|
794
|
+
stt_download_now: 'Download / prepare now',
|
|
793
795
|
tts_note: 'Edge TTS: free local engine — no key needed (Ahmet/Emel etc.). OpenAI engine: compatible speech API (tts-1, tts-1-hd; voices alloy, echo, fable, onyx, nova, shimmer).',
|
|
794
796
|
tts_engine: 'Engine',
|
|
795
797
|
tts_edge_voice: 'Edge voice',
|
package/src/renderer/renderer.js
CHANGED
|
@@ -2097,9 +2097,23 @@ function ttsFlushTail() {
|
|
|
2097
2097
|
if (rest) ttsEnqueueSentence(rest);
|
|
2098
2098
|
else ttsKick();
|
|
2099
2099
|
}
|
|
2100
|
-
|
|
2101
|
-
|
|
2100
|
+
async function renderTtsPane() {
|
|
2101
|
+
const pane = $('#tab-tts');
|
|
2102
2102
|
if (!pane) return;
|
|
2103
|
+
/* STT DURUMU: model indirildi mi / iniyor mu / hangi motor */
|
|
2104
|
+
let stt = null;
|
|
2105
|
+
try { stt = await beast.sttStatus(); } catch {}
|
|
2106
|
+
const stateText = {
|
|
2107
|
+
ready: 'HAZIR — model yüklü',
|
|
2108
|
+
loading: 'İNİYOR / yükleniyor…',
|
|
2109
|
+
downloaded: 'indirildi — ilk kullanımda yüklenir',
|
|
2110
|
+
partial: 'kısmen indi — devam edecek',
|
|
2111
|
+
missing: 'henüz indirilmedi',
|
|
2112
|
+
cloud: 'bulut motoru — indirme gerekmez',
|
|
2113
|
+
};
|
|
2114
|
+
const sttLine = stt
|
|
2115
|
+
? stt.engineLabel + ' · ' + (stateText[stt.state] || stt.state) + (stt.mb ? ' · ' + stt.mb + ' MB' : '')
|
|
2116
|
+
: (window.beast ? 'bilinmiyor' : '');
|
|
2103
2117
|
const edgeOpts = [
|
|
2104
2118
|
['tr-TR-AhmetNeural', 'Ahmet — Türkçe (erkek)'],
|
|
2105
2119
|
['tr-TR-EmelNeural', 'Emel — Türkçe (kadın)'],
|
|
@@ -2112,6 +2126,10 @@ async function renderTtsPane() { const pane = $('#tab-tts');
|
|
|
2112
2126
|
.join('');
|
|
2113
2127
|
pane.innerHTML =
|
|
2114
2128
|
'<h2>' + _t('tts_h2') + '</h2><div class="sub">' + _t('tts_sub') + '</div>' +
|
|
2129
|
+
'<div class="sub" style="margin:10px 0 4px;font-weight:700;color:var(--accent)">STT (Ses → Yazı)</div>' +
|
|
2130
|
+
`<div class="sub" id="sttStatusTxt" style="margin-bottom:8px">${sttLine}</div>` +
|
|
2131
|
+
`<button id="sttDlBtn" class="btn ghost" style="margin-bottom:14px">${_t('stt_download_now')}</button>` +
|
|
2132
|
+
'<div class="sub" style="margin:10px 0 4px;font-weight:700;color:var(--accent)">TTS (Yazı → Ses)</div>' +
|
|
2115
2133
|
`<div class="form-grid" style="grid-template-columns:auto 1fr 1fr;align-items:center;margin-top:10px">
|
|
2116
2134
|
<label class="lock-row"><input type="checkbox" id="ttsOn" /><span>${_t('tts_active')}</span></label>
|
|
2117
2135
|
<label style="grid-column:1">${_t('tts_engine')}</label>
|
|
@@ -2153,6 +2171,24 @@ async function renderTtsPane() { const pane = $('#tab-tts');
|
|
|
2153
2171
|
} catch {}
|
|
2154
2172
|
syncEngineUi();
|
|
2155
2173
|
$('#ttsEngine').addEventListener('change', syncEngineUi);
|
|
2174
|
+
|
|
2175
|
+
/* STT durum satırı: yenile + şimdi indir (yüklenirken 3 sn'de bir güncellenir) */
|
|
2176
|
+
const refreshSttStatus = async () => {
|
|
2177
|
+
try {
|
|
2178
|
+
stt = await beast.sttStatus();
|
|
2179
|
+
const el = $('#sttStatusTxt');
|
|
2180
|
+
if (el && stt) el.textContent = stt.engineLabel + ' · ' + (stateText[stt.state] || stt.state) + (stt.mb ? ' · ' + stt.mb + ' MB' : '');
|
|
2181
|
+
return stt;
|
|
2182
|
+
} catch { return null; }
|
|
2183
|
+
};
|
|
2184
|
+
$('#sttDlBtn').addEventListener('click', async () => {
|
|
2185
|
+
await beast.sttPrefetchNow().catch(() => {});
|
|
2186
|
+
toast('STT modeli indiriliyor/yükleniyor…');
|
|
2187
|
+
const poll = setInterval(async () => {
|
|
2188
|
+
const s = await refreshSttStatus();
|
|
2189
|
+
if (s && (s.state === 'ready' || s.state === 'cloud')) { clearInterval(poll); toast('STT hazır'); }
|
|
2190
|
+
}, 3000);
|
|
2191
|
+
});
|
|
2156
2192
|
$('#ttsSave').addEventListener('click', async () => {
|
|
2157
2193
|
await beast.waSetTts({
|
|
2158
2194
|
enabled: $('#ttsOn').checked,
|