@magmamath/students-features 0.9.111-rc-4 → 0.9.111-rc.6
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/commonjs/features/chatbot/TTS_HIGHLIGHTING.md +29 -17
- package/dist/commonjs/features/chatbot/components/Chat/Chat.js +4 -3
- package/dist/commonjs/features/chatbot/components/Chat/Chat.js.map +1 -1
- package/dist/commonjs/features/openEnded/components/OpenEndedScoreLabel.js +8 -2
- package/dist/commonjs/features/openEnded/components/OpenEndedScoreLabel.js.map +1 -1
- package/dist/module/features/chatbot/TTS_HIGHLIGHTING.md +29 -17
- package/dist/module/features/chatbot/components/Chat/Chat.js +4 -3
- package/dist/module/features/chatbot/components/Chat/Chat.js.map +1 -1
- package/dist/module/features/openEnded/components/OpenEndedScoreLabel.js +8 -2
- package/dist/module/features/openEnded/components/OpenEndedScoreLabel.js.map +1 -1
- package/dist/typescript/commonjs/features/openEnded/components/OpenEndedScoreLabel.d.ts.map +1 -1
- package/dist/typescript/module/features/openEnded/components/OpenEndedScoreLabel.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/features/chatbot/TTS_HIGHLIGHTING.md +29 -17
- package/src/features/chatbot/components/Chat/Chat.tsx +3 -3
- package/src/features/openEnded/components/OpenEndedScoreLabel.tsx +11 -2
|
@@ -39,16 +39,16 @@ chatModel.bot.setUpT2S({
|
|
|
39
39
|
|
|
40
40
|
## Architecture
|
|
41
41
|
|
|
42
|
-
###
|
|
42
|
+
### ChatTTSModel (ChatTTSModel.ts)
|
|
43
43
|
|
|
44
44
|
Handles TTS playback and word highlighting. Key design decisions:
|
|
45
45
|
|
|
46
|
-
- **
|
|
46
|
+
- **Map-based cache** — `audioCache: Map<string, AudioCache>` stores both `audioPath` and `timepoints` per message. When highlighting is off, `timepoints` is `[]`. Cache lives for the model's lifetime (cleared when user leaves the problem).
|
|
47
47
|
- **`fetchAudio()` method** — encapsulates API call + audioContent decoding. Highlight vs non-highlight differences are ternaries (SSML vs plain text, `enableTimePointing`).
|
|
48
48
|
- **`play()` is linear** — cache lookup → fetch if miss → store → activate highlight if enabled → play audio. No branching between highlight/non-highlight paths.
|
|
49
|
-
-
|
|
50
|
-
- **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at
|
|
51
|
-
- **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
|
|
49
|
+
- **Pause/resume guards** — `wordHighlightEnabled` check before toggling `setIsActive(false)`/`setIsActive(true)` on pause/resume.
|
|
50
|
+
- **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at `setConfig`.
|
|
51
|
+
- **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
|
|
52
52
|
|
|
53
53
|
### AudioProvider type
|
|
54
54
|
|
|
@@ -66,17 +66,28 @@ type AudioProvider = {
|
|
|
66
66
|
|
|
67
67
|
### ChatTTSHighlightModel (ChatTTSHighlightModel.ts)
|
|
68
68
|
|
|
69
|
-
Manages highlight state. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
|
|
69
|
+
Manages highlight state using Effector stores with declarative reset. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
|
|
70
70
|
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
71
|
+
- **`$isActive`** — gates `$highlightedWordIndex` computation. Toggled on pause/resume without resetting timepoints.
|
|
72
|
+
- **`$highlightedWordIndex`** — derived store, returns `-1` when inactive or no match. Parses mark name via `WORD_MARK_REGEX`.
|
|
73
|
+
- **`activate(timepoints, onTimeUpdate)`** — sets timepoints, enables highlighting, registers time update callback. Only triggers store updates when the highlighted word actually changes (`lastMark` comparison).
|
|
74
|
+
- **`deactivate(onTimeUpdate)`** — stops listening, resets all state via declarative `.reset()` chain.
|
|
75
|
+
- **All stores use `.reset(this.reset)`** — single `reset` event clears `$time`, `$timepoints`, and `$isActive`.
|
|
76
|
+
|
|
77
|
+
### Helpers (helpers/ttsHighlight.ts)
|
|
78
|
+
|
|
79
|
+
- **`textToSSML(text)`** — converts plain text to SSML with `<mark>` tags for word timing.
|
|
80
|
+
- **`findCurrentMark(timepoints, time)`** — iterates backwards through timepoints to find the current mark. Efficient for linear playback.
|
|
81
|
+
|
|
82
|
+
### Constants (constants.ts)
|
|
83
|
+
|
|
84
|
+
- **`WORD_MARK_REGEX`** — `/^w_(\d+)$/` — extracts word index from mark names like `w_0`, `w_1`.
|
|
74
85
|
|
|
75
86
|
### Naming conventions
|
|
76
87
|
|
|
77
88
|
| Name | Scope | Purpose |
|
|
78
89
|
|------|-------|---------|
|
|
79
|
-
| `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `
|
|
90
|
+
| `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `ChatTTSModel` |
|
|
80
91
|
| `wordHighlightEnabled` | private field | Whether highlighting is active (set once at config) |
|
|
81
92
|
| `isWordHighlightEnabled` | public getter | Read-only access to `wordHighlightEnabled` for external consumers |
|
|
82
93
|
| `isWordHighlightEnabled` | T2SConfig field | Config flag passed to `setUpT2S()` |
|
|
@@ -90,19 +101,20 @@ ChatTTSHighlightModel.activate(timepoints, onTimeUpdate)
|
|
|
90
101
|
↓
|
|
91
102
|
RAF loop → audio.currentTime → findCurrentMark() → only updates when mark changes
|
|
92
103
|
↓
|
|
93
|
-
$highlightedWordIndex = parse mark name "w_N" → N
|
|
104
|
+
$highlightedWordIndex = parse mark name "w_N" → N (or -1 if inactive/no match)
|
|
94
105
|
↓
|
|
95
|
-
Chat.tsx: model.t2s.isWordHighlightEnabled &&
|
|
106
|
+
Chat.tsx: model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1
|
|
96
107
|
↓
|
|
97
|
-
ChatMessage → MessageContent →
|
|
108
|
+
ChatMessage → MessageContent → TTSHighlightRenderer({ text, highlightedIndex })
|
|
98
109
|
```
|
|
99
110
|
|
|
100
111
|
## Key Files
|
|
101
112
|
|
|
102
113
|
| File | Purpose |
|
|
103
114
|
|------|---------|
|
|
104
|
-
| `model/ChatTTSModel.ts` | `
|
|
105
|
-
| `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, derived word index |
|
|
106
|
-
| `helpers/
|
|
107
|
-
| `
|
|
115
|
+
| `model/ChatTTSModel.ts` | `ChatTTSModel` — TTS playback, caching, highlight orchestration |
|
|
116
|
+
| `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, `$isActive`, derived word index |
|
|
117
|
+
| `helpers/ttsHighlight.ts` | `textToSSML` + `findCurrentMark` — SSML conversion and playback position lookup |
|
|
118
|
+
| `constants.ts` | `WORD_MARK_REGEX` and audio config defaults |
|
|
119
|
+
| `types/t2s.types.ts` | `AudioProvider`, `OnTimeUpdate`, `AudioStatus`, `AudioCache`, `TTSHighlightRendererProps` types |
|
|
108
120
|
| `components/Chat/Chat.tsx` | Reads `isWordHighlightEnabled` and `$highlightedWordIndex`, passes to messages |
|
|
@@ -62,7 +62,8 @@ const Chat = ({
|
|
|
62
62
|
},
|
|
63
63
|
children: [isOpen && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
64
64
|
style: [styles.gap, isInputDisabled && styles.messagesWithoutInput],
|
|
65
|
-
children: [messages.map(message => {
|
|
65
|
+
children: [messages.map((message, index) => {
|
|
66
|
+
const key = `${message.id}-${index}`;
|
|
66
67
|
const isPlayingMessage = message.id === currentPlayingId;
|
|
67
68
|
const messageHighlightIndex = model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1;
|
|
68
69
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.default.Fragment, {
|
|
@@ -85,9 +86,9 @@ const Chat = ({
|
|
|
85
86
|
status: audioStatus,
|
|
86
87
|
disabled: isTextToSpeechPending
|
|
87
88
|
}
|
|
88
|
-
}
|
|
89
|
+
})
|
|
89
90
|
})
|
|
90
|
-
},
|
|
91
|
+
}, key);
|
|
91
92
|
}), isHelpRequestPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_MessageLoader.MessageLoader, {
|
|
92
93
|
colorScheme: colorScheme
|
|
93
94
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_effectorReact","_ChatMessage","_MessageLoader","_ChatInput","_modelTypes","_styleTypes","_ConditionalWrapper","_jsxRuntime","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","TOOLBAR_HEIGHT","BOTTOM_OFFSET","Platform","select","web","Chat","model","isHintFeedback","isTextToSpeechEnabled","isInputDisabled","colorScheme","ColorScheme","Blue","MessageWrapper","TTSHighlightRenderer","dimensions","useWindowDimensions","ref","useRef","isOpen","useUnit","$isOpen","isHelpRequestPending","sendHelpRequestFx","pending","isTextToSpeechPending","api","textToSpeechTextFx","audioStatus","t2s","$status","currentPlayingId","$currentPlayingId","highlightedWordIndex","wordHighlight","$highlightedWordIndex","isTranslated","translation","$isTranslated","errorSpottingEnabled","errorSpotting","$isEnabled","messages","useStoreMap","$currentChatData","lastMessageId","at","id","MAX_HEIGHT","height","shouldWrapMessage","length","jsx","View","style","styles","container","maxHeight","children","jsxs","ScrollView","bounces","contentContainerStyle","list","onContentSizeChange","_","current","scrollToEnd","setScrollActive","gap","messagesWithoutInput","map","message","isPlayingMessage","messageHighlightIndex","isWordHighlightEnabled","Fragment","ConditionalWrapper","withWrapper","Wrapper","ChatMessage","withIcon","isOwnMessage","variant","MessageVariant","SENT","RECEIVED","withErrorSpotting","t2sState","isEnabled","isActive","isLoading","status","disabled","MessageLoader","ChatInput","hasMessages","exports","StyleSheet","create","flex","alignItems","width","paddingVertical","paddingRight","marginBottom"],"sourceRoot":"../../../../../../src","sources":["features/chatbot/components/Chat/Chat.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA;AAGA,IAAAG,YAAA,GAAAH,OAAA;AACA,IAAAI,cAAA,GAAAJ,OAAA;AACA,IAAAK,UAAA,GAAAL,OAAA;AACA,IAAAM,WAAA,GAAAN,OAAA;AACA,IAAAO,WAAA,GAAAP,OAAA;AACA,IAAAQ,mBAAA,GAAAR,OAAA;AAAkF,IAAAS,WAAA,GAAAT,OAAA;AAAA,SAAAU,yBAAAC,CAAA,6BAAAC,OAAA,mBAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,CAAA,WAAAA,CAAA,GAAAG,CAAA,GAAAD,CAAA,KAAAF,CAAA;AAAA,SAAAZ,wBAAAY,CAAA,EAAAE,CAAA,SAAAA,CAAA,IAAAF,CAAA,IAAAA,CAAA,CAAAI,UAAA,SAAAJ,CAAA,eAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,WAAAK,OAAA,EAAAL,CAAA,QAAAG,CAAA,GAAAJ,wBAAA,CAAAG,CAAA,OAAAC,CAAA,IAAAA,CAAA,CAAAG,GAAA,CAAAN,CAAA,UAAAG,CAAA,CAAAI,GAAA,CAAAP,CAAA,OAAAQ,CAAA,KAAAC,SAAA,UAAAC,CAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,CAAA,IAAAd,CAAA,oBAAAc,CAAA,OAAAC,cAAA,CAAAC,IAAA,CAAAhB,CAAA,EAAAc,CAAA,SAAAG,CAAA,GAAAP,CAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAb,CAAA,EAAAc,CAAA,UAAAG,CAAA,KAAAA,CAAA,CAAAV,GAAA,IAAAU,CAAA,CAAAC,GAAA,IAAAP,MAAA,CAAAC,cAAA,CAAAJ,CAAA,EAAAM,CAAA,EAAAG,CAAA,IAAAT,CAAA,CAAAM,CAAA,IAAAd,CAAA,CAAAc,CAAA,YAAAN,CAAA,CAAAH,OAAA,GAAAL,CAAA,EAAAG,CAAA,IAAAA,CAAA,CAAAe,GAAA,CAAAlB,CAAA,EAAAQ,CAAA,GAAAA,CAAA;AAGlF,MAAMW,cAAc,GAAG,GAAG;AAC1B,MAAMC,aAAa,GAAGC,qBAAQ,CAACC,MAAM,CAAC;EACpCC,GAAG,EAAE,GAAG;EACRlB,OAAO,EAAE;AACX,CAAC,CAAC;AAYK,MAAMmB,IAAI,GAAGA,CAAC;EACnBC,KAAK;EACLC,cAAc;EACdC,qBAAqB;EACrBC,eAAe;EACfC,WAAW,GAAGC,uBAAW,CAACC,IAAI;EAC9BC,cAAc;EACdC;AACS,CAAC,KAAK;EACf,MAAMC,UAAU,GAAG,IAAAC,gCAAmB,EAAC,CAAC;EACxC,MAAMC,GAAG,GAAG,IAAAC,aAAM,EAAa,IAAI,CAAC;EACpC,MAAMC,MAAM,GAAG,IAAAC,sBAAO,EAACd,KAAK,CAACe,OAAO,CAAC;EAErC,MAAMC,oBAAoB,GAAG,IAAAF,sBAAO,EAACd,KAAK,CAACiB,iBAAiB,CAACC,OAAO,CAAC;EACrE,MAAMC,qBAAqB,GAAG,IAAAL,sBAAO,EAACd,KAAK,CAACoB,GAAG,CAACC,kBAAkB,CAACH,OAAO,CAAC;EAE3E,MAAMI,WAAW,GAAG,IAAAR,sBAAO,EAACd,KAAK,CAACuB,GAAG,CAACC,OAAO,CAAC;EAC9C,MAAMC,gBAAgB,GAAG,IAAAX,sBAAO,EAACd,KAAK,CAACuB,GAAG,CAACG,iBAAiB,CAAC;EAC7D,MAAMC,oBAAoB,GAAG,IAAAb,sBAAO,EAACd,KAAK,CAACuB,GAAG,CAACK,aAAa,CAACC,qBAAqB,CAAC;EAEnF,MAAMC,YAAY,GAAG,IAAAhB,sBAAO,EAACd,KAAK,CAAC+B,WAAW,CAACC,aAAa,CAAC;EAC7D,MAAMC,oBAAoB,GAAG,IAAAnB,sBAAO,EAACd,KAAK,CAACkC,aAAa,CAACC,UAAU,CAAC;EAEpE,MAAMC,QAAQ,GAAG,IAAAC,0BAAW,EAACrC,KAAK,CAACsC,gBAAgB,EAAE,CAAC;IAAEF;EAAS,CAAC,KAAKA,QAAQ,CAAC;EAChF,MAAMG,aAAa,GAAGH,QAAQ,CAACI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAEC,EAAE;EAEzC,MAAMC,UAAU,GAAGjC,UAAU,CAACkC,MAAM,GAAGjD,cAAc,GAAGC,aAAa;EACrE,MAAMiD,iBAAiB,GAAGrC,cAAc,IAAIJ,eAAe,IAAIiC,QAAQ,CAACS,MAAM,KAAK,CAAC;EAEpF,oBACE,IAAAxE,WAAA,CAAAyE,GAAA,EAACjF,YAAA,CAAAkF,IAAI;IAACC,KAAK,EAAE,CAACC,MAAM,CAACC,SAAS,EAAE;MAAEC,SAAS,EAAET;IAAW,CAAC,CAAE;IAAAU,QAAA,eACzD,IAAA/E,WAAA,CAAAgF,IAAA,EAACxF,YAAA,CAAAyF,UAAU;MACT3C,GAAG,EAAEA,GAAI;MACT4C,OAAO,EAAE,KAAM;MACfC,qBAAqB,EAAEP,MAAM,CAACQ,IAAK;MACnCC,mBAAmB,EAAEA,CAACC,CAAC,EAAEhB,MAAM,KAAK;QAClChC,GAAG,CAACiD,OAAO,EAAEC,WAAW,CAAC,CAAC;QAE1B,IAAIlB,MAAM,IAAID,UAAU,EAAE;UACxB1C,KAAK,CAAC8D,eAAe,CAAC,IAAI,CAAC;QAC7B;MACF,CAAE;MAAAV,QAAA,GAEDvC,MAAM,iBACL,IAAAxC,WAAA,CAAAgF,IAAA,EAACxF,YAAA,CAAAkF,IAAI;QAACC,KAAK,EAAE,CAACC,MAAM,CAACc,GAAG,EAAE5D,eAAe,IAAI8C,MAAM,CAACe,oBAAoB,CAAE;QAAAZ,QAAA,GACvEhB,QAAQ,CAAC6B,GAAG,
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_effectorReact","_ChatMessage","_MessageLoader","_ChatInput","_modelTypes","_styleTypes","_ConditionalWrapper","_jsxRuntime","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","TOOLBAR_HEIGHT","BOTTOM_OFFSET","Platform","select","web","Chat","model","isHintFeedback","isTextToSpeechEnabled","isInputDisabled","colorScheme","ColorScheme","Blue","MessageWrapper","TTSHighlightRenderer","dimensions","useWindowDimensions","ref","useRef","isOpen","useUnit","$isOpen","isHelpRequestPending","sendHelpRequestFx","pending","isTextToSpeechPending","api","textToSpeechTextFx","audioStatus","t2s","$status","currentPlayingId","$currentPlayingId","highlightedWordIndex","wordHighlight","$highlightedWordIndex","isTranslated","translation","$isTranslated","errorSpottingEnabled","errorSpotting","$isEnabled","messages","useStoreMap","$currentChatData","lastMessageId","at","id","MAX_HEIGHT","height","shouldWrapMessage","length","jsx","View","style","styles","container","maxHeight","children","jsxs","ScrollView","bounces","contentContainerStyle","list","onContentSizeChange","_","current","scrollToEnd","setScrollActive","gap","messagesWithoutInput","map","message","index","key","isPlayingMessage","messageHighlightIndex","isWordHighlightEnabled","Fragment","ConditionalWrapper","withWrapper","Wrapper","ChatMessage","withIcon","isOwnMessage","variant","MessageVariant","SENT","RECEIVED","withErrorSpotting","t2sState","isEnabled","isActive","isLoading","status","disabled","MessageLoader","ChatInput","hasMessages","exports","StyleSheet","create","flex","alignItems","width","paddingVertical","paddingRight","marginBottom"],"sourceRoot":"../../../../../../src","sources":["features/chatbot/components/Chat/Chat.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -11,6 +11,10 @@ var _oeHelpers = require("../oe.helpers.js");
|
|
|
11
11
|
var _commonConstants = require("../../../shared/common.constants.js");
|
|
12
12
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
13
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
+
const SCORE_CONTAINER_WIDTH = {
|
|
15
|
+
singleDigit: _commonConstants.isWeb ? 20 : 24,
|
|
16
|
+
doubleDigit: _commonConstants.isWeb ? 22 : 26
|
|
17
|
+
};
|
|
14
18
|
const OpenEndedScoreLabel = ({
|
|
15
19
|
label,
|
|
16
20
|
score,
|
|
@@ -22,10 +26,13 @@ const OpenEndedScoreLabel = ({
|
|
|
22
26
|
variant,
|
|
23
27
|
disabled
|
|
24
28
|
});
|
|
29
|
+
const scoreContainerWidth = score !== null && score >= 10 ? SCORE_CONTAINER_WIDTH.doubleDigit : SCORE_CONTAINER_WIDTH.singleDigit;
|
|
25
30
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
26
31
|
style: styles.container,
|
|
27
32
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
28
|
-
style: styles.score,
|
|
33
|
+
style: [styles.score, {
|
|
34
|
+
width: scoreContainerWidth
|
|
35
|
+
}],
|
|
29
36
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeUi.Typography, {
|
|
30
37
|
variant: _reactNativeUi.HeadingVariants.H3,
|
|
31
38
|
style: {
|
|
@@ -52,7 +59,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
52
59
|
flexDirection: 'row',
|
|
53
60
|
alignItems: 'center',
|
|
54
61
|
justifyContent: 'center',
|
|
55
|
-
width: _commonConstants.isWeb ? 20 : 24,
|
|
56
62
|
height: 32,
|
|
57
63
|
borderWidth: 1,
|
|
58
64
|
borderRadius: _reactNativeUi.BORDER_RADIUS[200],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_reactNativeUi","_oeHelpers","_commonConstants","_jsxRuntime","e","__esModule","default","OpenEndedScoreLabel","label","score","maxScore","disabled","variant","colors","getScoreLabelColor","jsxs","View","style","styles","container","children","jsx","Typography","HeadingVariants","H3","color","maxScoreText","exports","StyleSheet","create","alignItems","flexDirection","justifyContent","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_reactNativeUi","_oeHelpers","_commonConstants","_jsxRuntime","e","__esModule","default","SCORE_CONTAINER_WIDTH","singleDigit","isWeb","doubleDigit","OpenEndedScoreLabel","label","score","maxScore","disabled","variant","colors","getScoreLabelColor","scoreContainerWidth","jsxs","View","style","styles","container","children","jsx","width","Typography","HeadingVariants","H3","color","maxScoreText","exports","StyleSheet","create","alignItems","flexDirection","justifyContent","height","borderWidth","borderRadius","BORDER_RADIUS","borderColor","COLORS","NEUTRAL_5","paddingVertical","SPACING","paddingHorizontal","backgroundColor","NEUTRAL_1","marginLeft"],"sourceRoot":"../../../../../src","sources":["features/openEnded/components/OpenEndedScoreLabel.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,cAAA,GAAAF,OAAA;AAOA,IAAAG,UAAA,GAAAH,OAAA;AAEA,IAAAI,gBAAA,GAAAJ,OAAA;AAAwD,IAAAK,WAAA,GAAAL,OAAA;AAAA,SAAAD,uBAAAO,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAUxD,MAAMG,qBAAqB,GAAG;EAC5BC,WAAW,EAAEC,sBAAK,GAAG,EAAE,GAAG,EAAE;EAC5BC,WAAW,EAAED,sBAAK,GAAG,EAAE,GAAG;AAC5B,CAAU;AAEH,MAAME,mBAAmB,GAAGA,CAAC;EAClCC,KAAK;EACLC,KAAK;EACLC,QAAQ;EACRC,QAAQ;EACRC;AACwB,CAAC,KAAK;EAC9B,MAAMC,MAAM,GAAG,IAAAC,6BAAkB,EAAC;IAAEF,OAAO;IAAED;EAAS,CAAC,CAAC;EACxD,MAAMI,mBAAmB,GACvBN,KAAK,KAAK,IAAI,IAAIA,KAAK,IAAI,EAAE,GACzBN,qBAAqB,CAACG,WAAW,GACjCH,qBAAqB,CAACC,WAAW;EAEvC,oBACE,IAAAL,WAAA,CAAAiB,IAAA,EAACrB,YAAA,CAAAsB,IAAI;IAACC,KAAK,EAAEC,MAAM,CAACC,SAAU;IAAAC,QAAA,gBAC5B,IAAAtB,WAAA,CAAAuB,GAAA,EAAC3B,YAAA,CAAAsB,IAAI;MAACC,KAAK,EAAE,CAACC,MAAM,CAACV,KAAK,EAAE;QAAEc,KAAK,EAAER;MAAoB,CAAC,CAAE;MAAAM,QAAA,eAC1D,IAAAtB,WAAA,CAAAuB,GAAA,EAAC1B,cAAA,CAAA4B,UAAU;QAACZ,OAAO,EAAEa,8BAAe,CAACC,EAAG;QAACR,KAAK,EAAE;UAAES,KAAK,EAAEd,MAAM,CAACJ;QAAM,CAAE;QAAAY,QAAA,EACrEZ;MAAK,CACI;IAAC,CACT,CAAC,eACP,IAAAV,WAAA,CAAAiB,IAAA,EAACpB,cAAA,CAAA4B,UAAU;MACTZ,OAAO,EAAEa,8BAAe,CAACC,EAAG;MAC5BR,KAAK,EAAE,CAACC,MAAM,CAACS,YAAY,EAAE;QAAED,KAAK,EAAEd,MAAM,CAACH;MAAS,CAAC,CAAE;MAAAW,QAAA,GAC1D,IACG,EAACX,QAAQ,EAAC,GAAC,EAACF,KAAK;IAAA,CACT,CAAC;EAAA,CACT,CAAC;AAEX,CAAC;AAAAqB,OAAA,CAAAtB,mBAAA,GAAAA,mBAAA;AAED,MAAMY,MAAM,GAAGW,uBAAU,CAACC,MAAM,CAAC;EAC/BX,SAAS,EAAE;IACTY,UAAU,EAAE,QAAQ;IACpBC,aAAa,EAAE;EACjB,CAAC;EACDxB,KAAK,EAAE;IACLwB,aAAa,EAAE,KAAK;IACpBD,UAAU,EAAE,QAAQ;IACpBE,cAAc,EAAE,QAAQ;IACxBC,MAAM,EAAE,EAAE;IACVC,WAAW,EAAE,CAAC;IACdC,YAAY,EAAEC,4BAAa,CAAC,GAAG,CAAC;IAChCC,WAAW,EAAEC,qBAAM,CAACC,SAAS;IAC7BC,eAAe,EAAErC,sBAAK,GAAGsC,sBAAO,CAAC,EAAE,CAAC,GAAG,CAAC;IACxCC,iBAAiB,EAAED,sBAAO,CAAC,GAAG,CAAC;IAC/BE,eAAe,EAAEL,qBAAM,CAACM;EAC1B,CAAC;EACDlB,YAAY,EAAE;IACZmB,UAAU,EAAEJ,sBAAO,CAAC,GAAG;EACzB;AACF,CAAC,CAAC","ignoreList":[]}
|
|
@@ -39,16 +39,16 @@ chatModel.bot.setUpT2S({
|
|
|
39
39
|
|
|
40
40
|
## Architecture
|
|
41
41
|
|
|
42
|
-
###
|
|
42
|
+
### ChatTTSModel (ChatTTSModel.ts)
|
|
43
43
|
|
|
44
44
|
Handles TTS playback and word highlighting. Key design decisions:
|
|
45
45
|
|
|
46
|
-
- **
|
|
46
|
+
- **Map-based cache** — `audioCache: Map<string, AudioCache>` stores both `audioPath` and `timepoints` per message. When highlighting is off, `timepoints` is `[]`. Cache lives for the model's lifetime (cleared when user leaves the problem).
|
|
47
47
|
- **`fetchAudio()` method** — encapsulates API call + audioContent decoding. Highlight vs non-highlight differences are ternaries (SSML vs plain text, `enableTimePointing`).
|
|
48
48
|
- **`play()` is linear** — cache lookup → fetch if miss → store → activate highlight if enabled → play audio. No branching between highlight/non-highlight paths.
|
|
49
|
-
-
|
|
50
|
-
- **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at
|
|
51
|
-
- **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
|
|
49
|
+
- **Pause/resume guards** — `wordHighlightEnabled` check before toggling `setIsActive(false)`/`setIsActive(true)` on pause/resume.
|
|
50
|
+
- **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at `setConfig`.
|
|
51
|
+
- **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
|
|
52
52
|
|
|
53
53
|
### AudioProvider type
|
|
54
54
|
|
|
@@ -66,17 +66,28 @@ type AudioProvider = {
|
|
|
66
66
|
|
|
67
67
|
### ChatTTSHighlightModel (ChatTTSHighlightModel.ts)
|
|
68
68
|
|
|
69
|
-
Manages highlight state. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
|
|
69
|
+
Manages highlight state using Effector stores with declarative reset. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
|
|
70
70
|
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
71
|
+
- **`$isActive`** — gates `$highlightedWordIndex` computation. Toggled on pause/resume without resetting timepoints.
|
|
72
|
+
- **`$highlightedWordIndex`** — derived store, returns `-1` when inactive or no match. Parses mark name via `WORD_MARK_REGEX`.
|
|
73
|
+
- **`activate(timepoints, onTimeUpdate)`** — sets timepoints, enables highlighting, registers time update callback. Only triggers store updates when the highlighted word actually changes (`lastMark` comparison).
|
|
74
|
+
- **`deactivate(onTimeUpdate)`** — stops listening, resets all state via declarative `.reset()` chain.
|
|
75
|
+
- **All stores use `.reset(this.reset)`** — single `reset` event clears `$time`, `$timepoints`, and `$isActive`.
|
|
76
|
+
|
|
77
|
+
### Helpers (helpers/ttsHighlight.ts)
|
|
78
|
+
|
|
79
|
+
- **`textToSSML(text)`** — converts plain text to SSML with `<mark>` tags for word timing.
|
|
80
|
+
- **`findCurrentMark(timepoints, time)`** — iterates backwards through timepoints to find the current mark. Efficient for linear playback.
|
|
81
|
+
|
|
82
|
+
### Constants (constants.ts)
|
|
83
|
+
|
|
84
|
+
- **`WORD_MARK_REGEX`** — `/^w_(\d+)$/` — extracts word index from mark names like `w_0`, `w_1`.
|
|
74
85
|
|
|
75
86
|
### Naming conventions
|
|
76
87
|
|
|
77
88
|
| Name | Scope | Purpose |
|
|
78
89
|
|------|-------|---------|
|
|
79
|
-
| `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `
|
|
90
|
+
| `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `ChatTTSModel` |
|
|
80
91
|
| `wordHighlightEnabled` | private field | Whether highlighting is active (set once at config) |
|
|
81
92
|
| `isWordHighlightEnabled` | public getter | Read-only access to `wordHighlightEnabled` for external consumers |
|
|
82
93
|
| `isWordHighlightEnabled` | T2SConfig field | Config flag passed to `setUpT2S()` |
|
|
@@ -90,19 +101,20 @@ ChatTTSHighlightModel.activate(timepoints, onTimeUpdate)
|
|
|
90
101
|
↓
|
|
91
102
|
RAF loop → audio.currentTime → findCurrentMark() → only updates when mark changes
|
|
92
103
|
↓
|
|
93
|
-
$highlightedWordIndex = parse mark name "w_N" → N
|
|
104
|
+
$highlightedWordIndex = parse mark name "w_N" → N (or -1 if inactive/no match)
|
|
94
105
|
↓
|
|
95
|
-
Chat.tsx: model.t2s.isWordHighlightEnabled &&
|
|
106
|
+
Chat.tsx: model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1
|
|
96
107
|
↓
|
|
97
|
-
ChatMessage → MessageContent →
|
|
108
|
+
ChatMessage → MessageContent → TTSHighlightRenderer({ text, highlightedIndex })
|
|
98
109
|
```
|
|
99
110
|
|
|
100
111
|
## Key Files
|
|
101
112
|
|
|
102
113
|
| File | Purpose |
|
|
103
114
|
|------|---------|
|
|
104
|
-
| `model/ChatTTSModel.ts` | `
|
|
105
|
-
| `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, derived word index |
|
|
106
|
-
| `helpers/
|
|
107
|
-
| `
|
|
115
|
+
| `model/ChatTTSModel.ts` | `ChatTTSModel` — TTS playback, caching, highlight orchestration |
|
|
116
|
+
| `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, `$isActive`, derived word index |
|
|
117
|
+
| `helpers/ttsHighlight.ts` | `textToSSML` + `findCurrentMark` — SSML conversion and playback position lookup |
|
|
118
|
+
| `constants.ts` | `WORD_MARK_REGEX` and audio config defaults |
|
|
119
|
+
| `types/t2s.types.ts` | `AudioProvider`, `OnTimeUpdate`, `AudioStatus`, `AudioCache`, `TTSHighlightRendererProps` types |
|
|
108
120
|
| `components/Chat/Chat.tsx` | Reads `isWordHighlightEnabled` and `$highlightedWordIndex`, passes to messages |
|
|
@@ -56,7 +56,8 @@ export const Chat = ({
|
|
|
56
56
|
},
|
|
57
57
|
children: [isOpen && /*#__PURE__*/_jsxs(View, {
|
|
58
58
|
style: [styles.gap, isInputDisabled && styles.messagesWithoutInput],
|
|
59
|
-
children: [messages.map(message => {
|
|
59
|
+
children: [messages.map((message, index) => {
|
|
60
|
+
const key = `${message.id}-${index}`;
|
|
60
61
|
const isPlayingMessage = message.id === currentPlayingId;
|
|
61
62
|
const messageHighlightIndex = model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1;
|
|
62
63
|
return /*#__PURE__*/_jsx(React.Fragment, {
|
|
@@ -79,9 +80,9 @@ export const Chat = ({
|
|
|
79
80
|
status: audioStatus,
|
|
80
81
|
disabled: isTextToSpeechPending
|
|
81
82
|
}
|
|
82
|
-
}
|
|
83
|
+
})
|
|
83
84
|
})
|
|
84
|
-
},
|
|
85
|
+
}, key);
|
|
85
86
|
}), isHelpRequestPending && /*#__PURE__*/_jsx(MessageLoader, {
|
|
86
87
|
colorScheme: colorScheme
|
|
87
88
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useRef","Platform","ScrollView","StyleSheet","useWindowDimensions","View","useStoreMap","useUnit","ChatMessage","MessageLoader","ChatInput","MessageVariant","ColorScheme","ConditionalWrapper","jsx","_jsx","jsxs","_jsxs","TOOLBAR_HEIGHT","BOTTOM_OFFSET","select","web","default","Chat","model","isHintFeedback","isTextToSpeechEnabled","isInputDisabled","colorScheme","Blue","MessageWrapper","TTSHighlightRenderer","dimensions","ref","isOpen","$isOpen","isHelpRequestPending","sendHelpRequestFx","pending","isTextToSpeechPending","api","textToSpeechTextFx","audioStatus","t2s","$status","currentPlayingId","$currentPlayingId","highlightedWordIndex","wordHighlight","$highlightedWordIndex","isTranslated","translation","$isTranslated","errorSpottingEnabled","errorSpotting","$isEnabled","messages","$currentChatData","lastMessageId","at","id","MAX_HEIGHT","height","shouldWrapMessage","length","style","styles","container","maxHeight","children","bounces","contentContainerStyle","list","onContentSizeChange","_","current","scrollToEnd","setScrollActive","gap","messagesWithoutInput","map","message","isPlayingMessage","messageHighlightIndex","isWordHighlightEnabled","Fragment","withWrapper","Wrapper","withIcon","isOwnMessage","variant","SENT","RECEIVED","withErrorSpotting","t2sState","isEnabled","isActive","isLoading","status","disabled","hasMessages","create","flex","alignItems","width","paddingVertical","paddingRight","marginBottom"],"sourceRoot":"../../../../../../src","sources":["features/chatbot/components/Chat/Chat.tsx"],"mappings":"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
|
|
1
|
+
{"version":3,"names":["React","useRef","Platform","ScrollView","StyleSheet","useWindowDimensions","View","useStoreMap","useUnit","ChatMessage","MessageLoader","ChatInput","MessageVariant","ColorScheme","ConditionalWrapper","jsx","_jsx","jsxs","_jsxs","TOOLBAR_HEIGHT","BOTTOM_OFFSET","select","web","default","Chat","model","isHintFeedback","isTextToSpeechEnabled","isInputDisabled","colorScheme","Blue","MessageWrapper","TTSHighlightRenderer","dimensions","ref","isOpen","$isOpen","isHelpRequestPending","sendHelpRequestFx","pending","isTextToSpeechPending","api","textToSpeechTextFx","audioStatus","t2s","$status","currentPlayingId","$currentPlayingId","highlightedWordIndex","wordHighlight","$highlightedWordIndex","isTranslated","translation","$isTranslated","errorSpottingEnabled","errorSpotting","$isEnabled","messages","$currentChatData","lastMessageId","at","id","MAX_HEIGHT","height","shouldWrapMessage","length","style","styles","container","maxHeight","children","bounces","contentContainerStyle","list","onContentSizeChange","_","current","scrollToEnd","setScrollActive","gap","messagesWithoutInput","map","message","index","key","isPlayingMessage","messageHighlightIndex","isWordHighlightEnabled","Fragment","withWrapper","Wrapper","withIcon","isOwnMessage","variant","SENT","RECEIVED","withErrorSpotting","t2sState","isEnabled","isActive","isLoading","status","disabled","hasMessages","create","flex","alignItems","width","paddingVertical","paddingRight","marginBottom"],"sourceRoot":"../../../../../../src","sources":["features/chatbot/components/Chat/Chat.tsx"],"mappings":";;AAAA,OAAOA,KAAK,IAAsCC,MAAM,QAAQ,OAAO;AACvE,SAASC,QAAQ,EAAEC,UAAU,EAAEC,UAAU,EAAEC,mBAAmB,EAAEC,IAAI,QAAQ,cAAc;AAC1F,SAASC,WAAW,EAAEC,OAAO,QAAQ,gBAAgB;AAGrD,SAASC,WAAW,QAAQ,+BAA4B;AACxD,SAASC,aAAa,QAAQ,iCAA8B;AAC5D,SAASC,SAAS,QAAQ,2BAAwB;AAClD,SAASC,cAAc,QAAQ,4BAAyB;AACxD,SAASC,WAAW,QAAQ,4BAAyB;AACrD,SAASC,kBAAkB,QAAQ,kDAA+C;AAAA,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAGlF,MAAMC,cAAc,GAAG,GAAG;AAC1B,MAAMC,aAAa,GAAGlB,QAAQ,CAACmB,MAAM,CAAC;EACpCC,GAAG,EAAE,GAAG;EACRC,OAAO,EAAE;AACX,CAAC,CAAC;AAYF,OAAO,MAAMC,IAAI,GAAGA,CAAC;EACnBC,KAAK;EACLC,cAAc;EACdC,qBAAqB;EACrBC,eAAe;EACfC,WAAW,GAAGhB,WAAW,CAACiB,IAAI;EAC9BC,cAAc;EACdC;AACS,CAAC,KAAK;EACf,MAAMC,UAAU,GAAG5B,mBAAmB,CAAC,CAAC;EACxC,MAAM6B,GAAG,GAAGjC,MAAM,CAAa,IAAI,CAAC;EACpC,MAAMkC,MAAM,GAAG3B,OAAO,CAACiB,KAAK,CAACW,OAAO,CAAC;EAErC,MAAMC,oBAAoB,GAAG7B,OAAO,CAACiB,KAAK,CAACa,iBAAiB,CAACC,OAAO,CAAC;EACrE,MAAMC,qBAAqB,GAAGhC,OAAO,CAACiB,KAAK,CAACgB,GAAG,CAACC,kBAAkB,CAACH,OAAO,CAAC;EAE3E,MAAMI,WAAW,GAAGnC,OAAO,CAACiB,KAAK,CAACmB,GAAG,CAACC,OAAO,CAAC;EAC9C,MAAMC,gBAAgB,GAAGtC,OAAO,CAACiB,KAAK,CAACmB,GAAG,CAACG,iBAAiB,CAAC;EAC7D,MAAMC,oBAAoB,GAAGxC,OAAO,CAACiB,KAAK,CAACmB,GAAG,CAACK,aAAa,CAACC,qBAAqB,CAAC;EAEnF,MAAMC,YAAY,GAAG3C,OAAO,CAACiB,KAAK,CAAC2B,WAAW,CAACC,aAAa,CAAC;EAC7D,MAAMC,oBAAoB,GAAG9C,OAAO,CAACiB,KAAK,CAAC8B,aAAa,CAACC,UAAU,CAAC;EAEpE,MAAMC,QAAQ,GAAGlD,WAAW,CAACkB,KAAK,CAACiC,gBAAgB,EAAE,CAAC;IAAED;EAAS,CAAC,KAAKA,QAAQ,CAAC;EAChF,MAAME,aAAa,GAAGF,QAAQ,CAACG,EAAE,CAAC,CAAC,CAAC,CAAC,EAAEC,EAAE;EAEzC,MAAMC,UAAU,GAAG7B,UAAU,CAAC8B,MAAM,GAAG5C,cAAc,GAAGC,aAAa;EACrE,MAAM4C,iBAAiB,GAAGjC,cAAc,IAAIH,eAAe,IAAI6B,QAAQ,CAACQ,MAAM,KAAK,CAAC;EAEpF,oBACEjD,IAAA,CAACV,IAAI;IAAC4D,KAAK,EAAE,CAACC,MAAM,CAACC,SAAS,EAAE;MAAEC,SAAS,EAAEP;IAAW,CAAC,CAAE;IAAAQ,QAAA,eACzDpD,KAAA,CAACf,UAAU;MACT+B,GAAG,EAAEA,GAAI;MACTqC,OAAO,EAAE,KAAM;MACfC,qBAAqB,EAAEL,MAAM,CAACM,IAAK;MACnCC,mBAAmB,EAAEA,CAACC,CAAC,EAAEZ,MAAM,KAAK;QAClC7B,GAAG,CAAC0C,OAAO,EAAEC,WAAW,CAAC,CAAC;QAE1B,IAAId,MAAM,IAAID,UAAU,EAAE;UACxBrC,KAAK,CAACqD,eAAe,CAAC,IAAI,CAAC;QAC7B;MACF,CAAE;MAAAR,QAAA,GAEDnC,MAAM,iBACLjB,KAAA,CAACZ,IAAI;QAAC4D,KAAK,EAAE,CAACC,MAAM,CAACY,GAAG,EAAEnD,eAAe,IAAIuC,MAAM,CAACa,oBAAoB,CAAE;QAAAV,QAAA,GACvEb,QAAQ,CAACwB,GAAG,CAAC,CAACC,OAAO,EAAEC,KAAK,KAAK;UAChC,MAAMC,GAAG,GAAG,GAAGF,OAAO,CAACrB,EAAE,IAAIsB,KAAK,EAAE;UACpC,MAAME,gBAAgB,GAAGH,OAAO,CAACrB,EAAE,KAAKf,gBAAgB;UACxD,MAAMwC,qBAAqB,GACzB7D,KAAK,CAACmB,GAAG,CAAC2C,sBAAsB,IAAIF,gBAAgB,GAAGrC,oBAAoB,GAAG,CAAC,CAAC;UAElF,oBACEhC,IAAA,CAAChB,KAAK,CAACwF,QAAQ;YAAAlB,QAAA,eACbtD,IAAA,CAACF,kBAAkB;cAAC2E,WAAW,EAAEzB,iBAAkB;cAAC0B,OAAO,EAAE3D,cAAe;cAAAuC,QAAA,eAC1EtD,IAAA,CAACP,WAAW;gBACV0C,YAAY,EAAEA,YAAa;gBAC3BwC,QAAQ,EAAE,CAACT,OAAO,CAACU,YAAY,IAAIV,OAAO,CAACrB,EAAE,KAAKF,aAAc;gBAChEuB,OAAO,EAAEA,OAAQ;gBACjBW,OAAO,EAAEX,OAAO,CAACU,YAAY,GAAGhF,cAAc,CAACkF,IAAI,GAAGlF,cAAc,CAACmF,QAAS;gBAC9ElE,WAAW,EAAEA,WAAY;gBACzBmE,iBAAiB,EAAE1C,oBAAoB,IAAI,CAAC4B,OAAO,CAACU,YAAa;gBACjE5C,oBAAoB,EAAEsC,qBAAsB;gBAC5CtD,oBAAoB,EAAEA,oBAAqB;gBAC3CiE,QAAQ,EAAE;kBACRC,SAAS,EAAEvE,qBAAqB,IAAI,CAACuD,OAAO,CAACU,YAAY;kBACzDO,QAAQ,EAAEd,gBAAgB;kBAC1Be,SAAS,EAAE5D,qBAAqB;kBAChC6D,MAAM,EAAE1D,WAAW;kBACnB2D,QAAQ,EAAE9D;gBACZ;cAAE,CACH;YAAC,CACgB;UAAC,GAnBF4C,GAoBL,CAAC;QAErB,CAAC,CAAC,EAED/C,oBAAoB,iBAAIrB,IAAA,CAACN,aAAa;UAACmB,WAAW,EAAEA;QAAY,CAAE,CAAC;MAAA,CAChE,CACP,EAEAM,MAAM,IAAI,CAACP,eAAe,iBACzBZ,IAAA,CAACL,SAAS;QACRe,cAAc,EAAEA,cAAe;QAC/BG,WAAW,EAAEA,WAAY;QACzB0E,WAAW,EAAE9C,QAAQ,CAACQ,MAAM,GAAG;MAAE,CAClC,CACF;IAAA,CACS;EAAC,CACT,CAAC;AAEX,CAAC;AAED,MAAME,MAAM,GAAG/D,UAAU,CAACoG,MAAM,CAAC;EAC/BpC,SAAS,EAAE;IACTqC,IAAI,EAAE,CAAC;IACPC,UAAU,EAAE,UAAU;IACtBC,KAAK,EAAE,GAAG;IACV5C,MAAM,EAAE;EACV,CAAC;EACDU,IAAI,EAAE;IACJiC,UAAU,EAAE,UAAU;IACtBE,eAAe,EAAE,CAAC;IAClBC,YAAY,EAAE;EAChB,CAAC;EACD7B,oBAAoB,EAAE;IACpB8B,YAAY,EAAE;EAChB,CAAC;EACD/B,GAAG,EAAE;IACH0B,IAAI,EAAE,CAAC;IACP1B,GAAG,EAAE;EACP;AACF,CAAC,CAAC","ignoreList":[]}
|
|
@@ -6,6 +6,10 @@ import { Typography, HeadingVariants, SPACING, BORDER_RADIUS, COLORS } from '@ma
|
|
|
6
6
|
import { getScoreLabelColor } from "../oe.helpers.js";
|
|
7
7
|
import { isWeb } from "../../../shared/common.constants.js";
|
|
8
8
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
|
+
const SCORE_CONTAINER_WIDTH = {
|
|
10
|
+
singleDigit: isWeb ? 20 : 24,
|
|
11
|
+
doubleDigit: isWeb ? 22 : 26
|
|
12
|
+
};
|
|
9
13
|
export const OpenEndedScoreLabel = ({
|
|
10
14
|
label,
|
|
11
15
|
score,
|
|
@@ -17,10 +21,13 @@ export const OpenEndedScoreLabel = ({
|
|
|
17
21
|
variant,
|
|
18
22
|
disabled
|
|
19
23
|
});
|
|
24
|
+
const scoreContainerWidth = score !== null && score >= 10 ? SCORE_CONTAINER_WIDTH.doubleDigit : SCORE_CONTAINER_WIDTH.singleDigit;
|
|
20
25
|
return /*#__PURE__*/_jsxs(View, {
|
|
21
26
|
style: styles.container,
|
|
22
27
|
children: [/*#__PURE__*/_jsx(View, {
|
|
23
|
-
style: styles.score,
|
|
28
|
+
style: [styles.score, {
|
|
29
|
+
width: scoreContainerWidth
|
|
30
|
+
}],
|
|
24
31
|
children: /*#__PURE__*/_jsx(Typography, {
|
|
25
32
|
variant: HeadingVariants.H3,
|
|
26
33
|
style: {
|
|
@@ -46,7 +53,6 @@ const styles = StyleSheet.create({
|
|
|
46
53
|
flexDirection: 'row',
|
|
47
54
|
alignItems: 'center',
|
|
48
55
|
justifyContent: 'center',
|
|
49
|
-
width: isWeb ? 20 : 24,
|
|
50
56
|
height: 32,
|
|
51
57
|
borderWidth: 1,
|
|
52
58
|
borderRadius: BORDER_RADIUS[200],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","View","StyleSheet","Typography","HeadingVariants","SPACING","BORDER_RADIUS","COLORS","getScoreLabelColor","isWeb","jsx","_jsx","jsxs","_jsxs","OpenEndedScoreLabel","label","score","maxScore","disabled","variant","colors","style","styles","container","children","H3","color","maxScoreText","create","alignItems","flexDirection","justifyContent","
|
|
1
|
+
{"version":3,"names":["React","View","StyleSheet","Typography","HeadingVariants","SPACING","BORDER_RADIUS","COLORS","getScoreLabelColor","isWeb","jsx","_jsx","jsxs","_jsxs","SCORE_CONTAINER_WIDTH","singleDigit","doubleDigit","OpenEndedScoreLabel","label","score","maxScore","disabled","variant","colors","scoreContainerWidth","style","styles","container","children","width","H3","color","maxScoreText","create","alignItems","flexDirection","justifyContent","height","borderWidth","borderRadius","borderColor","NEUTRAL_5","paddingVertical","paddingHorizontal","backgroundColor","NEUTRAL_1","marginLeft"],"sourceRoot":"../../../../../src","sources":["features/openEnded/components/OpenEndedScoreLabel.tsx"],"mappings":";;AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,IAAI,EAAEC,UAAU,QAAQ,cAAc;AAC/C,SACEC,UAAU,EACVC,eAAe,EACfC,OAAO,EACPC,aAAa,EACbC,MAAM,QACD,4BAA4B;AACnC,SAASC,kBAAkB,QAAQ,kBAAe;AAElD,SAASC,KAAK,QAAQ,qCAAkC;AAAA,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAUxD,MAAMC,qBAAqB,GAAG;EAC5BC,WAAW,EAAEN,KAAK,GAAG,EAAE,GAAG,EAAE;EAC5BO,WAAW,EAAEP,KAAK,GAAG,EAAE,GAAG;AAC5B,CAAU;AAEV,OAAO,MAAMQ,mBAAmB,GAAGA,CAAC;EAClCC,KAAK;EACLC,KAAK;EACLC,QAAQ;EACRC,QAAQ;EACRC;AACwB,CAAC,KAAK;EAC9B,MAAMC,MAAM,GAAGf,kBAAkB,CAAC;IAAEc,OAAO;IAAED;EAAS,CAAC,CAAC;EACxD,MAAMG,mBAAmB,GACvBL,KAAK,KAAK,IAAI,IAAIA,KAAK,IAAI,EAAE,GACzBL,qBAAqB,CAACE,WAAW,GACjCF,qBAAqB,CAACC,WAAW;EAEvC,oBACEF,KAAA,CAACZ,IAAI;IAACwB,KAAK,EAAEC,MAAM,CAACC,SAAU;IAAAC,QAAA,gBAC5BjB,IAAA,CAACV,IAAI;MAACwB,KAAK,EAAE,CAACC,MAAM,CAACP,KAAK,EAAE;QAAEU,KAAK,EAAEL;MAAoB,CAAC,CAAE;MAAAI,QAAA,eAC1DjB,IAAA,CAACR,UAAU;QAACmB,OAAO,EAAElB,eAAe,CAAC0B,EAAG;QAACL,KAAK,EAAE;UAAEM,KAAK,EAAER,MAAM,CAACJ;QAAM,CAAE;QAAAS,QAAA,EACrET;MAAK,CACI;IAAC,CACT,CAAC,eACPN,KAAA,CAACV,UAAU;MACTmB,OAAO,EAAElB,eAAe,CAAC0B,EAAG;MAC5BL,KAAK,EAAE,CAACC,MAAM,CAACM,YAAY,EAAE;QAAED,KAAK,EAAER,MAAM,CAACH;MAAS,CAAC,CAAE;MAAAQ,QAAA,GAC1D,IACG,EAACR,QAAQ,EAAC,GAAC,EAACF,KAAK;IAAA,CACT,CAAC;EAAA,CACT,CAAC;AAEX,CAAC;AAED,MAAMQ,MAAM,GAAGxB,UAAU,CAAC+B,MAAM,CAAC;EAC/BN,SAAS,EAAE;IACTO,UAAU,EAAE,QAAQ;IACpBC,aAAa,EAAE;EACjB,CAAC;EACDhB,KAAK,EAAE;IACLgB,aAAa,EAAE,KAAK;IACpBD,UAAU,EAAE,QAAQ;IACpBE,cAAc,EAAE,QAAQ;IACxBC,MAAM,EAAE,EAAE;IACVC,WAAW,EAAE,CAAC;IACdC,YAAY,EAAEjC,aAAa,CAAC,GAAG,CAAC;IAChCkC,WAAW,EAAEjC,MAAM,CAACkC,SAAS;IAC7BC,eAAe,EAAEjC,KAAK,GAAGJ,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC;IACxCsC,iBAAiB,EAAEtC,OAAO,CAAC,GAAG,CAAC;IAC/BuC,eAAe,EAAErC,MAAM,CAACsC;EAC1B,CAAC;EACDb,YAAY,EAAE;IACZc,UAAU,EAAEzC,OAAO,CAAC,GAAG;EACzB;AACF,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenEndedScoreLabel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/openEnded/components/OpenEndedScoreLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAUzB,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAGxD,KAAK,wBAAwB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,0BAA0B,CAAA;CACpC,CAAA;
|
|
1
|
+
{"version":3,"file":"OpenEndedScoreLabel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/openEnded/components/OpenEndedScoreLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAUzB,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAGxD,KAAK,wBAAwB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,0BAA0B,CAAA;CACpC,CAAA;AAOD,eAAO,MAAM,mBAAmB,mDAM7B,wBAAwB,sBAsB1B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenEndedScoreLabel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/openEnded/components/OpenEndedScoreLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAUzB,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAGxD,KAAK,wBAAwB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,0BAA0B,CAAA;CACpC,CAAA;
|
|
1
|
+
{"version":3,"file":"OpenEndedScoreLabel.d.ts","sourceRoot":"","sources":["../../../../../../src/features/openEnded/components/OpenEndedScoreLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAUzB,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAGxD,KAAK,wBAAwB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,0BAA0B,CAAA;CACpC,CAAA;AAOD,eAAO,MAAM,mBAAmB,mDAM7B,wBAAwB,sBAsB1B,CAAA"}
|
package/package.json
CHANGED
|
@@ -39,16 +39,16 @@ chatModel.bot.setUpT2S({
|
|
|
39
39
|
|
|
40
40
|
## Architecture
|
|
41
41
|
|
|
42
|
-
###
|
|
42
|
+
### ChatTTSModel (ChatTTSModel.ts)
|
|
43
43
|
|
|
44
44
|
Handles TTS playback and word highlighting. Key design decisions:
|
|
45
45
|
|
|
46
|
-
- **
|
|
46
|
+
- **Map-based cache** — `audioCache: Map<string, AudioCache>` stores both `audioPath` and `timepoints` per message. When highlighting is off, `timepoints` is `[]`. Cache lives for the model's lifetime (cleared when user leaves the problem).
|
|
47
47
|
- **`fetchAudio()` method** — encapsulates API call + audioContent decoding. Highlight vs non-highlight differences are ternaries (SSML vs plain text, `enableTimePointing`).
|
|
48
48
|
- **`play()` is linear** — cache lookup → fetch if miss → store → activate highlight if enabled → play audio. No branching between highlight/non-highlight paths.
|
|
49
|
-
-
|
|
50
|
-
- **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at
|
|
51
|
-
- **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
|
|
49
|
+
- **Pause/resume guards** — `wordHighlightEnabled` check before toggling `setIsActive(false)`/`setIsActive(true)` on pause/resume.
|
|
50
|
+
- **`wordHighlightEnabled` (private)** — stored result of `!!isWordHighlightEnabled && !!audioProvider.onTimeUpdate`. Set once at `setConfig`.
|
|
51
|
+
- **`isWordHighlightEnabled` (public getter)** — read-only access for external consumers (e.g. `Chat.tsx`).
|
|
52
52
|
|
|
53
53
|
### AudioProvider type
|
|
54
54
|
|
|
@@ -66,17 +66,28 @@ type AudioProvider = {
|
|
|
66
66
|
|
|
67
67
|
### ChatTTSHighlightModel (ChatTTSHighlightModel.ts)
|
|
68
68
|
|
|
69
|
-
Manages highlight state. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
|
|
69
|
+
Manages highlight state using Effector stores with declarative reset. Receives `OnTimeUpdate` callback directly (not the whole `AudioProvider`).
|
|
70
70
|
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
71
|
+
- **`$isActive`** — gates `$highlightedWordIndex` computation. Toggled on pause/resume without resetting timepoints.
|
|
72
|
+
- **`$highlightedWordIndex`** — derived store, returns `-1` when inactive or no match. Parses mark name via `WORD_MARK_REGEX`.
|
|
73
|
+
- **`activate(timepoints, onTimeUpdate)`** — sets timepoints, enables highlighting, registers time update callback. Only triggers store updates when the highlighted word actually changes (`lastMark` comparison).
|
|
74
|
+
- **`deactivate(onTimeUpdate)`** — stops listening, resets all state via declarative `.reset()` chain.
|
|
75
|
+
- **All stores use `.reset(this.reset)`** — single `reset` event clears `$time`, `$timepoints`, and `$isActive`.
|
|
76
|
+
|
|
77
|
+
### Helpers (helpers/ttsHighlight.ts)
|
|
78
|
+
|
|
79
|
+
- **`textToSSML(text)`** — converts plain text to SSML with `<mark>` tags for word timing.
|
|
80
|
+
- **`findCurrentMark(timepoints, time)`** — iterates backwards through timepoints to find the current mark. Efficient for linear playback.
|
|
81
|
+
|
|
82
|
+
### Constants (constants.ts)
|
|
83
|
+
|
|
84
|
+
- **`WORD_MARK_REGEX`** — `/^w_(\d+)$/` — extracts word index from mark names like `w_0`, `w_1`.
|
|
74
85
|
|
|
75
86
|
### Naming conventions
|
|
76
87
|
|
|
77
88
|
| Name | Scope | Purpose |
|
|
78
89
|
|------|-------|---------|
|
|
79
|
-
| `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `
|
|
90
|
+
| `wordHighlight` | public instance | `ChatTTSHighlightModel` instance on `ChatTTSModel` |
|
|
80
91
|
| `wordHighlightEnabled` | private field | Whether highlighting is active (set once at config) |
|
|
81
92
|
| `isWordHighlightEnabled` | public getter | Read-only access to `wordHighlightEnabled` for external consumers |
|
|
82
93
|
| `isWordHighlightEnabled` | T2SConfig field | Config flag passed to `setUpT2S()` |
|
|
@@ -90,19 +101,20 @@ ChatTTSHighlightModel.activate(timepoints, onTimeUpdate)
|
|
|
90
101
|
↓
|
|
91
102
|
RAF loop → audio.currentTime → findCurrentMark() → only updates when mark changes
|
|
92
103
|
↓
|
|
93
|
-
$highlightedWordIndex = parse mark name "w_N" → N
|
|
104
|
+
$highlightedWordIndex = parse mark name "w_N" → N (or -1 if inactive/no match)
|
|
94
105
|
↓
|
|
95
|
-
Chat.tsx: model.t2s.isWordHighlightEnabled &&
|
|
106
|
+
Chat.tsx: model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1
|
|
96
107
|
↓
|
|
97
|
-
ChatMessage → MessageContent →
|
|
108
|
+
ChatMessage → MessageContent → TTSHighlightRenderer({ text, highlightedIndex })
|
|
98
109
|
```
|
|
99
110
|
|
|
100
111
|
## Key Files
|
|
101
112
|
|
|
102
113
|
| File | Purpose |
|
|
103
114
|
|------|---------|
|
|
104
|
-
| `model/ChatTTSModel.ts` | `
|
|
105
|
-
| `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, derived word index |
|
|
106
|
-
| `helpers/
|
|
107
|
-
| `
|
|
115
|
+
| `model/ChatTTSModel.ts` | `ChatTTSModel` — TTS playback, caching, highlight orchestration |
|
|
116
|
+
| `model/ChatTTSHighlightModel.ts` | Highlight state — timepoints, current time, `$isActive`, derived word index |
|
|
117
|
+
| `helpers/ttsHighlight.ts` | `textToSSML` + `findCurrentMark` — SSML conversion and playback position lookup |
|
|
118
|
+
| `constants.ts` | `WORD_MARK_REGEX` and audio config defaults |
|
|
119
|
+
| `types/t2s.types.ts` | `AudioProvider`, `OnTimeUpdate`, `AudioStatus`, `AudioCache`, `TTSHighlightRendererProps` types |
|
|
108
120
|
| `components/Chat/Chat.tsx` | Reads `isWordHighlightEnabled` and `$highlightedWordIndex`, passes to messages |
|
|
@@ -72,16 +72,16 @@ export const Chat = ({
|
|
|
72
72
|
>
|
|
73
73
|
{isOpen && (
|
|
74
74
|
<View style={[styles.gap, isInputDisabled && styles.messagesWithoutInput]}>
|
|
75
|
-
{messages.map((message) => {
|
|
75
|
+
{messages.map((message, index) => {
|
|
76
|
+
const key = `${message.id}-${index}`
|
|
76
77
|
const isPlayingMessage = message.id === currentPlayingId
|
|
77
78
|
const messageHighlightIndex =
|
|
78
79
|
model.t2s.isWordHighlightEnabled && isPlayingMessage ? highlightedWordIndex : -1
|
|
79
80
|
|
|
80
81
|
return (
|
|
81
|
-
<React.Fragment key={
|
|
82
|
+
<React.Fragment key={key}>
|
|
82
83
|
<ConditionalWrapper withWrapper={shouldWrapMessage} Wrapper={MessageWrapper}>
|
|
83
84
|
<ChatMessage
|
|
84
|
-
key={message.id}
|
|
85
85
|
isTranslated={isTranslated}
|
|
86
86
|
withIcon={!message.isOwnMessage && message.id === lastMessageId}
|
|
87
87
|
message={message}
|
|
@@ -19,6 +19,11 @@ type OpenEndedScoreLabelProps = {
|
|
|
19
19
|
variant: OpenEndedScoreLabelVariant
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
const SCORE_CONTAINER_WIDTH = {
|
|
23
|
+
singleDigit: isWeb ? 20 : 24,
|
|
24
|
+
doubleDigit: isWeb ? 22 : 26,
|
|
25
|
+
} as const
|
|
26
|
+
|
|
22
27
|
export const OpenEndedScoreLabel = ({
|
|
23
28
|
label,
|
|
24
29
|
score,
|
|
@@ -27,9 +32,14 @@ export const OpenEndedScoreLabel = ({
|
|
|
27
32
|
variant,
|
|
28
33
|
}: OpenEndedScoreLabelProps) => {
|
|
29
34
|
const colors = getScoreLabelColor({ variant, disabled })
|
|
35
|
+
const scoreContainerWidth =
|
|
36
|
+
score !== null && score >= 10
|
|
37
|
+
? SCORE_CONTAINER_WIDTH.doubleDigit
|
|
38
|
+
: SCORE_CONTAINER_WIDTH.singleDigit
|
|
39
|
+
|
|
30
40
|
return (
|
|
31
41
|
<View style={styles.container}>
|
|
32
|
-
<View style={styles.score}>
|
|
42
|
+
<View style={[styles.score, { width: scoreContainerWidth }]}>
|
|
33
43
|
<Typography variant={HeadingVariants.H3} style={{ color: colors.score }}>
|
|
34
44
|
{score}
|
|
35
45
|
</Typography>
|
|
@@ -53,7 +63,6 @@ const styles = StyleSheet.create({
|
|
|
53
63
|
flexDirection: 'row',
|
|
54
64
|
alignItems: 'center',
|
|
55
65
|
justifyContent: 'center',
|
|
56
|
-
width: isWeb ? 20 : 24,
|
|
57
66
|
height: 32,
|
|
58
67
|
borderWidth: 1,
|
|
59
68
|
borderRadius: BORDER_RADIUS[200],
|