Add TTS to speak Julia's text chat responses
- Integrate useTextToSpeech hook in chat screen - Automatically speak assistant responses after API call - Add volume icon button in header when TTS is active (tap to stop) - Stop TTS when clearing chat history - Use Russian language (ru-RU) for TTS output 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
88d4afcdfd
commit
45f2b676e0
@ -25,6 +25,7 @@ import { useRouter, useFocusEffect } from 'expo-router';
|
||||
import { api } from '@/services/api';
|
||||
import { useBeneficiary } from '@/contexts/BeneficiaryContext';
|
||||
import { useVoiceTranscript } from '@/contexts/VoiceTranscriptContext';
|
||||
import { useTextToSpeech } from '@/hooks/useTextToSpeech';
|
||||
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
|
||||
import type { Message, Beneficiary } from '@/types';
|
||||
|
||||
@ -112,6 +113,12 @@ export default function ChatScreen() {
|
||||
const { currentBeneficiary, setCurrentBeneficiary } = useBeneficiary();
|
||||
const { transcript, hasNewTranscript, markTranscriptAsShown, getTranscriptAsMessages } = useVoiceTranscript();
|
||||
|
||||
// TTS for reading Julia's responses aloud
|
||||
const { speak, stop: stopTTS, isSpeaking } = useTextToSpeech({
|
||||
language: 'ru-RU',
|
||||
rate: 1.0,
|
||||
});
|
||||
|
||||
// Helper to create initial message with beneficiary name
|
||||
const createInitialMessage = useCallback((beneficiaryName?: string | null): Message => ({
|
||||
id: '1',
|
||||
@ -376,13 +383,17 @@ export default function ChatScreen() {
|
||||
const data = await response.json();
|
||||
|
||||
if (data.ok && data.response?.body) {
|
||||
const responseText = data.response.body;
|
||||
const assistantMessage: Message = {
|
||||
id: (Date.now() + 1).toString(),
|
||||
role: 'assistant',
|
||||
content: data.response.body,
|
||||
content: responseText,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
setMessages(prev => [...prev, assistantMessage]);
|
||||
|
||||
// Speak the response using TTS
|
||||
speak(responseText);
|
||||
} else {
|
||||
// Token might be expired, clear and retry once
|
||||
if (data.status === '401 Unauthorized') {
|
||||
@ -402,7 +413,7 @@ export default function ChatScreen() {
|
||||
} finally {
|
||||
setIsSending(false);
|
||||
}
|
||||
}, [isSending, getWellNuoToken, customDeploymentId, currentBeneficiary, beneficiaries]);
|
||||
}, [isSending, getWellNuoToken, customDeploymentId, currentBeneficiary, beneficiaries, speak]);
|
||||
|
||||
// Render message bubble
|
||||
const renderMessage = ({ item }: { item: Message }) => {
|
||||
@ -461,6 +472,15 @@ export default function ChatScreen() {
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
{/* TTS Stop button - only visible when speaking */}
|
||||
{isSpeaking && (
|
||||
<TouchableOpacity
|
||||
style={[styles.headerButton, styles.speakingButton]}
|
||||
onPress={stopTTS}
|
||||
>
|
||||
<Ionicons name="volume-high" size={22} color={AppColors.primary} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<TouchableOpacity
|
||||
style={styles.headerButton}
|
||||
onPress={() => setSortNewestFirst(prev => !prev)}
|
||||
@ -474,6 +494,7 @@ export default function ChatScreen() {
|
||||
<TouchableOpacity
|
||||
style={styles.headerButton}
|
||||
onPress={() => {
|
||||
stopTTS(); // Stop TTS when clearing chat
|
||||
Alert.alert(
|
||||
'Clear Chat',
|
||||
'Are you sure you want to clear all messages?',
|
||||
@ -666,6 +687,10 @@ const styles = StyleSheet.create({
|
||||
padding: Spacing.xs,
|
||||
marginLeft: Spacing.sm,
|
||||
},
|
||||
speakingButton: {
|
||||
backgroundColor: AppColors.primaryLight || '#E3F2FD',
|
||||
borderRadius: BorderRadius.full,
|
||||
},
|
||||
chatContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user