@pie-players/pie-assessment-toolkit 0.3.47 → 0.3.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attempt/AssessmentSession.js +2 -1
- package/dist/attempt/AssessmentSession.js.map +1 -1
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +12 -8
- package/dist/attempt/adapters/activity-to-test-attempt-session.js.map +1 -1
- package/dist/components/ItemToolBar.custom-element.js +56 -17
- package/dist/components/PieAssessmentToolkit.custom-element.js +84 -29
- package/dist/components/SectionToolBar.custom-element.js +55 -17
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/policy/core/pnp-policy-inputs.js +1 -2
- package/dist/policy/core/pnp-policy-inputs.js.map +1 -1
- package/dist/policy/core/provenance.js.map +1 -1
- package/dist/runtime/SectionRuntimeEngine.js +1 -1
- package/dist/runtime/SectionRuntimeEngine.js.map +1 -1
- package/dist/runtime/core/cohort.js.map +1 -1
- package/dist/runtime/core/engine-input.js.map +1 -1
- package/dist/runtime/core/engine-readiness.js.map +1 -1
- package/dist/runtime/core/engine-resolver.js.map +1 -1
- package/dist/runtime/core/engine-transition.js +1 -3
- package/dist/runtime/core/engine-transition.js.map +1 -1
- package/dist/runtime/registration-events.js.map +1 -1
- package/dist/runtime/session-event-emitter-policy.js.map +1 -1
- package/dist/services/HighlightCoordinator.js +2 -1
- package/dist/services/HighlightCoordinator.js.map +1 -1
- package/dist/services/I18nService.d.ts +1 -1
- package/dist/services/I18nService.js.map +1 -1
- package/dist/services/SSMLExtractor.js.map +1 -1
- package/dist/services/TTSService.js +5 -2
- package/dist/services/TTSService.js.map +1 -1
- package/dist/services/ThemeProvider.js.map +1 -1
- package/dist/services/ToolRegistry.d.ts +1 -1
- package/dist/services/ToolRegistry.js.map +1 -1
- package/dist/services/ToolkitCoordinator.js +21 -11
- package/dist/services/ToolkitCoordinator.js.map +1 -1
- package/dist/services/createDefaultToolRegistry.js +4 -2
- package/dist/services/createDefaultToolRegistry.js.map +1 -1
- package/dist/services/framework-error-bus.js.map +1 -1
- package/dist/services/framework-error.js.map +1 -1
- package/dist/services/interfaces.js.map +1 -1
- package/dist/services/section-controller-types.js.map +1 -1
- package/dist/services/tool-config-defaults.js +7 -1
- package/dist/services/tool-config-defaults.js.map +1 -1
- package/dist/services/tool-config-validation.js +3 -1
- package/dist/services/tool-config-validation.js.map +1 -1
- package/dist/services/tool-instance-id.js.map +1 -1
- package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -1
- package/dist/services/tool-providers/TTSToolProvider.js.map +1 -1
- package/dist/services/toolbar-items.js.map +1 -1
- package/dist/services/tools-config-normalizer.js +1 -2
- package/dist/services/tools-config-normalizer.js.map +1 -1
- package/dist/services/tts/browser-provider.js +60 -18
- package/dist/services/tts/browser-provider.js.map +1 -1
- package/dist/services/tts/catalog-span-alignment.js +8 -3
- package/dist/services/tts/catalog-span-alignment.js.map +1 -1
- package/dist/services/tts/generated-speech/assemble-plan.js.map +1 -1
- package/dist/services/tts/generated-speech/index.d.ts +1 -1
- package/dist/services/tts/generated-speech/index.js +1 -1
- package/dist/services/tts/generated-speech/index.js.map +1 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js +3 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js.map +1 -1
- package/dist/services/tts/highlight-pipeline/boundary-normalizer.js.map +1 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js.map +1 -1
- package/dist/services/tts/math-alignment/mathml-tokenizer.js.map +1 -1
- package/dist/services/tts/math-alignment/sequence-aligner.js.map +1 -1
- package/dist/services/tts/math-alignment/speech-tokenizer.js.map +1 -1
- package/dist/services/tts/math-aware-text-processing.js +6 -3
- package/dist/services/tts/math-aware-text-processing.js.map +1 -1
- package/dist/services/tts/math-speech.js +3 -1
- package/dist/services/tts/math-speech.js.map +1 -1
- package/dist/services/tts/visual-line-ranges.js.map +1 -1
- package/dist/services/tts-runtime-config.js +6 -2
- package/dist/services/tts-runtime-config.js.map +1 -1
- package/dist/tools/calculators/desmos-provider.js.map +1 -1
- package/dist/tools/default-tool-module-loaders.js.map +1 -1
- package/dist/tools/registrations/accessibility-tools.js.map +1 -1
- package/dist/tools/registrations/calculator.js +1 -1
- package/dist/tools/registrations/calculator.js.map +1 -1
- package/dist/tools/registrations/interaction-tools.js.map +1 -1
- package/dist/tools/registrations/measurement-tools.js.map +1 -1
- package/dist/tools/registrations/subject-specific-tools.js +1 -1
- package/dist/tools/registrations/subject-specific-tools.js.map +1 -1
- package/dist/tools/registrations/tts.js +4 -2
- package/dist/tools/registrations/tts.js.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/variant-resolver.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"math-aware-text-processing.js","sourceRoot":"","sources":["../../../src/services/tts/math-aware-text-processing.ts"],"names":[],"mappings":"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","sourcesContent":["import { canonicalizeMathML } from \"./mathml-sanitization.js\";\nimport {\n\tcollectVisibleTextAndMap,\n\ttype NormalizedTextMap,\n\ttype TextProcessingOptions,\n\tisNodeHiddenForTTS,\n\tnormalizeTextForSpeech,\n\tshouldInsertWordBoundarySpace,\n} from \"./text-processing.js\";\n\nexport type MathAwareSpeechChunk =\n\t| {\n\t\t\ttype: \"text\";\n\t\t\ttext: string;\n\t\t\tsourceElement?: Element;\n\t }\n\t| {\n\t\t\ttype: \"math\";\n\t\t\tmathml: string;\n\t\t\tfallbackText: string;\n\t\t\tsourceElement?: Element;\n\t };\n\nexport interface MathAwareTextResult {\n\tvisibleText: string;\n\tmap: NormalizedTextMap;\n\tchunks: MathAwareSpeechChunk[];\n\tcontainsMathMarkup: boolean;\n}\n\ninterface TextAccumulator {\n\tchars: string[];\n\tmap: NormalizedTextMap;\n\tposition: number;\n\tinLeadingWhitespace: boolean;\n\tlastCharWasWhitespace: boolean;\n\tlastMapped: { node: Text; offset: number } | null;\n\toptions?: TextProcessingOptions;\n}\n\nconst createAccumulator = (\n\toptions?: TextProcessingOptions,\n): TextAccumulator => ({\n\tchars: [],\n\tmap: new Map(),\n\tposition: 0,\n\tinLeadingWhitespace: true,\n\tlastCharWasWhitespace: false,\n\tlastMapped: null,\n\toptions,\n});\n\nconst isMathJaxElement = (element: Element): boolean =>\n\telement.classList?.contains(\"MathJax\") ||\n\telement.tagName?.toLowerCase() === \"mjx-container\";\n\nconst isAssistiveMathElement = (element: Element): boolean =>\n\telement.tagName?.toLowerCase() === \"mjx-assistive-mml\";\n\nconst isAnnotationElement = (element: Element): boolean => {\n\tconst tagName = element.tagName?.toLowerCase();\n\treturn tagName === \"annotation\" || tagName === \"annotation-xml\";\n};\n\nconst getDataMathML = (element: Element): string | null => {\n\tconst value = element.getAttribute(\"data-mathml\");\n\treturn value && value.trim() ? value : null;\n};\n\nconst findAssistiveMathML = (element: Element): string | null => {\n\tconst assistive = element.querySelector(\"mjx-assistive-mml math\");\n\treturn assistive?.outerHTML || null;\n};\n\nconst findCanonicalMathML = (element: Element): string | null => {\n\tif (element.tagName.toLowerCase() === \"math\") {\n\t\treturn canonicalizeMathML(element.outerHTML);\n\t}\n\tconst dataMath = getDataMathML(element);\n\tif (dataMath) {\n\t\tconst canonical = canonicalizeMathML(dataMath);\n\t\tif (canonical) return canonical;\n\t}\n\tif (isMathJaxElement(element)) {\n\t\tconst assistive = findAssistiveMathML(element);\n\t\tif (assistive) {\n\t\t\tconst canonical = canonicalizeMathML(assistive);\n\t\t\tif (canonical) return canonical;\n\t\t}\n\t}\n\treturn null;\n};\n\nconst isMathContainer = (element: Element): boolean =>\n\tBoolean(findCanonicalMathML(element));\n\nconst TEXT_CHUNK_SOURCE_TAGS = new Set([\n\t\"P\",\n\t\"H1\",\n\t\"H2\",\n\t\"H3\",\n\t\"H4\",\n\t\"H5\",\n\t\"H6\",\n\t\"LI\",\n\t\"TD\",\n\t\"TH\",\n\t\"DD\",\n\t\"DT\",\n\t\"FIGCAPTION\",\n\t\"LABEL\",\n\t\"BUTTON\",\n]);\n\nconst TEXT_CHUNK_SOURCE_ROLES = new Set([\n\t\"heading\",\n\t\"listitem\",\n\t\"option\",\n\t\"radio\",\n\t\"row\",\n\t\"cell\",\n\t\"columnheader\",\n\t\"rowheader\",\n]);\n\nconst resolveTextChunkSourceElement = (\n\ttextNode: Text,\n\troot: Element,\n): Element => {\n\tlet current = textNode.parentElement;\n\tlet best: Element | null = null;\n\twhile (current && current !== root) {\n\t\tconst role = (current.getAttribute(\"role\") || \"\").toLowerCase();\n\t\tconst tagName = current.tagName.toUpperCase();\n\t\tif (\n\t\t\tTEXT_CHUNK_SOURCE_TAGS.has(tagName) ||\n\t\t\tTEXT_CHUNK_SOURCE_ROLES.has(role)\n\t\t) {\n\t\t\tbest = current;\n\t\t\tbreak;\n\t\t}\n\t\tcurrent = current.parentElement;\n\t}\n\treturn best || root;\n};\n\nconst hasMathCandidate = (element: Element): boolean =>\n\tBoolean(\n\t\ttypeof element.querySelector === \"function\" &&\n\t\t\telement.querySelector(\n\t\t\t\t\"math, [data-mathml], .MathJax, mjx-container, mjx-assistive-mml\",\n\t\t\t),\n\t) ||\n\telement.tagName?.toLowerCase() === \"math\" ||\n\telement.hasAttribute?.(\"data-mathml\") ||\n\tisMathJaxElement(element);\n\nconst appendCharacter = (\n\tacc: TextAccumulator,\n\tcharacter: string,\n\tmapping: { node: Text; offset: number } | null,\n): void => {\n\tif (\n\t\t/[.,;:!?]/.test(character) &&\n\t\tacc.chars.length > 0 &&\n\t\tacc.chars[acc.chars.length - 1] === \" \"\n\t) {\n\t\tacc.chars.pop();\n\t\tacc.position--;\n\t\tacc.map.delete(acc.position);\n\t}\n\tacc.chars.push(character);\n\tif (mapping) {\n\t\tacc.map.set(acc.position, mapping);\n\t\tacc.lastMapped = mapping;\n\t} else if (acc.lastMapped) {\n\t\tacc.map.set(acc.position, acc.lastMapped);\n\t}\n\tacc.position++;\n};\n\nconst shouldInsertBoundarySpace = (\n\tacc: TextAccumulator,\n\tnextCharacter: string,\n): boolean => {\n\tif (\n\t\tacc.inLeadingWhitespace ||\n\t\tacc.lastCharWasWhitespace ||\n\t\tacc.chars.length === 0\n\t) {\n\t\treturn false;\n\t}\n\tconst previous = acc.chars[acc.chars.length - 1];\n\t// Defer to the shared locale-aware decision (Intl.Segmenter, falling back to\n\t// alnum) so adjacent text nodes split into words consistently with the main\n\t// visible-text collector, instead of an ASCII-only heuristic.\n\treturn shouldInsertWordBoundarySpace(previous, nextCharacter, acc.options);\n};\n\nconst appendTextNode = (acc: TextAccumulator, textNode: Text): void => {\n\tconst raw = textNode.textContent || \"\";\n\tlet appendedNonWhitespaceInNode = false;\n\tfor (let i = 0; i < raw.length; i++) {\n\t\tconst character = raw[i];\n\t\tconst isWhitespace = /\\s/.test(character);\n\t\tif (acc.inLeadingWhitespace) {\n\t\t\tif (!isWhitespace) {\n\t\t\t\tacc.inLeadingWhitespace = false;\n\t\t\t\tappendCharacter(acc, character, { node: textNode, offset: i });\n\t\t\t\tappendedNonWhitespaceInNode = true;\n\t\t\t\tacc.lastCharWasWhitespace = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (isWhitespace) {\n\t\t\tif (!acc.lastCharWasWhitespace) {\n\t\t\t\tappendCharacter(acc, \" \", { node: textNode, offset: i });\n\t\t\t}\n\t\t\tacc.lastCharWasWhitespace = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\t!appendedNonWhitespaceInNode &&\n\t\t\tshouldInsertBoundarySpace(acc, character)\n\t\t) {\n\t\t\tappendCharacter(acc, \" \", { node: textNode, offset: i });\n\t\t}\n\t\tappendCharacter(acc, character, { node: textNode, offset: i });\n\t\tappendedNonWhitespaceInNode = true;\n\t\tacc.lastCharWasWhitespace = false;\n\t}\n};\n\nconst appendCollectedText = (\n\tacc: TextAccumulator,\n\tcollected: { text: string; map: NormalizedTextMap },\n): void => {\n\tfor (let i = 0; i < collected.text.length; i++) {\n\t\tconst character = collected.text[i];\n\t\tconst isWhitespace = /\\s/.test(character);\n\t\tconst mapping = collected.map.get(i) || null;\n\t\tconst syntheticNode = mapping?.node || acc.lastMapped?.node || null;\n\t\tconst syntheticOffset = mapping?.offset ?? acc.lastMapped?.offset ?? 0;\n\t\tconst normalizedMapping = mapping\n\t\t\t? { node: mapping.node, offset: mapping.offset }\n\t\t\t: syntheticNode\n\t\t\t\t? { node: syntheticNode, offset: syntheticOffset }\n\t\t\t\t: null;\n\t\tif (acc.inLeadingWhitespace) {\n\t\t\tif (isWhitespace) continue;\n\t\t\tacc.inLeadingWhitespace = false;\n\t\t}\n\t\tif (isWhitespace) {\n\t\t\tif (!acc.lastCharWasWhitespace) {\n\t\t\t\tappendCharacter(acc, \" \", normalizedMapping);\n\t\t\t}\n\t\t\tacc.lastCharWasWhitespace = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (i === 0 && shouldInsertBoundarySpace(acc, character)) {\n\t\t\tappendCharacter(acc, \" \", normalizedMapping);\n\t\t}\n\t\tappendCharacter(acc, character, normalizedMapping);\n\t\tacc.lastCharWasWhitespace = false;\n\t\tif (mapping) {\n\t\t\tacc.map.set(acc.position - 1, {\n\t\t\t\tnode: mapping.node,\n\t\t\t\toffset: mapping.offset,\n\t\t\t});\n\t\t\tacc.lastMapped = { node: mapping.node, offset: mapping.offset };\n\t\t} else if (syntheticNode) {\n\t\t\tacc.map.set(acc.position - 1, {\n\t\t\t\tnode: syntheticNode,\n\t\t\t\toffset: syntheticOffset,\n\t\t\t});\n\t\t}\n\t}\n};\n\nconst textFallbackFromMathML = (mathml: string): string => {\n\tif (typeof DOMParser === \"undefined\") return \"\";\n\tconst parsed = new DOMParser().parseFromString(mathml, \"application/xml\");\n\tif (parsed.getElementsByTagName(\"parsererror\").length > 0) return \"\";\n\tconst parts: string[] = [];\n\tconst visit = (node: Node): void => {\n\t\tif (node.nodeType === 3) {\n\t\t\tconst text = node.textContent || \"\";\n\t\t\tif (text.trim()) parts.push(text);\n\t\t\treturn;\n\t\t}\n\t\tif (node.nodeType !== 1) return;\n\t\tconst element = node as Element;\n\t\tif (isAnnotationElement(element)) return;\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tvisit(child);\n\t\t}\n\t};\n\tvisit(parsed.documentElement);\n\treturn normalizeTextForSpeech(parts.join(\" \"));\n};\n\nconst collectVisibleMathFallback = (\n\telement: Element,\n\tcanonicalMathML: string,\n\toptions?: TextProcessingOptions,\n): { text: string; map: NormalizedTextMap } => {\n\tconst mathAcc = createAccumulator(options);\n\tconst visit = (node: Node): void => {\n\t\tif (isNodeHiddenForTTS(node, element)) return;\n\t\tif (node.nodeType === 3) {\n\t\t\tappendTextNode(mathAcc, node as Text);\n\t\t\treturn;\n\t\t}\n\t\tif (node.nodeType !== 1) return;\n\t\tconst childElement = node as Element;\n\t\tif (\n\t\t\tisAssistiveMathElement(childElement) ||\n\t\t\tisAnnotationElement(childElement)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const child of Array.from(childElement.childNodes)) {\n\t\t\tvisit(child);\n\t\t}\n\t};\n\tvisit(element);\n\ttrimTrailingWhitespace(mathAcc);\n\tconst text = normalizeTextForSpeech(mathAcc.chars.join(\"\"));\n\tif (text) {\n\t\treturn { text, map: mathAcc.map };\n\t}\n\tconst fallbackText = textFallbackFromMathML(canonicalMathML);\n\tif (!fallbackText) {\n\t\treturn collectVisibleTextAndMap(element, options);\n\t}\n\treturn {\n\t\ttext: fallbackText,\n\t\tmap: new Map(),\n\t};\n};\n\nconst trimTrailingWhitespace = (acc: TextAccumulator): void => {\n\twhile (acc.chars.length > 0 && /\\s/.test(acc.chars[acc.chars.length - 1])) {\n\t\tacc.chars.pop();\n\t\tacc.position--;\n\t\tacc.map.delete(acc.position);\n\t}\n};\n\nconst collectMathAware = (\n\troot: Element,\n\toptions?: TextProcessingOptions,\n): MathAwareTextResult => {\n\tconst acc = createAccumulator(options);\n\tconst chunks: MathAwareSpeechChunk[] = [];\n\tlet textChunkStart = 0;\n\tlet textChunkSourceElement: Element | undefined;\n\tlet containsMathMarkup = false;\n\n\tconst flushTextChunk = () => {\n\t\tconst text = normalizeTextForSpeech(\n\t\t\tacc.chars.slice(textChunkStart, acc.chars.length).join(\"\"),\n\t\t);\n\t\tif (text) {\n\t\t\tchunks.push({ type: \"text\", text, sourceElement: textChunkSourceElement });\n\t\t}\n\t\ttextChunkStart = acc.chars.length;\n\t\ttextChunkSourceElement = undefined;\n\t};\n\n\tconst processNode = (node: Node): void => {\n\t\tif (isNodeHiddenForTTS(node, root)) return;\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst sourceElement = resolveTextChunkSourceElement(node as Text, root);\n\t\t\tif (\n\t\t\t\ttextChunkSourceElement &&\n\t\t\t\tsourceElement !== textChunkSourceElement\n\t\t\t) {\n\t\t\t\tflushTextChunk();\n\t\t\t}\n\t\t\ttextChunkSourceElement = sourceElement;\n\t\t\tappendTextNode(acc, node as Text);\n\t\t\treturn;\n\t\t}\n\t\tif (node.nodeType !== Node.ELEMENT_NODE) return;\n\t\tconst element = node as Element;\n\t\tif (isAssistiveMathElement(element)) return;\n\t\tconst canonicalMathML = findCanonicalMathML(element);\n\t\tif (canonicalMathML) {\n\t\t\tflushTextChunk();\n\t\t\tconst collected = collectVisibleMathFallback(\n\t\t\t\telement,\n\t\t\t\tcanonicalMathML,\n\t\t\t\toptions,\n\t\t\t);\n\t\t\tappendCollectedText(acc, collected);\n\t\t\tconst fallbackText = normalizeTextForSpeech(collected.text);\n\t\t\tchunks.push({\n\t\t\t\ttype: \"math\",\n\t\t\t\tmathml: canonicalMathML,\n\t\t\t\tfallbackText,\n\t\t\t\tsourceElement: element,\n\t\t\t});\n\t\t\ttextChunkStart = acc.chars.length;\n\t\t\tcontainsMathMarkup = true;\n\t\t\treturn;\n\t\t}\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tprocessNode(child);\n\t\t}\n\t};\n\n\tfor (const child of Array.from(root.childNodes)) {\n\t\tprocessNode(child);\n\t}\n\n\ttrimTrailingWhitespace(acc);\n\tflushTextChunk();\n\tconst visibleText = acc.chars.join(\"\");\n\twhile (acc.map.has(visibleText.length)) {\n\t\tacc.map.delete(visibleText.length);\n\t}\n\treturn {\n\t\tvisibleText,\n\t\tmap: acc.map,\n\t\tchunks,\n\t\tcontainsMathMarkup,\n\t};\n};\n\nexport const collectMathAwareTextAndMap = (\n\telement: Element,\n\toptions?: TextProcessingOptions,\n): MathAwareTextResult => {\n\tif (!hasMathCandidate(element)) {\n\t\tconst { text, map } = collectVisibleTextAndMap(element, options);\n\t\treturn {\n\t\t\tvisibleText: text,\n\t\t\tmap,\n\t\t\tchunks: text ? [{ type: \"text\", text }] : [],\n\t\t\tcontainsMathMarkup: false,\n\t\t};\n\t}\n\treturn collectMathAware(element, options);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"math-aware-text-processing.js","sourceRoot":"","sources":["../../../src/services/tts/math-aware-text-processing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACN,wBAAwB,EAGxB,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,GAC7B,MAAM,sBAAsB,CAAC;AAgC9B,MAAM,iBAAiB,GAAG,CACzB,OAA+B,EACb,EAAE,CAAC,CAAC;IACtB,KAAK,EAAE,EAAE;IACT,GAAG,EAAE,IAAI,GAAG,EAAE;IACd,QAAQ,EAAE,CAAC;IACX,mBAAmB,EAAE,IAAI;IACzB,qBAAqB,EAAE,KAAK;IAC5B,UAAU,EAAE,IAAI;IAChB,OAAO;CACP,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,OAAgB,EAAW,EAAE,CACtD,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC;IACtC,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,CAAC;AAEpD,MAAM,sBAAsB,GAAG,CAAC,OAAgB,EAAW,EAAE,CAC5D,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,CAAC;AAExD,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAW,EAAE;IACzD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;IAC/C,OAAO,OAAO,KAAK,YAAY,IAAI,OAAO,KAAK,gBAAgB,CAAC;AACjE,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,OAAgB,EAAiB,EAAE;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IAClD,OAAO,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAiB,EAAE;IAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC;IAClE,OAAO,SAAS,EAAE,SAAS,IAAI,IAAI,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAiB,EAAE;IAC/D,IAAI,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QAC9C,OAAO,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,QAAQ,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,SAAS;YAAE,OAAO,SAAS,CAAC;IACjC,CAAC;IACD,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,SAAS,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;YAChD,IAAI,SAAS;gBAAE,OAAO,SAAS,CAAC;QACjC,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,OAAgB,EAAW,EAAE,CACrD,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAEvC,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACtC,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,YAAY;IACZ,OAAO;IACP,QAAQ;CACR,CAAC,CAAC;AAEH,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IACvC,SAAS;IACT,UAAU;IACV,QAAQ;IACR,OAAO;IACP,KAAK;IACL,MAAM;IACN,cAAc;IACd,WAAW;CACX,CAAC,CAAC;AAEH,MAAM,6BAA6B,GAAG,CACrC,QAAc,EACd,IAAa,EACH,EAAE;IACZ,IAAI,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC;IACrC,IAAI,IAAI,GAAmB,IAAI,CAAC;IAChC,OAAO,OAAO,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAChE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC9C,IACC,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC;YACnC,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,EAChC,CAAC;YACF,IAAI,GAAG,OAAO,CAAC;YACf,MAAM;QACP,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,IAAI,IAAI,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,OAAgB,EAAW,EAAE,CACtD,OAAO,CACN,OAAO,OAAO,CAAC,aAAa,KAAK,UAAU;IAC1C,OAAO,CAAC,aAAa,CACpB,iEAAiE,CACjE,CACF;IACD,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,MAAM;IACzC,OAAO,CAAC,YAAY,EAAE,CAAC,aAAa,CAAC;IACrC,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAE3B,MAAM,eAAe,GAAG,CACvB,GAAoB,EACpB,SAAiB,EACjB,OAA8C,EACvC,EAAE;IACT,IACC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;QAC1B,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QACpB,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,EACtC,CAAC;QACF,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,QAAQ,EAAE,CAAC;QACf,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IACD,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1B,IAAI,OAAO,EAAE,CAAC;QACb,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnC,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC;IAC1B,CAAC;SAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QAC3B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;IACD,GAAG,CAAC,QAAQ,EAAE,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CACjC,GAAoB,EACpB,aAAqB,EACX,EAAE;IACZ,IACC,GAAG,CAAC,mBAAmB;QACvB,GAAG,CAAC,qBAAqB;QACzB,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EACrB,CAAC;QACF,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACjD,6EAA6E;IAC7E,4EAA4E;IAC5E,8DAA8D;IAC9D,OAAO,6BAA6B,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;AAC5E,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,GAAoB,EAAE,QAAc,EAAQ,EAAE;IACrE,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC;IACvC,IAAI,2BAA2B,GAAG,KAAK,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,GAAG,CAAC,mBAAmB,EAAE,CAAC;YAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;gBACnB,GAAG,CAAC,mBAAmB,GAAG,KAAK,CAAC;gBAChC,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC/D,2BAA2B,GAAG,IAAI,CAAC;gBACnC,GAAG,CAAC,qBAAqB,GAAG,KAAK,CAAC;YACnC,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC;gBAChC,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,GAAG,CAAC,qBAAqB,GAAG,IAAI,CAAC;YACjC,SAAS;QACV,CAAC;QACD,IACC,CAAC,2BAA2B;YAC5B,yBAAyB,CAAC,GAAG,EAAE,SAAS,CAAC,EACxC,CAAC;YACF,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/D,2BAA2B,GAAG,IAAI,CAAC;QACnC,GAAG,CAAC,qBAAqB,GAAG,KAAK,CAAC;IACnC,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAC3B,GAAoB,EACpB,SAAmD,EAC5C,EAAE;IACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QAC7C,MAAM,aAAa,GAAG,OAAO,EAAE,IAAI,IAAI,GAAG,CAAC,UAAU,EAAE,IAAI,IAAI,IAAI,CAAC;QACpE,MAAM,eAAe,GAAG,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC,CAAC;QACvE,MAAM,iBAAiB,GAAG,OAAO;YAChC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;YAChD,CAAC,CAAC,aAAa;gBACd,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE;gBAClD,CAAC,CAAC,IAAI,CAAC;QACT,IAAI,GAAG,CAAC,mBAAmB,EAAE,CAAC;YAC7B,IAAI,YAAY;gBAAE,SAAS;YAC3B,GAAG,CAAC,mBAAmB,GAAG,KAAK,CAAC;QACjC,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC;gBAChC,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;YAC9C,CAAC;YACD,GAAG,CAAC,qBAAqB,GAAG,IAAI,CAAC;YACjC,SAAS;QACV,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,yBAAyB,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,CAAC;YAC1D,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAC9C,CAAC;QACD,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC;QACnD,GAAG,CAAC,qBAAqB,GAAG,KAAK,CAAC;QAClC,IAAI,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE;gBAC7B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM;aACtB,CAAC,CAAC;YACH,GAAG,CAAC,UAAU,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACjE,CAAC;aAAM,IAAI,aAAa,EAAE,CAAC;YAC1B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE;gBAC7B,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,eAAe;aACvB,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,MAAc,EAAU,EAAE;IACzD,IAAI,OAAO,SAAS,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC1E,IAAI,MAAM,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACrE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,CAAC,IAAU,EAAQ,EAAE;QAClC,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,IAAI,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,OAAO;QACR,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,OAAO,GAAG,IAAe,CAAC;QAChC,IAAI,mBAAmB,CAAC,OAAO,CAAC;YAAE,OAAO;QACzC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACF,CAAC,CAAC;IACF,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC9B,OAAO,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,0BAA0B,GAAG,CAClC,OAAgB,EAChB,eAAuB,EACvB,OAA+B,EACY,EAAE;IAC7C,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,CAAC,IAAU,EAAQ,EAAE;QAClC,IAAI,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC;YAAE,OAAO;QAC9C,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACzB,cAAc,CAAC,OAAO,EAAE,IAAY,CAAC,CAAC;YACtC,OAAO;QACR,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,YAAY,GAAG,IAAe,CAAC;QACrC,IACC,sBAAsB,CAAC,YAAY,CAAC;YACpC,mBAAmB,CAAC,YAAY,CAAC,EAChC,CAAC;YACF,OAAO;QACR,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;YACzD,KAAK,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACF,CAAC,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,CAAC;IACf,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,sBAAsB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5D,IAAI,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;IACnC,CAAC;IACD,MAAM,YAAY,GAAG,sBAAsB,CAAC,eAAe,CAAC,CAAC;IAC7D,IAAI,CAAC,YAAY,EAAE,CAAC;QACnB,OAAO,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IACD,OAAO;QACN,IAAI,EAAE,YAAY;QAClB,GAAG,EAAE,IAAI,GAAG,EAAE;KACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,GAAoB,EAAQ,EAAE;IAC7D,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,QAAQ,EAAE,CAAC;QACf,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CACxB,IAAa,EACb,OAA+B,EACT,EAAE;IACxB,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,sBAA2C,CAAC;IAChD,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAE/B,MAAM,cAAc,GAAG,GAAG,EAAE;QAC3B,MAAM,IAAI,GAAG,sBAAsB,CAClC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAC1D,CAAC;QACF,IAAI,IAAI,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM;gBACZ,IAAI;gBACJ,aAAa,EAAE,sBAAsB;aACrC,CAAC,CAAC;QACJ,CAAC;QACD,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QAClC,sBAAsB,GAAG,SAAS,CAAC;IACpC,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,IAAU,EAAQ,EAAE;QACxC,IAAI,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE,OAAO;QAC3C,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,MAAM,aAAa,GAAG,6BAA6B,CAAC,IAAY,EAAE,IAAI,CAAC,CAAC;YACxE,IAAI,sBAAsB,IAAI,aAAa,KAAK,sBAAsB,EAAE,CAAC;gBACxE,cAAc,EAAE,CAAC;YAClB,CAAC;YACD,sBAAsB,GAAG,aAAa,CAAC;YACvC,cAAc,CAAC,GAAG,EAAE,IAAY,CAAC,CAAC;YAClC,OAAO;QACR,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY;YAAE,OAAO;QAChD,MAAM,OAAO,GAAG,IAAe,CAAC;QAChC,IAAI,sBAAsB,CAAC,OAAO,CAAC;YAAE,OAAO;QAC5C,MAAM,eAAe,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,eAAe,EAAE,CAAC;YACrB,cAAc,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,0BAA0B,CAC3C,OAAO,EACP,eAAe,EACf,OAAO,CACP,CAAC;YACF,mBAAmB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACpC,MAAM,YAAY,GAAG,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC5D,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,eAAe;gBACvB,YAAY;gBACZ,aAAa,EAAE,OAAO;aACtB,CAAC,CAAC;YACH,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;YAClC,kBAAkB,GAAG,IAAI,CAAC;YAC1B,OAAO;QACR,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACpD,WAAW,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACF,CAAC,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACjD,WAAW,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC5B,cAAc,EAAE,CAAC;IACjB,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvC,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IACD,OAAO;QACN,WAAW;QACX,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,MAAM;QACN,kBAAkB;KAClB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACzC,OAAgB,EAChB,OAA+B,EACT,EAAE;IACxB,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjE,OAAO;YACN,WAAW,EAAE,IAAI;YACjB,GAAG;YACH,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;YAC5C,kBAAkB,EAAE,KAAK;SACzB,CAAC;IACH,CAAC;IACD,OAAO,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC,CAAC","sourcesContent":["import { canonicalizeMathML } from \"./mathml-sanitization.js\";\nimport {\n\tcollectVisibleTextAndMap,\n\ttype NormalizedTextMap,\n\ttype TextProcessingOptions,\n\tisNodeHiddenForTTS,\n\tnormalizeTextForSpeech,\n\tshouldInsertWordBoundarySpace,\n} from \"./text-processing.js\";\n\nexport type MathAwareSpeechChunk =\n\t| {\n\t\t\ttype: \"text\";\n\t\t\ttext: string;\n\t\t\tsourceElement?: Element;\n\t }\n\t| {\n\t\t\ttype: \"math\";\n\t\t\tmathml: string;\n\t\t\tfallbackText: string;\n\t\t\tsourceElement?: Element;\n\t };\n\nexport interface MathAwareTextResult {\n\tvisibleText: string;\n\tmap: NormalizedTextMap;\n\tchunks: MathAwareSpeechChunk[];\n\tcontainsMathMarkup: boolean;\n}\n\ninterface TextAccumulator {\n\tchars: string[];\n\tmap: NormalizedTextMap;\n\tposition: number;\n\tinLeadingWhitespace: boolean;\n\tlastCharWasWhitespace: boolean;\n\tlastMapped: { node: Text; offset: number } | null;\n\toptions?: TextProcessingOptions;\n}\n\nconst createAccumulator = (\n\toptions?: TextProcessingOptions,\n): TextAccumulator => ({\n\tchars: [],\n\tmap: new Map(),\n\tposition: 0,\n\tinLeadingWhitespace: true,\n\tlastCharWasWhitespace: false,\n\tlastMapped: null,\n\toptions,\n});\n\nconst isMathJaxElement = (element: Element): boolean =>\n\telement.classList?.contains(\"MathJax\") ||\n\telement.tagName?.toLowerCase() === \"mjx-container\";\n\nconst isAssistiveMathElement = (element: Element): boolean =>\n\telement.tagName?.toLowerCase() === \"mjx-assistive-mml\";\n\nconst isAnnotationElement = (element: Element): boolean => {\n\tconst tagName = element.tagName?.toLowerCase();\n\treturn tagName === \"annotation\" || tagName === \"annotation-xml\";\n};\n\nconst getDataMathML = (element: Element): string | null => {\n\tconst value = element.getAttribute(\"data-mathml\");\n\treturn value && value.trim() ? value : null;\n};\n\nconst findAssistiveMathML = (element: Element): string | null => {\n\tconst assistive = element.querySelector(\"mjx-assistive-mml math\");\n\treturn assistive?.outerHTML || null;\n};\n\nconst findCanonicalMathML = (element: Element): string | null => {\n\tif (element.tagName.toLowerCase() === \"math\") {\n\t\treturn canonicalizeMathML(element.outerHTML);\n\t}\n\tconst dataMath = getDataMathML(element);\n\tif (dataMath) {\n\t\tconst canonical = canonicalizeMathML(dataMath);\n\t\tif (canonical) return canonical;\n\t}\n\tif (isMathJaxElement(element)) {\n\t\tconst assistive = findAssistiveMathML(element);\n\t\tif (assistive) {\n\t\t\tconst canonical = canonicalizeMathML(assistive);\n\t\t\tif (canonical) return canonical;\n\t\t}\n\t}\n\treturn null;\n};\n\nconst isMathContainer = (element: Element): boolean =>\n\tBoolean(findCanonicalMathML(element));\n\nconst TEXT_CHUNK_SOURCE_TAGS = new Set([\n\t\"P\",\n\t\"H1\",\n\t\"H2\",\n\t\"H3\",\n\t\"H4\",\n\t\"H5\",\n\t\"H6\",\n\t\"LI\",\n\t\"TD\",\n\t\"TH\",\n\t\"DD\",\n\t\"DT\",\n\t\"FIGCAPTION\",\n\t\"LABEL\",\n\t\"BUTTON\",\n]);\n\nconst TEXT_CHUNK_SOURCE_ROLES = new Set([\n\t\"heading\",\n\t\"listitem\",\n\t\"option\",\n\t\"radio\",\n\t\"row\",\n\t\"cell\",\n\t\"columnheader\",\n\t\"rowheader\",\n]);\n\nconst resolveTextChunkSourceElement = (\n\ttextNode: Text,\n\troot: Element,\n): Element => {\n\tlet current = textNode.parentElement;\n\tlet best: Element | null = null;\n\twhile (current && current !== root) {\n\t\tconst role = (current.getAttribute(\"role\") || \"\").toLowerCase();\n\t\tconst tagName = current.tagName.toUpperCase();\n\t\tif (\n\t\t\tTEXT_CHUNK_SOURCE_TAGS.has(tagName) ||\n\t\t\tTEXT_CHUNK_SOURCE_ROLES.has(role)\n\t\t) {\n\t\t\tbest = current;\n\t\t\tbreak;\n\t\t}\n\t\tcurrent = current.parentElement;\n\t}\n\treturn best || root;\n};\n\nconst hasMathCandidate = (element: Element): boolean =>\n\tBoolean(\n\t\ttypeof element.querySelector === \"function\" &&\n\t\t\telement.querySelector(\n\t\t\t\t\"math, [data-mathml], .MathJax, mjx-container, mjx-assistive-mml\",\n\t\t\t),\n\t) ||\n\telement.tagName?.toLowerCase() === \"math\" ||\n\telement.hasAttribute?.(\"data-mathml\") ||\n\tisMathJaxElement(element);\n\nconst appendCharacter = (\n\tacc: TextAccumulator,\n\tcharacter: string,\n\tmapping: { node: Text; offset: number } | null,\n): void => {\n\tif (\n\t\t/[.,;:!?]/.test(character) &&\n\t\tacc.chars.length > 0 &&\n\t\tacc.chars[acc.chars.length - 1] === \" \"\n\t) {\n\t\tacc.chars.pop();\n\t\tacc.position--;\n\t\tacc.map.delete(acc.position);\n\t}\n\tacc.chars.push(character);\n\tif (mapping) {\n\t\tacc.map.set(acc.position, mapping);\n\t\tacc.lastMapped = mapping;\n\t} else if (acc.lastMapped) {\n\t\tacc.map.set(acc.position, acc.lastMapped);\n\t}\n\tacc.position++;\n};\n\nconst shouldInsertBoundarySpace = (\n\tacc: TextAccumulator,\n\tnextCharacter: string,\n): boolean => {\n\tif (\n\t\tacc.inLeadingWhitespace ||\n\t\tacc.lastCharWasWhitespace ||\n\t\tacc.chars.length === 0\n\t) {\n\t\treturn false;\n\t}\n\tconst previous = acc.chars[acc.chars.length - 1];\n\t// Defer to the shared locale-aware decision (Intl.Segmenter, falling back to\n\t// alnum) so adjacent text nodes split into words consistently with the main\n\t// visible-text collector, instead of an ASCII-only heuristic.\n\treturn shouldInsertWordBoundarySpace(previous, nextCharacter, acc.options);\n};\n\nconst appendTextNode = (acc: TextAccumulator, textNode: Text): void => {\n\tconst raw = textNode.textContent || \"\";\n\tlet appendedNonWhitespaceInNode = false;\n\tfor (let i = 0; i < raw.length; i++) {\n\t\tconst character = raw[i];\n\t\tconst isWhitespace = /\\s/.test(character);\n\t\tif (acc.inLeadingWhitespace) {\n\t\t\tif (!isWhitespace) {\n\t\t\t\tacc.inLeadingWhitespace = false;\n\t\t\t\tappendCharacter(acc, character, { node: textNode, offset: i });\n\t\t\t\tappendedNonWhitespaceInNode = true;\n\t\t\t\tacc.lastCharWasWhitespace = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (isWhitespace) {\n\t\t\tif (!acc.lastCharWasWhitespace) {\n\t\t\t\tappendCharacter(acc, \" \", { node: textNode, offset: i });\n\t\t\t}\n\t\t\tacc.lastCharWasWhitespace = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\t!appendedNonWhitespaceInNode &&\n\t\t\tshouldInsertBoundarySpace(acc, character)\n\t\t) {\n\t\t\tappendCharacter(acc, \" \", { node: textNode, offset: i });\n\t\t}\n\t\tappendCharacter(acc, character, { node: textNode, offset: i });\n\t\tappendedNonWhitespaceInNode = true;\n\t\tacc.lastCharWasWhitespace = false;\n\t}\n};\n\nconst appendCollectedText = (\n\tacc: TextAccumulator,\n\tcollected: { text: string; map: NormalizedTextMap },\n): void => {\n\tfor (let i = 0; i < collected.text.length; i++) {\n\t\tconst character = collected.text[i];\n\t\tconst isWhitespace = /\\s/.test(character);\n\t\tconst mapping = collected.map.get(i) || null;\n\t\tconst syntheticNode = mapping?.node || acc.lastMapped?.node || null;\n\t\tconst syntheticOffset = mapping?.offset ?? acc.lastMapped?.offset ?? 0;\n\t\tconst normalizedMapping = mapping\n\t\t\t? { node: mapping.node, offset: mapping.offset }\n\t\t\t: syntheticNode\n\t\t\t\t? { node: syntheticNode, offset: syntheticOffset }\n\t\t\t\t: null;\n\t\tif (acc.inLeadingWhitespace) {\n\t\t\tif (isWhitespace) continue;\n\t\t\tacc.inLeadingWhitespace = false;\n\t\t}\n\t\tif (isWhitespace) {\n\t\t\tif (!acc.lastCharWasWhitespace) {\n\t\t\t\tappendCharacter(acc, \" \", normalizedMapping);\n\t\t\t}\n\t\t\tacc.lastCharWasWhitespace = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (i === 0 && shouldInsertBoundarySpace(acc, character)) {\n\t\t\tappendCharacter(acc, \" \", normalizedMapping);\n\t\t}\n\t\tappendCharacter(acc, character, normalizedMapping);\n\t\tacc.lastCharWasWhitespace = false;\n\t\tif (mapping) {\n\t\t\tacc.map.set(acc.position - 1, {\n\t\t\t\tnode: mapping.node,\n\t\t\t\toffset: mapping.offset,\n\t\t\t});\n\t\t\tacc.lastMapped = { node: mapping.node, offset: mapping.offset };\n\t\t} else if (syntheticNode) {\n\t\t\tacc.map.set(acc.position - 1, {\n\t\t\t\tnode: syntheticNode,\n\t\t\t\toffset: syntheticOffset,\n\t\t\t});\n\t\t}\n\t}\n};\n\nconst textFallbackFromMathML = (mathml: string): string => {\n\tif (typeof DOMParser === \"undefined\") return \"\";\n\tconst parsed = new DOMParser().parseFromString(mathml, \"application/xml\");\n\tif (parsed.getElementsByTagName(\"parsererror\").length > 0) return \"\";\n\tconst parts: string[] = [];\n\tconst visit = (node: Node): void => {\n\t\tif (node.nodeType === 3) {\n\t\t\tconst text = node.textContent || \"\";\n\t\t\tif (text.trim()) parts.push(text);\n\t\t\treturn;\n\t\t}\n\t\tif (node.nodeType !== 1) return;\n\t\tconst element = node as Element;\n\t\tif (isAnnotationElement(element)) return;\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tvisit(child);\n\t\t}\n\t};\n\tvisit(parsed.documentElement);\n\treturn normalizeTextForSpeech(parts.join(\" \"));\n};\n\nconst collectVisibleMathFallback = (\n\telement: Element,\n\tcanonicalMathML: string,\n\toptions?: TextProcessingOptions,\n): { text: string; map: NormalizedTextMap } => {\n\tconst mathAcc = createAccumulator(options);\n\tconst visit = (node: Node): void => {\n\t\tif (isNodeHiddenForTTS(node, element)) return;\n\t\tif (node.nodeType === 3) {\n\t\t\tappendTextNode(mathAcc, node as Text);\n\t\t\treturn;\n\t\t}\n\t\tif (node.nodeType !== 1) return;\n\t\tconst childElement = node as Element;\n\t\tif (\n\t\t\tisAssistiveMathElement(childElement) ||\n\t\t\tisAnnotationElement(childElement)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const child of Array.from(childElement.childNodes)) {\n\t\t\tvisit(child);\n\t\t}\n\t};\n\tvisit(element);\n\ttrimTrailingWhitespace(mathAcc);\n\tconst text = normalizeTextForSpeech(mathAcc.chars.join(\"\"));\n\tif (text) {\n\t\treturn { text, map: mathAcc.map };\n\t}\n\tconst fallbackText = textFallbackFromMathML(canonicalMathML);\n\tif (!fallbackText) {\n\t\treturn collectVisibleTextAndMap(element, options);\n\t}\n\treturn {\n\t\ttext: fallbackText,\n\t\tmap: new Map(),\n\t};\n};\n\nconst trimTrailingWhitespace = (acc: TextAccumulator): void => {\n\twhile (acc.chars.length > 0 && /\\s/.test(acc.chars[acc.chars.length - 1])) {\n\t\tacc.chars.pop();\n\t\tacc.position--;\n\t\tacc.map.delete(acc.position);\n\t}\n};\n\nconst collectMathAware = (\n\troot: Element,\n\toptions?: TextProcessingOptions,\n): MathAwareTextResult => {\n\tconst acc = createAccumulator(options);\n\tconst chunks: MathAwareSpeechChunk[] = [];\n\tlet textChunkStart = 0;\n\tlet textChunkSourceElement: Element | undefined;\n\tlet containsMathMarkup = false;\n\n\tconst flushTextChunk = () => {\n\t\tconst text = normalizeTextForSpeech(\n\t\t\tacc.chars.slice(textChunkStart, acc.chars.length).join(\"\"),\n\t\t);\n\t\tif (text) {\n\t\t\tchunks.push({\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext,\n\t\t\t\tsourceElement: textChunkSourceElement,\n\t\t\t});\n\t\t}\n\t\ttextChunkStart = acc.chars.length;\n\t\ttextChunkSourceElement = undefined;\n\t};\n\n\tconst processNode = (node: Node): void => {\n\t\tif (isNodeHiddenForTTS(node, root)) return;\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst sourceElement = resolveTextChunkSourceElement(node as Text, root);\n\t\t\tif (textChunkSourceElement && sourceElement !== textChunkSourceElement) {\n\t\t\t\tflushTextChunk();\n\t\t\t}\n\t\t\ttextChunkSourceElement = sourceElement;\n\t\t\tappendTextNode(acc, node as Text);\n\t\t\treturn;\n\t\t}\n\t\tif (node.nodeType !== Node.ELEMENT_NODE) return;\n\t\tconst element = node as Element;\n\t\tif (isAssistiveMathElement(element)) return;\n\t\tconst canonicalMathML = findCanonicalMathML(element);\n\t\tif (canonicalMathML) {\n\t\t\tflushTextChunk();\n\t\t\tconst collected = collectVisibleMathFallback(\n\t\t\t\telement,\n\t\t\t\tcanonicalMathML,\n\t\t\t\toptions,\n\t\t\t);\n\t\t\tappendCollectedText(acc, collected);\n\t\t\tconst fallbackText = normalizeTextForSpeech(collected.text);\n\t\t\tchunks.push({\n\t\t\t\ttype: \"math\",\n\t\t\t\tmathml: canonicalMathML,\n\t\t\t\tfallbackText,\n\t\t\t\tsourceElement: element,\n\t\t\t});\n\t\t\ttextChunkStart = acc.chars.length;\n\t\t\tcontainsMathMarkup = true;\n\t\t\treturn;\n\t\t}\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tprocessNode(child);\n\t\t}\n\t};\n\n\tfor (const child of Array.from(root.childNodes)) {\n\t\tprocessNode(child);\n\t}\n\n\ttrimTrailingWhitespace(acc);\n\tflushTextChunk();\n\tconst visibleText = acc.chars.join(\"\");\n\twhile (acc.map.has(visibleText.length)) {\n\t\tacc.map.delete(visibleText.length);\n\t}\n\treturn {\n\t\tvisibleText,\n\t\tmap: acc.map,\n\t\tchunks,\n\t\tcontainsMathMarkup,\n\t};\n};\n\nexport const collectMathAwareTextAndMap = (\n\telement: Element,\n\toptions?: TextProcessingOptions,\n): MathAwareTextResult => {\n\tif (!hasMathCandidate(element)) {\n\t\tconst { text, map } = collectVisibleTextAndMap(element, options);\n\t\treturn {\n\t\t\tvisibleText: text,\n\t\t\tmap,\n\t\t\tchunks: text ? [{ type: \"text\", text }] : [],\n\t\t\tcontainsMathMarkup: false,\n\t\t};\n\t}\n\treturn collectMathAware(element, options);\n};\n"]}
|
|
@@ -45,7 +45,9 @@ const setupSre = async (sre, language, markup, mathSpeech) => {
|
|
|
45
45
|
...(normalizedMathSpeech?.engineOptions || {}),
|
|
46
46
|
locale,
|
|
47
47
|
domain: normalizedMathSpeech?.domain || domainForLocale(locale),
|
|
48
|
-
...(normalizedMathSpeech?.style
|
|
48
|
+
...(normalizedMathSpeech?.style
|
|
49
|
+
? { style: normalizedMathSpeech.style }
|
|
50
|
+
: {}),
|
|
49
51
|
modality: "speech",
|
|
50
52
|
markup,
|
|
51
53
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"math-speech.js","sourceRoot":"","sources":["../../../src/services/tts/math-speech.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MathAwareSpeechChunk } from \"./math-aware-text-processing.js\";\nimport { normalizeTextForSpeech } from \"./text-processing.js\";\n\ninterface SpeechRuleEngineApi {\n\tsetupEngine?: (options: Record<string, unknown>) => Promise<void> | void;\n\tengineReady?: () => Promise<void>;\n\ttoSpeech: (mathml: string) => string;\n}\n\nexport interface ResolveMathSpeechOptions {\n\tlanguage?: string;\n\tloadSre?: () => Promise<SpeechRuleEngineApi>;\n\t/**\n\t * Optional SRE configuration supplied by the host. This deliberately exposes\n\t * SRE's own knobs instead of adding toolkit speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n\t/**\n\t * Also produce SRE's SSML rendering (markup: \"ssml\") for the equation, for\n\t * the runtime generated-SSML path (PIE-623). Only populated when the input\n\t * is a single math chunk and SRE succeeds. The plain `speechText` is always\n\t * computed with markup: \"none\" so the plain path is unaffected.\n\t */\n\tproduceSsml?: boolean;\n}\n\nexport interface SREMathSpeechOptions {\n\t/** SRE domain, e.g. \"clearspeak\" or \"mathspeak\". Defaults by locale. */\n\tdomain?: string;\n\t/** Raw SRE style/preference string. ClearSpeak preferences are \":\"-joined. */\n\tstyle?: string;\n\t/** Extra SRE setupEngine options for hosts that need a newly exposed SRE knob. */\n\tengineOptions?: Record<string, unknown>;\n}\n\nexport interface ResolvedMathSpeech {\n\tspeechText: string;\n\tusedMathSpeech: boolean;\n\tusedFallback: boolean;\n\t/**\n\t * SRE SSML rendering of the equation (a self-contained `<speak>` document),\n\t * present only when `produceSsml` was requested for a single math chunk and\n\t * SRE produced trackable SSML.\n\t */\n\tssml?: string;\n}\n\nlet sreLoadPromise: Promise<SpeechRuleEngineApi> | null = null;\nlet sreOperationQueue: Promise<unknown> = Promise.resolve();\n\nconst normalizeLocale = (language?: string): string =>\n\t(language || \"en\").split(\"-\")[0].toLowerCase() || \"en\";\n\nconst defaultLoadSre = async (): Promise<SpeechRuleEngineApi> => {\n\tif (!sreLoadPromise) {\n\t\tsreLoadPromise = import(\"speech-rule-engine\").then((module) => {\n\t\t\tconst candidate =\n\t\t\t\t(module as { default?: SpeechRuleEngineApi }).default ||\n\t\t\t\t(module as unknown as SpeechRuleEngineApi);\n\t\t\tif (!candidate || typeof candidate.toSpeech !== \"function\") {\n\t\t\t\tthrow new Error(\"speech-rule-engine did not expose toSpeech\");\n\t\t\t}\n\t\t\treturn candidate;\n\t\t});\n\t}\n\treturn sreLoadPromise;\n};\n\n// SRE's ClearSpeak rule set is English-only; MathSpeak is localized to many more\n// locales. Use ClearSpeak for English (highest-quality math prose) and MathSpeak\n// elsewhere, so non-English content gets locale-appropriate voicing instead of\n// silently falling back to English ClearSpeak rules.\nconst domainForLocale = (locale: string): string =>\n\tlocale === \"en\" ? \"clearspeak\" : \"mathspeak\";\n\nconst isPlainRecord = (value: unknown): value is Record<string, unknown> =>\n\t!!value && typeof value === \"object\" && !Array.isArray(value);\n\nconst trimOption = (value: unknown): string | undefined =>\n\ttypeof value === \"string\" && value.trim() ? value.trim() : undefined;\n\nexport const normalizeSREMathSpeechOptions = (\n\toptions: unknown,\n): SREMathSpeechOptions | undefined => {\n\tif (!isPlainRecord(options)) return undefined;\n\tconst domain = trimOption(options.domain);\n\tconst style = trimOption(options.style);\n\tconst engineOptions = isPlainRecord(options.engineOptions)\n\t\t? options.engineOptions\n\t\t: undefined;\n\tif (!domain && !style && !engineOptions) return undefined;\n\treturn {\n\t\t...(domain ? { domain } : {}),\n\t\t...(style ? { style } : {}),\n\t\t...(engineOptions ? { engineOptions } : {}),\n\t};\n};\n\nconst setupSre = async (\n\tsre: SpeechRuleEngineApi,\n\tlanguage: string | undefined,\n\tmarkup: \"none\" | \"ssml\",\n\tmathSpeech?: SREMathSpeechOptions,\n): Promise<void> => {\n\tconst locale = normalizeLocale(language);\n\tconst normalizedMathSpeech = normalizeSREMathSpeechOptions(mathSpeech);\n\tawait sre.setupEngine?.({\n\t\t...(normalizedMathSpeech?.engineOptions || {}),\n\t\tlocale,\n\t\tdomain: normalizedMathSpeech?.domain || domainForLocale(locale),\n\t\t...(normalizedMathSpeech?.style ? { style: normalizedMathSpeech.style } : {}),\n\t\tmodality: \"speech\",\n\t\tmarkup,\n\t});\n\tawait sre.engineReady?.();\n};\n\nconst runSerializedSreOperation = async <T>(\n\toperation: () => Promise<T>,\n): Promise<T> => {\n\tconst result = sreOperationQueue.then(operation, operation);\n\tsreOperationQueue = result.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\treturn result;\n};\n\nconst toSpeechWithSreSettings = async (\n\tsre: SpeechRuleEngineApi,\n\tmathml: string,\n\tlanguage: string | undefined,\n\tmarkup: \"none\" | \"ssml\",\n\tmathSpeech?: SREMathSpeechOptions,\n): Promise<string> =>\n\trunSerializedSreOperation(async () => {\n\t\tawait setupSre(sre, language, markup, mathSpeech);\n\t\treturn sre.toSpeech(mathml);\n\t});\n\n// SRE's SSML rendering wraps the spoken words in highlight-safe structural tags\n// (`speak`, `prosody`, `say-as interpret-as=\"character\"`, `break`), all handled\n// by `extractSpokenText`, so word-boundary offsets into the raw SSML still map\n// back to spoken tokens. SRE also prepends an XML prolog (`<?xml …?>`); AWS\n// Polly and Google Cloud TTS reject SSML that does not begin with `<speak>`, so\n// we strip the prolog here. The stripped string is the single source of truth:\n// it is both what the provider receives and what the alignment tokenizes, so\n// offsets stay consistent. We only accept output that contains a `<speak>`\n// element, so a bad/empty render degrades to plain text.\nconst stripXmlProlog = (ssml: string): string =>\n\tssml.replace(/^\\s*<\\?xml[^>]*\\?>\\s*/i, \"\");\n\nconst generateMathSsml = async (\n\tsre: SpeechRuleEngineApi,\n\tmathml: string,\n\tlanguage?: string,\n\tmathSpeech?: SREMathSpeechOptions,\n): Promise<string | null> => {\n\ttry {\n\t\tconst ssml = stripXmlProlog(\n\t\t\tawait toSpeechWithSreSettings(sre, mathml, language, \"ssml\", mathSpeech),\n\t\t);\n\t\treturn ssml.includes(\"<speak\") ? ssml : null;\n\t} catch (error) {\n\t\tconsole.debug(\"[TTSService] Math SSML generation failed; using plain\", {\n\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t});\n\t\treturn null;\n\t}\n};\n\nexport const resolveMathSpeechFromChunks = async (\n\tchunks: MathAwareSpeechChunk[],\n\toptions: ResolveMathSpeechOptions = {},\n): Promise<ResolvedMathSpeech> => {\n\tif (!chunks.some((chunk) => chunk.type === \"math\")) {\n\t\treturn {\n\t\t\tspeechText: normalizeTextForSpeech(\n\t\t\t\tchunks\n\t\t\t\t\t.map((chunk) =>\n\t\t\t\t\t\tchunk.type === \"text\" ? chunk.text : chunk.fallbackText,\n\t\t\t\t\t)\n\t\t\t\t\t.join(\" \"),\n\t\t\t),\n\t\t\tusedMathSpeech: false,\n\t\t\tusedFallback: false,\n\t\t};\n\t}\n\n\tlet sre: SpeechRuleEngineApi | null = null;\n\tlet usedMathSpeech = false;\n\tlet usedFallback = false;\n\tconst loadSre = options.loadSre || defaultLoadSre;\n\tconst speechParts: string[] = [];\n\n\tfor (const chunk of chunks) {\n\t\tif (chunk.type === \"text\") {\n\t\t\tspeechParts.push(chunk.text);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tif (!sre) {\n\t\t\t\tsre = await loadSre();\n\t\t\t}\n\t\t\tconst speech = normalizeTextForSpeech(\n\t\t\t\tawait toSpeechWithSreSettings(\n\t\t\t\t\tsre,\n\t\t\t\t\tchunk.mathml,\n\t\t\t\t\toptions.language,\n\t\t\t\t\t\"none\",\n\t\t\t\t\toptions.mathSpeech,\n\t\t\t\t),\n\t\t\t);\n\t\t\tif (speech) {\n\t\t\t\tspeechParts.push(speech);\n\t\t\t\tusedMathSpeech = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tusedFallback = true;\n\t\t\tspeechParts.push(chunk.fallbackText);\n\t\t} catch (error) {\n\t\t\tusedFallback = true;\n\t\t\tconsole.debug(\n\t\t\t\t\"[TTSService] Math speech generation failed; using visible fallback\",\n\t\t\t\t{\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t},\n\t\t\t);\n\t\t\tspeechParts.push(chunk.fallbackText);\n\t\t}\n\t}\n\n\t// Generated-SSML path: only meaningful for a single math chunk (the runtime\n\t// composes one chunk per equation). Computed after the plain pass so the\n\t// markup: \"none\" `speechText` above is unchanged. The \"none\" → \"ssml\"\n\t// engine reconfiguration happens sequentially within this call.\n\tconst speechText = normalizeTextForSpeech(speechParts.join(\" \"));\n\tlet ssml: string | undefined;\n\tif (\n\t\toptions.produceSsml &&\n\t\tsre &&\n\t\tusedMathSpeech &&\n\t\tchunks.length === 1 &&\n\t\tchunks[0].type === \"math\"\n\t) {\n\t\tconst generated = await generateMathSsml(\n\t\t\tsre,\n\t\t\tchunks[0].mathml,\n\t\t\toptions.language,\n\t\t\toptions.mathSpeech,\n\t\t);\n\t\tssml = generated ?? undefined;\n\t}\n\n\treturn {\n\t\tspeechText,\n\t\tusedMathSpeech,\n\t\tusedFallback,\n\t\tssml,\n\t};\n};\n"]}
|
|
1
|
+
{"version":3,"file":"math-speech.js","sourceRoot":"","sources":["../../../src/services/tts/math-speech.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MathAwareSpeechChunk } from \"./math-aware-text-processing.js\";\nimport { normalizeTextForSpeech } from \"./text-processing.js\";\n\ninterface SpeechRuleEngineApi {\n\tsetupEngine?: (options: Record<string, unknown>) => Promise<void> | void;\n\tengineReady?: () => Promise<void>;\n\ttoSpeech: (mathml: string) => string;\n}\n\nexport interface ResolveMathSpeechOptions {\n\tlanguage?: string;\n\tloadSre?: () => Promise<SpeechRuleEngineApi>;\n\t/**\n\t * Optional SRE configuration supplied by the host. This deliberately exposes\n\t * SRE's own knobs instead of adding toolkit speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n\t/**\n\t * Also produce SRE's SSML rendering (markup: \"ssml\") for the equation, for\n\t * the runtime generated-SSML path (PIE-623). Only populated when the input\n\t * is a single math chunk and SRE succeeds. The plain `speechText` is always\n\t * computed with markup: \"none\" so the plain path is unaffected.\n\t */\n\tproduceSsml?: boolean;\n}\n\nexport interface SREMathSpeechOptions {\n\t/** SRE domain, e.g. \"clearspeak\" or \"mathspeak\". Defaults by locale. */\n\tdomain?: string;\n\t/** Raw SRE style/preference string. ClearSpeak preferences are \":\"-joined. */\n\tstyle?: string;\n\t/** Extra SRE setupEngine options for hosts that need a newly exposed SRE knob. */\n\tengineOptions?: Record<string, unknown>;\n}\n\nexport interface ResolvedMathSpeech {\n\tspeechText: string;\n\tusedMathSpeech: boolean;\n\tusedFallback: boolean;\n\t/**\n\t * SRE SSML rendering of the equation (a self-contained `<speak>` document),\n\t * present only when `produceSsml` was requested for a single math chunk and\n\t * SRE produced trackable SSML.\n\t */\n\tssml?: string;\n}\n\nlet sreLoadPromise: Promise<SpeechRuleEngineApi> | null = null;\nlet sreOperationQueue: Promise<unknown> = Promise.resolve();\n\nconst normalizeLocale = (language?: string): string =>\n\t(language || \"en\").split(\"-\")[0].toLowerCase() || \"en\";\n\nconst defaultLoadSre = async (): Promise<SpeechRuleEngineApi> => {\n\tif (!sreLoadPromise) {\n\t\tsreLoadPromise = import(\"speech-rule-engine\").then((module) => {\n\t\t\tconst candidate =\n\t\t\t\t(module as { default?: SpeechRuleEngineApi }).default ||\n\t\t\t\t(module as unknown as SpeechRuleEngineApi);\n\t\t\tif (!candidate || typeof candidate.toSpeech !== \"function\") {\n\t\t\t\tthrow new Error(\"speech-rule-engine did not expose toSpeech\");\n\t\t\t}\n\t\t\treturn candidate;\n\t\t});\n\t}\n\treturn sreLoadPromise;\n};\n\n// SRE's ClearSpeak rule set is English-only; MathSpeak is localized to many more\n// locales. Use ClearSpeak for English (highest-quality math prose) and MathSpeak\n// elsewhere, so non-English content gets locale-appropriate voicing instead of\n// silently falling back to English ClearSpeak rules.\nconst domainForLocale = (locale: string): string =>\n\tlocale === \"en\" ? \"clearspeak\" : \"mathspeak\";\n\nconst isPlainRecord = (value: unknown): value is Record<string, unknown> =>\n\t!!value && typeof value === \"object\" && !Array.isArray(value);\n\nconst trimOption = (value: unknown): string | undefined =>\n\ttypeof value === \"string\" && value.trim() ? value.trim() : undefined;\n\nexport const normalizeSREMathSpeechOptions = (\n\toptions: unknown,\n): SREMathSpeechOptions | undefined => {\n\tif (!isPlainRecord(options)) return undefined;\n\tconst domain = trimOption(options.domain);\n\tconst style = trimOption(options.style);\n\tconst engineOptions = isPlainRecord(options.engineOptions)\n\t\t? options.engineOptions\n\t\t: undefined;\n\tif (!domain && !style && !engineOptions) return undefined;\n\treturn {\n\t\t...(domain ? { domain } : {}),\n\t\t...(style ? { style } : {}),\n\t\t...(engineOptions ? { engineOptions } : {}),\n\t};\n};\n\nconst setupSre = async (\n\tsre: SpeechRuleEngineApi,\n\tlanguage: string | undefined,\n\tmarkup: \"none\" | \"ssml\",\n\tmathSpeech?: SREMathSpeechOptions,\n): Promise<void> => {\n\tconst locale = normalizeLocale(language);\n\tconst normalizedMathSpeech = normalizeSREMathSpeechOptions(mathSpeech);\n\tawait sre.setupEngine?.({\n\t\t...(normalizedMathSpeech?.engineOptions || {}),\n\t\tlocale,\n\t\tdomain: normalizedMathSpeech?.domain || domainForLocale(locale),\n\t\t...(normalizedMathSpeech?.style\n\t\t\t? { style: normalizedMathSpeech.style }\n\t\t\t: {}),\n\t\tmodality: \"speech\",\n\t\tmarkup,\n\t});\n\tawait sre.engineReady?.();\n};\n\nconst runSerializedSreOperation = async <T>(\n\toperation: () => Promise<T>,\n): Promise<T> => {\n\tconst result = sreOperationQueue.then(operation, operation);\n\tsreOperationQueue = result.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\treturn result;\n};\n\nconst toSpeechWithSreSettings = async (\n\tsre: SpeechRuleEngineApi,\n\tmathml: string,\n\tlanguage: string | undefined,\n\tmarkup: \"none\" | \"ssml\",\n\tmathSpeech?: SREMathSpeechOptions,\n): Promise<string> =>\n\trunSerializedSreOperation(async () => {\n\t\tawait setupSre(sre, language, markup, mathSpeech);\n\t\treturn sre.toSpeech(mathml);\n\t});\n\n// SRE's SSML rendering wraps the spoken words in highlight-safe structural tags\n// (`speak`, `prosody`, `say-as interpret-as=\"character\"`, `break`), all handled\n// by `extractSpokenText`, so word-boundary offsets into the raw SSML still map\n// back to spoken tokens. SRE also prepends an XML prolog (`<?xml …?>`); AWS\n// Polly and Google Cloud TTS reject SSML that does not begin with `<speak>`, so\n// we strip the prolog here. The stripped string is the single source of truth:\n// it is both what the provider receives and what the alignment tokenizes, so\n// offsets stay consistent. We only accept output that contains a `<speak>`\n// element, so a bad/empty render degrades to plain text.\nconst stripXmlProlog = (ssml: string): string =>\n\tssml.replace(/^\\s*<\\?xml[^>]*\\?>\\s*/i, \"\");\n\nconst generateMathSsml = async (\n\tsre: SpeechRuleEngineApi,\n\tmathml: string,\n\tlanguage?: string,\n\tmathSpeech?: SREMathSpeechOptions,\n): Promise<string | null> => {\n\ttry {\n\t\tconst ssml = stripXmlProlog(\n\t\t\tawait toSpeechWithSreSettings(sre, mathml, language, \"ssml\", mathSpeech),\n\t\t);\n\t\treturn ssml.includes(\"<speak\") ? ssml : null;\n\t} catch (error) {\n\t\tconsole.debug(\"[TTSService] Math SSML generation failed; using plain\", {\n\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t});\n\t\treturn null;\n\t}\n};\n\nexport const resolveMathSpeechFromChunks = async (\n\tchunks: MathAwareSpeechChunk[],\n\toptions: ResolveMathSpeechOptions = {},\n): Promise<ResolvedMathSpeech> => {\n\tif (!chunks.some((chunk) => chunk.type === \"math\")) {\n\t\treturn {\n\t\t\tspeechText: normalizeTextForSpeech(\n\t\t\t\tchunks\n\t\t\t\t\t.map((chunk) =>\n\t\t\t\t\t\tchunk.type === \"text\" ? chunk.text : chunk.fallbackText,\n\t\t\t\t\t)\n\t\t\t\t\t.join(\" \"),\n\t\t\t),\n\t\t\tusedMathSpeech: false,\n\t\t\tusedFallback: false,\n\t\t};\n\t}\n\n\tlet sre: SpeechRuleEngineApi | null = null;\n\tlet usedMathSpeech = false;\n\tlet usedFallback = false;\n\tconst loadSre = options.loadSre || defaultLoadSre;\n\tconst speechParts: string[] = [];\n\n\tfor (const chunk of chunks) {\n\t\tif (chunk.type === \"text\") {\n\t\t\tspeechParts.push(chunk.text);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tif (!sre) {\n\t\t\t\tsre = await loadSre();\n\t\t\t}\n\t\t\tconst speech = normalizeTextForSpeech(\n\t\t\t\tawait toSpeechWithSreSettings(\n\t\t\t\t\tsre,\n\t\t\t\t\tchunk.mathml,\n\t\t\t\t\toptions.language,\n\t\t\t\t\t\"none\",\n\t\t\t\t\toptions.mathSpeech,\n\t\t\t\t),\n\t\t\t);\n\t\t\tif (speech) {\n\t\t\t\tspeechParts.push(speech);\n\t\t\t\tusedMathSpeech = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tusedFallback = true;\n\t\t\tspeechParts.push(chunk.fallbackText);\n\t\t} catch (error) {\n\t\t\tusedFallback = true;\n\t\t\tconsole.debug(\n\t\t\t\t\"[TTSService] Math speech generation failed; using visible fallback\",\n\t\t\t\t{\n\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t},\n\t\t\t);\n\t\t\tspeechParts.push(chunk.fallbackText);\n\t\t}\n\t}\n\n\t// Generated-SSML path: only meaningful for a single math chunk (the runtime\n\t// composes one chunk per equation). Computed after the plain pass so the\n\t// markup: \"none\" `speechText` above is unchanged. The \"none\" → \"ssml\"\n\t// engine reconfiguration happens sequentially within this call.\n\tconst speechText = normalizeTextForSpeech(speechParts.join(\" \"));\n\tlet ssml: string | undefined;\n\tif (\n\t\toptions.produceSsml &&\n\t\tsre &&\n\t\tusedMathSpeech &&\n\t\tchunks.length === 1 &&\n\t\tchunks[0].type === \"math\"\n\t) {\n\t\tconst generated = await generateMathSsml(\n\t\t\tsre,\n\t\t\tchunks[0].mathml,\n\t\t\toptions.language,\n\t\t\toptions.mathSpeech,\n\t\t);\n\t\tssml = generated ?? undefined;\n\t}\n\n\treturn {\n\t\tspeechText,\n\t\tusedMathSpeech,\n\t\tusedFallback,\n\t\tssml,\n\t};\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual-line-ranges.js","sourceRoot":"","sources":["../../../src/services/tts/visual-line-ranges.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Derive visual line box ranges inside a root element for TTS read-along.\n *\n * Cloud TTS (Polly, Google, etc.) only provides word/sentence character offsets.\n * “Lines” are layout-dependent (wrap, zoom, font size), so we compute them in\n * the browser from the same DOM Range already used for word highlighting.\n */\n\nconst LINE_TOP_EPSILON = 2;\nconst CARET_INSET = 1;\nconst HORIZONTAL_PROBE_STEP = 3;\nconst MAX_HORIZONTAL_PROBES = 400;\nconst MAX_LINE_RANGES = 48;\n\ntype DocumentWithCaret = Document & {\n\tcaretRangeFromPoint?: (x: number, y: number) => Range | null;\n\tcaretPositionFromPoint?: (\n\t\tx: number,\n\t\ty: number,\n\t) => { offsetNode: Node; offset: number } | null;\n};\n\nfunction caretRangeAtPoint(doc: Document, x: number, y: number): Range | null {\n\tconst d = doc as DocumentWithCaret;\n\tif (typeof d.caretRangeFromPoint === \"function\") {\n\t\ttry {\n\t\t\treturn d.caretRangeFromPoint(x, y);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\tconst pos = d.caretPositionFromPoint?.(x, y);\n\tif (\n\t\tpos?.offsetNode?.nodeType === Node.TEXT_NODE ||\n\t\tpos?.offsetNode?.nodeType === Node.ELEMENT_NODE\n\t) {\n\t\tconst r = doc.createRange();\n\t\ttry {\n\t\t\tr.setStart(pos.offsetNode, pos.offset);\n\t\t\tr.collapse(true);\n\t\t\treturn r;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction collapsedRangeTop(r: Range): number | null {\n\tconst rects = r.getClientRects();\n\tif (rects.length === 0) return null;\n\treturn rects[0].top;\n}\n\n/**\n * Intersect `range` with the contents of `root` (document order).\n * Returns null if there is no non-empty intersection.\n */\nexport function intersectRangeWithElement(\n\trange: Range,\n\troot: Element,\n): Range | null {\n\tif (typeof document === \"undefined\") return null;\n\tif (typeof range.compareBoundaryPoints !== \"function\") return null;\n\ttry {\n\t\tconst doc = range.startContainer.ownerDocument || document;\n\t\tconst rootRange = doc.createRange();\n\t\trootRange.selectNodeContents(root);\n\n\t\tif (range.compareBoundaryPoints(Range.END_TO_START, rootRange) <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tif (range.compareBoundaryPoints(Range.START_TO_END, rootRange) >= 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst out = doc.createRange();\n\t\tif (range.compareBoundaryPoints(Range.START_TO_START, rootRange) < 0) {\n\t\t\tout.setStart(rootRange.startContainer, rootRange.startOffset);\n\t\t} else {\n\t\t\tout.setStart(range.startContainer, range.startOffset);\n\t\t}\n\t\tif (range.compareBoundaryPoints(Range.END_TO_END, rootRange) > 0) {\n\t\t\tout.setEnd(rootRange.endContainer, rootRange.endOffset);\n\t\t} else {\n\t\t\tout.setEnd(range.endContainer, range.endOffset);\n\t\t}\n\t\tif (out.collapsed) return null;\n\t\treturn out;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction lineKeyForRect(top: number): number {\n\treturn Math.round(top / LINE_TOP_EPSILON);\n}\n\nfunction extendLineEdge(\n\tdoc: Document,\n\troot: Element,\n\trefTop: number,\n\tmidY: number,\n\tstartX: number,\n\trootLeft: number,\n\trootRight: number,\n\tdirection: \"left\" | \"right\",\n): Range | null {\n\tlet lastGood: Range | null = null;\n\tlet x = startX;\n\tif (direction === \"left\") {\n\t\tfor (let i = 0; i < MAX_HORIZONTAL_PROBES && x >= rootLeft + CARET_INSET; i++) {\n\t\t\tconst cr = caretRangeAtPoint(doc, x, midY);\n\t\t\tif (!cr || !rootContainsNode(root, cr.startContainer)) break;\n\t\t\tconst t = collapsedRangeTop(cr);\n\t\t\tif (t === null || Math.abs(t - refTop) > LINE_TOP_EPSILON) break;\n\t\t\tlastGood = cr.cloneRange();\n\t\t\tx -= HORIZONTAL_PROBE_STEP;\n\t\t}\n\t} else {\n\t\tfor (let i = 0; i < MAX_HORIZONTAL_PROBES && x <= rootRight - CARET_INSET; i++) {\n\t\t\tconst cr = caretRangeAtPoint(doc, x, midY);\n\t\t\tif (!cr || !rootContainsNode(root, cr.startContainer)) break;\n\t\t\tconst t = collapsedRangeTop(cr);\n\t\t\tif (t === null || Math.abs(t - refTop) > LINE_TOP_EPSILON) break;\n\t\t\tlastGood = cr.cloneRange();\n\t\t\tx += HORIZONTAL_PROBE_STEP;\n\t\t}\n\t}\n\treturn lastGood;\n}\n\nfunction rootContainsNode(root: Element, node: Node): boolean {\n\tif (typeof root.contains !== \"function\") return false;\n\ttry {\n\t\treturn root.contains(node);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction fallbackSingleRangeFromFocus(focus: Range): Range[] {\n\ttry {\n\t\tconst doc = focus.startContainer.ownerDocument || document;\n\t\tconst r = doc.createRange();\n\t\tr.setStart(focus.startContainer, focus.startOffset);\n\t\tr.setEnd(focus.endContainer, focus.endOffset);\n\t\treturn [r];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Returns one Range per visual line that intersects `focus`, expanded to the\n * full width of each line within `root`. Falls back to `[intersectedFocus]`\n * when layout or caret APIs are unavailable.\n */\nexport function visualLineRangesForFocusInRoot(\n\troot: Element,\n\tfocus: Range,\n): Range[] {\n\tif (typeof document === \"undefined\") return [];\n\tif (!focus.startContainer) {\n\t\treturn [];\n\t}\n\n\tconst doc = focus.startContainer.ownerDocument || document;\n\tconst intersected = intersectRangeWithElement(focus, root);\n\tif (!intersected) {\n\t\treturn fallbackSingleRangeFromFocus(focus);\n\t}\n\n\tlet rects: DOMRect[];\n\ttry {\n\t\trects = Array.from(intersected.getClientRects()).filter(\n\t\t\t(r) => r.width > 0 && r.height > 0,\n\t\t);\n\t} catch {\n\t\treturn [intersected.cloneRange()];\n\t}\n\tif (rects.length === 0) {\n\t\treturn [intersected.cloneRange()];\n\t}\n\n\tlet rootBounds: DOMRect;\n\ttry {\n\t\trootBounds = root.getBoundingClientRect();\n\t} catch {\n\t\treturn [intersected.cloneRange()];\n\t}\n\tconst groups = new Map<number, DOMRect[]>();\n\tfor (const rect of rects) {\n\t\tconst key = lineKeyForRect(rect.top);\n\t\tconst list = groups.get(key);\n\t\tif (list) list.push(rect);\n\t\telse groups.set(key, [rect]);\n\t}\n\n\tconst sortedKeys = Array.from(groups.keys()).sort((a, b) => a - b);\n\tconst out: Range[] = [];\n\n\tfor (const key of sortedKeys) {\n\t\tif (out.length >= MAX_LINE_RANGES) break;\n\t\tconst group = groups.get(key);\n\t\tif (!group?.length) continue;\n\n\t\tlet sumTop = 0;\n\t\tlet sumMid = 0;\n\t\tlet minL = Infinity;\n\t\tlet maxR = -Infinity;\n\t\tfor (const r of group) {\n\t\t\tsumTop += r.top;\n\t\t\tsumMid += r.top + r.height / 2;\n\t\t\tminL = Math.min(minL, r.left);\n\t\t\tmaxR = Math.max(maxR, r.right);\n\t\t}\n\t\tconst refTop = sumTop / group.length;\n\t\tconst midY = sumMid / group.length;\n\n\t\tconst leftEdge = extendLineEdge(\n\t\t\tdoc,\n\t\t\troot,\n\t\t\trefTop,\n\t\t\tmidY,\n\t\t\tminL,\n\t\t\trootBounds.left,\n\t\t\trootBounds.right,\n\t\t\t\"left\",\n\t\t);\n\t\tconst rightEdge = extendLineEdge(\n\t\t\tdoc,\n\t\t\troot,\n\t\t\trefTop,\n\t\t\tmidY,\n\t\t\tmaxR,\n\t\t\trootBounds.left,\n\t\t\trootBounds.right,\n\t\t\t\"right\",\n\t\t);\n\n\t\tif (!leftEdge || !rightEdge) {\n\t\t\tconst fallback = intersected.cloneRange();\n\t\t\treturn [fallback];\n\t\t}\n\n\t\tconst lineRange = doc.createRange();\n\t\ttry {\n\t\t\tlineRange.setStart(leftEdge.startContainer, leftEdge.startOffset);\n\t\t\tlineRange.setEnd(rightEdge.startContainer, rightEdge.startOffset);\n\t\t} catch {\n\t\t\treturn [intersected.cloneRange()];\n\t\t}\n\n\t\tif (lineRange.collapsed) {\n\t\t\treturn [intersected.cloneRange()];\n\t\t}\n\n\t\tconst clipped = intersectRangeWithElement(lineRange, root);\n\t\tif (clipped && !clipped.collapsed) {\n\t\t\tout.push(clipped);\n\t\t} else {\n\t\t\treturn [intersected.cloneRange()];\n\t\t}\n\t}\n\n\treturn out.length > 0 ? out : [intersected.cloneRange()];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"visual-line-ranges.js","sourceRoot":"","sources":["../../../src/services/tts/visual-line-ranges.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Derive visual line box ranges inside a root element for TTS read-along.\n *\n * Cloud TTS (Polly, Google, etc.) only provides word/sentence character offsets.\n * “Lines” are layout-dependent (wrap, zoom, font size), so we compute them in\n * the browser from the same DOM Range already used for word highlighting.\n */\n\nconst LINE_TOP_EPSILON = 2;\nconst CARET_INSET = 1;\nconst HORIZONTAL_PROBE_STEP = 3;\nconst MAX_HORIZONTAL_PROBES = 400;\nconst MAX_LINE_RANGES = 48;\n\ntype DocumentWithCaret = Document & {\n\tcaretRangeFromPoint?: (x: number, y: number) => Range | null;\n\tcaretPositionFromPoint?: (\n\t\tx: number,\n\t\ty: number,\n\t) => { offsetNode: Node; offset: number } | null;\n};\n\nfunction caretRangeAtPoint(doc: Document, x: number, y: number): Range | null {\n\tconst d = doc as DocumentWithCaret;\n\tif (typeof d.caretRangeFromPoint === \"function\") {\n\t\ttry {\n\t\t\treturn d.caretRangeFromPoint(x, y);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\tconst pos = d.caretPositionFromPoint?.(x, y);\n\tif (\n\t\tpos?.offsetNode?.nodeType === Node.TEXT_NODE ||\n\t\tpos?.offsetNode?.nodeType === Node.ELEMENT_NODE\n\t) {\n\t\tconst r = doc.createRange();\n\t\ttry {\n\t\t\tr.setStart(pos.offsetNode, pos.offset);\n\t\t\tr.collapse(true);\n\t\t\treturn r;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction collapsedRangeTop(r: Range): number | null {\n\tconst rects = r.getClientRects();\n\tif (rects.length === 0) return null;\n\treturn rects[0].top;\n}\n\n/**\n * Intersect `range` with the contents of `root` (document order).\n * Returns null if there is no non-empty intersection.\n */\nexport function intersectRangeWithElement(\n\trange: Range,\n\troot: Element,\n): Range | null {\n\tif (typeof document === \"undefined\") return null;\n\tif (typeof range.compareBoundaryPoints !== \"function\") return null;\n\ttry {\n\t\tconst doc = range.startContainer.ownerDocument || document;\n\t\tconst rootRange = doc.createRange();\n\t\trootRange.selectNodeContents(root);\n\n\t\tif (range.compareBoundaryPoints(Range.END_TO_START, rootRange) <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tif (range.compareBoundaryPoints(Range.START_TO_END, rootRange) >= 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst out = doc.createRange();\n\t\tif (range.compareBoundaryPoints(Range.START_TO_START, rootRange) < 0) {\n\t\t\tout.setStart(rootRange.startContainer, rootRange.startOffset);\n\t\t} else {\n\t\t\tout.setStart(range.startContainer, range.startOffset);\n\t\t}\n\t\tif (range.compareBoundaryPoints(Range.END_TO_END, rootRange) > 0) {\n\t\t\tout.setEnd(rootRange.endContainer, rootRange.endOffset);\n\t\t} else {\n\t\t\tout.setEnd(range.endContainer, range.endOffset);\n\t\t}\n\t\tif (out.collapsed) return null;\n\t\treturn out;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction lineKeyForRect(top: number): number {\n\treturn Math.round(top / LINE_TOP_EPSILON);\n}\n\nfunction extendLineEdge(\n\tdoc: Document,\n\troot: Element,\n\trefTop: number,\n\tmidY: number,\n\tstartX: number,\n\trootLeft: number,\n\trootRight: number,\n\tdirection: \"left\" | \"right\",\n): Range | null {\n\tlet lastGood: Range | null = null;\n\tlet x = startX;\n\tif (direction === \"left\") {\n\t\tfor (\n\t\t\tlet i = 0;\n\t\t\ti < MAX_HORIZONTAL_PROBES && x >= rootLeft + CARET_INSET;\n\t\t\ti++\n\t\t) {\n\t\t\tconst cr = caretRangeAtPoint(doc, x, midY);\n\t\t\tif (!cr || !rootContainsNode(root, cr.startContainer)) break;\n\t\t\tconst t = collapsedRangeTop(cr);\n\t\t\tif (t === null || Math.abs(t - refTop) > LINE_TOP_EPSILON) break;\n\t\t\tlastGood = cr.cloneRange();\n\t\t\tx -= HORIZONTAL_PROBE_STEP;\n\t\t}\n\t} else {\n\t\tfor (\n\t\t\tlet i = 0;\n\t\t\ti < MAX_HORIZONTAL_PROBES && x <= rootRight - CARET_INSET;\n\t\t\ti++\n\t\t) {\n\t\t\tconst cr = caretRangeAtPoint(doc, x, midY);\n\t\t\tif (!cr || !rootContainsNode(root, cr.startContainer)) break;\n\t\t\tconst t = collapsedRangeTop(cr);\n\t\t\tif (t === null || Math.abs(t - refTop) > LINE_TOP_EPSILON) break;\n\t\t\tlastGood = cr.cloneRange();\n\t\t\tx += HORIZONTAL_PROBE_STEP;\n\t\t}\n\t}\n\treturn lastGood;\n}\n\nfunction rootContainsNode(root: Element, node: Node): boolean {\n\tif (typeof root.contains !== \"function\") return false;\n\ttry {\n\t\treturn root.contains(node);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction fallbackSingleRangeFromFocus(focus: Range): Range[] {\n\ttry {\n\t\tconst doc = focus.startContainer.ownerDocument || document;\n\t\tconst r = doc.createRange();\n\t\tr.setStart(focus.startContainer, focus.startOffset);\n\t\tr.setEnd(focus.endContainer, focus.endOffset);\n\t\treturn [r];\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Returns one Range per visual line that intersects `focus`, expanded to the\n * full width of each line within `root`. Falls back to `[intersectedFocus]`\n * when layout or caret APIs are unavailable.\n */\nexport function visualLineRangesForFocusInRoot(\n\troot: Element,\n\tfocus: Range,\n): Range[] {\n\tif (typeof document === \"undefined\") return [];\n\tif (!focus.startContainer) {\n\t\treturn [];\n\t}\n\n\tconst doc = focus.startContainer.ownerDocument || document;\n\tconst intersected = intersectRangeWithElement(focus, root);\n\tif (!intersected) {\n\t\treturn fallbackSingleRangeFromFocus(focus);\n\t}\n\n\tlet rects: DOMRect[];\n\ttry {\n\t\trects = Array.from(intersected.getClientRects()).filter(\n\t\t\t(r) => r.width > 0 && r.height > 0,\n\t\t);\n\t} catch {\n\t\treturn [intersected.cloneRange()];\n\t}\n\tif (rects.length === 0) {\n\t\treturn [intersected.cloneRange()];\n\t}\n\n\tlet rootBounds: DOMRect;\n\ttry {\n\t\trootBounds = root.getBoundingClientRect();\n\t} catch {\n\t\treturn [intersected.cloneRange()];\n\t}\n\tconst groups = new Map<number, DOMRect[]>();\n\tfor (const rect of rects) {\n\t\tconst key = lineKeyForRect(rect.top);\n\t\tconst list = groups.get(key);\n\t\tif (list) list.push(rect);\n\t\telse groups.set(key, [rect]);\n\t}\n\n\tconst sortedKeys = Array.from(groups.keys()).sort((a, b) => a - b);\n\tconst out: Range[] = [];\n\n\tfor (const key of sortedKeys) {\n\t\tif (out.length >= MAX_LINE_RANGES) break;\n\t\tconst group = groups.get(key);\n\t\tif (!group?.length) continue;\n\n\t\tlet sumTop = 0;\n\t\tlet sumMid = 0;\n\t\tlet minL = Infinity;\n\t\tlet maxR = -Infinity;\n\t\tfor (const r of group) {\n\t\t\tsumTop += r.top;\n\t\t\tsumMid += r.top + r.height / 2;\n\t\t\tminL = Math.min(minL, r.left);\n\t\t\tmaxR = Math.max(maxR, r.right);\n\t\t}\n\t\tconst refTop = sumTop / group.length;\n\t\tconst midY = sumMid / group.length;\n\n\t\tconst leftEdge = extendLineEdge(\n\t\t\tdoc,\n\t\t\troot,\n\t\t\trefTop,\n\t\t\tmidY,\n\t\t\tminL,\n\t\t\trootBounds.left,\n\t\t\trootBounds.right,\n\t\t\t\"left\",\n\t\t);\n\t\tconst rightEdge = extendLineEdge(\n\t\t\tdoc,\n\t\t\troot,\n\t\t\trefTop,\n\t\t\tmidY,\n\t\t\tmaxR,\n\t\t\trootBounds.left,\n\t\t\trootBounds.right,\n\t\t\t\"right\",\n\t\t);\n\n\t\tif (!leftEdge || !rightEdge) {\n\t\t\tconst fallback = intersected.cloneRange();\n\t\t\treturn [fallback];\n\t\t}\n\n\t\tconst lineRange = doc.createRange();\n\t\ttry {\n\t\t\tlineRange.setStart(leftEdge.startContainer, leftEdge.startOffset);\n\t\t\tlineRange.setEnd(rightEdge.startContainer, rightEdge.startOffset);\n\t\t} catch {\n\t\t\treturn [intersected.cloneRange()];\n\t\t}\n\n\t\tif (lineRange.collapsed) {\n\t\t\treturn [intersected.cloneRange()];\n\t\t}\n\n\t\tconst clipped = intersectRangeWithElement(lineRange, root);\n\t\tif (clipped && !clipped.collapsed) {\n\t\t\tout.push(clipped);\n\t\t} else {\n\t\t\treturn [intersected.cloneRange()];\n\t\t}\n\t}\n\n\treturn out.length > 0 ? out : [intersected.cloneRange()];\n}\n"]}
|
|
@@ -122,11 +122,15 @@ export const buildRuntimeTTSConfig = (config) => {
|
|
|
122
122
|
pitch: config.pitch,
|
|
123
123
|
providerOptions: {
|
|
124
124
|
...(config.language ? { locale: config.language } : {}),
|
|
125
|
-
...(backend === "polly" && config.engine
|
|
125
|
+
...(backend === "polly" && config.engine
|
|
126
|
+
? { engine: config.engine }
|
|
127
|
+
: {}),
|
|
126
128
|
...(backend === "polly" && typeof config.sampleRate === "number"
|
|
127
129
|
? { sampleRate: config.sampleRate }
|
|
128
130
|
: {}),
|
|
129
|
-
...(backend === "polly" && config.format
|
|
131
|
+
...(backend === "polly" && config.format
|
|
132
|
+
? { format: config.format }
|
|
133
|
+
: {}),
|
|
130
134
|
...(backend === "polly"
|
|
131
135
|
? {
|
|
132
136
|
speechMarkTypes: config.speechMarksMode === "word+sentence"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tts-runtime-config.js","sourceRoot":"","sources":["../../src/services/tts-runtime-config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TTSConfig } from \"./TTSService.js\";\nimport type { ToolProviderConfig } from \"./tools-config-normalizer.js\";\nimport {\n\tnormalizeSREMathSpeechOptions,\n\ttype SREMathSpeechOptions,\n} from \"./tts/math-speech.js\";\n\nexport type TTSLayoutMode =\n\t| \"reserved-row\"\n\t| \"expanding-row\"\n\t| \"floating-overlay\"\n\t| \"left-aligned\";\n\nconst VALID_TTS_LAYOUT_MODES = new Set<TTSLayoutMode>([\n\t\"reserved-row\",\n\t\"expanding-row\",\n\t\"floating-overlay\",\n\t\"left-aligned\",\n]);\n\nexport interface TTSHostToolbarLayout {\n\tmount: \"before-buttons\";\n\tcontrolsRow: {\n\t\treserveSpace: boolean;\n\t\texpandWhenToolActive: boolean;\n\t};\n}\n\nexport interface TTSRuntimeSettings {\n\tbackend?: \"browser\" | \"polly\" | \"google\" | \"server\";\n\tserverProvider?: \"polly\" | \"google\" | \"custom\";\n\tprovider?: \"polly\" | \"google\" | \"custom\";\n\tengine?: \"standard\" | \"neural\";\n\tsampleRate?: number;\n\tformat?: \"mp3\" | \"ogg\" | \"pcm\";\n\tspeechMarksMode?: \"word\" | \"word+sentence\";\n\tdefaultVoice?: string;\n\trate?: number;\n\tpitch?: number;\n\tapiEndpoint?: string;\n\tlanguage?: string;\n\ttransportMode?: \"pie\" | \"custom\";\n\tendpointMode?: \"synthesizePath\" | \"rootPost\";\n\tendpointValidationMode?: \"voices\" | \"endpoint\" | \"none\";\n\tincludeAuthOnAssetFetch?: boolean;\n\tvalidateEndpoint?: boolean;\n\tcache?: boolean;\n\tspeedRate?: \"slow\" | \"medium\" | \"fast\";\n\tlang_id?: string;\n\t/**\n\t * Optional inline TTS speed buttons.\n\t * - Omitted/non-array: default speed buttons are shown.\n\t * - Empty array: hide speed buttons.\n\t * - Arrays that sanitize to no valid values: default speed buttons are shown.\n\t */\n\tspeedOptions?: number[];\n\tlayoutMode?: TTSLayoutMode;\n\t/**\n\t * Per-token highlighting of math expressions.\n\t * - `true` / omitted (default): when the spoken math aligns confidently to the\n\t * rendered MathML, the formula is highlighted glyph by glyph; otherwise it\n\t * safely falls back to a whole-formula block.\n\t * - `false`: every formula is highlighted as a single block (the fallback),\n\t * never broken into per-token highlights. Prose word tracking is unaffected.\n\t */\n\tmathTokenHighlighting?: boolean;\n\t/**\n\t * Speech Rule Engine options for generated MathML speech. Hosts can use these\n\t * to tune SRE itself (for example ClearSpeak ImpliedTimes/Paren preferences)\n\t * instead of relying on toolkit-specific speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n}\n\nconst toRecord = (value: unknown): Record<string, unknown> =>\n\tvalue && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n\nconst isServerBackend = (\n\tbackend: TTSRuntimeSettings[\"backend\"],\n): backend is \"polly\" | \"google\" | \"server\" =>\n\tbackend === \"polly\" || backend === \"google\" || backend === \"server\";\n\nconst withDefault = <T>(value: T | undefined, fallback: T): T =>\n\tvalue === undefined ? fallback : value;\n\nexport const normalizeTTSLayoutMode = (\n\tvalue: unknown,\n\tfallback: TTSLayoutMode = \"left-aligned\",\n): TTSLayoutMode =>\n\ttypeof value === \"string\" &&\n\tVALID_TTS_LAYOUT_MODES.has(value as TTSLayoutMode)\n\t\t? (value as TTSLayoutMode)\n\t\t: fallback;\n\n/** Default inline TTS speed button multipliers (excluding 1.0×). */\nexport const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);\n\n/**\n * Resolves inline toolbar speed options from host config.\n * - Omitted/non-array: default speed buttons.\n * - Empty array: hide speed buttons.\n * - Arrays that sanitize to no valid values: default speed buttons.\n * - 1.0× is never shown as a discrete speed button.\n */\nexport const normalizeTTSSpeedOptions = (value: unknown): number[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\tconst deduped = new Set<number>();\n\tfor (const entry of value) {\n\t\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) continue;\n\t\tconst rounded = Math.round(entry * 100) / 100;\n\t\tif (rounded === 1) continue;\n\t\tdeduped.add(rounded);\n\t}\n\treturn deduped.size ? Array.from(deduped) : [...DEFAULT_TTS_SPEED_OPTIONS];\n};\n\nexport const formatTTSSpeedOptionsAsText = (values: number[]): string =>\n\tvalues.join(\", \");\n\n/**\n * Parse comma/semicolon-separated multipliers from settings UI text.\n * - Empty or whitespace-only string → hide speed buttons (`[]`).\n * - Non-empty text with no parseable finite numbers → same as invalid-only array config: defaults.\n */\nexport const parseTTSSpeedOptionsFromText = (text: string): number[] => {\n\tconst trimmed = text.trim();\n\tif (!trimmed) return [];\n\tconst parts = trimmed\n\t\t.split(/[,;]+/)\n\t\t.map((p) => p.trim())\n\t\t.filter(Boolean);\n\tconst candidates = parts\n\t\t.map((p) => Number.parseFloat(p))\n\t\t.filter((n) => Number.isFinite(n));\n\tif (!candidates.length) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\treturn normalizeTTSSpeedOptions(candidates);\n};\n\nconst applyRuntimeDefaults = (\n\tconfig: TTSRuntimeSettings,\n): TTSRuntimeSettings => {\n\tconst withLayoutDefaults: TTSRuntimeSettings = {\n\t\t...config,\n\t\tlayoutMode: normalizeTTSLayoutMode(config.layoutMode),\n\t};\n\tconst backend = config.backend || \"browser\";\n\tif (!isServerBackend(backend)) return withLayoutDefaults;\n\n\tconst withServerDefaults: TTSRuntimeSettings = {\n\t\t...withLayoutDefaults,\n\t\tapiEndpoint: withDefault(withLayoutDefaults.apiEndpoint, \"/api/tts\"),\n\t\ttransportMode: withDefault(withLayoutDefaults.transportMode, \"pie\"),\n\t\tendpointValidationMode: withDefault(\n\t\t\twithLayoutDefaults.endpointValidationMode,\n\t\t\t\"voices\",\n\t\t),\n\t\tvalidateEndpoint: withDefault(withLayoutDefaults.validateEndpoint, true),\n\t\tincludeAuthOnAssetFetch: withDefault(\n\t\t\twithLayoutDefaults.includeAuthOnAssetFetch,\n\t\t\tfalse,\n\t\t),\n\t\trate: withDefault(withLayoutDefaults.rate, 1.0),\n\t\tlanguage: withDefault(withLayoutDefaults.language, \"en-US\"),\n\t};\n\n\tif (backend === \"polly\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(withServerDefaults.defaultVoice, \"Joanna\"),\n\t\t\tengine: withDefault(withServerDefaults.engine, \"neural\"),\n\t\t\tformat: withDefault(withServerDefaults.format, \"mp3\"),\n\t\t\tspeechMarksMode: withDefault(\n\t\t\t\twithServerDefaults.speechMarksMode,\n\t\t\t\t\"word+sentence\",\n\t\t\t),\n\t\t};\n\t}\n\n\tif (backend === \"google\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(withServerDefaults.defaultVoice, \"en-US-Wavenet-A\"),\n\t\t};\n\t}\n\n\treturn withServerDefaults;\n};\n\nexport const resolveTTSRuntimeSettings = (\n\tconfig: ToolProviderConfig | TTSRuntimeSettings | undefined,\n): TTSRuntimeSettings => {\n\tconst configRecord = toRecord(config);\n\tconst settingsRecord = toRecord(configRecord.settings);\n\treturn applyRuntimeDefaults({\n\t\t...configRecord,\n\t\t...settingsRecord,\n\t} as TTSRuntimeSettings);\n};\n\nexport const resolveTTSBackend = (\n\tconfig: TTSRuntimeSettings,\n): NonNullable<TTSRuntimeSettings[\"backend\"]> => config.backend || \"browser\";\n\nexport const resolveRuntimeProvider = (\n\tconfig: TTSRuntimeSettings,\n\tbackend: NonNullable<TTSRuntimeSettings[\"backend\"]>,\n): TTSRuntimeSettings[\"serverProvider\"] => {\n\tif (backend === \"polly\" || backend === \"google\") return backend;\n\tif (backend === \"server\") {\n\t\treturn config.serverProvider || config.provider;\n\t}\n\treturn config.serverProvider || config.provider;\n};\n\nexport const resolveTransportMode = (\n\tconfig: TTSRuntimeSettings,\n\truntimeProvider: TTSRuntimeSettings[\"serverProvider\"],\n): NonNullable<TTSRuntimeSettings[\"transportMode\"]> =>\n\tconfig.transportMode || (runtimeProvider === \"custom\" ? \"custom\" : \"pie\");\n\nexport const buildRuntimeTTSConfig = (\n\tconfig: TTSRuntimeSettings,\n): Partial<TTSConfig> => {\n\tconst backend = resolveTTSBackend(config);\n\tconst runtimeProvider = resolveRuntimeProvider(config, backend);\n\tconst transportMode = resolveTransportMode(config, runtimeProvider);\n\tconst mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);\n\treturn {\n\t\tvoice: config.defaultVoice,\n\t\trate: config.rate,\n\t\tpitch: config.pitch,\n\t\tproviderOptions: {\n\t\t\t...(config.language ? { locale: config.language } : {}),\n\t\t\t...(backend === \"polly\" && config.engine ? { engine: config.engine } : {}),\n\t\t\t...(backend === \"polly\" && typeof config.sampleRate === \"number\"\n\t\t\t\t? { sampleRate: config.sampleRate }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && config.format ? { format: config.format } : {}),\n\t\t\t...(backend === \"polly\"\n\t\t\t\t? {\n\t\t\t\t\t\tspeechMarkTypes:\n\t\t\t\t\t\t\tconfig.speechMarksMode === \"word+sentence\"\n\t\t\t\t\t\t\t\t? [\"word\", \"sentence\"]\n\t\t\t\t\t\t\t\t: [\"word\"],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && typeof config.cache === \"boolean\"\n\t\t\t\t? { cache: config.cache }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.speedRate\n\t\t\t\t? { speedRate: config.speedRate }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.lang_id\n\t\t\t\t? { lang_id: config.lang_id }\n\t\t\t\t: {}),\n\t\t\t...(mathSpeech ? { mathSpeech } : {}),\n\t\t},\n\t\tapiEndpoint: config.apiEndpoint,\n\t\tprovider: runtimeProvider,\n\t\tlanguage: config.language,\n\t\ttransportMode,\n\t\tendpointMode: config.endpointMode,\n\t\tendpointValidationMode: config.endpointValidationMode,\n\t\tincludeAuthOnAssetFetch: config.includeAuthOnAssetFetch,\n\t\tvalidateEndpoint: config.validateEndpoint,\n\t\t// Toolkit-level highlight setting carried through the config channel\n\t\t// (like apiEndpoint/transportMode); consumed by the highlight pipeline,\n\t\t// ignored by providers. Only forwarded when set so the pipeline default\n\t\t// (per-token enabled) applies otherwise.\n\t\t...(typeof config.mathTokenHighlighting === \"boolean\"\n\t\t\t? { mathTokenHighlighting: config.mathTokenHighlighting }\n\t\t\t: {}),\n\t} as Partial<TTSConfig>;\n};\n\nexport const resolveTTSLayoutMode = (\n\tconfig: TTSRuntimeSettings,\n): TTSLayoutMode => normalizeTTSLayoutMode(config.layoutMode);\n\nexport const resolveTTSHostToolbarLayout = (\n\tconfig: TTSRuntimeSettings,\n): TTSHostToolbarLayout => {\n\tconst layoutMode = resolveTTSLayoutMode(config);\n\tswitch (layoutMode) {\n\t\tcase \"reserved-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: true,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"expanding-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: true,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"floating-overlay\":\n\t\tcase \"left-aligned\":\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t}\n};\n"]}
|
|
1
|
+
{"version":3,"file":"tts-runtime-config.js","sourceRoot":"","sources":["../../src/services/tts-runtime-config.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,6BAA6B,GAE7B,MAAM,sBAAsB,CAAC;AAQ9B,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAgB;IACrD,cAAc;IACd,eAAe;IACf,kBAAkB;IAClB,cAAc;CACd,CAAC,CAAC;AAwDH,MAAM,QAAQ,GAAG,CAAC,KAAc,EAA2B,EAAE,CAC5D,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAiC,CAAC,CAAC,CAAC,EAAE,CAAC;AAE9E,MAAM,eAAe,GAAG,CACvB,OAAsC,EACK,EAAE,CAC7C,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,CAAC;AAErE,MAAM,WAAW,GAAG,CAAI,KAAoB,EAAE,QAAW,EAAK,EAAE,CAC/D,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAExC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACrC,KAAc,EACd,WAA0B,cAAc,EACxB,EAAE,CAClB,OAAO,KAAK,KAAK,QAAQ;IACzB,sBAAsB,CAAC,GAAG,CAAC,KAAsB,CAAC;IACjD,CAAC,CAAE,KAAuB;IAC1B,CAAC,CAAC,QAAQ,CAAC;AAEb,oEAAoE;AACpE,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAc,EAAY,EAAE;IACpE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,yBAAyB,CAAC,CAAC;IACjE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;YACrE,SAAS;QACV,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;QAC9C,IAAI,OAAO,KAAK,CAAC;YAAE,SAAS;QAC5B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,yBAAyB,CAAC,CAAC;AAC5E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,MAAgB,EAAU,EAAE,CACvE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEnB;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,IAAY,EAAY,EAAE;IACtE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,OAAO;SACnB,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,MAAM,UAAU,GAAG,KAAK;SACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;SAChC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,MAAM;QAAE,OAAO,CAAC,GAAG,yBAAyB,CAAC,CAAC;IAC9D,OAAO,wBAAwB,CAAC,UAAU,CAAC,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAC5B,MAA0B,EACL,EAAE;IACvB,MAAM,kBAAkB,GAAuB;QAC9C,GAAG,MAAM;QACT,UAAU,EAAE,sBAAsB,CAAC,MAAM,CAAC,UAAU,CAAC;KACrD,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC;IAC5C,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;QAAE,OAAO,kBAAkB,CAAC;IAEzD,MAAM,kBAAkB,GAAuB;QAC9C,GAAG,kBAAkB;QACrB,WAAW,EAAE,WAAW,CAAC,kBAAkB,CAAC,WAAW,EAAE,UAAU,CAAC;QACpE,aAAa,EAAE,WAAW,CAAC,kBAAkB,CAAC,aAAa,EAAE,KAAK,CAAC;QACnE,sBAAsB,EAAE,WAAW,CAClC,kBAAkB,CAAC,sBAAsB,EACzC,QAAQ,CACR;QACD,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,gBAAgB,EAAE,IAAI,CAAC;QACxE,uBAAuB,EAAE,WAAW,CACnC,kBAAkB,CAAC,uBAAuB,EAC1C,KAAK,CACL;QACD,IAAI,EAAE,WAAW,CAAC,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC;QAC/C,QAAQ,EAAE,WAAW,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC3D,CAAC;IAEF,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO;YACN,GAAG,kBAAkB;YACrB,YAAY,EAAE,WAAW,CAAC,kBAAkB,CAAC,YAAY,EAAE,QAAQ,CAAC;YACpE,MAAM,EAAE,WAAW,CAAC,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC;YACxD,MAAM,EAAE,WAAW,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC;YACrD,eAAe,EAAE,WAAW,CAC3B,kBAAkB,CAAC,eAAe,EAClC,eAAe,CACf;SACD,CAAC;IACH,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO;YACN,GAAG,kBAAkB;YACrB,YAAY,EAAE,WAAW,CACxB,kBAAkB,CAAC,YAAY,EAC/B,iBAAiB,CACjB;SACD,CAAC;IACH,CAAC;IAED,OAAO,kBAAkB,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACxC,MAA2D,EACtC,EAAE;IACvB,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,cAAc,GAAG,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvD,OAAO,oBAAoB,CAAC;QAC3B,GAAG,YAAY;QACf,GAAG,cAAc;KACK,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAChC,MAA0B,EACmB,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC;AAE7E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACrC,MAA0B,EAC1B,OAAmD,EACZ,EAAE;IACzC,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChE,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,QAAQ,CAAC;IACjD,CAAC;IACD,OAAO,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,QAAQ,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CACnC,MAA0B,EAC1B,eAAqD,EACF,EAAE,CACrD,MAAM,CAAC,aAAa,IAAI,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACpC,MAA0B,EACL,EAAE;IACvB,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,eAAe,GAAG,sBAAsB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,oBAAoB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,6BAA6B,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACpE,OAAO;QACN,KAAK,EAAE,MAAM,CAAC,YAAY;QAC1B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,eAAe,EAAE;YAChB,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM;gBACvC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;gBAC3B,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ;gBAC/D,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE;gBACnC,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM;gBACvC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;gBAC3B,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,OAAO,KAAK,OAAO;gBACtB,CAAC,CAAC;oBACA,eAAe,EACd,MAAM,CAAC,eAAe,KAAK,eAAe;wBACzC,CAAC,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC;wBACtB,CAAC,CAAC,CAAC,MAAM,CAAC;iBACZ;gBACF,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,SAAS;gBAClE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;gBACzB,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS;gBACjD,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE;gBACjC,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO;gBAC/C,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;gBAC7B,CAAC,CAAC,EAAE,CAAC;YACN,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrC;QACD,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,aAAa;QACb,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,sBAAsB,EAAE,MAAM,CAAC,sBAAsB;QACrD,uBAAuB,EAAE,MAAM,CAAC,uBAAuB;QACvD,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,qEAAqE;QACrE,wEAAwE;QACxE,wEAAwE;QACxE,yCAAyC;QACzC,GAAG,CAAC,OAAO,MAAM,CAAC,qBAAqB,KAAK,SAAS;YACpD,CAAC,CAAC,EAAE,qBAAqB,EAAE,MAAM,CAAC,qBAAqB,EAAE;YACzD,CAAC,CAAC,EAAE,CAAC;KACgB,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CACnC,MAA0B,EACV,EAAE,CAAC,sBAAsB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAC1C,MAA0B,EACH,EAAE;IACzB,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAChD,QAAQ,UAAU,EAAE,CAAC;QACpB,KAAK,cAAc;YAClB,OAAO;gBACN,KAAK,EAAE,gBAAgB;gBACvB,WAAW,EAAE;oBACZ,YAAY,EAAE,IAAI;oBAClB,oBAAoB,EAAE,KAAK;iBAC3B;aACD,CAAC;QACH,KAAK,eAAe;YACnB,OAAO;gBACN,KAAK,EAAE,gBAAgB;gBACvB,WAAW,EAAE;oBACZ,YAAY,EAAE,KAAK;oBACnB,oBAAoB,EAAE,IAAI;iBAC1B;aACD,CAAC;QACH,KAAK,kBAAkB,CAAC;QACxB,KAAK,cAAc,CAAC;QACpB;YACC,OAAO;gBACN,KAAK,EAAE,gBAAgB;gBACvB,WAAW,EAAE;oBACZ,YAAY,EAAE,KAAK;oBACnB,oBAAoB,EAAE,KAAK;iBAC3B;aACD,CAAC;IACJ,CAAC;AACF,CAAC,CAAC","sourcesContent":["import type { TTSConfig } from \"./TTSService.js\";\nimport type { ToolProviderConfig } from \"./tools-config-normalizer.js\";\nimport {\n\tnormalizeSREMathSpeechOptions,\n\ttype SREMathSpeechOptions,\n} from \"./tts/math-speech.js\";\n\nexport type TTSLayoutMode =\n\t| \"reserved-row\"\n\t| \"expanding-row\"\n\t| \"floating-overlay\"\n\t| \"left-aligned\";\n\nconst VALID_TTS_LAYOUT_MODES = new Set<TTSLayoutMode>([\n\t\"reserved-row\",\n\t\"expanding-row\",\n\t\"floating-overlay\",\n\t\"left-aligned\",\n]);\n\nexport interface TTSHostToolbarLayout {\n\tmount: \"before-buttons\";\n\tcontrolsRow: {\n\t\treserveSpace: boolean;\n\t\texpandWhenToolActive: boolean;\n\t};\n}\n\nexport interface TTSRuntimeSettings {\n\tbackend?: \"browser\" | \"polly\" | \"google\" | \"server\";\n\tserverProvider?: \"polly\" | \"google\" | \"custom\";\n\tprovider?: \"polly\" | \"google\" | \"custom\";\n\tengine?: \"standard\" | \"neural\";\n\tsampleRate?: number;\n\tformat?: \"mp3\" | \"ogg\" | \"pcm\";\n\tspeechMarksMode?: \"word\" | \"word+sentence\";\n\tdefaultVoice?: string;\n\trate?: number;\n\tpitch?: number;\n\tapiEndpoint?: string;\n\tlanguage?: string;\n\ttransportMode?: \"pie\" | \"custom\";\n\tendpointMode?: \"synthesizePath\" | \"rootPost\";\n\tendpointValidationMode?: \"voices\" | \"endpoint\" | \"none\";\n\tincludeAuthOnAssetFetch?: boolean;\n\tvalidateEndpoint?: boolean;\n\tcache?: boolean;\n\tspeedRate?: \"slow\" | \"medium\" | \"fast\";\n\tlang_id?: string;\n\t/**\n\t * Optional inline TTS speed buttons.\n\t * - Omitted/non-array: default speed buttons are shown.\n\t * - Empty array: hide speed buttons.\n\t * - Arrays that sanitize to no valid values: default speed buttons are shown.\n\t */\n\tspeedOptions?: number[];\n\tlayoutMode?: TTSLayoutMode;\n\t/**\n\t * Per-token highlighting of math expressions.\n\t * - `true` / omitted (default): when the spoken math aligns confidently to the\n\t * rendered MathML, the formula is highlighted glyph by glyph; otherwise it\n\t * safely falls back to a whole-formula block.\n\t * - `false`: every formula is highlighted as a single block (the fallback),\n\t * never broken into per-token highlights. Prose word tracking is unaffected.\n\t */\n\tmathTokenHighlighting?: boolean;\n\t/**\n\t * Speech Rule Engine options for generated MathML speech. Hosts can use these\n\t * to tune SRE itself (for example ClearSpeak ImpliedTimes/Paren preferences)\n\t * instead of relying on toolkit-specific speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n}\n\nconst toRecord = (value: unknown): Record<string, unknown> =>\n\tvalue && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n\nconst isServerBackend = (\n\tbackend: TTSRuntimeSettings[\"backend\"],\n): backend is \"polly\" | \"google\" | \"server\" =>\n\tbackend === \"polly\" || backend === \"google\" || backend === \"server\";\n\nconst withDefault = <T>(value: T | undefined, fallback: T): T =>\n\tvalue === undefined ? fallback : value;\n\nexport const normalizeTTSLayoutMode = (\n\tvalue: unknown,\n\tfallback: TTSLayoutMode = \"left-aligned\",\n): TTSLayoutMode =>\n\ttypeof value === \"string\" &&\n\tVALID_TTS_LAYOUT_MODES.has(value as TTSLayoutMode)\n\t\t? (value as TTSLayoutMode)\n\t\t: fallback;\n\n/** Default inline TTS speed button multipliers (excluding 1.0×). */\nexport const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);\n\n/**\n * Resolves inline toolbar speed options from host config.\n * - Omitted/non-array: default speed buttons.\n * - Empty array: hide speed buttons.\n * - Arrays that sanitize to no valid values: default speed buttons.\n * - 1.0× is never shown as a discrete speed button.\n */\nexport const normalizeTTSSpeedOptions = (value: unknown): number[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\tconst deduped = new Set<number>();\n\tfor (const entry of value) {\n\t\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0)\n\t\t\tcontinue;\n\t\tconst rounded = Math.round(entry * 100) / 100;\n\t\tif (rounded === 1) continue;\n\t\tdeduped.add(rounded);\n\t}\n\treturn deduped.size ? Array.from(deduped) : [...DEFAULT_TTS_SPEED_OPTIONS];\n};\n\nexport const formatTTSSpeedOptionsAsText = (values: number[]): string =>\n\tvalues.join(\", \");\n\n/**\n * Parse comma/semicolon-separated multipliers from settings UI text.\n * - Empty or whitespace-only string → hide speed buttons (`[]`).\n * - Non-empty text with no parseable finite numbers → same as invalid-only array config: defaults.\n */\nexport const parseTTSSpeedOptionsFromText = (text: string): number[] => {\n\tconst trimmed = text.trim();\n\tif (!trimmed) return [];\n\tconst parts = trimmed\n\t\t.split(/[,;]+/)\n\t\t.map((p) => p.trim())\n\t\t.filter(Boolean);\n\tconst candidates = parts\n\t\t.map((p) => Number.parseFloat(p))\n\t\t.filter((n) => Number.isFinite(n));\n\tif (!candidates.length) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\treturn normalizeTTSSpeedOptions(candidates);\n};\n\nconst applyRuntimeDefaults = (\n\tconfig: TTSRuntimeSettings,\n): TTSRuntimeSettings => {\n\tconst withLayoutDefaults: TTSRuntimeSettings = {\n\t\t...config,\n\t\tlayoutMode: normalizeTTSLayoutMode(config.layoutMode),\n\t};\n\tconst backend = config.backend || \"browser\";\n\tif (!isServerBackend(backend)) return withLayoutDefaults;\n\n\tconst withServerDefaults: TTSRuntimeSettings = {\n\t\t...withLayoutDefaults,\n\t\tapiEndpoint: withDefault(withLayoutDefaults.apiEndpoint, \"/api/tts\"),\n\t\ttransportMode: withDefault(withLayoutDefaults.transportMode, \"pie\"),\n\t\tendpointValidationMode: withDefault(\n\t\t\twithLayoutDefaults.endpointValidationMode,\n\t\t\t\"voices\",\n\t\t),\n\t\tvalidateEndpoint: withDefault(withLayoutDefaults.validateEndpoint, true),\n\t\tincludeAuthOnAssetFetch: withDefault(\n\t\t\twithLayoutDefaults.includeAuthOnAssetFetch,\n\t\t\tfalse,\n\t\t),\n\t\trate: withDefault(withLayoutDefaults.rate, 1.0),\n\t\tlanguage: withDefault(withLayoutDefaults.language, \"en-US\"),\n\t};\n\n\tif (backend === \"polly\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(withServerDefaults.defaultVoice, \"Joanna\"),\n\t\t\tengine: withDefault(withServerDefaults.engine, \"neural\"),\n\t\t\tformat: withDefault(withServerDefaults.format, \"mp3\"),\n\t\t\tspeechMarksMode: withDefault(\n\t\t\t\twithServerDefaults.speechMarksMode,\n\t\t\t\t\"word+sentence\",\n\t\t\t),\n\t\t};\n\t}\n\n\tif (backend === \"google\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(\n\t\t\t\twithServerDefaults.defaultVoice,\n\t\t\t\t\"en-US-Wavenet-A\",\n\t\t\t),\n\t\t};\n\t}\n\n\treturn withServerDefaults;\n};\n\nexport const resolveTTSRuntimeSettings = (\n\tconfig: ToolProviderConfig | TTSRuntimeSettings | undefined,\n): TTSRuntimeSettings => {\n\tconst configRecord = toRecord(config);\n\tconst settingsRecord = toRecord(configRecord.settings);\n\treturn applyRuntimeDefaults({\n\t\t...configRecord,\n\t\t...settingsRecord,\n\t} as TTSRuntimeSettings);\n};\n\nexport const resolveTTSBackend = (\n\tconfig: TTSRuntimeSettings,\n): NonNullable<TTSRuntimeSettings[\"backend\"]> => config.backend || \"browser\";\n\nexport const resolveRuntimeProvider = (\n\tconfig: TTSRuntimeSettings,\n\tbackend: NonNullable<TTSRuntimeSettings[\"backend\"]>,\n): TTSRuntimeSettings[\"serverProvider\"] => {\n\tif (backend === \"polly\" || backend === \"google\") return backend;\n\tif (backend === \"server\") {\n\t\treturn config.serverProvider || config.provider;\n\t}\n\treturn config.serverProvider || config.provider;\n};\n\nexport const resolveTransportMode = (\n\tconfig: TTSRuntimeSettings,\n\truntimeProvider: TTSRuntimeSettings[\"serverProvider\"],\n): NonNullable<TTSRuntimeSettings[\"transportMode\"]> =>\n\tconfig.transportMode || (runtimeProvider === \"custom\" ? \"custom\" : \"pie\");\n\nexport const buildRuntimeTTSConfig = (\n\tconfig: TTSRuntimeSettings,\n): Partial<TTSConfig> => {\n\tconst backend = resolveTTSBackend(config);\n\tconst runtimeProvider = resolveRuntimeProvider(config, backend);\n\tconst transportMode = resolveTransportMode(config, runtimeProvider);\n\tconst mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);\n\treturn {\n\t\tvoice: config.defaultVoice,\n\t\trate: config.rate,\n\t\tpitch: config.pitch,\n\t\tproviderOptions: {\n\t\t\t...(config.language ? { locale: config.language } : {}),\n\t\t\t...(backend === \"polly\" && config.engine\n\t\t\t\t? { engine: config.engine }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && typeof config.sampleRate === \"number\"\n\t\t\t\t? { sampleRate: config.sampleRate }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && config.format\n\t\t\t\t? { format: config.format }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\"\n\t\t\t\t? {\n\t\t\t\t\t\tspeechMarkTypes:\n\t\t\t\t\t\t\tconfig.speechMarksMode === \"word+sentence\"\n\t\t\t\t\t\t\t\t? [\"word\", \"sentence\"]\n\t\t\t\t\t\t\t\t: [\"word\"],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && typeof config.cache === \"boolean\"\n\t\t\t\t? { cache: config.cache }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.speedRate\n\t\t\t\t? { speedRate: config.speedRate }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.lang_id\n\t\t\t\t? { lang_id: config.lang_id }\n\t\t\t\t: {}),\n\t\t\t...(mathSpeech ? { mathSpeech } : {}),\n\t\t},\n\t\tapiEndpoint: config.apiEndpoint,\n\t\tprovider: runtimeProvider,\n\t\tlanguage: config.language,\n\t\ttransportMode,\n\t\tendpointMode: config.endpointMode,\n\t\tendpointValidationMode: config.endpointValidationMode,\n\t\tincludeAuthOnAssetFetch: config.includeAuthOnAssetFetch,\n\t\tvalidateEndpoint: config.validateEndpoint,\n\t\t// Toolkit-level highlight setting carried through the config channel\n\t\t// (like apiEndpoint/transportMode); consumed by the highlight pipeline,\n\t\t// ignored by providers. Only forwarded when set so the pipeline default\n\t\t// (per-token enabled) applies otherwise.\n\t\t...(typeof config.mathTokenHighlighting === \"boolean\"\n\t\t\t? { mathTokenHighlighting: config.mathTokenHighlighting }\n\t\t\t: {}),\n\t} as Partial<TTSConfig>;\n};\n\nexport const resolveTTSLayoutMode = (\n\tconfig: TTSRuntimeSettings,\n): TTSLayoutMode => normalizeTTSLayoutMode(config.layoutMode);\n\nexport const resolveTTSHostToolbarLayout = (\n\tconfig: TTSRuntimeSettings,\n): TTSHostToolbarLayout => {\n\tconst layoutMode = resolveTTSLayoutMode(config);\n\tswitch (layoutMode) {\n\t\tcase \"reserved-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: true,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"expanding-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: true,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"floating-overlay\":\n\t\tcase \"left-aligned\":\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t}\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"desmos-provider.js","sourceRoot":"","sources":["../../../src/tools/calculators/desmos-provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Desmos Calculator Provider\n * Implementation of CalculatorProvider for Desmos calculators\n *\n * Supports: Basic, Scientific, and Graphing calculators\n * Based on Desmos API v1.10+\n */\n\nimport type {\n\tCalculationHistoryEntry,\n\tCalculator,\n\tCalculatorProvider,\n\tCalculatorProviderCapabilities,\n\tCalculatorProviderConfig,\n\tCalculatorState,\n\tCalculatorType,\n\tDesmosCalculatorConfig,\n} from \"@pie-players/pie-calculator\";\nimport { COMMON_LIBRARIES, libraryLoader } from \"../library-loader.js\";\n\n/**\n * Desmos Calculator Provider Implementation\n */\nexport class DesmosCalculatorProvider implements CalculatorProvider {\n\treadonly providerId = \"desmos\";\n\treadonly providerName = \"Desmos\";\n\treadonly supportedTypes: CalculatorType[] = [\n\t\t\"basic\",\n\t\t\"scientific\",\n\t\t\"graphing\",\n\t];\n\treadonly version = \"1.10\";\n\n\tprivate initialized = false;\n\tprivate apiKey?: string;\n\n\t/**\n\t * Get the configured API key\n\t */\n\tgetApiKey(): string | undefined {\n\t\treturn this.apiKey;\n\t}\n\n\t/**\n\t * Initialize Desmos library\n\t * @param config Optional configuration including API key\n\t */\n\tasync initialize(config?: { apiKey?: string }): Promise<void> {\n\t\tif (this.initialized) return;\n\n\t\t// SSR guard: Desmos calculators should NEVER run on the server\n\t\tif (typeof window === \"undefined\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"Desmos calculators can only be initialized in the browser\",\n\t\t\t);\n\t\t}\n\n\t\t// Store API key from config, environment variable, or global\n\t\tthis.apiKey =\n\t\t\tconfig?.apiKey ||\n\t\t\t(typeof process !== \"undefined\" && process.env?.DESMOS_API_KEY) ||\n\t\t\t(typeof window !== \"undefined\" && (window as any).PIE_DESMOS_API_KEY);\n\n\t\t// Warn if no API key is provided (production usage requires it)\n\t\tif (!this.apiKey) {\n\t\t\tconsole.warn(\n\t\t\t\t\"[DesmosProvider] No API key provided. Production usage requires a Desmos API key. \" +\n\t\t\t\t\t\"Obtain one from https://www.desmos.com/api or contact partnerships@desmos.com\",\n\t\t\t);\n\t\t}\n\n\t\t// Load Desmos library\n\t\tawait libraryLoader.loadScript(COMMON_LIBRARIES.desmos);\n\n\t\t// Verify Desmos API is available\n\t\tif (!(window as any).Desmos) {\n\t\t\tthrow new Error(\"Desmos API not loaded\");\n\t\t}\n\n\t\tthis.initialized = true;\n\t\tconsole.log(\n\t\t\t`[DesmosProvider] Initialized successfully${this.apiKey ? \" with API key\" : \" (no API key)\"}`,\n\t\t);\n\t}\n\n\t/**\n\t * Create a calculator instance\n\t */\n\tasync createCalculator(\n\t\ttype: CalculatorType,\n\t\tcontainer: HTMLElement,\n\t\tconfig?: CalculatorProviderConfig,\n\t): Promise<Calculator> {\n\t\tif (!this.initialized) {\n\t\t\tawait this.initialize();\n\t\t}\n\n\t\tif (!this.supportsType(type)) {\n\t\t\tthrow new Error(`Desmos does not support calculator type: ${type}`);\n\t\t}\n\n\t\treturn new DesmosCalculator(this, type, container, config);\n\t}\n\n\t/**\n\t * Check if type is supported\n\t */\n\tsupportsType(type: CalculatorType): boolean {\n\t\treturn this.supportedTypes.includes(type);\n\t}\n\n\t/**\n\t * Cleanup (no-op for Desmos)\n\t */\n\tdestroy(): void {\n\t\t// Desmos doesn't require global cleanup\n\t\tthis.initialized = false;\n\t}\n\n\t/**\n\t * Get provider capabilities\n\t */\n\tgetCapabilities(): CalculatorProviderCapabilities {\n\t\treturn {\n\t\t\tsupportsHistory: true,\n\t\t\tsupportsGraphing: true,\n\t\t\tsupportsExpressions: true,\n\t\t\tcanExport: true,\n\t\t\tmaxPrecision: 15, // JavaScript number precision\n\t\t\tinputMethods: [\"keyboard\", \"mouse\", \"touch\"],\n\t\t};\n\t}\n}\n\n/**\n * Desmos Calculator Instance\n */\nclass DesmosCalculator implements Calculator {\n\treadonly provider: CalculatorProvider;\n\treadonly type: CalculatorType;\n\n\tprivate desmosCalculator: any;\n\tprivate container: HTMLElement;\n\tprivate config?: CalculatorProviderConfig;\n\n\tconstructor(\n\t\tprovider: CalculatorProvider,\n\t\ttype: CalculatorType,\n\t\tcontainer: HTMLElement,\n\t\tconfig?: CalculatorProviderConfig,\n\t) {\n\t\tthis.provider = provider;\n\t\tthis.type = type;\n\t\tthis.container = container;\n\t\tthis.config = config;\n\n\t\tthis._initializeCalculator();\n\t}\n\n\t/**\n\t * Initialize Desmos calculator instance\n\t * Based on production implementation patterns\n\t */\n\tprivate _initializeCalculator(): void {\n\t\tconst Desmos = (window as any).Desmos;\n\n\t\t// Get Desmos-specific config or empty object\n\t\tconst desmosConfig = this.config?.desmos || {};\n\n\t\t// Determine API key (config overrides provider-level)\n\t\tconst apiKey =\n\t\t\tdesmosConfig.apiKey ||\n\t\t\t(this.provider as DesmosCalculatorProvider).getApiKey();\n\n\t\t// Apply restricted mode defaults if enabled\n\t\tconst restrictedDefaults = this._getRestrictedModeDefaults();\n\n\t\t// Merge order: type-specific defaults < restricted mode defaults < explicit config\n\t\t// This ensures explicit config can override restricted mode when needed\n\t\tconst options = {\n\t\t\t...this._getTypeSpecificDefaults(),\n\t\t\t...restrictedDefaults,\n\t\t\t...desmosConfig,\n\t\t\t...this._mapConfigToDesmos(this.config),\n\t\t};\n\n\t\t// Add API key if available\n\t\tif (apiKey) {\n\t\t\toptions.apiKey = apiKey;\n\t\t}\n\n\t\t// Create appropriate calculator type\n\t\tswitch (this.type) {\n\t\t\tcase \"basic\":\n\t\t\t\tthis.desmosCalculator = Desmos.FourFunctionCalculator(\n\t\t\t\t\tthis.container,\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"scientific\":\n\t\t\t\tthis.desmosCalculator = Desmos.ScientificCalculator(\n\t\t\t\t\tthis.container,\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"graphing\":\n\t\t\t\tthis.desmosCalculator = Desmos.GraphingCalculator(\n\t\t\t\t\tthis.container,\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown Desmos calculator type: ${this.type}`);\n\t\t}\n\n\t\tconsole.log(\n\t\t\t`[DesmosCalculator] Created ${this.type} calculator with options:`,\n\t\t\toptions,\n\t\t);\n\t}\n\n\t/**\n\t * Get type-specific default options\n\t */\n\tprivate _getTypeSpecificDefaults(): any {\n\t\tconst defaults: any = {\n\t\t\tborder: false, // No border around calculator (production implementation pattern)\n\t\t};\n\n\t\tswitch (this.type) {\n\t\t\tcase \"basic\":\n\t\t\t\t// Basic calculator: no keypad, no graph paper (just the calculator itself)\n\t\t\t\t// Matches production FourFunctionCalculator setup\n\t\t\t\tdefaults.keypad = false;\n\t\t\t\tdefaults.graphpaper = false;\n\t\t\t\tbreak;\n\t\t\tcase \"scientific\":\n\t\t\t\t// Scientific calculator: minimal defaults, mostly controlled by config\n\t\t\t\tbreak;\n\t\t\tcase \"graphing\":\n\t\t\t\t// Graphing calculator: enable expressions, zoom buttons, topbar by default\n\t\t\t\tdefaults.expressions = true;\n\t\t\t\tdefaults.zoomButtons = true;\n\t\t\t\tdefaults.expressionsTopbar = true;\n\t\t\t\tdefaults.settingsMenu = true;\n\t\t\t\tdefaults.notes = true;\n\t\t\t\tdefaults.folders = true;\n\t\t\t\tdefaults.images = false; // Images disabled by default (production pattern)\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn defaults;\n\t}\n\n\t/**\n\t * Get restricted mode defaults (test mode options)\n\t * Based on production test mode configuration\n\t */\n\tprivate _getRestrictedModeDefaults(): any {\n\t\tif (!this.config?.restrictedMode) {\n\t\t\treturn {};\n\t\t}\n\n\t\t// Restricted mode defaults based on production test mode settings\n\t\tconst restricted: any = {\n\t\t\tborder: false,\n\t\t\tlinks: false,\n\t\t\tqwertyKeyboard: true,\n\t\t\tdegreeMode: true,\n\t\t\tdecimalToFraction: true,\n\t\t};\n\n\t\t// Type-specific restricted mode options\n\t\tif (this.type === \"graphing\") {\n\t\t\tObject.assign(restricted, {\n\t\t\t\timages: false,\n\t\t\t\tfolders: false,\n\t\t\t\tnotes: false,\n\t\t\t\trestrictedFunctions: true,\n\t\t\t\tplotSingleVariableImplicitEquations: false,\n\t\t\t\tplotImplicits: false,\n\t\t\t\tplotInequalities: false,\n\t\t\t\tsliders: false,\n\t\t\t\tsettingsMenu: false,\n\t\t\t\tzoomButtons: false,\n\t\t\t\tgeometryComputationFunctions: true,\n\t\t\t\tdistributions: true,\n\t\t\t});\n\t\t} else if (this.type === \"scientific\") {\n\t\t\tObject.assign(restricted, {\n\t\t\t\tfunctionDefinition: false,\n\t\t\t\tbrailleExpressionDownload: false,\n\t\t\t});\n\t\t}\n\n\t\treturn restricted;\n\t}\n\n\t/**\n\t * Map provider config to Desmos options\n\t */\n\tprivate _mapConfigToDesmos(config?: CalculatorProviderConfig): any {\n\t\tif (!config) return {};\n\n\t\tconst desmosOptions: any = {};\n\n\t\t// Map locale to Desmos language option\n\t\tif (config.locale) {\n\t\t\tdesmosOptions.language = config.locale;\n\t\t}\n\n\t\t// Theme mapping (Desmos may support this via CSS, not API)\n\t\t// Note: Desmos doesn't have a theme option in the API, but we keep this\n\t\t// for potential future use or CSS-based theming\n\n\t\treturn desmosOptions;\n\t}\n\n\t/**\n\t * Get current value/expression\n\t */\n\tgetValue(): string {\n\t\t// For graphing calculator, get all expressions\n\t\tif (this.type === \"graphing\") {\n\t\t\tconst state = this.desmosCalculator.getState();\n\t\t\treturn JSON.stringify(state.expressions.list);\n\t\t}\n\n\t\t// For basic/scientific, get current expression\n\t\tconst state = this.desmosCalculator.getState();\n\t\treturn state.expression || \"\";\n\t}\n\n\t/**\n\t * Set value/expression\n\t */\n\tsetValue(value: string): void {\n\t\tif (this.type === \"graphing\") {\n\t\t\ttry {\n\t\t\t\tconst expressions = JSON.parse(value);\n\t\t\t\tthis.desmosCalculator.setState({ expressions: { list: expressions } });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"[DesmosCalculator] Invalid expression format:\", error);\n\t\t\t}\n\t\t} else {\n\t\t\t// Basic/Scientific calculators\n\t\t\tthis.desmosCalculator.setExpression({ latex: value });\n\t\t}\n\t}\n\n\t/**\n\t * Clear calculator\n\t */\n\tclear(): void {\n\t\tif (this.type === \"graphing\") {\n\t\t\tthis.desmosCalculator.setBlank();\n\t\t} else {\n\t\t\tthis.setValue(\"\");\n\t\t}\n\t}\n\n\t/**\n\t * Get calculation history (not natively supported by Desmos)\n\t */\n\tgetHistory(): CalculationHistoryEntry[] {\n\t\t// Desmos doesn't provide history natively\n\t\t// Would need to implement custom tracking\n\t\treturn [];\n\t}\n\n\t/**\n\t * Clear history\n\t */\n\tclearHistory(): void {\n\t\t// No-op - Desmos doesn't have history\n\t}\n\n\t/**\n\t * Resize calculator when container dimensions change\n\t * Matches production pattern: calculatorInstance.resize()\n\t */\n\tresize(): void {\n\t\tif (\n\t\t\tthis.desmosCalculator &&\n\t\t\ttypeof this.desmosCalculator.resize === \"function\"\n\t\t) {\n\t\t\tthis.desmosCalculator.resize();\n\t\t}\n\t}\n\n\t/**\n\t * Move keyboard focus to the primary input/expression field so keyboard\n\t * users can begin typing immediately after the calculator opens.\n\t */\n\tfocus(): void {\n\t\ttry {\n\t\t\tif (\n\t\t\t\tthis.type === \"graphing\" &&\n\t\t\t\ttypeof this.desmosCalculator?.focusFirstExpression === \"function\"\n\t\t\t) {\n\t\t\t\tthis.desmosCalculator.focusFirstExpression();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst target = this.container.querySelector<HTMLElement>(\n\t\t\t\t'.dcg-mq-editable-field[tabindex=\"0\"], textarea, [contenteditable=\"true\"], [tabindex]:not([tabindex=\"-1\"])',\n\t\t\t);\n\t\t\ttarget?.focus();\n\t\t} catch (error) {\n\t\t\tconsole.warn(\"[DesmosCalculator] focus() failed:\", error);\n\t\t}\n\t}\n\n\t/**\n\t * Evaluate expression (for graphing calculator)\n\t */\n\tasync evaluate(expression: string): Promise<string> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\t// Set expression and wait for computation\n\t\t\t\tthis.desmosCalculator.setExpression({ latex: expression });\n\n\t\t\t\t// For basic math, Desmos evaluates automatically\n\t\t\t\t// Get the result from state\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tconst result = this.getValue();\n\t\t\t\t\tresolve(result);\n\t\t\t\t}, 100); // Small delay for Desmos to compute\n\t\t\t} catch (error) {\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Export calculator state\n\t */\n\texportState(): CalculatorState {\n\t\tconst state = this.desmosCalculator.getState();\n\n\t\treturn {\n\t\t\ttype: this.type,\n\t\t\tprovider: \"desmos\",\n\t\t\tvalue: this.getValue(),\n\t\t\tproviderState: state,\n\t\t};\n\t}\n\n\t/**\n\t * Import calculator state\n\t */\n\timportState(state: CalculatorState): void {\n\t\tif (state.provider !== \"desmos\") {\n\t\t\tthrow new Error(`Cannot import state from provider: ${state.provider}`);\n\t\t}\n\n\t\tif (state.providerState) {\n\t\t\tthis.desmosCalculator.setState(state.providerState);\n\t\t} else if (state.value) {\n\t\t\tthis.setValue(state.value);\n\t\t}\n\t}\n\n\t/**\n\t * Destroy calculator\n\t */\n\tdestroy(): void {\n\t\tif (this.desmosCalculator) {\n\t\t\ttry {\n\t\t\t\tthis.desmosCalculator.destroy();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\"[DesmosCalculator] Error during destroy:\", error);\n\t\t\t}\n\t\t\tthis.desmosCalculator = null;\n\t\t}\n\n\t\t// Clear the container to ensure Desmos releases all references\n\t\tif (this.container) {\n\t\t\t// Remove any Desmos-specific attributes\n\t\t\tthis.container.removeAttribute(\"data-desmos-id\");\n\n\t\t\t// Use modern API - more efficient and cleaner\n\t\t\tthis.container.replaceChildren();\n\t\t}\n\t}\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"desmos-provider.js","sourceRoot":"","sources":["../../../src/tools/calculators/desmos-provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Desmos Calculator Provider\n * Implementation of CalculatorProvider for Desmos calculators\n *\n * Supports: Basic, Scientific, and Graphing calculators\n * Based on Desmos API v1.10+\n */\n\nimport type {\n\tCalculationHistoryEntry,\n\tCalculator,\n\tCalculatorProvider,\n\tCalculatorProviderCapabilities,\n\tCalculatorProviderConfig,\n\tCalculatorState,\n\tCalculatorType,\n\tDesmosCalculatorConfig,\n} from \"@pie-players/pie-calculator\";\nimport { COMMON_LIBRARIES, libraryLoader } from \"../library-loader.js\";\n\n/**\n * Desmos Calculator Provider Implementation\n */\nexport class DesmosCalculatorProvider implements CalculatorProvider {\n\treadonly providerId = \"desmos\";\n\treadonly providerName = \"Desmos\";\n\treadonly supportedTypes: CalculatorType[] = [\n\t\t\"basic\",\n\t\t\"scientific\",\n\t\t\"graphing\",\n\t];\n\treadonly version = \"1.10\";\n\n\tprivate initialized = false;\n\tprivate apiKey?: string;\n\n\t/**\n\t * Get the configured API key\n\t */\n\tgetApiKey(): string | undefined {\n\t\treturn this.apiKey;\n\t}\n\n\t/**\n\t * Initialize Desmos library\n\t * @param config Optional configuration including API key\n\t */\n\tasync initialize(config?: { apiKey?: string }): Promise<void> {\n\t\tif (this.initialized) return;\n\n\t\t// SSR guard: Desmos calculators should NEVER run on the server\n\t\tif (typeof window === \"undefined\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"Desmos calculators can only be initialized in the browser\",\n\t\t\t);\n\t\t}\n\n\t\t// Store API key from config, environment variable, or global\n\t\tthis.apiKey =\n\t\t\tconfig?.apiKey ||\n\t\t\t(typeof process !== \"undefined\" && process.env?.DESMOS_API_KEY) ||\n\t\t\t(typeof window !== \"undefined\" && (window as any).PIE_DESMOS_API_KEY);\n\n\t\t// Warn if no API key is provided (production usage requires it)\n\t\tif (!this.apiKey) {\n\t\t\tconsole.warn(\n\t\t\t\t\"[DesmosProvider] No API key provided. Production usage requires a Desmos API key. \" +\n\t\t\t\t\t\"Obtain one from https://www.desmos.com/api or contact partnerships@desmos.com\",\n\t\t\t);\n\t\t}\n\n\t\t// Load Desmos library\n\t\tawait libraryLoader.loadScript(COMMON_LIBRARIES.desmos);\n\n\t\t// Verify Desmos API is available\n\t\tif (!(window as any).Desmos) {\n\t\t\tthrow new Error(\"Desmos API not loaded\");\n\t\t}\n\n\t\tthis.initialized = true;\n\t\tconsole.log(\n\t\t\t`[DesmosProvider] Initialized successfully${this.apiKey ? \" with API key\" : \" (no API key)\"}`,\n\t\t);\n\t}\n\n\t/**\n\t * Create a calculator instance\n\t */\n\tasync createCalculator(\n\t\ttype: CalculatorType,\n\t\tcontainer: HTMLElement,\n\t\tconfig?: CalculatorProviderConfig,\n\t): Promise<Calculator> {\n\t\tif (!this.initialized) {\n\t\t\tawait this.initialize();\n\t\t}\n\n\t\tif (!this.supportsType(type)) {\n\t\t\tthrow new Error(`Desmos does not support calculator type: ${type}`);\n\t\t}\n\n\t\treturn new DesmosCalculator(this, type, container, config);\n\t}\n\n\t/**\n\t * Check if type is supported\n\t */\n\tsupportsType(type: CalculatorType): boolean {\n\t\treturn this.supportedTypes.includes(type);\n\t}\n\n\t/**\n\t * Cleanup (no-op for Desmos)\n\t */\n\tdestroy(): void {\n\t\t// Desmos doesn't require global cleanup\n\t\tthis.initialized = false;\n\t}\n\n\t/**\n\t * Get provider capabilities\n\t */\n\tgetCapabilities(): CalculatorProviderCapabilities {\n\t\treturn {\n\t\t\tsupportsHistory: true,\n\t\t\tsupportsGraphing: true,\n\t\t\tsupportsExpressions: true,\n\t\t\tcanExport: true,\n\t\t\tmaxPrecision: 15, // JavaScript number precision\n\t\t\tinputMethods: [\"keyboard\", \"mouse\", \"touch\"],\n\t\t};\n\t}\n}\n\n/**\n * Desmos Calculator Instance\n */\nclass DesmosCalculator implements Calculator {\n\treadonly provider: CalculatorProvider;\n\treadonly type: CalculatorType;\n\n\tprivate desmosCalculator: any;\n\tprivate container: HTMLElement;\n\tprivate config?: CalculatorProviderConfig;\n\n\tconstructor(\n\t\tprovider: CalculatorProvider,\n\t\ttype: CalculatorType,\n\t\tcontainer: HTMLElement,\n\t\tconfig?: CalculatorProviderConfig,\n\t) {\n\t\tthis.provider = provider;\n\t\tthis.type = type;\n\t\tthis.container = container;\n\t\tthis.config = config;\n\n\t\tthis._initializeCalculator();\n\t}\n\n\t/**\n\t * Initialize Desmos calculator instance\n\t * Based on production implementation patterns\n\t */\n\tprivate _initializeCalculator(): void {\n\t\tconst Desmos = (window as any).Desmos;\n\n\t\t// Get Desmos-specific config or empty object\n\t\tconst desmosConfig = this.config?.desmos || {};\n\n\t\t// Determine API key (config overrides provider-level)\n\t\tconst apiKey =\n\t\t\tdesmosConfig.apiKey ||\n\t\t\t(this.provider as DesmosCalculatorProvider).getApiKey();\n\n\t\t// Apply restricted mode defaults if enabled\n\t\tconst restrictedDefaults = this._getRestrictedModeDefaults();\n\n\t\t// Merge order: type-specific defaults < restricted mode defaults < explicit config\n\t\t// This ensures explicit config can override restricted mode when needed\n\t\tconst options = {\n\t\t\t...this._getTypeSpecificDefaults(),\n\t\t\t...restrictedDefaults,\n\t\t\t...desmosConfig,\n\t\t\t...this._mapConfigToDesmos(this.config),\n\t\t};\n\n\t\t// Add API key if available\n\t\tif (apiKey) {\n\t\t\toptions.apiKey = apiKey;\n\t\t}\n\n\t\t// Create appropriate calculator type\n\t\tswitch (this.type) {\n\t\t\tcase \"basic\":\n\t\t\t\tthis.desmosCalculator = Desmos.FourFunctionCalculator(\n\t\t\t\t\tthis.container,\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"scientific\":\n\t\t\t\tthis.desmosCalculator = Desmos.ScientificCalculator(\n\t\t\t\t\tthis.container,\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"graphing\":\n\t\t\t\tthis.desmosCalculator = Desmos.GraphingCalculator(\n\t\t\t\t\tthis.container,\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown Desmos calculator type: ${this.type}`);\n\t\t}\n\n\t\tconsole.log(\n\t\t\t`[DesmosCalculator] Created ${this.type} calculator with options:`,\n\t\t\toptions,\n\t\t);\n\t}\n\n\t/**\n\t * Get type-specific default options\n\t */\n\tprivate _getTypeSpecificDefaults(): any {\n\t\tconst defaults: any = {\n\t\t\tborder: false, // No border around calculator (production implementation pattern)\n\t\t};\n\n\t\tswitch (this.type) {\n\t\t\tcase \"basic\":\n\t\t\t\t// Basic calculator: no keypad, no graph paper (just the calculator itself)\n\t\t\t\t// Matches production FourFunctionCalculator setup\n\t\t\t\tdefaults.keypad = false;\n\t\t\t\tdefaults.graphpaper = false;\n\t\t\t\tbreak;\n\t\t\tcase \"scientific\":\n\t\t\t\t// Scientific calculator: minimal defaults, mostly controlled by config\n\t\t\t\tbreak;\n\t\t\tcase \"graphing\":\n\t\t\t\t// Graphing calculator: enable expressions, zoom buttons, topbar by default\n\t\t\t\tdefaults.expressions = true;\n\t\t\t\tdefaults.zoomButtons = true;\n\t\t\t\tdefaults.expressionsTopbar = true;\n\t\t\t\tdefaults.settingsMenu = true;\n\t\t\t\tdefaults.notes = true;\n\t\t\t\tdefaults.folders = true;\n\t\t\t\tdefaults.images = false; // Images disabled by default (production pattern)\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn defaults;\n\t}\n\n\t/**\n\t * Get restricted mode defaults (test mode options)\n\t * Based on production test mode configuration\n\t */\n\tprivate _getRestrictedModeDefaults(): any {\n\t\tif (!this.config?.restrictedMode) {\n\t\t\treturn {};\n\t\t}\n\n\t\t// Restricted mode defaults based on production test mode settings\n\t\tconst restricted: any = {\n\t\t\tborder: false,\n\t\t\tlinks: false,\n\t\t\tqwertyKeyboard: true,\n\t\t\tdegreeMode: true,\n\t\t\tdecimalToFraction: true,\n\t\t};\n\n\t\t// Type-specific restricted mode options\n\t\tif (this.type === \"graphing\") {\n\t\t\tObject.assign(restricted, {\n\t\t\t\timages: false,\n\t\t\t\tfolders: false,\n\t\t\t\tnotes: false,\n\t\t\t\trestrictedFunctions: true,\n\t\t\t\tplotSingleVariableImplicitEquations: false,\n\t\t\t\tplotImplicits: false,\n\t\t\t\tplotInequalities: false,\n\t\t\t\tsliders: false,\n\t\t\t\tsettingsMenu: false,\n\t\t\t\tzoomButtons: false,\n\t\t\t\tgeometryComputationFunctions: true,\n\t\t\t\tdistributions: true,\n\t\t\t});\n\t\t} else if (this.type === \"scientific\") {\n\t\t\tObject.assign(restricted, {\n\t\t\t\tfunctionDefinition: false,\n\t\t\t\tbrailleExpressionDownload: false,\n\t\t\t});\n\t\t}\n\n\t\treturn restricted;\n\t}\n\n\t/**\n\t * Map provider config to Desmos options\n\t */\n\tprivate _mapConfigToDesmos(config?: CalculatorProviderConfig): any {\n\t\tif (!config) return {};\n\n\t\tconst desmosOptions: any = {};\n\n\t\t// Map locale to Desmos language option\n\t\tif (config.locale) {\n\t\t\tdesmosOptions.language = config.locale;\n\t\t}\n\n\t\t// Theme mapping (Desmos may support this via CSS, not API)\n\t\t// Note: Desmos doesn't have a theme option in the API, but we keep this\n\t\t// for potential future use or CSS-based theming\n\n\t\treturn desmosOptions;\n\t}\n\n\t/**\n\t * Get current value/expression\n\t */\n\tgetValue(): string {\n\t\t// For graphing calculator, get all expressions\n\t\tif (this.type === \"graphing\") {\n\t\t\tconst state = this.desmosCalculator.getState();\n\t\t\treturn JSON.stringify(state.expressions.list);\n\t\t}\n\n\t\t// For basic/scientific, get current expression\n\t\tconst state = this.desmosCalculator.getState();\n\t\treturn state.expression || \"\";\n\t}\n\n\t/**\n\t * Set value/expression\n\t */\n\tsetValue(value: string): void {\n\t\tif (this.type === \"graphing\") {\n\t\t\ttry {\n\t\t\t\tconst expressions = JSON.parse(value);\n\t\t\t\tthis.desmosCalculator.setState({ expressions: { list: expressions } });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"[DesmosCalculator] Invalid expression format:\", error);\n\t\t\t}\n\t\t} else {\n\t\t\t// Basic/Scientific calculators\n\t\t\tthis.desmosCalculator.setExpression({ latex: value });\n\t\t}\n\t}\n\n\t/**\n\t * Clear calculator\n\t */\n\tclear(): void {\n\t\tif (this.type === \"graphing\") {\n\t\t\tthis.desmosCalculator.setBlank();\n\t\t} else {\n\t\t\tthis.setValue(\"\");\n\t\t}\n\t}\n\n\t/**\n\t * Get calculation history (not natively supported by Desmos)\n\t */\n\tgetHistory(): CalculationHistoryEntry[] {\n\t\t// Desmos doesn't provide history natively\n\t\t// Would need to implement custom tracking\n\t\treturn [];\n\t}\n\n\t/**\n\t * Clear history\n\t */\n\tclearHistory(): void {\n\t\t// No-op - Desmos doesn't have history\n\t}\n\n\t/**\n\t * Resize calculator when container dimensions change\n\t * Matches production pattern: calculatorInstance.resize()\n\t */\n\tresize(): void {\n\t\tif (\n\t\t\tthis.desmosCalculator &&\n\t\t\ttypeof this.desmosCalculator.resize === \"function\"\n\t\t) {\n\t\t\tthis.desmosCalculator.resize();\n\t\t}\n\t}\n\n\t/**\n\t * Move keyboard focus to the primary input/expression field so keyboard\n\t * users can begin typing immediately after the calculator opens.\n\t */\n\tfocus(): void {\n\t\ttry {\n\t\t\tif (\n\t\t\t\tthis.type === \"graphing\" &&\n\t\t\t\ttypeof this.desmosCalculator?.focusFirstExpression === \"function\"\n\t\t\t) {\n\t\t\t\tthis.desmosCalculator.focusFirstExpression();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst target = this.container.querySelector<HTMLElement>(\n\t\t\t\t'.dcg-mq-editable-field[tabindex=\"0\"], textarea, [contenteditable=\"true\"], [tabindex]:not([tabindex=\"-1\"])',\n\t\t\t);\n\t\t\ttarget?.focus();\n\t\t} catch (error) {\n\t\t\tconsole.warn(\"[DesmosCalculator] focus() failed:\", error);\n\t\t}\n\t}\n\n\t/**\n\t * Evaluate expression (for graphing calculator)\n\t */\n\tasync evaluate(expression: string): Promise<string> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\t// Set expression and wait for computation\n\t\t\t\tthis.desmosCalculator.setExpression({ latex: expression });\n\n\t\t\t\t// For basic math, Desmos evaluates automatically\n\t\t\t\t// Get the result from state\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tconst result = this.getValue();\n\t\t\t\t\tresolve(result);\n\t\t\t\t}, 100); // Small delay for Desmos to compute\n\t\t\t} catch (error) {\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Export calculator state\n\t */\n\texportState(): CalculatorState {\n\t\tconst state = this.desmosCalculator.getState();\n\n\t\treturn {\n\t\t\ttype: this.type,\n\t\t\tprovider: \"desmos\",\n\t\t\tvalue: this.getValue(),\n\t\t\tproviderState: state,\n\t\t};\n\t}\n\n\t/**\n\t * Import calculator state\n\t */\n\timportState(state: CalculatorState): void {\n\t\tif (state.provider !== \"desmos\") {\n\t\t\tthrow new Error(`Cannot import state from provider: ${state.provider}`);\n\t\t}\n\n\t\tif (state.providerState) {\n\t\t\tthis.desmosCalculator.setState(state.providerState);\n\t\t} else if (state.value) {\n\t\t\tthis.setValue(state.value);\n\t\t}\n\t}\n\n\t/**\n\t * Destroy calculator\n\t */\n\tdestroy(): void {\n\t\tif (this.desmosCalculator) {\n\t\t\ttry {\n\t\t\t\tthis.desmosCalculator.destroy();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\"[DesmosCalculator] Error during destroy:\", error);\n\t\t\t}\n\t\t\tthis.desmosCalculator = null;\n\t\t}\n\n\t\t// Clear the container to ensure Desmos releases all references\n\t\tif (this.container) {\n\t\t\t// Remove any Desmos-specific attributes\n\t\t\tthis.container.removeAttribute(\"data-desmos-id\");\n\n\t\t\t// Use modern API - more efficient and cleaner\n\t\t\tthis.container.replaceChildren();\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-tool-module-loaders.js","sourceRoot":"","sources":["../../src/tools/default-tool-module-loaders.ts"],"names":[],"mappings":"AAEA,MAAM,oBAAoB,GAAG,
|
|
1
|
+
{"version":3,"file":"default-tool-module-loaders.js","sourceRoot":"","sources":["../../src/tools/default-tool-module-loaders.ts"],"names":[],"mappings":"AAEA,MAAM,oBAAoB,GAAG,CAAC,IAA4B,EAAiB,EAAE,CAC5E,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AAE9B;;;;;GAKG;AACH,SAAS,oBAAoB;IAC5B,IACC,OAAO,UAAU,KAAK,WAAW;QACjC,gBAAgB,IAAI,UAAU;QAC9B,UAAU,CAAC,cAAc,EAAE,GAAG,CAAC,qBAAqB,CAAC,EACpD,CAAC;QACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,oBAAoB,CAC1B,GAAG,EAAE;IACJ,0IAA0I;IAC1I,2EAA2E;IAC3E,MAAM,CAAC,yCAAyC,CAAC,CAClD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAqC;IAC5E,6DAA6D;IAC7D,iEAAiE;IACjE,UAAU,EAAE,oBAAoB;IAChC,YAAY,EAAE,GAAG,EAAE,CAClB,oBAAoB,CACnB,GAAG,EAAE;IACJ,0IAA0I;IAC1I,2EAA2E;IAC3E,MAAM,CAAC,kCAAkC,CAAC,CAC3C;CACF,CAAC","sourcesContent":["import type { ToolModuleLoader } from \"../services/ToolRegistry.js\";\n\nconst loadSideEffectModule = (load: () => Promise<unknown>): Promise<void> =>\n\tload().then(() => undefined);\n\n/**\n * Default lazy module loaders for built-in tools.\n *\n * Keeping this map near tool registrations avoids hard-coding module imports\n * in runtime components.\n */\nfunction loadCalculatorModule(): Promise<unknown> {\n\tif (\n\t\ttypeof globalThis !== \"undefined\" &&\n\t\t\"customElements\" in globalThis &&\n\t\tglobalThis.customElements?.get(\"pie-tool-calculator\")\n\t) {\n\t\treturn Promise.resolve();\n\t}\n\treturn loadSideEffectModule(\n\t\t() =>\n\t\t\t// biome-ignore lint/suspicious/noTsIgnore: module is optional; @ts-expect-error would fail in workspace builds where the symlink resolves\n\t\t\t// @ts-ignore Optional host module may be absent from toolkit package deps.\n\t\t\timport(\"@pie-players/pie-tool-calculator-desmos\"),\n\t);\n}\n\nexport const DEFAULT_TOOL_MODULE_LOADERS: Record<string, ToolModuleLoader> = {\n\t// Keep toolkit defaults limited to broadly expected modules.\n\t// Hosts can register additional optional tool loaders as needed.\n\tcalculator: loadCalculatorModule,\n\ttextToSpeech: () =>\n\t\tloadSideEffectModule(\n\t\t\t() =>\n\t\t\t\t// biome-ignore lint/suspicious/noTsIgnore: module is optional; @ts-expect-error would fail in workspace builds where the symlink resolves\n\t\t\t\t// @ts-ignore Optional host module may be absent from toolkit package deps.\n\t\t\t\timport(\"@pie-players/pie-tool-tts-inline\"),\n\t\t),\n};\n"]}
|