Display Julia's voice responses in chat

When user speaks via voice mode, both their question and Julia's
response are now shown in the text chat. This provides a unified
conversation history for both voice and text interactions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sergei 2026-01-27 16:41:14 -08:00
parent 8f64a6e6af
commit 88d4afcdfd
2 changed files with 33 additions and 1 deletions

View File

@ -24,6 +24,7 @@ import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter, useFocusEffect } from 'expo-router';
import { api } from '@/services/api';
import { useBeneficiary } from '@/contexts/BeneficiaryContext';
import { useVoiceTranscript } from '@/contexts/VoiceTranscriptContext';
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
import type { Message, Beneficiary } from '@/types';
@ -109,6 +110,7 @@ function normalizeQuestion(userMessage: string): string {
export default function ChatScreen() {
const router = useRouter();
const { currentBeneficiary, setCurrentBeneficiary } = useBeneficiary();
const { transcript, hasNewTranscript, markTranscriptAsShown, getTranscriptAsMessages } = useVoiceTranscript();
// Helper to create initial message with beneficiary name
const createInitialMessage = useCallback((beneficiaryName?: string | null): Message => ({
@ -195,6 +197,26 @@ export default function ChatScreen() {
}
}, [deploymentName, createInitialMessage]);
// Add voice transcript messages to chat when new ones arrive
useEffect(() => {
if (hasNewTranscript && transcript.length > 0) {
const voiceMessages = getTranscriptAsMessages();
if (voiceMessages.length > 0) {
setMessages(prev => {
// Filter out messages that are already in the chat (by id)
const existingIds = new Set(prev.map(m => m.id));
const newMessages = voiceMessages.filter(m => !existingIds.has(m.id));
if (newMessages.length > 0) {
console.log('[Chat] Adding', newMessages.length, 'voice messages to chat');
return [...prev, ...newMessages];
}
return prev;
});
}
markTranscriptAsShown();
}
}, [hasNewTranscript, transcript, getTranscriptAsMessages, markTranscriptAsShown]);
// Load beneficiaries
const loadBeneficiaries = useCallback(async () => {
setLoadingBeneficiaries(true);

View File

@ -19,6 +19,7 @@ import React, {
} from 'react';
import * as Speech from 'expo-speech';
import { api } from '@/services/api';
import { useVoiceTranscript } from './VoiceTranscriptContext';
// WellNuo API configuration (same as chat.tsx)
const API_URL = 'https://eluxnetworks.net/function/well-api/api';
@ -146,6 +147,9 @@ export function VoiceProvider({ children }: { children: ReactNode }) {
const [isListening, setIsListening] = useState(false);
const [isSpeaking, setIsSpeaking] = useState(false);
// Voice transcript context for chat display
const { addTranscriptEntry } = useVoiceTranscript();
// API token cache
const apiTokenRef = useRef<string | null>(null);
@ -207,6 +211,9 @@ export function VoiceProvider({ children }: { children: ReactNode }) {
setStatus('processing');
setError(null);
// Add user message to transcript for chat display
addTranscriptEntry('user', trimmedText);
try {
// Get API token
const token = await getWellNuoToken();
@ -246,6 +253,9 @@ export function VoiceProvider({ children }: { children: ReactNode }) {
console.log('[VoiceContext] API response:', responseText.slice(0, 100) + '...');
setLastResponse(responseText);
// Add Julia's response to transcript for chat display
addTranscriptEntry('assistant', responseText);
// Speak the response
await speak(responseText);
@ -266,7 +276,7 @@ export function VoiceProvider({ children }: { children: ReactNode }) {
return null;
}
},
[getWellNuoToken]
[getWellNuoToken, addTranscriptEntry]
);
/**