@danieltmn/tamnora 0.6.1 → 0.6.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/CHANGELOG.md +6 -0
- package/harness/packages/server/public/app.js +5 -0
- package/harness/packages/server/public/index.html +5 -1
- package/harness/packages/server/src/lib/channels/index.js +11 -4
- package/harness/packages/server/src/lib/channels/telegram.js +17 -5
- package/harness/packages/server/src/routes/channels.js +1 -0
- package/harness/packages/server/test/server.test.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ Todos los cambios relevantes de este proyecto se documentan en este archivo.
|
|
|
5
5
|
El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/)
|
|
6
6
|
y el proyecto usa [Versionado Semantico](https://semver.org/lang/es/).
|
|
7
7
|
|
|
8
|
+
## [0.6.2] - 2026-10-05
|
|
9
|
+
|
|
10
|
+
### Cambios
|
|
11
|
+
|
|
12
|
+
- fix(telegram): proveedor de transcripcion dedicado y error claro en la voz
|
|
13
|
+
|
|
8
14
|
## [0.6.1] - 2026-10-05
|
|
9
15
|
|
|
10
16
|
### Cambios
|
|
@@ -2399,6 +2399,7 @@ const skillForm = $('#skill-form');
|
|
|
2399
2399
|
const tgTokenEl = $('#tg-token');
|
|
2400
2400
|
const tgChatsEl = $('#tg-chats');
|
|
2401
2401
|
const tgTranscribeEl = $('#tg-transcribe');
|
|
2402
|
+
const tgTranscribeProviderEl = $('#tg-transcribe-provider');
|
|
2402
2403
|
const tgStatusEl = $('#tg-status');
|
|
2403
2404
|
|
|
2404
2405
|
function setStatus(node, text, cls = '') {
|
|
@@ -2631,6 +2632,9 @@ async function refreshChannels() {
|
|
|
2631
2632
|
if (tgTranscribeEl && document.activeElement !== tgTranscribeEl) {
|
|
2632
2633
|
tgTranscribeEl.value = tg.transcribeModel ?? 'whisper-1';
|
|
2633
2634
|
}
|
|
2635
|
+
if (tgTranscribeProviderEl && document.activeElement !== tgTranscribeProviderEl) {
|
|
2636
|
+
tgTranscribeProviderEl.value = tg.transcribeProvider ?? '';
|
|
2637
|
+
}
|
|
2634
2638
|
if (tgTokenEl && document.activeElement !== tgTokenEl) {
|
|
2635
2639
|
tgTokenEl.value = '';
|
|
2636
2640
|
tgTokenEl.placeholder = tg.tokenHint ? `${tg.tokenHint} (dejar vacío para no cambiar)` : '123456:ABC…';
|
|
@@ -2643,6 +2647,7 @@ async function submitChannel() {
|
|
|
2643
2647
|
const body = {
|
|
2644
2648
|
allowedChatIds: tgChatsEl?.value ?? '',
|
|
2645
2649
|
transcribeModel: tgTranscribeEl?.value.trim() || 'whisper-1',
|
|
2650
|
+
transcribeProvider: tgTranscribeProviderEl?.value.trim() || '',
|
|
2646
2651
|
};
|
|
2647
2652
|
const token = tgTokenEl.value.trim();
|
|
2648
2653
|
if (token) body.token = token;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</head>
|
|
34
34
|
<body>
|
|
35
35
|
<header class="topbar">
|
|
36
|
-
<div class="brand"><span class="logo"><span class="logo-t">T</span><span class="logo-h">H</span></span> <span class="ver">v0.6.
|
|
36
|
+
<div class="brand"><span class="logo"><span class="logo-t">T</span><span class="logo-h">H</span></span> <span class="ver">v0.6.2</span></div>
|
|
37
37
|
<nav class="tabs">
|
|
38
38
|
<button class="tab active" data-tab="chat">chat</button>
|
|
39
39
|
<button class="tab" data-tab="providers">proveedores</button>
|
|
@@ -394,6 +394,10 @@
|
|
|
394
394
|
<label class="field"><span>chats autorizados (ids separados por coma)</span>
|
|
395
395
|
<input id="tg-chats" spellcheck="false" placeholder="123456789, -1001234567890" />
|
|
396
396
|
</label>
|
|
397
|
+
<label class="field"><span>proveedor de transcripción (voz, opcional)</span>
|
|
398
|
+
<input id="tg-transcribe-provider" spellcheck="false"
|
|
399
|
+
placeholder="openai · groq — vacío = proveedor activo" />
|
|
400
|
+
</label>
|
|
397
401
|
<label class="field"><span>modelo de transcripción (voz)</span>
|
|
398
402
|
<input id="tg-transcribe" spellcheck="false" placeholder="whisper-1" />
|
|
399
403
|
</label>
|
|
@@ -36,6 +36,7 @@ export function createChannelsManager(ctx, { log = () => {}, enabled = true } =
|
|
|
36
36
|
if (cfg.token) tg.token = cfg.token;
|
|
37
37
|
if (Array.isArray(cfg.allowedChatIds) && cfg.allowedChatIds.length) tg.allowedChatIds = cfg.allowedChatIds;
|
|
38
38
|
if (cfg.transcribeModel) tg.transcribeModel = cfg.transcribeModel;
|
|
39
|
+
if (cfg.transcribeProvider) tg.transcribeProvider = cfg.transcribeProvider;
|
|
39
40
|
return tg;
|
|
40
41
|
};
|
|
41
42
|
|
|
@@ -43,7 +44,12 @@ export function createChannelsManager(ctx, { log = () => {}, enabled = true } =
|
|
|
43
44
|
const tg = readConfig();
|
|
44
45
|
const token = tg.token || process.env.TAMNORA_TELEGRAM_TOKEN || '';
|
|
45
46
|
const allowedChatIds = parseAllowed(tg.allowedChatIds ?? process.env.TAMNORA_TELEGRAM_CHAT_IDS ?? []);
|
|
46
|
-
return {
|
|
47
|
+
return {
|
|
48
|
+
token,
|
|
49
|
+
allowedChatIds,
|
|
50
|
+
transcribeModel: tg.transcribeModel,
|
|
51
|
+
transcribeProvider: tg.transcribeProvider,
|
|
52
|
+
};
|
|
47
53
|
}
|
|
48
54
|
|
|
49
55
|
function stop() {
|
|
@@ -56,9 +62,9 @@ export function createChannelsManager(ctx, { log = () => {}, enabled = true } =
|
|
|
56
62
|
function load() {
|
|
57
63
|
stop();
|
|
58
64
|
if (!enabled) return { enabled: false, channels: [] };
|
|
59
|
-
const { token, allowedChatIds, transcribeModel } = effective();
|
|
65
|
+
const { token, allowedChatIds, transcribeModel, transcribeProvider } = effective();
|
|
60
66
|
const channels = [];
|
|
61
|
-
const telegram = startTelegramChannel(ctx, { token, allowedChatIds, transcribeModel, log });
|
|
67
|
+
const telegram = startTelegramChannel(ctx, { token, allowedChatIds, transcribeModel, transcribeProvider, log });
|
|
62
68
|
if (telegram) channels.push(telegram);
|
|
63
69
|
const unsubscribe = ctx.runs?.subscribeAll?.((sessionId, event) => {
|
|
64
70
|
for (const channel of channels) {
|
|
@@ -75,12 +81,13 @@ export function createChannelsManager(ctx, { log = () => {}, enabled = true } =
|
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
function status() {
|
|
78
|
-
const { token, allowedChatIds, transcribeModel } = effective();
|
|
84
|
+
const { token, allowedChatIds, transcribeModel, transcribeProvider } = effective();
|
|
79
85
|
return {
|
|
80
86
|
tokenSet: Boolean(token),
|
|
81
87
|
tokenHint: tokenHint(token),
|
|
82
88
|
allowedChatIds,
|
|
83
89
|
transcribeModel: transcribeModel || 'whisper-1',
|
|
90
|
+
transcribeProvider: transcribeProvider || '',
|
|
84
91
|
running: Boolean(active && active.channels.length),
|
|
85
92
|
};
|
|
86
93
|
}
|
|
@@ -82,7 +82,10 @@ export function completionFooter(stopReason, rounds, toolCalls, durationMs) {
|
|
|
82
82
|
/**
|
|
83
83
|
* Arranca el canal de Telegram. Devuelve `{ stop, notify }` o `null` sin token.
|
|
84
84
|
*/
|
|
85
|
-
export function startTelegramChannel(
|
|
85
|
+
export function startTelegramChannel(
|
|
86
|
+
ctx,
|
|
87
|
+
{ token, allowedChatIds = [], transcribeModel = 'whisper-1', transcribeProvider = '', log = () => {} } = {}
|
|
88
|
+
) {
|
|
86
89
|
if (!token) return null;
|
|
87
90
|
const allowed = new Set(allowedChatIds.map(String));
|
|
88
91
|
const controllers = new Map();
|
|
@@ -130,10 +133,11 @@ export function startTelegramChannel(ctx, { token, allowedChatIds = [], transcri
|
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
async function transcribe(buffer, filename) {
|
|
133
|
-
const providerId = ctx.effectiveProviderId();
|
|
134
|
-
const
|
|
136
|
+
const providerId = transcribeProvider || ctx.effectiveProviderId();
|
|
137
|
+
const settings = ctx.providerSettings(providerId) ?? {};
|
|
138
|
+
const baseUrl = (settings.baseUrl || '').replace(/\/+$/, '');
|
|
135
139
|
const apiKey = ctx.apiKeyFor(providerId);
|
|
136
|
-
if (!baseUrl) throw new Error(
|
|
140
|
+
if (!baseUrl) throw new Error(`el proveedor "${providerId}" no tiene baseUrl para transcribir`);
|
|
137
141
|
const form = new FormData();
|
|
138
142
|
form.append('file', new Blob([buffer]), filename);
|
|
139
143
|
form.append('model', transcribeModel);
|
|
@@ -142,7 +146,15 @@ export function startTelegramChannel(ctx, { token, allowedChatIds = [], transcri
|
|
|
142
146
|
headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
|
|
143
147
|
body: form,
|
|
144
148
|
});
|
|
145
|
-
if (!res.ok)
|
|
149
|
+
if (!res.ok) {
|
|
150
|
+
const hint =
|
|
151
|
+
res.status === 404
|
|
152
|
+
? ` — "${providerId}" no expone /audio/transcriptions`
|
|
153
|
+
: '';
|
|
154
|
+
throw new Error(
|
|
155
|
+
`transcripción falló (HTTP ${res.status})${hint}. Elegí un proveedor con voz (OpenAI, Groq…) en Ajustes → Telegram.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
146
158
|
const data = await res.json();
|
|
147
159
|
return String(data.text ?? '').trim();
|
|
148
160
|
}
|
|
@@ -30,6 +30,7 @@ export function registerChannels(route, ctx) {
|
|
|
30
30
|
}
|
|
31
31
|
if ('allowedChatIds' in body) next.allowedChatIds = sanitizeAllowed(body.allowedChatIds);
|
|
32
32
|
if ('transcribeModel' in body) next.transcribeModel = String(body.transcribeModel ?? '').trim() || 'whisper-1';
|
|
33
|
+
if ('transcribeProvider' in body) next.transcribeProvider = String(body.transcribeProvider ?? '').trim();
|
|
33
34
|
|
|
34
35
|
app.telegram = next;
|
|
35
36
|
writeApp(app);
|
|
@@ -287,10 +287,11 @@ test('configures Telegram from the console (masked token)', async () => {
|
|
|
287
287
|
res = await fetch(`${base}/api/channels/telegram`, {
|
|
288
288
|
method: 'PUT',
|
|
289
289
|
headers: json,
|
|
290
|
-
body: JSON.stringify({ token: '123456:ABCDEFghij' }),
|
|
290
|
+
body: JSON.stringify({ token: '123456:ABCDEFghij', transcribeProvider: 'openai' }),
|
|
291
291
|
});
|
|
292
292
|
data = await res.json();
|
|
293
293
|
assert.equal(data.telegram.tokenSet, true);
|
|
294
|
+
assert.equal(data.telegram.transcribeProvider, 'openai');
|
|
294
295
|
assert.match(data.telegram.tokenHint, /ghij$/);
|
|
295
296
|
assert.doesNotMatch(JSON.stringify(data), /ABCDEF/);
|
|
296
297
|
|
package/package.json
CHANGED