@@ -13,98 +13,31 @@ import {
13
13
import SWMIcon from '../assets/icons/swm_icon.svg' ;
14
14
import Spinner from 'react-native-loading-spinner-overlay' ;
15
15
import {
16
- STREAMING_ACTION ,
17
- useSpeechToText ,
18
16
useLLM ,
19
17
QWEN3_0_6B_QUANTIZED ,
20
18
QWEN3_TOKENIZER ,
21
19
QWEN3_TOKENIZER_CONFIG ,
22
20
} from 'react-native-executorch' ;
23
21
import PauseIcon from '../assets/icons/pause_icon.svg' ;
24
- import MicIcon from '../assets/icons/mic_icon.svg' ;
25
22
import SendIcon from '../assets/icons/send_icon.svg' ;
26
- import StopIcon from '../assets/icons/stop_icon.svg' ;
27
23
import ColorPalette from '../colors' ;
28
24
import Messages from '../components/Messages' ;
29
- import LiveAudioStream from 'react-native-live-audio-stream' ;
30
- import { Buffer } from 'buffer' ;
31
-
32
- const audioStreamOptions = {
33
- sampleRate : 16000 ,
34
- channels : 1 ,
35
- bitsPerSample : 16 ,
36
- audioSource : 1 ,
37
- bufferSize : 16000 ,
38
- } ;
39
-
40
- const startStreamingAudio = ( options : any , onChunk : ( data : string ) => void ) => {
41
- LiveAudioStream . init ( options ) ;
42
- LiveAudioStream . on ( 'data' , onChunk ) ;
43
- LiveAudioStream . start ( ) ;
44
- } ;
45
-
46
- const float32ArrayFromPCMBinaryBuffer = ( b64EncodedBuffer : string ) => {
47
- const b64DecodedChunk = Buffer . from ( b64EncodedBuffer , 'base64' ) ;
48
- const int16Array = new Int16Array ( b64DecodedChunk . buffer ) ;
49
-
50
- const float32Array = new Float32Array ( int16Array . length ) ;
51
- for ( let i = 0 ; i < int16Array . length ; i ++ ) {
52
- float32Array [ i ] = Math . max (
53
- - 1 ,
54
- Math . min ( 1 , ( int16Array [ i ] / audioStreamOptions . bufferSize ) * 8 )
55
- ) ;
56
- }
57
- return float32Array ;
58
- } ;
59
25
60
26
export default function LLMScreen ( {
61
27
setIsGenerating,
62
28
} : {
63
29
setIsGenerating : React . Dispatch < React . SetStateAction < boolean > > ;
64
30
} ) {
65
- const [ isRecording , setIsRecording ] = useState ( false ) ;
66
31
const [ isTextInputFocused , setIsTextInputFocused ] = useState ( false ) ;
67
32
const [ userInput , setUserInput ] = useState ( '' ) ;
68
33
const textInputRef = useRef < TextInput > ( null ) ;
69
- const messageRecorded = useRef < boolean > ( false ) ;
70
34
71
35
const llm = useLLM ( {
72
36
modelSource : QWEN3_0_6B_QUANTIZED ,
73
37
tokenizerSource : QWEN3_TOKENIZER ,
74
38
tokenizerConfigSource : QWEN3_TOKENIZER_CONFIG ,
75
- chatConfig : {
76
- contextWindowLength : 6 ,
77
- } ,
78
- } ) ;
79
- const speechToText = useSpeechToText ( {
80
- modelName : 'moonshine' ,
81
- windowSize : 3 ,
82
- overlapSeconds : 1.2 ,
83
39
} ) ;
84
40
85
- const onChunk = ( data : string ) => {
86
- const float32Chunk = float32ArrayFromPCMBinaryBuffer ( data ) ;
87
- speechToText . streamingTranscribe (
88
- STREAMING_ACTION . DATA ,
89
- Array . from ( float32Chunk )
90
- ) ;
91
- } ;
92
-
93
- const handleRecordPress = async ( ) => {
94
- if ( isRecording ) {
95
- setIsRecording ( false ) ;
96
- LiveAudioStream . stop ( ) ;
97
- messageRecorded . current = true ;
98
- await llm . sendMessage (
99
- await speechToText . streamingTranscribe ( STREAMING_ACTION . STOP )
100
- ) ;
101
- } else {
102
- setIsRecording ( true ) ;
103
- startStreamingAudio ( audioStreamOptions , onChunk ) ;
104
- await speechToText . streamingTranscribe ( STREAMING_ACTION . START ) ;
105
- }
106
- } ;
107
-
108
41
useEffect ( ( ) => {
109
42
setIsGenerating ( llm . isGenerating ) ;
110
43
} , [ llm . isGenerating , setIsGenerating ] ) ;
@@ -118,10 +51,10 @@ export default function LLMScreen({
118
51
}
119
52
} ;
120
53
121
- return ! llm . isReady || ! speechToText . isReady ? (
54
+ return ! llm . isReady ? (
122
55
< Spinner
123
- visible = { ! llm . isReady || ! speechToText . isReady }
124
- textContent = { `Loading the model ${ ( llm . downloadProgress * 100 ) . toFixed ( 0 ) } %\nLoading the speech model ${ ( speechToText . downloadProgress * 100 ) . toFixed ( 0 ) } % ` }
56
+ visible = { ! llm . isReady }
57
+ textContent = { `Loading the model ${ ( llm . downloadProgress * 100 ) . toFixed ( 0 ) } %\n ` }
125
58
/>
126
59
) : (
127
60
< TouchableWithoutFeedback onPress = { Keyboard . dismiss } >
@@ -134,17 +67,10 @@ export default function LLMScreen({
134
67
< SWMIcon width = { 45 } height = { 45 } />
135
68
< Text style = { styles . textModelName } > Qwen 3 x Whisper</ Text >
136
69
</ View >
137
- { llm . messageHistory . length || speechToText . sequence ? (
70
+ { llm . messageHistory . length ? (
138
71
< View style = { styles . chatContainer } >
139
72
< Messages
140
- chatHistory = {
141
- speechToText . isGenerating
142
- ? [
143
- ...llm . messageHistory ,
144
- { role : 'user' , content : speechToText . sequence } ,
145
- ]
146
- : llm . messageHistory
147
- }
73
+ chatHistory = { llm . messageHistory }
148
74
llmResponse = { llm . response }
149
75
isGenerating = { llm . isGenerating }
150
76
deleteMessage = { llm . deleteMessage }
@@ -162,13 +88,13 @@ export default function LLMScreen({
162
88
< TextInput
163
89
onFocus = { ( ) => setIsTextInputFocused ( true ) }
164
90
onBlur = { ( ) => setIsTextInputFocused ( false ) }
165
- editable = { ! isRecording && ! llm . isGenerating }
91
+ editable = { ! ! llm . isGenerating }
166
92
style = { {
167
93
...styles . textInput ,
168
94
borderColor : isTextInputFocused
169
95
? ColorPalette . blueDark
170
96
: ColorPalette . blueLight ,
171
- display : isRecording ? 'none' : 'flex' ,
97
+ display : 'flex' ,
172
98
} }
173
99
placeholder = "Your message"
174
100
placeholderTextColor = { '#C1C6E5' }
@@ -180,19 +106,6 @@ export default function LLMScreen({
180
106
< TouchableOpacity onPress = { llm . interrupt } >
181
107
< PauseIcon height = { 40 } width = { 40 } padding = { 4 } margin = { 8 } />
182
108
</ TouchableOpacity >
183
- ) : ! userInput ? (
184
- < TouchableOpacity
185
- style = {
186
- ! isRecording ? styles . recordTouchable : styles . recordingInfo
187
- }
188
- onPress = { handleRecordPress }
189
- >
190
- { isRecording ? (
191
- < StopIcon height = { 40 } width = { 40 } padding = { 4 } margin = { 8 } />
192
- ) : (
193
- < MicIcon height = { 40 } width = { 40 } padding = { 4 } margin = { 8 } />
194
- ) }
195
- </ TouchableOpacity >
196
109
) : (
197
110
< TouchableOpacity
198
111
style = { styles . recordTouchable }
@@ -208,9 +121,6 @@ export default function LLMScreen({
208
121
}
209
122
210
123
const styles = StyleSheet . create ( {
211
- container : {
212
- flex : 1 ,
213
- } ,
214
124
keyboardAvoidingView : {
215
125
flex : 1 ,
216
126
} ,
@@ -262,20 +172,9 @@ const styles = StyleSheet.create({
262
172
color : ColorPalette . primary ,
263
173
padding : 16 ,
264
174
} ,
265
- fromUrlTouchable : {
266
- height : '100%' ,
267
- justifyContent : 'center' ,
268
- alignItems : 'flex-start' ,
269
- } ,
270
175
recordTouchable : {
271
176
height : '100%' ,
272
177
justifyContent : 'center' ,
273
178
alignItems : 'center' ,
274
179
} ,
275
- recordingInfo : {
276
- width : '100%' ,
277
- display : 'flex' ,
278
- justifyContent : 'center' ,
279
- alignItems : 'center' ,
280
- } ,
281
180
} ) ;
0 commit comments