mingyang91 commited on
Commit
b371670
·
verified ·
1 Parent(s): 59eba26
Files changed (6) hide show
  1. Cargo.lock +43 -47
  2. Cargo.toml +4 -14
  3. src/asr/aws.rs +10 -6
  4. src/asr/mod.rs +3 -2
  5. src/asr/whisper.rs +67 -64
  6. src/lesson.rs +119 -27
Cargo.lock CHANGED
@@ -104,9 +104,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
104
 
105
  [[package]]
106
  name = "aws-config"
107
- version = "0.57.2"
108
  source = "registry+https://github.com/rust-lang/crates.io-index"
109
- checksum = "f2bf00cb9416daab4ce4927c54ebe63c08b9caf4d7b9314b6d7a4a2c5a1afb09"
110
  dependencies = [
111
  "aws-credential-types",
112
  "aws-http",
@@ -135,9 +135,9 @@ dependencies = [
135
 
136
  [[package]]
137
  name = "aws-credential-types"
138
- version = "0.57.2"
139
  source = "registry+https://github.com/rust-lang/crates.io-index"
140
- checksum = "cb9073c88dbf12f68ce7d0e149f989627a1d1ae3d2b680459f04ccc29d1cbd0f"
141
  dependencies = [
142
  "aws-smithy-async",
143
  "aws-smithy-runtime-api",
@@ -147,11 +147,10 @@ dependencies = [
147
 
148
  [[package]]
149
  name = "aws-http"
150
- version = "0.57.2"
151
  source = "registry+https://github.com/rust-lang/crates.io-index"
152
- checksum = "24067106d09620cf02d088166cdaedeaca7146d4d499c41b37accecbea11b246"
153
  dependencies = [
154
- "aws-smithy-http",
155
  "aws-smithy-runtime-api",
156
  "aws-smithy-types",
157
  "aws-types",
@@ -164,9 +163,9 @@ dependencies = [
164
 
165
  [[package]]
166
  name = "aws-runtime"
167
- version = "0.57.2"
168
  source = "registry+https://github.com/rust-lang/crates.io-index"
169
- checksum = "fc6ee0152c06d073602236a4e94a8c52a327d310c1ecd596570ce795af8777ff"
170
  dependencies = [
171
  "aws-credential-types",
172
  "aws-http",
@@ -186,9 +185,9 @@ dependencies = [
186
 
187
  [[package]]
188
  name = "aws-sdk-polly"
189
- version = "0.36.0"
190
  source = "registry+https://github.com/rust-lang/crates.io-index"
191
- checksum = "c1447f6042e2853798f535f3a9e64b3dea089f777ec1442da8ef96644456eb07"
192
  dependencies = [
193
  "aws-credential-types",
194
  "aws-http",
@@ -209,9 +208,9 @@ dependencies = [
209
 
210
  [[package]]
211
  name = "aws-sdk-sso"
212
- version = "0.36.0"
213
  source = "registry+https://github.com/rust-lang/crates.io-index"
214
- checksum = "2eb8158015232b4596ccef74a205600398e152d704b40b7ec9f486092474d7fa"
215
  dependencies = [
216
  "aws-credential-types",
217
  "aws-http",
@@ -231,9 +230,9 @@ dependencies = [
231
 
232
  [[package]]
233
  name = "aws-sdk-ssooidc"
234
- version = "0.36.0"
235
  source = "registry+https://github.com/rust-lang/crates.io-index"
236
- checksum = "36a1493e1c57f173e53621935bfb5b6217376168dbdb4cd459aebcf645924a48"
237
  dependencies = [
238
  "aws-credential-types",
239
  "aws-http",
@@ -253,9 +252,9 @@ dependencies = [
253
 
254
  [[package]]
255
  name = "aws-sdk-sts"
256
- version = "0.36.0"
257
  source = "registry+https://github.com/rust-lang/crates.io-index"
258
- checksum = "e032b77f5cd1dd3669d777a38ac08cbf8ec68e29460d4ef5d3e50cffa74ec75a"
259
  dependencies = [
260
  "aws-credential-types",
261
  "aws-http",
@@ -276,9 +275,9 @@ dependencies = [
276
 
277
  [[package]]
278
  name = "aws-sdk-transcribestreaming"
279
- version = "0.36.0"
280
  source = "registry+https://github.com/rust-lang/crates.io-index"
281
- checksum = "1f2d3625e963f2d453f278d4d8791ca62a055d1e0d1d78e413e6b60308c941f7"
282
  dependencies = [
283
  "aws-credential-types",
284
  "aws-http",
@@ -301,9 +300,9 @@ dependencies = [
301
 
302
  [[package]]
303
  name = "aws-sdk-translate"
304
- version = "0.36.0"
305
  source = "registry+https://github.com/rust-lang/crates.io-index"
306
- checksum = "7e29d057d3d192013cd1611b9d758c444c981824184514a00543ad8fdf89ef01"
307
  dependencies = [
308
  "aws-credential-types",
309
  "aws-http",
@@ -324,14 +323,15 @@ dependencies = [
324
 
325
  [[package]]
326
  name = "aws-sigv4"
327
- version = "0.57.2"
328
  source = "registry+https://github.com/rust-lang/crates.io-index"
329
- checksum = "64f81a6abc4daab06b53cabf27c54189928893283093e37164ca53aa47488a5b"
330
  dependencies = [
331
  "aws-credential-types",
332
  "aws-smithy-eventstream",
333
  "aws-smithy-http",
334
  "aws-smithy-runtime-api",
 
335
  "bytes",
336
  "form_urlencoded",
337
  "hex",
@@ -347,9 +347,9 @@ dependencies = [
347
 
348
  [[package]]
349
  name = "aws-smithy-async"
350
- version = "0.57.2"
351
  source = "registry+https://github.com/rust-lang/crates.io-index"
352
- checksum = "dbe53fccd3b10414b9cae63767a15a2789b34e6c6727b6e32b33e8c7998a3e80"
353
  dependencies = [
354
  "futures-util",
355
  "pin-project-lite",
@@ -358,9 +358,9 @@ dependencies = [
358
 
359
  [[package]]
360
  name = "aws-smithy-eventstream"
361
- version = "0.57.2"
362
  source = "registry+https://github.com/rust-lang/crates.io-index"
363
- checksum = "6b33fa99f928a5815b94ee07e1377901bcf51aa749034a2c802dc38f9dcfacf5"
364
  dependencies = [
365
  "aws-smithy-types",
366
  "bytes",
@@ -369,9 +369,9 @@ dependencies = [
369
 
370
  [[package]]
371
  name = "aws-smithy-http"
372
- version = "0.57.2"
373
  source = "registry+https://github.com/rust-lang/crates.io-index"
374
- checksum = "f7972373213d1d6e619c0edc9dda2d6634154e4ed75c5e0b2bf065cd5ec9f0d1"
375
  dependencies = [
376
  "aws-smithy-eventstream",
377
  "aws-smithy-runtime-api",
@@ -390,18 +390,18 @@ dependencies = [
390
 
391
  [[package]]
392
  name = "aws-smithy-json"
393
- version = "0.57.2"
394
  source = "registry+https://github.com/rust-lang/crates.io-index"
395
- checksum = "b6d64d5af16dd585de9ff6c606423c1aaad47c6baa38de41c2beb32ef21c6645"
396
  dependencies = [
397
  "aws-smithy-types",
398
  ]
399
 
400
  [[package]]
401
  name = "aws-smithy-query"
402
- version = "0.57.2"
403
  source = "registry+https://github.com/rust-lang/crates.io-index"
404
- checksum = "7527bf5335154ba1b285479c50b630e44e93d1b4a759eaceb8d0bf9fbc82caa5"
405
  dependencies = [
406
  "aws-smithy-types",
407
  "urlencoding",
@@ -409,9 +409,9 @@ dependencies = [
409
 
410
  [[package]]
411
  name = "aws-smithy-runtime"
412
- version = "0.57.2"
413
  source = "registry+https://github.com/rust-lang/crates.io-index"
414
- checksum = "839b363adf3b2bdab2742a1f540fec23039ea8bc9ec0f9f61df48470cfe5527b"
415
  dependencies = [
416
  "aws-smithy-async",
417
  "aws-smithy-http",
@@ -433,9 +433,9 @@ dependencies = [
433
 
434
  [[package]]
435
  name = "aws-smithy-runtime-api"
436
- version = "0.57.2"
437
  source = "registry+https://github.com/rust-lang/crates.io-index"
438
- checksum = "f24ecc446e62c3924539e7c18dec8038dba4fdf8718d5c2de62f9d2fecca8ba9"
439
  dependencies = [
440
  "aws-smithy-async",
441
  "aws-smithy-types",
@@ -449,9 +449,9 @@ dependencies = [
449
 
450
  [[package]]
451
  name = "aws-smithy-types"
452
- version = "0.57.2"
453
  source = "registry+https://github.com/rust-lang/crates.io-index"
454
- checksum = "051de910296522a21178a2ea402ea59027eef4b63f1cef04a0be2bb5e25dea03"
455
  dependencies = [
456
  "base64-simd",
457
  "bytes",
@@ -472,18 +472,18 @@ dependencies = [
472
 
473
  [[package]]
474
  name = "aws-smithy-xml"
475
- version = "0.57.2"
476
  source = "registry+https://github.com/rust-lang/crates.io-index"
477
- checksum = "cb1e3ac22c652662096c8e37a6f9af80c6f3520cab5610b2fe76c725bce18eac"
478
  dependencies = [
479
  "xmlparser",
480
  ]
481
 
482
  [[package]]
483
  name = "aws-types"
484
- version = "0.57.2"
485
  source = "registry+https://github.com/rust-lang/crates.io-index"
486
- checksum = "048bbf1c24cdf4eb1efcdc243388a93a90ebf63979e25fc1c7b8cbd9cb6beb38"
487
  dependencies = [
488
  "aws-credential-types",
489
  "aws-smithy-async",
@@ -1565,8 +1565,6 @@ dependencies = [
1565
  "tracing-subscriber",
1566
  "tracing-test",
1567
  "whisper",
1568
- "whisper-rs",
1569
- "whisper-rs-sys",
1570
  ]
1571
 
1572
  [[package]]
@@ -2537,13 +2535,11 @@ name = "whisper"
2537
  version = "0.1.0"
2538
  dependencies = [
2539
  "fvad",
2540
- "hound",
2541
  "lazy_static",
2542
  "once_cell",
2543
  "serde",
2544
  "tokio",
2545
  "tracing",
2546
- "tracing-test",
2547
  "whisper-rs",
2548
  "whisper-rs-sys",
2549
  ]
 
104
 
105
  [[package]]
106
  name = "aws-config"
107
+ version = "1.0.0"
108
  source = "registry+https://github.com/rust-lang/crates.io-index"
109
+ checksum = "8e245d7c741a8e4b23133f36750c4bcb3938a66ac49510caaf8b83afd52db1ec"
110
  dependencies = [
111
  "aws-credential-types",
112
  "aws-http",
 
135
 
136
  [[package]]
137
  name = "aws-credential-types"
138
+ version = "1.0.0"
139
  source = "registry+https://github.com/rust-lang/crates.io-index"
140
+ checksum = "e6dec6f3d42983be70a113f999476185e124884f43f4d60129c7157aede7bda1"
141
  dependencies = [
142
  "aws-smithy-async",
143
  "aws-smithy-runtime-api",
 
147
 
148
  [[package]]
149
  name = "aws-http"
150
+ version = "0.60.0"
151
  source = "registry+https://github.com/rust-lang/crates.io-index"
152
+ checksum = "361c4310fdce94328cc2d1ca0c8a48c13f43009c61d3367585685a50ca8c66b6"
153
  dependencies = [
 
154
  "aws-smithy-runtime-api",
155
  "aws-smithy-types",
156
  "aws-types",
 
163
 
164
  [[package]]
165
  name = "aws-runtime"
166
+ version = "1.0.0"
167
  source = "registry+https://github.com/rust-lang/crates.io-index"
168
+ checksum = "36ba3ad97d674bfaeed684d528a07cee6e81cbf16e6d6c7e272a130b5e71e6b9"
169
  dependencies = [
170
  "aws-credential-types",
171
  "aws-http",
 
185
 
186
  [[package]]
187
  name = "aws-sdk-polly"
188
+ version = "0.39.0"
189
  source = "registry+https://github.com/rust-lang/crates.io-index"
190
+ checksum = "6171a347258d10090d7e6de9c729547f182a47787ba26969571ed1b96a67a461"
191
  dependencies = [
192
  "aws-credential-types",
193
  "aws-http",
 
208
 
209
  [[package]]
210
  name = "aws-sdk-sso"
211
+ version = "0.39.0"
212
  source = "registry+https://github.com/rust-lang/crates.io-index"
213
+ checksum = "5786afe1fd164e53f108b2bd4982a31c5a821dc1677d05a12de65ebcc6ede52a"
214
  dependencies = [
215
  "aws-credential-types",
216
  "aws-http",
 
230
 
231
  [[package]]
232
  name = "aws-sdk-ssooidc"
233
+ version = "0.39.0"
234
  source = "registry+https://github.com/rust-lang/crates.io-index"
235
+ checksum = "31569ac7750ebc3097058c1e72d79576e16b3fb262aa0d6510188bff623f9804"
236
  dependencies = [
237
  "aws-credential-types",
238
  "aws-http",
 
252
 
253
  [[package]]
254
  name = "aws-sdk-sts"
255
+ version = "0.39.0"
256
  source = "registry+https://github.com/rust-lang/crates.io-index"
257
+ checksum = "9b1d955bacd8c3637908a40a4af2f7a732461ee7d95ec02599a3610ee55781d7"
258
  dependencies = [
259
  "aws-credential-types",
260
  "aws-http",
 
275
 
276
  [[package]]
277
  name = "aws-sdk-transcribestreaming"
278
+ version = "0.39.0"
279
  source = "registry+https://github.com/rust-lang/crates.io-index"
280
+ checksum = "06c279198248d3780d3756c6ff04dec862f48233f162dfa2229684c67232c020"
281
  dependencies = [
282
  "aws-credential-types",
283
  "aws-http",
 
300
 
301
  [[package]]
302
  name = "aws-sdk-translate"
303
+ version = "0.39.0"
304
  source = "registry+https://github.com/rust-lang/crates.io-index"
305
+ checksum = "f021251dcd868e9628633e8c8093828aa8828ead1acf5bee6ed77cb3f2cfa268"
306
  dependencies = [
307
  "aws-credential-types",
308
  "aws-http",
 
323
 
324
  [[package]]
325
  name = "aws-sigv4"
326
+ version = "1.0.0"
327
  source = "registry+https://github.com/rust-lang/crates.io-index"
328
+ checksum = "b4d07e2f2fc32acb7423d054ec8ba2b361dafc95fabc5a211baf4a566571d20e"
329
  dependencies = [
330
  "aws-credential-types",
331
  "aws-smithy-eventstream",
332
  "aws-smithy-http",
333
  "aws-smithy-runtime-api",
334
+ "aws-smithy-types",
335
  "bytes",
336
  "form_urlencoded",
337
  "hex",
 
347
 
348
  [[package]]
349
  name = "aws-smithy-async"
350
+ version = "1.0.0"
351
  source = "registry+https://github.com/rust-lang/crates.io-index"
352
+ checksum = "133965d3038e4b79be8ceb7e0ccae2144ddf7b2abff5827d24dc451d559c56b9"
353
  dependencies = [
354
  "futures-util",
355
  "pin-project-lite",
 
358
 
359
  [[package]]
360
  name = "aws-smithy-eventstream"
361
+ version = "0.60.0"
362
  source = "registry+https://github.com/rust-lang/crates.io-index"
363
+ checksum = "1c669e1e5fc0d79561bf7a122b118bd50c898758354fe2c53eb8f2d31507cbc3"
364
  dependencies = [
365
  "aws-smithy-types",
366
  "bytes",
 
369
 
370
  [[package]]
371
  name = "aws-smithy-http"
372
+ version = "0.60.0"
373
  source = "registry+https://github.com/rust-lang/crates.io-index"
374
+ checksum = "5b1de8aee22f67de467b2e3d0dd0fb30859dc53f579a63bd5381766b987db644"
375
  dependencies = [
376
  "aws-smithy-eventstream",
377
  "aws-smithy-runtime-api",
 
390
 
391
  [[package]]
392
  name = "aws-smithy-json"
393
+ version = "0.60.0"
394
  source = "registry+https://github.com/rust-lang/crates.io-index"
395
+ checksum = "6a46dd338dc9576d6a6a5b5a19bd678dcad018ececee11cf28ecd7588bd1a55c"
396
  dependencies = [
397
  "aws-smithy-types",
398
  ]
399
 
400
  [[package]]
401
  name = "aws-smithy-query"
402
+ version = "0.60.0"
403
  source = "registry+https://github.com/rust-lang/crates.io-index"
404
+ checksum = "feb5b8c7a86d4b6399169670723b7e6f21a39fc833a30f5c5a2f997608178129"
405
  dependencies = [
406
  "aws-smithy-types",
407
  "urlencoding",
 
409
 
410
  [[package]]
411
  name = "aws-smithy-runtime"
412
+ version = "1.0.0"
413
  source = "registry+https://github.com/rust-lang/crates.io-index"
414
+ checksum = "2dac9354849acb0ce5f64f97321d1ca7703336542630b2e91bd3fcddbf1719a3"
415
  dependencies = [
416
  "aws-smithy-async",
417
  "aws-smithy-http",
 
433
 
434
  [[package]]
435
  name = "aws-smithy-runtime-api"
436
+ version = "1.0.0"
437
  source = "registry+https://github.com/rust-lang/crates.io-index"
438
+ checksum = "f8d85925920c037d30cfdd4cd93680e94c66671fd88083f9a96cb7bb456ef021"
439
  dependencies = [
440
  "aws-smithy-async",
441
  "aws-smithy-types",
 
449
 
450
  [[package]]
451
  name = "aws-smithy-types"
452
+ version = "1.0.0"
453
  source = "registry+https://github.com/rust-lang/crates.io-index"
454
+ checksum = "91c44684ec45e4ca6f535912885e18e6f7e88c873802cc115a6fb54aebed80f2"
455
  dependencies = [
456
  "base64-simd",
457
  "bytes",
 
472
 
473
  [[package]]
474
  name = "aws-smithy-xml"
475
+ version = "0.60.0"
476
  source = "registry+https://github.com/rust-lang/crates.io-index"
477
+ checksum = "0ec40d74a67fd395bc3f6b4ccbdf1543672622d905ef3f979689aea5b730cb95"
478
  dependencies = [
479
  "xmlparser",
480
  ]
481
 
482
  [[package]]
483
  name = "aws-types"
484
+ version = "1.0.0"
485
  source = "registry+https://github.com/rust-lang/crates.io-index"
486
+ checksum = "b18c0eb301cce69298555c4884795497c67b3bd511aa3f07470382f4bf3ef043"
487
  dependencies = [
488
  "aws-credential-types",
489
  "aws-smithy-async",
 
1565
  "tracing-subscriber",
1566
  "tracing-test",
1567
  "whisper",
 
 
1568
  ]
1569
 
1570
  [[package]]
 
2535
  version = "0.1.0"
2536
  dependencies = [
2537
  "fvad",
 
2538
  "lazy_static",
2539
  "once_cell",
2540
  "serde",
2541
  "tokio",
2542
  "tracing",
 
2543
  "whisper-rs",
2544
  "whisper-rs-sys",
2545
  ]
Cargo.toml CHANGED
@@ -3,16 +3,13 @@ name = "polyhedron"
3
  version = "0.1.0"
4
  edition = "2021"
5
 
6
- [workspace]
7
- members = ["whisper"]
8
-
9
  [dependencies]
10
  anyhow = "1.0"
11
  async-stream = "0.3"
12
- aws-config = "0.57.2"
13
- aws-sdk-transcribestreaming = "0.36.0"
14
- aws-sdk-translate = "0.36.0"
15
- aws-sdk-polly = "0.36.0"
16
  config = "0.13"
17
  futures-util = "0.3"
18
  once_cell = "1.18"
@@ -35,13 +32,6 @@ whisper = ["dep:whisper"]
35
  version = "1.3"
36
  features = ["websocket", "static-files"]
37
 
38
- [dependencies.whisper-rs]
39
- git = "https://github.com/mingyang91/whisper-rs.git"
40
- features = ["coreml", "metal"]
41
- [dependencies.whisper-rs-sys]
42
- git = "https://github.com/mingyang91/whisper-rs.git"
43
- package = "whisper-rs-sys"
44
-
45
  [dev-dependencies]
46
  hound = "3.5.1"
47
  tracing-test = "*"
 
3
  version = "0.1.0"
4
  edition = "2021"
5
 
 
 
 
6
  [dependencies]
7
  anyhow = "1.0"
8
  async-stream = "0.3"
9
+ aws-config = "1.0.0"
10
+ aws-sdk-transcribestreaming = "0.39.0"
11
+ aws-sdk-translate = "0.39.0"
12
+ aws-sdk-polly = "0.39.0"
13
  config = "0.13"
14
  futures-util = "0.3"
15
  once_cell = "1.18"
 
32
  version = "1.3"
33
  features = ["websocket", "static-files"]
34
 
 
 
 
 
 
 
 
35
  [dev-dependencies]
36
  hound = "3.5.1"
37
  tracing-test = "*"
src/asr/aws.rs CHANGED
@@ -1,7 +1,8 @@
1
  use std::error::Error;
2
- use std::fmt::{Display, Formatter};
3
  use async_stream::stream;
4
  use async_trait::async_trait;
 
5
  use aws_sdk_transcribestreaming::operation::start_stream_transcription::StartStreamTranscriptionOutput;
6
  use aws_sdk_transcribestreaming::primitives::Blob;
7
  use aws_sdk_transcribestreaming::types::{
@@ -14,17 +15,21 @@ use futures_util::TryStreamExt;
14
  use crate::asr::{ASR, Event};
15
 
16
  pub struct AWS_ASR {
17
- client: aws_sdk_transcribestreaming::Client,
18
  speaker_voice_channel: tokio::sync::mpsc::Sender<Vec<i16>>,
19
  speaker_transcript: tokio::sync::broadcast::Sender<Event>,
20
  drop_handler: Option<tokio::sync::oneshot::Sender<()>>,
21
  }
22
 
 
 
 
 
 
 
23
  impl AWS_ASR {
24
  pub async fn from_env(lang: LanguageCode) -> anyhow::Result<Self> {
25
  let config = aws_config::load_from_env().await;
26
  let transcript_client = aws_sdk_transcribestreaming::Client::new(&config);
27
- let client = transcript_client.clone();
28
 
29
  let (speaker_voice_channel, mut speaker_voice_rx) = tokio::sync::mpsc::channel::<Vec<i16>>(128);
30
  let (speaker_transcript, _) = tokio::sync::broadcast::channel::<Event>(128);
@@ -70,7 +75,6 @@ impl AWS_ASR {
70
  });
71
 
72
  Ok(Self {
73
- client,
74
  speaker_voice_channel,
75
  speaker_transcript,
76
  drop_handler: Some(drop_handler)
@@ -99,8 +103,8 @@ impl Drop for AWS_ASR {
99
 
100
  #[async_trait]
101
  impl ASR for AWS_ASR {
102
- async fn frame(&mut self, frame: &[i16]) -> anyhow::Result<()> {
103
- Ok(self.speaker_voice_channel.send(frame.to_vec()).await?)
104
  }
105
 
106
  fn subscribe(&mut self) -> Receiver<Event> {
 
1
  use std::error::Error;
2
+ use std::fmt::{Debug, Display, Formatter};
3
  use async_stream::stream;
4
  use async_trait::async_trait;
5
+ use aws_config::SdkConfig;
6
  use aws_sdk_transcribestreaming::operation::start_stream_transcription::StartStreamTranscriptionOutput;
7
  use aws_sdk_transcribestreaming::primitives::Blob;
8
  use aws_sdk_transcribestreaming::types::{
 
15
  use crate::asr::{ASR, Event};
16
 
17
  pub struct AWS_ASR {
 
18
  speaker_voice_channel: tokio::sync::mpsc::Sender<Vec<i16>>,
19
  speaker_transcript: tokio::sync::broadcast::Sender<Event>,
20
  drop_handler: Option<tokio::sync::oneshot::Sender<()>>,
21
  }
22
 
23
+ impl Debug for AWS_ASR {
24
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
25
+ write!(f, "AWS_ASR")
26
+ }
27
+ }
28
+
29
  impl AWS_ASR {
30
  pub async fn from_env(lang: LanguageCode) -> anyhow::Result<Self> {
31
  let config = aws_config::load_from_env().await;
32
  let transcript_client = aws_sdk_transcribestreaming::Client::new(&config);
 
33
 
34
  let (speaker_voice_channel, mut speaker_voice_rx) = tokio::sync::mpsc::channel::<Vec<i16>>(128);
35
  let (speaker_transcript, _) = tokio::sync::broadcast::channel::<Event>(128);
 
75
  });
76
 
77
  Ok(Self {
 
78
  speaker_voice_channel,
79
  speaker_transcript,
80
  drop_handler: Some(drop_handler)
 
103
 
104
  #[async_trait]
105
  impl ASR for AWS_ASR {
106
+ async fn frame(&mut self, frame: Vec<i16>) -> anyhow::Result<()> {
107
+ Ok(self.speaker_voice_channel.send(frame).await?)
108
  }
109
 
110
  fn subscribe(&mut self) -> Receiver<Event> {
src/asr/mod.rs CHANGED
@@ -1,4 +1,5 @@
1
- mod aws;
 
2
  pub(crate) mod whisper;
3
 
4
  use async_trait::async_trait;
@@ -12,6 +13,6 @@ pub(crate) struct Event {
12
 
13
  #[async_trait]
14
  pub(crate) trait ASR {
15
- async fn frame(&mut self, frame: &[i16]) -> anyhow::Result<()>;
16
  fn subscribe(&mut self) -> Receiver<Event>;
17
  }
 
1
+ pub(crate) mod aws;
2
+ #[cfg(feature = "whisper")]
3
  pub(crate) mod whisper;
4
 
5
  use async_trait::async_trait;
 
13
 
14
  #[async_trait]
15
  pub(crate) trait ASR {
16
+ async fn frame(&mut self, frame: Vec<i16>) -> anyhow::Result<()>;
17
  fn subscribe(&mut self) -> Receiver<Event>;
18
  }
src/asr/whisper.rs CHANGED
@@ -1,79 +1,82 @@
1
- #[cfg(feature = "whisper")]
2
- pub mod whisper_asr {
3
- use async_trait::async_trait;
4
- use tokio::{select, spawn};
5
- use tokio::sync::broadcast::Receiver;
6
- use tokio::sync::broadcast::error::RecvError;
7
- use lazy_static::lazy_static;
8
- use whisper::config::WhisperConfig;
9
 
10
- extern crate whisper;
11
 
12
- use whisper::handler::{Error, Output, WhisperHandler, Context};
13
- use crate::asr::{ASR, Event};
14
- use crate::config::SETTINGS;
15
 
16
- lazy_static! {
17
- pub static ref CONTEXT: Context = Context::new(&SETTINGS.whisper.model)
18
- .expect("Failed to initialize whisper context");
19
- }
 
 
 
 
 
20
 
21
- pub struct Whisper_ASR {
22
- whisper: WhisperHandler,
23
- tx: tokio::sync::broadcast::Sender<Event>,
24
  }
 
25
 
26
- impl Whisper_ASR {
27
- pub async fn from_config() -> Result<Whisper_ASR, Error> {
28
- let whisper = CONTEXT.create_handler(&SETTINGS.whisper, "".to_string())?;
29
- let mut output_rx = whisper.subscribe();
30
- let (tx, _) = tokio::sync::broadcast::channel(64);
31
- let shared_tx = tx.clone();
32
- let fut = async move {
33
- loop {
34
- select! {
35
- poll = output_rx.recv() => {
36
- match poll {
37
- Ok(outputs) => {
38
- for output in outputs {
39
- let res = match output {
40
- Output::Stable(segment) => tx.send(Event {
41
- transcript: segment.text,
42
- is_final: true,
43
- }),
44
- Output::Unstable(segment) => tx.send(Event {
45
- transcript: segment.text,
46
- is_final: false,
47
- }),
48
- };
49
- if let Err(e) = res {
50
- tracing::warn!("Failed to send whisper event: {}", e);
51
- break
52
- }
53
  }
54
- },
55
- Err(RecvError::Closed) => break,
56
- Err(RecvError::Lagged(lagged)) => {
57
- tracing::warn!("Whisper ASR output lagged: {}", lagged);
58
  }
 
 
 
 
59
  }
60
- },
61
- }
62
  }
63
- };
64
- spawn(fut);
65
- Ok(Self { whisper, tx: shared_tx })
66
- }
67
  }
 
68
 
69
- #[async_trait]
70
- impl ASR for Whisper_ASR {
71
- async fn frame(&mut self, frame: &[i16]) -> anyhow::Result<()> {
72
- Ok(self.whisper.send_i16(frame.to_vec()).await?)
73
- }
74
 
75
- fn subscribe(&mut self) -> Receiver<Event> {
76
- self.tx.subscribe()
77
- }
78
  }
79
  }
 
1
+ use std::fmt::{Debug, Formatter};
2
+ use async_trait::async_trait;
3
+ use tokio::{select, spawn};
4
+ use tokio::sync::broadcast::Receiver;
5
+ use tokio::sync::broadcast::error::RecvError;
6
+ use lazy_static::lazy_static;
 
 
7
 
8
+ extern crate whisper;
9
 
10
+ use whisper::handler::{Error, Output, WhisperHandler, Context};
11
+ use crate::asr::{ASR, Event};
12
+ use crate::config::SETTINGS;
13
 
14
+ lazy_static! {
15
+ pub static ref CONTEXT: Context = Context::new(&SETTINGS.whisper.model)
16
+ .expect("Failed to initialize whisper context");
17
+ }
18
+
19
+ pub struct Whisper_ASR {
20
+ whisper: WhisperHandler,
21
+ tx: tokio::sync::broadcast::Sender<Event>,
22
+ }
23
 
24
+ impl Debug for Whisper_ASR {
25
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
26
+ write!(f, "Whisper_ASR")
27
  }
28
+ }
29
 
30
+ impl Whisper_ASR {
31
+ pub async fn from_config() -> Result<Whisper_ASR, Error> {
32
+ let whisper = CONTEXT.create_handler(&SETTINGS.whisper, "".to_string())?;
33
+ let mut output_rx = whisper.subscribe();
34
+ let (tx, _) = tokio::sync::broadcast::channel(64);
35
+ let shared_tx = tx.clone();
36
+ let fut = async move {
37
+ loop {
38
+ select! {
39
+ poll = output_rx.recv() => {
40
+ match poll {
41
+ Ok(outputs) => {
42
+ for output in outputs {
43
+ let res = match output {
44
+ Output::Stable(segment) => tx.send(Event {
45
+ transcript: segment.text,
46
+ is_final: true,
47
+ }),
48
+ Output::Unstable(segment) => tx.send(Event {
49
+ transcript: segment.text,
50
+ is_final: false,
51
+ }),
52
+ };
53
+ if let Err(e) = res {
54
+ tracing::warn!("Failed to send whisper event: {}", e);
55
+ break
 
56
  }
 
 
 
 
57
  }
58
+ },
59
+ Err(RecvError::Closed) => break,
60
+ Err(RecvError::Lagged(lagged)) => {
61
+ tracing::warn!("Whisper ASR output lagged: {}", lagged);
62
  }
63
+ }
64
+ },
65
  }
66
+ }
67
+ };
68
+ spawn(fut);
69
+ Ok(Self { whisper, tx: shared_tx })
70
  }
71
+ }
72
 
73
+ #[async_trait]
74
+ impl ASR for Whisper_ASR {
75
+ async fn frame(&mut self, frame: Vec<i16>) -> anyhow::Result<()> {
76
+ Ok(self.whisper.send_i16(frame).await?)
77
+ }
78
 
79
+ fn subscribe(&mut self) -> Receiver<Event> {
80
+ self.tx.subscribe()
 
81
  }
82
  }
src/lesson.rs CHANGED
@@ -5,35 +5,59 @@ use aws_sdk_transcribestreaming::types::{LanguageCode};
5
  use futures_util::future::try_join;
6
  use serde::{Deserialize, Serialize};
7
  use std::collections::BTreeMap;
8
- use std::fmt::{Display};
9
  use std::io::BufRead;
 
10
  use std::sync::{Arc, Weak};
11
  use tokio::sync::RwLock;
 
12
 
13
  use tokio::select;
14
- use crate::asr::Event;
15
 
16
- #[derive(Clone, Debug)]
17
- pub struct LessonsManager {
 
 
18
  translate_client: aws_sdk_translate::Client,
19
  polly_client: aws_sdk_polly::Client,
20
  lessons: Arc<RwLock<BTreeMap<u32, Lesson>>>,
21
  }
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  impl LessonsManager {
24
  pub(crate) fn new(sdk_config: &SdkConfig) -> Self {
25
  let translate_client = aws_sdk_translate::Client::new(sdk_config);
26
  let polly_client = aws_sdk_polly::Client::new(sdk_config);
27
- LessonsManager {
28
  translate_client,
29
  polly_client,
30
  lessons: Arc::new(RwLock::new(BTreeMap::new())),
31
- }
 
32
  }
33
 
34
  pub(crate) async fn create_lesson(&self, id: u32, speaker_lang: LanguageCode) -> Lesson {
35
  let mut map = self.lessons.write().await;
36
- let lesson: Lesson = InnerLesson::new(self.clone(), speaker_lang).into();
37
  map.insert(id, lesson.clone());
38
  lesson
39
  }
@@ -49,16 +73,24 @@ pub(crate) struct Lesson {
49
  inner: Arc<InnerLesson>,
50
  }
51
 
 
 
 
 
 
 
 
 
52
  impl Lesson {
53
  pub(crate) async fn get_or_init(&self, lang: String) -> LangLesson {
54
  {
55
- let map = self.inner.lang_lessons.read().await;
56
  if let Some(lang_lesson) = map.get(&lang).and_then(|weak| weak.upgrade()) {
57
  return lang_lesson.into();
58
  }
59
  }
60
  {
61
- let mut map = self.inner.lang_lessons.write().await;
62
  if let Some(lang_lesson) = map.get(&lang).and_then(|weak| weak.upgrade()) {
63
  lang_lesson.into()
64
  } else {
@@ -70,11 +102,11 @@ impl Lesson {
70
  }
71
 
72
  pub(crate) async fn send(&self, frame: Vec<i16>) -> anyhow::Result<()> {
73
- Ok(self.inner.speaker_voice_channel.send(frame).await?)
74
  }
75
 
76
  pub(crate) fn transcript_channel(&self) -> tokio::sync::broadcast::Receiver<Event> {
77
- self.inner.speaker_transcript.subscribe()
78
  }
79
  }
80
 
@@ -87,7 +119,7 @@ impl From<InnerLesson> for Lesson {
87
  }
88
 
89
  #[derive(Debug)]
90
- struct InnerLesson {
91
  parent: LessonsManager,
92
  speaker_lang: LanguageCode,
93
  speaker_voice_channel: tokio::sync::mpsc::Sender<Vec<i16>>,
@@ -97,10 +129,54 @@ struct InnerLesson {
97
  }
98
 
99
  impl InnerLesson {
100
- fn new(parent: LessonsManager, speaker_lang: LanguageCode) -> InnerLesson {
101
  let (speaker_transcript, _) = tokio::sync::broadcast::channel::<Event>(128);
102
- let (speaker_voice_channel, mut speaker_voice_rx) = tokio::sync::mpsc::channel(128);
103
  let (drop_handler, drop_rx) = tokio::sync::oneshot::channel::<Signal>();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
  InnerLesson {
106
  parent,
@@ -121,7 +197,7 @@ impl Drop for InnerLesson {
121
  }
122
  }
123
 
124
- struct InnerLangLesson {
125
  parent: Lesson,
126
  translated_tx: tokio::sync::broadcast::Sender<String>,
127
  voice_lessons: RwLock<BTreeMap<VoiceId, Weak<InnerVoiceLesson>>>,
@@ -143,7 +219,15 @@ pub(crate) struct LangLesson {
143
 
144
  impl LangLesson {
145
  pub(crate) fn translated_channel(&self) -> tokio::sync::broadcast::Receiver<String> {
146
- self.inner.translated_tx.subscribe()
 
 
 
 
 
 
 
 
147
  }
148
  }
149
 
@@ -164,11 +248,11 @@ impl From<Arc<InnerLangLesson>> for LangLesson {
164
  impl LangLesson {
165
  fn new(parent: Lesson, lang: String) -> Self {
166
  let shared_lang = lang.clone();
167
- let shared_speaker_lang = parent.inner.speaker_lang.clone();
168
  let (translated_tx, _) = tokio::sync::broadcast::channel::<String>(128);
169
  let shared_translated_tx = translated_tx.clone();
170
- let mut transcript_rx = parent.inner.speaker_transcript.subscribe();
171
- let translate_client = parent.inner.parent.translate_client.clone();
172
  let (drop_handler, drop_rx) = tokio::sync::oneshot::channel::<Signal>();
173
  tokio::spawn(async move {
174
  let fut = async {
@@ -212,14 +296,14 @@ impl LangLesson {
212
 
213
  pub(crate) async fn get_or_init(&mut self, voice: VoiceId) -> VoiceLesson {
214
  {
215
- let map = self.inner.voice_lessons.read().await;
216
  if let Some(voice_lesson) = map.get(&voice).and_then(|weak| weak.upgrade()) {
217
  return voice_lesson.into();
218
  }
219
  }
220
 
221
  {
222
- let mut map = self.inner.voice_lessons.write().await;
223
  if let Some(voice_lesson) = map.get(&voice).and_then(|weak| weak.upgrade()) {
224
  voice_lesson.into()
225
  } else {
@@ -238,11 +322,19 @@ pub(crate) struct VoiceLesson {
238
 
239
  impl VoiceLesson {
240
  pub(crate) fn voice_channel(&self) -> tokio::sync::broadcast::Receiver<Vec<u8>> {
241
- self.inner.voice_lesson.subscribe()
242
  }
243
 
244
  pub(crate) fn lip_sync_channel(&self) -> tokio::sync::broadcast::Receiver<Vec<Viseme>> {
245
- self.inner.lip_sync_tx.subscribe()
 
 
 
 
 
 
 
 
246
  }
247
  }
248
 
@@ -260,7 +352,7 @@ impl From<Arc<InnerVoiceLesson>> for VoiceLesson {
260
  }
261
  }
262
 
263
- struct InnerVoiceLesson {
264
  lip_sync_tx: tokio::sync::broadcast::Sender<Vec<Viseme>>,
265
  voice_lesson: tokio::sync::broadcast::Sender<Vec<u8>>,
266
  drop_handler: Option<tokio::sync::oneshot::Sender<Signal>>,
@@ -275,13 +367,13 @@ impl InnerVoiceLesson {
275
  fn new(parent: LangLesson, voice: VoiceId) -> InnerVoiceLesson {
276
  let shared_voice_id: VoiceId = voice.clone();
277
  let (tx, rx) = tokio::sync::oneshot::channel::<Signal>();
278
- let mut translate_rx = parent.inner.translated_tx.subscribe();
279
  let (voice_lesson, _) = tokio::sync::broadcast::channel::<Vec<u8>>(128);
280
  let shared_voice_lesson = voice_lesson.clone();
281
  let (lip_sync_tx, _) = tokio::sync::broadcast::channel::<Vec<Viseme>>(128);
282
  let shared_lip_sync_tx = lip_sync_tx.clone();
283
- let client = parent.inner.parent.inner.parent.polly_client.clone();
284
- // let lang: LanguageCode = parent.inner.lang.clone().parse().expect("Invalid language code");
285
  tokio::spawn(async move {
286
  let fut = async {
287
  while let Ok(translated) = translate_rx.recv().await {
 
5
  use futures_util::future::try_join;
6
  use serde::{Deserialize, Serialize};
7
  use std::collections::BTreeMap;
8
+ use std::fmt::{Debug, Display, Formatter};
9
  use std::io::BufRead;
10
+ use std::ops::Deref;
11
  use std::sync::{Arc, Weak};
12
  use tokio::sync::RwLock;
13
+ use tracing::warn;
14
 
15
  use tokio::select;
16
+ use crate::asr::{Event, aws::AWS_ASR, ASR};
17
 
18
+ #[cfg(feature = "whisper")]
19
+ use crate::asr::whisper::Whisper_ASR;
20
+
21
+ pub struct InnerLessonsManager {
22
  translate_client: aws_sdk_translate::Client,
23
  polly_client: aws_sdk_polly::Client,
24
  lessons: Arc<RwLock<BTreeMap<u32, Lesson>>>,
25
  }
26
 
27
+ #[derive(Clone)]
28
+ pub struct LessonsManager {
29
+ inner: Arc<InnerLessonsManager>,
30
+ }
31
+
32
+ impl Debug for LessonsManager {
33
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34
+ f.debug_struct("LessonsManager").finish()
35
+ }
36
+ }
37
+
38
+ impl Deref for LessonsManager {
39
+ type Target = InnerLessonsManager;
40
+
41
+ fn deref(&self) -> &Self::Target {
42
+ &self.inner
43
+ }
44
+ }
45
+
46
  impl LessonsManager {
47
  pub(crate) fn new(sdk_config: &SdkConfig) -> Self {
48
  let translate_client = aws_sdk_translate::Client::new(sdk_config);
49
  let polly_client = aws_sdk_polly::Client::new(sdk_config);
50
+ let inner = InnerLessonsManager {
51
  translate_client,
52
  polly_client,
53
  lessons: Arc::new(RwLock::new(BTreeMap::new())),
54
+ };
55
+ LessonsManager { inner: Arc::new(inner) }
56
  }
57
 
58
  pub(crate) async fn create_lesson(&self, id: u32, speaker_lang: LanguageCode) -> Lesson {
59
  let mut map = self.lessons.write().await;
60
+ let lesson: Lesson = InnerLesson::new(self.clone(), speaker_lang).await.into();
61
  map.insert(id, lesson.clone());
62
  lesson
63
  }
 
73
  inner: Arc<InnerLesson>,
74
  }
75
 
76
+ impl Deref for Lesson {
77
+ type Target = InnerLesson;
78
+
79
+ fn deref(&self) -> &Self::Target {
80
+ &self.inner
81
+ }
82
+ }
83
+
84
  impl Lesson {
85
  pub(crate) async fn get_or_init(&self, lang: String) -> LangLesson {
86
  {
87
+ let map = self.lang_lessons.read().await;
88
  if let Some(lang_lesson) = map.get(&lang).and_then(|weak| weak.upgrade()) {
89
  return lang_lesson.into();
90
  }
91
  }
92
  {
93
+ let mut map = self.lang_lessons.write().await;
94
  if let Some(lang_lesson) = map.get(&lang).and_then(|weak| weak.upgrade()) {
95
  lang_lesson.into()
96
  } else {
 
102
  }
103
 
104
  pub(crate) async fn send(&self, frame: Vec<i16>) -> anyhow::Result<()> {
105
+ Ok(self.speaker_voice_channel.send(frame).await?)
106
  }
107
 
108
  pub(crate) fn transcript_channel(&self) -> tokio::sync::broadcast::Receiver<Event> {
109
+ self.speaker_transcript.subscribe()
110
  }
111
  }
112
 
 
119
  }
120
 
121
  #[derive(Debug)]
122
+ pub(crate) struct InnerLesson {
123
  parent: LessonsManager,
124
  speaker_lang: LanguageCode,
125
  speaker_voice_channel: tokio::sync::mpsc::Sender<Vec<i16>>,
 
129
  }
130
 
131
  impl InnerLesson {
132
+ async fn new(parent: LessonsManager, speaker_lang: LanguageCode) -> InnerLesson {
133
  let (speaker_transcript, _) = tokio::sync::broadcast::channel::<Event>(128);
134
+ let (speaker_voice_channel, mut speaker_voice_rx) = tokio::sync::mpsc::channel::<Vec<i16>>(128);
135
  let (drop_handler, drop_rx) = tokio::sync::oneshot::channel::<Signal>();
136
+ let mut aws_asr = AWS_ASR::from_env(LanguageCode::EnGb)
137
+ .await
138
+ .expect("Failed to initialize AWS ASR");
139
+ #[cfg(feature = "whisper")]
140
+ let mut whisper_asr = Whisper_ASR::from_config()
141
+ .await
142
+ .expect("Failed to initialize Whisper ASR");
143
+
144
+ tokio::spawn(async move {
145
+ let fut = async {
146
+ #[cfg(not(feature = "whisper"))]
147
+ let mut transcribe = aws_asr.subscribe();
148
+ #[cfg(feature = "whisper")]
149
+ let mut transcribe = whisper_asr.subscribe();
150
+ loop {
151
+ select! {
152
+ msg = speaker_voice_rx.recv() => {
153
+ match msg {
154
+ Some(frame) => {
155
+ #[cfg(not(feature = "whisper"))]
156
+ let res = aws_asr.frame(frame).await?;
157
+ #[cfg(feature = "whisper")]
158
+ let res = whisper_asr.frame(frame).await?;
159
+ },
160
+ None => break,
161
+ }
162
+ },
163
+ a = transcribe.recv() => {
164
+ todo!()
165
+ }
166
+ }
167
+ }
168
+
169
+ Ok(()) as anyhow::Result<()>
170
+ };
171
+ select! {
172
+ res = fut => {
173
+ if let Err(e) = res {
174
+ warn!("Error: {:?}", e);
175
+ }
176
+ }
177
+ _ = drop_rx => {}
178
+ }
179
+ });
180
 
181
  InnerLesson {
182
  parent,
 
197
  }
198
  }
199
 
200
+ pub(crate) struct InnerLangLesson {
201
  parent: Lesson,
202
  translated_tx: tokio::sync::broadcast::Sender<String>,
203
  voice_lessons: RwLock<BTreeMap<VoiceId, Weak<InnerVoiceLesson>>>,
 
219
 
220
  impl LangLesson {
221
  pub(crate) fn translated_channel(&self) -> tokio::sync::broadcast::Receiver<String> {
222
+ self.translated_tx.subscribe()
223
+ }
224
+ }
225
+
226
+ impl Deref for LangLesson {
227
+ type Target = InnerLangLesson;
228
+
229
+ fn deref(&self) -> &Self::Target {
230
+ &self.inner
231
  }
232
  }
233
 
 
248
  impl LangLesson {
249
  fn new(parent: Lesson, lang: String) -> Self {
250
  let shared_lang = lang.clone();
251
+ let shared_speaker_lang = parent.speaker_lang.clone();
252
  let (translated_tx, _) = tokio::sync::broadcast::channel::<String>(128);
253
  let shared_translated_tx = translated_tx.clone();
254
+ let mut transcript_rx = parent.speaker_transcript.subscribe();
255
+ let translate_client = parent.parent.translate_client.clone();
256
  let (drop_handler, drop_rx) = tokio::sync::oneshot::channel::<Signal>();
257
  tokio::spawn(async move {
258
  let fut = async {
 
296
 
297
  pub(crate) async fn get_or_init(&mut self, voice: VoiceId) -> VoiceLesson {
298
  {
299
+ let map = self.voice_lessons.read().await;
300
  if let Some(voice_lesson) = map.get(&voice).and_then(|weak| weak.upgrade()) {
301
  return voice_lesson.into();
302
  }
303
  }
304
 
305
  {
306
+ let mut map = self.voice_lessons.write().await;
307
  if let Some(voice_lesson) = map.get(&voice).and_then(|weak| weak.upgrade()) {
308
  voice_lesson.into()
309
  } else {
 
322
 
323
  impl VoiceLesson {
324
  pub(crate) fn voice_channel(&self) -> tokio::sync::broadcast::Receiver<Vec<u8>> {
325
+ self.voice_lesson.subscribe()
326
  }
327
 
328
  pub(crate) fn lip_sync_channel(&self) -> tokio::sync::broadcast::Receiver<Vec<Viseme>> {
329
+ self.lip_sync_tx.subscribe()
330
+ }
331
+ }
332
+
333
+ impl Deref for VoiceLesson {
334
+ type Target = InnerVoiceLesson;
335
+
336
+ fn deref(&self) -> &Self::Target {
337
+ &self.inner
338
  }
339
  }
340
 
 
352
  }
353
  }
354
 
355
+ pub(crate) struct InnerVoiceLesson {
356
  lip_sync_tx: tokio::sync::broadcast::Sender<Vec<Viseme>>,
357
  voice_lesson: tokio::sync::broadcast::Sender<Vec<u8>>,
358
  drop_handler: Option<tokio::sync::oneshot::Sender<Signal>>,
 
367
  fn new(parent: LangLesson, voice: VoiceId) -> InnerVoiceLesson {
368
  let shared_voice_id: VoiceId = voice.clone();
369
  let (tx, rx) = tokio::sync::oneshot::channel::<Signal>();
370
+ let mut translate_rx = parent.translated_tx.subscribe();
371
  let (voice_lesson, _) = tokio::sync::broadcast::channel::<Vec<u8>>(128);
372
  let shared_voice_lesson = voice_lesson.clone();
373
  let (lip_sync_tx, _) = tokio::sync::broadcast::channel::<Vec<Viseme>>(128);
374
  let shared_lip_sync_tx = lip_sync_tx.clone();
375
+ let client = parent.parent.parent.polly_client.clone();
376
+ // let lang: LanguageCode = parent.lang.clone().parse().expect("Invalid language code");
377
  tokio::spawn(async move {
378
  let fut = async {
379
  while let Ok(translated) = translate_rx.recv().await {