@magmamath/students-features 0.9.113 → 0.9.114-rc.1

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.
Files changed (367) hide show
  1. package/dist/commonjs/features/chatbot/components/ChatInput/RequestHintButton.js.map +1 -1
  2. package/dist/commonjs/features/chatbot/components/ChatMessage/MessageButtonsBlock.js.map +1 -1
  3. package/dist/commonjs/features/chatbot/components/ChatMessage/MessageTextToSpeech.js +8 -48
  4. package/dist/commonjs/features/chatbot/components/ChatMessage/MessageTextToSpeech.js.map +1 -1
  5. package/dist/commonjs/features/chatbot/constants.js +4 -4
  6. package/dist/commonjs/features/chatbot/constants.js.map +1 -1
  7. package/dist/commonjs/features/gifCelebrations/helpers.js +1 -0
  8. package/dist/commonjs/features/gifCelebrations/helpers.js.map +1 -1
  9. package/dist/commonjs/features/voice/constants.js +22 -0
  10. package/dist/commonjs/features/voice/constants.js.map +1 -0
  11. package/dist/commonjs/features/voice/helpers.js +211 -0
  12. package/dist/commonjs/features/voice/helpers.js.map +1 -0
  13. package/dist/commonjs/features/voice/index.js +138 -0
  14. package/dist/commonjs/features/voice/index.js.map +1 -0
  15. package/dist/commonjs/features/voice/model/index.js +68 -0
  16. package/dist/commonjs/features/voice/model/index.js.map +1 -0
  17. package/dist/commonjs/features/voice/playing/components/VoiceIcon.js +49 -0
  18. package/dist/commonjs/features/voice/playing/components/VoiceIcon.js.map +1 -0
  19. package/dist/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdown.js +208 -0
  20. package/dist/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdown.js.map +1 -0
  21. package/dist/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdownItem.js +108 -0
  22. package/dist/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdownItem.js.map +1 -0
  23. package/dist/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.js +50 -0
  24. package/dist/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.js.map +1 -0
  25. package/dist/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.js +34 -0
  26. package/dist/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.js.map +1 -0
  27. package/dist/commonjs/features/voice/playing/model/Player.model.js +87 -0
  28. package/dist/commonjs/features/voice/playing/model/Player.model.js.map +1 -0
  29. package/dist/commonjs/features/voice/playing/model/VoicePlayer.model.js +244 -0
  30. package/dist/commonjs/features/voice/playing/model/VoicePlayer.model.js.map +1 -0
  31. package/dist/commonjs/features/voice/playing/model/VoiceTranscriptionsCollection.js +41 -0
  32. package/dist/commonjs/features/voice/playing/model/VoiceTranscriptionsCollection.js.map +1 -0
  33. package/dist/commonjs/features/voice/playing/model/VoiceTranscriptionsDownloader.model.js +39 -0
  34. package/dist/commonjs/features/voice/playing/model/VoiceTranscriptionsDownloader.model.js.map +1 -0
  35. package/dist/commonjs/features/voice/playing/model/VoiceTranscriptionsDropdown.model.js +15 -0
  36. package/dist/commonjs/features/voice/playing/model/VoiceTranscriptionsDropdown.model.js.map +1 -0
  37. package/dist/commonjs/features/voice/playing/model/index.js +47 -0
  38. package/dist/commonjs/features/voice/playing/model/index.js.map +1 -0
  39. package/dist/commonjs/features/voice/recording/components/VoiceRecord.js +74 -0
  40. package/dist/commonjs/features/voice/recording/components/VoiceRecord.js.map +1 -0
  41. package/dist/commonjs/features/voice/recording/components/VoiceRecordButton.js +61 -0
  42. package/dist/commonjs/features/voice/recording/components/VoiceRecordButton.js.map +1 -0
  43. package/dist/commonjs/features/voice/recording/components/VoiceRecordDeleteButton.js +35 -0
  44. package/dist/commonjs/features/voice/recording/components/VoiceRecordDeleteButton.js.map +1 -0
  45. package/dist/commonjs/features/voice/recording/components/VoiceRecordDevider.js +27 -0
  46. package/dist/commonjs/features/voice/recording/components/VoiceRecordDevider.js.map +1 -0
  47. package/dist/commonjs/features/voice/recording/components/VoiceRecordTimer.js +50 -0
  48. package/dist/commonjs/features/voice/recording/components/VoiceRecordTimer.js.map +1 -0
  49. package/dist/commonjs/features/voice/recording/hooks/useVoiceRecorder.js +59 -0
  50. package/dist/commonjs/features/voice/recording/hooks/useVoiceRecorder.js.map +1 -0
  51. package/dist/commonjs/features/voice/recording/hooks/useVoiceRecorderAnimation.js +22 -0
  52. package/dist/commonjs/features/voice/recording/hooks/useVoiceRecorderAnimation.js.map +1 -0
  53. package/dist/commonjs/features/voice/recording/modal/ModalFooterButtons.js +53 -0
  54. package/dist/commonjs/features/voice/recording/modal/ModalFooterButtons.js.map +1 -0
  55. package/dist/commonjs/features/voice/recording/modal/VoiceRecordDeleteModal.js +78 -0
  56. package/dist/commonjs/features/voice/recording/modal/VoiceRecordDeleteModal.js.map +1 -0
  57. package/dist/commonjs/features/voice/recording/modal/VoiceRecordUndoModal.js +51 -0
  58. package/dist/commonjs/features/voice/recording/modal/VoiceRecordUndoModal.js.map +1 -0
  59. package/dist/commonjs/features/voice/recording/model/Recorder.model.js +54 -0
  60. package/dist/commonjs/features/voice/recording/model/Recorder.model.js.map +1 -0
  61. package/dist/commonjs/features/voice/recording/model/Uploader.model.js +44 -0
  62. package/dist/commonjs/features/voice/recording/model/Uploader.model.js.map +1 -0
  63. package/dist/commonjs/features/voice/recording/model/VoiceRecord.model.js +239 -0
  64. package/dist/commonjs/features/voice/recording/model/VoiceRecord.model.js.map +1 -0
  65. package/dist/commonjs/features/voice/recording/model/VoiceRecordCollection.js +30 -0
  66. package/dist/commonjs/features/voice/recording/model/VoiceRecordCollection.js.map +1 -0
  67. package/dist/commonjs/features/voice/recording/model/index.js +34 -0
  68. package/dist/commonjs/features/voice/recording/model/index.js.map +1 -0
  69. package/dist/commonjs/features/voice/types.js +6 -0
  70. package/dist/commonjs/features/voice/types.js.map +1 -0
  71. package/dist/commonjs/index.js +12 -0
  72. package/dist/commonjs/index.js.map +1 -1
  73. package/dist/commonjs/shared/components/PlayButton.js +70 -0
  74. package/dist/commonjs/shared/components/PlayButton.js.map +1 -0
  75. package/dist/commonjs/shared/translation/localization/ca.json +17 -0
  76. package/dist/commonjs/shared/translation/localization/de.json +17 -0
  77. package/dist/commonjs/shared/translation/localization/en.json +17 -0
  78. package/dist/commonjs/shared/translation/localization/gb.json +17 -0
  79. package/dist/commonjs/shared/translation/localization/sct.json +17 -0
  80. package/dist/commonjs/shared/translation/localization/sw.json +17 -0
  81. package/dist/module/features/chatbot/components/ChatInput/RequestHintButton.js.map +1 -1
  82. package/dist/module/features/chatbot/components/ChatMessage/MessageButtonsBlock.js.map +1 -1
  83. package/dist/module/features/chatbot/components/ChatMessage/MessageTextToSpeech.js +9 -49
  84. package/dist/module/features/chatbot/components/ChatMessage/MessageTextToSpeech.js.map +1 -1
  85. package/dist/module/features/chatbot/constants.js +5 -5
  86. package/dist/module/features/chatbot/constants.js.map +1 -1
  87. package/dist/module/features/gifCelebrations/helpers.js +1 -0
  88. package/dist/module/features/gifCelebrations/helpers.js.map +1 -1
  89. package/dist/module/features/voice/constants.js +18 -0
  90. package/dist/module/features/voice/constants.js.map +1 -0
  91. package/dist/module/features/voice/helpers.js +194 -0
  92. package/dist/module/features/voice/helpers.js.map +1 -0
  93. package/dist/module/features/voice/index.js +20 -0
  94. package/dist/module/features/voice/index.js.map +1 -0
  95. package/dist/module/features/voice/model/index.js +15 -0
  96. package/dist/module/features/voice/model/index.js.map +1 -0
  97. package/dist/module/features/voice/playing/components/VoiceIcon.js +41 -0
  98. package/dist/module/features/voice/playing/components/VoiceIcon.js.map +1 -0
  99. package/dist/module/features/voice/playing/components/VoiceTranscriptionsDropdown.js +201 -0
  100. package/dist/module/features/voice/playing/components/VoiceTranscriptionsDropdown.js.map +1 -0
  101. package/dist/module/features/voice/playing/components/VoiceTranscriptionsDropdownItem.js +102 -0
  102. package/dist/module/features/voice/playing/components/VoiceTranscriptionsDropdownItem.js.map +1 -0
  103. package/dist/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.js +45 -0
  104. package/dist/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.js.map +1 -0
  105. package/dist/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.js +29 -0
  106. package/dist/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.js.map +1 -0
  107. package/dist/module/features/voice/playing/model/Player.model.js +82 -0
  108. package/dist/module/features/voice/playing/model/Player.model.js.map +1 -0
  109. package/dist/module/features/voice/playing/model/VoicePlayer.model.js +234 -0
  110. package/dist/module/features/voice/playing/model/VoicePlayer.model.js.map +1 -0
  111. package/dist/module/features/voice/playing/model/VoiceTranscriptionsCollection.js +36 -0
  112. package/dist/module/features/voice/playing/model/VoiceTranscriptionsCollection.js.map +1 -0
  113. package/dist/module/features/voice/playing/model/VoiceTranscriptionsDownloader.model.js +34 -0
  114. package/dist/module/features/voice/playing/model/VoiceTranscriptionsDownloader.model.js.map +1 -0
  115. package/dist/module/features/voice/playing/model/VoiceTranscriptionsDropdown.model.js +10 -0
  116. package/dist/module/features/voice/playing/model/VoiceTranscriptionsDropdown.model.js.map +1 -0
  117. package/dist/module/features/voice/playing/model/index.js +8 -0
  118. package/dist/module/features/voice/playing/model/index.js.map +1 -0
  119. package/dist/module/features/voice/recording/components/VoiceRecord.js +67 -0
  120. package/dist/module/features/voice/recording/components/VoiceRecord.js.map +1 -0
  121. package/dist/module/features/voice/recording/components/VoiceRecordButton.js +55 -0
  122. package/dist/module/features/voice/recording/components/VoiceRecordButton.js.map +1 -0
  123. package/dist/module/features/voice/recording/components/VoiceRecordDeleteButton.js +29 -0
  124. package/dist/module/features/voice/recording/components/VoiceRecordDeleteButton.js.map +1 -0
  125. package/dist/module/features/voice/recording/components/VoiceRecordDevider.js +21 -0
  126. package/dist/module/features/voice/recording/components/VoiceRecordDevider.js.map +1 -0
  127. package/dist/module/features/voice/recording/components/VoiceRecordTimer.js +44 -0
  128. package/dist/module/features/voice/recording/components/VoiceRecordTimer.js.map +1 -0
  129. package/dist/module/features/voice/recording/hooks/useVoiceRecorder.js +54 -0
  130. package/dist/module/features/voice/recording/hooks/useVoiceRecorder.js.map +1 -0
  131. package/dist/module/features/voice/recording/hooks/useVoiceRecorderAnimation.js +17 -0
  132. package/dist/module/features/voice/recording/hooks/useVoiceRecorderAnimation.js.map +1 -0
  133. package/dist/module/features/voice/recording/modal/ModalFooterButtons.js +47 -0
  134. package/dist/module/features/voice/recording/modal/ModalFooterButtons.js.map +1 -0
  135. package/dist/module/features/voice/recording/modal/VoiceRecordDeleteModal.js +71 -0
  136. package/dist/module/features/voice/recording/modal/VoiceRecordDeleteModal.js.map +1 -0
  137. package/dist/module/features/voice/recording/modal/VoiceRecordUndoModal.js +45 -0
  138. package/dist/module/features/voice/recording/modal/VoiceRecordUndoModal.js.map +1 -0
  139. package/dist/module/features/voice/recording/model/Recorder.model.js +49 -0
  140. package/dist/module/features/voice/recording/model/Recorder.model.js.map +1 -0
  141. package/dist/module/features/voice/recording/model/Uploader.model.js +39 -0
  142. package/dist/module/features/voice/recording/model/Uploader.model.js.map +1 -0
  143. package/dist/module/features/voice/recording/model/VoiceRecord.model.js +234 -0
  144. package/dist/module/features/voice/recording/model/VoiceRecord.model.js.map +1 -0
  145. package/dist/module/features/voice/recording/model/VoiceRecordCollection.js +25 -0
  146. package/dist/module/features/voice/recording/model/VoiceRecordCollection.js.map +1 -0
  147. package/dist/module/features/voice/recording/model/index.js +7 -0
  148. package/dist/module/features/voice/recording/model/index.js.map +1 -0
  149. package/dist/module/features/voice/types.js +4 -0
  150. package/dist/module/features/voice/types.js.map +1 -0
  151. package/dist/module/index.js +1 -0
  152. package/dist/module/index.js.map +1 -1
  153. package/dist/module/shared/components/PlayButton.js +64 -0
  154. package/dist/module/shared/components/PlayButton.js.map +1 -0
  155. package/dist/module/shared/translation/localization/ca.json +17 -0
  156. package/dist/module/shared/translation/localization/de.json +17 -0
  157. package/dist/module/shared/translation/localization/en.json +17 -0
  158. package/dist/module/shared/translation/localization/gb.json +17 -0
  159. package/dist/module/shared/translation/localization/sct.json +17 -0
  160. package/dist/module/shared/translation/localization/sw.json +17 -0
  161. package/dist/typescript/commonjs/features/chatbot/components/ChatInput/RequestHintButton.d.ts.map +1 -1
  162. package/dist/typescript/commonjs/features/chatbot/components/ChatMessage/MessageButtonsBlock.d.ts.map +1 -1
  163. package/dist/typescript/commonjs/features/chatbot/components/ChatMessage/MessageTextToSpeech.d.ts +2 -2
  164. package/dist/typescript/commonjs/features/chatbot/components/ChatMessage/MessageTextToSpeech.d.ts.map +1 -1
  165. package/dist/typescript/commonjs/features/chatbot/constants.d.ts +5 -5
  166. package/dist/typescript/commonjs/features/chatbot/constants.d.ts.map +1 -1
  167. package/dist/typescript/commonjs/features/gifCelebrations/helpers.d.ts.map +1 -1
  168. package/dist/typescript/commonjs/features/voice/constants.d.ts +15 -0
  169. package/dist/typescript/commonjs/features/voice/constants.d.ts.map +1 -0
  170. package/dist/typescript/commonjs/features/voice/helpers.d.ts +46 -0
  171. package/dist/typescript/commonjs/features/voice/helpers.d.ts.map +1 -0
  172. package/dist/typescript/commonjs/features/voice/index.d.ts +13 -0
  173. package/dist/typescript/commonjs/features/voice/index.d.ts.map +1 -0
  174. package/dist/typescript/commonjs/features/voice/model/index.d.ts +11 -0
  175. package/dist/typescript/commonjs/features/voice/model/index.d.ts.map +1 -0
  176. package/dist/typescript/commonjs/features/voice/playing/components/VoiceIcon.d.ts +8 -0
  177. package/dist/typescript/commonjs/features/voice/playing/components/VoiceIcon.d.ts.map +1 -0
  178. package/dist/typescript/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdown.d.ts +15 -0
  179. package/dist/typescript/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdown.d.ts.map +1 -0
  180. package/dist/typescript/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdownItem.d.ts +12 -0
  181. package/dist/typescript/commonjs/features/voice/playing/components/VoiceTranscriptionsDropdownItem.d.ts.map +1 -0
  182. package/dist/typescript/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.d.ts +16 -0
  183. package/dist/typescript/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.d.ts.map +1 -0
  184. package/dist/typescript/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.d.ts +11 -0
  185. package/dist/typescript/commonjs/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.d.ts.map +1 -0
  186. package/dist/typescript/commonjs/features/voice/playing/model/Player.model.d.ts +21 -0
  187. package/dist/typescript/commonjs/features/voice/playing/model/Player.model.d.ts.map +1 -0
  188. package/dist/typescript/commonjs/features/voice/playing/model/VoicePlayer.model.d.ts +41 -0
  189. package/dist/typescript/commonjs/features/voice/playing/model/VoicePlayer.model.d.ts.map +1 -0
  190. package/dist/typescript/commonjs/features/voice/playing/model/VoiceTranscriptionsCollection.d.ts +26 -0
  191. package/dist/typescript/commonjs/features/voice/playing/model/VoiceTranscriptionsCollection.d.ts.map +1 -0
  192. package/dist/typescript/commonjs/features/voice/playing/model/VoiceTranscriptionsDownloader.model.d.ts +18 -0
  193. package/dist/typescript/commonjs/features/voice/playing/model/VoiceTranscriptionsDownloader.model.d.ts.map +1 -0
  194. package/dist/typescript/commonjs/features/voice/playing/model/VoiceTranscriptionsDropdown.model.d.ts +7 -0
  195. package/dist/typescript/commonjs/features/voice/playing/model/VoiceTranscriptionsDropdown.model.d.ts.map +1 -0
  196. package/dist/typescript/commonjs/features/voice/playing/model/index.d.ts +7 -0
  197. package/dist/typescript/commonjs/features/voice/playing/model/index.d.ts.map +1 -0
  198. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecord.d.ts +10 -0
  199. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecord.d.ts.map +1 -0
  200. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordButton.d.ts +10 -0
  201. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordButton.d.ts.map +1 -0
  202. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordDeleteButton.d.ts +8 -0
  203. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordDeleteButton.d.ts.map +1 -0
  204. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordDevider.d.ts +3 -0
  205. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordDevider.d.ts.map +1 -0
  206. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordTimer.d.ts +11 -0
  207. package/dist/typescript/commonjs/features/voice/recording/components/VoiceRecordTimer.d.ts.map +1 -0
  208. package/dist/typescript/commonjs/features/voice/recording/hooks/useVoiceRecorder.d.ts +5 -0
  209. package/dist/typescript/commonjs/features/voice/recording/hooks/useVoiceRecorder.d.ts.map +1 -0
  210. package/dist/typescript/commonjs/features/voice/recording/hooks/useVoiceRecorderAnimation.d.ts +6 -0
  211. package/dist/typescript/commonjs/features/voice/recording/hooks/useVoiceRecorderAnimation.d.ts.map +1 -0
  212. package/dist/typescript/commonjs/features/voice/recording/modal/ModalFooterButtons.d.ts +12 -0
  213. package/dist/typescript/commonjs/features/voice/recording/modal/ModalFooterButtons.d.ts.map +1 -0
  214. package/dist/typescript/commonjs/features/voice/recording/modal/VoiceRecordDeleteModal.d.ts +11 -0
  215. package/dist/typescript/commonjs/features/voice/recording/modal/VoiceRecordDeleteModal.d.ts.map +1 -0
  216. package/dist/typescript/commonjs/features/voice/recording/modal/VoiceRecordUndoModal.d.ts +11 -0
  217. package/dist/typescript/commonjs/features/voice/recording/modal/VoiceRecordUndoModal.d.ts.map +1 -0
  218. package/dist/typescript/commonjs/features/voice/recording/model/Recorder.model.d.ts +19 -0
  219. package/dist/typescript/commonjs/features/voice/recording/model/Recorder.model.d.ts.map +1 -0
  220. package/dist/typescript/commonjs/features/voice/recording/model/Uploader.model.d.ts +18 -0
  221. package/dist/typescript/commonjs/features/voice/recording/model/Uploader.model.d.ts.map +1 -0
  222. package/dist/typescript/commonjs/features/voice/recording/model/VoiceRecord.model.d.ts +50 -0
  223. package/dist/typescript/commonjs/features/voice/recording/model/VoiceRecord.model.d.ts.map +1 -0
  224. package/dist/typescript/commonjs/features/voice/recording/model/VoiceRecordCollection.d.ts +10 -0
  225. package/dist/typescript/commonjs/features/voice/recording/model/VoiceRecordCollection.d.ts.map +1 -0
  226. package/dist/typescript/commonjs/features/voice/recording/model/index.d.ts +5 -0
  227. package/dist/typescript/commonjs/features/voice/recording/model/index.d.ts.map +1 -0
  228. package/dist/typescript/commonjs/features/voice/types.d.ts +58 -0
  229. package/dist/typescript/commonjs/features/voice/types.d.ts.map +1 -0
  230. package/dist/typescript/commonjs/index.d.ts +1 -0
  231. package/dist/typescript/commonjs/index.d.ts.map +1 -1
  232. package/dist/typescript/commonjs/shared/components/PlayButton.d.ts +18 -0
  233. package/dist/typescript/commonjs/shared/components/PlayButton.d.ts.map +1 -0
  234. package/dist/typescript/commonjs/shared/translation/constants.d.ts +102 -0
  235. package/dist/typescript/commonjs/shared/translation/constants.d.ts.map +1 -1
  236. package/dist/typescript/commonjs/shared/translation/model.d.ts +34 -0
  237. package/dist/typescript/commonjs/shared/translation/model.d.ts.map +1 -1
  238. package/dist/typescript/commonjs/types/common.types.d.ts +3 -0
  239. package/dist/typescript/commonjs/types/common.types.d.ts.map +1 -1
  240. package/dist/typescript/module/features/chatbot/components/ChatInput/RequestHintButton.d.ts.map +1 -1
  241. package/dist/typescript/module/features/chatbot/components/ChatMessage/MessageButtonsBlock.d.ts.map +1 -1
  242. package/dist/typescript/module/features/chatbot/components/ChatMessage/MessageTextToSpeech.d.ts +2 -2
  243. package/dist/typescript/module/features/chatbot/components/ChatMessage/MessageTextToSpeech.d.ts.map +1 -1
  244. package/dist/typescript/module/features/chatbot/constants.d.ts +5 -5
  245. package/dist/typescript/module/features/chatbot/constants.d.ts.map +1 -1
  246. package/dist/typescript/module/features/gifCelebrations/helpers.d.ts.map +1 -1
  247. package/dist/typescript/module/features/voice/constants.d.ts +15 -0
  248. package/dist/typescript/module/features/voice/constants.d.ts.map +1 -0
  249. package/dist/typescript/module/features/voice/helpers.d.ts +46 -0
  250. package/dist/typescript/module/features/voice/helpers.d.ts.map +1 -0
  251. package/dist/typescript/module/features/voice/index.d.ts +13 -0
  252. package/dist/typescript/module/features/voice/index.d.ts.map +1 -0
  253. package/dist/typescript/module/features/voice/model/index.d.ts +11 -0
  254. package/dist/typescript/module/features/voice/model/index.d.ts.map +1 -0
  255. package/dist/typescript/module/features/voice/playing/components/VoiceIcon.d.ts +8 -0
  256. package/dist/typescript/module/features/voice/playing/components/VoiceIcon.d.ts.map +1 -0
  257. package/dist/typescript/module/features/voice/playing/components/VoiceTranscriptionsDropdown.d.ts +15 -0
  258. package/dist/typescript/module/features/voice/playing/components/VoiceTranscriptionsDropdown.d.ts.map +1 -0
  259. package/dist/typescript/module/features/voice/playing/components/VoiceTranscriptionsDropdownItem.d.ts +12 -0
  260. package/dist/typescript/module/features/voice/playing/components/VoiceTranscriptionsDropdownItem.d.ts.map +1 -0
  261. package/dist/typescript/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.d.ts +16 -0
  262. package/dist/typescript/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.d.ts.map +1 -0
  263. package/dist/typescript/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.d.ts +11 -0
  264. package/dist/typescript/module/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.d.ts.map +1 -0
  265. package/dist/typescript/module/features/voice/playing/model/Player.model.d.ts +21 -0
  266. package/dist/typescript/module/features/voice/playing/model/Player.model.d.ts.map +1 -0
  267. package/dist/typescript/module/features/voice/playing/model/VoicePlayer.model.d.ts +41 -0
  268. package/dist/typescript/module/features/voice/playing/model/VoicePlayer.model.d.ts.map +1 -0
  269. package/dist/typescript/module/features/voice/playing/model/VoiceTranscriptionsCollection.d.ts +26 -0
  270. package/dist/typescript/module/features/voice/playing/model/VoiceTranscriptionsCollection.d.ts.map +1 -0
  271. package/dist/typescript/module/features/voice/playing/model/VoiceTranscriptionsDownloader.model.d.ts +18 -0
  272. package/dist/typescript/module/features/voice/playing/model/VoiceTranscriptionsDownloader.model.d.ts.map +1 -0
  273. package/dist/typescript/module/features/voice/playing/model/VoiceTranscriptionsDropdown.model.d.ts +7 -0
  274. package/dist/typescript/module/features/voice/playing/model/VoiceTranscriptionsDropdown.model.d.ts.map +1 -0
  275. package/dist/typescript/module/features/voice/playing/model/index.d.ts +7 -0
  276. package/dist/typescript/module/features/voice/playing/model/index.d.ts.map +1 -0
  277. package/dist/typescript/module/features/voice/recording/components/VoiceRecord.d.ts +10 -0
  278. package/dist/typescript/module/features/voice/recording/components/VoiceRecord.d.ts.map +1 -0
  279. package/dist/typescript/module/features/voice/recording/components/VoiceRecordButton.d.ts +10 -0
  280. package/dist/typescript/module/features/voice/recording/components/VoiceRecordButton.d.ts.map +1 -0
  281. package/dist/typescript/module/features/voice/recording/components/VoiceRecordDeleteButton.d.ts +8 -0
  282. package/dist/typescript/module/features/voice/recording/components/VoiceRecordDeleteButton.d.ts.map +1 -0
  283. package/dist/typescript/module/features/voice/recording/components/VoiceRecordDevider.d.ts +3 -0
  284. package/dist/typescript/module/features/voice/recording/components/VoiceRecordDevider.d.ts.map +1 -0
  285. package/dist/typescript/module/features/voice/recording/components/VoiceRecordTimer.d.ts +11 -0
  286. package/dist/typescript/module/features/voice/recording/components/VoiceRecordTimer.d.ts.map +1 -0
  287. package/dist/typescript/module/features/voice/recording/hooks/useVoiceRecorder.d.ts +5 -0
  288. package/dist/typescript/module/features/voice/recording/hooks/useVoiceRecorder.d.ts.map +1 -0
  289. package/dist/typescript/module/features/voice/recording/hooks/useVoiceRecorderAnimation.d.ts +6 -0
  290. package/dist/typescript/module/features/voice/recording/hooks/useVoiceRecorderAnimation.d.ts.map +1 -0
  291. package/dist/typescript/module/features/voice/recording/modal/ModalFooterButtons.d.ts +12 -0
  292. package/dist/typescript/module/features/voice/recording/modal/ModalFooterButtons.d.ts.map +1 -0
  293. package/dist/typescript/module/features/voice/recording/modal/VoiceRecordDeleteModal.d.ts +11 -0
  294. package/dist/typescript/module/features/voice/recording/modal/VoiceRecordDeleteModal.d.ts.map +1 -0
  295. package/dist/typescript/module/features/voice/recording/modal/VoiceRecordUndoModal.d.ts +11 -0
  296. package/dist/typescript/module/features/voice/recording/modal/VoiceRecordUndoModal.d.ts.map +1 -0
  297. package/dist/typescript/module/features/voice/recording/model/Recorder.model.d.ts +19 -0
  298. package/dist/typescript/module/features/voice/recording/model/Recorder.model.d.ts.map +1 -0
  299. package/dist/typescript/module/features/voice/recording/model/Uploader.model.d.ts +18 -0
  300. package/dist/typescript/module/features/voice/recording/model/Uploader.model.d.ts.map +1 -0
  301. package/dist/typescript/module/features/voice/recording/model/VoiceRecord.model.d.ts +50 -0
  302. package/dist/typescript/module/features/voice/recording/model/VoiceRecord.model.d.ts.map +1 -0
  303. package/dist/typescript/module/features/voice/recording/model/VoiceRecordCollection.d.ts +10 -0
  304. package/dist/typescript/module/features/voice/recording/model/VoiceRecordCollection.d.ts.map +1 -0
  305. package/dist/typescript/module/features/voice/recording/model/index.d.ts +5 -0
  306. package/dist/typescript/module/features/voice/recording/model/index.d.ts.map +1 -0
  307. package/dist/typescript/module/features/voice/types.d.ts +58 -0
  308. package/dist/typescript/module/features/voice/types.d.ts.map +1 -0
  309. package/dist/typescript/module/index.d.ts +1 -0
  310. package/dist/typescript/module/index.d.ts.map +1 -1
  311. package/dist/typescript/module/shared/components/PlayButton.d.ts +18 -0
  312. package/dist/typescript/module/shared/components/PlayButton.d.ts.map +1 -0
  313. package/dist/typescript/module/shared/translation/constants.d.ts +102 -0
  314. package/dist/typescript/module/shared/translation/constants.d.ts.map +1 -1
  315. package/dist/typescript/module/shared/translation/model.d.ts +34 -0
  316. package/dist/typescript/module/shared/translation/model.d.ts.map +1 -1
  317. package/dist/typescript/module/types/common.types.d.ts +3 -0
  318. package/dist/typescript/module/types/common.types.d.ts.map +1 -1
  319. package/package.json +11 -4
  320. package/src/features/chatbot/components/ChatInput/RequestHintButton.tsx +0 -1
  321. package/src/features/chatbot/components/ChatMessage/MessageButtonsBlock.tsx +1 -1
  322. package/src/features/chatbot/components/ChatMessage/MessageTextToSpeech.tsx +9 -51
  323. package/src/features/chatbot/constants.ts +4 -4
  324. package/src/features/gifCelebrations/helpers.ts +1 -0
  325. package/src/features/voice/constants.ts +14 -0
  326. package/src/features/voice/helpers.ts +254 -0
  327. package/src/features/voice/index.ts +17 -0
  328. package/src/features/voice/model/index.ts +13 -0
  329. package/src/features/voice/playing/components/VoiceIcon.tsx +38 -0
  330. package/src/features/voice/playing/components/VoiceTranscriptionsDropdown.tsx +239 -0
  331. package/src/features/voice/playing/components/VoiceTranscriptionsDropdownItem.tsx +127 -0
  332. package/src/features/voice/playing/hooks/useVoiceTranscriptionsDropdown.ts +54 -0
  333. package/src/features/voice/playing/hooks/useVoiceTranscriptionsDropdownItemAnimation.ts +40 -0
  334. package/src/features/voice/playing/model/Player.model.ts +92 -0
  335. package/src/features/voice/playing/model/VoicePlayer.model.ts +282 -0
  336. package/src/features/voice/playing/model/VoiceTranscriptionsCollection.ts +53 -0
  337. package/src/features/voice/playing/model/VoiceTranscriptionsDownloader.model.ts +43 -0
  338. package/src/features/voice/playing/model/VoiceTranscriptionsDropdown.model.ts +12 -0
  339. package/src/features/voice/playing/model/index.ts +6 -0
  340. package/src/features/voice/recording/components/VoiceRecord.tsx +65 -0
  341. package/src/features/voice/recording/components/VoiceRecordButton.tsx +63 -0
  342. package/src/features/voice/recording/components/VoiceRecordDeleteButton.tsx +25 -0
  343. package/src/features/voice/recording/components/VoiceRecordDevider.tsx +17 -0
  344. package/src/features/voice/recording/components/VoiceRecordTimer.tsx +49 -0
  345. package/src/features/voice/recording/hooks/useVoiceRecorder.ts +62 -0
  346. package/src/features/voice/recording/hooks/useVoiceRecorderAnimation.ts +19 -0
  347. package/src/features/voice/recording/modal/ModalFooterButtons.tsx +54 -0
  348. package/src/features/voice/recording/modal/VoiceRecordDeleteModal.tsx +82 -0
  349. package/src/features/voice/recording/modal/VoiceRecordUndoModal.tsx +50 -0
  350. package/src/features/voice/recording/model/Recorder.model.ts +62 -0
  351. package/src/features/voice/recording/model/Uploader.model.ts +48 -0
  352. package/src/features/voice/recording/model/VoiceRecord.model.ts +278 -0
  353. package/src/features/voice/recording/model/VoiceRecordCollection.ts +26 -0
  354. package/src/features/voice/recording/model/index.ts +4 -0
  355. package/src/features/voice/types.ts +69 -0
  356. package/src/index.ts +1 -0
  357. package/src/shared/components/PlayButton.tsx +84 -0
  358. package/src/shared/translation/localization/ca.json +17 -0
  359. package/src/shared/translation/localization/de.json +17 -0
  360. package/src/shared/translation/localization/en.json +17 -0
  361. package/src/shared/translation/localization/gb.json +17 -0
  362. package/src/shared/translation/localization/sct.json +17 -0
  363. package/src/shared/translation/localization/sw.json +17 -0
  364. package/src/types/common.types.ts +1 -0
  365. package/dist/commonjs/features/chatbot/TTS_HIGHLIGHTING.md +0 -120
  366. package/dist/module/features/chatbot/TTS_HIGHLIGHTING.md +0 -120
  367. package/src/features/chatbot/TTS_HIGHLIGHTING.md +0 -120
@@ -0,0 +1,84 @@
1
+ import React from 'react'
2
+ import { ActivityIndicator } from 'react-native'
3
+ import { Button, COLORS } from '@magmamath/react-native-ui'
4
+
5
+ import { SpeakerIcon } from '../icons/SpeakerIcon'
6
+ import { PlayIcon } from '../icons/PlayIcon'
7
+ import { PauseIcon } from '../icons/PauseIcon'
8
+ import { AudioStatus } from '../../features/chatbot/types/t2s.types'
9
+ import { CONTROLS_COLORS_MAP } from '../../features/chatbot/constants'
10
+ import { ColorScheme } from '../../features/chatbot/types/style.types'
11
+
12
+ type TextToSpeechIconProps = {
13
+ status?: AudioStatus
14
+ isLoading?: boolean
15
+ isActive?: boolean
16
+ colorScheme?: ColorScheme
17
+ activityIndicatorColor?: string
18
+ }
19
+
20
+ const TextToSpeechIcon = ({
21
+ status,
22
+ isActive,
23
+ isLoading,
24
+ colorScheme = ColorScheme.Blue,
25
+ activityIndicatorColor,
26
+ }: TextToSpeechIconProps) => {
27
+ if (isLoading && isActive) {
28
+ return (
29
+ <ActivityIndicator
30
+ color={activityIndicatorColor || CONTROLS_COLORS_MAP[colorScheme].background}
31
+ />
32
+ )
33
+ }
34
+
35
+ if (!isActive) {
36
+ return <SpeakerIcon />
37
+ }
38
+
39
+ if (status === 'playing') return <PauseIcon color={COLORS.NEUTRAL_1} />
40
+ if (status === 'paused') return <PlayIcon color={COLORS.NEUTRAL_1} />
41
+ return <SpeakerIcon />
42
+ }
43
+
44
+ type MessageTextToSpeechProps = {
45
+ state: {
46
+ status?: AudioStatus
47
+ isActive?: boolean
48
+ isLoading?: boolean
49
+ disabled?: boolean
50
+ isEnabled?: boolean
51
+ }
52
+ activityIndicatorColor?: string
53
+ colorScheme?: ColorScheme
54
+ onPress?: () => void
55
+ }
56
+
57
+ export const PlayButton = ({
58
+ state: { status, disabled, isActive, isLoading },
59
+ colorScheme = ColorScheme.Blue,
60
+ onPress,
61
+ activityIndicatorColor,
62
+ ...props
63
+ }: MessageTextToSpeechProps) => {
64
+ return (
65
+ <Button
66
+ disabled={disabled}
67
+ isActive={isActive}
68
+ variant={'secondary'}
69
+ colorScheme={colorScheme}
70
+ size={'small'}
71
+ onPress={onPress}
72
+ icon={
73
+ <TextToSpeechIcon
74
+ isActive={isActive}
75
+ isLoading={isLoading}
76
+ status={status}
77
+ colorScheme={colorScheme}
78
+ activityIndicatorColor={activityIndicatorColor}
79
+ />
80
+ }
81
+ {...props}
82
+ />
83
+ )
84
+ }
@@ -39,5 +39,22 @@
39
39
  "volume": "Volume",
40
40
  "weight": "Weight",
41
41
  "time": "Time"
42
+ },
43
+ "voice": {
44
+ "deleteRecording": "Delete recording?",
45
+ "youWontBeAbleToRecover": "You won't be able to recover this file once it's gone.",
46
+ "recordingDeleted": "Recording successfully deleted.",
47
+ "delete": "Delete",
48
+ "cancel": "Cancel",
49
+ "noMicrophoneAccess": "No microphone access.",
50
+ "noMicrophoneAccessBySystem": "Microphone access denied by system settings.",
51
+ "noMicrophoneFound": "No microphone found.",
52
+ "uploadFailed": "Upload failed. Please try again.",
53
+ "redoRecording": "Redo recording?",
54
+ "redo": "Redo",
55
+ "thisWillRemoveRecording": "This will remove your previous recording.",
56
+ "transcriptions": "Transcriptions",
57
+ "attempt": "Attempt {{number}}",
58
+ "transcriptNotAvailable": "Transcript not available"
42
59
  }
43
60
  }
@@ -39,5 +39,22 @@
39
39
  "volume": "Volumen",
40
40
  "weight": "Gewicht",
41
41
  "time": "Zeit"
42
+ },
43
+ "voice": {
44
+ "deleteRecording": "Aufnahme löschen?",
45
+ "youWontBeAbleToRecover": "Du kannst die Datei nicht wiederherstellen, wenn sie einmal gelöscht ist.",
46
+ "recordingDeleted": "Aufnahme gelöscht.",
47
+ "delete": "Löschen",
48
+ "cancel": "Abbrechen",
49
+ "noMicrophoneAccess": "Kein Mikrofon-Zugriff.",
50
+ "noMicrophoneAccessBySystem": "Mikrofonzugriff durch Systemeinstellungen verweigert.",
51
+ "noMicrophoneFound": "Kein Mikrofon gefunden.",
52
+ "uploadFailed": "Hochladen fehlgeschlagen. Bitte versuche es erneut.",
53
+ "redoRecording": "Aufnahme erneut aufnehmen?",
54
+ "redo": "Wiederholen",
55
+ "thisWillRemoveRecording": "Dadurch wird die Aufnahme entfernt.",
56
+ "transcriptions": "Transkriptionen",
57
+ "attempt": "Versuch {{number}}",
58
+ "transcriptNotAvailable": "Transkript nicht verfügbar"
42
59
  }
43
60
  }
@@ -39,5 +39,22 @@
39
39
  "volume": "Volume",
40
40
  "weight": "Weight",
41
41
  "time": "Time"
42
+ },
43
+ "voice": {
44
+ "deleteRecording": "Delete recording?",
45
+ "youWontBeAbleToRecover": "You won't be able to recover this file once it's gone.",
46
+ "recordingDeleted": "Recording successfully deleted.",
47
+ "delete": "Delete",
48
+ "cancel": "Cancel",
49
+ "noMicrophoneAccess": "No microphone access.",
50
+ "noMicrophoneAccessBySystem": "Microphone access denied by system settings.",
51
+ "noMicrophoneFound": "No microphone found.",
52
+ "uploadFailed": "Upload failed. Please try again.",
53
+ "redoRecording": "Redo recording?",
54
+ "redo": "Redo",
55
+ "thisWillRemoveRecording": "This will remove your previous recording.",
56
+ "transcriptions": "Transcriptions",
57
+ "attempt": "Attempt {{number}}",
58
+ "transcriptNotAvailable": "Transcript not available"
42
59
  }
43
60
  }
@@ -39,5 +39,22 @@
39
39
  "volume": "Volume",
40
40
  "weight": "Weight",
41
41
  "time": "Time"
42
+ },
43
+ "voice": {
44
+ "deleteRecording": "Delete recording?",
45
+ "youWontBeAbleToRecover": "You won't be able to recover this file once it's gone.",
46
+ "recordingDeleted": "Recording successfully deleted.",
47
+ "delete": "Delete",
48
+ "cancel": "Cancel",
49
+ "noMicrophoneAccess": "No microphone access.",
50
+ "noMicrophoneAccessBySystem": "Microphone access denied by system settings.",
51
+ "noMicrophoneFound": "No microphone found.",
52
+ "uploadFailed": "Upload failed. Please try again.",
53
+ "redoRecording": "Redo recording?",
54
+ "redo": "Redo",
55
+ "thisWillRemoveRecording": "This will remove your previous recording.",
56
+ "transcriptions": "Transcriptions",
57
+ "attempt": "Attempt {{number}}",
58
+ "transcriptNotAvailable": "Transcript not available"
42
59
  }
43
60
  }
@@ -39,5 +39,22 @@
39
39
  "volume": "Volume",
40
40
  "weight": "Weight",
41
41
  "time": "Time"
42
+ },
43
+ "voice": {
44
+ "deleteRecording": "Delete recording?",
45
+ "youWontBeAbleToRecover": "You won't be able to recover this file once it's gone.",
46
+ "recordingDeleted": "Recording successfully deleted.",
47
+ "delete": "Delete",
48
+ "cancel": "Cancel",
49
+ "noMicrophoneAccess": "No microphone access.",
50
+ "noMicrophoneAccessBySystem": "Microphone access denied by system settings.",
51
+ "noMicrophoneFound": "No microphone found.",
52
+ "uploadFailed": "Upload failed. Please try again.",
53
+ "redoRecording": "Redo recording?",
54
+ "redo": "Redo",
55
+ "thisWillRemoveRecording": "This will remove your previous recording.",
56
+ "transcriptions": "Transcriptions",
57
+ "attempt": "Attempt {{number}}",
58
+ "transcriptNotAvailable": "Transcript not available"
42
59
  }
43
60
  }
@@ -39,5 +39,22 @@
39
39
  "volume": "Volym",
40
40
  "weight": "Vikt",
41
41
  "time": "Tid"
42
+ },
43
+ "voice": {
44
+ "deleteRecording": "Radera inspelningen?",
45
+ "youWontBeAbleToRecover": "Du kommer inte att kunna återställa filen när den väl är borta.",
46
+ "recordingDeleted": "Inspelningen raderad.",
47
+ "delete": "Radera",
48
+ "cancel": "Avbryt",
49
+ "noMicrophoneAccess": "Ingen mikrofonåtkomst.",
50
+ "noMicrophoneAccessBySystem": "Mikrofonåtkomst nekad av systeminställningar.",
51
+ "noMicrophoneFound": "Ingen mikrofon hittades.",
52
+ "uploadFailed": "Uppladdning misslyckades. Försök igen.",
53
+ "redoRecording": "Spela in igen?",
54
+ "redo": "Gör om",
55
+ "thisWillRemoveRecording": "Detta tar bort inspelningen.",
56
+ "transcriptions": "Transkriptioner",
57
+ "attempt": "Försök {{number}}",
58
+ "transcriptNotAvailable": "Transkript inte tillgängligt"
42
59
  }
43
60
  }
@@ -4,5 +4,6 @@ export type Size = {
4
4
  width: number
5
5
  height: number
6
6
  }
7
+ export type WithAbortSignal<T> = T & { signal?: AbortSignal }
7
8
 
8
9
  export type ColorValue = (typeof COLORS)[keyof typeof COLORS]
@@ -1,120 +0,0 @@
1
- # TTS Word-by-Word Highlighting
2
-
3
- ## Overview
4
-
5
- Word-by-word text highlighting synchronized with text-to-speech playback in the chatbot. The feature is optional and enabled via `isWordHighlightEnabled` config flag.
6
-
7
- ## How It Works
8
-
9
- ```
10
- ┌─────────────────────────────────────────────────────────────────┐
11
- │ 1. User clicks TTS button on a message │
12
- │ ↓ │
13
- │ 2. Text is converted to SSML with word marks │
14
- │ "Hello world" → <speak><mark name="w_0"/>Hello │
15
- │ <mark name="w_1"/>world</speak> │
16
- │ ↓ │
17
- │ 3. Google TTS API returns audio + timepoints │
18
- │ [{ markName: "w_0", timeSeconds: 0.0 }, │
19
- │ { markName: "w_1", timeSeconds: 0.5 }] │
20
- │ ↓ │
21
- │ 4. Audio plays, onTimeUpdate fires via RAF loop │
22
- │ ↓ │
23
- │ 5. Current time → find matching timepoint → word index │
24
- │ ↓ │
25
- │ 6. $highlightedWordIndex updates → UI re-renders highlighted │
26
- └─────────────────────────────────────────────────────────────────┘
27
- ```
28
-
29
- ## Usage
30
-
31
- ```tsx
32
- // In students-web model setup
33
- chatModel.bot.setUpT2S({
34
- audioProvider: createT2SAudioProvider(),
35
- textSanitizer: removeKatexPartFromTextToSpeech,
36
- isWordHighlightEnabled: true,
37
- })
38
- ```
39
-
40
- ## Architecture
41
-
42
- ### ChatTTSModel (ChatTTSModel.ts)
43
-
44
- Handles TTS playback and word highlighting. Key design decisions:
45
-
46
- - **Map-based cache** — `audioCache: Map<string, AudioCache>` stores both `audioPath` and `timepoints` per message. When highlighting is off, `timepoints` is `[]`. Cache lives for the model's lifetime (cleared when user leaves the problem).
47
- - **`fetchAudio()` method** — encapsulates API call + audioContent decoding. Highlight vs non-highlight differences are ternaries (SSML vs plain text, `enableTimePointing`).
48
- - **`play()` is linear** — cache lookup → fetch if miss → store → activate highlight if enabled → play audio. No branching between highlight/non-highlight paths.
49
- - **Pause/resume guards** — `wordHighlightEnabled` check before toggling `setIsActive(false)`/`setIsActive(true)` on pause/resume.
50
- - **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at `setConfig`.
51
- - **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
52
-
53
- ### AudioProvider type
54
-
55
- ```typescript
56
- type AudioProvider = {
57
- play: (audioPath: string, onPlaybackComplete: () => void) => Promise<void>
58
- pause: () => void
59
- resume: () => void
60
- stop: () => void
61
- onTimeUpdate?: OnTimeUpdate // optional — presence enables highlight capability
62
- }
63
- ```
64
-
65
- `onTimeUpdate` is optional. It's the mechanism that syncs audio playback time with word highlights via a RAF loop. If the provider doesn't have it, highlighting won't activate even if `isWordHighlightEnabled: true`.
66
-
67
- ### ChatTTSHighlightModel (ChatTTSHighlightModel.ts)
68
-
69
- Manages highlight state using Effector stores with declarative reset. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
70
-
71
- - **`$isActive`** — gates `$highlightedWordIndex` computation. Toggled on pause/resume without resetting timepoints.
72
- - **`$highlightedWordIndex`** — derived store, returns `-1` when inactive or no match. Parses mark name via `WORD_MARK_REGEX`.
73
- - **`activate(timepoints, onTimeUpdate)`** — sets timepoints, enables highlighting, registers time update callback. Only triggers store updates when the highlighted word actually changes (`lastMark` comparison).
74
- - **`deactivate(onTimeUpdate)`** — stops listening, resets all state via declarative `.reset()` chain.
75
- - **All stores use `.reset(this.reset)`** — single `reset` event clears `$time`, `$timepoints`, and `$isActive`.
76
-
77
- ### Helpers (helpers/ttsHighlight.ts)
78
-
79
- - **`textToSSML(text)`** — converts plain text to SSML with `<mark>` tags for word timing.
80
- - **`findCurrentMark(timepoints, time)`** — iterates backwards through timepoints to find the current mark. Efficient for linear playback.
81
-
82
- ### Constants (constants.ts)
83
-
84
- - **`WORD_MARK_REGEX`** — `/^w_(\d+)$/` — extracts word index from mark names like `w_0`, `w_1`.
85
-
86
- ### Naming conventions
87
-
88
- | Name | Scope | Purpose |
89
- |------|-------|---------|
90
- | `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `ChatTTSModel` |
91
- | `wordHighlightEnabled` | private field | Whether highlighting is active (set once at config) |
92
- | `isWordHighlightEnabled` | public getter | Read-only access to `wordHighlightEnabled` for external consumers |
93
- | `isWordHighlightEnabled` | T2SConfig field | Config flag passed to `setUpT2S()` |
94
-
95
- ## Data Flow
96
-
97
- ```
98
- AudioProvider.onTimeUpdate(callback)
99
-
100
- ChatTTSHighlightModel.activate(timepoints, onTimeUpdate)
101
-
102
- RAF loop → audio.currentTime → findCurrentMark() → only updates when mark changes
103
-
104
- $highlightedWordIndex = parse mark name "w_N" → N (or -1 if inactive/no match)
105
-
106
- Chat.tsx: model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1
107
-
108
- ChatMessage → MessageContent → TTSHighlightRenderer({ text, highlightedIndex })
109
- ```
110
-
111
- ## Key Files
112
-
113
- | File | Purpose |
114
- |------|---------|
115
- | `model/ChatTTSModel.ts` | `ChatTTSModel` — TTS playback, caching, highlight orchestration |
116
- | `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, `$isActive`, derived word index |
117
- | `helpers/ttsHighlight.ts` | `textToSSML` + `findCurrentMark` — SSML conversion and playback position lookup |
118
- | `constants.ts` | `WORD_MARK_REGEX` and audio config defaults |
119
- | `types/t2s.types.ts` | `AudioProvider`, `OnTimeUpdate`, `AudioStatus`, `AudioCache`, `TTSHighlightRendererProps` types |
120
- | `components/Chat/Chat.tsx` | Reads `isWordHighlightEnabled` and `$highlightedWordIndex`, passes to messages |
@@ -1,120 +0,0 @@
1
- # TTS Word-by-Word Highlighting
2
-
3
- ## Overview
4
-
5
- Word-by-word text highlighting synchronized with text-to-speech playback in the chatbot. The feature is optional and enabled via `isWordHighlightEnabled` config flag.
6
-
7
- ## How It Works
8
-
9
- ```
10
- ┌─────────────────────────────────────────────────────────────────┐
11
- │ 1. User clicks TTS button on a message │
12
- │ ↓ │
13
- │ 2. Text is converted to SSML with word marks │
14
- │ "Hello world" → <speak><mark name="w_0"/>Hello │
15
- │ <mark name="w_1"/>world</speak> │
16
- │ ↓ │
17
- │ 3. Google TTS API returns audio + timepoints │
18
- │ [{ markName: "w_0", timeSeconds: 0.0 }, │
19
- │ { markName: "w_1", timeSeconds: 0.5 }] │
20
- │ ↓ │
21
- │ 4. Audio plays, onTimeUpdate fires via RAF loop │
22
- │ ↓ │
23
- │ 5. Current time → find matching timepoint → word index │
24
- │ ↓ │
25
- │ 6. $highlightedWordIndex updates → UI re-renders highlighted │
26
- └─────────────────────────────────────────────────────────────────┘
27
- ```
28
-
29
- ## Usage
30
-
31
- ```tsx
32
- // In students-web model setup
33
- chatModel.bot.setUpT2S({
34
- audioProvider: createT2SAudioProvider(),
35
- textSanitizer: removeKatexPartFromTextToSpeech,
36
- isWordHighlightEnabled: true,
37
- })
38
- ```
39
-
40
- ## Architecture
41
-
42
- ### ChatTTSModel (ChatTTSModel.ts)
43
-
44
- Handles TTS playback and word highlighting. Key design decisions:
45
-
46
- - **Map-based cache** — `audioCache: Map<string, AudioCache>` stores both `audioPath` and `timepoints` per message. When highlighting is off, `timepoints` is `[]`. Cache lives for the model's lifetime (cleared when user leaves the problem).
47
- - **`fetchAudio()` method** — encapsulates API call + audioContent decoding. Highlight vs non-highlight differences are ternaries (SSML vs plain text, `enableTimePointing`).
48
- - **`play()` is linear** — cache lookup → fetch if miss → store → activate highlight if enabled → play audio. No branching between highlight/non-highlight paths.
49
- - **Pause/resume guards** — `wordHighlightEnabled` check before toggling `setIsActive(false)`/`setIsActive(true)` on pause/resume.
50
- - **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at `setConfig`.
51
- - **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
52
-
53
- ### AudioProvider type
54
-
55
- ```typescript
56
- type AudioProvider = {
57
- play: (audioPath: string, onPlaybackComplete: () => void) => Promise<void>
58
- pause: () => void
59
- resume: () => void
60
- stop: () => void
61
- onTimeUpdate?: OnTimeUpdate // optional — presence enables highlight capability
62
- }
63
- ```
64
-
65
- `onTimeUpdate` is optional. It's the mechanism that syncs audio playback time with word highlights via a RAF loop. If the provider doesn't have it, highlighting won't activate even if `isWordHighlightEnabled: true`.
66
-
67
- ### ChatTTSHighlightModel (ChatTTSHighlightModel.ts)
68
-
69
- Manages highlight state using Effector stores with declarative reset. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
70
-
71
- - **`$isActive`** — gates `$highlightedWordIndex` computation. Toggled on pause/resume without resetting timepoints.
72
- - **`$highlightedWordIndex`** — derived store, returns `-1` when inactive or no match. Parses mark name via `WORD_MARK_REGEX`.
73
- - **`activate(timepoints, onTimeUpdate)`** — sets timepoints, enables highlighting, registers time update callback. Only triggers store updates when the highlighted word actually changes (`lastMark` comparison).
74
- - **`deactivate(onTimeUpdate)`** — stops listening, resets all state via declarative `.reset()` chain.
75
- - **All stores use `.reset(this.reset)`** — single `reset` event clears `$time`, `$timepoints`, and `$isActive`.
76
-
77
- ### Helpers (helpers/ttsHighlight.ts)
78
-
79
- - **`textToSSML(text)`** — converts plain text to SSML with `<mark>` tags for word timing.
80
- - **`findCurrentMark(timepoints, time)`** — iterates backwards through timepoints to find the current mark. Efficient for linear playback.
81
-
82
- ### Constants (constants.ts)
83
-
84
- - **`WORD_MARK_REGEX`** — `/^w_(\d+)$/` — extracts word index from mark names like `w_0`, `w_1`.
85
-
86
- ### Naming conventions
87
-
88
- | Name | Scope | Purpose |
89
- |------|-------|---------|
90
- | `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `ChatTTSModel` |
91
- | `wordHighlightEnabled` | private field | Whether highlighting is active (set once at config) |
92
- | `isWordHighlightEnabled` | public getter | Read-only access to `wordHighlightEnabled` for external consumers |
93
- | `isWordHighlightEnabled` | T2SConfig field | Config flag passed to `setUpT2S()` |
94
-
95
- ## Data Flow
96
-
97
- ```
98
- AudioProvider.onTimeUpdate(callback)
99
-
100
- ChatTTSHighlightModel.activate(timepoints, onTimeUpdate)
101
-
102
- RAF loop → audio.currentTime → findCurrentMark() → only updates when mark changes
103
-
104
- $highlightedWordIndex = parse mark name "w_N" → N (or -1 if inactive/no match)
105
-
106
- Chat.tsx: model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1
107
-
108
- ChatMessage → MessageContent → TTSHighlightRenderer({ text, highlightedIndex })
109
- ```
110
-
111
- ## Key Files
112
-
113
- | File | Purpose |
114
- |------|---------|
115
- | `model/ChatTTSModel.ts` | `ChatTTSModel` — TTS playback, caching, highlight orchestration |
116
- | `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, `$isActive`, derived word index |
117
- | `helpers/ttsHighlight.ts` | `textToSSML` + `findCurrentMark` — SSML conversion and playback position lookup |
118
- | `constants.ts` | `WORD_MARK_REGEX` and audio config defaults |
119
- | `types/t2s.types.ts` | `AudioProvider`, `OnTimeUpdate`, `AudioStatus`, `AudioCache`, `TTSHighlightRendererProps` types |
120
- | `components/Chat/Chat.tsx` | Reads `isWordHighlightEnabled` and `$highlightedWordIndex`, passes to messages |
@@ -1,120 +0,0 @@
1
- # TTS Word-by-Word Highlighting
2
-
3
- ## Overview
4
-
5
- Word-by-word text highlighting synchronized with text-to-speech playback in the chatbot. The feature is optional and enabled via `isWordHighlightEnabled` config flag.
6
-
7
- ## How It Works
8
-
9
- ```
10
- ┌─────────────────────────────────────────────────────────────────┐
11
- │ 1. User clicks TTS button on a message │
12
- │ ↓ │
13
- │ 2. Text is converted to SSML with word marks │
14
- │ "Hello world" → <speak><mark name="w_0"/>Hello │
15
- │ <mark name="w_1"/>world</speak> │
16
- │ ↓ │
17
- │ 3. Google TTS API returns audio + timepoints │
18
- │ [{ markName: "w_0", timeSeconds: 0.0 }, │
19
- │ { markName: "w_1", timeSeconds: 0.5 }] │
20
- │ ↓ │
21
- │ 4. Audio plays, onTimeUpdate fires via RAF loop │
22
- │ ↓ │
23
- │ 5. Current time → find matching timepoint → word index │
24
- │ ↓ │
25
- │ 6. $highlightedWordIndex updates → UI re-renders highlighted │
26
- └─────────────────────────────────────────────────────────────────┘
27
- ```
28
-
29
- ## Usage
30
-
31
- ```tsx
32
- // In students-web model setup
33
- chatModel.bot.setUpT2S({
34
- audioProvider: createT2SAudioProvider(),
35
- textSanitizer: removeKatexPartFromTextToSpeech,
36
- isWordHighlightEnabled: true,
37
- })
38
- ```
39
-
40
- ## Architecture
41
-
42
- ### ChatTTSModel (ChatTTSModel.ts)
43
-
44
- Handles TTS playback and word highlighting. Key design decisions:
45
-
46
- - **Map-based cache** — `audioCache: Map<string, AudioCache>` stores both `audioPath` and `timepoints` per message. When highlighting is off, `timepoints` is `[]`. Cache lives for the model's lifetime (cleared when user leaves the problem).
47
- - **`fetchAudio()` method** — encapsulates API call + audioContent decoding. Highlight vs non-highlight differences are ternaries (SSML vs plain text, `enableTimePointing`).
48
- - **`play()` is linear** — cache lookup → fetch if miss → store → activate highlight if enabled → play audio. No branching between highlight/non-highlight paths.
49
- - **Pause/resume guards** — `wordHighlightEnabled` check before toggling `setIsActive(false)`/`setIsActive(true)` on pause/resume.
50
- - **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at `setConfig`.
51
- - **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
52
-
53
- ### AudioProvider type
54
-
55
- ```typescript
56
- type AudioProvider = {
57
- play: (audioPath: string, onPlaybackComplete: () => void) => Promise<void>
58
- pause: () => void
59
- resume: () => void
60
- stop: () => void
61
- onTimeUpdate?: OnTimeUpdate // optional — presence enables highlight capability
62
- }
63
- ```
64
-
65
- `onTimeUpdate` is optional. It's the mechanism that syncs audio playback time with word highlights via a RAF loop. If the provider doesn't have it, highlighting won't activate even if `isWordHighlightEnabled: true`.
66
-
67
- ### ChatTTSHighlightModel (ChatTTSHighlightModel.ts)
68
-
69
- Manages highlight state using Effector stores with declarative reset. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
70
-
71
- - **`$isActive`** — gates `$highlightedWordIndex` computation. Toggled on pause/resume without resetting timepoints.
72
- - **`$highlightedWordIndex`** — derived store, returns `-1` when inactive or no match. Parses mark name via `WORD_MARK_REGEX`.
73
- - **`activate(timepoints, onTimeUpdate)`** — sets timepoints, enables highlighting, registers time update callback. Only triggers store updates when the highlighted word actually changes (`lastMark` comparison).
74
- - **`deactivate(onTimeUpdate)`** — stops listening, resets all state via declarative `.reset()` chain.
75
- - **All stores use `.reset(this.reset)`** — single `reset` event clears `$time`, `$timepoints`, and `$isActive`.
76
-
77
- ### Helpers (helpers/ttsHighlight.ts)
78
-
79
- - **`textToSSML(text)`** — converts plain text to SSML with `<mark>` tags for word timing.
80
- - **`findCurrentMark(timepoints, time)`** — iterates backwards through timepoints to find the current mark. Efficient for linear playback.
81
-
82
- ### Constants (constants.ts)
83
-
84
- - **`WORD_MARK_REGEX`** — `/^w_(\d+)$/` — extracts word index from mark names like `w_0`, `w_1`.
85
-
86
- ### Naming conventions
87
-
88
- | Name | Scope | Purpose |
89
- |------|-------|---------|
90
- | `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `ChatTTSModel` |
91
- | `wordHighlightEnabled` | private field | Whether highlighting is active (set once at config) |
92
- | `isWordHighlightEnabled` | public getter | Read-only access to `wordHighlightEnabled` for external consumers |
93
- | `isWordHighlightEnabled` | T2SConfig field | Config flag passed to `setUpT2S()` |
94
-
95
- ## Data Flow
96
-
97
- ```
98
- AudioProvider.onTimeUpdate(callback)
99
-
100
- ChatTTSHighlightModel.activate(timepoints, onTimeUpdate)
101
-
102
- RAF loop → audio.currentTime → findCurrentMark() → only updates when mark changes
103
-
104
- $highlightedWordIndex = parse mark name "w_N" → N (or -1 if inactive/no match)
105
-
106
- Chat.tsx: model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1
107
-
108
- ChatMessage → MessageContent → TTSHighlightRenderer({ text, highlightedIndex })
109
- ```
110
-
111
- ## Key Files
112
-
113
- | File | Purpose |
114
- |------|---------|
115
- | `model/ChatTTSModel.ts` | `ChatTTSModel` — TTS playback, caching, highlight orchestration |
116
- | `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, `$isActive`, derived word index |
117
- | `helpers/ttsHighlight.ts` | `textToSSML` + `findCurrentMark` — SSML conversion and playback position lookup |
118
- | `constants.ts` | `WORD_MARK_REGEX` and audio config defaults |
119
- | `types/t2s.types.ts` | `AudioProvider`, `OnTimeUpdate`, `AudioStatus`, `AudioCache`, `TTSHighlightRendererProps` types |
120
- | `components/Chat/Chat.tsx` | Reads `isWordHighlightEnabled` and `$highlightedWordIndex`, passes to messages |