@mulingai-npm/redis 3.4.1 → 3.5.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.
@@ -1,359 +1,359 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MulingstreamChunkManager = void 0;
4
- const uuid_1 = require("uuid");
5
- const EXPIRATION = 12 * 60 * 60;
6
- const ROOM_ARRAY_LENGTH = 50;
7
- class MulingstreamChunkManager {
8
- constructor(redisClient) {
9
- this.redisClient = redisClient;
10
- }
11
- roomZsetKey(roomId) {
12
- return `room:${roomId}:chunks`;
13
- }
14
- chunkHashKey(chunkId) {
15
- return `chunk:${chunkId}`;
16
- }
17
- generateChunkId(roomId, chunkNumber) {
18
- return `[${roomId}]-[${chunkNumber}]-[${(0, uuid_1.v4)()}]`;
19
- }
20
- serialize(value) {
21
- return JSON.stringify(value);
22
- }
23
- deserialize(v) {
24
- return v ? JSON.parse(v) : undefined;
25
- }
26
- hashToChunk(h) {
27
- return {
28
- chunkId: h.chunkId,
29
- roomId: h.roomId,
30
- chunkNumber: parseInt(h.chunkNumber, 10),
31
- language: h.language,
32
- sttProviders: this.deserialize(h.sttProviders),
33
- targetLanguages: this.deserialize(h.targetLanguages),
34
- shortCodeTargetLanguages: this.deserialize(h.shortCodeTargetLanguages),
35
- finalTranscription: h.finalTranscription,
36
- sttStatus: h.sttStatus,
37
- createdAt: parseInt(h.createdAt, 10),
38
- audioChunk: this.deserialize(h.audioChunk),
39
- stt: this.deserialize(h.stt),
40
- translation: this.deserialize(h.translation),
41
- tts: this.deserialize(h.tts)
42
- };
43
- }
44
- getTimeout(start, end) {
45
- return 25000;
46
- }
47
- async initRoom(roomId) {
48
- const exists = await this.redisClient.exists(this.roomZsetKey(roomId));
49
- if (exists)
50
- return false;
51
- await this.redisClient.expire(this.roomZsetKey(roomId), EXPIRATION);
52
- return true;
53
- }
54
- async getRooms() {
55
- const keys = await this.redisClient.keys('room:*:chunks');
56
- return keys.map((k) => k.replace(/^room:(.*):chunks$/, '$1'));
57
- }
58
- async getMulingstreamChunksByRoom(roomId) {
59
- const ids = await this.redisClient.zrange(this.roomZsetKey(roomId), 0, -1);
60
- if (!ids.length)
61
- return null;
62
- const pipe = this.redisClient.pipeline();
63
- ids.forEach((cid) => pipe.hgetall(this.chunkHashKey(cid)));
64
- const res = await pipe.exec();
65
- if (!res)
66
- return null;
67
- return res === null || res === void 0 ? void 0 : res.map(([, d]) => this.hashToChunk(d));
68
- }
69
- getRoomById(roomId) {
70
- return this.getMulingstreamChunksByRoom(roomId);
71
- }
72
- async addMulingstreamChunk(params) {
73
- var _a, _b;
74
- const { roomId, chunkNumber, language, start, end, duration, isFirst, isLast, sttProviders, targetLanguages, shortCodeTargetLanguages } = params;
75
- if (chunkNumber === 1) {
76
- const old = await this.redisClient.zrange(this.roomZsetKey(roomId), 0, -1);
77
- if (old.length) {
78
- const p = this.redisClient.pipeline();
79
- old.forEach((cid) => p.unlink(this.chunkHashKey(cid)));
80
- p.del(this.roomZsetKey(roomId));
81
- await p.exec();
82
- }
83
- }
84
- else {
85
- const dup = await this.redisClient.zrangebyscore(this.roomZsetKey(roomId), chunkNumber, chunkNumber);
86
- if (dup.length) {
87
- const p = this.redisClient.pipeline();
88
- dup.forEach((cid) => p.unlink(this.chunkHashKey(cid)));
89
- p.zrem(this.roomZsetKey(roomId), ...dup);
90
- await p.exec();
91
- }
92
- }
93
- const chunkId = this.generateChunkId(roomId, chunkNumber);
94
- const audioChunk = { start, end, duration, isFirst, isLast, audioFilePath: '' };
95
- const stt = {};
96
- sttProviders.forEach((p) => (stt[p.service] = { transcription: '', model: p.model, status: 'INIT' }));
97
- const translation = {};
98
- const tts = {};
99
- shortCodeTargetLanguages.forEach((l) => {
100
- translation[l] = { translation: '', status: 'INIT' };
101
- tts[l] = { ttsAudioPath: '', status: 'INIT', isEmitted: false };
102
- });
103
- const createdAt = Date.now();
104
- const chunk = {
105
- chunkId,
106
- roomId,
107
- chunkNumber,
108
- language,
109
- sttProviders,
110
- targetLanguages,
111
- shortCodeTargetLanguages,
112
- finalTranscription: '',
113
- sttStatus: 'INIT',
114
- createdAt,
115
- audioChunk,
116
- stt,
117
- translation,
118
- tts
119
- };
120
- const hash = {
121
- chunkId,
122
- roomId,
123
- chunkNumber: String(chunkNumber),
124
- language,
125
- sttProviders: this.serialize(sttProviders),
126
- targetLanguages: this.serialize(targetLanguages),
127
- shortCodeTargetLanguages: this.serialize(shortCodeTargetLanguages),
128
- finalTranscription: '',
129
- sttStatus: 'INIT',
130
- createdAt: String(createdAt),
131
- audioChunk: this.serialize(audioChunk),
132
- stt: this.serialize(stt),
133
- translation: this.serialize(translation),
134
- tts: this.serialize(tts)
135
- };
136
- const pipe = this.redisClient.pipeline();
137
- pipe.hset(this.chunkHashKey(chunkId), hash);
138
- pipe.expire(this.chunkHashKey(chunkId), EXPIRATION);
139
- pipe.zadd(this.roomZsetKey(roomId), chunkNumber, chunkId);
140
- pipe.expire(this.roomZsetKey(roomId), EXPIRATION);
141
- pipe.zrange(this.roomZsetKey(roomId), 0, -ROOM_ARRAY_LENGTH - 1, 'WITHSCORES');
142
- const execResults = await pipe.exec();
143
- const oldPairs = ((_b = (_a = execResults === null || execResults === void 0 ? void 0 : execResults[4]) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : []);
144
- if (Array.isArray(oldPairs) && oldPairs.length) {
145
- const oldIds = [];
146
- for (let i = 0; i < oldPairs.length; i += 2)
147
- oldIds.push(oldPairs[i]);
148
- const trim = this.redisClient.pipeline();
149
- trim.zrem(this.roomZsetKey(roomId), ...oldIds);
150
- oldIds.forEach((cid) => trim.unlink(this.chunkHashKey(cid)));
151
- await trim.exec();
152
- }
153
- return chunk;
154
- }
155
- async getChunkId(roomId, n) {
156
- const ids = await this.redisClient.zrangebyscore(this.roomZsetKey(roomId), n, n);
157
- return ids.length ? ids[0] : null;
158
- }
159
- async getMulingstreamChunkById(roomId, n) {
160
- const cid = await this.getChunkId(roomId, n);
161
- if (!cid)
162
- return null;
163
- const raw = await this.redisClient.hgetall(this.chunkHashKey(cid));
164
- return raw.chunkId ? this.hashToChunk(raw) : null;
165
- }
166
- async withChunk(roomId, n, fn) {
167
- const cid = await this.getChunkId(roomId, n);
168
- if (!cid)
169
- return null;
170
- const key = this.chunkHashKey(cid);
171
- const raw = await this.redisClient.hgetall(key);
172
- if (!raw.chunkId)
173
- return null;
174
- const chunk = this.hashToChunk(raw);
175
- await fn(chunk);
176
- const p = this.redisClient.pipeline();
177
- p.hset(key, {
178
- finalTranscription: chunk.finalTranscription,
179
- sttStatus: chunk.sttStatus,
180
- stt: this.serialize(chunk.stt),
181
- translation: this.serialize(chunk.translation),
182
- tts: this.serialize(chunk.tts),
183
- audioChunk: this.serialize(chunk.audioChunk)
184
- });
185
- p.expire(key, EXPIRATION);
186
- await p.exec();
187
- return chunk;
188
- }
189
- async updateAudioFilePath(roomId, chunkNumber, audioFilePath) {
190
- return this.withChunk(roomId, chunkNumber, (chunk) => {
191
- chunk.audioChunk.audioFilePath = audioFilePath;
192
- });
193
- }
194
- async updateStt(roomId, n, service, opt) {
195
- return this.withChunk(roomId, n, (c) => {
196
- if (!c.stt[service])
197
- return;
198
- if (opt.transcription !== undefined)
199
- c.stt[service].transcription = opt.transcription;
200
- if (opt.sttStatus !== undefined)
201
- c.stt[service].status = opt.sttStatus;
202
- });
203
- }
204
- async updateSttObject(roomId, n, newStt) {
205
- return this.withChunk(roomId, n, (c) => {
206
- c.stt = newStt;
207
- });
208
- }
209
- async discardStt(roomId, n) {
210
- return this.withChunk(roomId, n, (c) => {
211
- Object.keys(c.stt).forEach((p) => {
212
- c.stt[p].transcription = '';
213
- c.stt[p].status = 'DISCARDED';
214
- });
215
- c.finalTranscription = '';
216
- c.sttStatus = 'DISCARDED';
217
- });
218
- }
219
- async updateSttAsUsed(roomId, chunkNumber) {
220
- return this.withChunk(roomId, chunkNumber, (chunk) => {
221
- Object.keys(chunk.stt).forEach((sttProvider) => {
222
- chunk.stt[sttProvider].status = 'USED';
223
- });
224
- });
225
- }
226
- async updateFinalTranscription(roomId, n, opt) {
227
- return this.withChunk(roomId, n, (c) => {
228
- if (opt.transcription !== undefined)
229
- c.finalTranscription = opt.transcription;
230
- if (opt.sttStatus !== undefined)
231
- c.sttStatus = opt.sttStatus;
232
- });
233
- }
234
- async discardPostStt(roomId, n) {
235
- return this.withChunk(roomId, n, (c) => {
236
- Object.values(c.translation).forEach((t) => (t.status = 'DISCARDED'));
237
- Object.values(c.tts).forEach((t) => (t.status = 'DISCARDED'));
238
- });
239
- }
240
- async discardLanguage(roomId, n, lang) {
241
- return this.withChunk(roomId, n, (c) => {
242
- if (c.translation[lang])
243
- c.translation[lang].status = 'DISCARDED';
244
- if (c.tts[lang])
245
- c.tts[lang].status = 'DISCARDED';
246
- });
247
- }
248
- async discardLanguages(roomId, n, opt) {
249
- return this.withChunk(roomId, n, (c) => {
250
- var _a, _b;
251
- (_a = opt.translation) === null || _a === void 0 ? void 0 : _a.forEach((l) => {
252
- const e = c.translation[l];
253
- if (e && e.status === 'INIT')
254
- e.status = 'DISCARDED';
255
- });
256
- (_b = opt.tts) === null || _b === void 0 ? void 0 : _b.forEach((l) => {
257
- const e = c.tts[l];
258
- if (e && e.status === 'INIT')
259
- e.status = 'DISCARDED';
260
- });
261
- });
262
- }
263
- async updateTranslation(roomId, n, lang, opt) {
264
- return this.withChunk(roomId, n, (c) => {
265
- const e = c.translation[lang];
266
- if (!e)
267
- return;
268
- if (opt.translation !== undefined)
269
- e.translation = opt.translation;
270
- if (opt.status !== undefined)
271
- e.status = opt.status;
272
- });
273
- }
274
- async updateTranslationInBulk(roomId, n, dict, status = 'READY') {
275
- return this.withChunk(roomId, n, (c) => {
276
- Object.entries(dict).forEach(([l, txt]) => {
277
- if (!c.translation[l])
278
- return;
279
- c.translation[l].translation = txt;
280
- c.translation[l].status = status;
281
- });
282
- });
283
- }
284
- async updateTts(roomId, n, lang, opt) {
285
- return this.withChunk(roomId, n, (c) => {
286
- const e = c.tts[lang];
287
- if (!e)
288
- return;
289
- if (opt.ttsAudioPath !== undefined)
290
- e.ttsAudioPath = opt.ttsAudioPath;
291
- if (opt.status !== undefined)
292
- e.status = opt.status;
293
- if (opt.isEmitted !== undefined)
294
- e.isEmitted = opt.isEmitted;
295
- });
296
- }
297
- async areTranslationsProcessed(roomId, n) {
298
- const c = await this.getMulingstreamChunkById(roomId, n);
299
- return !!c && Object.values(c.translation).every((t) => t.status !== 'INIT');
300
- }
301
- async getAllReadyTts(roomId, lang) {
302
- var _a;
303
- const chunks = (_a = (await this.getMulingstreamChunksByRoom(roomId))) !== null && _a !== void 0 ? _a : [];
304
- if (!chunks.length)
305
- return [];
306
- chunks.sort((a, b) => a.chunkNumber - b.chunkNumber);
307
- let lastIdx = -1;
308
- for (let i = chunks.length - 1; i >= 0; i--)
309
- if (chunks[i].tts[lang]) {
310
- lastIdx = i;
311
- break;
312
- }
313
- if (lastIdx === -1)
314
- return [];
315
- let firstIdx = lastIdx;
316
- for (let i = lastIdx - 1; i >= 0; i--) {
317
- if (!chunks[i].tts[lang])
318
- break;
319
- firstIdx = i;
320
- }
321
- const window = chunks.slice(firstIdx, lastIdx + 1);
322
- let lastDone = -1;
323
- for (let i = window.length - 1; i >= 0; i--) {
324
- const s = window[i].tts[lang].status;
325
- if (s === 'USED' || s === 'DISCARDED') {
326
- lastDone = i;
327
- break;
328
- }
329
- }
330
- const ready = [];
331
- let blocked = false;
332
- const now = Date.now();
333
- for (let i = lastDone + 1; i < window.length; i++) {
334
- const entry = window[i].tts[lang];
335
- const audio = window[i].audioChunk;
336
- if (entry.status === 'INIT') {
337
- if (now - window[i].createdAt > this.getTimeout(audio.start, audio.end))
338
- entry.status = 'DISCARDED';
339
- else
340
- blocked = true;
341
- continue;
342
- }
343
- if (entry.status === 'READY') {
344
- if (blocked)
345
- break;
346
- ready.push(window[i]);
347
- continue;
348
- }
349
- break;
350
- }
351
- if (!ready.length || blocked) {
352
- const p = this.redisClient.pipeline();
353
- window.forEach((c) => p.hset(this.chunkHashKey(c.chunkId), { tts: this.serialize(c.tts) }));
354
- await p.exec();
355
- }
356
- return ready;
357
- }
358
- }
359
- exports.MulingstreamChunkManager = MulingstreamChunkManager;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MulingstreamChunkManager = void 0;
4
+ const uuid_1 = require("uuid");
5
+ const EXPIRATION = 12 * 60 * 60;
6
+ const ROOM_ARRAY_LENGTH = 50;
7
+ class MulingstreamChunkManager {
8
+ constructor(redisClient) {
9
+ this.redisClient = redisClient;
10
+ }
11
+ roomZsetKey(roomId) {
12
+ return `room:${roomId}:chunks`;
13
+ }
14
+ chunkHashKey(chunkId) {
15
+ return `chunk:${chunkId}`;
16
+ }
17
+ generateChunkId(roomId, chunkNumber) {
18
+ return `[${roomId}]-[${chunkNumber}]-[${(0, uuid_1.v4)()}]`;
19
+ }
20
+ serialize(value) {
21
+ return JSON.stringify(value);
22
+ }
23
+ deserialize(v) {
24
+ return v ? JSON.parse(v) : undefined;
25
+ }
26
+ hashToChunk(h) {
27
+ return {
28
+ chunkId: h.chunkId,
29
+ roomId: h.roomId,
30
+ chunkNumber: parseInt(h.chunkNumber, 10),
31
+ language: h.language,
32
+ sttProviders: this.deserialize(h.sttProviders),
33
+ targetLanguages: this.deserialize(h.targetLanguages),
34
+ shortCodeTargetLanguages: this.deserialize(h.shortCodeTargetLanguages),
35
+ finalTranscription: h.finalTranscription,
36
+ sttStatus: h.sttStatus,
37
+ createdAt: parseInt(h.createdAt, 10),
38
+ audioChunk: this.deserialize(h.audioChunk),
39
+ stt: this.deserialize(h.stt),
40
+ translation: this.deserialize(h.translation),
41
+ tts: this.deserialize(h.tts)
42
+ };
43
+ }
44
+ getTimeout(start, end) {
45
+ return 25000;
46
+ }
47
+ async initRoom(roomId) {
48
+ const exists = await this.redisClient.exists(this.roomZsetKey(roomId));
49
+ if (exists)
50
+ return false;
51
+ await this.redisClient.expire(this.roomZsetKey(roomId), EXPIRATION);
52
+ return true;
53
+ }
54
+ async getRooms() {
55
+ const keys = await this.redisClient.keys('room:*:chunks');
56
+ return keys.map((k) => k.replace(/^room:(.*):chunks$/, '$1'));
57
+ }
58
+ async getMulingstreamChunksByRoom(roomId) {
59
+ const ids = await this.redisClient.zrange(this.roomZsetKey(roomId), 0, -1);
60
+ if (!ids.length)
61
+ return null;
62
+ const pipe = this.redisClient.pipeline();
63
+ ids.forEach((cid) => pipe.hgetall(this.chunkHashKey(cid)));
64
+ const res = await pipe.exec();
65
+ if (!res)
66
+ return null;
67
+ return res === null || res === void 0 ? void 0 : res.map(([, d]) => this.hashToChunk(d));
68
+ }
69
+ getRoomById(roomId) {
70
+ return this.getMulingstreamChunksByRoom(roomId);
71
+ }
72
+ async addMulingstreamChunk(params) {
73
+ var _a, _b;
74
+ const { roomId, chunkNumber, language, start, end, duration, isFirst, isLast, sttProviders, targetLanguages, shortCodeTargetLanguages } = params;
75
+ if (chunkNumber === 1) {
76
+ const old = await this.redisClient.zrange(this.roomZsetKey(roomId), 0, -1);
77
+ if (old.length) {
78
+ const p = this.redisClient.pipeline();
79
+ old.forEach((cid) => p.unlink(this.chunkHashKey(cid)));
80
+ p.del(this.roomZsetKey(roomId));
81
+ await p.exec();
82
+ }
83
+ }
84
+ else {
85
+ const dup = await this.redisClient.zrangebyscore(this.roomZsetKey(roomId), chunkNumber, chunkNumber);
86
+ if (dup.length) {
87
+ const p = this.redisClient.pipeline();
88
+ dup.forEach((cid) => p.unlink(this.chunkHashKey(cid)));
89
+ p.zrem(this.roomZsetKey(roomId), ...dup);
90
+ await p.exec();
91
+ }
92
+ }
93
+ const chunkId = this.generateChunkId(roomId, chunkNumber);
94
+ const audioChunk = { start, end, duration, isFirst, isLast, audioFilePath: '' };
95
+ const stt = {};
96
+ sttProviders.forEach((p) => (stt[p.service] = { transcription: '', model: p.model, status: 'INIT' }));
97
+ const translation = {};
98
+ const tts = {};
99
+ shortCodeTargetLanguages.forEach((l) => {
100
+ translation[l] = { translation: '', status: 'INIT' };
101
+ tts[l] = { ttsAudioPath: '', status: 'INIT', isEmitted: false };
102
+ });
103
+ const createdAt = Date.now();
104
+ const chunk = {
105
+ chunkId,
106
+ roomId,
107
+ chunkNumber,
108
+ language,
109
+ sttProviders,
110
+ targetLanguages,
111
+ shortCodeTargetLanguages,
112
+ finalTranscription: '',
113
+ sttStatus: 'INIT',
114
+ createdAt,
115
+ audioChunk,
116
+ stt,
117
+ translation,
118
+ tts
119
+ };
120
+ const hash = {
121
+ chunkId,
122
+ roomId,
123
+ chunkNumber: String(chunkNumber),
124
+ language,
125
+ sttProviders: this.serialize(sttProviders),
126
+ targetLanguages: this.serialize(targetLanguages),
127
+ shortCodeTargetLanguages: this.serialize(shortCodeTargetLanguages),
128
+ finalTranscription: '',
129
+ sttStatus: 'INIT',
130
+ createdAt: String(createdAt),
131
+ audioChunk: this.serialize(audioChunk),
132
+ stt: this.serialize(stt),
133
+ translation: this.serialize(translation),
134
+ tts: this.serialize(tts)
135
+ };
136
+ const pipe = this.redisClient.pipeline();
137
+ pipe.hset(this.chunkHashKey(chunkId), hash);
138
+ pipe.expire(this.chunkHashKey(chunkId), EXPIRATION);
139
+ pipe.zadd(this.roomZsetKey(roomId), chunkNumber, chunkId);
140
+ pipe.expire(this.roomZsetKey(roomId), EXPIRATION);
141
+ pipe.zrange(this.roomZsetKey(roomId), 0, -ROOM_ARRAY_LENGTH - 1, 'WITHSCORES');
142
+ const execResults = await pipe.exec();
143
+ const oldPairs = ((_b = (_a = execResults === null || execResults === void 0 ? void 0 : execResults[4]) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : []);
144
+ if (Array.isArray(oldPairs) && oldPairs.length) {
145
+ const oldIds = [];
146
+ for (let i = 0; i < oldPairs.length; i += 2)
147
+ oldIds.push(oldPairs[i]);
148
+ const trim = this.redisClient.pipeline();
149
+ trim.zrem(this.roomZsetKey(roomId), ...oldIds);
150
+ oldIds.forEach((cid) => trim.unlink(this.chunkHashKey(cid)));
151
+ await trim.exec();
152
+ }
153
+ return chunk;
154
+ }
155
+ async getChunkId(roomId, n) {
156
+ const ids = await this.redisClient.zrangebyscore(this.roomZsetKey(roomId), n, n);
157
+ return ids.length ? ids[0] : null;
158
+ }
159
+ async getMulingstreamChunkById(roomId, n) {
160
+ const cid = await this.getChunkId(roomId, n);
161
+ if (!cid)
162
+ return null;
163
+ const raw = await this.redisClient.hgetall(this.chunkHashKey(cid));
164
+ return raw.chunkId ? this.hashToChunk(raw) : null;
165
+ }
166
+ async withChunk(roomId, n, fn) {
167
+ const cid = await this.getChunkId(roomId, n);
168
+ if (!cid)
169
+ return null;
170
+ const key = this.chunkHashKey(cid);
171
+ const raw = await this.redisClient.hgetall(key);
172
+ if (!raw.chunkId)
173
+ return null;
174
+ const chunk = this.hashToChunk(raw);
175
+ await fn(chunk);
176
+ const p = this.redisClient.pipeline();
177
+ p.hset(key, {
178
+ finalTranscription: chunk.finalTranscription,
179
+ sttStatus: chunk.sttStatus,
180
+ stt: this.serialize(chunk.stt),
181
+ translation: this.serialize(chunk.translation),
182
+ tts: this.serialize(chunk.tts),
183
+ audioChunk: this.serialize(chunk.audioChunk)
184
+ });
185
+ p.expire(key, EXPIRATION);
186
+ await p.exec();
187
+ return chunk;
188
+ }
189
+ async updateAudioFilePath(roomId, chunkNumber, audioFilePath) {
190
+ return this.withChunk(roomId, chunkNumber, (chunk) => {
191
+ chunk.audioChunk.audioFilePath = audioFilePath;
192
+ });
193
+ }
194
+ async updateStt(roomId, n, service, opt) {
195
+ return this.withChunk(roomId, n, (c) => {
196
+ if (!c.stt[service])
197
+ return;
198
+ if (opt.transcription !== undefined)
199
+ c.stt[service].transcription = opt.transcription;
200
+ if (opt.sttStatus !== undefined)
201
+ c.stt[service].status = opt.sttStatus;
202
+ });
203
+ }
204
+ async updateSttObject(roomId, n, newStt) {
205
+ return this.withChunk(roomId, n, (c) => {
206
+ c.stt = newStt;
207
+ });
208
+ }
209
+ async discardStt(roomId, n) {
210
+ return this.withChunk(roomId, n, (c) => {
211
+ Object.keys(c.stt).forEach((p) => {
212
+ c.stt[p].transcription = '';
213
+ c.stt[p].status = 'DISCARDED';
214
+ });
215
+ c.finalTranscription = '';
216
+ c.sttStatus = 'DISCARDED';
217
+ });
218
+ }
219
+ async updateSttAsUsed(roomId, chunkNumber) {
220
+ return this.withChunk(roomId, chunkNumber, (chunk) => {
221
+ Object.keys(chunk.stt).forEach((sttProvider) => {
222
+ chunk.stt[sttProvider].status = 'USED';
223
+ });
224
+ });
225
+ }
226
+ async updateFinalTranscription(roomId, n, opt) {
227
+ return this.withChunk(roomId, n, (c) => {
228
+ if (opt.transcription !== undefined)
229
+ c.finalTranscription = opt.transcription;
230
+ if (opt.sttStatus !== undefined)
231
+ c.sttStatus = opt.sttStatus;
232
+ });
233
+ }
234
+ async discardPostStt(roomId, n) {
235
+ return this.withChunk(roomId, n, (c) => {
236
+ Object.values(c.translation).forEach((t) => (t.status = 'DISCARDED'));
237
+ Object.values(c.tts).forEach((t) => (t.status = 'DISCARDED'));
238
+ });
239
+ }
240
+ async discardLanguage(roomId, n, lang) {
241
+ return this.withChunk(roomId, n, (c) => {
242
+ if (c.translation[lang])
243
+ c.translation[lang].status = 'DISCARDED';
244
+ if (c.tts[lang])
245
+ c.tts[lang].status = 'DISCARDED';
246
+ });
247
+ }
248
+ async discardLanguages(roomId, n, opt) {
249
+ return this.withChunk(roomId, n, (c) => {
250
+ var _a, _b;
251
+ (_a = opt.translation) === null || _a === void 0 ? void 0 : _a.forEach((l) => {
252
+ const e = c.translation[l];
253
+ if (e && e.status === 'INIT')
254
+ e.status = 'DISCARDED';
255
+ });
256
+ (_b = opt.tts) === null || _b === void 0 ? void 0 : _b.forEach((l) => {
257
+ const e = c.tts[l];
258
+ if (e && e.status === 'INIT')
259
+ e.status = 'DISCARDED';
260
+ });
261
+ });
262
+ }
263
+ async updateTranslation(roomId, n, lang, opt) {
264
+ return this.withChunk(roomId, n, (c) => {
265
+ const e = c.translation[lang];
266
+ if (!e)
267
+ return;
268
+ if (opt.translation !== undefined)
269
+ e.translation = opt.translation;
270
+ if (opt.status !== undefined)
271
+ e.status = opt.status;
272
+ });
273
+ }
274
+ async updateTranslationInBulk(roomId, n, dict, status = 'READY') {
275
+ return this.withChunk(roomId, n, (c) => {
276
+ Object.entries(dict).forEach(([l, txt]) => {
277
+ if (!c.translation[l])
278
+ return;
279
+ c.translation[l].translation = txt;
280
+ c.translation[l].status = status;
281
+ });
282
+ });
283
+ }
284
+ async updateTts(roomId, n, lang, opt) {
285
+ return this.withChunk(roomId, n, (c) => {
286
+ const e = c.tts[lang];
287
+ if (!e)
288
+ return;
289
+ if (opt.ttsAudioPath !== undefined)
290
+ e.ttsAudioPath = opt.ttsAudioPath;
291
+ if (opt.status !== undefined)
292
+ e.status = opt.status;
293
+ if (opt.isEmitted !== undefined)
294
+ e.isEmitted = opt.isEmitted;
295
+ });
296
+ }
297
+ async areTranslationsProcessed(roomId, n) {
298
+ const c = await this.getMulingstreamChunkById(roomId, n);
299
+ return !!c && Object.values(c.translation).every((t) => t.status !== 'INIT');
300
+ }
301
+ async getAllReadyTts(roomId, lang) {
302
+ var _a;
303
+ const chunks = (_a = (await this.getMulingstreamChunksByRoom(roomId))) !== null && _a !== void 0 ? _a : [];
304
+ if (!chunks.length)
305
+ return [];
306
+ chunks.sort((a, b) => a.chunkNumber - b.chunkNumber);
307
+ let lastIdx = -1;
308
+ for (let i = chunks.length - 1; i >= 0; i--)
309
+ if (chunks[i].tts[lang]) {
310
+ lastIdx = i;
311
+ break;
312
+ }
313
+ if (lastIdx === -1)
314
+ return [];
315
+ let firstIdx = lastIdx;
316
+ for (let i = lastIdx - 1; i >= 0; i--) {
317
+ if (!chunks[i].tts[lang])
318
+ break;
319
+ firstIdx = i;
320
+ }
321
+ const window = chunks.slice(firstIdx, lastIdx + 1);
322
+ let lastDone = -1;
323
+ for (let i = window.length - 1; i >= 0; i--) {
324
+ const s = window[i].tts[lang].status;
325
+ if (s === 'USED' || s === 'DISCARDED') {
326
+ lastDone = i;
327
+ break;
328
+ }
329
+ }
330
+ const ready = [];
331
+ let blocked = false;
332
+ const now = Date.now();
333
+ for (let i = lastDone + 1; i < window.length; i++) {
334
+ const entry = window[i].tts[lang];
335
+ const audio = window[i].audioChunk;
336
+ if (entry.status === 'INIT') {
337
+ if (now - window[i].createdAt > this.getTimeout(audio.start, audio.end))
338
+ entry.status = 'DISCARDED';
339
+ else
340
+ blocked = true;
341
+ continue;
342
+ }
343
+ if (entry.status === 'READY') {
344
+ if (blocked)
345
+ break;
346
+ ready.push(window[i]);
347
+ continue;
348
+ }
349
+ break;
350
+ }
351
+ if (!ready.length || blocked) {
352
+ const p = this.redisClient.pipeline();
353
+ window.forEach((c) => p.hset(this.chunkHashKey(c.chunkId), { tts: this.serialize(c.tts) }));
354
+ await p.exec();
355
+ }
356
+ return ready;
357
+ }
358
+ }
359
+ exports.MulingstreamChunkManager = MulingstreamChunkManager;