beast-agent 2.76.5 → 2.77.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.
Files changed (54) hide show
  1. package/package.json +1 -1
  2. package/src/agent/bots.js +669 -664
  3. package/src/agent/customtools.js +6 -19
  4. package/src/agent/engine.js +55 -307
  5. package/src/agent/seeds/tool-yazma/SKILL.md +13 -16
  6. package/src/agent/skills.js +14 -35
  7. package/src/agent/supertonic.js +622 -0
  8. package/src/agent/tools.js +3 -7
  9. package/src/main.js +77 -6068
  10. package/src/preload.js +2 -17
  11. package/src/renderer/i18n.js +14 -8
  12. package/src/renderer/index.html +0 -297
  13. package/src/renderer/renderer.js +142 -2280
  14. package/src/renderer/style.css +3 -825
  15. package/src/agent/defaulttools/mt5_barlar2/run.js +0 -188
  16. package/src/agent/defaulttools/mt5_barlar2/tool.json +0 -23
  17. package/src/agent/defaulttools/mt5_bekleyen/run.js +0 -105
  18. package/src/agent/defaulttools/mt5_bekleyen/tool.json +0 -18
  19. package/src/agent/defaulttools/mt5_durum/run.js +0 -93
  20. package/src/agent/defaulttools/mt5_durum/tool.json +0 -10
  21. package/src/agent/defaulttools/mt5_emir/run.js +0 -98
  22. package/src/agent/defaulttools/mt5_emir/tool.json +0 -17
  23. package/src/agent/defaulttools/mt5_emir_iptal/run.js +0 -90
  24. package/src/agent/defaulttools/mt5_emir_iptal/tool.json +0 -12
  25. package/src/agent/defaulttools/mt5_fiyat/run.js +0 -87
  26. package/src/agent/defaulttools/mt5_fiyat/tool.json +0 -16
  27. package/src/agent/defaulttools/mt5_gecmis/run.js +0 -87
  28. package/src/agent/defaulttools/mt5_gecmis/tool.json +0 -12
  29. package/src/agent/defaulttools/mt5_kapat/run.js +0 -108
  30. package/src/agent/defaulttools/mt5_kapat/tool.json +0 -15
  31. package/src/agent/defaulttools/mt5_m15_m5/m15m5.py +0 -60
  32. package/src/agent/defaulttools/mt5_m15_m5/run.js +0 -73
  33. package/src/agent/defaulttools/mt5_m15_m5/tool.json +0 -10
  34. package/src/agent/defaulttools/mt5_pozisyon_gecmis/run.js +0 -144
  35. package/src/agent/defaulttools/mt5_pozisyon_gecmis/tool.json +0 -12
  36. package/src/agent/defaulttools/mt5_shot/run.js +0 -649
  37. package/src/agent/defaulttools/mt5_shot/stitch.js +0 -151
  38. package/src/agent/defaulttools/mt5_shot/tool.json +0 -25
  39. package/src/agent/defaulttools/mt5_sltp/run.js +0 -92
  40. package/src/agent/defaulttools/mt5_sltp/tool.json +0 -14
  41. package/src/agent/financetools.js +0 -1025
  42. package/src/agent/finindicators.js +0 -254
  43. package/src/agent/finrisk.js +0 -289
  44. package/src/agent/finstats.js +0 -239
  45. package/src/agent/finwatch.js +0 -302
  46. package/src/agent/mt5/BeastFinance.mq5 +0 -498
  47. package/src/agent/mt5/BeastShot.tpl +0 -0
  48. package/src/agent/mt5setup.js +0 -542
  49. package/src/agent/scripts/mt5_bridge.py +0 -575
  50. package/src/agent/seeds/haber-duygu/SKILL.md +0 -49
  51. package/src/agent/seeds/mql5/SKILL.md +0 -154
  52. package/src/agent/seeds/price-action/SKILL.md +0 -60
  53. package/src/agent/seeds/risk-yonetimi/SKILL.md +0 -52
  54. package/src/mt5bridge.js +0 -215
@@ -0,0 +1,622 @@
1
+ 'use strict';
2
+
3
+ /* Beast Supertonic 3 TTS: tamamen YEREL/offline, 31 dil destekli neural
4
+ seslendirme (Supertone/supertonic-3, ONNX Runtime CPU).
5
+ - Model: %APPDATA%\beast\supertonic\onnx (toplam ~400MB, ilk kullanımda
6
+ indirilir; tts.json + unicode_indexer.json + 4 ONNX oturumu).
7
+ - Sesler: M1-M5 (erkek) / F1-F5 (kadın) voice style JSON'ları
8
+ %APPDATA%\beast\supertonic\voice_styles altına iner.
9
+ - Çıktı: 44.1kHz mono 16-bit WAV buffer — WhatsApp sesli not yolu ffmpeg
10
+ ile ogg/opus'a çevirir, masaüstü oynatıcı WAV'ı doğrudan çalar.
11
+ - Oturumlar ilk sentezde yüklenir ve 10 dk boşta kalınca bellekten
12
+ bırakılır; indirmeler kilitli, ilerleme progressbus'a akar.
13
+ - Implementasyon resmi nodejs örneğinin (helper.js) CommonJS portu. */
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const os = require('os');
18
+ const { Readable } = require('stream');
19
+ const { pipeline } = require('stream/promises');
20
+ const { beastRoot } = require('./memory');
21
+ const log = require('./logger');
22
+ const { emitInstallProgress } = require('./progressbus');
23
+
24
+ const HF_BASE = 'https://huggingface.co/Supertone/supertonic-3/resolve/main';
25
+ const DEFAULT_VOICE = 'M1';
26
+ const DEFAULT_LANG = 'tr';
27
+ const DEFAULT_SPEED = 1.05;
28
+ const DEFAULT_STEPS = 8;
29
+ const IDLE_UNLOAD_MS = 10 * 60 * 1000;
30
+
31
+ /* onnx/ klasörü: config + indexer + 4 model (sıra indirme sırası) */
32
+ const MODEL_FILES = [
33
+ 'tts.json',
34
+ 'unicode_indexer.json',
35
+ 'duration_predictor.onnx',
36
+ 'text_encoder.onnx',
37
+ 'vector_estimator.onnx',
38
+ 'vocoder.onnx',
39
+ ];
40
+
41
+ const VOICES = {
42
+ M1: { name: 'M1 — Erkek 1' },
43
+ M2: { name: 'M2 — Erkek 2' },
44
+ M3: { name: 'M3 — Erkek 3' },
45
+ M4: { name: 'M4 — Erkek 4' },
46
+ M5: { name: 'M5 — Erkek 5' },
47
+ F1: { name: 'F1 — Kadın 1' },
48
+ F2: { name: 'F2 — Kadın 2' },
49
+ F3: { name: 'F3 — Kadın 3' },
50
+ F4: { name: 'F4 — Kadın 4' },
51
+ F5: { name: 'F5 — Kadın 5' },
52
+ };
53
+
54
+ /* Desteklenen 31 dil + na (bilinmeyen/dil bağımsız) — UI sıralaması önemli */
55
+ const LANGS = {
56
+ tr: 'Türkçe',
57
+ en: 'English',
58
+ de: 'Deutsch',
59
+ fr: 'Français',
60
+ es: 'Español',
61
+ it: 'Italiano',
62
+ ru: 'Русский',
63
+ ar: 'العربية',
64
+ ja: '日本語',
65
+ ko: '한국어',
66
+ pt: 'Português',
67
+ nl: 'Nederlands',
68
+ pl: 'Polski',
69
+ hi: 'हिन्दी',
70
+ id: 'Bahasa Indonesia',
71
+ vi: 'Tiếng Việt',
72
+ uk: 'Українська',
73
+ bg: 'Bulgarian',
74
+ cs: 'Čeština',
75
+ da: 'Dansk',
76
+ el: 'Ελληνικά',
77
+ et: 'Eesti',
78
+ fi: 'Suomi',
79
+ hr: 'Hrvatski',
80
+ hu: 'Magyar',
81
+ lt: 'Lietuvių',
82
+ lv: 'Latviešu',
83
+ ro: 'Română',
84
+ sk: 'Slovenčina',
85
+ sl: 'Slovenščina',
86
+ sv: 'Svenska',
87
+ na: 'Otomatik (dil bilinmiyor)',
88
+ };
89
+
90
+ /* ---------- yollar ---------- */
91
+
92
+ function rootDir() {
93
+ return path.join(beastRoot(), 'supertonic');
94
+ }
95
+ function onnxDir() {
96
+ return path.join(rootDir(), 'onnx');
97
+ }
98
+ function stylesDir() {
99
+ return path.join(rootDir(), 'voice_styles');
100
+ }
101
+ function modelPath(name) {
102
+ return path.join(onnxDir(), name);
103
+ }
104
+ function stylePath(id) {
105
+ return path.join(stylesDir(), String(id) + '.json');
106
+ }
107
+
108
+ function resolveVoice(id) {
109
+ const v = String(id || '').trim().toUpperCase();
110
+ return VOICES[v] ? v : DEFAULT_VOICE;
111
+ }
112
+ function resolveLang(id) {
113
+ const l = String(id || '').trim().toLowerCase();
114
+ return LANGS[l] ? l : DEFAULT_LANG;
115
+ }
116
+ function clampNum(n, lo, hi) {
117
+ return Math.max(lo, Math.min(hi, n));
118
+ }
119
+
120
+ function bigEnough(p, min) {
121
+ try {
122
+ const st = fs.statSync(p);
123
+ return st.isFile() && st.size >= min;
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+ function modelInstalled() {
129
+ return MODEL_FILES.every((f) => bigEnough(modelPath(f), 1000));
130
+ }
131
+ function voiceInstalled(id) {
132
+ return !!VOICES[id] && bigEnough(stylePath(id), 1000);
133
+ }
134
+
135
+ /* ---------- indirme (yüzde akışlı, .part → atomik rename) ---------- */
136
+
137
+ async function download(url, dest, tag, label) {
138
+ const res = await fetch(url, { redirect: 'follow' });
139
+ if (!res.ok || !res.body) throw new Error('indirilemedi (http ' + res.status + ')');
140
+ const total = Number(res.headers.get('content-length')) || 0;
141
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
142
+ const tmp = dest + '.part';
143
+ let loaded = 0;
144
+ let last = 0;
145
+ const rs = Readable.fromWeb(res.body);
146
+ rs.on('data', (c) => {
147
+ loaded += c.length;
148
+ const now = Date.now();
149
+ if (now - last > 500) {
150
+ last = now;
151
+ emitInstallProgress(tag, {
152
+ pct: total ? Math.round((loaded / total) * 100) : 0,
153
+ loaded,
154
+ total,
155
+ file: label,
156
+ });
157
+ }
158
+ });
159
+ await pipeline(rs, fs.createWriteStream(tmp));
160
+ const st = fs.statSync(tmp);
161
+ if (st.size < 1000) {
162
+ fs.rmSync(tmp, { force: true });
163
+ throw new Error('eksik indirme: ' + label);
164
+ }
165
+ fs.renameSync(tmp, dest);
166
+ emitInstallProgress(tag, { pct: 100, loaded, total: total || loaded, file: label });
167
+ }
168
+
169
+ /* ---------- kurulum (kilitli) ---------- */
170
+
171
+ let modelPromise = null;
172
+ const voicePromises = new Map();
173
+
174
+ function ensureModel() {
175
+ if (modelInstalled()) return Promise.resolve(true);
176
+ if (modelPromise) return modelPromise;
177
+ modelPromise = (async () => {
178
+ log.info('supertonic', 'model indiriliyor (~400MB): ' + HF_BASE);
179
+ for (const f of MODEL_FILES) {
180
+ const dest = modelPath(f);
181
+ if (bigEnough(dest, 1000)) continue;
182
+ emitInstallProgress('supertonic', { pct: 0, file: f });
183
+ await download(HF_BASE + '/onnx/' + f, dest, 'supertonic', f);
184
+ }
185
+ if (!modelInstalled()) throw new Error('supertonic model dosyaları eksik');
186
+ log.info('supertonic', 'model hazır: ' + onnxDir());
187
+ return true;
188
+ })().catch((e) => {
189
+ log.error('supertonic', 'model indirme başarısız: ' + String((e && e.message) || e));
190
+ throw e;
191
+ }).finally(() => {
192
+ modelPromise = null; // kilit çözülür; kuruluysa yukarıdaki kısa yol devrede
193
+ });
194
+ return modelPromise;
195
+ }
196
+
197
+ function ensureVoice(id) {
198
+ const vid = resolveVoice(id);
199
+ if (voiceInstalled(vid)) return Promise.resolve(true);
200
+ if (voicePromises.has(vid)) return voicePromises.get(vid);
201
+ const p = (async () => {
202
+ log.info('supertonic', 'ses stili indiriliyor: ' + vid);
203
+ await download(HF_BASE + '/voice_styles/' + vid + '.json', stylePath(vid), 'supertonic-voice', vid + '.json');
204
+ if (!voiceInstalled(vid)) throw new Error('ses stili indirilemedi: ' + vid);
205
+ log.info('supertonic', 'ses hazır: ' + vid);
206
+ return true;
207
+ })().catch((e) => {
208
+ log.error('supertonic', 'ses indirme başarısız (' + vid + '): ' + String((e && e.message) || e));
209
+ throw e;
210
+ }).finally(() => {
211
+ voicePromises.delete(vid);
212
+ });
213
+ voicePromises.set(vid, p);
214
+ return p;
215
+ }
216
+
217
+ /* UI için durum: { installed, model, voice, voiceId, installing } */
218
+ function status(voiceId) {
219
+ const vid = resolveVoice(voiceId);
220
+ return {
221
+ installed: modelInstalled() && voiceInstalled(vid),
222
+ model: modelInstalled(),
223
+ voice: voiceInstalled(vid),
224
+ voiceId: vid,
225
+ installing: !!modelPromise || voicePromises.has(vid),
226
+ };
227
+ }
228
+
229
+ /* elle/otomatik kurulum: model + ses (hata fırlatmaz, {ok} döner) */
230
+ async function install(voiceId) {
231
+ const vid = resolveVoice(voiceId);
232
+ try {
233
+ await ensureModel();
234
+ await ensureVoice(vid);
235
+ return { ok: true, voice: vid };
236
+ } catch (e) {
237
+ return { ok: false, voice: vid, error: String((e && e.message) || e) };
238
+ }
239
+ }
240
+
241
+ /* ---------- ONNX motoru (lazy yükleme + boşta bellek bırakma) ---------- */
242
+
243
+ let engine = null;
244
+ let enginePromise = null;
245
+ let busy = 0;
246
+ let idleTimer = null;
247
+
248
+ function touchIdle() {
249
+ if (idleTimer) clearTimeout(idleTimer);
250
+ idleTimer = setTimeout(releaseEngine, IDLE_UNLOAD_MS);
251
+ if (idleTimer.unref) idleTimer.unref();
252
+ }
253
+
254
+ function releaseEngine() {
255
+ if (busy > 0 || !engine) {
256
+ if (engine) touchIdle();
257
+ return;
258
+ }
259
+ for (const s of [engine.dp, engine.textEnc, engine.vectorEst, engine.vocoder]) {
260
+ try { s.release(); } catch {}
261
+ }
262
+ engine = null;
263
+ log.info('supertonic', 'model boşta — bellekten bırakıldı');
264
+ }
265
+
266
+ /* onnxruntime-node'un EN YENİ kopyasını seç: kökteki eski sürüm (1.14)
267
+ Windows'ta delay-load hatasıyla süreci çökertebiliyor; @huggingface/
268
+ transformers kendi yeni kopyasını (1.21+) nested taşır. */
269
+ function ortVersion(dir) {
270
+ try {
271
+ return String(JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8')).version || '0');
272
+ } catch {
273
+ return '0';
274
+ }
275
+ }
276
+ function verNum(v) {
277
+ const p = String(v).split('.').map((x) => parseInt(x, 10) || 0);
278
+ return (p[0] || 0) * 1000000 + (p[1] || 0) * 1000 + (p[2] || 0);
279
+ }
280
+ function loadOrt() {
281
+ const candidates = [];
282
+ try {
283
+ let dir = path.dirname(require.resolve('@huggingface/transformers'));
284
+ while (dir && dir !== path.dirname(dir)) {
285
+ if (fs.existsSync(path.join(dir, 'package.json'))) break;
286
+ dir = path.dirname(dir);
287
+ }
288
+ if (dir) candidates.push(path.join(dir, 'node_modules', 'onnxruntime-node'));
289
+ } catch {}
290
+ try {
291
+ candidates.push(path.dirname(require.resolve('onnxruntime-node/package.json')));
292
+ } catch {}
293
+ const found = candidates
294
+ .filter((c) => fs.existsSync(path.join(c, 'package.json')))
295
+ .map((c) => ({ dir: c, v: ortVersion(c) }))
296
+ .sort((a, b) => verNum(b.v) - verNum(a.v));
297
+ for (const c of found) {
298
+ try {
299
+ const m = require(c.dir);
300
+ if (m && typeof m.InferenceSession === 'function') {
301
+ log.info('supertonic', 'onnxruntime-node ' + c.v + ' kullanılıyor');
302
+ return m;
303
+ }
304
+ } catch (e) {
305
+ log.info('supertonic', 'onnxruntime adayı yüklenemedi (' + c.v + '): ' + String((e && e.message) || e));
306
+ }
307
+ }
308
+ return require('onnxruntime-node');
309
+ }
310
+
311
+ async function doLoadEngine() {
312
+ await ensureModel();
313
+ const ort = loadOrt();
314
+ const cfg = JSON.parse(fs.readFileSync(modelPath('tts.json'), 'utf8'));
315
+ const indexer = JSON.parse(fs.readFileSync(modelPath('unicode_indexer.json'), 'utf8'));
316
+ const threads = Math.max(1, Math.min(4, (os.cpus() && os.cpus().length || 2) - 1));
317
+ const opts = { intraOpNumThreads: threads, interOpNumThreads: 1, executionProviders: ['cpu'] };
318
+ log.info('supertonic', 'model yükleniyor (cpu, ' + threads + ' iş parçacığı)…');
319
+ const [dp, textEnc, vectorEst, vocoder] = await Promise.all([
320
+ ort.InferenceSession.create(modelPath('duration_predictor.onnx'), opts),
321
+ ort.InferenceSession.create(modelPath('text_encoder.onnx'), opts),
322
+ ort.InferenceSession.create(modelPath('vector_estimator.onnx'), opts),
323
+ ort.InferenceSession.create(modelPath('vocoder.onnx'), opts),
324
+ ]);
325
+ log.info('supertonic', 'model yüklendi');
326
+ return {
327
+ ort,
328
+ cfg,
329
+ indexer,
330
+ dp,
331
+ textEnc,
332
+ vectorEst,
333
+ vocoder,
334
+ styles: new Map(),
335
+ sampleRate: cfg.ae.sample_rate,
336
+ baseChunkSize: cfg.ae.base_chunk_size,
337
+ chunkCompressFactor: cfg.ttl.chunk_compress_factor,
338
+ ldim: cfg.ttl.latent_dim,
339
+ };
340
+ }
341
+
342
+ function loadEngine() {
343
+ if (engine) return Promise.resolve(engine);
344
+ if (!enginePromise) {
345
+ enginePromise = doLoadEngine().then(
346
+ (e) => { engine = e; enginePromise = null; return e; },
347
+ (e) => { enginePromise = null; throw e; }
348
+ );
349
+ }
350
+ return enginePromise;
351
+ }
352
+
353
+ /* ses stili JSON → { ttl, dp } tensorları (motor başına önbellek) */
354
+ function loadStyle(eng, id) {
355
+ const cached = eng.styles.get(id);
356
+ if (cached) return cached;
357
+ const raw = JSON.parse(fs.readFileSync(stylePath(id), 'utf8'));
358
+ const ttl = new eng.ort.Tensor('float32', Float32Array.from(raw.style_ttl.data.flat(Infinity)), raw.style_ttl.dims);
359
+ const dp = new eng.ort.Tensor('float32', Float32Array.from(raw.style_dp.data.flat(Infinity)), raw.style_dp.dims);
360
+ const style = { ttl, dp };
361
+ eng.styles.set(id, style);
362
+ return style;
363
+ }
364
+
365
+ /* ---------- metin ön işleme (resmi helper.js portu) ---------- */
366
+
367
+ function preprocessText(text, lang) {
368
+ let t = String(text || '').normalize('NFKD');
369
+ t = t.replace(/[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F700}-\u{1F77F}\u{1F780}-\u{1F7FF}\u{1F800}-\u{1F8FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F1E6}-\u{1F1FF}]+/gu, '');
370
+ const replacements = {
371
+ '–': '-', '‑': '-', '—': '-', _: ' ',
372
+ '\u201C': '"', '\u201D': '"', '\u2018': "'", '\u2019': "'",
373
+ '´': "'", '`': "'", '[': ' ', ']': ' ', '|': ' ', '/': ' ', '#': ' ', '→': ' ', '←': ' ',
374
+ };
375
+ for (const [k, v] of Object.entries(replacements)) t = t.split(k).join(v);
376
+ t = t.replace(/[♥☆♡©\\]/g, '');
377
+ t = t.replace(/@/g, ' at ').replace(/e\.g\.,/g, 'for example, ').replace(/i\.e\.,/g, 'that is, ');
378
+ t = t.replace(/ ,/g, ',').replace(/ \./g, '.').replace(/ !/g, '!').replace(/ \?/g, '?').replace(/ ;/g, ';').replace(/ :/g, ':').replace(/ '/g, "'");
379
+ while (t.includes('""')) t = t.replace('""', '"');
380
+ while (t.includes("''")) t = t.replace("''", "'");
381
+ while (t.includes('``')) t = t.replace('``', '`');
382
+ t = t.replace(/\s+/g, ' ').trim();
383
+ if (!/[.!?;:,'\"')\]}…。」』】〉》›»]$/.test(t)) t += '.';
384
+ return '<' + lang + '>' + t + '</' + lang + '>';
385
+ }
386
+
387
+ function chunkText(text, maxLen) {
388
+ const paragraphs = String(text).trim().split(/\n\s*\n+/).filter((p) => p.trim());
389
+ const chunks = [];
390
+ for (let paragraph of paragraphs) {
391
+ paragraph = paragraph.trim();
392
+ if (!paragraph) continue;
393
+ const sentences = paragraph.split(/(?<!Mr\.|Mrs\.|Ms\.|Dr\.|Prof\.|Sr\.|Jr\.|Ph\.D\.|etc\.|e\.g\.|i\.e\.|vs\.|Inc\.|Ltd\.|Co\.|Corp\.|St\.|Ave\.|Blvd\.)(?<!\b[A-Z]\.)(?<=[.!?])\s+/);
394
+ let current = '';
395
+ for (const sentence of sentences) {
396
+ if (current.length + sentence.length + 1 <= maxLen) current += (current ? ' ' : '') + sentence;
397
+ else {
398
+ if (current) chunks.push(current.trim());
399
+ current = sentence;
400
+ }
401
+ }
402
+ if (current) chunks.push(current.trim());
403
+ }
404
+ return chunks.length ? chunks : [String(text).trim()];
405
+ }
406
+
407
+ /* ---------- tensör yardımcıları ---------- */
408
+
409
+ function lengthToMask(lengths, maxLen) {
410
+ maxLen = maxLen || Math.max(...lengths);
411
+ const mask = [];
412
+ for (let i = 0; i < lengths.length; i++) {
413
+ const row = [];
414
+ for (let j = 0; j < maxLen; j++) row.push(j < lengths[i] ? 1.0 : 0.0);
415
+ mask.push([row]);
416
+ }
417
+ return mask;
418
+ }
419
+
420
+ function getLatentMask(wavLengths, baseChunkSize, chunkCompressFactor) {
421
+ const latentSize = baseChunkSize * chunkCompressFactor;
422
+ return lengthToMask(wavLengths.map((len) => Math.floor((len + latentSize - 1) / latentSize)));
423
+ }
424
+
425
+ function arrayToTensor(ort, array, dims) {
426
+ return new ort.Tensor('float32', Float32Array.from(array.flat(Infinity)), dims);
427
+ }
428
+
429
+ function intArrayToTensor(ort, array, dims) {
430
+ return new ort.Tensor('int64', BigInt64Array.from(array.flat(Infinity).map((x) => BigInt(x))), dims);
431
+ }
432
+
433
+ /* ---------- çıkarım ---------- */
434
+
435
+ function sampleNoisyLatent(eng, duration) {
436
+ const wavLenMax = Math.max(...duration) * eng.sampleRate;
437
+ const wavLengths = duration.map((d) => Math.floor(d * eng.sampleRate));
438
+ const chunkSize = eng.baseChunkSize * eng.chunkCompressFactor;
439
+ const latentLen = Math.floor((wavLenMax + chunkSize - 1) / chunkSize);
440
+ const latentDim = eng.ldim * eng.chunkCompressFactor;
441
+
442
+ const noisyLatent = [];
443
+ for (let b = 0; b < duration.length; b++) {
444
+ const batch = [];
445
+ for (let d = 0; d < latentDim; d++) {
446
+ const row = [];
447
+ for (let t = 0; t < latentLen; t++) {
448
+ const eps = 1e-10;
449
+ const u1 = Math.max(eps, Math.random());
450
+ const u2 = Math.random();
451
+ row.push(Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2)); // Box-Muller
452
+ }
453
+ batch.push(row);
454
+ }
455
+ noisyLatent.push(batch);
456
+ }
457
+
458
+ const latentMask = getLatentMask(wavLengths, eng.baseChunkSize, eng.chunkCompressFactor);
459
+ for (let b = 0; b < noisyLatent.length; b++) {
460
+ for (let d = 0; d < noisyLatent[b].length; d++) {
461
+ for (let t = 0; t < noisyLatent[b][d].length; t++) {
462
+ noisyLatent[b][d][t] *= latentMask[b][0][t];
463
+ }
464
+ }
465
+ }
466
+ return { noisyLatent, latentMask };
467
+ }
468
+
469
+ async function inferOne(eng, text, lang, style, steps, speed) {
470
+ const ort = eng.ort;
471
+ const processed = preprocessText(text, lang);
472
+ const textIdsLen = processed.length;
473
+ const textIdsRow = new Array(textIdsLen).fill(0);
474
+ const unicodeVals = Array.from(processed).map((c) => c.charCodeAt(0));
475
+ for (let j = 0; j < unicodeVals.length; j++) {
476
+ const idx = eng.indexer[unicodeVals[j]];
477
+ textIdsRow[j] = Number.isFinite(idx) ? idx : -1;
478
+ }
479
+ const textIds = [textIdsRow];
480
+ const textMask = lengthToMask([textIdsLen]);
481
+ const textIdsShape = [1, textIdsLen];
482
+ const textMaskShape = [1, 1, textMask[0][0].length];
483
+
484
+ const textMaskTensor = arrayToTensor(ort, textMask, textMaskShape);
485
+
486
+ const dpResult = await eng.dp.run({
487
+ text_ids: intArrayToTensor(ort, textIds, textIdsShape),
488
+ style_dp: style.dp,
489
+ text_mask: textMaskTensor,
490
+ });
491
+ const durOnnx = Array.from(dpResult.duration.data);
492
+ for (let i = 0; i < durOnnx.length; i++) durOnnx[i] /= speed;
493
+
494
+ const textEncResult = await eng.textEnc.run({
495
+ text_ids: intArrayToTensor(ort, textIds, textIdsShape),
496
+ style_ttl: style.ttl,
497
+ text_mask: textMaskTensor,
498
+ });
499
+ const textEmbTensor = textEncResult.text_emb;
500
+
501
+ const { noisyLatent, latentMask } = sampleNoisyLatent(eng, durOnnx);
502
+ const latentShape = [1, noisyLatent[0].length, noisyLatent[0][0].length];
503
+ const latentMaskShape = [1, 1, latentMask[0][0].length];
504
+ const latentMaskTensor = arrayToTensor(ort, latentMask, latentMaskShape);
505
+
506
+ const totalStepArray = new Array(1).fill(steps);
507
+ const scalarShape = [1];
508
+ const totalStepTensor = arrayToTensor(ort, totalStepArray, scalarShape);
509
+
510
+ for (let step = 0; step < steps; step++) {
511
+ const currentStepArray = new Array(1).fill(step);
512
+ const vectorEstResult = await eng.vectorEst.run({
513
+ noisy_latent: arrayToTensor(ort, noisyLatent, latentShape),
514
+ text_emb: textEmbTensor,
515
+ style_ttl: style.ttl,
516
+ text_mask: textMaskTensor,
517
+ latent_mask: latentMaskTensor,
518
+ total_step: totalStepTensor,
519
+ current_step: arrayToTensor(ort, currentStepArray, scalarShape),
520
+ });
521
+ const denoised = vectorEstResult.denoised_latent.data;
522
+ let idx = 0;
523
+ for (let b = 0; b < noisyLatent.length; b++) {
524
+ for (let d = 0; d < noisyLatent[b].length; d++) {
525
+ for (let t = 0; t < noisyLatent[b][d].length; t++) {
526
+ noisyLatent[b][d][t] = denoised[idx++];
527
+ }
528
+ }
529
+ }
530
+ }
531
+
532
+ const vocoderResult = await eng.vocoder.run({
533
+ latent: arrayToTensor(ort, noisyLatent, latentShape),
534
+ });
535
+ const wavAll = vocoderResult.wav_tts.data;
536
+ const wavLen = Math.floor(durOnnx[0] * eng.sampleRate);
537
+ return wavAll.slice(0, wavLen);
538
+ }
539
+
540
+ async function runInference(eng, text, lang, style, steps, speed) {
541
+ const maxLen = lang === 'ko' || lang === 'ja' ? 120 : 300;
542
+ const chunks = chunkText(text, maxLen);
543
+ let wav = null;
544
+ const silenceLen = Math.floor(0.3 * eng.sampleRate);
545
+ for (const chunk of chunks) {
546
+ const part = await inferOne(eng, chunk, lang, style, steps, speed);
547
+ if (!wav) {
548
+ wav = part;
549
+ } else if (part.length) {
550
+ const merged = new Float32Array(wav.length + silenceLen + part.length);
551
+ merged.set(wav, 0);
552
+ merged.set(part, wav.length + silenceLen);
553
+ wav = merged;
554
+ }
555
+ }
556
+ return wav || new Float32Array(0);
557
+ }
558
+
559
+ /* ---------- WAV (16-bit PCM mono) ---------- */
560
+
561
+ function encodeWav(samples, sampleRate) {
562
+ const dataSize = samples.length * 2;
563
+ const buf = Buffer.alloc(44 + dataSize);
564
+ buf.write('RIFF', 0);
565
+ buf.writeUInt32LE(36 + dataSize, 4);
566
+ buf.write('WAVE', 8);
567
+ buf.write('fmt ', 12);
568
+ buf.writeUInt32LE(16, 16);
569
+ buf.writeUInt16LE(1, 20);
570
+ buf.writeUInt16LE(1, 22);
571
+ buf.writeUInt32LE(sampleRate, 24);
572
+ buf.writeUInt32LE(sampleRate * 2, 28);
573
+ buf.writeUInt16LE(2, 32);
574
+ buf.writeUInt16LE(16, 34);
575
+ buf.write('data', 36);
576
+ buf.writeUInt32LE(dataSize, 40);
577
+ for (let i = 0; i < samples.length; i++) {
578
+ const s = Math.max(-1, Math.min(1, samples[i]));
579
+ buf.writeInt16LE(Math.floor(s * 32767), 44 + i * 2);
580
+ }
581
+ return buf;
582
+ }
583
+
584
+ /* ---------- sentez: metin → { audio: WAV buffer, mime } ---------- */
585
+
586
+ async function synthesize(text, opts = {}) {
587
+ const t = String(text || '').trim();
588
+ if (!t) throw new Error('boş metin');
589
+ const vid = resolveVoice(opts.voice);
590
+ const lang = resolveLang(opts.lang);
591
+ const speed = clampNum(Number(opts.speed) || DEFAULT_SPEED, 0.7, 2);
592
+ const steps = Math.round(clampNum(Number(opts.steps) || DEFAULT_STEPS, 5, 12));
593
+ await ensureModel();
594
+ await ensureVoice(vid);
595
+ const eng = await loadEngine();
596
+ const style = loadStyle(eng, vid);
597
+ busy++;
598
+ try {
599
+ const pcm = await runInference(eng, t.slice(0, 4000), lang, style, steps, speed);
600
+ if (!pcm.length) throw new Error('ses üretilemedi');
601
+ return { audio: encodeWav(pcm, eng.sampleRate), mime: 'audio/wav' };
602
+ } finally {
603
+ busy--;
604
+ if (busy <= 0) touchIdle();
605
+ }
606
+ }
607
+
608
+ module.exports = {
609
+ VOICES,
610
+ LANGS,
611
+ DEFAULT_VOICE,
612
+ DEFAULT_LANG,
613
+ DEFAULT_SPEED,
614
+ DEFAULT_STEPS,
615
+ synthesize,
616
+ install,
617
+ status,
618
+ ensureModel,
619
+ ensureVoice,
620
+ modelInstalled,
621
+ voiceInstalled,
622
+ };
@@ -14,8 +14,6 @@ const gittools = require('./gittools');
14
14
  const repomap = require('./repomap');
15
15
  const xlsxtools = require('./xlsxtools');
16
16
  const typesafe = require('./typesafe');
17
- let financetools = null;
18
- try { financetools = require('./financetools'); } catch {}
19
17
 
20
18
  const MAX_CMD_OUTPUT = 16000;
21
19
  const MAX_FILE_CHARS = 200000;
@@ -1794,11 +1792,10 @@ function readCacheDrop(abs) {
1794
1792
  }
1795
1793
 
1796
1794
  const definitions = [
1797
- /* yerleşik modül araçları: git, repo haritası, excel, finance (MT5), TypeSafe */
1795
+ /* yerleşik modül araçları: git, repo haritası, excel, TypeSafe */
1798
1796
  ...gittools.definitions,
1799
1797
  ...repomap.definitions,
1800
1798
  ...xlsxtools.definitions,
1801
- ...(financetools ? financetools.definitions : []),
1802
1799
  ...typesafe.definitions,
1803
1800
  {
1804
1801
  type: 'function',
@@ -2082,13 +2079,12 @@ const definitions = [
2082
2079
 
2083
2080
  async function exec(name, args, ctx) {
2084
2081
  const cwd = ctx.cwd;
2085
- /* modül araçları: gittools / repomap / xlsxtools / financetools / typesafe — kendi handler'larında */
2082
+ /* modül araçları: gittools / repomap / xlsxtools / typesafe — kendi handler'larında */
2086
2083
  const modHandler =
2087
2084
  gittools.handlers[name] ||
2088
2085
  repomap.handlers[name] ||
2089
2086
  xlsxtools.handlers[name] ||
2090
- typesafe.handlers[name] ||
2091
- (financetools && financetools.handlers[name]);
2087
+ typesafe.handlers[name];
2092
2088
  if (modHandler) {
2093
2089
  try {
2094
2090
  return JSON.stringify(await modHandler(args, ctx));