@pie-players/pie-assessment-toolkit 0.3.43 → 0.3.45

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 (441) hide show
  1. package/README.md +54 -69
  2. package/dist/attempt/AssessmentSession.d.ts +0 -1
  3. package/dist/attempt/AssessmentSession.js.map +1 -1
  4. package/dist/attempt/TestSession.d.ts +0 -1
  5. package/dist/attempt/TestSession.js.map +1 -1
  6. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -1
  7. package/dist/attempt/adapters/activity-to-test-attempt-session.js.map +1 -1
  8. package/dist/components/ItemToolBar.custom-element.js +1607 -428
  9. package/dist/components/PieAssessmentToolkit.custom-element.js +19498 -3590
  10. package/dist/components/SectionToolBar.custom-element.js +1887 -611
  11. package/dist/components/item-toolbar-element.d.ts +0 -1
  12. package/dist/components/item-toolbar-element.js.map +1 -1
  13. package/dist/components/pie-assessment-toolkit-element.d.ts +0 -1
  14. package/dist/components/pie-assessment-toolkit-element.js.map +1 -1
  15. package/dist/components/section-toolbar-element.d.ts +0 -1
  16. package/dist/components/section-toolbar-element.js.map +1 -1
  17. package/dist/components/vendor/nds/README.md +110 -0
  18. package/dist/components/vendor/nds/nds-icon-button.js +826 -0
  19. package/dist/context/assessment-toolkit-context.d.ts +0 -1
  20. package/dist/context/assessment-toolkit-context.js.map +1 -1
  21. package/dist/context/runtime-context-consumer.d.ts +0 -1
  22. package/dist/context/runtime-context-consumer.js.map +1 -1
  23. package/dist/index.d.ts +3 -7
  24. package/dist/index.js +1 -3
  25. package/dist/index.js.map +1 -1
  26. package/dist/item-loader.d.ts +0 -1
  27. package/dist/item-loader.js.map +1 -1
  28. package/dist/policy/core/PolicySource.d.ts +0 -1
  29. package/dist/policy/core/PolicySource.js.map +1 -1
  30. package/dist/policy/core/ToolPolicyEngine.d.ts +1 -3
  31. package/dist/policy/core/ToolPolicyEngine.js +1 -2
  32. package/dist/policy/core/ToolPolicyEngine.js.map +1 -1
  33. package/dist/policy/core/compose-decision.d.ts +0 -1
  34. package/dist/policy/core/compose-decision.js.map +1 -1
  35. package/dist/policy/core/decision-types.d.ts +0 -1
  36. package/dist/policy/core/decision-types.js.map +1 -1
  37. package/dist/policy/core/engine-context.d.ts +0 -1
  38. package/dist/policy/core/engine-context.js.map +1 -1
  39. package/dist/policy/core/pnp-policy-inputs.d.ts +2 -4
  40. package/dist/policy/core/pnp-policy-inputs.js +2 -3
  41. package/dist/policy/core/pnp-policy-inputs.js.map +1 -1
  42. package/dist/policy/core/policy-source-tag.d.ts +0 -1
  43. package/dist/policy/core/policy-source-tag.js.map +1 -1
  44. package/dist/policy/core/provenance.d.ts +7 -35
  45. package/dist/policy/core/provenance.js +4 -21
  46. package/dist/policy/core/provenance.js.map +1 -1
  47. package/dist/policy/engine.d.ts +0 -1
  48. package/dist/policy/engine.js.map +1 -1
  49. package/dist/policy/internal.d.ts +0 -1
  50. package/dist/policy/internal.js.map +1 -1
  51. package/dist/policy/sources/PnpPolicySource.d.ts +6 -20
  52. package/dist/policy/sources/PnpPolicySource.js +6 -19
  53. package/dist/policy/sources/PnpPolicySource.js.map +1 -1
  54. package/dist/runtime/RuntimeRegistry.d.ts +0 -1
  55. package/dist/runtime/RuntimeRegistry.js.map +1 -1
  56. package/dist/runtime/SectionRuntimeEngine.d.ts +13 -29
  57. package/dist/runtime/SectionRuntimeEngine.js +13 -27
  58. package/dist/runtime/SectionRuntimeEngine.js.map +1 -1
  59. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +2 -3
  60. package/dist/runtime/adapter/SectionEngineAdapter.js +2 -2
  61. package/dist/runtime/adapter/SectionEngineAdapter.js.map +1 -1
  62. package/dist/runtime/adapter/coordinator-bridge.d.ts +1 -2
  63. package/dist/runtime/adapter/coordinator-bridge.js +1 -1
  64. package/dist/runtime/adapter/coordinator-bridge.js.map +1 -1
  65. package/dist/runtime/adapter/dom-event-bridge.d.ts +1 -2
  66. package/dist/runtime/adapter/dom-event-bridge.js +1 -1
  67. package/dist/runtime/adapter/dom-event-bridge.js.map +1 -1
  68. package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -1
  69. package/dist/runtime/adapter/framework-error-bridge.js.map +1 -1
  70. package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -1
  71. package/dist/runtime/adapter/instrumentation-bridge.js.map +1 -1
  72. package/dist/runtime/adapter/subscriber-fanout.d.ts +0 -1
  73. package/dist/runtime/adapter/subscriber-fanout.js.map +1 -1
  74. package/dist/runtime/catalog-registration.d.ts +12 -0
  75. package/dist/runtime/catalog-registration.js +54 -0
  76. package/dist/runtime/catalog-registration.js.map +1 -0
  77. package/dist/runtime/core/SectionEngineCore.d.ts +0 -1
  78. package/dist/runtime/core/SectionEngineCore.js.map +1 -1
  79. package/dist/runtime/core/cohort.d.ts +0 -1
  80. package/dist/runtime/core/cohort.js.map +1 -1
  81. package/dist/runtime/core/engine-input.d.ts +0 -1
  82. package/dist/runtime/core/engine-input.js.map +1 -1
  83. package/dist/runtime/core/engine-output.d.ts +2 -3
  84. package/dist/runtime/core/engine-output.js +2 -2
  85. package/dist/runtime/core/engine-output.js.map +1 -1
  86. package/dist/runtime/core/engine-readiness.d.ts +2 -3
  87. package/dist/runtime/core/engine-readiness.js.map +1 -1
  88. package/dist/runtime/core/engine-resolver.d.ts +13 -42
  89. package/dist/runtime/core/engine-resolver.js +19 -76
  90. package/dist/runtime/core/engine-resolver.js.map +1 -1
  91. package/dist/runtime/core/engine-stage-derivation.d.ts +0 -1
  92. package/dist/runtime/core/engine-stage-derivation.js.map +1 -1
  93. package/dist/runtime/core/engine-state.d.ts +0 -1
  94. package/dist/runtime/core/engine-state.js.map +1 -1
  95. package/dist/runtime/core/engine-transition.d.ts +1 -2
  96. package/dist/runtime/core/engine-transition.js +1 -1
  97. package/dist/runtime/core/engine-transition.js.map +1 -1
  98. package/dist/runtime/engine-context.d.ts +0 -1
  99. package/dist/runtime/engine-context.js.map +1 -1
  100. package/dist/runtime/engine.d.ts +1 -2
  101. package/dist/runtime/engine.js.map +1 -1
  102. package/dist/runtime/internal.d.ts +0 -1
  103. package/dist/runtime/internal.js.map +1 -1
  104. package/dist/runtime/registration-events.d.ts +0 -1
  105. package/dist/runtime/registration-events.js.map +1 -1
  106. package/dist/runtime/runtime-id.d.ts +0 -1
  107. package/dist/runtime/runtime-id.js.map +1 -1
  108. package/dist/runtime/section-runtime-engine-host-context.d.ts +22 -16
  109. package/dist/runtime/section-runtime-engine-host-context.js +10 -10
  110. package/dist/runtime/section-runtime-engine-host-context.js.map +1 -1
  111. package/dist/runtime/session-event-emitter-policy.d.ts +0 -1
  112. package/dist/runtime/session-event-emitter-policy.js.map +1 -1
  113. package/dist/runtime/stage-emit-gate.d.ts +4 -5
  114. package/dist/runtime/stage-emit-gate.js +3 -3
  115. package/dist/runtime/stage-emit-gate.js.map +1 -1
  116. package/dist/runtime/tool-host-contract.d.ts +0 -1
  117. package/dist/runtime/tool-host-contract.js.map +1 -1
  118. package/dist/services/AccessibilityCatalogResolver.d.ts +23 -1
  119. package/dist/services/AccessibilityCatalogResolver.js +200 -28
  120. package/dist/services/AccessibilityCatalogResolver.js.map +1 -1
  121. package/dist/services/ContextVariableStore.d.ts +0 -1
  122. package/dist/services/ContextVariableStore.js.map +1 -1
  123. package/dist/services/ElementToolStateStore.d.ts +0 -1
  124. package/dist/services/ElementToolStateStore.js.map +1 -1
  125. package/dist/services/HighlightCoordinator.d.ts +25 -1
  126. package/dist/services/HighlightCoordinator.js +125 -0
  127. package/dist/services/HighlightCoordinator.js.map +1 -1
  128. package/dist/services/I18nService.d.ts +0 -1
  129. package/dist/services/I18nService.js.map +1 -1
  130. package/dist/services/RangeSerializer.d.ts +0 -1
  131. package/dist/services/RangeSerializer.js.map +1 -1
  132. package/dist/services/SSMLExtractor.d.ts +16 -2
  133. package/dist/services/SSMLExtractor.js +86 -7
  134. package/dist/services/SSMLExtractor.js.map +1 -1
  135. package/dist/services/TTSService.d.ts +30 -5
  136. package/dist/services/TTSService.js +652 -159
  137. package/dist/services/TTSService.js.map +1 -1
  138. package/dist/services/ThemeProvider.d.ts +0 -1
  139. package/dist/services/ThemeProvider.js.map +1 -1
  140. package/dist/services/ToolConfigResolver.d.ts +0 -1
  141. package/dist/services/ToolConfigResolver.js.map +1 -1
  142. package/dist/services/ToolCoordinator.d.ts +0 -1
  143. package/dist/services/ToolCoordinator.js.map +1 -1
  144. package/dist/services/ToolRegistry.d.ts +2 -3
  145. package/dist/services/ToolRegistry.js +1 -1
  146. package/dist/services/ToolRegistry.js.map +1 -1
  147. package/dist/services/ToolkitCoordinator.d.ts +16 -74
  148. package/dist/services/ToolkitCoordinator.js +34 -113
  149. package/dist/services/ToolkitCoordinator.js.map +1 -1
  150. package/dist/services/create-tools-config.d.ts +0 -1
  151. package/dist/services/create-tools-config.js.map +1 -1
  152. package/dist/services/createDefaultToolRegistry.d.ts +0 -1
  153. package/dist/services/createDefaultToolRegistry.js.map +1 -1
  154. package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -1
  155. package/dist/services/defaultPersonalNeedsProfile.js.map +1 -1
  156. package/dist/services/framework-error-bus.d.ts +0 -1
  157. package/dist/services/framework-error-bus.js.map +1 -1
  158. package/dist/services/framework-error.d.ts +0 -1
  159. package/dist/services/framework-error.js.map +1 -1
  160. package/dist/services/interfaces.d.ts +20 -3
  161. package/dist/services/interfaces.js.map +1 -1
  162. package/dist/services/pnp-standard-features.d.ts +0 -1
  163. package/dist/services/pnp-standard-features.js.map +1 -1
  164. package/dist/services/section-controller-types.d.ts +0 -1
  165. package/dist/services/section-controller-types.js.map +1 -1
  166. package/dist/services/tool-config-defaults.d.ts +0 -1
  167. package/dist/services/tool-config-defaults.js.map +1 -1
  168. package/dist/services/tool-config-validation.d.ts +1 -2
  169. package/dist/services/tool-config-validation.js +7 -7
  170. package/dist/services/tool-config-validation.js.map +1 -1
  171. package/dist/services/tool-context.d.ts +0 -1
  172. package/dist/services/tool-context.js.map +1 -1
  173. package/dist/services/tool-instance-id.d.ts +0 -1
  174. package/dist/services/tool-instance-id.js +1 -1
  175. package/dist/services/tool-instance-id.js.map +1 -1
  176. package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -1
  177. package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -1
  178. package/dist/services/tool-providers/TTSToolProvider.d.ts +0 -1
  179. package/dist/services/tool-providers/TTSToolProvider.js +3 -3
  180. package/dist/services/tool-providers/TTSToolProvider.js.map +1 -1
  181. package/dist/services/tool-providers/ToolProviderApi.d.ts +0 -1
  182. package/dist/services/tool-providers/ToolProviderApi.js.map +1 -1
  183. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +0 -1
  184. package/dist/services/tool-providers/ToolProviderRegistry.js.map +1 -1
  185. package/dist/services/tool-providers/index.d.ts +0 -1
  186. package/dist/services/tool-providers/index.js.map +1 -1
  187. package/dist/services/toolbar-items.d.ts +0 -1
  188. package/dist/services/toolbar-items.js.map +1 -1
  189. package/dist/services/tools-config-normalizer.d.ts +13 -3
  190. package/dist/services/tools-config-normalizer.js +3 -8
  191. package/dist/services/tools-config-normalizer.js.map +1 -1
  192. package/dist/services/tts/browser-provider.d.ts +0 -1
  193. package/dist/services/tts/browser-provider.js +2 -0
  194. package/dist/services/tts/browser-provider.js.map +1 -1
  195. package/dist/services/tts/catalog-span-alignment.d.ts +39 -0
  196. package/dist/services/tts/catalog-span-alignment.js +300 -0
  197. package/dist/services/tts/catalog-span-alignment.js.map +1 -0
  198. package/dist/services/tts/generated-speech/assemble-plan.d.ts +33 -0
  199. package/dist/services/tts/generated-speech/assemble-plan.js +111 -0
  200. package/dist/services/tts/generated-speech/assemble-plan.js.map +1 -0
  201. package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +25 -0
  202. package/dist/services/tts/generated-speech/dom/build-dom-plan.js +66 -0
  203. package/dist/services/tts/generated-speech/dom/build-dom-plan.js.map +1 -0
  204. package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +19 -0
  205. package/dist/services/tts/generated-speech/dom/to-chunk-inputs.js +71 -0
  206. package/dist/services/tts/generated-speech/dom/to-chunk-inputs.js.map +1 -0
  207. package/dist/services/tts/generated-speech/dom/types.d.ts +37 -0
  208. package/dist/services/tts/generated-speech/dom/types.js +2 -0
  209. package/dist/services/tts/generated-speech/dom/types.js.map +1 -0
  210. package/dist/services/tts/generated-speech/index.d.ts +17 -0
  211. package/dist/services/tts/generated-speech/index.js +17 -0
  212. package/dist/services/tts/generated-speech/index.js.map +1 -0
  213. package/dist/services/tts/generated-speech/math-speech-cache.d.ts +15 -0
  214. package/dist/services/tts/generated-speech/math-speech-cache.js +78 -0
  215. package/dist/services/tts/generated-speech/math-speech-cache.js.map +1 -0
  216. package/dist/services/tts/generated-speech/types.d.ts +104 -0
  217. package/dist/services/tts/generated-speech/types.js +18 -0
  218. package/dist/services/tts/generated-speech/types.js.map +1 -0
  219. package/dist/services/tts/highlight-pipeline/boundary-normalizer.d.ts +2 -0
  220. package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +106 -0
  221. package/dist/services/tts/highlight-pipeline/boundary-normalizer.js.map +1 -0
  222. package/dist/services/tts/highlight-pipeline/create-highlight-plan.d.ts +6 -0
  223. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +217 -0
  224. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js.map +1 -0
  225. package/dist/services/tts/highlight-pipeline/highlight-policy.d.ts +2 -0
  226. package/dist/services/tts/highlight-pipeline/highlight-policy.js +32 -0
  227. package/dist/services/tts/highlight-pipeline/highlight-policy.js.map +1 -0
  228. package/dist/services/tts/highlight-pipeline/index.d.ts +9 -0
  229. package/dist/services/tts/highlight-pipeline/index.js +9 -0
  230. package/dist/services/tts/highlight-pipeline/index.js.map +1 -0
  231. package/dist/services/tts/highlight-pipeline/math-semantic-resolver.d.ts +3 -0
  232. package/dist/services/tts/highlight-pipeline/math-semantic-resolver.js +32 -0
  233. package/dist/services/tts/highlight-pipeline/math-semantic-resolver.js.map +1 -0
  234. package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.d.ts +29 -0
  235. package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +44 -0
  236. package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js.map +1 -0
  237. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.d.ts +2 -0
  238. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +20 -0
  239. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js.map +1 -0
  240. package/dist/services/tts/highlight-pipeline/readable-region.d.ts +1 -0
  241. package/dist/services/tts/highlight-pipeline/readable-region.js +19 -0
  242. package/dist/services/tts/highlight-pipeline/readable-region.js.map +1 -0
  243. package/dist/services/tts/highlight-pipeline/rendered-math-target-resolver.d.ts +6 -0
  244. package/dist/services/tts/highlight-pipeline/rendered-math-target-resolver.js +198 -0
  245. package/dist/services/tts/highlight-pipeline/rendered-math-target-resolver.js.map +1 -0
  246. package/dist/services/tts/highlight-pipeline/types.d.ts +72 -0
  247. package/dist/services/tts/highlight-pipeline/types.js +2 -0
  248. package/dist/services/tts/highlight-pipeline/types.js.map +1 -0
  249. package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +2 -0
  250. package/dist/services/tts/highlight-pipeline/visible-map-range.js +22 -0
  251. package/dist/services/tts/highlight-pipeline/visible-map-range.js.map +1 -0
  252. package/dist/services/tts/math-alignment/index.d.ts +30 -0
  253. package/dist/services/tts/math-alignment/index.js +66 -0
  254. package/dist/services/tts/math-alignment/index.js.map +1 -0
  255. package/dist/services/tts/math-alignment/mathml-tokenizer.d.ts +2 -0
  256. package/dist/services/tts/math-alignment/mathml-tokenizer.js +317 -0
  257. package/dist/services/tts/math-alignment/mathml-tokenizer.js.map +1 -0
  258. package/dist/services/tts/math-alignment/range-resolver.d.ts +10 -0
  259. package/dist/services/tts/math-alignment/range-resolver.js +13 -0
  260. package/dist/services/tts/math-alignment/range-resolver.js.map +1 -0
  261. package/dist/services/tts/math-alignment/sequence-aligner.d.ts +7 -0
  262. package/dist/services/tts/math-alignment/sequence-aligner.js +119 -0
  263. package/dist/services/tts/math-alignment/sequence-aligner.js.map +1 -0
  264. package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +31 -0
  265. package/dist/services/tts/math-alignment/speech-tokenizer.js +143 -0
  266. package/dist/services/tts/math-alignment/speech-tokenizer.js.map +1 -0
  267. package/dist/services/tts/math-alignment/types.d.ts +58 -0
  268. package/dist/services/tts/math-alignment/types.js +2 -0
  269. package/dist/services/tts/math-alignment/types.js.map +1 -0
  270. package/dist/services/tts/math-aware-text-processing.d.ts +18 -0
  271. package/dist/services/tts/math-aware-text-processing.js +348 -0
  272. package/dist/services/tts/math-aware-text-processing.js.map +1 -0
  273. package/dist/services/tts/math-speech.d.ts +44 -0
  274. package/dist/services/tts/math-speech.js +147 -0
  275. package/dist/services/tts/math-speech.js.map +1 -0
  276. package/dist/services/tts/mathml-sanitization.d.ts +1 -0
  277. package/dist/services/tts/mathml-sanitization.js +170 -0
  278. package/dist/services/tts/mathml-sanitization.js.map +1 -0
  279. package/dist/services/tts/ssml/spoken-text.d.ts +33 -0
  280. package/dist/services/tts/ssml/spoken-text.js +159 -0
  281. package/dist/services/tts/ssml/spoken-text.js.map +1 -0
  282. package/dist/services/tts/text-processing.d.ts +3 -1
  283. package/dist/services/tts/text-processing.js +30 -4
  284. package/dist/services/tts/text-processing.js.map +1 -1
  285. package/dist/services/tts/text-segmentation.d.ts +0 -1
  286. package/dist/services/tts/text-segmentation.js.map +1 -1
  287. package/dist/services/tts/visual-line-ranges.d.ts +0 -1
  288. package/dist/services/tts/visual-line-ranges.js.map +1 -1
  289. package/dist/services/tts-control-events.d.ts +0 -1
  290. package/dist/services/tts-control-events.js.map +1 -1
  291. package/dist/services/tts-runtime-config.d.ts +17 -2
  292. package/dist/services/tts-runtime-config.js +11 -1
  293. package/dist/services/tts-runtime-config.js.map +1 -1
  294. package/dist/tools/calculators/desmos-provider.d.ts +0 -1
  295. package/dist/tools/calculators/desmos-provider.js.map +1 -1
  296. package/dist/tools/client.d.ts +0 -1
  297. package/dist/tools/client.js.map +1 -1
  298. package/dist/tools/default-tool-module-loaders.d.ts +0 -1
  299. package/dist/tools/default-tool-module-loaders.js.map +1 -1
  300. package/dist/tools/index.d.ts +0 -1
  301. package/dist/tools/index.js.map +1 -1
  302. package/dist/tools/library-loader.d.ts +0 -1
  303. package/dist/tools/library-loader.js.map +1 -1
  304. package/dist/tools/registrations/accessibility-tools.d.ts +0 -1
  305. package/dist/tools/registrations/accessibility-tools.js +0 -1
  306. package/dist/tools/registrations/accessibility-tools.js.map +1 -1
  307. package/dist/tools/registrations/calculator.d.ts +0 -1
  308. package/dist/tools/registrations/calculator.js +41 -2
  309. package/dist/tools/registrations/calculator.js.map +1 -1
  310. package/dist/tools/registrations/interaction-tools.d.ts +0 -1
  311. package/dist/tools/registrations/interaction-tools.js.map +1 -1
  312. package/dist/tools/registrations/measurement-tools.d.ts +0 -1
  313. package/dist/tools/registrations/measurement-tools.js.map +1 -1
  314. package/dist/tools/registrations/subject-specific-tools.d.ts +0 -1
  315. package/dist/tools/registrations/subject-specific-tools.js.map +1 -1
  316. package/dist/tools/registrations/toolbar-registration-helpers.d.ts +0 -1
  317. package/dist/tools/registrations/toolbar-registration-helpers.js.map +1 -1
  318. package/dist/tools/registrations/tts.d.ts +0 -1
  319. package/dist/tools/registrations/tts.js.map +1 -1
  320. package/dist/tools/response-discovery.d.ts +0 -1
  321. package/dist/tools/response-discovery.js.map +1 -1
  322. package/dist/tools/tool-tag-map.d.ts +0 -1
  323. package/dist/tools/tool-tag-map.js +0 -1
  324. package/dist/tools/tool-tag-map.js.map +1 -1
  325. package/dist/tools/types.d.ts +0 -1
  326. package/dist/tools/types.js.map +1 -1
  327. package/dist/tools/variant-resolver.d.ts +0 -1
  328. package/dist/tools/variant-resolver.js.map +1 -1
  329. package/dist/utils/logger.d.ts +0 -1
  330. package/dist/utils/logger.js.map +1 -1
  331. package/package.json +8 -11
  332. package/dist/attempt/AssessmentSession.d.ts.map +0 -1
  333. package/dist/attempt/TestSession.d.ts.map +0 -1
  334. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts.map +0 -1
  335. package/dist/components/item-toolbar-element.d.ts.map +0 -1
  336. package/dist/components/pie-assessment-toolkit-element.d.ts.map +0 -1
  337. package/dist/components/section-toolbar-element.d.ts.map +0 -1
  338. package/dist/context/assessment-toolkit-context.d.ts.map +0 -1
  339. package/dist/context/runtime-context-consumer.d.ts.map +0 -1
  340. package/dist/index.d.ts.map +0 -1
  341. package/dist/item-loader.d.ts.map +0 -1
  342. package/dist/policy/core/PolicySource.d.ts.map +0 -1
  343. package/dist/policy/core/ToolPolicyEngine.d.ts.map +0 -1
  344. package/dist/policy/core/compose-decision.d.ts.map +0 -1
  345. package/dist/policy/core/decision-types.d.ts.map +0 -1
  346. package/dist/policy/core/engine-context.d.ts.map +0 -1
  347. package/dist/policy/core/pnp-policy-inputs.d.ts.map +0 -1
  348. package/dist/policy/core/policy-source-tag.d.ts.map +0 -1
  349. package/dist/policy/core/provenance.d.ts.map +0 -1
  350. package/dist/policy/engine.d.ts.map +0 -1
  351. package/dist/policy/internal.d.ts.map +0 -1
  352. package/dist/policy/sources/PnpPolicySource.d.ts.map +0 -1
  353. package/dist/runtime/RuntimeRegistry.d.ts.map +0 -1
  354. package/dist/runtime/SectionRuntimeEngine.d.ts.map +0 -1
  355. package/dist/runtime/adapter/SectionEngineAdapter.d.ts.map +0 -1
  356. package/dist/runtime/adapter/coordinator-bridge.d.ts.map +0 -1
  357. package/dist/runtime/adapter/dom-event-bridge.d.ts.map +0 -1
  358. package/dist/runtime/adapter/framework-error-bridge.d.ts.map +0 -1
  359. package/dist/runtime/adapter/instrumentation-bridge.d.ts.map +0 -1
  360. package/dist/runtime/adapter/subscriber-fanout.d.ts.map +0 -1
  361. package/dist/runtime/core/SectionEngineCore.d.ts.map +0 -1
  362. package/dist/runtime/core/cohort.d.ts.map +0 -1
  363. package/dist/runtime/core/engine-input.d.ts.map +0 -1
  364. package/dist/runtime/core/engine-output.d.ts.map +0 -1
  365. package/dist/runtime/core/engine-readiness.d.ts.map +0 -1
  366. package/dist/runtime/core/engine-resolver.d.ts.map +0 -1
  367. package/dist/runtime/core/engine-stage-derivation.d.ts.map +0 -1
  368. package/dist/runtime/core/engine-state.d.ts.map +0 -1
  369. package/dist/runtime/core/engine-transition.d.ts.map +0 -1
  370. package/dist/runtime/engine-context.d.ts.map +0 -1
  371. package/dist/runtime/engine.d.ts.map +0 -1
  372. package/dist/runtime/internal.d.ts.map +0 -1
  373. package/dist/runtime/registration-events.d.ts.map +0 -1
  374. package/dist/runtime/runtime-id.d.ts.map +0 -1
  375. package/dist/runtime/section-runtime-engine-host-context.d.ts.map +0 -1
  376. package/dist/runtime/session-event-emitter-policy.d.ts.map +0 -1
  377. package/dist/runtime/stage-emit-gate.d.ts.map +0 -1
  378. package/dist/runtime/tool-host-contract.d.ts.map +0 -1
  379. package/dist/services/AccessibilityCatalogResolver.d.ts.map +0 -1
  380. package/dist/services/ContextVariableStore.d.ts.map +0 -1
  381. package/dist/services/ElementToolStateStore.d.ts.map +0 -1
  382. package/dist/services/HighlightCoordinator.d.ts.map +0 -1
  383. package/dist/services/I18nService.d.ts.map +0 -1
  384. package/dist/services/PNPToolResolver.d.ts +0 -281
  385. package/dist/services/PNPToolResolver.d.ts.map +0 -1
  386. package/dist/services/PNPToolResolver.js +0 -514
  387. package/dist/services/PNPToolResolver.js.map +0 -1
  388. package/dist/services/RangeSerializer.d.ts.map +0 -1
  389. package/dist/services/SSMLExtractor.d.ts.map +0 -1
  390. package/dist/services/TTSService.d.ts.map +0 -1
  391. package/dist/services/ThemeProvider.d.ts.map +0 -1
  392. package/dist/services/ToolConfigResolver.d.ts.map +0 -1
  393. package/dist/services/ToolCoordinator.d.ts.map +0 -1
  394. package/dist/services/ToolRegistry.d.ts.map +0 -1
  395. package/dist/services/ToolkitCoordinator.d.ts.map +0 -1
  396. package/dist/services/create-tools-config.d.ts.map +0 -1
  397. package/dist/services/createDefaultToolRegistry.d.ts.map +0 -1
  398. package/dist/services/defaultPersonalNeedsProfile.d.ts.map +0 -1
  399. package/dist/services/framework-error-bus.d.ts.map +0 -1
  400. package/dist/services/framework-error.d.ts.map +0 -1
  401. package/dist/services/interfaces.d.ts.map +0 -1
  402. package/dist/services/pnp-provenance.d.ts +0 -167
  403. package/dist/services/pnp-provenance.d.ts.map +0 -1
  404. package/dist/services/pnp-provenance.js +0 -231
  405. package/dist/services/pnp-provenance.js.map +0 -1
  406. package/dist/services/pnp-standard-features.d.ts.map +0 -1
  407. package/dist/services/section-controller-types.d.ts.map +0 -1
  408. package/dist/services/tool-config-defaults.d.ts.map +0 -1
  409. package/dist/services/tool-config-validation.d.ts.map +0 -1
  410. package/dist/services/tool-context.d.ts.map +0 -1
  411. package/dist/services/tool-instance-id.d.ts.map +0 -1
  412. package/dist/services/tool-providers/DesmosToolProvider.d.ts.map +0 -1
  413. package/dist/services/tool-providers/TTSToolProvider.d.ts.map +0 -1
  414. package/dist/services/tool-providers/ToolProviderApi.d.ts.map +0 -1
  415. package/dist/services/tool-providers/ToolProviderRegistry.d.ts.map +0 -1
  416. package/dist/services/tool-providers/index.d.ts.map +0 -1
  417. package/dist/services/toolbar-items.d.ts.map +0 -1
  418. package/dist/services/tools-config-normalizer.d.ts.map +0 -1
  419. package/dist/services/tts/browser-provider.d.ts.map +0 -1
  420. package/dist/services/tts/text-processing.d.ts.map +0 -1
  421. package/dist/services/tts/text-segmentation.d.ts.map +0 -1
  422. package/dist/services/tts/visual-line-ranges.d.ts.map +0 -1
  423. package/dist/services/tts-control-events.d.ts.map +0 -1
  424. package/dist/services/tts-runtime-config.d.ts.map +0 -1
  425. package/dist/tools/calculators/desmos-provider.d.ts.map +0 -1
  426. package/dist/tools/client.d.ts.map +0 -1
  427. package/dist/tools/default-tool-module-loaders.d.ts.map +0 -1
  428. package/dist/tools/index.d.ts.map +0 -1
  429. package/dist/tools/library-loader.d.ts.map +0 -1
  430. package/dist/tools/registrations/accessibility-tools.d.ts.map +0 -1
  431. package/dist/tools/registrations/calculator.d.ts.map +0 -1
  432. package/dist/tools/registrations/interaction-tools.d.ts.map +0 -1
  433. package/dist/tools/registrations/measurement-tools.d.ts.map +0 -1
  434. package/dist/tools/registrations/subject-specific-tools.d.ts.map +0 -1
  435. package/dist/tools/registrations/toolbar-registration-helpers.d.ts.map +0 -1
  436. package/dist/tools/registrations/tts.d.ts.map +0 -1
  437. package/dist/tools/response-discovery.d.ts.map +0 -1
  438. package/dist/tools/tool-tag-map.d.ts.map +0 -1
  439. package/dist/tools/types.d.ts.map +0 -1
  440. package/dist/tools/variant-resolver.d.ts.map +0 -1
  441. package/dist/utils/logger.d.ts.map +0 -1
@@ -0,0 +1,300 @@
1
+ import { extractSpokenText } from "./ssml/spoken-text.js";
2
+ import { createSpeechAlignmentTokenPattern, normalizeTextForSpeech, } from "./text-processing.js";
3
+ // Shared Unicode-aware tokenizer (see `createSpeechAlignmentTokenPattern`), so
4
+ // accented Latin and non-Latin words tokenize the same way here as in the math
5
+ // speech tokenizer. LIMITATION (i18n): the phrase table below is still English,
6
+ // so multi-word operator phrases ("plus or minus", "divided by") only align for
7
+ // English speech; other locales degrade to coarse region highlighting. A fresh
8
+ // pattern per call because of the global flag's mutable `lastIndex`.
9
+ const TOKEN_PATTERN = createSpeechAlignmentTokenPattern();
10
+ const NUMERIC_WORDS = new Map([
11
+ ["zero", "0"],
12
+ ["one", "1"],
13
+ ["two", "2"],
14
+ ["three", "3"],
15
+ ["four", "4"],
16
+ ["five", "5"],
17
+ ["six", "6"],
18
+ ["seven", "7"],
19
+ ["eight", "8"],
20
+ ["nine", "9"],
21
+ ["ten", "10"],
22
+ ]);
23
+ const SPOKEN_PHRASE_TARGETS = [
24
+ { phrase: ["plus", "or", "minus"], visible: "±", score: 8 },
25
+ { phrase: ["square", "root"], visible: "√", score: 8 },
26
+ { phrase: ["divided", "by"], visible: "/", score: 7 },
27
+ { phrase: ["all", "over"], visible: "/", score: 7 },
28
+ { phrase: ["equals"], visible: "=", score: 7 },
29
+ { phrase: ["equal"], visible: "=", score: 7 },
30
+ { phrase: ["times"], visible: "\u2062", score: 7 },
31
+ { phrase: ["multiplied", "by"], visible: "\u2062", score: 7 },
32
+ { phrase: ["over"], visible: "/", score: 6 },
33
+ { phrase: ["squared"], visible: "²", score: 6 },
34
+ { phrase: ["squared"], visible: "2", score: 4 },
35
+ { phrase: ["negative"], visible: "-", score: 5 },
36
+ { phrase: ["minus"], visible: "-", score: 5 },
37
+ { phrase: ["plus"], visible: "+", score: 5 },
38
+ ];
39
+ const tokenize = (text) => {
40
+ const tokens = [];
41
+ for (const match of text.matchAll(TOKEN_PATTERN)) {
42
+ const value = match[0];
43
+ const start = match.index ?? 0;
44
+ tokens.push({
45
+ text: value,
46
+ normalized: value.toLowerCase(),
47
+ start,
48
+ end: start + value.length,
49
+ });
50
+ }
51
+ return tokens;
52
+ };
53
+ const normalizedTokenValue = (token) => NUMERIC_WORDS.get(token.normalized) || token.normalized;
54
+ const createCandidates = (spokenTokens, visibleTokens) => {
55
+ const candidates = [];
56
+ for (let spokenIndex = 0; spokenIndex < spokenTokens.length; spokenIndex++) {
57
+ for (let visibleIndex = 0; visibleIndex < visibleTokens.length; visibleIndex++) {
58
+ const spokenValue = normalizedTokenValue(spokenTokens[spokenIndex]);
59
+ const visibleValue = normalizedTokenValue(visibleTokens[visibleIndex]);
60
+ if (spokenValue === visibleValue) {
61
+ candidates.push({
62
+ spokenStartToken: spokenIndex,
63
+ spokenEndToken: spokenIndex + 1,
64
+ visibleToken: visibleIndex,
65
+ score: 10,
66
+ });
67
+ }
68
+ }
69
+ for (const phraseTarget of SPOKEN_PHRASE_TARGETS) {
70
+ const phraseTokens = spokenTokens.slice(spokenIndex, spokenIndex + phraseTarget.phrase.length);
71
+ if (phraseTokens.length !== phraseTarget.phrase.length)
72
+ continue;
73
+ if (!phraseTokens.every((token, tokenIndex) => token.normalized === phraseTarget.phrase[tokenIndex])) {
74
+ continue;
75
+ }
76
+ for (let visibleIndex = 0; visibleIndex < visibleTokens.length; visibleIndex++) {
77
+ if (visibleTokens[visibleIndex].normalized !== phraseTarget.visible) {
78
+ continue;
79
+ }
80
+ candidates.push({
81
+ spokenStartToken: spokenIndex,
82
+ spokenEndToken: spokenIndex + phraseTarget.phrase.length,
83
+ visibleToken: visibleIndex,
84
+ score: phraseTarget.score,
85
+ });
86
+ }
87
+ }
88
+ }
89
+ return candidates;
90
+ };
91
+ const computeAnchors = (spokenTokens, visibleTokens) => {
92
+ const candidates = createCandidates(spokenTokens, visibleTokens).sort((left, right) => spokenTokens[left.spokenStartToken].start -
93
+ spokenTokens[right.spokenStartToken].start ||
94
+ visibleTokens[left.visibleToken].start - visibleTokens[right.visibleToken].start);
95
+ const bestScore = new Array(candidates.length).fill(0);
96
+ const previous = new Array(candidates.length).fill(-1);
97
+ for (let i = 0; i < candidates.length; i++) {
98
+ const candidate = candidates[i];
99
+ bestScore[i] = candidate.score;
100
+ for (let j = 0; j < i; j++) {
101
+ const prior = candidates[j];
102
+ if (prior.spokenEndToken <= candidate.spokenStartToken &&
103
+ prior.visibleToken < candidate.visibleToken) {
104
+ const spokenGap = candidate.spokenStartToken - prior.spokenEndToken;
105
+ const visibleGap = candidate.visibleToken - prior.visibleToken - 1;
106
+ const gapPenalty = Math.max(0, Math.abs(spokenGap - visibleGap) - 2);
107
+ const score = bestScore[j] + candidate.score - gapPenalty;
108
+ if (score > bestScore[i]) {
109
+ bestScore[i] = score;
110
+ previous[i] = j;
111
+ }
112
+ }
113
+ }
114
+ }
115
+ let bestIndex = -1;
116
+ for (let i = 0; i < bestScore.length; i++) {
117
+ if (bestIndex < 0 || bestScore[i] > bestScore[bestIndex]) {
118
+ bestIndex = i;
119
+ }
120
+ }
121
+ if (bestIndex < 0)
122
+ return [];
123
+ const chosen = [];
124
+ let current = bestIndex;
125
+ while (current >= 0) {
126
+ chosen.unshift(candidates[current]);
127
+ current = previous[current];
128
+ }
129
+ return chosen.map((candidate) => {
130
+ const firstSpoken = spokenTokens[candidate.spokenStartToken];
131
+ const lastSpoken = spokenTokens[candidate.spokenEndToken - 1];
132
+ const visible = visibleTokens[candidate.visibleToken];
133
+ return {
134
+ spokenStart: firstSpoken.start,
135
+ spokenEnd: lastSpoken.end,
136
+ visibleStart: visible.start,
137
+ visibleEnd: visible.end,
138
+ score: candidate.score,
139
+ };
140
+ });
141
+ };
142
+ const scoreConfidence = (anchors, spokenTokens, visibleTokens) => {
143
+ if (anchors.length === 0)
144
+ return 0;
145
+ const tokenCoverage = anchors.length / Math.max(1, Math.min(spokenTokens.length, visibleTokens.length));
146
+ const averageScore = anchors.reduce((total, anchor) => total + anchor.score, 0) /
147
+ anchors.length /
148
+ 10;
149
+ return Math.min(1, tokenCoverage * averageScore);
150
+ };
151
+ export const createCatalogSpanAlignment = (args) => {
152
+ const extracted = extractSpokenText(args.speechText);
153
+ const visibleText = normalizeTextForSpeech(args.visibleText);
154
+ const spokenText = extracted.spokenText;
155
+ const spokenTokens = tokenize(spokenText);
156
+ const visibleTokens = tokenize(visibleText);
157
+ const anchors = extracted.unsupportedSemantic
158
+ ? []
159
+ : computeAnchors(spokenTokens, visibleTokens);
160
+ const confidence = scoreConfidence(anchors, spokenTokens, visibleTokens);
161
+ const isExact = spokenText === visibleText && spokenText.length > 0;
162
+ const hasShortSingleExactAnchor = anchors.length === 1 &&
163
+ anchors[0].score === 10 &&
164
+ spokenTokens.length <= 2 &&
165
+ visibleTokens.length <= 2;
166
+ const playbackMode = extracted.unsupportedSemantic
167
+ ? "region-fallback"
168
+ : isExact
169
+ ? "exact-word"
170
+ : anchors.length >= 2 || hasShortSingleExactAnchor
171
+ ? confidence >= 0.12
172
+ ? "anchor-span"
173
+ : "region-fallback"
174
+ : "region-fallback";
175
+ const boundaryOffsetMode = extracted.unsupportedSemantic
176
+ ? "unsupported"
177
+ : extracted.hasMarkup
178
+ ? "raw-ssml"
179
+ : "plain-spoken-text";
180
+ return {
181
+ speechText: args.speechText,
182
+ spokenText,
183
+ visibleText,
184
+ playbackMode,
185
+ boundaryOffsetMode,
186
+ anchors,
187
+ confidence,
188
+ spokenTokens,
189
+ visibleTokens,
190
+ rawToSpokenOffsetMap: extracted.rawToSpokenOffsetMap,
191
+ };
192
+ };
193
+ const findTokenAtOffset = (tokens, offset) => tokens.find((token) => token.start <= offset && offset < token.end) || null;
194
+ const normalizeBoundaryWord = (word) => {
195
+ if (!word)
196
+ return null;
197
+ if (/^<[^>]+>$/.test(word.trim()))
198
+ return null;
199
+ const token = tokenize(word)[0];
200
+ if (!token)
201
+ return null;
202
+ return NUMERIC_WORDS.get(token.normalized) || token.normalized;
203
+ };
204
+ const candidateMatchesBoundaryWord = (alignment, candidate, boundaryWord) => {
205
+ const normalizedBoundary = normalizeBoundaryWord(boundaryWord);
206
+ if (!candidate || !normalizedBoundary)
207
+ return false;
208
+ const token = findTokenAtOffset(alignment.spokenTokens, candidate.start);
209
+ if (!token)
210
+ return false;
211
+ return normalizedTokenValue(token) === normalizedBoundary;
212
+ };
213
+ const mapRawOffsetToSpokenOffset = (alignment, position) => {
214
+ const direct = alignment.rawToSpokenOffsetMap.get(position);
215
+ if (direct !== undefined)
216
+ return direct;
217
+ for (let offset = position; offset < alignment.speechText.length; offset++) {
218
+ const mapped = alignment.rawToSpokenOffsetMap.get(offset);
219
+ if (mapped !== undefined)
220
+ return mapped;
221
+ if (alignment.speechText[offset] === ">")
222
+ break;
223
+ }
224
+ return null;
225
+ };
226
+ const resolveRawBoundaryOffset = (alignment, position, safeLength) => {
227
+ const mappedStart = mapRawOffsetToSpokenOffset(alignment, position);
228
+ if (mappedStart === null)
229
+ return null;
230
+ const mappedEnd = mapRawOffsetToSpokenOffset(alignment, Math.max(position, position + safeLength - 1));
231
+ const token = findTokenAtOffset(alignment.spokenTokens, mappedStart);
232
+ const mappedLength = mappedEnd !== null && mappedEnd >= mappedStart
233
+ ? mappedEnd - mappedStart + 1
234
+ : token
235
+ ? token.end - mappedStart
236
+ : safeLength;
237
+ return { start: mappedStart, length: Math.max(1, mappedLength) };
238
+ };
239
+ const resolvePlainBoundaryOffset = (alignment, position, safeLength) => {
240
+ if (position < 0 || position >= alignment.spokenText.length)
241
+ return null;
242
+ const token = findTokenAtOffset(alignment.spokenTokens, position);
243
+ if (!token)
244
+ return null;
245
+ return { start: position, length: Math.min(safeLength, token.end - position) };
246
+ };
247
+ export const resolveSpokenBoundaryOffset = (alignment, position, length = 1, boundaryWord) => {
248
+ if (alignment.boundaryOffsetMode === "unsupported" ||
249
+ !Number.isFinite(position)) {
250
+ return null;
251
+ }
252
+ const safeLength = Math.max(1, Number.isFinite(length) ? length : 1);
253
+ if (boundaryWord && /^<[^>]+>$/.test(boundaryWord.trim()))
254
+ return null;
255
+ if (alignment.boundaryOffsetMode === "raw-ssml") {
256
+ const rawCandidate = resolveRawBoundaryOffset(alignment, position, safeLength);
257
+ const plainCandidate = resolvePlainBoundaryOffset(alignment, position, safeLength);
258
+ if (boundaryWord) {
259
+ if (candidateMatchesBoundaryWord(alignment, rawCandidate, boundaryWord)) {
260
+ return rawCandidate;
261
+ }
262
+ if (candidateMatchesBoundaryWord(alignment, plainCandidate, boundaryWord)) {
263
+ return plainCandidate;
264
+ }
265
+ if (normalizeBoundaryWord(boundaryWord))
266
+ return null;
267
+ }
268
+ return rawCandidate || plainCandidate;
269
+ }
270
+ return (resolvePlainBoundaryOffset(alignment, position, safeLength) ||
271
+ resolveRawBoundaryOffset(alignment, position, safeLength));
272
+ };
273
+ export const resolveVisibleSpanForBoundary = (alignment, spokenOffset) => {
274
+ if (alignment.playbackMode === "region-fallback")
275
+ return null;
276
+ const exactAnchor = alignment.anchors.find((anchor) => anchor.spokenStart <= spokenOffset && spokenOffset < anchor.spokenEnd);
277
+ if (exactAnchor) {
278
+ return { start: exactAnchor.visibleStart, end: exactAnchor.visibleEnd };
279
+ }
280
+ let previous = null;
281
+ let next = null;
282
+ for (const anchor of alignment.anchors) {
283
+ if (anchor.spokenEnd <= spokenOffset) {
284
+ previous = anchor;
285
+ continue;
286
+ }
287
+ if (anchor.spokenStart > spokenOffset) {
288
+ next = anchor;
289
+ break;
290
+ }
291
+ }
292
+ if (previous && next) {
293
+ return {
294
+ start: Math.min(previous.visibleStart, next.visibleStart),
295
+ end: Math.max(previous.visibleEnd, next.visibleEnd),
296
+ };
297
+ }
298
+ return null;
299
+ };
300
+ //# sourceMappingURL=catalog-span-alignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-span-alignment.js","sourceRoot":"","sources":["../../../src/services/tts/catalog-span-alignment.ts"],"names":[],"mappings":"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","sourcesContent":["import { extractSpokenText } from \"./ssml/spoken-text.js\";\nimport {\n\tcreateSpeechAlignmentTokenPattern,\n\tnormalizeTextForSpeech,\n} from \"./text-processing.js\";\n\nexport type CatalogChunkPlaybackMode =\n\t| \"exact-word\"\n\t| \"anchor-span\"\n\t| \"region-fallback\";\n\nexport type BoundaryOffsetMode =\n\t| \"plain-spoken-text\"\n\t| \"raw-ssml\"\n\t| \"unsupported\";\n\nexport interface CatalogTextToken {\n\ttext: string;\n\tnormalized: string;\n\tstart: number;\n\tend: number;\n}\n\nexport interface CatalogSpanAnchor {\n\tspokenStart: number;\n\tspokenEnd: number;\n\tvisibleStart: number;\n\tvisibleEnd: number;\n\tscore: number;\n}\n\nexport interface CatalogSpanAlignment {\n\tspeechText: string;\n\tspokenText: string;\n\tvisibleText: string;\n\tplaybackMode: CatalogChunkPlaybackMode;\n\tboundaryOffsetMode: BoundaryOffsetMode;\n\tanchors: CatalogSpanAnchor[];\n\tconfidence: number;\n\tspokenTokens: CatalogTextToken[];\n\tvisibleTokens: CatalogTextToken[];\n\trawToSpokenOffsetMap: Map<number, number>;\n}\n\ninterface MatchCandidate {\n\tspokenStartToken: number;\n\tspokenEndToken: number;\n\tvisibleToken: number;\n\tscore: number;\n}\n\n// Shared Unicode-aware tokenizer (see `createSpeechAlignmentTokenPattern`), so\n// accented Latin and non-Latin words tokenize the same way here as in the math\n// speech tokenizer. LIMITATION (i18n): the phrase table below is still English,\n// so multi-word operator phrases (\"plus or minus\", \"divided by\") only align for\n// English speech; other locales degrade to coarse region highlighting. A fresh\n// pattern per call because of the global flag's mutable `lastIndex`.\nconst TOKEN_PATTERN = createSpeechAlignmentTokenPattern();\n\nconst NUMERIC_WORDS = new Map<string, string>([\n\t[\"zero\", \"0\"],\n\t[\"one\", \"1\"],\n\t[\"two\", \"2\"],\n\t[\"three\", \"3\"],\n\t[\"four\", \"4\"],\n\t[\"five\", \"5\"],\n\t[\"six\", \"6\"],\n\t[\"seven\", \"7\"],\n\t[\"eight\", \"8\"],\n\t[\"nine\", \"9\"],\n\t[\"ten\", \"10\"],\n]);\n\nconst SPOKEN_PHRASE_TARGETS: Array<{\n\tphrase: string[];\n\tvisible: string;\n\tscore: number;\n}> = [\n\t{ phrase: [\"plus\", \"or\", \"minus\"], visible: \"±\", score: 8 },\n\t{ phrase: [\"square\", \"root\"], visible: \"√\", score: 8 },\n\t{ phrase: [\"divided\", \"by\"], visible: \"/\", score: 7 },\n\t{ phrase: [\"all\", \"over\"], visible: \"/\", score: 7 },\n\t{ phrase: [\"equals\"], visible: \"=\", score: 7 },\n\t{ phrase: [\"equal\"], visible: \"=\", score: 7 },\n\t{ phrase: [\"times\"], visible: \"\\u2062\", score: 7 },\n\t{ phrase: [\"multiplied\", \"by\"], visible: \"\\u2062\", score: 7 },\n\t{ phrase: [\"over\"], visible: \"/\", score: 6 },\n\t{ phrase: [\"squared\"], visible: \"²\", score: 6 },\n\t{ phrase: [\"squared\"], visible: \"2\", score: 4 },\n\t{ phrase: [\"negative\"], visible: \"-\", score: 5 },\n\t{ phrase: [\"minus\"], visible: \"-\", score: 5 },\n\t{ phrase: [\"plus\"], visible: \"+\", score: 5 },\n];\n\nconst tokenize = (text: string): CatalogTextToken[] => {\n\tconst tokens: CatalogTextToken[] = [];\n\tfor (const match of text.matchAll(TOKEN_PATTERN)) {\n\t\tconst value = match[0];\n\t\tconst start = match.index ?? 0;\n\t\ttokens.push({\n\t\t\ttext: value,\n\t\t\tnormalized: value.toLowerCase(),\n\t\t\tstart,\n\t\t\tend: start + value.length,\n\t\t});\n\t}\n\treturn tokens;\n};\n\nconst normalizedTokenValue = (token: CatalogTextToken): string =>\n\tNUMERIC_WORDS.get(token.normalized) || token.normalized;\n\nconst createCandidates = (\n\tspokenTokens: CatalogTextToken[],\n\tvisibleTokens: CatalogTextToken[],\n): MatchCandidate[] => {\n\tconst candidates: MatchCandidate[] = [];\n\tfor (let spokenIndex = 0; spokenIndex < spokenTokens.length; spokenIndex++) {\n\t\tfor (let visibleIndex = 0; visibleIndex < visibleTokens.length; visibleIndex++) {\n\t\t\tconst spokenValue = normalizedTokenValue(spokenTokens[spokenIndex]);\n\t\t\tconst visibleValue = normalizedTokenValue(visibleTokens[visibleIndex]);\n\t\t\tif (spokenValue === visibleValue) {\n\t\t\t\tcandidates.push({\n\t\t\t\t\tspokenStartToken: spokenIndex,\n\t\t\t\t\tspokenEndToken: spokenIndex + 1,\n\t\t\t\t\tvisibleToken: visibleIndex,\n\t\t\t\t\tscore: 10,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const phraseTarget of SPOKEN_PHRASE_TARGETS) {\n\t\t\tconst phraseTokens = spokenTokens.slice(\n\t\t\t\tspokenIndex,\n\t\t\t\tspokenIndex + phraseTarget.phrase.length,\n\t\t\t);\n\t\t\tif (phraseTokens.length !== phraseTarget.phrase.length) continue;\n\t\t\tif (\n\t\t\t\t!phraseTokens.every(\n\t\t\t\t\t(token, tokenIndex) =>\n\t\t\t\t\t\ttoken.normalized === phraseTarget.phrase[tokenIndex],\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (\n\t\t\t\tlet visibleIndex = 0;\n\t\t\t\tvisibleIndex < visibleTokens.length;\n\t\t\t\tvisibleIndex++\n\t\t\t) {\n\t\t\t\tif (visibleTokens[visibleIndex].normalized !== phraseTarget.visible) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcandidates.push({\n\t\t\t\t\tspokenStartToken: spokenIndex,\n\t\t\t\t\tspokenEndToken: spokenIndex + phraseTarget.phrase.length,\n\t\t\t\t\tvisibleToken: visibleIndex,\n\t\t\t\t\tscore: phraseTarget.score,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\treturn candidates;\n};\n\nconst computeAnchors = (\n\tspokenTokens: CatalogTextToken[],\n\tvisibleTokens: CatalogTextToken[],\n): CatalogSpanAnchor[] => {\n\tconst candidates = createCandidates(spokenTokens, visibleTokens).sort(\n\t\t(left, right) =>\n\t\t\tspokenTokens[left.spokenStartToken].start -\n\t\t\t\tspokenTokens[right.spokenStartToken].start ||\n\t\t\tvisibleTokens[left.visibleToken].start - visibleTokens[right.visibleToken].start,\n\t);\n\tconst bestScore = new Array(candidates.length).fill(0) as number[];\n\tconst previous = new Array(candidates.length).fill(-1) as number[];\n\n\tfor (let i = 0; i < candidates.length; i++) {\n\t\tconst candidate = candidates[i];\n\t\tbestScore[i] = candidate.score;\n\t\tfor (let j = 0; j < i; j++) {\n\t\t\tconst prior = candidates[j];\n\t\t\tif (\n\t\t\t\tprior.spokenEndToken <= candidate.spokenStartToken &&\n\t\t\t\tprior.visibleToken < candidate.visibleToken\n\t\t\t) {\n\t\t\t\tconst spokenGap = candidate.spokenStartToken - prior.spokenEndToken;\n\t\t\t\tconst visibleGap = candidate.visibleToken - prior.visibleToken - 1;\n\t\t\t\tconst gapPenalty = Math.max(0, Math.abs(spokenGap - visibleGap) - 2);\n\t\t\t\tconst score = bestScore[j] + candidate.score - gapPenalty;\n\t\t\t\tif (score > bestScore[i]) {\n\t\t\t\t\tbestScore[i] = score;\n\t\t\t\t\tprevious[i] = j;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tlet bestIndex = -1;\n\tfor (let i = 0; i < bestScore.length; i++) {\n\t\tif (bestIndex < 0 || bestScore[i] > bestScore[bestIndex]) {\n\t\t\tbestIndex = i;\n\t\t}\n\t}\n\tif (bestIndex < 0) return [];\n\n\tconst chosen: MatchCandidate[] = [];\n\tlet current = bestIndex;\n\twhile (current >= 0) {\n\t\tchosen.unshift(candidates[current]);\n\t\tcurrent = previous[current];\n\t}\n\n\treturn chosen.map((candidate) => {\n\t\tconst firstSpoken = spokenTokens[candidate.spokenStartToken];\n\t\tconst lastSpoken = spokenTokens[candidate.spokenEndToken - 1];\n\t\tconst visible = visibleTokens[candidate.visibleToken];\n\t\treturn {\n\t\t\tspokenStart: firstSpoken.start,\n\t\t\tspokenEnd: lastSpoken.end,\n\t\t\tvisibleStart: visible.start,\n\t\t\tvisibleEnd: visible.end,\n\t\t\tscore: candidate.score,\n\t\t};\n\t});\n};\n\nconst scoreConfidence = (\n\tanchors: CatalogSpanAnchor[],\n\tspokenTokens: CatalogTextToken[],\n\tvisibleTokens: CatalogTextToken[],\n): number => {\n\tif (anchors.length === 0) return 0;\n\tconst tokenCoverage =\n\t\tanchors.length / Math.max(1, Math.min(spokenTokens.length, visibleTokens.length));\n\tconst averageScore =\n\t\tanchors.reduce((total, anchor) => total + anchor.score, 0) /\n\t\tanchors.length /\n\t\t10;\n\treturn Math.min(1, tokenCoverage * averageScore);\n};\n\nexport const createCatalogSpanAlignment = (args: {\n\tspeechText: string;\n\tvisibleText: string;\n}): CatalogSpanAlignment => {\n\tconst extracted = extractSpokenText(args.speechText);\n\tconst visibleText = normalizeTextForSpeech(args.visibleText);\n\tconst spokenText = extracted.spokenText;\n\tconst spokenTokens = tokenize(spokenText);\n\tconst visibleTokens = tokenize(visibleText);\n\tconst anchors = extracted.unsupportedSemantic\n\t\t? []\n\t\t: computeAnchors(spokenTokens, visibleTokens);\n\tconst confidence = scoreConfidence(anchors, spokenTokens, visibleTokens);\n\tconst isExact = spokenText === visibleText && spokenText.length > 0;\n\tconst hasShortSingleExactAnchor =\n\t\tanchors.length === 1 &&\n\t\tanchors[0].score === 10 &&\n\t\tspokenTokens.length <= 2 &&\n\t\tvisibleTokens.length <= 2;\n\tconst playbackMode: CatalogChunkPlaybackMode = extracted.unsupportedSemantic\n\t\t? \"region-fallback\"\n\t\t: isExact\n\t\t\t? \"exact-word\"\n\t\t\t: anchors.length >= 2 || hasShortSingleExactAnchor\n\t\t\t\t? confidence >= 0.12\n\t\t\t\t\t? \"anchor-span\"\n\t\t\t\t\t: \"region-fallback\"\n\t\t\t\t: \"region-fallback\";\n\tconst boundaryOffsetMode: BoundaryOffsetMode = extracted.unsupportedSemantic\n\t\t? \"unsupported\"\n\t\t: extracted.hasMarkup\n\t\t\t? \"raw-ssml\"\n\t\t\t: \"plain-spoken-text\";\n\n\treturn {\n\t\tspeechText: args.speechText,\n\t\tspokenText,\n\t\tvisibleText,\n\t\tplaybackMode,\n\t\tboundaryOffsetMode,\n\t\tanchors,\n\t\tconfidence,\n\t\tspokenTokens,\n\t\tvisibleTokens,\n\t\trawToSpokenOffsetMap: extracted.rawToSpokenOffsetMap,\n\t};\n};\n\nconst findTokenAtOffset = (\n\ttokens: CatalogTextToken[],\n\toffset: number,\n): CatalogTextToken | null =>\n\ttokens.find((token) => token.start <= offset && offset < token.end) || null;\n\nconst normalizeBoundaryWord = (word?: string): string | null => {\n\tif (!word) return null;\n\tif (/^<[^>]+>$/.test(word.trim())) return null;\n\tconst token = tokenize(word)[0];\n\tif (!token) return null;\n\treturn NUMERIC_WORDS.get(token.normalized) || token.normalized;\n};\n\nconst candidateMatchesBoundaryWord = (\n\talignment: CatalogSpanAlignment,\n\tcandidate: { start: number; length: number } | null,\n\tboundaryWord?: string,\n): boolean => {\n\tconst normalizedBoundary = normalizeBoundaryWord(boundaryWord);\n\tif (!candidate || !normalizedBoundary) return false;\n\tconst token = findTokenAtOffset(alignment.spokenTokens, candidate.start);\n\tif (!token) return false;\n\treturn normalizedTokenValue(token) === normalizedBoundary;\n};\n\nconst mapRawOffsetToSpokenOffset = (\n\talignment: CatalogSpanAlignment,\n\tposition: number,\n): number | null => {\n\tconst direct = alignment.rawToSpokenOffsetMap.get(position);\n\tif (direct !== undefined) return direct;\n\tfor (let offset = position; offset < alignment.speechText.length; offset++) {\n\t\tconst mapped = alignment.rawToSpokenOffsetMap.get(offset);\n\t\tif (mapped !== undefined) return mapped;\n\t\tif (alignment.speechText[offset] === \">\") break;\n\t}\n\treturn null;\n};\n\nconst resolveRawBoundaryOffset = (\n\talignment: CatalogSpanAlignment,\n\tposition: number,\n\tsafeLength: number,\n): { start: number; length: number } | null => {\n\tconst mappedStart = mapRawOffsetToSpokenOffset(alignment, position);\n\tif (mappedStart === null) return null;\n\tconst mappedEnd = mapRawOffsetToSpokenOffset(\n\t\talignment,\n\t\tMath.max(position, position + safeLength - 1),\n\t);\n\tconst token = findTokenAtOffset(alignment.spokenTokens, mappedStart);\n\tconst mappedLength =\n\t\tmappedEnd !== null && mappedEnd >= mappedStart\n\t\t\t? mappedEnd - mappedStart + 1\n\t\t\t: token\n\t\t\t\t? token.end - mappedStart\n\t\t\t\t: safeLength;\n\treturn { start: mappedStart, length: Math.max(1, mappedLength) };\n};\n\nconst resolvePlainBoundaryOffset = (\n\talignment: CatalogSpanAlignment,\n\tposition: number,\n\tsafeLength: number,\n): { start: number; length: number } | null => {\n\tif (position < 0 || position >= alignment.spokenText.length) return null;\n\tconst token = findTokenAtOffset(alignment.spokenTokens, position);\n\tif (!token) return null;\n\treturn { start: position, length: Math.min(safeLength, token.end - position) };\n};\n\nexport const resolveSpokenBoundaryOffset = (\n\talignment: CatalogSpanAlignment,\n\tposition: number,\n\tlength = 1,\n\tboundaryWord?: string,\n): { start: number; length: number } | null => {\n\tif (\n\t\talignment.boundaryOffsetMode === \"unsupported\" ||\n\t\t!Number.isFinite(position)\n\t) {\n\t\treturn null;\n\t}\n\tconst safeLength = Math.max(1, Number.isFinite(length) ? length : 1);\n\tif (boundaryWord && /^<[^>]+>$/.test(boundaryWord.trim())) return null;\n\tif (alignment.boundaryOffsetMode === \"raw-ssml\") {\n\t\tconst rawCandidate = resolveRawBoundaryOffset(\n\t\t\talignment,\n\t\t\tposition,\n\t\t\tsafeLength,\n\t\t);\n\t\tconst plainCandidate = resolvePlainBoundaryOffset(\n\t\t\talignment,\n\t\t\tposition,\n\t\t\tsafeLength,\n\t\t);\n\t\tif (boundaryWord) {\n\t\t\tif (\n\t\t\t\tcandidateMatchesBoundaryWord(alignment, rawCandidate, boundaryWord)\n\t\t\t) {\n\t\t\t\treturn rawCandidate;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcandidateMatchesBoundaryWord(alignment, plainCandidate, boundaryWord)\n\t\t\t) {\n\t\t\t\treturn plainCandidate;\n\t\t\t}\n\t\t\tif (normalizeBoundaryWord(boundaryWord)) return null;\n\t\t}\n\t\treturn rawCandidate || plainCandidate;\n\t}\n\treturn (\n\t\tresolvePlainBoundaryOffset(alignment, position, safeLength) ||\n\t\tresolveRawBoundaryOffset(alignment, position, safeLength)\n\t);\n};\n\nexport const resolveVisibleSpanForBoundary = (\n\talignment: CatalogSpanAlignment,\n\tspokenOffset: number,\n): { start: number; end: number } | null => {\n\tif (alignment.playbackMode === \"region-fallback\") return null;\n\tconst exactAnchor = alignment.anchors.find(\n\t\t(anchor) => anchor.spokenStart <= spokenOffset && spokenOffset < anchor.spokenEnd,\n\t);\n\tif (exactAnchor) {\n\t\treturn { start: exactAnchor.visibleStart, end: exactAnchor.visibleEnd };\n\t}\n\n\tlet previous: CatalogSpanAnchor | null = null;\n\tlet next: CatalogSpanAnchor | null = null;\n\tfor (const anchor of alignment.anchors) {\n\t\tif (anchor.spokenEnd <= spokenOffset) {\n\t\t\tprevious = anchor;\n\t\t\tcontinue;\n\t\t}\n\t\tif (anchor.spokenStart > spokenOffset) {\n\t\t\tnext = anchor;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (previous && next) {\n\t\treturn {\n\t\t\tstart: Math.min(previous.visibleStart, next.visibleStart),\n\t\t\tend: Math.max(previous.visibleEnd, next.visibleEnd),\n\t\t};\n\t}\n\treturn null;\n};\n"]}
@@ -0,0 +1,33 @@
1
+ import type { MathAwareSpeechChunk } from "../math-aware-text-processing.js";
2
+ import { type ResolvedMathSpeech, type SREMathSpeechOptions } from "../math-speech.js";
3
+ import type { AssembledSpeech } from "./types.js";
4
+ type MathChunk = Extract<MathAwareSpeechChunk, {
5
+ type: "math";
6
+ }>;
7
+ /**
8
+ * Resolves spoken text for a single math chunk. Injectable so the runtime can
9
+ * supply a memoized resolver (deterministic caching) and tests can stub SRE.
10
+ * Mirrors `resolveMathSpeechFromChunks([chunk], options)`.
11
+ */
12
+ export type MathSpeechResolver = (chunk: MathChunk, options: {
13
+ language?: string;
14
+ produceSsml?: boolean;
15
+ mathSpeech?: SREMathSpeechOptions;
16
+ }) => Promise<ResolvedMathSpeech>;
17
+ /**
18
+ * Assemble an anchor-free speech plan from already-collected math-aware chunks.
19
+ *
20
+ * PURE: no DOM walking, no app-service imports. Preserves the spoken-text and
21
+ * visible-span bookkeeping from the inline generated path, so the runtime output
22
+ * is stable once serialized to plain text.
23
+ */
24
+ export declare const assembleGeneratedSpeech: (args: {
25
+ chunks: ReadonlyArray<MathAwareSpeechChunk>;
26
+ visibleText: string;
27
+ language?: string;
28
+ mathSpeech?: SREMathSpeechOptions;
29
+ /** Request SRE SSML per math equation (used by the SSML playback format). */
30
+ produceSsml?: boolean;
31
+ resolveMathSpeech?: MathSpeechResolver;
32
+ }) => Promise<AssembledSpeech>;
33
+ export {};
@@ -0,0 +1,111 @@
1
+ import { resolveMathSpeechFromChunks, } from "../math-speech.js";
2
+ import { normalizeTextForSpeech } from "../text-processing.js";
3
+ import { segmentSentences as segmentTextToSentences } from "../text-segmentation.js";
4
+ const defaultMathSpeechResolver = (chunk, options) => resolveMathSpeechFromChunks([chunk], options);
5
+ const normalizeLocale = (language) => (language || "en").split("-")[0].toLowerCase() || "en";
6
+ const PRESERVE_PROSE_CHUNK_TAGS = new Set([
7
+ "H1",
8
+ "H2",
9
+ "H3",
10
+ "H4",
11
+ "H5",
12
+ "H6",
13
+ "LI",
14
+ "LABEL",
15
+ "BUTTON",
16
+ ]);
17
+ const PRESERVE_PROSE_CHUNK_ROLES = new Set([
18
+ "heading",
19
+ "listitem",
20
+ "option",
21
+ "radio",
22
+ ]);
23
+ const shouldPreserveProseChunk = (chunk) => {
24
+ if (chunk.type !== "text" || !chunk.sourceElement)
25
+ return false;
26
+ const tagName = chunk.sourceElement.tagName.toUpperCase();
27
+ const role = (chunk.sourceElement.getAttribute("role") || "").toLowerCase();
28
+ return (PRESERVE_PROSE_CHUNK_TAGS.has(tagName) ||
29
+ PRESERVE_PROSE_CHUNK_ROLES.has(role));
30
+ };
31
+ /**
32
+ * Assemble an anchor-free speech plan from already-collected math-aware chunks.
33
+ *
34
+ * PURE: no DOM walking, no app-service imports. Preserves the spoken-text and
35
+ * visible-span bookkeeping from the inline generated path, so the runtime output
36
+ * is stable once serialized to plain text.
37
+ */
38
+ export const assembleGeneratedSpeech = async (args) => {
39
+ const resolveMathSpeech = args.resolveMathSpeech ?? defaultMathSpeechResolver;
40
+ const { visibleText } = args;
41
+ const segments = [];
42
+ // Cursor-based span tracking:
43
+ // locate each chunk's normalized text within the aggregate visible text,
44
+ // advancing a cursor so math fallbacks reserve their span even though only
45
+ // prose spans are sliced for highlighting.
46
+ let visibleCursor = 0;
47
+ const nextVisibleSpan = (text) => {
48
+ const normalized = normalizeTextForSpeech(text);
49
+ const found = visibleText.indexOf(normalized, visibleCursor);
50
+ const start = found >= 0 ? found : visibleCursor;
51
+ const end = start + normalized.length;
52
+ visibleCursor = end;
53
+ return { start, end };
54
+ };
55
+ const speechParts = [];
56
+ for (let index = 0; index < args.chunks.length; index++) {
57
+ const chunk = args.chunks[index];
58
+ if (chunk.type === "text") {
59
+ const proseSegments = shouldPreserveProseChunk(chunk)
60
+ ? [{ text: chunk.text, offset: 0 }]
61
+ : segmentTextToSentences(chunk.text, {
62
+ locale: args.language,
63
+ });
64
+ for (const prose of proseSegments) {
65
+ const text = normalizeTextForSpeech(prose.text);
66
+ if (!text)
67
+ continue;
68
+ const visibleSpan = nextVisibleSpan(text);
69
+ segments.push({
70
+ sourceChunkIndex: index,
71
+ segment: {
72
+ kind: "prose",
73
+ spokenText: text,
74
+ visibleText: text,
75
+ visibleSpan,
76
+ },
77
+ });
78
+ speechParts.push(text);
79
+ }
80
+ continue;
81
+ }
82
+ const visibleSpan = nextVisibleSpan(chunk.fallbackText);
83
+ const generated = await resolveMathSpeech(chunk, {
84
+ language: args.language,
85
+ produceSsml: args.produceSsml,
86
+ mathSpeech: args.mathSpeech,
87
+ });
88
+ const usedFallback = !generated.speechText;
89
+ const spokenText = generated.speechText || chunk.fallbackText;
90
+ segments.push({
91
+ sourceChunkIndex: index,
92
+ segment: {
93
+ kind: "math",
94
+ spokenText,
95
+ mathml: chunk.mathml,
96
+ fallbackText: chunk.fallbackText,
97
+ visibleSpan,
98
+ usedFallback,
99
+ ssml: generated.ssml,
100
+ },
101
+ });
102
+ speechParts.push(spokenText);
103
+ }
104
+ return {
105
+ segments,
106
+ locale: normalizeLocale(args.language),
107
+ visibleText,
108
+ plainSpeechText: normalizeTextForSpeech(speechParts.join(" ")),
109
+ };
110
+ };
111
+ //# sourceMappingURL=assemble-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble-plan.js","sourceRoot":"","sources":["../../../../src/services/tts/generated-speech/assemble-plan.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MathAwareSpeechChunk } from \"../math-aware-text-processing.js\";\nimport {\n\tresolveMathSpeechFromChunks,\n\ttype ResolvedMathSpeech,\n\ttype SREMathSpeechOptions,\n} from \"../math-speech.js\";\nimport { normalizeTextForSpeech } from \"../text-processing.js\";\nimport { segmentSentences as segmentTextToSentences } from \"../text-segmentation.js\";\nimport type { AssembledSegment, AssembledSpeech } from \"./types.js\";\n\ntype MathChunk = Extract<MathAwareSpeechChunk, { type: \"math\" }>;\n\n/**\n * Resolves spoken text for a single math chunk. Injectable so the runtime can\n * supply a memoized resolver (deterministic caching) and tests can stub SRE.\n * Mirrors `resolveMathSpeechFromChunks([chunk], options)`.\n */\nexport type MathSpeechResolver = (\n\tchunk: MathChunk,\n\toptions: {\n\t\tlanguage?: string;\n\t\tproduceSsml?: boolean;\n\t\tmathSpeech?: SREMathSpeechOptions;\n\t},\n) => Promise<ResolvedMathSpeech>;\n\nconst defaultMathSpeechResolver: MathSpeechResolver = (chunk, options) =>\n\tresolveMathSpeechFromChunks([chunk], options);\n\nconst normalizeLocale = (language?: string): string =>\n\t(language || \"en\").split(\"-\")[0].toLowerCase() || \"en\";\n\nconst PRESERVE_PROSE_CHUNK_TAGS = new Set([\n\t\"H1\",\n\t\"H2\",\n\t\"H3\",\n\t\"H4\",\n\t\"H5\",\n\t\"H6\",\n\t\"LI\",\n\t\"LABEL\",\n\t\"BUTTON\",\n]);\n\nconst PRESERVE_PROSE_CHUNK_ROLES = new Set([\n\t\"heading\",\n\t\"listitem\",\n\t\"option\",\n\t\"radio\",\n]);\n\nconst shouldPreserveProseChunk = (\n\tchunk: MathAwareSpeechChunk,\n): boolean => {\n\tif (chunk.type !== \"text\" || !chunk.sourceElement) return false;\n\tconst tagName = chunk.sourceElement.tagName.toUpperCase();\n\tconst role = (chunk.sourceElement.getAttribute(\"role\") || \"\").toLowerCase();\n\treturn (\n\t\tPRESERVE_PROSE_CHUNK_TAGS.has(tagName) ||\n\t\tPRESERVE_PROSE_CHUNK_ROLES.has(role)\n\t);\n};\n\n/**\n * Assemble an anchor-free speech plan from already-collected math-aware chunks.\n *\n * PURE: no DOM walking, no app-service imports. Preserves the spoken-text and\n * visible-span bookkeeping from the inline generated path, so the runtime output\n * is stable once serialized to plain text.\n */\nexport const assembleGeneratedSpeech = async (args: {\n\tchunks: ReadonlyArray<MathAwareSpeechChunk>;\n\tvisibleText: string;\n\tlanguage?: string;\n\tmathSpeech?: SREMathSpeechOptions;\n\t/** Request SRE SSML per math equation (used by the SSML playback format). */\n\tproduceSsml?: boolean;\n\tresolveMathSpeech?: MathSpeechResolver;\n}): Promise<AssembledSpeech> => {\n\tconst resolveMathSpeech = args.resolveMathSpeech ?? defaultMathSpeechResolver;\n\tconst { visibleText } = args;\n\tconst segments: AssembledSegment[] = [];\n\n\t// Cursor-based span tracking:\n\t// locate each chunk's normalized text within the aggregate visible text,\n\t// advancing a cursor so math fallbacks reserve their span even though only\n\t// prose spans are sliced for highlighting.\n\tlet visibleCursor = 0;\n\tconst nextVisibleSpan = (text: string): { start: number; end: number } => {\n\t\tconst normalized = normalizeTextForSpeech(text);\n\t\tconst found = visibleText.indexOf(normalized, visibleCursor);\n\t\tconst start = found >= 0 ? found : visibleCursor;\n\t\tconst end = start + normalized.length;\n\t\tvisibleCursor = end;\n\t\treturn { start, end };\n\t};\n\n\tconst speechParts: string[] = [];\n\n\tfor (let index = 0; index < args.chunks.length; index++) {\n\t\tconst chunk = args.chunks[index];\n\t\tif (chunk.type === \"text\") {\n\t\t\tconst proseSegments = shouldPreserveProseChunk(chunk)\n\t\t\t\t? [{ text: chunk.text, offset: 0 }]\n\t\t\t\t: segmentTextToSentences(chunk.text, {\n\t\t\t\t\t\tlocale: args.language,\n\t\t\t\t\t});\n\t\t\tfor (const prose of proseSegments) {\n\t\t\t\tconst text = normalizeTextForSpeech(prose.text);\n\t\t\t\tif (!text) continue;\n\t\t\t\tconst visibleSpan = nextVisibleSpan(text);\n\t\t\t\tsegments.push({\n\t\t\t\t\tsourceChunkIndex: index,\n\t\t\t\t\tsegment: {\n\t\t\t\t\t\tkind: \"prose\",\n\t\t\t\t\t\tspokenText: text,\n\t\t\t\t\t\tvisibleText: text,\n\t\t\t\t\t\tvisibleSpan,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tspeechParts.push(text);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst visibleSpan = nextVisibleSpan(chunk.fallbackText);\n\t\tconst generated = await resolveMathSpeech(chunk, {\n\t\t\tlanguage: args.language,\n\t\t\tproduceSsml: args.produceSsml,\n\t\t\tmathSpeech: args.mathSpeech,\n\t\t});\n\t\tconst usedFallback = !generated.speechText;\n\t\tconst spokenText = generated.speechText || chunk.fallbackText;\n\t\tsegments.push({\n\t\t\tsourceChunkIndex: index,\n\t\t\tsegment: {\n\t\t\t\tkind: \"math\",\n\t\t\t\tspokenText,\n\t\t\t\tmathml: chunk.mathml,\n\t\t\t\tfallbackText: chunk.fallbackText,\n\t\t\t\tvisibleSpan,\n\t\t\t\tusedFallback,\n\t\t\t\tssml: generated.ssml,\n\t\t\t},\n\t\t});\n\t\tspeechParts.push(spokenText);\n\t}\n\n\treturn {\n\t\tsegments,\n\t\tlocale: normalizeLocale(args.language),\n\t\tvisibleText,\n\t\tplainSpeechText: normalizeTextForSpeech(speechParts.join(\" \")),\n\t};\n};\n"]}
@@ -0,0 +1,25 @@
1
+ import type { TextProcessingOptions } from "../../text-processing.js";
2
+ import { type MathSpeechResolver } from "../assemble-plan.js";
3
+ import type { SREMathSpeechOptions } from "../../math-speech.js";
4
+ import type { GeneratedSpeechPlan } from "../types.js";
5
+ import type { DomAnchor } from "./types.js";
6
+ export interface BuildGeneratedSpeechResult {
7
+ plan: GeneratedSpeechPlan<DomAnchor>;
8
+ containsMathMarkup: boolean;
9
+ /** Aggregate visible text from the DOM walk (may be empty). */
10
+ visibleText: string;
11
+ }
12
+ /**
13
+ * DOM adapter: walk a live content root, assemble the (pure) speech plan, and
14
+ * bind each segment to its live-DOM anchor. This is the only generated-speech
15
+ * entry point that touches the DOM; assembly and serialization stay pure.
16
+ */
17
+ export declare const buildGeneratedSpeechFromRoot: (args: {
18
+ contentRoot: Element;
19
+ language?: string;
20
+ mathSpeech?: SREMathSpeechOptions;
21
+ textProcessingOptions?: TextProcessingOptions;
22
+ /** Request SRE SSML per equation (for the SSML playback format). */
23
+ produceSsml?: boolean;
24
+ resolveMathSpeech?: MathSpeechResolver;
25
+ }) => Promise<BuildGeneratedSpeechResult>;
@@ -0,0 +1,66 @@
1
+ import { resolveReadableRegion } from "../../highlight-pipeline/index.js";
2
+ import { collectMathAwareTextAndMap } from "../../math-aware-text-processing.js";
3
+ import { assembleGeneratedSpeech, } from "../assemble-plan.js";
4
+ const sliceVisibleMap = (map, start, end) => {
5
+ const sliced = new Map();
6
+ for (let index = start; index < end; index++) {
7
+ const mapping = map.get(index);
8
+ if (mapping) {
9
+ sliced.set(index - start, mapping);
10
+ }
11
+ }
12
+ return sliced;
13
+ };
14
+ /**
15
+ * DOM adapter: walk a live content root, assemble the (pure) speech plan, and
16
+ * bind each segment to its live-DOM anchor. This is the only generated-speech
17
+ * entry point that touches the DOM; assembly and serialization stay pure.
18
+ */
19
+ export const buildGeneratedSpeechFromRoot = async (args) => {
20
+ const extracted = collectMathAwareTextAndMap(args.contentRoot, args.textProcessingOptions);
21
+ const assembled = await assembleGeneratedSpeech({
22
+ chunks: extracted.chunks,
23
+ visibleText: extracted.visibleText,
24
+ language: args.language,
25
+ mathSpeech: args.mathSpeech,
26
+ produceSsml: args.produceSsml,
27
+ resolveMathSpeech: args.resolveMathSpeech,
28
+ });
29
+ const items = assembled.segments.map(({ segment, sourceChunkIndex }) => {
30
+ const sourceChunk = extracted.chunks[sourceChunkIndex];
31
+ if (segment.kind === "prose") {
32
+ const sourceElement = sourceChunk?.type === "text"
33
+ ? (sourceChunk.sourceElement ?? args.contentRoot)
34
+ : args.contentRoot;
35
+ return {
36
+ segment,
37
+ anchor: {
38
+ sourceElement,
39
+ regionElement: resolveReadableRegion(sourceElement, args.contentRoot),
40
+ visibleMap: sliceVisibleMap(extracted.map, segment.visibleSpan.start, segment.visibleSpan.end),
41
+ },
42
+ };
43
+ }
44
+ const mathElement = sourceChunk?.type === "math"
45
+ ? (sourceChunk.sourceElement ?? null)
46
+ : null;
47
+ return {
48
+ segment,
49
+ anchor: {
50
+ sourceElement: mathElement,
51
+ regionElement: mathElement,
52
+ },
53
+ };
54
+ });
55
+ return {
56
+ plan: {
57
+ items,
58
+ locale: assembled.locale,
59
+ visibleText: assembled.visibleText,
60
+ plainSpeechText: assembled.plainSpeechText,
61
+ },
62
+ containsMathMarkup: extracted.containsMathMarkup,
63
+ visibleText: extracted.visibleText,
64
+ };
65
+ };
66
+ //# sourceMappingURL=build-dom-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-dom-plan.js","sourceRoot":"","sources":["../../../../../src/services/tts/generated-speech/dom/build-dom-plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAKjF,OAAO,EACN,uBAAuB,GAEvB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,eAAe,GAAG,CACvB,GAAsB,EACtB,KAAa,EACb,GAAW,EACS,EAAE;IACtB,MAAM,MAAM,GAAsB,IAAI,GAAG,EAAE,CAAC;IAC5C,KAAK,IAAI,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC;QACpC,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AASF;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,EAAE,IAQlD,EAAuC,EAAE;IACzC,MAAM,SAAS,GAAG,0BAA0B,CAC3C,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,qBAAqB,CAC1B,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,uBAAuB,CAAC;QAC/C,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,WAAW,EAAE,SAAS,CAAC,WAAW;QAClC,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;KACzC,CAAC,CAAC;IAEH,MAAM,KAAK,GAA0B,SAAS,CAAC,QAAQ,CAAC,GAAG,CAC1D,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE;QACjC,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACvD,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC9B,MAAM,aAAa,GAClB,WAAW,EAAE,IAAI,KAAK,MAAM;gBAC3B,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,IAAI,IAAI,CAAC,WAAW,CAAC;gBACjD,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,MAAM,EAAE;oBACP,aAAa;oBACb,aAAa,EAAE,qBAAqB,CACnC,aAAa,EACb,IAAI,CAAC,WAAW,CAChB;oBACD,UAAU,EAAE,eAAe,CAC1B,SAAS,CAAC,GAAG,EACb,OAAO,CAAC,WAAW,CAAC,KAAK,EACzB,OAAO,CAAC,WAAW,CAAC,GAAG,CACvB;iBACD;aACD,CAAC;QACH,CAAC;QACD,MAAM,WAAW,GAChB,WAAW,EAAE,IAAI,KAAK,MAAM;YAC3B,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,IAAI,IAAI,CAAC;YACrC,CAAC,CAAC,IAAI,CAAC;QACT,OAAO;YACN,OAAO;YACP,MAAM,EAAE;gBACP,aAAa,EAAE,WAAW;gBAC1B,aAAa,EAAE,WAAW;aAC1B;SACD,CAAC;IACH,CAAC,CACD,CAAC;IAEF,OAAO;QACN,IAAI,EAAE;YACL,KAAK;YACL,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,eAAe,EAAE,SAAS,CAAC,eAAe;SAC1C;QACD,kBAAkB,EAAE,SAAS,CAAC,kBAAkB;QAChD,WAAW,EAAE,SAAS,CAAC,WAAW;KAClC,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { resolveReadableRegion } from \"../../highlight-pipeline/index.js\";\nimport { collectMathAwareTextAndMap } from \"../../math-aware-text-processing.js\";\nimport type {\n\tNormalizedTextMap,\n\tTextProcessingOptions,\n} from \"../../text-processing.js\";\nimport {\n\tassembleGeneratedSpeech,\n\ttype MathSpeechResolver,\n} from \"../assemble-plan.js\";\nimport type { SREMathSpeechOptions } from \"../../math-speech.js\";\nimport type { GeneratedSpeechPlan, PlanItem } from \"../types.js\";\nimport type { DomAnchor } from \"./types.js\";\n\nconst sliceVisibleMap = (\n\tmap: NormalizedTextMap,\n\tstart: number,\n\tend: number,\n): NormalizedTextMap => {\n\tconst sliced: NormalizedTextMap = new Map();\n\tfor (let index = start; index < end; index++) {\n\t\tconst mapping = map.get(index);\n\t\tif (mapping) {\n\t\t\tsliced.set(index - start, mapping);\n\t\t}\n\t}\n\treturn sliced;\n};\n\nexport interface BuildGeneratedSpeechResult {\n\tplan: GeneratedSpeechPlan<DomAnchor>;\n\tcontainsMathMarkup: boolean;\n\t/** Aggregate visible text from the DOM walk (may be empty). */\n\tvisibleText: string;\n}\n\n/**\n * DOM adapter: walk a live content root, assemble the (pure) speech plan, and\n * bind each segment to its live-DOM anchor. This is the only generated-speech\n * entry point that touches the DOM; assembly and serialization stay pure.\n */\nexport const buildGeneratedSpeechFromRoot = async (args: {\n\tcontentRoot: Element;\n\tlanguage?: string;\n\tmathSpeech?: SREMathSpeechOptions;\n\ttextProcessingOptions?: TextProcessingOptions;\n\t/** Request SRE SSML per equation (for the SSML playback format). */\n\tproduceSsml?: boolean;\n\tresolveMathSpeech?: MathSpeechResolver;\n}): Promise<BuildGeneratedSpeechResult> => {\n\tconst extracted = collectMathAwareTextAndMap(\n\t\targs.contentRoot,\n\t\targs.textProcessingOptions,\n\t);\n\tconst assembled = await assembleGeneratedSpeech({\n\t\tchunks: extracted.chunks,\n\t\tvisibleText: extracted.visibleText,\n\t\tlanguage: args.language,\n\t\tmathSpeech: args.mathSpeech,\n\t\tproduceSsml: args.produceSsml,\n\t\tresolveMathSpeech: args.resolveMathSpeech,\n\t});\n\n\tconst items: PlanItem<DomAnchor>[] = assembled.segments.map(\n\t\t({ segment, sourceChunkIndex }) => {\n\t\t\tconst sourceChunk = extracted.chunks[sourceChunkIndex];\n\t\t\tif (segment.kind === \"prose\") {\n\t\t\t\tconst sourceElement =\n\t\t\t\t\tsourceChunk?.type === \"text\"\n\t\t\t\t\t\t? (sourceChunk.sourceElement ?? args.contentRoot)\n\t\t\t\t\t\t: args.contentRoot;\n\t\t\t\treturn {\n\t\t\t\t\tsegment,\n\t\t\t\t\tanchor: {\n\t\t\t\t\t\tsourceElement,\n\t\t\t\t\t\tregionElement: resolveReadableRegion(\n\t\t\t\t\t\t\tsourceElement,\n\t\t\t\t\t\t\targs.contentRoot,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tvisibleMap: sliceVisibleMap(\n\t\t\t\t\t\t\textracted.map,\n\t\t\t\t\t\t\tsegment.visibleSpan.start,\n\t\t\t\t\t\t\tsegment.visibleSpan.end,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst mathElement =\n\t\t\t\tsourceChunk?.type === \"math\"\n\t\t\t\t\t? (sourceChunk.sourceElement ?? null)\n\t\t\t\t\t: null;\n\t\t\treturn {\n\t\t\t\tsegment,\n\t\t\t\tanchor: {\n\t\t\t\t\tsourceElement: mathElement,\n\t\t\t\t\tregionElement: mathElement,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t);\n\n\treturn {\n\t\tplan: {\n\t\t\titems,\n\t\t\tlocale: assembled.locale,\n\t\t\tvisibleText: assembled.visibleText,\n\t\t\tplainSpeechText: assembled.plainSpeechText,\n\t\t},\n\t\tcontainsMathMarkup: extracted.containsMathMarkup,\n\t\tvisibleText: extracted.visibleText,\n\t};\n};\n"]}
@@ -0,0 +1,19 @@
1
+ import type { GeneratedSpeechPlan } from "../types.js";
2
+ import type { DomAnchor, GeneratedSpeechChunk } from "./types.js";
3
+ export interface PlanToChunksOptions {
4
+ /**
5
+ * Playback format:
6
+ * - "plain" (default): plain spoken text for every chunk (Phase A, the
7
+ * stable generated-speech behavior).
8
+ * - "ssml": math chunks with SRE SSML send that SSML to the provider (with
9
+ * a plain fallback attached); prose chunks always stay plain.
10
+ */
11
+ format?: "plain" | "ssml";
12
+ }
13
+ /**
14
+ * Convert an anchored speech plan into playback chunks for
15
+ * `TTSService.speakCatalogChunk`. The aggregate `contentToSpeak` stays plain
16
+ * (see `plan.plainSpeechText`), so no SSML leaks into break-detection or seek
17
+ * planning — SSML lives only in per-chunk `speechText`.
18
+ */
19
+ export declare const planToCompositionChunkInputs: (plan: GeneratedSpeechPlan<DomAnchor>, options?: PlanToChunksOptions) => GeneratedSpeechChunk[];