beast-agent 2.3.3 → 2.4.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/package.json +1 -1
- package/src/agent/mem0.js +6 -1
- package/src/agent/perception.js +447 -0
- package/src/agent/progressbus.js +41 -0
- package/src/agent/tools.js +10 -3
- package/src/agent/whatsapp.js +97 -2
- package/src/main.js +287 -6
- package/src/preload.js +4 -0
- package/src/renderer/i18n.js +68 -0
- package/src/renderer/index.html +2 -0
- package/src/renderer/renderer.js +176 -1
package/src/main.js
CHANGED
|
@@ -655,11 +655,16 @@ async function ensureStt() {
|
|
|
655
655
|
hf.env.cacheDir = modelsDir;
|
|
656
656
|
hf.env.allowLocalModels = false;
|
|
657
657
|
let lastErr = null;
|
|
658
|
+
const bus = require('./agent/progressbus');
|
|
658
659
|
for (const dtype of ['q4f16', 'q4', 'q8']) {
|
|
659
660
|
try {
|
|
660
|
-
const p = await hf.pipeline('automatic-speech-recognition', wanted, {
|
|
661
|
+
const p = await hf.pipeline('automatic-speech-recognition', wanted, {
|
|
662
|
+
dtype,
|
|
663
|
+
progress_callback: bus.fileProgressAggregator('stt'),
|
|
664
|
+
});
|
|
661
665
|
sttPipeline = p;
|
|
662
666
|
sttModel = wanted;
|
|
667
|
+
bus.emitInstallProgress('stt', { pct: 100 });
|
|
663
668
|
waLog('STT hazır: ' + wanted + ' (dtype ' + dtype + ')');
|
|
664
669
|
return sttPipeline;
|
|
665
670
|
} catch (e) {
|
|
@@ -676,6 +681,37 @@ async function ensureStt() {
|
|
|
676
681
|
return sttLoading;
|
|
677
682
|
}
|
|
678
683
|
|
|
684
|
+
/* ---------- Kurulum yüzde göstergesi: agent modüllerinden gelen progress
|
|
685
|
+
renderer'a 'install-progress' event'i olarak akıtılır (throttle'lı);
|
|
686
|
+
installPctState'i install:status da okur (sekme sonradan açılırsa ilk
|
|
687
|
+
çizimde yüzde zaten dolu gelir). ---------- */
|
|
688
|
+
const installPctState = {}; // id -> { pct, loaded, total, ts }
|
|
689
|
+
{
|
|
690
|
+
const bus = require('./agent/progressbus');
|
|
691
|
+
const lastSent = new Map(); // id -> { t, pct }
|
|
692
|
+
bus.onInstallProgress((id, d) => {
|
|
693
|
+
try {
|
|
694
|
+
if (!id || !d || typeof d.pct !== 'number' || !isFinite(d.pct)) return;
|
|
695
|
+
const cur = {
|
|
696
|
+
pct: Math.max(0, Math.min(100, Math.round(d.pct))),
|
|
697
|
+
loaded: d.loaded || 0,
|
|
698
|
+
total: d.total || 0,
|
|
699
|
+
ts: Date.now(),
|
|
700
|
+
};
|
|
701
|
+
installPctState[id] = cur;
|
|
702
|
+
const now = Date.now();
|
|
703
|
+
const prev = lastSent.get(id) || { t: 0, pct: -1 };
|
|
704
|
+
/* aynı yüzde tekrarını ve <500ms'lik küçük sıçramaları yut (event fırtınası olmasın) */
|
|
705
|
+
if (cur.pct === prev.pct && now - prev.t < 3000) return;
|
|
706
|
+
if (now - prev.t < 500 && Math.abs(cur.pct - prev.pct) < 2) return;
|
|
707
|
+
lastSent.set(id, { t: now, pct: cur.pct });
|
|
708
|
+
if (win && !win.isDestroyed()) {
|
|
709
|
+
win.webContents.send('agent:event', { type: 'install-progress', id, pct: cur.pct, loaded: cur.loaded, total: cur.total });
|
|
710
|
+
}
|
|
711
|
+
} catch {}
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
|
|
679
715
|
/* ogg/opus/mp3 → mono 16kHz Float32 PCM (ffmpeg ile) */
|
|
680
716
|
function decodeAudioToPcm16k(buf) {
|
|
681
717
|
return new Promise((resolve, reject) => {
|
|
@@ -3220,6 +3256,7 @@ app.whenReady().then(() => {
|
|
|
3220
3256
|
createTray();
|
|
3221
3257
|
cron.init({ onFire: cronFire });
|
|
3222
3258
|
watchers.start({ onTrigger: watcherFire });
|
|
3259
|
+
empatiKickoff(); // empati loop: açılış + 90 sn sonra ilk tarama, sonra cfg aralığı
|
|
3223
3260
|
startEventBus();
|
|
3224
3261
|
ideWatchStart(); // soldaki dosya ağacı canlı izlemede
|
|
3225
3262
|
studioWatchStart(); // Beast Studio klasörü canlı izlemede
|
|
@@ -3918,7 +3955,18 @@ async function ocrRead({ image, lang = 'tur+eng' } = {}) {
|
|
|
3918
3955
|
if (!worker) {
|
|
3919
3956
|
const tessDir = path.join(APP_DIR, 'tessdata');
|
|
3920
3957
|
fs.mkdirSync(tessDir, { recursive: true });
|
|
3921
|
-
|
|
3958
|
+
const bus = require('./agent/progressbus');
|
|
3959
|
+
worker = await t.createWorker(langKey, 1, {
|
|
3960
|
+
cachePath: tessDir,
|
|
3961
|
+
logger: (m) => {
|
|
3962
|
+
try {
|
|
3963
|
+
/* dil verisi (.traineddata) inerken yüzde üret — OCR çalışma anını kirletme */
|
|
3964
|
+
if (m && /traineddata/i.test(String(m.status || '')) && typeof m.progress === 'number' && isFinite(m.progress)) {
|
|
3965
|
+
bus.emitInstallProgress('ocr', { pct: m.progress * 100 });
|
|
3966
|
+
}
|
|
3967
|
+
} catch {}
|
|
3968
|
+
},
|
|
3969
|
+
});
|
|
3922
3970
|
_ocrWorkers.set(langKey, worker);
|
|
3923
3971
|
}
|
|
3924
3972
|
let input = image;
|
|
@@ -5839,6 +5887,20 @@ ipcMain.handle('stt:prefetch', () => {
|
|
|
5839
5887
|
ipcMain.handle('install:status', async () => {
|
|
5840
5888
|
const rows = [];
|
|
5841
5889
|
const pkgOk = (id) => { try { require.resolve(id); return true; } catch { return false; } };
|
|
5890
|
+
/* progress bus'tan canlı yüzde (10 dk taze ise güvenilir sayılır) */
|
|
5891
|
+
const pctOf = (id) => {
|
|
5892
|
+
const s = installPctState[id];
|
|
5893
|
+
return s && Date.now() - s.ts < 10 * 60 * 1000 ? s : null;
|
|
5894
|
+
};
|
|
5895
|
+
const pctFields = (id) => {
|
|
5896
|
+
const s = pctOf(id);
|
|
5897
|
+
if (!s) return {};
|
|
5898
|
+
return {
|
|
5899
|
+
pct: s.pct,
|
|
5900
|
+
loadedMb: s.loaded ? Math.round(s.loaded / 1048576) : undefined,
|
|
5901
|
+
totalMb: s.total ? Math.round(s.total / 1048576) : undefined,
|
|
5902
|
+
};
|
|
5903
|
+
};
|
|
5842
5904
|
const scanModel = (rel) => {
|
|
5843
5905
|
const dir = path.join(APP_DIR, 'models', ...rel.split('/'));
|
|
5844
5906
|
let files = [];
|
|
@@ -5870,14 +5932,28 @@ ipcMain.handle('install:status', async () => {
|
|
|
5870
5932
|
else if (s.hasCfg && s.onnx >= 2 && s.tmp === 0) state = 'downloaded';
|
|
5871
5933
|
else if (s.files.length) state = 'partial';
|
|
5872
5934
|
else state = 'missing';
|
|
5873
|
-
rows.push({
|
|
5935
|
+
rows.push({
|
|
5936
|
+
id: 'stt',
|
|
5937
|
+
name: 'STT modeli — whisper-large-v3-turbo',
|
|
5938
|
+
state,
|
|
5939
|
+
detail: sttEngineLabel(),
|
|
5940
|
+
mb: Math.round(s.bytes / 1048576),
|
|
5941
|
+
...(['missing', 'partial', 'loading'].includes(state) ? pctFields('stt') : {}),
|
|
5942
|
+
});
|
|
5874
5943
|
}
|
|
5875
5944
|
|
|
5876
5945
|
/* 2) Embedding modeli (hafıza semantik arama) */
|
|
5877
5946
|
{
|
|
5878
5947
|
const s = scanModel('Xenova/all-MiniLM-L6-v2');
|
|
5879
5948
|
const state = s.hasCfg && s.onnx >= 1 && s.tmp === 0 ? 'ok' : (s.files.length ? 'partial' : 'missing');
|
|
5880
|
-
rows.push({
|
|
5949
|
+
rows.push({
|
|
5950
|
+
id: 'emb',
|
|
5951
|
+
name: 'Embedding modeli — all-MiniLM-L6-v2',
|
|
5952
|
+
state,
|
|
5953
|
+
detail: 'hafıza semantik arama',
|
|
5954
|
+
mb: Math.round(s.bytes / 1048576),
|
|
5955
|
+
...(['missing', 'partial', 'loading'].includes(state) ? pctFields('emb') : {}),
|
|
5956
|
+
});
|
|
5881
5957
|
}
|
|
5882
5958
|
|
|
5883
5959
|
/* 3) ffmpeg */
|
|
@@ -5890,7 +5966,17 @@ ipcMain.handle('install:status', async () => {
|
|
|
5890
5966
|
rows.push({ id: 'ort', name: 'ONNX Runtime — model motoru', state: pkgOk('onnxruntime-node') ? 'ok' : 'missing', detail: 'npm paketi' });
|
|
5891
5967
|
|
|
5892
5968
|
/* 5) OCR */
|
|
5893
|
-
|
|
5969
|
+
{
|
|
5970
|
+
const po = pctOf('ocr');
|
|
5971
|
+
const dl = pkgOk('tesseract.js') && po && po.pct < 100; // dil verisi şu an iniyor
|
|
5972
|
+
rows.push({
|
|
5973
|
+
id: 'ocr',
|
|
5974
|
+
name: 'OCR — Tesseract (ekran okuma)',
|
|
5975
|
+
state: dl ? 'loading' : (pkgOk('tesseract.js') ? 'ok' : 'missing'),
|
|
5976
|
+
detail: dl ? 'dil verisi iniyor — ilk OCR kullanımında' : (pkgOk('tesseract.js') ? 'kurulu — dil verisi ilk kullanımda iner' : 'npm paketi eksik'),
|
|
5977
|
+
...(dl ? pctFields('ocr') : {}),
|
|
5978
|
+
});
|
|
5979
|
+
}
|
|
5894
5980
|
|
|
5895
5981
|
/* 6) Python (opsiyonel — betikler) */
|
|
5896
5982
|
let pyVer = '';
|
|
@@ -5900,7 +5986,15 @@ ipcMain.handle('install:status', async () => {
|
|
|
5900
5986
|
if (pyVer) break;
|
|
5901
5987
|
} catch {}
|
|
5902
5988
|
}
|
|
5903
|
-
|
|
5989
|
+
if (!pyVer) {
|
|
5990
|
+
const ps = pctOf('python');
|
|
5991
|
+
if (ps && ps.pct < 100) { // gömülü python zip'i şu an iniyor
|
|
5992
|
+
rows.push({ id: 'python', name: 'Python — betikler / web arama', state: 'loading', detail: 'gömülü python indiriliyor', ...pctFields('python') });
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
if (pyVer || !rows.some((r) => r.id === 'python')) {
|
|
5996
|
+
rows.push({ id: 'python', name: 'Python — betikler / web arama', state: pyVer ? 'ok' : 'optional', detail: pyVer ? 'v' + pyVer : 'sistemde bulunamadı — opsiyonel' });
|
|
5997
|
+
}
|
|
5904
5998
|
|
|
5905
5999
|
/* 7) Edge TTS (bulut) */
|
|
5906
6000
|
rows.push({ id: 'edge', name: 'Edge TTS — seslendirme', state: 'cloud', detail: 'bulut — kurulum gerekmez' });
|
|
@@ -6094,6 +6188,193 @@ function watcherFire(w, value) {
|
|
|
6094
6188
|
} catch {}
|
|
6095
6189
|
}
|
|
6096
6190
|
|
|
6191
|
+
/* ---------- EMPATİ LOOP: proaktif algı/event alt sistemi ----------
|
|
6192
|
+
Ana sohbet motorundan bağımsız: sinyal topla → ucuz filtre modeliyle puanla →
|
|
6193
|
+
kompozit öncelik → değerliyse ANA modelle kısa proaktif mesaj üret →
|
|
6194
|
+
masaüstü + WA'ya bildir. Önemsiz olaylar yalnız depoya yazılır, rahatsız etmez. */
|
|
6195
|
+
|
|
6196
|
+
const empati = require('./agent/perception');
|
|
6197
|
+
const empatiRuntime = { running: false, timer: null };
|
|
6198
|
+
|
|
6199
|
+
function empatiCfg() {
|
|
6200
|
+
return empati.mergeCfg(settings.empati || {});
|
|
6201
|
+
}
|
|
6202
|
+
|
|
6203
|
+
function empatiLog(line) {
|
|
6204
|
+
try { waLog('[EMPATİ] ' + line); } catch {}
|
|
6205
|
+
}
|
|
6206
|
+
|
|
6207
|
+
/* tarama (filtre) modeli: sekmeden seçilmişse onu çöz; seçilmemişse ANA model */
|
|
6208
|
+
function empatiFilterSel() {
|
|
6209
|
+
const fm = empatiCfg().filterModel;
|
|
6210
|
+
if (fm) {
|
|
6211
|
+
try {
|
|
6212
|
+
const r = engine._resolve(fm);
|
|
6213
|
+
if (r) return r;
|
|
6214
|
+
} catch {}
|
|
6215
|
+
}
|
|
6216
|
+
return engine.sel;
|
|
6217
|
+
}
|
|
6218
|
+
|
|
6219
|
+
/* sinyal toplayıcılar — perception modülü saf kalır, engine/köprülerle burada konuşur */
|
|
6220
|
+
async function empatiSignalSelf() {
|
|
6221
|
+
const out = [];
|
|
6222
|
+
try {
|
|
6223
|
+
const w = engine.lastWhereWasI();
|
|
6224
|
+
if (w && w.pendingTodos && w.pendingTodos.length) {
|
|
6225
|
+
out.push({
|
|
6226
|
+
type: 'todo',
|
|
6227
|
+
title: 'Yarım kalan görevler: ' + w.pendingTodos.map((t) => t.title).join(' · ').slice(0, 200),
|
|
6228
|
+
detail: 'oturum ' + (w.code || '') + ' · ' + w.pendingTodos.length + ' görev bekliyor',
|
|
6229
|
+
});
|
|
6230
|
+
}
|
|
6231
|
+
} catch {}
|
|
6232
|
+
return out;
|
|
6233
|
+
}
|
|
6234
|
+
|
|
6235
|
+
async function empatiSignalNews() {
|
|
6236
|
+
const topics = String(empatiCfg().newsTopics || '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
6237
|
+
if (!topics.length) return [];
|
|
6238
|
+
return empati.fetchNews(topics);
|
|
6239
|
+
}
|
|
6240
|
+
|
|
6241
|
+
/* tek toplu filtre çağrısı (maliyet freni); model yok/çökerse boş → deterministik puan */
|
|
6242
|
+
function empatiLlmFilter(prompt) {
|
|
6243
|
+
const sel = empatiFilterSel();
|
|
6244
|
+
if (!sel) return Promise.resolve('');
|
|
6245
|
+
const ctrl = new AbortController();
|
|
6246
|
+
const kill = setTimeout(() => ctrl.abort(), 45000);
|
|
6247
|
+
return require('./agent/llm')
|
|
6248
|
+
.chatOnce(sel, {
|
|
6249
|
+
messages: [
|
|
6250
|
+
{ role: 'system', content: empati.FILTER_SYSTEM },
|
|
6251
|
+
{ role: 'user', content: prompt },
|
|
6252
|
+
],
|
|
6253
|
+
temperature: 0.1,
|
|
6254
|
+
}, { signal: ctrl.signal })
|
|
6255
|
+
.then((r) => String(r.content || ''))
|
|
6256
|
+
.catch(() => '')
|
|
6257
|
+
.finally(() => clearTimeout(kill));
|
|
6258
|
+
}
|
|
6259
|
+
|
|
6260
|
+
/* compose her zaman ANA model kullanır — filtre ucuz, anlamlandırma güçlü */
|
|
6261
|
+
function empatiLlmCompose(prompt) {
|
|
6262
|
+
if (!engine.sel) return Promise.resolve('');
|
|
6263
|
+
const ctrl = new AbortController();
|
|
6264
|
+
const kill = setTimeout(() => ctrl.abort(), 60000);
|
|
6265
|
+
return require('./agent/llm')
|
|
6266
|
+
.chatOnce(engine.sel, {
|
|
6267
|
+
messages: [
|
|
6268
|
+
{ role: 'system', content: empati.COMPOSE_SYSTEM },
|
|
6269
|
+
{ role: 'user', content: prompt },
|
|
6270
|
+
],
|
|
6271
|
+
temperature: 0.6,
|
|
6272
|
+
}, { signal: ctrl.signal })
|
|
6273
|
+
.then((r) => String(r.content || '').trim().slice(0, 600))
|
|
6274
|
+
.catch(() => '')
|
|
6275
|
+
.finally(() => clearTimeout(kill));
|
|
6276
|
+
}
|
|
6277
|
+
|
|
6278
|
+
/* bildirim hedefi: sekmeden seçilen entegrasyon; seçilmemişse bağlı olanlar.
|
|
6279
|
+
Hiçbir entegrasyon yazılamazsa masaüstü chat UI (toast) kalır. */
|
|
6280
|
+
function empatiNotify(text, ev) {
|
|
6281
|
+
const cfg = empatiCfg();
|
|
6282
|
+
const senders = [];
|
|
6283
|
+
const tryWa = () => {
|
|
6284
|
+
try {
|
|
6285
|
+
const own = waOwnerNum();
|
|
6286
|
+
if (own && wa && wa.connected) senders.push(() => sendWaSafe(own + '@s.whatsapp.net', '🫡 *Beast proaktif:*\n' + text));
|
|
6287
|
+
} catch {}
|
|
6288
|
+
};
|
|
6289
|
+
const tryTg = () => {
|
|
6290
|
+
try {
|
|
6291
|
+
if (tg && tg.connected) for (const id of tgOwnerIds()) senders.push(() => sendTgSafe(id, '🫡 *Beast proaktif:*\n' + text));
|
|
6292
|
+
} catch {}
|
|
6293
|
+
};
|
|
6294
|
+
const tryDc = () => {
|
|
6295
|
+
try {
|
|
6296
|
+
if (dc && dc.connected) for (const id of dcOwnerIds()) senders.push(() => sendDcSafe(id, '🫡 **Beast proaktif:**\n' + text));
|
|
6297
|
+
} catch {}
|
|
6298
|
+
};
|
|
6299
|
+
if (cfg.notifyTarget === 'whatsapp') tryWa();
|
|
6300
|
+
else if (cfg.notifyTarget === 'telegram') tryTg();
|
|
6301
|
+
else if (cfg.notifyTarget === 'discord') tryDc();
|
|
6302
|
+
else { tryWa(); tryTg(); tryDc(); } // auto: ekli/bağlı entegrasyonlar
|
|
6303
|
+
let sent = 0;
|
|
6304
|
+
for (const fn of senders) {
|
|
6305
|
+
try { fn(); sent++; } catch {}
|
|
6306
|
+
}
|
|
6307
|
+
/* hiçbir entegrasyona yazılamadıysa yalnız masaüstü chat UI'a düş */
|
|
6308
|
+
try {
|
|
6309
|
+
if (!sent && win && !win.isDestroyed()) {
|
|
6310
|
+
win.webContents.send('agent:event', { type: 'proactive', id: ev.id, level: ev.level, title: ev.title, text });
|
|
6311
|
+
}
|
|
6312
|
+
} catch {}
|
|
6313
|
+
}
|
|
6314
|
+
|
|
6315
|
+
async function empatiCycle(manual) {
|
|
6316
|
+
if (empatiRuntime.running) return { ok: false, error: 'döngü zaten çalışıyor' };
|
|
6317
|
+
const cfg = empatiCfg();
|
|
6318
|
+
if (!cfg.enabled && !manual) return { ok: false, error: 'kapalı' };
|
|
6319
|
+
empatiRuntime.running = true;
|
|
6320
|
+
try {
|
|
6321
|
+
const r = await empati.runCycle({
|
|
6322
|
+
cfg,
|
|
6323
|
+
signals: { self: empatiSignalSelf, news: empatiSignalNews },
|
|
6324
|
+
llmFilter: empatiLlmFilter,
|
|
6325
|
+
now: new Date(),
|
|
6326
|
+
log: empatiLog,
|
|
6327
|
+
});
|
|
6328
|
+
let notified = 0;
|
|
6329
|
+
for (const a of r.actions) {
|
|
6330
|
+
let text = '';
|
|
6331
|
+
try { text = await empatiLlmCompose(empati.composePrompt(a.event, cfg)); } catch {}
|
|
6332
|
+
if (!text) text = empati.composeFallback(a.event);
|
|
6333
|
+
empatiNotify(text, a.event);
|
|
6334
|
+
empati.markNotified(a.event.id, a.level, text, cfg.cooldownMin);
|
|
6335
|
+
notified++;
|
|
6336
|
+
}
|
|
6337
|
+
if (notified && win && !win.isDestroyed()) {
|
|
6338
|
+
win.webContents.send('agent:event', { type: 'empati', notified });
|
|
6339
|
+
}
|
|
6340
|
+
return { ok: true, ...r.summary, notified };
|
|
6341
|
+
} finally {
|
|
6342
|
+
empatiRuntime.running = false;
|
|
6343
|
+
}
|
|
6344
|
+
}
|
|
6345
|
+
|
|
6346
|
+
function empatiSchedule() {
|
|
6347
|
+
if (empatiRuntime.timer) clearTimeout(empatiRuntime.timer);
|
|
6348
|
+
empatiRuntime.timer = null;
|
|
6349
|
+
const cfg = empatiCfg();
|
|
6350
|
+
if (!cfg.enabled) return;
|
|
6351
|
+
empatiRuntime.timer = setTimeout(async () => {
|
|
6352
|
+
try { await empatiCycle(false); } catch {}
|
|
6353
|
+
empatiSchedule();
|
|
6354
|
+
}, cfg.intervalMin * 60000);
|
|
6355
|
+
}
|
|
6356
|
+
|
|
6357
|
+
/* açılış + 90 sn: ilk tarama (başlangıç fırtınasını önle), sonra cfg aralığı */
|
|
6358
|
+
function empatiKickoff() {
|
|
6359
|
+
setTimeout(() => {
|
|
6360
|
+
empatiCycle(false).catch(() => {});
|
|
6361
|
+
empatiSchedule();
|
|
6362
|
+
}, 90 * 1000);
|
|
6363
|
+
}
|
|
6364
|
+
|
|
6365
|
+
ipcMain.handle('empati:get', () => ({ ...empatiCfg(), running: empatiRuntime.running, lastRunAt: empati.lastRunAt() }));
|
|
6366
|
+
ipcMain.handle('empati:set', (_e, patch) => {
|
|
6367
|
+
const cfg = empati.mergeCfg({ ...empatiCfg(), ...(patch || {}) });
|
|
6368
|
+
settings.empati = cfg;
|
|
6369
|
+
saveSettings();
|
|
6370
|
+
empatiSchedule(); // aralık/model değişmiş olabilir
|
|
6371
|
+
return { ...cfg };
|
|
6372
|
+
});
|
|
6373
|
+
ipcMain.handle('empati:scan', async () => {
|
|
6374
|
+
try { return await empatiCycle(true); } catch (e) { return { ok: false, error: String((e && e.message) || e).slice(0, 200) }; }
|
|
6375
|
+
});
|
|
6376
|
+
ipcMain.handle('empati:events', () => empati.listEvents(80));
|
|
6377
|
+
|
|
6097
6378
|
ipcMain.handle('cron:list', () => cron.list());
|
|
6098
6379
|
/* #23 Fallout: provider → kayıtlı API key haritası.
|
|
6099
6380
|
Birincil kaynak: engine chain (config+custom+env çözülmüş).
|
package/src/preload.js
CHANGED
|
@@ -207,4 +207,8 @@ contextBridge.exposeInMainWorld('beast', {
|
|
|
207
207
|
ideDelete: (rel) => ipcRenderer.invoke('ide:delete', rel),
|
|
208
208
|
onWaEvent: (cb) => ipcRenderer.on('wa:event', (_e, ev) => cb(ev)),
|
|
209
209
|
onEvent: (cb) => ipcRenderer.on('agent:event', (_e, ev) => cb(ev)),
|
|
210
|
+
empatiGet: () => ipcRenderer.invoke('empati:get'),
|
|
211
|
+
empatiSet: (patch) => ipcRenderer.invoke('empati:set', patch),
|
|
212
|
+
empatiScan: () => ipcRenderer.invoke('empati:scan'),
|
|
213
|
+
empatiEvents: () => ipcRenderer.invoke('empati:events'),
|
|
210
214
|
});
|
package/src/renderer/i18n.js
CHANGED
|
@@ -114,6 +114,40 @@
|
|
|
114
114
|
up_install_now: 'Yeniden Başlat & Kur',
|
|
115
115
|
up_note: 'Kurulumdan sonra uygulama otomatik yeniden başlar. İstersen WhatsApp\u2019tan /update komutunu da kullanabilirsin.',
|
|
116
116
|
tab_events: 'Olay Merkezi',
|
|
117
|
+
tab_empati: 'Empati Loop',
|
|
118
|
+
em_h2: 'Empati Loop — Proaktif Algı',
|
|
119
|
+
em_sub: 'Beast arka planda periyodik tarar: yarım kalan işler, haber akışı. Boru hattı: sinyal → ucuz filtre modeli → öncelik puanı → bildirim. Önemsiz olaylar yalnız depoya yazılır, seni rahatsız etmez.',
|
|
120
|
+
em_ipc_err: 'Empati servisine ulaşılamadı.',
|
|
121
|
+
em_on: 'Empati Loop açık',
|
|
122
|
+
em_interval: 'Tarama aralığı (dk)',
|
|
123
|
+
em_min_notify: 'Bildirim eşiği (puan)',
|
|
124
|
+
em_cooldown: 'Konu sessizliği (dk)',
|
|
125
|
+
em_model: 'Tarama (filtre) modeli',
|
|
126
|
+
em_model_main: 'Ana model (seçili)',
|
|
127
|
+
em_model_sub: 'Seçmezsen tarama ana modelle yapılır. Anlamlandırma (mesaj yazımı) her zaman ana modelle.',
|
|
128
|
+
em_notify: 'Bildirim hedefi',
|
|
129
|
+
em_notify_auto: 'Otomatik — bağlı entegrasyonlar',
|
|
130
|
+
em_notify_wa: 'WhatsApp',
|
|
131
|
+
em_notify_tg: 'Telegram',
|
|
132
|
+
em_notify_dc: 'Discord',
|
|
133
|
+
em_notify_sub: 'Seçmezsen ekli ve bağlı entegrasyonların hepsine yazar; hiçbiri bağlı değilse masaüstü sohbete düşer.',
|
|
134
|
+
em_interests: 'İlgi alanların — haber filtresi buna göre ağırlıklandırılır',
|
|
135
|
+
em_interests_ph: 'örn: yapay zeka, yazılım, trading, open source',
|
|
136
|
+
em_news: 'Haber kaynağı (Google News)',
|
|
137
|
+
em_news_topics_ph: 'haber konuları, virgülle: yapay zeka, ekonomi…',
|
|
138
|
+
em_scan: 'Şimdi Tara',
|
|
139
|
+
em_scan_ok: 'Tarama: {raw} sinyal · {queued} bildirim · {stored} depo',
|
|
140
|
+
em_events: 'Son olaylar',
|
|
141
|
+
em_no_events: 'Henüz olay yok — Şimdi Tara ile deneyebilirsin.',
|
|
142
|
+
em_saved: 'Empati ayarları kaydedildi',
|
|
143
|
+
em_lastrun: 'Son tarama',
|
|
144
|
+
em_note: 'İzleyiciler (watchers) kendi bildirimlerini zaten yapıyor; Empati Loop onları tekrar bildirmez. Filtre modeli tek toplu çağrıyla çalışır; model yoksa puanlama deterministik yapılır.',
|
|
145
|
+
em_st_notified: 'bildirildi',
|
|
146
|
+
em_st_queued: 'kuyrukta',
|
|
147
|
+
em_st_stored: 'depo',
|
|
148
|
+
em_st_ignored: 'yok sayıldı',
|
|
149
|
+
em_lv_high: 'YÜKSEK',
|
|
150
|
+
em_lv_medium: 'ORTA',
|
|
117
151
|
tab_cron: 'Cron',
|
|
118
152
|
tab_usage: 'Maliyet · Limit',
|
|
119
153
|
tab_logs: 'Log',
|
|
@@ -691,6 +725,40 @@
|
|
|
691
725
|
up_install_now: 'Restart & Install',
|
|
692
726
|
up_note: 'The app restarts itself after installing. You can also use the /update command from WhatsApp.',
|
|
693
727
|
tab_events: 'Event Center',
|
|
728
|
+
tab_empati: 'Empathy Loop',
|
|
729
|
+
em_h2: 'Empathy Loop — Proactive Perception',
|
|
730
|
+
em_sub: 'Beast scans periodically in the background: half-done work, news flow. Pipeline: signal → cheap filter model → priority score → notification. Unimportant events are only stored, they never bother you.',
|
|
731
|
+
em_ipc_err: 'Could not reach the empathy service.',
|
|
732
|
+
em_on: 'Empathy Loop enabled',
|
|
733
|
+
em_interval: 'Scan interval (min)',
|
|
734
|
+
em_min_notify: 'Notify threshold (score)',
|
|
735
|
+
em_cooldown: 'Topic silence (min)',
|
|
736
|
+
em_model: 'Scan (filter) model',
|
|
737
|
+
em_model_main: 'Main model (selected)',
|
|
738
|
+
em_model_sub: 'If left empty, scanning uses the main model. Composing the message always uses the main model.',
|
|
739
|
+
em_notify: 'Notification target',
|
|
740
|
+
em_notify_auto: 'Auto — connected integrations',
|
|
741
|
+
em_notify_wa: 'WhatsApp',
|
|
742
|
+
em_notify_tg: 'Telegram',
|
|
743
|
+
em_notify_dc: 'Discord',
|
|
744
|
+
em_notify_sub: 'If left empty, it writes to all connected integrations; with none connected it lands in the desktop chat.',
|
|
745
|
+
em_interests: 'Your interests — news filtering is weighted by these',
|
|
746
|
+
em_interests_ph: 'e.g. AI, software, trading, open source',
|
|
747
|
+
em_news: 'News source (Google News)',
|
|
748
|
+
em_news_topics_ph: 'news topics, comma separated: AI, economy…',
|
|
749
|
+
em_scan: 'Scan Now',
|
|
750
|
+
em_scan_ok: 'Scan: {raw} signals · {queued} notify · {stored} stored',
|
|
751
|
+
em_events: 'Recent events',
|
|
752
|
+
em_no_events: 'No events yet — try Scan Now.',
|
|
753
|
+
em_saved: 'Empathy settings saved',
|
|
754
|
+
em_lastrun: 'Last scan',
|
|
755
|
+
em_note: 'Watchers already notify on their own; the Empathy Loop does not repeat them. The filter model runs in a single batched call; without a model, scoring is deterministic.',
|
|
756
|
+
em_st_notified: 'notified',
|
|
757
|
+
em_st_queued: 'queued',
|
|
758
|
+
em_st_stored: 'stored',
|
|
759
|
+
em_st_ignored: 'ignored',
|
|
760
|
+
em_lv_high: 'HIGH',
|
|
761
|
+
em_lv_medium: 'MEDIUM',
|
|
694
762
|
tab_cron: 'Cron',
|
|
695
763
|
tab_usage: 'Cost · Limit',
|
|
696
764
|
tab_logs: 'Logs',
|
package/src/renderer/index.html
CHANGED
|
@@ -239,6 +239,7 @@
|
|
|
239
239
|
<button class="tab" data-tab="websearch" data-i18n="tab_websearch">Web Arama</button>
|
|
240
240
|
<button class="tab" data-tab="mcp" data-i18n="tab_mcp">MCP</button>
|
|
241
241
|
<button class="tab" data-tab="events" data-i18n="tab_events">Olay Merkezi</button>
|
|
242
|
+
<button class="tab" data-tab="empati" data-i18n="tab_empati">Empati Loop</button>
|
|
242
243
|
<button class="tab" data-tab="cron" data-i18n="tab_cron">Cron</button>
|
|
243
244
|
<button class="tab" data-tab="usage" data-i18n="tab_usage">Maliyet · Limit</button>
|
|
244
245
|
<button class="tab" data-tab="logs" data-i18n="tab_logs">Log</button>
|
|
@@ -264,6 +265,7 @@
|
|
|
264
265
|
<div id="tab-websearch" class="pane" hidden></div>
|
|
265
266
|
<div id="tab-mcp" class="pane" hidden></div>
|
|
266
267
|
<div id="tab-events" class="pane" hidden></div>
|
|
268
|
+
<div id="tab-empati" class="pane" hidden></div>
|
|
267
269
|
<div id="tab-usage" class="pane" hidden></div>
|
|
268
270
|
<div id="tab-logs" class="pane" hidden></div>
|
|
269
271
|
<div id="tab-dash" class="pane" hidden></div>
|