@pie-players/pie-assessment-toolkit 0.3.73 → 0.3.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +469 -318
- package/dist/attempt/AssessmentSession.d.ts +1 -5
- package/dist/attempt/AssessmentSession.js +0 -29
- package/dist/attempt/TestSession.d.ts +1 -20
- package/dist/attempt/TestSession.js +8 -99
- package/dist/components/ItemScope.custom-element.d.ts +1 -0
- package/dist/components/ItemScope.custom-element.js +1 -0
- package/dist/components/ItemToolBar.custom-element.d.ts +1 -0
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.d.ts +1 -0
- package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
- package/dist/components/SectionToolBar.custom-element.d.ts +1 -0
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
- package/dist/components/chunks/ItemToolBar-97hx60z4.js +2 -0
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
- package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
- package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
- package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
- package/dist/components/item-scope-element.d.ts +2 -0
- package/dist/components/item-scope-element.js +2 -0
- package/dist/context/assessment-toolkit-context.d.ts +32 -6
- package/dist/index.d.ts +23 -48
- package/dist/index.js +12 -37
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +85 -34
- package/dist/policy/core/ToolPolicyEngine.js +148 -46
- package/dist/policy/core/compose-decision.d.ts +28 -7
- package/dist/policy/core/compose-decision.js +75 -54
- package/dist/policy/core/decision-types.d.ts +65 -34
- package/dist/policy/core/feature-decision.d.ts +16 -9
- package/dist/policy/core/feature-decision.js +14 -8
- package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
- package/dist/policy/core/pnp-policy-inputs.js +28 -56
- package/dist/policy/core/provenance.d.ts +9 -4
- package/dist/policy/core/provenance.js +1 -1
- package/dist/policy/engine.d.ts +7 -23
- package/dist/policy/engine.js +5 -20
- package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
- package/dist/policy/sources/PnpPolicySource.js +117 -118
- package/dist/runtime/SectionControllerBinding.d.ts +279 -0
- package/dist/runtime/SectionControllerBinding.js +450 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
- package/dist/runtime/SectionRuntimeEngine.js +30 -372
- package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
- package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
- package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
- package/dist/runtime/adapter/dom-event-bridge.js +17 -44
- package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
- package/dist/runtime/adapter/subscriber-fanout.js +1 -2
- package/dist/runtime/catalog-context.d.ts +19 -0
- package/dist/runtime/catalog-context.js +28 -0
- package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
- package/dist/runtime/composition-emit-scheduler.js +9 -15
- package/dist/runtime/content-language.d.ts +32 -0
- package/dist/runtime/content-language.js +46 -0
- package/dist/runtime/content-region.d.ts +17 -0
- package/dist/runtime/content-region.js +29 -0
- package/dist/runtime/content-registration.d.ts +13 -0
- package/dist/runtime/content-registration.js +25 -0
- package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
- package/dist/runtime/core/SectionEngineCore.js +2 -2
- package/dist/runtime/core/cohort.d.ts +1 -1
- package/dist/runtime/core/cohort.js +1 -1
- package/dist/runtime/core/engine-input.d.ts +18 -30
- package/dist/runtime/core/engine-input.js +11 -12
- package/dist/runtime/core/engine-output.d.ts +16 -40
- package/dist/runtime/core/engine-output.js +9 -21
- package/dist/runtime/core/engine-readiness.d.ts +5 -37
- package/dist/runtime/core/engine-readiness.js +8 -41
- package/dist/runtime/core/engine-resolver.d.ts +46 -74
- package/dist/runtime/core/engine-resolver.js +18 -43
- package/dist/runtime/core/engine-state.d.ts +28 -36
- package/dist/runtime/core/engine-state.js +18 -21
- package/dist/runtime/core/engine-transition.d.ts +14 -19
- package/dist/runtime/core/engine-transition.js +71 -51
- package/dist/runtime/engine.d.ts +16 -19
- package/dist/runtime/engine.js +12 -19
- package/dist/runtime/page-warnings.d.ts +13 -0
- package/dist/runtime/page-warnings.js +22 -0
- package/dist/runtime/policy-input-forwarding.d.ts +25 -0
- package/dist/runtime/policy-input-forwarding.js +25 -0
- package/dist/runtime/registration-events.d.ts +14 -0
- package/dist/runtime/runtime-event-claim.d.ts +8 -0
- package/dist/runtime/runtime-event-claim.js +15 -0
- package/dist/runtime/shell-event-bridge.d.ts +45 -0
- package/dist/runtime/shell-event-bridge.js +127 -0
- package/dist/runtime/shell-registration.d.ts +73 -0
- package/dist/runtime/shell-registration.js +95 -0
- package/dist/runtime/shell-scope.d.ts +68 -0
- package/dist/runtime/shell-scope.js +188 -0
- package/dist/runtime/tool-host-contract.d.ts +28 -10
- package/dist/runtime/tool-host-contract.js +31 -10
- package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
- package/dist/runtime/unclaimed-registration-watch.js +23 -0
- package/dist/services/ElementToolStateStore.d.ts +14 -10
- package/dist/services/ElementToolStateStore.js +37 -13
- package/dist/services/HighlightCoordinator.d.ts +22 -28
- package/dist/services/HighlightCoordinator.js +431 -327
- package/dist/services/RangeSerializer.d.ts +10 -1
- package/dist/services/RangeSerializer.js +87 -14
- package/dist/services/TTSService.d.ts +130 -69
- package/dist/services/TTSService.js +713 -570
- package/dist/services/ToolCoordinator.d.ts +43 -66
- package/dist/services/ToolCoordinator.js +164 -208
- package/dist/services/ToolRegistry.d.ts +78 -54
- package/dist/services/ToolRegistry.js +107 -105
- package/dist/services/ToolkitCoordinator.d.ts +261 -175
- package/dist/services/ToolkitCoordinator.js +667 -433
- package/dist/services/audio-handoff.d.ts +6 -7
- package/dist/services/audio-handoff.js +20 -14
- package/dist/services/catalog-owner.d.ts +11 -1
- package/dist/services/catalog-owner.js +25 -0
- package/dist/services/create-tools-config.d.ts +2 -2
- package/dist/services/framework-error-bus.d.ts +3 -6
- package/dist/services/framework-error-bus.js +3 -6
- package/dist/services/framework-error.d.ts +30 -8
- package/dist/services/framework-error.js +9 -7
- package/dist/services/interfaces.d.ts +158 -129
- package/dist/services/section-controller-types.d.ts +15 -0
- package/dist/services/section-session-assignment.d.ts +21 -0
- package/dist/services/section-session-assignment.js +82 -0
- package/dist/services/spoken-audio-cards.d.ts +0 -2
- package/dist/services/spoken-audio-cards.js +1 -3
- package/dist/services/tool-config-defaults.d.ts +3 -3
- package/dist/services/tool-config-defaults.js +3 -3
- package/dist/services/tool-config-validation.d.ts +14 -4
- package/dist/services/tool-config-validation.js +63 -71
- package/dist/services/tool-context.d.ts +0 -8
- package/dist/services/tool-context.js +29 -25
- package/dist/services/tool-icons.d.ts +4 -3
- package/dist/services/tool-icons.js +4 -3
- package/dist/services/tool-instance-id.d.ts +0 -1
- package/dist/services/tool-instance-id.js +0 -6
- package/dist/services/tool-providers/TTSToolProvider.d.ts +41 -80
- package/dist/services/tool-providers/TTSToolProvider.js +81 -40
- package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +32 -28
- package/dist/services/tool-providers/ToolProviderRegistry.js +121 -107
- package/dist/services/tool-providers/index.d.ts +0 -9
- package/dist/services/tool-providers/index.js +2 -4
- package/dist/services/tool-request.d.ts +27 -12
- package/dist/services/tool-request.js +24 -14
- package/dist/services/toolbar-decided-tools.d.ts +15 -0
- package/dist/services/toolbar-decided-tools.js +28 -0
- package/dist/services/tools-config-normalizer.d.ts +37 -23
- package/dist/services/tools-config-normalizer.js +2 -10
- package/dist/services/tts/browser-provider.d.ts +38 -2
- package/dist/services/tts/browser-provider.js +276 -140
- package/dist/services/tts/catalog-span-alignment.d.ts +2 -17
- package/dist/services/tts/catalog-span-alignment.js +17 -142
- package/dist/services/tts/flat-tree.d.ts +71 -0
- package/dist/services/tts/flat-tree.js +269 -0
- package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
- package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
- package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
- package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
- package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
- package/dist/services/tts/generated-speech/types.d.ts +0 -12
- package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +12 -62
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +38 -5
- package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +3 -6
- package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
- package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
- package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
- package/dist/services/tts/math-alignment/index.d.ts +0 -5
- package/dist/services/tts/math-alignment/index.js +5 -25
- package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +9 -1
- package/dist/services/tts/math-alignment/speech-tokenizer.js +38 -36
- package/dist/services/tts/math-alignment/types.d.ts +4 -2
- package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
- package/dist/services/tts/math-aware-text-processing.js +74 -18
- package/dist/services/tts/math-control-names.d.ts +21 -0
- package/dist/services/tts/math-control-names.js +142 -0
- package/dist/services/tts/math-speech.d.ts +16 -1
- package/dist/services/tts/math-speech.js +55 -19
- package/dist/services/tts/provider-options.d.ts +41 -0
- package/dist/services/tts/provider-options.js +1 -0
- package/dist/services/tts/sre-engine.d.ts +7 -0
- package/dist/services/tts/sre-engine.js +11 -0
- package/dist/services/tts/sre-locales.d.ts +14 -0
- package/dist/services/tts/sre-locales.js +57 -0
- package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
- package/dist/services/tts/ssml/spoken-text.js +29 -0
- package/dist/services/tts/start-failure.d.ts +11 -0
- package/dist/services/tts/start-failure.js +19 -0
- package/dist/services/tts/text-processing.d.ts +9 -1
- package/dist/services/tts/text-processing.js +46 -34
- package/dist/services/tts/text-segmentation.d.ts +7 -0
- package/dist/services/tts/text-segmentation.js +47 -0
- package/dist/services/tts-runtime-config.d.ts +44 -18
- package/dist/services/tts-runtime-config.js +22 -93
- package/dist/tools/content-capability-resolution.d.ts +7 -9
- package/dist/tools/content-capability-resolution.js +8 -45
- package/dist/tools/registration.d.ts +58 -0
- package/dist/tools/registration.js +54 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
- package/dist/tools/tool-surface-host.d.ts +6 -10
- package/dist/tools/tool-surface-host.js +44 -42
- package/dist/tools/tool-tag-map.d.ts +5 -15
- package/dist/tools/tool-tag-map.js +6 -20
- package/dist/utils/structural-equality.d.ts +11 -0
- package/dist/utils/structural-equality.js +47 -0
- package/package.json +24 -59
- package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
- package/dist/components/chunks/ItemToolBar-byq80z42.js +0 -40
- package/dist/components/chunks/ItemToolBar-d36g3aw4.js +0 -49
- package/dist/context/runtime-context-consumer.d.ts +0 -13
- package/dist/context/runtime-context-consumer.js +0 -51
- package/dist/item-loader.d.ts +0 -44
- package/dist/item-loader.js +0 -61
- package/dist/policy/core/engine-context.d.ts +0 -29
- package/dist/policy/core/engine-context.js +0 -27
- package/dist/policy/core/policy-source-tag.d.ts +0 -31
- package/dist/policy/core/policy-source-tag.js +0 -28
- package/dist/policy/internal.d.ts +0 -25
- package/dist/policy/internal.js +0 -25
- package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
- package/dist/runtime/adapter/coordinator-bridge.js +0 -126
- package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
- package/dist/runtime/adapter/framework-error-bridge.js +0 -46
- package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
- package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
- package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
- package/dist/runtime/core/engine-stage-derivation.js +0 -29
- package/dist/runtime/engine-context.d.ts +0 -39
- package/dist/runtime/engine-context.js +0 -31
- package/dist/runtime/internal.d.ts +0 -43
- package/dist/runtime/internal.js +0 -45
- package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -80
- package/dist/runtime/section-runtime-engine-host-context.js +0 -95
- package/dist/runtime/stage-emit-gate.d.ts +0 -92
- package/dist/runtime/stage-emit-gate.js +0 -82
- package/dist/services/I18nService.d.ts +0 -47
- package/dist/services/I18nService.js +0 -84
- package/dist/services/ThemeProvider.d.ts +0 -95
- package/dist/services/ThemeProvider.js +0 -334
- package/dist/services/ToolConfigResolver.d.ts +0 -161
- package/dist/services/ToolConfigResolver.js +0 -229
- package/dist/services/catalog-media.d.ts +0 -56
- package/dist/services/catalog-media.js +0 -190
- package/dist/services/createDefaultToolRegistry.d.ts +0 -53
- package/dist/services/createDefaultToolRegistry.js +0 -45
- package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
- package/dist/services/defaultPersonalNeedsProfile.js +0 -26
- package/dist/services/pnp-standard-features.d.ts +0 -238
- package/dist/services/pnp-standard-features.js +0 -338
- package/dist/services/tool-providers/CortexToolProvider.d.ts +0 -13
- package/dist/services/tool-providers/CortexToolProvider.js +0 -32
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -14
- package/dist/services/tool-providers/DesmosToolProvider.js +0 -32
- package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +0 -16
- package/dist/services/tool-providers/GeoGebraToolProvider.js +0 -32
- package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +0 -35
- package/dist/services/tool-providers/LazyCalculatorToolProvider.js +0 -95
- package/dist/services/tts/visual-line-ranges.d.ts +0 -18
- package/dist/services/tts/visual-line-ranges.js +0 -226
- package/dist/tools/client.d.ts +0 -12
- package/dist/tools/client.js +0 -14
- package/dist/tools/index.d.ts +0 -8
- package/dist/tools/index.js +0 -10
- package/dist/tools/internal.d.ts +0 -43
- package/dist/tools/internal.js +0 -41
- package/dist/tools/response-discovery.d.ts +0 -61
- package/dist/tools/response-discovery.js +0 -113
- package/dist/tools/types.d.ts +0 -337
- package/dist/tools/types.js +0 -12
- package/dist/tools/variant-resolver.d.ts +0 -41
- package/dist/tools/variant-resolver.js +0 -207
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Strips SSML markup to the words a TTS engine would actually voice, while
|
|
5
|
-
* recording a `rawToSpokenOffsetMap` from raw-SSML character offsets to
|
|
6
|
-
* normalized spoken-text offsets. This is the single source of truth for SSML
|
|
7
|
-
* stripping used by:
|
|
8
|
-
* - the catalog span aligner (`catalog-span-alignment.ts`),
|
|
9
|
-
* - the math speech tokenizer (`math-alignment/speech-tokenizer.ts`),
|
|
10
|
-
* - the runtime generated-speech path (PIE-623).
|
|
11
|
-
*
|
|
12
|
-
* Keeping one implementation guarantees provider word-boundary offsets (which
|
|
13
|
-
* are into the raw SSML string) map to the same spoken text on every path.
|
|
14
|
-
*
|
|
15
|
-
* Tag handling:
|
|
16
|
-
* - Structural tags (`speak`, `p`, `s`, `emphasis`, `prosody`, `say-as`,
|
|
17
|
-
* `voice`, `lang`) are transparent; their text content flows through.
|
|
18
|
-
* `p`/`s` open tags inject a word boundary space.
|
|
19
|
-
* - `break` injects a space (a pause is a word boundary).
|
|
20
|
-
* - `sub alias="…"` substitutes the alias text (and skips the original).
|
|
21
|
-
* `sub` with no alias marks the content unsupported for word tracking.
|
|
22
|
-
* - Semantic tags that change *what* is spoken without leaving trackable
|
|
23
|
-
* text (`audio`, `phoneme`) mark the content unsupported.
|
|
24
|
-
* - Any other unknown element marks the content unsupported (degrade to
|
|
25
|
-
* coarse region highlighting rather than mis-track).
|
|
26
|
-
*/
|
|
1
|
+
/** Whether `text` is an SSML document: it opens with a `<speak>` element. */
|
|
2
|
+
export declare const isSsmlDocument: (text: string) => boolean;
|
|
27
3
|
export interface ExtractedSpokenText {
|
|
28
4
|
spokenText: string;
|
|
29
5
|
rawToSpokenOffsetMap: Map<number, number>;
|
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
import { normalizeTextForSpeech } from "../text-processing.js";
|
|
2
|
+
/**
|
|
3
|
+
* Shared SSML → spoken-text extractor.
|
|
4
|
+
*
|
|
5
|
+
* Strips SSML markup to the words a TTS engine would actually voice, while
|
|
6
|
+
* recording a `rawToSpokenOffsetMap` from raw-SSML character offsets to
|
|
7
|
+
* normalized spoken-text offsets. This is the single source of truth for SSML
|
|
8
|
+
* stripping used by:
|
|
9
|
+
* - the catalog span aligner (`catalog-span-alignment.ts`),
|
|
10
|
+
* - the math speech tokenizer (`math-alignment/speech-tokenizer.ts`),
|
|
11
|
+
* - the runtime generated-speech path (PIE-623).
|
|
12
|
+
*
|
|
13
|
+
* Keeping one implementation guarantees provider word-boundary offsets (which
|
|
14
|
+
* are into the raw SSML string) map to the same spoken text on every path.
|
|
15
|
+
*
|
|
16
|
+
* Tag handling:
|
|
17
|
+
* - Structural tags (`speak`, `p`, `s`, `emphasis`, `prosody`, `say-as`,
|
|
18
|
+
* `voice`, `lang`) are transparent; their text content flows through.
|
|
19
|
+
* `p`/`s` open tags inject a word boundary space.
|
|
20
|
+
* - `break` injects a space (a pause is a word boundary).
|
|
21
|
+
* - `sub alias="…"` substitutes the alias text (and skips the original).
|
|
22
|
+
* `sub` with no alias marks the content unsupported for word tracking.
|
|
23
|
+
* - Semantic tags that change *what* is spoken without leaving trackable
|
|
24
|
+
* text (`audio`, `phoneme`) mark the content unsupported.
|
|
25
|
+
* - Any other unknown element marks the content unsupported (degrade to
|
|
26
|
+
* coarse region highlighting rather than mis-track).
|
|
27
|
+
*/
|
|
28
|
+
const SSML_DOCUMENT = /^\s*<speak[\s/>]/i;
|
|
29
|
+
/** Whether `text` is an SSML document: it opens with a `<speak>` element. */
|
|
30
|
+
export const isSsmlDocument = (text) => SSML_DOCUMENT.test(text);
|
|
2
31
|
const STRUCTURAL_SSML_TAGS = new Set([
|
|
3
32
|
"speak",
|
|
4
33
|
"p",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `code` a speak's rejection carries when speech could not start, as
|
|
3
|
+
* distinct from a failure while speaking. Read by shape: several copies of the
|
|
4
|
+
* toolkit can share a page, so an error class from one fails `instanceof` in
|
|
5
|
+
* another.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TTS_START_FAILED_CODE = "tts-start-failed";
|
|
8
|
+
/** Whether a speak rejected because speech could not start. */
|
|
9
|
+
export declare function isTTSStartFailure(error: unknown): boolean;
|
|
10
|
+
/** Marks `cause` as a start failure, keeping its message and stack. */
|
|
11
|
+
export declare function toTTSStartFailure(cause: unknown): Error;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `code` a speak's rejection carries when speech could not start, as
|
|
3
|
+
* distinct from a failure while speaking. Read by shape: several copies of the
|
|
4
|
+
* toolkit can share a page, so an error class from one fails `instanceof` in
|
|
5
|
+
* another.
|
|
6
|
+
*/
|
|
7
|
+
export const TTS_START_FAILED_CODE = "tts-start-failed";
|
|
8
|
+
/** Whether a speak rejected because speech could not start. */
|
|
9
|
+
export function isTTSStartFailure(error) {
|
|
10
|
+
return (typeof error === "object" &&
|
|
11
|
+
error !== null &&
|
|
12
|
+
error.code === TTS_START_FAILED_CODE);
|
|
13
|
+
}
|
|
14
|
+
/** Marks `cause` as a start failure, keeping its message and stack. */
|
|
15
|
+
export function toTTSStartFailure(cause) {
|
|
16
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
17
|
+
error.code = TTS_START_FAILED_CODE;
|
|
18
|
+
return error;
|
|
19
|
+
}
|
|
@@ -62,9 +62,17 @@ export declare const collectRangeTextForSpeech: (range: Range, root: Element) =>
|
|
|
62
62
|
text: string;
|
|
63
63
|
filtered: boolean;
|
|
64
64
|
};
|
|
65
|
+
/** The part of `textNode`'s text that `range` holds, for a node it intersects. */
|
|
66
|
+
export declare const textInRange: (textNode: Text, range: Range) => string;
|
|
67
|
+
/**
|
|
68
|
+
* Whether `range` holds all of `element`'s speakable text: its first and last
|
|
69
|
+
* speakable characters, which a contiguous range holding both holds everything
|
|
70
|
+
* between. An element with no speakable text, an image for one, is held when the
|
|
71
|
+
* range touches it, since no part of it can be selected alone.
|
|
72
|
+
*/
|
|
73
|
+
export declare const rangeHoldsSpeakableElement: (range: Range, element: Element, root?: Element | null) => boolean;
|
|
65
74
|
export declare const shouldInsertWordBoundarySpace: (previousChar: string | null, nextChar: string | null, options?: TextProcessingOptions) => boolean;
|
|
66
75
|
export declare const collectVisibleTextAndMap: (element: Element, options?: TextProcessingOptions) => {
|
|
67
76
|
text: string;
|
|
68
77
|
map: NormalizedTextMap;
|
|
69
78
|
};
|
|
70
|
-
export declare const extractVisibleText: (element: Element, options?: TextProcessingOptions) => string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { flatTreeParentElement, flatTreeTextNodes, rangeHoldsTextPosition, rangeIntersectsComposedNode, } from "./flat-tree.js";
|
|
1
2
|
export const normalizeTextForSpeech = (text) => text.trim().replace(/\s+/g, " ");
|
|
2
3
|
// Single source of truth for aligning spoken text to visible / math text.
|
|
3
4
|
// Letters are matched with `\p{L}` so the tokenizer is Unicode-aware — accented
|
|
@@ -50,15 +51,15 @@ export const isElementHiddenForTTS = (element) => {
|
|
|
50
51
|
return false;
|
|
51
52
|
};
|
|
52
53
|
export const isNodeHiddenForTTS = (node, root) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// Up the flat tree, so a node in a shadow root inherits its host's
|
|
55
|
+
// visibility and a slotted node the visibility of the slot rendering it.
|
|
56
|
+
let current = node.nodeType === 1 ? node : flatTreeParentElement(node);
|
|
56
57
|
while (current) {
|
|
57
58
|
if (isElementHiddenForTTS(current))
|
|
58
59
|
return true;
|
|
59
60
|
if (root && current === root)
|
|
60
61
|
break;
|
|
61
|
-
current = current
|
|
62
|
+
current = flatTreeParentElement(current);
|
|
62
63
|
}
|
|
63
64
|
return false;
|
|
64
65
|
};
|
|
@@ -112,15 +113,14 @@ export const isElementSuppressedForTTS = (element) => {
|
|
|
112
113
|
return true;
|
|
113
114
|
};
|
|
114
115
|
export const isNodeSuppressedForTTS = (node, root) => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
: node.parentElement;
|
|
116
|
+
// Through shadow hosts as well: suppression on a host covers its shadow tree.
|
|
117
|
+
let current = node.nodeType === 1 ? node : flatTreeParentElement(node);
|
|
118
118
|
while (current) {
|
|
119
119
|
if (isElementSuppressedForTTS(current))
|
|
120
120
|
return true;
|
|
121
121
|
if (root && current === root)
|
|
122
122
|
break;
|
|
123
|
-
current = current
|
|
123
|
+
current = flatTreeParentElement(current);
|
|
124
124
|
}
|
|
125
125
|
return false;
|
|
126
126
|
};
|
|
@@ -146,11 +146,7 @@ export const isNodeExcludedFromSpeech = (node, root) => isNodeHiddenForTTS(node,
|
|
|
146
146
|
* nothing".
|
|
147
147
|
*/
|
|
148
148
|
export const collectRangeTextForSpeech = (range, root) => {
|
|
149
|
-
if (typeof
|
|
150
|
-
typeof document.createTreeWalker !==
|
|
151
|
-
"function" ||
|
|
152
|
-
typeof NodeFilter === "undefined" ||
|
|
153
|
-
typeof range.intersectsNode !== "function") {
|
|
149
|
+
if (typeof range.intersectsNode !== "function") {
|
|
154
150
|
// Degraded, and deliberately not silent about the difference: callers still
|
|
155
151
|
// enforce whole-selection suppression from the range's common ancestor, so
|
|
156
152
|
// the construct guard holds even here. What is lost is per-node filtering
|
|
@@ -159,25 +155,49 @@ export const collectRangeTextForSpeech = (range, root) => {
|
|
|
159
155
|
}
|
|
160
156
|
const parts = [];
|
|
161
157
|
let filtered = false;
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
while (current) {
|
|
165
|
-
const textNode = current;
|
|
166
|
-
if (range.intersectsNode(textNode)) {
|
|
158
|
+
for (const textNode of flatTreeTextNodes(root)) {
|
|
159
|
+
if (rangeIntersectsComposedNode(range, textNode)) {
|
|
167
160
|
if (isNodeExcludedFromSpeech(textNode, root)) {
|
|
168
161
|
filtered = true;
|
|
169
162
|
}
|
|
170
163
|
else {
|
|
171
|
-
|
|
172
|
-
const start = textNode === range.startContainer ? range.startOffset : 0;
|
|
173
|
-
const end = textNode === range.endContainer ? range.endOffset : raw.length;
|
|
174
|
-
parts.push(raw.slice(start, end));
|
|
164
|
+
parts.push(textInRange(textNode, range));
|
|
175
165
|
}
|
|
176
166
|
}
|
|
177
|
-
current = walker.nextNode();
|
|
178
167
|
}
|
|
179
168
|
return { text: parts.join(""), filtered };
|
|
180
169
|
};
|
|
170
|
+
/** The part of `textNode`'s text that `range` holds, for a node it intersects. */
|
|
171
|
+
export const textInRange = (textNode, range) => {
|
|
172
|
+
const raw = textNode.textContent || "";
|
|
173
|
+
const start = textNode === range.startContainer ? range.startOffset : 0;
|
|
174
|
+
const end = textNode === range.endContainer ? range.endOffset : raw.length;
|
|
175
|
+
return raw.slice(start, end);
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Whether `range` holds all of `element`'s speakable text: its first and last
|
|
179
|
+
* speakable characters, which a contiguous range holding both holds everything
|
|
180
|
+
* between. An element with no speakable text, an image for one, is held when the
|
|
181
|
+
* range touches it, since no part of it can be selected alone.
|
|
182
|
+
*/
|
|
183
|
+
export const rangeHoldsSpeakableElement = (range, element, root) => {
|
|
184
|
+
let first = null;
|
|
185
|
+
let last = null;
|
|
186
|
+
for (const textNode of flatTreeTextNodes(element)) {
|
|
187
|
+
if (isNodeExcludedFromSpeech(textNode, root))
|
|
188
|
+
continue;
|
|
189
|
+
const raw = textNode.textContent || "";
|
|
190
|
+
const firstOffset = raw.search(/\S/);
|
|
191
|
+
if (firstOffset === -1)
|
|
192
|
+
continue;
|
|
193
|
+
first ??= { node: textNode, offset: firstOffset };
|
|
194
|
+
last = { node: textNode, offset: raw.trimEnd().length - 1 };
|
|
195
|
+
}
|
|
196
|
+
if (!first || !last)
|
|
197
|
+
return rangeIntersectsComposedNode(range, element);
|
|
198
|
+
return (rangeHoldsTextPosition(range, first.node, first.offset) &&
|
|
199
|
+
rangeHoldsTextPosition(range, last.node, last.offset));
|
|
200
|
+
};
|
|
181
201
|
export const shouldInsertWordBoundarySpace = (previousChar, nextChar, options) => {
|
|
182
202
|
if (!previousChar || !nextChar)
|
|
183
203
|
return false;
|
|
@@ -210,10 +230,7 @@ export const shouldInsertWordBoundarySpace = (previousChar, nextChar, options) =
|
|
|
210
230
|
};
|
|
211
231
|
export const collectVisibleTextAndMap = (element, options) => {
|
|
212
232
|
const map = new Map();
|
|
213
|
-
if (typeof document === "undefined"
|
|
214
|
-
typeof document.createTreeWalker !==
|
|
215
|
-
"function" ||
|
|
216
|
-
typeof NodeFilter === "undefined") {
|
|
233
|
+
if (typeof document === "undefined") {
|
|
217
234
|
return { text: "", map };
|
|
218
235
|
}
|
|
219
236
|
const outChars = [];
|
|
@@ -222,11 +239,8 @@ export const collectVisibleTextAndMap = (element, options) => {
|
|
|
222
239
|
let lastCharWasWhitespace = false;
|
|
223
240
|
let lastMapped = null;
|
|
224
241
|
let previousVisibleChar = null;
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
while (current) {
|
|
228
|
-
const textNode = current;
|
|
229
|
-
const parent = textNode.parentElement;
|
|
242
|
+
for (const textNode of flatTreeTextNodes(element)) {
|
|
243
|
+
const parent = flatTreeParentElement(textNode);
|
|
230
244
|
if (parent && !isNodeExcludedFromSpeech(textNode, element)) {
|
|
231
245
|
const raw = textNode.textContent || "";
|
|
232
246
|
const firstVisibleMatch = raw.match(/\S/);
|
|
@@ -274,7 +288,6 @@ export const collectVisibleTextAndMap = (element, options) => {
|
|
|
274
288
|
}
|
|
275
289
|
}
|
|
276
290
|
}
|
|
277
|
-
current = walker.nextNode();
|
|
278
291
|
}
|
|
279
292
|
const text = outChars.join("").trimEnd();
|
|
280
293
|
while (map.has(text.length)) {
|
|
@@ -282,4 +295,3 @@ export const collectVisibleTextAndMap = (element, options) => {
|
|
|
282
295
|
}
|
|
283
296
|
return { text, map };
|
|
284
297
|
};
|
|
285
|
-
export const extractVisibleText = (element, options) => collectVisibleTextAndMap(element, options).text;
|
|
@@ -7,3 +7,10 @@ export interface SentenceSegmentationOptions {
|
|
|
7
7
|
useSentenceSegmenter?: boolean;
|
|
8
8
|
}
|
|
9
9
|
export declare const segmentSentences: (text: string, options?: SentenceSegmentationOptions) => SentenceSegment[];
|
|
10
|
+
/**
|
|
11
|
+
* `text` in pieces of at most `maxLength` characters: whole sentences while they
|
|
12
|
+
* fit, a sentence too long for one piece cut at its last space that fits, and a
|
|
13
|
+
* word too long for one piece cut where the limit falls. Each piece is a trimmed
|
|
14
|
+
* substring of `text`, at its offset there.
|
|
15
|
+
*/
|
|
16
|
+
export declare const splitTextToLength: (text: string, maxLength: number, options?: SentenceSegmentationOptions) => SentenceSegment[];
|
|
@@ -35,3 +35,50 @@ export const segmentSentences = (text, options) => {
|
|
|
35
35
|
}
|
|
36
36
|
return parsed.length > 0 ? parsed : [{ text, offset: 0 }];
|
|
37
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* `text` in pieces of at most `maxLength` characters: whole sentences while they
|
|
40
|
+
* fit, a sentence too long for one piece cut at its last space that fits, and a
|
|
41
|
+
* word too long for one piece cut where the limit falls. Each piece is a trimmed
|
|
42
|
+
* substring of `text`, at its offset there.
|
|
43
|
+
*/
|
|
44
|
+
export const splitTextToLength = (text, maxLength, options) => {
|
|
45
|
+
const limit = Math.max(1, Math.floor(maxLength));
|
|
46
|
+
const pieces = [];
|
|
47
|
+
let start = -1;
|
|
48
|
+
let end = -1;
|
|
49
|
+
const flush = () => {
|
|
50
|
+
if (start >= 0)
|
|
51
|
+
pieces.push({ text: text.slice(start, end), offset: start });
|
|
52
|
+
start = -1;
|
|
53
|
+
};
|
|
54
|
+
const append = (spanStart, spanEnd) => {
|
|
55
|
+
if (start >= 0 && spanEnd - start <= limit) {
|
|
56
|
+
end = spanEnd;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
flush();
|
|
60
|
+
let cursor = spanStart;
|
|
61
|
+
while (spanEnd - cursor > limit) {
|
|
62
|
+
const window = text.slice(cursor, cursor + limit + 1);
|
|
63
|
+
const space = window.search(/\s\S*$/);
|
|
64
|
+
const cut = space > 0 ? cursor + space : cursor + limit;
|
|
65
|
+
pieces.push({ text: text.slice(cursor, cut).trimEnd(), offset: cursor });
|
|
66
|
+
cursor = cut;
|
|
67
|
+
while (cursor < spanEnd && /\s/.test(text[cursor]))
|
|
68
|
+
cursor++;
|
|
69
|
+
}
|
|
70
|
+
if (cursor < spanEnd) {
|
|
71
|
+
start = cursor;
|
|
72
|
+
end = spanEnd;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
for (const sentence of segmentSentences(text, options)) {
|
|
76
|
+
const leading = sentence.text.search(/\S/);
|
|
77
|
+
if (leading === -1)
|
|
78
|
+
continue;
|
|
79
|
+
const spanStart = sentence.offset + leading;
|
|
80
|
+
append(spanStart, sentence.offset + sentence.text.trimEnd().length);
|
|
81
|
+
}
|
|
82
|
+
flush();
|
|
83
|
+
return pieces;
|
|
84
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TTSConfig } from "./TTSService.js";
|
|
2
|
-
import type { ToolProviderConfig } from "./tools-config-normalizer.js";
|
|
2
|
+
import type { TextToSpeechToolProviderConfig, ToolProviderConfig } from "./tools-config-normalizer.js";
|
|
3
3
|
import { type SREMathSpeechOptions } from "./tts/math-speech.js";
|
|
4
4
|
export type TTSLayoutMode = "reserved-row" | "expanding-row" | "floating-overlay" | "left-aligned";
|
|
5
5
|
export interface TTSHostToolbarLayout {
|
|
@@ -26,9 +26,10 @@ export interface NormalizedTTSSpeedOption {
|
|
|
26
26
|
isDefault: boolean;
|
|
27
27
|
}
|
|
28
28
|
export interface TTSRuntimeSettings {
|
|
29
|
-
|
|
29
|
+
/** `browser` speaks through the Web Speech API; `server` through a TTS server. */
|
|
30
|
+
backend?: "browser" | "server";
|
|
31
|
+
/** The service behind a `server` backend. */
|
|
30
32
|
serverProvider?: "polly" | "google" | "custom";
|
|
31
|
-
provider?: "polly" | "google" | "custom";
|
|
32
33
|
engine?: "standard" | "neural";
|
|
33
34
|
sampleRate?: number;
|
|
34
35
|
format?: "mp3" | "ogg" | "pcm";
|
|
@@ -37,14 +38,35 @@ export interface TTSRuntimeSettings {
|
|
|
37
38
|
rate?: number;
|
|
38
39
|
pitch?: number;
|
|
39
40
|
apiEndpoint?: string;
|
|
41
|
+
/**
|
|
42
|
+
* The host's locale, used for a read whose content names no language: it
|
|
43
|
+
* drives text normalization and segmentation, is sent as `language` on the
|
|
44
|
+
* `pie` transport and as `lang_id` on the `custom` transport when nothing
|
|
45
|
+
* names a language, and a server given no voice picks one for it. The
|
|
46
|
+
* content language a read resolves (markup `lang`, the tool's `language`,
|
|
47
|
+
* the toolkit's `content-language`, then `lang_id`) wins over it.
|
|
48
|
+
* `docs/architecture/internationalization.md#tts-language` is the contract.
|
|
49
|
+
*/
|
|
40
50
|
language?: string;
|
|
41
51
|
transportMode?: "pie" | "custom";
|
|
42
52
|
endpointMode?: "synthesizePath" | "rootPost";
|
|
43
53
|
endpointValidationMode?: "voices" | "endpoint" | "none";
|
|
44
54
|
includeAuthOnAssetFetch?: boolean;
|
|
55
|
+
/** Origins trusted with the `Authorization` header on asset fetches. */
|
|
56
|
+
assetOrigins?: string[];
|
|
57
|
+
/** Fetch `credentials` mode for requests to the TTS server. */
|
|
58
|
+
credentials?: "omit" | "same-origin" | "include";
|
|
59
|
+
/** Headers sent with every request to the TTS server. */
|
|
60
|
+
headers?: Record<string, string>;
|
|
45
61
|
validateEndpoint?: boolean;
|
|
46
62
|
cache?: boolean;
|
|
47
63
|
speedRate?: "slow" | "medium" | "fast";
|
|
64
|
+
/**
|
|
65
|
+
* The custom transport's locale, sent on every read in place of the content
|
|
66
|
+
* language. Where markup and the tool name no language it is also the read's
|
|
67
|
+
* content language, so text processing and catalog lookups follow it. Leave
|
|
68
|
+
* it unset to let content language reach the service.
|
|
69
|
+
*/
|
|
48
70
|
lang_id?: string;
|
|
49
71
|
/**
|
|
50
72
|
* Optional inline TTS speed buttons.
|
|
@@ -75,19 +97,13 @@ export interface TTSRuntimeSettings {
|
|
|
75
97
|
* instead of relying on toolkit-specific speech rewrites.
|
|
76
98
|
*/
|
|
77
99
|
mathSpeech?: SREMathSpeechOptions;
|
|
100
|
+
/**
|
|
101
|
+
* Options passed through to the provider. The fields derived from the
|
|
102
|
+
* settings above, such as `locale` and the Polly engine, win over these.
|
|
103
|
+
*/
|
|
104
|
+
providerOptions?: Record<string, unknown>;
|
|
78
105
|
}
|
|
79
106
|
export declare const normalizeTTSLayoutMode: (value: unknown, fallback?: TTSLayoutMode) => TTSLayoutMode;
|
|
80
|
-
/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */
|
|
81
|
-
export declare const DEFAULT_TTS_SPEED_OPTIONS: readonly number[];
|
|
82
|
-
export declare const normalizeTTSSpeedOptionConfigs: (value: unknown) => TTSSpeedOption[];
|
|
83
|
-
/**
|
|
84
|
-
* Resolves inline toolbar speed options from host config.
|
|
85
|
-
* - Omitted/non-array: default speed buttons.
|
|
86
|
-
* - Empty array: hide speed buttons.
|
|
87
|
-
* - Arrays that sanitize to no valid values: default speed buttons.
|
|
88
|
-
* - 1.0× is never shown as a discrete speed button.
|
|
89
|
-
*/
|
|
90
|
-
export declare const normalizeTTSSpeedOptions: (value: unknown) => number[];
|
|
91
107
|
export declare const normalizeTTSSpeedControlOptions: (value: unknown) => NormalizedTTSSpeedOption[];
|
|
92
108
|
export declare const formatTTSSpeedOptionsAsText: (values: number[]) => string;
|
|
93
109
|
/**
|
|
@@ -96,10 +112,20 @@ export declare const formatTTSSpeedOptionsAsText: (values: number[]) => string;
|
|
|
96
112
|
* - Non-empty text with no parseable finite numbers → same as invalid-only array config: defaults.
|
|
97
113
|
*/
|
|
98
114
|
export declare const parseTTSSpeedOptionsFromText: (text: string) => number[];
|
|
99
|
-
|
|
115
|
+
/**
|
|
116
|
+
* The runtime settings of a `textToSpeech` provider entry: its top-level keys
|
|
117
|
+
* with defaults applied. `enabled` and the runtime `provider` object belong to
|
|
118
|
+
* the tool registration and are dropped.
|
|
119
|
+
*/
|
|
120
|
+
export declare const resolveTTSRuntimeSettings: (config: TextToSpeechToolProviderConfig | ToolProviderConfig | TTSRuntimeSettings | undefined) => TTSRuntimeSettings;
|
|
100
121
|
export declare const resolveTTSBackend: (config: TTSRuntimeSettings) => NonNullable<TTSRuntimeSettings["backend"]>;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
122
|
+
/**
|
|
123
|
+
* The provider configuration built from host settings: the contract's portable
|
|
124
|
+
* fields plus the server adapter's, under the adapter's names.
|
|
125
|
+
*/
|
|
126
|
+
export type RuntimeTTSConfig = Pick<TTSConfig, "voice" | "rate" | "pitch" | "providerOptions" | "mathTokenHighlighting"> & Pick<TTSRuntimeSettings, "apiEndpoint" | "language" | "transportMode" | "endpointMode" | "endpointValidationMode" | "includeAuthOnAssetFetch" | "assetOrigins" | "credentials" | "headers" | "validateEndpoint"> & {
|
|
127
|
+
provider?: TTSRuntimeSettings["serverProvider"];
|
|
128
|
+
};
|
|
129
|
+
export declare const buildRuntimeTTSConfig: (config: TTSRuntimeSettings) => RuntimeTTSConfig;
|
|
104
130
|
export declare const resolveTTSLayoutMode: (config: TTSRuntimeSettings) => TTSLayoutMode;
|
|
105
131
|
export declare const resolveTTSHostToolbarLayout: (config: TTSRuntimeSettings) => TTSHostToolbarLayout;
|
|
@@ -6,26 +6,16 @@ const VALID_TTS_LAYOUT_MODES = new Set([
|
|
|
6
6
|
"left-aligned",
|
|
7
7
|
]);
|
|
8
8
|
const toRecord = (value) => value && typeof value === "object" ? value : {};
|
|
9
|
-
const isServerBackend = (backend) => backend === "polly" || backend === "google" || backend === "server";
|
|
10
9
|
const withDefault = (value, fallback) => value === undefined ? fallback : value;
|
|
11
10
|
export const normalizeTTSLayoutMode = (value, fallback = "left-aligned") => typeof value === "string" &&
|
|
12
11
|
VALID_TTS_LAYOUT_MODES.has(value)
|
|
13
12
|
? value
|
|
14
13
|
: fallback;
|
|
15
|
-
/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */
|
|
16
|
-
export const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);
|
|
17
14
|
const DEFAULT_TTS_SPEED_CONTROL_OPTIONS = Object.freeze([
|
|
18
15
|
{ rate: 0.8, label: "Slow", ariaLabel: "Slow speed" },
|
|
19
16
|
{ rate: 1, label: "Normal", ariaLabel: "Normal speed", default: true },
|
|
20
17
|
{ rate: 1.25, label: "Fast", ariaLabel: "Fast speed" },
|
|
21
18
|
]);
|
|
22
|
-
const normalizeSpeedRate = (entry) => {
|
|
23
|
-
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
const rounded = Math.round(entry * 100) / 100;
|
|
27
|
-
return rounded === 1 ? undefined : rounded;
|
|
28
|
-
};
|
|
29
19
|
const normalizeControlSpeedRate = (entry) => {
|
|
30
20
|
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
31
21
|
return undefined;
|
|
@@ -51,56 +41,6 @@ const normalizeSpeedAriaLabel = (label, ariaLabel, usedDefaultLabel) => {
|
|
|
51
41
|
return ariaLabel;
|
|
52
42
|
return `${label} ${ariaLabel}`;
|
|
53
43
|
};
|
|
54
|
-
const normalizeTTSSpeedOptionConfig = (entry) => {
|
|
55
|
-
if (typeof entry === "number")
|
|
56
|
-
return normalizeSpeedRate(entry);
|
|
57
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
58
|
-
return undefined;
|
|
59
|
-
const record = entry;
|
|
60
|
-
const rate = normalizeSpeedRate(record.rate);
|
|
61
|
-
if (rate === undefined)
|
|
62
|
-
return undefined;
|
|
63
|
-
const label = trimOptionalText(record.label);
|
|
64
|
-
const ariaLabel = trimOptionalText(record.ariaLabel);
|
|
65
|
-
return {
|
|
66
|
-
rate,
|
|
67
|
-
...(label ? { label } : {}),
|
|
68
|
-
...(ariaLabel ? { ariaLabel } : {}),
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
export const normalizeTTSSpeedOptionConfigs = (value) => {
|
|
72
|
-
if (!Array.isArray(value))
|
|
73
|
-
return [...DEFAULT_TTS_SPEED_OPTIONS];
|
|
74
|
-
if (value.length === 0)
|
|
75
|
-
return [];
|
|
76
|
-
const dedupedRates = new Set();
|
|
77
|
-
const normalized = [];
|
|
78
|
-
for (const entry of value) {
|
|
79
|
-
const option = normalizeTTSSpeedOptionConfig(entry);
|
|
80
|
-
if (option === undefined)
|
|
81
|
-
continue;
|
|
82
|
-
const rate = typeof option === "number" ? option : option.rate;
|
|
83
|
-
if (dedupedRates.has(rate))
|
|
84
|
-
continue;
|
|
85
|
-
dedupedRates.add(rate);
|
|
86
|
-
normalized.push(option);
|
|
87
|
-
}
|
|
88
|
-
return normalized.length ? normalized : [...DEFAULT_TTS_SPEED_OPTIONS];
|
|
89
|
-
};
|
|
90
|
-
/**
|
|
91
|
-
* Resolves inline toolbar speed options from host config.
|
|
92
|
-
* - Omitted/non-array: default speed buttons.
|
|
93
|
-
* - Empty array: hide speed buttons.
|
|
94
|
-
* - Arrays that sanitize to no valid values: default speed buttons.
|
|
95
|
-
* - 1.0× is never shown as a discrete speed button.
|
|
96
|
-
*/
|
|
97
|
-
export const normalizeTTSSpeedOptions = (value) => {
|
|
98
|
-
if (!Array.isArray(value))
|
|
99
|
-
return [...DEFAULT_TTS_SPEED_OPTIONS];
|
|
100
|
-
if (value.length === 0)
|
|
101
|
-
return [];
|
|
102
|
-
return normalizeTTSSpeedOptionConfigs(value).map((option) => typeof option === "number" ? option : option.rate);
|
|
103
|
-
};
|
|
104
44
|
export const normalizeTTSSpeedControlOptions = (value) => {
|
|
105
45
|
const input = Array.isArray(value)
|
|
106
46
|
? value
|
|
@@ -203,8 +143,7 @@ const applyRuntimeDefaults = (config) => {
|
|
|
203
143
|
...config,
|
|
204
144
|
layoutMode: normalizeTTSLayoutMode(config.layoutMode),
|
|
205
145
|
};
|
|
206
|
-
|
|
207
|
-
if (!isServerBackend(backend))
|
|
146
|
+
if (config.backend !== "server")
|
|
208
147
|
return withLayoutDefaults;
|
|
209
148
|
const withServerDefaults = {
|
|
210
149
|
...withLayoutDefaults,
|
|
@@ -216,62 +155,48 @@ const applyRuntimeDefaults = (config) => {
|
|
|
216
155
|
rate: withDefault(withLayoutDefaults.rate, 1.0),
|
|
217
156
|
language: withDefault(withLayoutDefaults.language, "en-US"),
|
|
218
157
|
};
|
|
219
|
-
if (
|
|
158
|
+
if (config.serverProvider === "polly") {
|
|
220
159
|
return {
|
|
221
160
|
...withServerDefaults,
|
|
222
|
-
defaultVoice: withDefault(withServerDefaults.defaultVoice, "Joanna"),
|
|
223
161
|
engine: withDefault(withServerDefaults.engine, "neural"),
|
|
224
162
|
format: withDefault(withServerDefaults.format, "mp3"),
|
|
225
163
|
speechMarksMode: withDefault(withServerDefaults.speechMarksMode, "word+sentence"),
|
|
226
164
|
};
|
|
227
165
|
}
|
|
228
|
-
if (backend === "google") {
|
|
229
|
-
return {
|
|
230
|
-
...withServerDefaults,
|
|
231
|
-
defaultVoice: withDefault(withServerDefaults.defaultVoice, "en-US-Wavenet-A"),
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
166
|
return withServerDefaults;
|
|
235
167
|
};
|
|
168
|
+
/**
|
|
169
|
+
* The runtime settings of a `textToSpeech` provider entry: its top-level keys
|
|
170
|
+
* with defaults applied. `enabled` and the runtime `provider` object belong to
|
|
171
|
+
* the tool registration and are dropped.
|
|
172
|
+
*/
|
|
236
173
|
export const resolveTTSRuntimeSettings = (config) => {
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
return applyRuntimeDefaults({
|
|
240
|
-
...configRecord,
|
|
241
|
-
...settingsRecord,
|
|
242
|
-
});
|
|
174
|
+
const { enabled: _enabled, provider: _provider, ...settings } = toRecord(config);
|
|
175
|
+
return applyRuntimeDefaults(settings);
|
|
243
176
|
};
|
|
244
177
|
export const resolveTTSBackend = (config) => config.backend || "browser";
|
|
245
|
-
export const resolveRuntimeProvider = (config, backend) => {
|
|
246
|
-
if (backend === "polly" || backend === "google")
|
|
247
|
-
return backend;
|
|
248
|
-
if (backend === "server") {
|
|
249
|
-
return config.serverProvider || config.provider;
|
|
250
|
-
}
|
|
251
|
-
return config.serverProvider || config.provider;
|
|
252
|
-
};
|
|
253
|
-
export const resolveTransportMode = (config, runtimeProvider) => config.transportMode || (runtimeProvider === "custom" ? "custom" : "pie");
|
|
254
178
|
export const buildRuntimeTTSConfig = (config) => {
|
|
255
|
-
const
|
|
256
|
-
const
|
|
257
|
-
const transportMode =
|
|
179
|
+
const runtimeProvider = resolveTTSBackend(config) === "server" ? config.serverProvider : undefined;
|
|
180
|
+
const polly = runtimeProvider === "polly";
|
|
181
|
+
const transportMode = config.transportMode || (runtimeProvider === "custom" ? "custom" : "pie");
|
|
258
182
|
const mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);
|
|
259
|
-
|
|
183
|
+
const runtimeConfig = {
|
|
260
184
|
voice: config.defaultVoice,
|
|
261
185
|
rate: config.rate,
|
|
262
186
|
pitch: config.pitch,
|
|
263
187
|
providerOptions: {
|
|
188
|
+
...toRecord(config.providerOptions),
|
|
264
189
|
...(config.language ? { locale: config.language } : {}),
|
|
265
|
-
...(
|
|
190
|
+
...(polly && config.engine
|
|
266
191
|
? { engine: config.engine }
|
|
267
192
|
: {}),
|
|
268
|
-
...(
|
|
193
|
+
...(polly && typeof config.sampleRate === "number"
|
|
269
194
|
? { sampleRate: config.sampleRate }
|
|
270
195
|
: {}),
|
|
271
|
-
...(
|
|
196
|
+
...(polly && config.format
|
|
272
197
|
? { format: config.format }
|
|
273
198
|
: {}),
|
|
274
|
-
...(
|
|
199
|
+
...(polly
|
|
275
200
|
? {
|
|
276
201
|
speechMarkTypes: config.speechMarksMode === "word+sentence"
|
|
277
202
|
? ["word", "sentence"]
|
|
@@ -296,6 +221,9 @@ export const buildRuntimeTTSConfig = (config) => {
|
|
|
296
221
|
endpointMode: config.endpointMode,
|
|
297
222
|
endpointValidationMode: config.endpointValidationMode,
|
|
298
223
|
includeAuthOnAssetFetch: config.includeAuthOnAssetFetch,
|
|
224
|
+
assetOrigins: config.assetOrigins,
|
|
225
|
+
credentials: config.credentials,
|
|
226
|
+
headers: config.headers,
|
|
299
227
|
validateEndpoint: config.validateEndpoint,
|
|
300
228
|
// Toolkit-level highlight setting carried through the config channel
|
|
301
229
|
// (like apiEndpoint/transportMode); consumed by the highlight pipeline,
|
|
@@ -305,6 +233,7 @@ export const buildRuntimeTTSConfig = (config) => {
|
|
|
305
233
|
? { mathTokenHighlighting: config.mathTokenHighlighting }
|
|
306
234
|
: {}),
|
|
307
235
|
};
|
|
236
|
+
return runtimeConfig;
|
|
308
237
|
};
|
|
309
238
|
export const resolveTTSLayoutMode = (config) => normalizeTTSLayoutMode(config.layoutMode);
|
|
310
239
|
export const resolveTTSHostToolbarLayout = (config) => {
|