@mulingai-npm/redis 2.3.0 → 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.
@@ -1,242 +1,242 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MulingstreamChunkManager = void 0;
4
- const EXPIRATION = 12 * 60 * 60; // 12 hours in seconds
5
- const ROOM_ARRAY_LENGTH = 50; // keep only the last 5 elements
6
- class MulingstreamChunkManager {
7
- constructor(redisClient) {
8
- this.redisClient = redisClient;
9
- }
10
- /**
11
- * Initializes a room in Redis as an empty JSON array.
12
- * If the key [roomId] already exists, we do NOT overwrite it.
13
- * Returns true if room was created, false if room already existed.
14
- */
15
- async initRoom(roomId) {
16
- // Check if the key already exists (JSON.GET)
17
- const isRoomExisting = await this.redisClient.jsonGet(`[${roomId}]`, '.');
18
- if (isRoomExisting !== null) {
19
- return false;
20
- }
21
- // Create an empty array at the root
22
- await this.redisClient.jsonSet(`[${roomId}]`, '.', []);
23
- await this.redisClient.expire(`[${roomId}]`, EXPIRATION);
24
- return true;
25
- }
26
- /**
27
- * Returns all rooms. This is naive if you store many other keys in Redis,
28
- * because we search keys for pattern "[*]".
29
- * Adjust as needed if you have a separate naming prefix.
30
- */
31
- async getRooms() {
32
- // e.g., if we store everything as [foo], [bar], etc., we do:
33
- const rooms = await this.redisClient.keys('\\[*\\]');
34
- // This returns the raw keys, e.g. ['[myRoom]', '[anotherRoom]']
35
- // We might want to strip off the brackets:
36
- return rooms.map((k) => k.replace(/^\[|\]$/g, ''));
37
- }
38
- /**
39
- * Returns the entire array of chunks for the given roomId,
40
- * or null if the room doesn't exist in Redis.
41
- */
42
- async getMulingstreamChunksByRoom(roomId) {
43
- // JSON.GET [roomId] .
44
- const chunks = await this.redisClient.jsonGet(`[${roomId}]`, '.');
45
- if (chunks === null) {
46
- return null;
47
- }
48
- return chunks;
49
- }
50
- async getRoomById(roomId) {
51
- return this.getMulingstreamChunksByRoom(roomId);
52
- }
53
- async addMulingstreamChunk(params) {
54
- var _a;
55
- const { roomId, chunkNumber, language, start, end, duration, isFirst, isLast, theme, sttProviders, targetLanguages, shortCodeTargetLanguages } = params;
56
- const audioChunk = {
57
- start,
58
- end,
59
- duration,
60
- isFirst,
61
- isLast,
62
- theme,
63
- processingStart: Date.now()
64
- };
65
- const stt = {};
66
- for (const sttProvider of sttProviders) {
67
- stt[sttProvider] = {
68
- transcription: '',
69
- status: 'INIT'
70
- };
71
- }
72
- const translation = {};
73
- const tts = {};
74
- for (const lang of targetLanguages) {
75
- translation[lang] = {
76
- translation: '',
77
- status: 'INIT'
78
- };
79
- tts[lang] = {
80
- ttsAudioPath: '',
81
- status: 'INIT',
82
- isEmitted: false
83
- };
84
- }
85
- const newChunk = {
86
- roomId,
87
- chunkNumber,
88
- language,
89
- sttProviders,
90
- targetLanguages,
91
- shortCodeTargetLanguages,
92
- finalTranscription: '',
93
- sttStatus: 'INIT',
94
- audioChunk,
95
- stt,
96
- translation,
97
- tts
98
- };
99
- const chunks = (_a = (await this.redisClient.jsonGet(`[${roomId}]`, '.'))) !== null && _a !== void 0 ? _a : [];
100
- const idx = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
101
- if (idx !== -1) {
102
- chunks[idx] = newChunk;
103
- }
104
- else {
105
- chunks.push(newChunk);
106
- if (chunks.length > ROOM_ARRAY_LENGTH) {
107
- chunks.shift();
108
- }
109
- }
110
- await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
111
- await this.redisClient.expire(`[${roomId}]`, EXPIRATION);
112
- }
113
- /**
114
- * Given roomId and chunkNumber, return the single chunk from the array
115
- * or null if not found.
116
- */
117
- async getMulingstreamChunkById(roomId, chunkNumber) {
118
- // Retrieve the entire array
119
- const chunks = await this.getMulingstreamChunksByRoom(roomId);
120
- if (!chunks)
121
- return null;
122
- // Find by chunkNumber
123
- const chunk = chunks.find((c) => c.chunkNumber === chunkNumber);
124
- return chunk || null;
125
- }
126
- /**
127
- * Update STT fields for a given chunk.
128
- * If transcription or sttStatus is null, skip that field.
129
- */
130
- async updateStt(roomId, chunkNumber, sttProvider, options) {
131
- const chunks = await this.getMulingstreamChunksByRoom(roomId);
132
- if (!chunks)
133
- return false;
134
- // Find the chunk
135
- const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
136
- if (chunkIndex === -1)
137
- return false;
138
- const chunk = chunks[chunkIndex];
139
- // If this stt provider doesn't exist, ignore
140
- if (!chunk.stt[sttProvider])
141
- return false;
142
- // Update
143
- if (options.transcription != null) {
144
- chunk.stt[sttProvider].transcription = options.transcription;
145
- }
146
- if (options.sttStatus != null) {
147
- chunk.stt[sttProvider].status = options.sttStatus;
148
- }
149
- // Write back
150
- chunks[chunkIndex] = chunk;
151
- await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
152
- return true;
153
- }
154
- /**
155
- * Update the final transcription field for a chunk.
156
- */
157
- async updateFinalTranscription(roomId, chunkNumber, transcription, sttStatus) {
158
- const chunks = await this.getMulingstreamChunksByRoom(roomId);
159
- if (!chunks)
160
- return false;
161
- // Find the chunk
162
- const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
163
- if (chunkIndex === -1)
164
- return false;
165
- chunks[chunkIndex].finalTranscription = transcription;
166
- chunks[chunkIndex].sttStatus = sttStatus;
167
- // Write back
168
- await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
169
- return true;
170
- }
171
- /**
172
- * Discards all post-STT steps for a given chunk:
173
- * sets all translation[].status & tts[].status to "DISCARDED".
174
- */
175
- async discardPostStt(roomId, chunkNumber) {
176
- const chunks = await this.getMulingstreamChunksByRoom(roomId);
177
- if (!chunks)
178
- return false;
179
- // Find chunk
180
- const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
181
- if (chunkIndex === -1)
182
- return false;
183
- // Discard translation & TTS statuses
184
- const chunk = chunks[chunkIndex];
185
- for (const lang of Object.keys(chunk.translation)) {
186
- chunk.translation[lang].status = 'DISCARDED';
187
- }
188
- for (const lang of Object.keys(chunk.tts)) {
189
- chunk.tts[lang].status = 'DISCARDED';
190
- }
191
- chunks[chunkIndex] = chunk;
192
- await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
193
- return true;
194
- }
195
- /**
196
- * Discards a specific language in both translation and tts for a chunk.
197
- */
198
- async discardLanguage(roomId, chunkNumber, language) {
199
- const chunks = await this.getMulingstreamChunksByRoom(roomId);
200
- if (!chunks)
201
- return false;
202
- const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
203
- if (chunkIndex === -1)
204
- return false;
205
- const chunk = chunks[chunkIndex];
206
- if (chunk.translation[language]) {
207
- chunk.translation[language].status = 'DISCARDED';
208
- }
209
- if (chunk.tts[language]) {
210
- chunk.tts[language].status = 'DISCARDED';
211
- }
212
- chunks[chunkIndex] = chunk;
213
- await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
214
- return true;
215
- }
216
- async updateTranslation(roomId, chunkNumber, language, options) {
217
- // Fetch all chunks for this room
218
- const chunks = await this.getMulingstreamChunksByRoom(roomId);
219
- if (!chunks)
220
- return false;
221
- // Locate the target chunk
222
- const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
223
- if (chunkIndex === -1)
224
- return false;
225
- const chunk = chunks[chunkIndex];
226
- // Make sure the requested language exists in this chunk
227
- if (!chunk.translation[language]) {
228
- return false;
229
- }
230
- if (options.translation !== undefined) {
231
- chunk.translation[language].translation = options.translation;
232
- }
233
- if (options.status !== undefined) {
234
- chunk.translation[language].status = options.status;
235
- }
236
- // Persist the whole array back to Redis
237
- chunks[chunkIndex] = chunk;
238
- await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
239
- return true;
240
- }
241
- }
242
- exports.MulingstreamChunkManager = MulingstreamChunkManager;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MulingstreamChunkManager = void 0;
4
+ const EXPIRATION = 12 * 60 * 60; // 12 hours in seconds
5
+ const ROOM_ARRAY_LENGTH = 50; // keep only the last 5 elements
6
+ class MulingstreamChunkManager {
7
+ constructor(redisClient) {
8
+ this.redisClient = redisClient;
9
+ }
10
+ /**
11
+ * Initializes a room in Redis as an empty JSON array.
12
+ * If the key [roomId] already exists, we do NOT overwrite it.
13
+ * Returns true if room was created, false if room already existed.
14
+ */
15
+ async initRoom(roomId) {
16
+ // Check if the key already exists (JSON.GET)
17
+ const isRoomExisting = await this.redisClient.jsonGet(`[${roomId}]`, '.');
18
+ if (isRoomExisting !== null) {
19
+ return false;
20
+ }
21
+ // Create an empty array at the root
22
+ await this.redisClient.jsonSet(`[${roomId}]`, '.', []);
23
+ await this.redisClient.expire(`[${roomId}]`, EXPIRATION);
24
+ return true;
25
+ }
26
+ /**
27
+ * Returns all rooms. This is naive if you store many other keys in Redis,
28
+ * because we search keys for pattern "[*]".
29
+ * Adjust as needed if you have a separate naming prefix.
30
+ */
31
+ async getRooms() {
32
+ // e.g., if we store everything as [foo], [bar], etc., we do:
33
+ const rooms = await this.redisClient.keys('\\[*\\]');
34
+ // This returns the raw keys, e.g. ['[myRoom]', '[anotherRoom]']
35
+ // We might want to strip off the brackets:
36
+ return rooms.map((k) => k.replace(/^\[|\]$/g, ''));
37
+ }
38
+ /**
39
+ * Returns the entire array of chunks for the given roomId,
40
+ * or null if the room doesn't exist in Redis.
41
+ */
42
+ async getMulingstreamChunksByRoom(roomId) {
43
+ // JSON.GET [roomId] .
44
+ const chunks = await this.redisClient.jsonGet(`[${roomId}]`, '.');
45
+ if (chunks === null) {
46
+ return null;
47
+ }
48
+ return chunks;
49
+ }
50
+ async getRoomById(roomId) {
51
+ return this.getMulingstreamChunksByRoom(roomId);
52
+ }
53
+ async addMulingstreamChunk(params) {
54
+ var _a;
55
+ const { roomId, chunkNumber, language, start, end, duration, isFirst, isLast, theme, sttProviders, targetLanguages, shortCodeTargetLanguages } = params;
56
+ const audioChunk = {
57
+ start,
58
+ end,
59
+ duration,
60
+ isFirst,
61
+ isLast,
62
+ theme,
63
+ processingStart: Date.now()
64
+ };
65
+ const stt = {};
66
+ for (const sttProvider of sttProviders) {
67
+ stt[sttProvider] = {
68
+ transcription: '',
69
+ status: 'INIT'
70
+ };
71
+ }
72
+ const translation = {};
73
+ const tts = {};
74
+ for (const lang of shortCodeTargetLanguages) {
75
+ translation[lang] = {
76
+ translation: '',
77
+ status: 'INIT'
78
+ };
79
+ tts[lang] = {
80
+ ttsAudioPath: '',
81
+ status: 'INIT',
82
+ isEmitted: false
83
+ };
84
+ }
85
+ const newChunk = {
86
+ roomId,
87
+ chunkNumber,
88
+ language,
89
+ sttProviders,
90
+ targetLanguages,
91
+ shortCodeTargetLanguages,
92
+ finalTranscription: '',
93
+ sttStatus: 'INIT',
94
+ audioChunk,
95
+ stt,
96
+ translation,
97
+ tts
98
+ };
99
+ const chunks = (_a = (await this.redisClient.jsonGet(`[${roomId}]`, '.'))) !== null && _a !== void 0 ? _a : [];
100
+ const idx = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
101
+ if (idx !== -1) {
102
+ chunks[idx] = newChunk;
103
+ }
104
+ else {
105
+ chunks.push(newChunk);
106
+ if (chunks.length > ROOM_ARRAY_LENGTH) {
107
+ chunks.shift();
108
+ }
109
+ }
110
+ await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
111
+ await this.redisClient.expire(`[${roomId}]`, EXPIRATION);
112
+ }
113
+ /**
114
+ * Given roomId and chunkNumber, return the single chunk from the array
115
+ * or null if not found.
116
+ */
117
+ async getMulingstreamChunkById(roomId, chunkNumber) {
118
+ // Retrieve the entire array
119
+ const chunks = await this.getMulingstreamChunksByRoom(roomId);
120
+ if (!chunks)
121
+ return null;
122
+ // Find by chunkNumber
123
+ const chunk = chunks.find((c) => c.chunkNumber === chunkNumber);
124
+ return chunk || null;
125
+ }
126
+ /**
127
+ * Update STT fields for a given chunk.
128
+ * If transcription or sttStatus is null, skip that field.
129
+ */
130
+ async updateStt(roomId, chunkNumber, sttProvider, options) {
131
+ const chunks = await this.getMulingstreamChunksByRoom(roomId);
132
+ if (!chunks)
133
+ return false;
134
+ // Find the chunk
135
+ const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
136
+ if (chunkIndex === -1)
137
+ return false;
138
+ const chunk = chunks[chunkIndex];
139
+ // If this stt provider doesn't exist, ignore
140
+ if (!chunk.stt[sttProvider])
141
+ return false;
142
+ // Update
143
+ if (options.transcription != null) {
144
+ chunk.stt[sttProvider].transcription = options.transcription;
145
+ }
146
+ if (options.sttStatus != null) {
147
+ chunk.stt[sttProvider].status = options.sttStatus;
148
+ }
149
+ // Write back
150
+ chunks[chunkIndex] = chunk;
151
+ await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
152
+ return true;
153
+ }
154
+ /**
155
+ * Update the final transcription field for a chunk.
156
+ */
157
+ async updateFinalTranscription(roomId, chunkNumber, transcription, sttStatus) {
158
+ const chunks = await this.getMulingstreamChunksByRoom(roomId);
159
+ if (!chunks)
160
+ return false;
161
+ // Find the chunk
162
+ const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
163
+ if (chunkIndex === -1)
164
+ return false;
165
+ chunks[chunkIndex].finalTranscription = transcription;
166
+ chunks[chunkIndex].sttStatus = sttStatus;
167
+ // Write back
168
+ await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
169
+ return true;
170
+ }
171
+ /**
172
+ * Discards all post-STT steps for a given chunk:
173
+ * sets all translation[].status & tts[].status to "DISCARDED".
174
+ */
175
+ async discardPostStt(roomId, chunkNumber) {
176
+ const chunks = await this.getMulingstreamChunksByRoom(roomId);
177
+ if (!chunks)
178
+ return false;
179
+ // Find chunk
180
+ const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
181
+ if (chunkIndex === -1)
182
+ return false;
183
+ // Discard translation & TTS statuses
184
+ const chunk = chunks[chunkIndex];
185
+ for (const lang of Object.keys(chunk.translation)) {
186
+ chunk.translation[lang].status = 'DISCARDED';
187
+ }
188
+ for (const lang of Object.keys(chunk.tts)) {
189
+ chunk.tts[lang].status = 'DISCARDED';
190
+ }
191
+ chunks[chunkIndex] = chunk;
192
+ await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
193
+ return true;
194
+ }
195
+ /**
196
+ * Discards a specific language in both translation and tts for a chunk.
197
+ */
198
+ async discardLanguage(roomId, chunkNumber, language) {
199
+ const chunks = await this.getMulingstreamChunksByRoom(roomId);
200
+ if (!chunks)
201
+ return false;
202
+ const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
203
+ if (chunkIndex === -1)
204
+ return false;
205
+ const chunk = chunks[chunkIndex];
206
+ if (chunk.translation[language]) {
207
+ chunk.translation[language].status = 'DISCARDED';
208
+ }
209
+ if (chunk.tts[language]) {
210
+ chunk.tts[language].status = 'DISCARDED';
211
+ }
212
+ chunks[chunkIndex] = chunk;
213
+ await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
214
+ return true;
215
+ }
216
+ async updateTranslation(roomId, chunkNumber, language, options) {
217
+ // Fetch all chunks for this room
218
+ const chunks = await this.getMulingstreamChunksByRoom(roomId);
219
+ if (!chunks)
220
+ return false;
221
+ // Locate the target chunk
222
+ const chunkIndex = chunks.findIndex((c) => c.chunkNumber === chunkNumber);
223
+ if (chunkIndex === -1)
224
+ return false;
225
+ const chunk = chunks[chunkIndex];
226
+ // Make sure the requested language exists in this chunk
227
+ if (!chunk.translation[language]) {
228
+ return false;
229
+ }
230
+ if (options.translation !== undefined) {
231
+ chunk.translation[language].translation = options.translation;
232
+ }
233
+ if (options.status !== undefined) {
234
+ chunk.translation[language].status = options.status;
235
+ }
236
+ // Persist the whole array back to Redis
237
+ chunks[chunkIndex] = chunk;
238
+ await this.redisClient.jsonSet(`[${roomId}]`, '.', chunks);
239
+ return true;
240
+ }
241
+ }
242
+ exports.MulingstreamChunkManager = MulingstreamChunkManager;
@@ -1,29 +1,29 @@
1
- import { RedisClient } from '../redis-client';
2
- export type MulingstreamListenerData = {
3
- listenerId: string;
4
- roomId: string;
5
- socketId?: string;
6
- token: string;
7
- name?: string;
8
- firstJoined: number;
9
- language?: string;
10
- isActive?: boolean;
11
- };
12
- export declare class MulingstreamListenerManager {
13
- private redisClient;
14
- constructor(redisClient: RedisClient);
15
- private parseHashData;
16
- addListener(listenerData: Omit<MulingstreamListenerData, 'listenerId'>): Promise<string>;
17
- getAllListeners(): Promise<MulingstreamListenerData[]>;
18
- getListenersByRoom(roomId: string): Promise<MulingstreamListenerData[]>;
19
- getListener(listenerIdOrToken: string): Promise<MulingstreamListenerData | null>;
20
- removeListenerByToken(token: string): Promise<boolean>;
21
- updateNameLanguage(listenerIdOrToken: string, name: string, language: string): Promise<boolean>;
22
- updateSocketId(listenerIdOrToken: string, socketId: string): Promise<boolean>;
23
- getTargetSocketIdsByRoomLanguage(roomId: string, language: string): Promise<string[]>;
24
- /**
25
- * Returns an array of unique languages for the given room, from highest frequency to lowest.
26
- * If a listener has no language (empty string / undefined), it is ignored.
27
- */
28
- getUniqueLanguagesByRoom(roomId: string): Promise<string[]>;
29
- }
1
+ import { RedisClient } from '../redis-client';
2
+ export type MulingstreamListenerData = {
3
+ listenerId: string;
4
+ roomId: string;
5
+ socketId?: string;
6
+ token: string;
7
+ name?: string;
8
+ firstJoined: number;
9
+ language?: string;
10
+ isActive?: boolean;
11
+ };
12
+ export declare class MulingstreamListenerManager {
13
+ private redisClient;
14
+ constructor(redisClient: RedisClient);
15
+ private parseHashData;
16
+ addListener(listenerData: Omit<MulingstreamListenerData, 'listenerId'>): Promise<string>;
17
+ getAllListeners(): Promise<MulingstreamListenerData[]>;
18
+ getListenersByRoom(roomId: string): Promise<MulingstreamListenerData[]>;
19
+ getListener(listenerIdOrToken: string): Promise<MulingstreamListenerData | null>;
20
+ removeListenerByToken(token: string): Promise<boolean>;
21
+ updateNameLanguage(listenerIdOrToken: string, name: string, language: string): Promise<boolean>;
22
+ updateSocketId(listenerIdOrToken: string, socketId: string): Promise<boolean>;
23
+ getTargetSocketIdsByRoomLanguage(roomId: string, language: string): Promise<string[]>;
24
+ /**
25
+ * Returns an array of unique languages for the given room, from highest frequency to lowest.
26
+ * If a listener has no language (empty string / undefined), it is ignored.
27
+ */
28
+ getUniqueLanguagesByRoom(roomId: string): Promise<string[]>;
29
+ }