@mulingai-npm/redis 3.29.0 → 3.29.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.
@@ -6,9 +6,7 @@ export interface ChunkLogOptions {
6
6
  language?: boolean;
7
7
  processLength?: boolean;
8
8
  finalTranscription?: boolean;
9
- sttStatus?: boolean;
10
- audioFilePath?: boolean;
11
- stt?: boolean;
9
+ streamingChunk?: boolean;
12
10
  translation?: boolean;
13
11
  tts?: boolean;
14
12
  label?: string;
@@ -5,13 +5,11 @@ const mulingstream_chunk_manager_1 = require("../managers/mulingstream-chunk-man
5
5
  const defaults = {
6
6
  chunkId: false,
7
7
  chunkNumber: true,
8
- audioFilePath: true,
9
8
  roomId: false,
10
9
  processLength: false,
11
10
  language: false,
12
11
  finalTranscription: true,
13
- sttStatus: true,
14
- stt: false,
12
+ streamingChunk: false,
15
13
  translation: false,
16
14
  tts: true,
17
15
  label: ''
@@ -62,18 +60,14 @@ class MulingstreamChunkLogger extends mulingstream_chunk_manager_1.MulingstreamC
62
60
  out.roomId = chunk.roomId;
63
61
  if (o.chunkNumber)
64
62
  out.chunkNumber = chunk.chunkNumber;
65
- if (o.audioFilePath)
66
- out.audioFilePath = chunk.audioChunk.audioFilePath;
63
+ if (o.streamingChunk)
64
+ out.streamingChunk = chunk.streamingChunk;
67
65
  if (o.processLength)
68
66
  out.processLength = Date.now() - chunk.createdAt + 'ms';
69
67
  if (o.language)
70
68
  out.language = chunk.language;
71
69
  if (o.finalTranscription)
72
70
  out.finalTranscription = chunk.finalTranscription;
73
- if (o.sttStatus)
74
- out.sttStatus = chunk.sttStatus;
75
- if (o.stt)
76
- out.stt = chunk.stt;
77
71
  if (o.translation)
78
72
  out.translation = chunk.translation;
79
73
  if (o.tts)
@@ -1,36 +1,30 @@
1
1
  import { RedisClient } from '../redis-client';
2
2
  export type StepStatus = 'INIT' | 'DISCARDED' | 'READY' | 'USED';
3
- export type SttService = 'azure' | 'whisper' | 'deepgram';
3
+ export type SttService = 'azure' | 'deepgram';
4
4
  export type SttProvider = {
5
5
  service: SttService;
6
6
  model?: string;
7
7
  };
8
+ export type StreamingChunkData = {
9
+ startMs: number;
10
+ endMs: number;
11
+ durationMs: number;
12
+ confidence: number;
13
+ wordCount: number;
14
+ speechFinal: boolean;
15
+ provider: string;
16
+ model?: string;
17
+ };
8
18
  export type MulingstreamChunkData = {
9
19
  chunkId: string;
10
20
  roomId: string;
11
21
  chunkNumber: number;
12
22
  language: string;
13
- sttProviders: SttProvider[];
14
23
  targetLanguages: string[];
15
24
  shortCodeTargetLanguages: string[];
16
25
  finalTranscription: string;
17
- sttStatus: StepStatus;
18
26
  createdAt: number;
19
- audioChunk: {
20
- start: number;
21
- end: number;
22
- duration: number;
23
- isFirst: boolean;
24
- isLast: boolean;
25
- audioFilePath: string;
26
- };
27
- stt: {
28
- [service: string]: {
29
- transcription: string;
30
- model?: string;
31
- status: StepStatus;
32
- };
33
- };
27
+ streamingChunk: StreamingChunkData;
34
28
  translation: {
35
29
  [language: string]: {
36
30
  translation: string;
@@ -60,39 +54,31 @@ export declare class MulingstreamChunkManager {
60
54
  getRooms(): Promise<string[]>;
61
55
  getMulingstreamChunksByRoom(roomId: string): Promise<MulingstreamChunkData[] | null>;
62
56
  getRoomById(roomId: string): Promise<MulingstreamChunkData[]>;
63
- addMulingstreamChunk(params: {
57
+ /**
58
+ * Add a streaming chunk with STT already completed
59
+ * This is the primary method for streaming-based transcription
60
+ */
61
+ addStreamingChunk(params: {
64
62
  roomId: string;
65
63
  chunkNumber: number;
66
64
  language: string;
67
- start: number;
68
- end: number;
69
- duration: number;
70
- isFirst: boolean;
71
- isLast: boolean;
72
- sttProviders: SttProvider[];
65
+ transcription: string;
66
+ sttProvider: SttProvider;
73
67
  targetLanguages: string[];
74
68
  shortCodeTargetLanguages: string[];
69
+ streamingData: {
70
+ startMs: number;
71
+ endMs: number;
72
+ durationMs: number;
73
+ confidence: number;
74
+ wordCount: number;
75
+ speechFinal: boolean;
76
+ };
75
77
  }): Promise<MulingstreamChunkData>;
76
78
  private getChunkId;
77
79
  getMulingstreamChunkById(roomId: string, n: number): Promise<MulingstreamChunkData>;
78
80
  private withChunk;
79
- updateAudioFilePath(roomId: string, chunkNumber: number, audioFilePath: string): Promise<MulingstreamChunkData | null>;
80
- updateStt(roomId: string, n: number, service: SttService, opt: {
81
- transcription?: string;
82
- sttStatus?: StepStatus;
83
- }): Promise<MulingstreamChunkData | null>;
84
- updateSttObject(roomId: string, n: number, newStt: Record<string, {
85
- transcription: string;
86
- model?: string;
87
- status: StepStatus;
88
- }>): Promise<MulingstreamChunkData | null>;
89
- discardStt(roomId: string, n: number): Promise<MulingstreamChunkData | null>;
90
- updateSttAsUsed(roomId: string, chunkNumber: number): Promise<MulingstreamChunkData | null>;
91
- updateFinalTranscription(roomId: string, n: number, opt: {
92
- transcription?: string;
93
- sttStatus?: StepStatus;
94
- }): Promise<MulingstreamChunkData | null>;
95
- discardPostStt(roomId: string, n: number): Promise<MulingstreamChunkData | null>;
81
+ updateFinalTranscription(roomId: string, n: number, transcription: string): Promise<MulingstreamChunkData | null>;
96
82
  discardLanguage(roomId: string, n: number, lang: string): Promise<MulingstreamChunkData | null>;
97
83
  discardLanguages(roomId: string, n: number, opt: {
98
84
  translation?: string[];
@@ -29,19 +29,16 @@ class MulingstreamChunkManager {
29
29
  roomId: h.roomId,
30
30
  chunkNumber: parseInt(h.chunkNumber, 10),
31
31
  language: h.language,
32
- sttProviders: this.deserialize(h.sttProviders),
33
32
  targetLanguages: this.deserialize(h.targetLanguages),
34
33
  shortCodeTargetLanguages: this.deserialize(h.shortCodeTargetLanguages),
35
34
  finalTranscription: h.finalTranscription,
36
- sttStatus: h.sttStatus,
37
35
  createdAt: parseInt(h.createdAt, 10),
38
- audioChunk: this.deserialize(h.audioChunk),
39
- stt: this.deserialize(h.stt),
36
+ streamingChunk: this.deserialize(h.streamingChunk),
40
37
  translation: this.deserialize(h.translation),
41
38
  tts: this.deserialize(h.tts)
42
39
  };
43
40
  }
44
- getTimeout(start, end) {
41
+ getTimeout() {
45
42
  return 25000;
46
43
  }
47
44
  async initRoom(roomId) {
@@ -69,9 +66,14 @@ class MulingstreamChunkManager {
69
66
  getRoomById(roomId) {
70
67
  return this.getMulingstreamChunksByRoom(roomId);
71
68
  }
72
- async addMulingstreamChunk(params) {
69
+ /**
70
+ * Add a streaming chunk with STT already completed
71
+ * This is the primary method for streaming-based transcription
72
+ */
73
+ async addStreamingChunk(params) {
73
74
  var _a, _b;
74
- const { roomId, chunkNumber, language, start, end, duration, isFirst, isLast, sttProviders, targetLanguages, shortCodeTargetLanguages } = params;
75
+ const { roomId, chunkNumber, language, transcription, sttProvider, targetLanguages, shortCodeTargetLanguages, streamingData } = params;
76
+ // Clear room if this is first chunk (new session)
75
77
  if (chunkNumber === 1) {
76
78
  const old = await this.redisClient.zrange(this.roomZsetKey(roomId), 0, -1);
77
79
  if (old.length) {
@@ -82,6 +84,7 @@ class MulingstreamChunkManager {
82
84
  }
83
85
  }
84
86
  else {
87
+ // Remove duplicate chunk numbers
85
88
  const dup = await this.redisClient.zrangebyscore(this.roomZsetKey(roomId), chunkNumber, chunkNumber);
86
89
  if (dup.length) {
87
90
  const p = this.redisClient.pipeline();
@@ -91,13 +94,20 @@ class MulingstreamChunkManager {
91
94
  }
92
95
  }
93
96
  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
+ // Streaming chunk data (includes STT provider info)
98
+ const streamingChunk = {
99
+ startMs: streamingData.startMs,
100
+ endMs: streamingData.endMs,
101
+ durationMs: streamingData.durationMs,
102
+ confidence: streamingData.confidence,
103
+ wordCount: streamingData.wordCount,
104
+ speechFinal: streamingData.speechFinal,
105
+ provider: sttProvider.service,
106
+ model: sttProvider.model
107
+ };
97
108
  const translation = {};
98
109
  const tts = {};
99
- // Use ISO codes (targetLanguages) for translation/tts keys, NOT short codes
100
- // This ensures consistency throughout the pipeline - we can always derive short codes from ISO codes when needed
110
+ // Use ISO codes (targetLanguages) for translation/tts keys
101
111
  targetLanguages.forEach((l) => {
102
112
  translation[l] = { translation: '', status: 'INIT' };
103
113
  tts[l] = { ttsAudioPath: '', status: 'INIT', isEmitted: false };
@@ -108,14 +118,11 @@ class MulingstreamChunkManager {
108
118
  roomId,
109
119
  chunkNumber,
110
120
  language,
111
- sttProviders,
112
121
  targetLanguages,
113
122
  shortCodeTargetLanguages,
114
- finalTranscription: '',
115
- sttStatus: 'INIT',
123
+ finalTranscription: transcription,
116
124
  createdAt,
117
- audioChunk,
118
- stt,
125
+ streamingChunk,
119
126
  translation,
120
127
  tts
121
128
  };
@@ -124,14 +131,11 @@ class MulingstreamChunkManager {
124
131
  roomId,
125
132
  chunkNumber: String(chunkNumber),
126
133
  language,
127
- sttProviders: this.serialize(sttProviders),
128
134
  targetLanguages: this.serialize(targetLanguages),
129
135
  shortCodeTargetLanguages: this.serialize(shortCodeTargetLanguages),
130
- finalTranscription: '',
131
- sttStatus: 'INIT',
136
+ finalTranscription: transcription,
132
137
  createdAt: String(createdAt),
133
- audioChunk: this.serialize(audioChunk),
134
- stt: this.serialize(stt),
138
+ streamingChunk: this.serialize(streamingChunk),
135
139
  translation: this.serialize(translation),
136
140
  tts: this.serialize(tts)
137
141
  };
@@ -143,6 +147,7 @@ class MulingstreamChunkManager {
143
147
  pipe.zrange(this.roomZsetKey(roomId), 0, -ROOM_ARRAY_LENGTH - 1, 'WITHSCORES');
144
148
  const execResults = await pipe.exec();
145
149
  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 : []);
150
+ // Trim old chunks if room exceeds max length
146
151
  if (Array.isArray(oldPairs) && oldPairs.length) {
147
152
  const oldIds = [];
148
153
  for (let i = 0; i < oldPairs.length; i += 2)
@@ -178,65 +183,17 @@ class MulingstreamChunkManager {
178
183
  const p = this.redisClient.pipeline();
179
184
  p.hset(key, {
180
185
  finalTranscription: chunk.finalTranscription,
181
- sttStatus: chunk.sttStatus,
182
- stt: this.serialize(chunk.stt),
183
186
  translation: this.serialize(chunk.translation),
184
187
  tts: this.serialize(chunk.tts),
185
- audioChunk: this.serialize(chunk.audioChunk)
188
+ streamingChunk: this.serialize(chunk.streamingChunk)
186
189
  });
187
190
  p.expire(key, EXPIRATION);
188
191
  await p.exec();
189
192
  return chunk;
190
193
  }
191
- async updateAudioFilePath(roomId, chunkNumber, audioFilePath) {
192
- return this.withChunk(roomId, chunkNumber, (chunk) => {
193
- chunk.audioChunk.audioFilePath = audioFilePath;
194
- });
195
- }
196
- async updateStt(roomId, n, service, opt) {
197
- return this.withChunk(roomId, n, (c) => {
198
- if (!c.stt[service])
199
- return;
200
- if (opt.transcription !== undefined)
201
- c.stt[service].transcription = opt.transcription;
202
- if (opt.sttStatus !== undefined)
203
- c.stt[service].status = opt.sttStatus;
204
- });
205
- }
206
- async updateSttObject(roomId, n, newStt) {
207
- return this.withChunk(roomId, n, (c) => {
208
- c.stt = newStt;
209
- });
210
- }
211
- async discardStt(roomId, n) {
212
- return this.withChunk(roomId, n, (c) => {
213
- Object.keys(c.stt).forEach((p) => {
214
- c.stt[p].transcription = '';
215
- c.stt[p].status = 'DISCARDED';
216
- });
217
- c.finalTranscription = '';
218
- c.sttStatus = 'DISCARDED';
219
- });
220
- }
221
- async updateSttAsUsed(roomId, chunkNumber) {
222
- return this.withChunk(roomId, chunkNumber, (chunk) => {
223
- Object.keys(chunk.stt).forEach((sttProvider) => {
224
- chunk.stt[sttProvider].status = 'USED';
225
- });
226
- });
227
- }
228
- async updateFinalTranscription(roomId, n, opt) {
229
- return this.withChunk(roomId, n, (c) => {
230
- if (opt.transcription !== undefined)
231
- c.finalTranscription = opt.transcription;
232
- if (opt.sttStatus !== undefined)
233
- c.sttStatus = opt.sttStatus;
234
- });
235
- }
236
- async discardPostStt(roomId, n) {
194
+ async updateFinalTranscription(roomId, n, transcription) {
237
195
  return this.withChunk(roomId, n, (c) => {
238
- Object.values(c.translation).forEach((t) => (t.status = 'DISCARDED'));
239
- Object.values(c.tts).forEach((t) => (t.status = 'DISCARDED'));
196
+ c.finalTranscription = transcription;
240
197
  });
241
198
  }
242
199
  async discardLanguage(roomId, n, lang) {
@@ -348,9 +305,8 @@ class MulingstreamChunkManager {
348
305
  const now = Date.now();
349
306
  for (let i = lastDone + 1; i < window.length; i++) {
350
307
  const entry = window[i].tts[lang];
351
- const audio = window[i].audioChunk;
352
308
  if (entry.status === 'INIT') {
353
- if (now - window[i].createdAt > this.getTimeout(audio.start, audio.end))
309
+ if (now - window[i].createdAt > this.getTimeout())
354
310
  entry.status = 'DISCARDED';
355
311
  else
356
312
  blocked = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulingai-npm/redis",
3
- "version": "3.29.0",
3
+ "version": "3.29.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {