@magmamath/students-features 1.5.3-rc.3 → 1.5.3-rc.5
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/dist/commonjs/features/chatbot/model/VoiceTranscriptSnapshotModel.js +35 -8
- package/dist/commonjs/features/chatbot/model/VoiceTranscriptSnapshotModel.js.map +1 -1
- package/dist/commonjs/lib/effector/createControllerEffect.js +7 -6
- package/dist/commonjs/lib/effector/createControllerEffect.js.map +1 -1
- package/dist/module/features/chatbot/model/VoiceTranscriptSnapshotModel.js +35 -8
- package/dist/module/features/chatbot/model/VoiceTranscriptSnapshotModel.js.map +1 -1
- package/dist/module/lib/effector/createControllerEffect.js +7 -6
- package/dist/module/lib/effector/createControllerEffect.js.map +1 -1
- package/dist/typescript/commonjs/features/chatbot/model/VoiceTranscriptSnapshotModel.d.ts +6 -1
- package/dist/typescript/commonjs/features/chatbot/model/VoiceTranscriptSnapshotModel.d.ts.map +1 -1
- package/dist/typescript/commonjs/lib/effector/createControllerEffect.d.ts +1 -0
- package/dist/typescript/commonjs/lib/effector/createControllerEffect.d.ts.map +1 -1
- package/dist/typescript/module/features/chatbot/model/VoiceTranscriptSnapshotModel.d.ts +6 -1
- package/dist/typescript/module/features/chatbot/model/VoiceTranscriptSnapshotModel.d.ts.map +1 -1
- package/dist/typescript/module/lib/effector/createControllerEffect.d.ts +1 -0
- package/dist/typescript/module/lib/effector/createControllerEffect.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/features/chatbot/model/VoiceTranscriptSnapshotModel.ts +42 -9
- package/src/i18n/.generated/schema.json +1 -0
- package/src/lib/effector/createControllerEffect.ts +13 -6
|
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.VoiceTranscriptSnapshotModel = void 0;
|
|
7
7
|
var _effector = require("effector");
|
|
8
8
|
var _types = require("../../voice/types.js");
|
|
9
|
+
var _i18n = require("../../../i18n/i18n.js");
|
|
9
10
|
const TRANSCRIPT_RETRY_INTERVAL_MS = 2000;
|
|
10
11
|
const TRANSCRIPT_MAX_RETRIES = 20;
|
|
12
|
+
const CHAT_WITH_VOICE_TIMEOUT_MS = 60_000;
|
|
11
13
|
// Voice key: `${assignmentId}-${problemId}-${attemptsCount}`
|
|
12
14
|
// Chat key: `${assignmentId}-${problemId}` — survives attempt increments and voice deletion.
|
|
13
15
|
const toChatKey = voiceKey => {
|
|
@@ -39,6 +41,9 @@ class VoiceTranscriptSnapshotModel {
|
|
|
39
41
|
};
|
|
40
42
|
wrapRequestHint = apiFn => {
|
|
41
43
|
return async (params, requestConfig) => {
|
|
44
|
+
if (this.hasPendingVoice()) {
|
|
45
|
+
requestConfig?.extendTimeoutMs?.(CHAT_WITH_VOICE_TIMEOUT_MS);
|
|
46
|
+
}
|
|
42
47
|
const voiceTranscript = await this.getTranscriptForCurrent();
|
|
43
48
|
return apiFn(voiceTranscript ? {
|
|
44
49
|
...params,
|
|
@@ -46,12 +51,21 @@ class VoiceTranscriptSnapshotModel {
|
|
|
46
51
|
} : params, requestConfig);
|
|
47
52
|
};
|
|
48
53
|
};
|
|
54
|
+
hasPendingVoice() {
|
|
55
|
+
const voiceKey = this.voiceRecord.$currentKey.getState();
|
|
56
|
+
if (!voiceKey) return false;
|
|
57
|
+
const chatKey = toChatKey(voiceKey);
|
|
58
|
+
if (chatKey && this.snapshotByChatKey.has(chatKey)) return true;
|
|
59
|
+
return !!this.voiceRecord.collection.get(voiceKey);
|
|
60
|
+
}
|
|
49
61
|
constructor({
|
|
50
62
|
voiceRecord,
|
|
51
|
-
api
|
|
63
|
+
api,
|
|
64
|
+
errorHandler
|
|
52
65
|
}) {
|
|
53
66
|
this.voiceRecord = voiceRecord;
|
|
54
67
|
this.api = api;
|
|
68
|
+
this.errorHandler = errorHandler;
|
|
55
69
|
(0, _effector.sample)({
|
|
56
70
|
clock: voiceRecord.setCurrentRecord,
|
|
57
71
|
source: voiceRecord.$currentKey,
|
|
@@ -62,26 +76,39 @@ class VoiceTranscriptSnapshotModel {
|
|
|
62
76
|
}),
|
|
63
77
|
target: this.captureSnapshotFx
|
|
64
78
|
});
|
|
79
|
+
(0, _effector.sample)({
|
|
80
|
+
clock: voiceRecord.deleteCurrentRecording,
|
|
81
|
+
source: voiceRecord.$currentKey,
|
|
82
|
+
target: this.clearSnapshotFx
|
|
83
|
+
});
|
|
65
84
|
}
|
|
66
85
|
transcriptByAudioFileId = new Map();
|
|
67
86
|
snapshotByChatKey = new Map();
|
|
68
|
-
captureSnapshotFx = (0, _effector.createEffect)(
|
|
87
|
+
captureSnapshotFx = (0, _effector.createEffect)(({
|
|
69
88
|
voiceKey,
|
|
70
89
|
record
|
|
71
90
|
}) => {
|
|
72
91
|
const chatKey = toChatKey(voiceKey);
|
|
73
92
|
if (!chatKey) return;
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
const transcriptPromise = this.resolveAudioFileId(record).then(audioFileId => audioFileId ? this.fetchTranscript(audioFileId) : undefined);
|
|
94
|
+
this.snapshotByChatKey.set(chatKey, transcriptPromise);
|
|
95
|
+
});
|
|
96
|
+
clearSnapshotFx = (0, _effector.createEffect)(voiceKey => {
|
|
97
|
+
const chatKey = toChatKey(voiceKey);
|
|
98
|
+
if (chatKey) this.snapshotByChatKey.delete(chatKey);
|
|
77
99
|
});
|
|
78
100
|
async pollTranscript(audioFileId) {
|
|
79
101
|
for (let attempt = 0; attempt < TRANSCRIPT_MAX_RETRIES; attempt++) {
|
|
80
102
|
await new Promise(resolve => setTimeout(resolve, TRANSCRIPT_RETRY_INTERVAL_MS));
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
103
|
+
try {
|
|
104
|
+
const response = await this.api.getAudioFileTranscript(audioFileId);
|
|
105
|
+
if (response.status === _types.TranscriptionStatus.COMPLETED) return response.text;
|
|
106
|
+
if (response.status === _types.TranscriptionStatus.FAILED) break;
|
|
107
|
+
} catch {
|
|
108
|
+
// network/request failure — retry on next iteration
|
|
109
|
+
}
|
|
84
110
|
}
|
|
111
|
+
this.errorHandler?.((0, _i18n.getText)('voice.transcriptionError'));
|
|
85
112
|
return undefined;
|
|
86
113
|
}
|
|
87
114
|
async resolveAudioFileId(record) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_effector","require","_types","TRANSCRIPT_RETRY_INTERVAL_MS","TRANSCRIPT_MAX_RETRIES","toChatKey","voiceKey","lastDashIndex","lastIndexOf","slice","VoiceTranscriptSnapshotModel","fetchTranscript","audioFileId","cached","transcriptByAudioFileId","get","promise","pollTranscript","catch","undefined","set","getTranscriptForCurrent","voiceRecord","$currentKey","getState","chatKey","snapshot","snapshotByChatKey","record","collection","resolveAudioFileId","wrapRequestHint","apiFn","params","requestConfig","voiceTranscript","constructor","api","sample","clock","setCurrentRecord","source","filter","_","fn","target","captureSnapshotFx","Map","createEffect","attempt","Promise","resolve","setTimeout","response","getAudioFileTranscript","status","TranscriptionStatus","COMPLETED","text","FAILED","id","audioUploadPromise","result","exports"],"sourceRoot":"../../../../../src","sources":["features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"mappings":";;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;
|
|
1
|
+
{"version":3,"names":["_effector","require","_types","_i18n","TRANSCRIPT_RETRY_INTERVAL_MS","TRANSCRIPT_MAX_RETRIES","CHAT_WITH_VOICE_TIMEOUT_MS","toChatKey","voiceKey","lastDashIndex","lastIndexOf","slice","VoiceTranscriptSnapshotModel","fetchTranscript","audioFileId","cached","transcriptByAudioFileId","get","promise","pollTranscript","catch","undefined","set","getTranscriptForCurrent","voiceRecord","$currentKey","getState","chatKey","snapshot","snapshotByChatKey","record","collection","resolveAudioFileId","wrapRequestHint","apiFn","params","requestConfig","hasPendingVoice","extendTimeoutMs","voiceTranscript","has","constructor","api","errorHandler","sample","clock","setCurrentRecord","source","filter","_","fn","target","captureSnapshotFx","deleteCurrentRecording","clearSnapshotFx","Map","createEffect","transcriptPromise","then","delete","attempt","Promise","resolve","setTimeout","response","getAudioFileTranscript","status","TranscriptionStatus","COMPLETED","text","FAILED","getText","id","audioUploadPromise","result","exports"],"sourceRoot":"../../../../../src","sources":["features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -13,14 +13,15 @@ function controlledRequest(request) {
|
|
|
13
13
|
abortAfter = 20000
|
|
14
14
|
}) => {
|
|
15
15
|
let timeout = null;
|
|
16
|
-
|
|
17
|
-
timeout
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
const scheduleAbort = ms => {
|
|
17
|
+
if (timeout !== null) clearTimeout(timeout);
|
|
18
|
+
timeout = ms > 0 ? setTimeout(() => controller.abort('timeout'), ms) : null;
|
|
19
|
+
};
|
|
20
|
+
if (abortAfter) scheduleAbort(abortAfter);
|
|
21
21
|
try {
|
|
22
22
|
const response = await request(data, {
|
|
23
|
-
signal: controller?.signal
|
|
23
|
+
signal: controller?.signal,
|
|
24
|
+
extendTimeoutMs: scheduleAbort
|
|
24
25
|
});
|
|
25
26
|
if (timeout !== null) clearTimeout(timeout);
|
|
26
27
|
return response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_effector","require","controlledRequest","request","data","controller","AbortController","abortAfter","timeout","setTimeout","abort","response","signal","
|
|
1
|
+
{"version":3,"names":["_effector","require","controlledRequest","request","data","controller","AbortController","abortAfter","timeout","scheduleAbort","ms","clearTimeout","setTimeout","abort","response","signal","extendTimeoutMs","error","code","reason","Error","createControllerEffect","fn","effect","createEffect","fail","watch","exports"],"sourceRoot":"../../../../src","sources":["lib/effector/createControllerEffect.ts"],"mappings":";;;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AAqBO,SAASC,iBAAiBA,CAC/BC,OAAiE,EACjE;EACA,OAAO,OAAO;IACZC,IAAI;IACJC,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;IAClCC,UAAU,GAAG;EACY,CAAC,KAAK;IAC/B,IAAIC,OAA6C,GAAG,IAAI;IAExD,MAAMC,aAAa,GAAIC,EAAU,IAAK;MACpC,IAAIF,OAAO,KAAK,IAAI,EAAEG,YAAY,CAACH,OAAO,CAAC;MAC3CA,OAAO,GAAGE,EAAE,GAAG,CAAC,GAAGE,UAAU,CAAC,MAAMP,UAAU,CAACQ,KAAK,CAAC,SAAS,CAAC,EAAEH,EAAE,CAAC,GAAG,IAAI;IAC7E,CAAC;IAED,IAAIH,UAAU,EAAEE,aAAa,CAACF,UAAU,CAAC;IAEzC,IAAI;MACF,MAAMO,QAAQ,GAAG,MAAMX,OAAO,CAACC,IAAI,EAAE;QACnCW,MAAM,EAAEV,UAAU,EAAEU,MAAM;QAC1BC,eAAe,EAAEP;MACnB,CAAC,CAAC;MACF,IAAID,OAAO,KAAK,IAAI,EAAEG,YAAY,CAACH,OAAO,CAAC;MAC3C,OAAOM,QAAQ;IACjB,CAAC,CAAC,OAAOG,KAAc,EAAE;MACvB,IAAKA,KAAK,CAAuBC,IAAI,KAAK,cAAc,EAAE;QACxD,IAAIb,UAAU,CAACU,MAAM,CAACI,MAAM,KAAK,SAAS,EAAE;UAC1C,MAAM,IAAIC,KAAK,CAAC,mBAAmB,CAAC;QACtC;QACA,MAAM,IAAIA,KAAK,CAAC,0BAA0B,CAAC;MAC7C;MAEA,MAAMH,KAAK;IACb;EACF,CAAC;AACH;AAEO,MAAMI,sBAAsB,GACjCC,EAA4D,IACzD;EACH,MAAMnB,OAAO,GAAGD,iBAAiB,CAAOoB,EAAE,CAAC;EAC3C,MAAMC,MAAM,GAAG,IAAAC,sBAAY,EAAEpB,IAAO,IAClCD,OAAO,CAAC;IAAEC,IAAI;IAAEC,UAAU,EAAEkB,MAAM,CAAClB;EAAW,CAAC,CACjD,CAA2B;EAC3BkB,MAAM,CAAClB,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;EAEzCiB,MAAM,CAACE,IAAI,CAACC,KAAK,CAAC,MAAM;IACtBH,MAAM,CAAClB,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;EAC3C,CAAC,CAAC;EAEF,OAAOiB,MAAM;AACf,CAAC;AAAAI,OAAA,CAAAN,sBAAA,GAAAA,sBAAA","ignoreList":[]}
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { createEffect, sample } from 'effector';
|
|
4
4
|
import { TranscriptionStatus } from "../../voice/types.js";
|
|
5
|
+
import { getText } from "../../../i18n/i18n.js";
|
|
5
6
|
const TRANSCRIPT_RETRY_INTERVAL_MS = 2000;
|
|
6
7
|
const TRANSCRIPT_MAX_RETRIES = 20;
|
|
8
|
+
const CHAT_WITH_VOICE_TIMEOUT_MS = 60_000;
|
|
7
9
|
// Voice key: `${assignmentId}-${problemId}-${attemptsCount}`
|
|
8
10
|
// Chat key: `${assignmentId}-${problemId}` — survives attempt increments and voice deletion.
|
|
9
11
|
const toChatKey = voiceKey => {
|
|
@@ -35,6 +37,9 @@ export class VoiceTranscriptSnapshotModel {
|
|
|
35
37
|
};
|
|
36
38
|
wrapRequestHint = apiFn => {
|
|
37
39
|
return async (params, requestConfig) => {
|
|
40
|
+
if (this.hasPendingVoice()) {
|
|
41
|
+
requestConfig?.extendTimeoutMs?.(CHAT_WITH_VOICE_TIMEOUT_MS);
|
|
42
|
+
}
|
|
38
43
|
const voiceTranscript = await this.getTranscriptForCurrent();
|
|
39
44
|
return apiFn(voiceTranscript ? {
|
|
40
45
|
...params,
|
|
@@ -42,12 +47,21 @@ export class VoiceTranscriptSnapshotModel {
|
|
|
42
47
|
} : params, requestConfig);
|
|
43
48
|
};
|
|
44
49
|
};
|
|
50
|
+
hasPendingVoice() {
|
|
51
|
+
const voiceKey = this.voiceRecord.$currentKey.getState();
|
|
52
|
+
if (!voiceKey) return false;
|
|
53
|
+
const chatKey = toChatKey(voiceKey);
|
|
54
|
+
if (chatKey && this.snapshotByChatKey.has(chatKey)) return true;
|
|
55
|
+
return !!this.voiceRecord.collection.get(voiceKey);
|
|
56
|
+
}
|
|
45
57
|
constructor({
|
|
46
58
|
voiceRecord,
|
|
47
|
-
api
|
|
59
|
+
api,
|
|
60
|
+
errorHandler
|
|
48
61
|
}) {
|
|
49
62
|
this.voiceRecord = voiceRecord;
|
|
50
63
|
this.api = api;
|
|
64
|
+
this.errorHandler = errorHandler;
|
|
51
65
|
sample({
|
|
52
66
|
clock: voiceRecord.setCurrentRecord,
|
|
53
67
|
source: voiceRecord.$currentKey,
|
|
@@ -58,26 +72,39 @@ export class VoiceTranscriptSnapshotModel {
|
|
|
58
72
|
}),
|
|
59
73
|
target: this.captureSnapshotFx
|
|
60
74
|
});
|
|
75
|
+
sample({
|
|
76
|
+
clock: voiceRecord.deleteCurrentRecording,
|
|
77
|
+
source: voiceRecord.$currentKey,
|
|
78
|
+
target: this.clearSnapshotFx
|
|
79
|
+
});
|
|
61
80
|
}
|
|
62
81
|
transcriptByAudioFileId = new Map();
|
|
63
82
|
snapshotByChatKey = new Map();
|
|
64
|
-
captureSnapshotFx = createEffect(
|
|
83
|
+
captureSnapshotFx = createEffect(({
|
|
65
84
|
voiceKey,
|
|
66
85
|
record
|
|
67
86
|
}) => {
|
|
68
87
|
const chatKey = toChatKey(voiceKey);
|
|
69
88
|
if (!chatKey) return;
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
89
|
+
const transcriptPromise = this.resolveAudioFileId(record).then(audioFileId => audioFileId ? this.fetchTranscript(audioFileId) : undefined);
|
|
90
|
+
this.snapshotByChatKey.set(chatKey, transcriptPromise);
|
|
91
|
+
});
|
|
92
|
+
clearSnapshotFx = createEffect(voiceKey => {
|
|
93
|
+
const chatKey = toChatKey(voiceKey);
|
|
94
|
+
if (chatKey) this.snapshotByChatKey.delete(chatKey);
|
|
73
95
|
});
|
|
74
96
|
async pollTranscript(audioFileId) {
|
|
75
97
|
for (let attempt = 0; attempt < TRANSCRIPT_MAX_RETRIES; attempt++) {
|
|
76
98
|
await new Promise(resolve => setTimeout(resolve, TRANSCRIPT_RETRY_INTERVAL_MS));
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
99
|
+
try {
|
|
100
|
+
const response = await this.api.getAudioFileTranscript(audioFileId);
|
|
101
|
+
if (response.status === TranscriptionStatus.COMPLETED) return response.text;
|
|
102
|
+
if (response.status === TranscriptionStatus.FAILED) break;
|
|
103
|
+
} catch {
|
|
104
|
+
// network/request failure — retry on next iteration
|
|
105
|
+
}
|
|
80
106
|
}
|
|
107
|
+
this.errorHandler?.(getText('voice.transcriptionError'));
|
|
81
108
|
return undefined;
|
|
82
109
|
}
|
|
83
110
|
async resolveAudioFileId(record) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["createEffect","sample","TranscriptionStatus","TRANSCRIPT_RETRY_INTERVAL_MS","TRANSCRIPT_MAX_RETRIES","toChatKey","voiceKey","lastDashIndex","lastIndexOf","slice","VoiceTranscriptSnapshotModel","fetchTranscript","audioFileId","cached","transcriptByAudioFileId","get","promise","pollTranscript","catch","undefined","set","getTranscriptForCurrent","voiceRecord","$currentKey","getState","chatKey","snapshot","snapshotByChatKey","record","collection","resolveAudioFileId","wrapRequestHint","apiFn","params","requestConfig","voiceTranscript","constructor","api","clock","setCurrentRecord","source","filter","_","fn","target","captureSnapshotFx","Map","attempt","Promise","resolve","setTimeout","response","getAudioFileTranscript","status","COMPLETED","text","FAILED","id","audioUploadPromise","result"],"sourceRoot":"../../../../../src","sources":["features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"mappings":";;AAAA,SAASA,YAAY,EAAEC,MAAM,QAAQ,UAAU;AAC/C,SAEEC,mBAAmB,QAEd,sBAAmB;
|
|
1
|
+
{"version":3,"names":["createEffect","sample","TranscriptionStatus","getText","TRANSCRIPT_RETRY_INTERVAL_MS","TRANSCRIPT_MAX_RETRIES","CHAT_WITH_VOICE_TIMEOUT_MS","toChatKey","voiceKey","lastDashIndex","lastIndexOf","slice","VoiceTranscriptSnapshotModel","fetchTranscript","audioFileId","cached","transcriptByAudioFileId","get","promise","pollTranscript","catch","undefined","set","getTranscriptForCurrent","voiceRecord","$currentKey","getState","chatKey","snapshot","snapshotByChatKey","record","collection","resolveAudioFileId","wrapRequestHint","apiFn","params","requestConfig","hasPendingVoice","extendTimeoutMs","voiceTranscript","has","constructor","api","errorHandler","clock","setCurrentRecord","source","filter","_","fn","target","captureSnapshotFx","deleteCurrentRecording","clearSnapshotFx","Map","transcriptPromise","then","delete","attempt","Promise","resolve","setTimeout","response","getAudioFileTranscript","status","COMPLETED","text","FAILED","id","audioUploadPromise","result"],"sourceRoot":"../../../../../src","sources":["features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -8,14 +8,15 @@ export function controlledRequest(request) {
|
|
|
8
8
|
abortAfter = 20000
|
|
9
9
|
}) => {
|
|
10
10
|
let timeout = null;
|
|
11
|
-
|
|
12
|
-
timeout
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
const scheduleAbort = ms => {
|
|
12
|
+
if (timeout !== null) clearTimeout(timeout);
|
|
13
|
+
timeout = ms > 0 ? setTimeout(() => controller.abort('timeout'), ms) : null;
|
|
14
|
+
};
|
|
15
|
+
if (abortAfter) scheduleAbort(abortAfter);
|
|
16
16
|
try {
|
|
17
17
|
const response = await request(data, {
|
|
18
|
-
signal: controller?.signal
|
|
18
|
+
signal: controller?.signal,
|
|
19
|
+
extendTimeoutMs: scheduleAbort
|
|
19
20
|
});
|
|
20
21
|
if (timeout !== null) clearTimeout(timeout);
|
|
21
22
|
return response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["createEffect","controlledRequest","request","data","controller","AbortController","abortAfter","timeout","setTimeout","abort","response","signal","
|
|
1
|
+
{"version":3,"names":["createEffect","controlledRequest","request","data","controller","AbortController","abortAfter","timeout","scheduleAbort","ms","clearTimeout","setTimeout","abort","response","signal","extendTimeoutMs","error","code","reason","Error","createControllerEffect","fn","effect","fail","watch"],"sourceRoot":"../../../../src","sources":["lib/effector/createControllerEffect.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAqB,UAAU;AAqBpD,OAAO,SAASC,iBAAiBA,CAC/BC,OAAiE,EACjE;EACA,OAAO,OAAO;IACZC,IAAI;IACJC,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;IAClCC,UAAU,GAAG;EACY,CAAC,KAAK;IAC/B,IAAIC,OAA6C,GAAG,IAAI;IAExD,MAAMC,aAAa,GAAIC,EAAU,IAAK;MACpC,IAAIF,OAAO,KAAK,IAAI,EAAEG,YAAY,CAACH,OAAO,CAAC;MAC3CA,OAAO,GAAGE,EAAE,GAAG,CAAC,GAAGE,UAAU,CAAC,MAAMP,UAAU,CAACQ,KAAK,CAAC,SAAS,CAAC,EAAEH,EAAE,CAAC,GAAG,IAAI;IAC7E,CAAC;IAED,IAAIH,UAAU,EAAEE,aAAa,CAACF,UAAU,CAAC;IAEzC,IAAI;MACF,MAAMO,QAAQ,GAAG,MAAMX,OAAO,CAACC,IAAI,EAAE;QACnCW,MAAM,EAAEV,UAAU,EAAEU,MAAM;QAC1BC,eAAe,EAAEP;MACnB,CAAC,CAAC;MACF,IAAID,OAAO,KAAK,IAAI,EAAEG,YAAY,CAACH,OAAO,CAAC;MAC3C,OAAOM,QAAQ;IACjB,CAAC,CAAC,OAAOG,KAAc,EAAE;MACvB,IAAKA,KAAK,CAAuBC,IAAI,KAAK,cAAc,EAAE;QACxD,IAAIb,UAAU,CAACU,MAAM,CAACI,MAAM,KAAK,SAAS,EAAE;UAC1C,MAAM,IAAIC,KAAK,CAAC,mBAAmB,CAAC;QACtC;QACA,MAAM,IAAIA,KAAK,CAAC,0BAA0B,CAAC;MAC7C;MAEA,MAAMH,KAAK;IACb;EACF,CAAC;AACH;AAEA,OAAO,MAAMI,sBAAsB,GACjCC,EAA4D,IACzD;EACH,MAAMnB,OAAO,GAAGD,iBAAiB,CAAOoB,EAAE,CAAC;EAC3C,MAAMC,MAAM,GAAGtB,YAAY,CAAEG,IAAO,IAClCD,OAAO,CAAC;IAAEC,IAAI;IAAEC,UAAU,EAAEkB,MAAM,CAAClB;EAAW,CAAC,CACjD,CAA2B;EAC3BkB,MAAM,CAAClB,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;EAEzCiB,MAAM,CAACC,IAAI,CAACC,KAAK,CAAC,MAAM;IACtBF,MAAM,CAAClB,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;EAC3C,CAAC,CAAC;EAEF,OAAOiB,MAAM;AACf,CAAC","ignoreList":[]}
|
|
@@ -4,9 +4,11 @@ import { RequestOptionalConfig } from '../../../lib/effector/createControllerEff
|
|
|
4
4
|
type GetTranscriptApi = {
|
|
5
5
|
getAudioFileTranscript: (audioFileId: string) => Promise<AudioTranscriptResponse>;
|
|
6
6
|
};
|
|
7
|
+
export type VoiceTranscriptErrorHandler = (errorMessage: string) => void;
|
|
7
8
|
type VoiceTranscriptSnapshotModelProps = {
|
|
8
9
|
voiceRecord: VoiceRecordModel;
|
|
9
10
|
api: GetTranscriptApi;
|
|
11
|
+
errorHandler?: VoiceTranscriptErrorHandler;
|
|
10
12
|
};
|
|
11
13
|
export declare class VoiceTranscriptSnapshotModel {
|
|
12
14
|
readonly fetchTranscript: (audioFileId: string) => Promise<string | undefined>;
|
|
@@ -14,12 +16,15 @@ export declare class VoiceTranscriptSnapshotModel {
|
|
|
14
16
|
readonly wrapRequestHint: <P extends object, R>(apiFn: (params: P & {
|
|
15
17
|
voiceTranscript?: string;
|
|
16
18
|
}, requestConfig?: RequestOptionalConfig) => Promise<R>) => (params: P, requestConfig?: RequestOptionalConfig) => Promise<R>;
|
|
17
|
-
|
|
19
|
+
private hasPendingVoice;
|
|
20
|
+
constructor({ voiceRecord, api, errorHandler }: VoiceTranscriptSnapshotModelProps);
|
|
18
21
|
private readonly voiceRecord;
|
|
19
22
|
private readonly api;
|
|
23
|
+
private readonly errorHandler?;
|
|
20
24
|
private readonly transcriptByAudioFileId;
|
|
21
25
|
private readonly snapshotByChatKey;
|
|
22
26
|
private readonly captureSnapshotFx;
|
|
27
|
+
private readonly clearSnapshotFx;
|
|
23
28
|
private pollTranscript;
|
|
24
29
|
private resolveAudioFileId;
|
|
25
30
|
}
|
package/dist/typescript/commonjs/features/chatbot/model/VoiceTranscriptSnapshotModel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceTranscriptSnapshotModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EAGxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAA;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAA;
|
|
1
|
+
{"version":3,"file":"VoiceTranscriptSnapshotModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EAGxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAA;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAA;AAOpF,KAAK,gBAAgB,GAAG;IACtB,sBAAsB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAA;CAClF,CAAA;AAOD,MAAM,MAAM,2BAA2B,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;AAExE,KAAK,iCAAiC,GAAG;IACvC,WAAW,EAAE,gBAAgB,CAAA;IAC7B,GAAG,EAAE,gBAAgB,CAAA;IACrB,YAAY,CAAC,EAAE,2BAA2B,CAAA;CAC3C,CAAA;AAUD,qBAAa,4BAA4B;IACvC,SAAgB,eAAe,gBAAiB,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAOnF;IAED,SAAgB,uBAAuB,QAAa,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiB9E;IAED,SAAgB,eAAe,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAC7C,CACL,MAAM,EAAE,CAAC,GAAG;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,EACxC,aAAa,CAAC,EAAE,qBAAqB,KAClC,OAAO,CAAC,CAAC,CAAC,cAEO,CAAC,kBAAkB,qBAAqB,KAAG,OAAO,CAAC,CAAC,CAAC,CAO5E;IAED,OAAO,CAAC,eAAe;gBAQX,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,iCAAiC;IAoBjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAiD;IACzF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiD;IAEnF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAQhC;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG9B;YAEY,cAAc;YAgBd,kBAAkB;CAUjC"}
|
|
@@ -9,6 +9,7 @@ type ControlledRequestProps<P> = {
|
|
|
9
9
|
};
|
|
10
10
|
export type RequestOptionalConfig = {
|
|
11
11
|
signal?: AbortSignal;
|
|
12
|
+
extendTimeoutMs?: (ms: number) => void;
|
|
12
13
|
};
|
|
13
14
|
export declare function controlledRequest<R = void, P = void>(request: (props: P, config?: RequestOptionalConfig) => Promise<R>): ({ data, controller, abortAfter, }: ControlledRequestProps<P>) => Promise<R>;
|
|
14
15
|
export declare const createControllerEffect: <T, P = void>(fn: (props: P, config?: RequestOptionalConfig) => Promise<T>) => ControlledEffect<P, T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createControllerEffect.d.ts","sourceRoot":"","sources":["../../../../../src/lib/effector/createControllerEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAMpD,MAAM,MAAM,gBAAgB,CAAC,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAClD,UAAU,EAAE,eAAe,CAAA;CAC5B,CAAA;AAED,KAAK,sBAAsB,CAAC,CAAC,IAAI;IAC/B,IAAI,EAAE,CAAC,CAAA;IACP,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;
|
|
1
|
+
{"version":3,"file":"createControllerEffect.d.ts","sourceRoot":"","sources":["../../../../../src/lib/effector/createControllerEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAMpD,MAAM,MAAM,gBAAgB,CAAC,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAClD,UAAU,EAAE,eAAe,CAAA;CAC5B,CAAA;AAED,KAAK,sBAAsB,CAAC,CAAC,IAAI;IAC/B,IAAI,EAAE,CAAC,CAAA;IACP,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CACvC,CAAA;AAED,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAClD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,qBAAqB,KAAK,OAAO,CAAC,CAAC,CAAC,uCAM9D,sBAAsB,CAAC,CAAC,CAAC,gBA4B7B;AAED,eAAO,MAAM,sBAAsB,GAAI,CAAC,EAAE,CAAC,aACrC,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,qBAAqB,KAAK,OAAO,CAAC,CAAC,CAAC,2BAa7D,CAAA"}
|
|
@@ -4,9 +4,11 @@ import { RequestOptionalConfig } from '../../../lib/effector/createControllerEff
|
|
|
4
4
|
type GetTranscriptApi = {
|
|
5
5
|
getAudioFileTranscript: (audioFileId: string) => Promise<AudioTranscriptResponse>;
|
|
6
6
|
};
|
|
7
|
+
export type VoiceTranscriptErrorHandler = (errorMessage: string) => void;
|
|
7
8
|
type VoiceTranscriptSnapshotModelProps = {
|
|
8
9
|
voiceRecord: VoiceRecordModel;
|
|
9
10
|
api: GetTranscriptApi;
|
|
11
|
+
errorHandler?: VoiceTranscriptErrorHandler;
|
|
10
12
|
};
|
|
11
13
|
export declare class VoiceTranscriptSnapshotModel {
|
|
12
14
|
readonly fetchTranscript: (audioFileId: string) => Promise<string | undefined>;
|
|
@@ -14,12 +16,15 @@ export declare class VoiceTranscriptSnapshotModel {
|
|
|
14
16
|
readonly wrapRequestHint: <P extends object, R>(apiFn: (params: P & {
|
|
15
17
|
voiceTranscript?: string;
|
|
16
18
|
}, requestConfig?: RequestOptionalConfig) => Promise<R>) => (params: P, requestConfig?: RequestOptionalConfig) => Promise<R>;
|
|
17
|
-
|
|
19
|
+
private hasPendingVoice;
|
|
20
|
+
constructor({ voiceRecord, api, errorHandler }: VoiceTranscriptSnapshotModelProps);
|
|
18
21
|
private readonly voiceRecord;
|
|
19
22
|
private readonly api;
|
|
23
|
+
private readonly errorHandler?;
|
|
20
24
|
private readonly transcriptByAudioFileId;
|
|
21
25
|
private readonly snapshotByChatKey;
|
|
22
26
|
private readonly captureSnapshotFx;
|
|
27
|
+
private readonly clearSnapshotFx;
|
|
23
28
|
private pollTranscript;
|
|
24
29
|
private resolveAudioFileId;
|
|
25
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceTranscriptSnapshotModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EAGxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAA;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAA;
|
|
1
|
+
{"version":3,"file":"VoiceTranscriptSnapshotModel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/chatbot/model/VoiceTranscriptSnapshotModel.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EAGxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAA;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAA;AAOpF,KAAK,gBAAgB,GAAG;IACtB,sBAAsB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAA;CAClF,CAAA;AAOD,MAAM,MAAM,2BAA2B,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;AAExE,KAAK,iCAAiC,GAAG;IACvC,WAAW,EAAE,gBAAgB,CAAA;IAC7B,GAAG,EAAE,gBAAgB,CAAA;IACrB,YAAY,CAAC,EAAE,2BAA2B,CAAA;CAC3C,CAAA;AAUD,qBAAa,4BAA4B;IACvC,SAAgB,eAAe,gBAAiB,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAOnF;IAED,SAAgB,uBAAuB,QAAa,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiB9E;IAED,SAAgB,eAAe,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAC7C,CACL,MAAM,EAAE,CAAC,GAAG;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,EACxC,aAAa,CAAC,EAAE,qBAAqB,KAClC,OAAO,CAAC,CAAC,CAAC,cAEO,CAAC,kBAAkB,qBAAqB,KAAG,OAAO,CAAC,CAAC,CAAC,CAO5E;IAED,OAAO,CAAC,eAAe;gBAQX,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,iCAAiC;IAoBjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAiD;IACzF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiD;IAEnF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAQhC;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG9B;YAEY,cAAc;YAgBd,kBAAkB;CAUjC"}
|
|
@@ -9,6 +9,7 @@ type ControlledRequestProps<P> = {
|
|
|
9
9
|
};
|
|
10
10
|
export type RequestOptionalConfig = {
|
|
11
11
|
signal?: AbortSignal;
|
|
12
|
+
extendTimeoutMs?: (ms: number) => void;
|
|
12
13
|
};
|
|
13
14
|
export declare function controlledRequest<R = void, P = void>(request: (props: P, config?: RequestOptionalConfig) => Promise<R>): ({ data, controller, abortAfter, }: ControlledRequestProps<P>) => Promise<R>;
|
|
14
15
|
export declare const createControllerEffect: <T, P = void>(fn: (props: P, config?: RequestOptionalConfig) => Promise<T>) => ControlledEffect<P, T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createControllerEffect.d.ts","sourceRoot":"","sources":["../../../../../src/lib/effector/createControllerEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAMpD,MAAM,MAAM,gBAAgB,CAAC,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAClD,UAAU,EAAE,eAAe,CAAA;CAC5B,CAAA;AAED,KAAK,sBAAsB,CAAC,CAAC,IAAI;IAC/B,IAAI,EAAE,CAAC,CAAA;IACP,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;
|
|
1
|
+
{"version":3,"file":"createControllerEffect.d.ts","sourceRoot":"","sources":["../../../../../src/lib/effector/createControllerEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAMpD,MAAM,MAAM,gBAAgB,CAAC,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAClD,UAAU,EAAE,eAAe,CAAA;CAC5B,CAAA;AAED,KAAK,sBAAsB,CAAC,CAAC,IAAI;IAC/B,IAAI,EAAE,CAAC,CAAA;IACP,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CACvC,CAAA;AAED,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,EAClD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,qBAAqB,KAAK,OAAO,CAAC,CAAC,CAAC,uCAM9D,sBAAsB,CAAC,CAAC,CAAC,gBA4B7B;AAED,eAAO,MAAM,sBAAsB,GAAI,CAAC,EAAE,CAAC,aACrC,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,qBAAqB,KAAK,OAAO,CAAC,CAAC,CAAC,2BAa7D,CAAA"}
|
package/package.json
CHANGED
|
@@ -6,9 +6,11 @@ import {
|
|
|
6
6
|
} from '../../voice/types'
|
|
7
7
|
import { VoiceRecordModel } from '../../voice/recording/model/VoiceRecord.model'
|
|
8
8
|
import { RequestOptionalConfig } from '../../../lib/effector/createControllerEffect'
|
|
9
|
+
import { getText } from '../../../i18n/i18n'
|
|
9
10
|
|
|
10
11
|
const TRANSCRIPT_RETRY_INTERVAL_MS = 2000
|
|
11
12
|
const TRANSCRIPT_MAX_RETRIES = 20
|
|
13
|
+
const CHAT_WITH_VOICE_TIMEOUT_MS = 60_000
|
|
12
14
|
|
|
13
15
|
type GetTranscriptApi = {
|
|
14
16
|
getAudioFileTranscript: (audioFileId: string) => Promise<AudioTranscriptResponse>
|
|
@@ -19,9 +21,12 @@ type CaptureParams = {
|
|
|
19
21
|
record: VoiceRecordCollectionItem
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
export type VoiceTranscriptErrorHandler = (errorMessage: string) => void
|
|
25
|
+
|
|
22
26
|
type VoiceTranscriptSnapshotModelProps = {
|
|
23
27
|
voiceRecord: VoiceRecordModel
|
|
24
28
|
api: GetTranscriptApi
|
|
29
|
+
errorHandler?: VoiceTranscriptErrorHandler
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
// Voice key: `${assignmentId}-${problemId}-${attemptsCount}`
|
|
@@ -68,14 +73,26 @@ export class VoiceTranscriptSnapshotModel {
|
|
|
68
73
|
) => Promise<R>,
|
|
69
74
|
) => {
|
|
70
75
|
return async (params: P, requestConfig?: RequestOptionalConfig): Promise<R> => {
|
|
76
|
+
if (this.hasPendingVoice()) {
|
|
77
|
+
requestConfig?.extendTimeoutMs?.(CHAT_WITH_VOICE_TIMEOUT_MS)
|
|
78
|
+
}
|
|
71
79
|
const voiceTranscript = await this.getTranscriptForCurrent()
|
|
72
80
|
return apiFn(voiceTranscript ? { ...params, voiceTranscript } : params, requestConfig)
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
|
|
76
|
-
|
|
84
|
+
private hasPendingVoice(): boolean {
|
|
85
|
+
const voiceKey = this.voiceRecord.$currentKey.getState()
|
|
86
|
+
if (!voiceKey) return false
|
|
87
|
+
const chatKey = toChatKey(voiceKey)
|
|
88
|
+
if (chatKey && this.snapshotByChatKey.has(chatKey)) return true
|
|
89
|
+
return !!this.voiceRecord.collection.get(voiceKey)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
constructor({ voiceRecord, api, errorHandler }: VoiceTranscriptSnapshotModelProps) {
|
|
77
93
|
this.voiceRecord = voiceRecord
|
|
78
94
|
this.api = api
|
|
95
|
+
this.errorHandler = errorHandler
|
|
79
96
|
|
|
80
97
|
sample({
|
|
81
98
|
clock: voiceRecord.setCurrentRecord,
|
|
@@ -84,32 +101,48 @@ export class VoiceTranscriptSnapshotModel {
|
|
|
84
101
|
fn: (voiceKey, record) => ({ voiceKey, record }),
|
|
85
102
|
target: this.captureSnapshotFx,
|
|
86
103
|
})
|
|
104
|
+
|
|
105
|
+
sample({
|
|
106
|
+
clock: voiceRecord.deleteCurrentRecording,
|
|
107
|
+
source: voiceRecord.$currentKey,
|
|
108
|
+
target: this.clearSnapshotFx,
|
|
109
|
+
})
|
|
87
110
|
}
|
|
88
111
|
|
|
89
112
|
private readonly voiceRecord: VoiceRecordModel
|
|
90
113
|
private readonly api: GetTranscriptApi
|
|
114
|
+
private readonly errorHandler?: VoiceTranscriptErrorHandler
|
|
91
115
|
private readonly transcriptByAudioFileId = new Map<string, Promise<string | undefined>>()
|
|
92
116
|
private readonly snapshotByChatKey = new Map<string, Promise<string | undefined>>()
|
|
93
117
|
|
|
94
|
-
private readonly captureSnapshotFx = createEffect(
|
|
118
|
+
private readonly captureSnapshotFx = createEffect(({ voiceKey, record }: CaptureParams) => {
|
|
95
119
|
const chatKey = toChatKey(voiceKey)
|
|
96
120
|
if (!chatKey) return
|
|
97
121
|
|
|
98
|
-
const
|
|
99
|
-
|
|
122
|
+
const transcriptPromise = this.resolveAudioFileId(record).then((audioFileId) =>
|
|
123
|
+
audioFileId ? this.fetchTranscript(audioFileId) : undefined,
|
|
124
|
+
)
|
|
125
|
+
this.snapshotByChatKey.set(chatKey, transcriptPromise)
|
|
126
|
+
})
|
|
100
127
|
|
|
101
|
-
|
|
128
|
+
private readonly clearSnapshotFx = createEffect((voiceKey: string) => {
|
|
129
|
+
const chatKey = toChatKey(voiceKey)
|
|
130
|
+
if (chatKey) this.snapshotByChatKey.delete(chatKey)
|
|
102
131
|
})
|
|
103
132
|
|
|
104
133
|
private async pollTranscript(audioFileId: string): Promise<string | undefined> {
|
|
105
134
|
for (let attempt = 0; attempt < TRANSCRIPT_MAX_RETRIES; attempt++) {
|
|
106
135
|
await new Promise((resolve) => setTimeout(resolve, TRANSCRIPT_RETRY_INTERVAL_MS))
|
|
107
136
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
137
|
+
try {
|
|
138
|
+
const response = await this.api.getAudioFileTranscript(audioFileId)
|
|
139
|
+
if (response.status === TranscriptionStatus.COMPLETED) return response.text
|
|
140
|
+
if (response.status === TranscriptionStatus.FAILED) break
|
|
141
|
+
} catch {
|
|
142
|
+
// network/request failure — retry on next iteration
|
|
143
|
+
}
|
|
112
144
|
}
|
|
145
|
+
this.errorHandler?.(getText('voice.transcriptionError'))
|
|
113
146
|
return undefined
|
|
114
147
|
}
|
|
115
148
|
|
|
@@ -144,6 +144,7 @@
|
|
|
144
144
|
"redo": "Redo",
|
|
145
145
|
"redoRecording": "Redo recording?",
|
|
146
146
|
"thisWillRemoveRecording": "This will remove your previous recording.",
|
|
147
|
+
"transcriptionError": "Transcription request error",
|
|
147
148
|
"transcriptions": "Transcriptions",
|
|
148
149
|
"transcriptNotAvailable": "Transcript not available",
|
|
149
150
|
"uploadFailed": "Upload failed. Please try again.",
|
|
@@ -14,7 +14,10 @@ type ControlledRequestProps<P> = {
|
|
|
14
14
|
abortAfter?: number
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export type RequestOptionalConfig = {
|
|
17
|
+
export type RequestOptionalConfig = {
|
|
18
|
+
signal?: AbortSignal
|
|
19
|
+
extendTimeoutMs?: (ms: number) => void
|
|
20
|
+
}
|
|
18
21
|
|
|
19
22
|
export function controlledRequest<R = void, P = void>(
|
|
20
23
|
request: (props: P, config?: RequestOptionalConfig) => Promise<R>,
|
|
@@ -26,14 +29,18 @@ export function controlledRequest<R = void, P = void>(
|
|
|
26
29
|
}: ControlledRequestProps<P>) => {
|
|
27
30
|
let timeout: ReturnType<typeof setTimeout> | null = null
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
timeout
|
|
31
|
-
|
|
32
|
-
}, abortAfter)
|
|
32
|
+
const scheduleAbort = (ms: number) => {
|
|
33
|
+
if (timeout !== null) clearTimeout(timeout)
|
|
34
|
+
timeout = ms > 0 ? setTimeout(() => controller.abort('timeout'), ms) : null
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
if (abortAfter) scheduleAbort(abortAfter)
|
|
38
|
+
|
|
35
39
|
try {
|
|
36
|
-
const response = await request(data, {
|
|
40
|
+
const response = await request(data, {
|
|
41
|
+
signal: controller?.signal,
|
|
42
|
+
extendTimeoutMs: scheduleAbort,
|
|
43
|
+
})
|
|
37
44
|
if (timeout !== null) clearTimeout(timeout)
|
|
38
45
|
return response
|
|
39
46
|
} catch (error: unknown) {
|