'use client'; import React, { Dispatch, SetStateAction, useCallback, useState } from 'react'; import { StyleSheet, TextInput, View } from 'react-native'; import { fetchApi } from '@/lib/server-api-util'; import { Message } from '@/types/ask'; import { RecordingPresets, useAudioRecorder } from 'expo-audio'; interface Props { setIsHello: (isHello: boolean) => void, conversationId: string | null, setUserMessages: Dispatch>; setConversationId: (conversationId: string) => void, } export default function AudioRecordPlay(props: Props) { const { setIsHello, conversationId, setUserMessages, setConversationId } = props; const audioRecorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY); const [isRecording, setIsRecording] = useState(false); const [isVoiceStart, setIsVoiceStart] = useState(false); const [elapsedTime, setElapsedTime] = useState(0); // 用户询问 const [inputValue, setInputValue] = useState(''); const [timerInterval, setTimerInterval] = useState(0); const formatTime = (ms: number): string => { const totalSeconds = ms / 1000; const minutes = Math.floor(totalSeconds / 60); const seconds = Math.floor(totalSeconds % 60); const milliseconds = Math.floor(ms % 1000); return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}.${String(milliseconds).padStart(3, '0')}`; }; // 开始录音 const record = async () => { await audioRecorder.prepareToRecordAsync(); const startTime = Date.now(); // 每 10ms 更新一次时间 const interval = setInterval(() => { const elapsed = Date.now() - startTime; setElapsedTime(elapsed); }, 10); setTimerInterval(interval); setIsVoiceStart(true) audioRecorder.record(); setIsRecording(true); }; const stopRecording = async () => { // The recording will be available on `audioRecorder.uri`. if (timerInterval) clearInterval(timerInterval); setTimerInterval(0); await audioRecorder.stop(); setIsRecording(false); }; // useEffect(() => { // (async () => { // const status = await AudioModule.requestRecordingPermissionsAsync(); // if (!status.granted) { // Alert.alert('Permission to access microphone was denied'); // } // })(); // }, []); // 获取对话信息 const createNewConversation = useCallback(async (user_text: string) => { const data = await fetchApi("/chat/new", { method: "POST", }); setConversationId(data); await getConversation({ session_id: data, user_text }); }, []); const getConversation = useCallback(async ({ session_id, user_text }: { session_id: string, user_text: string }) => { if (!session_id) return; const response = await fetchApi(`/chat`, { method: "POST", body: JSON.stringify({ session_id, user_text }) }); setUserMessages((prev: Message[]) => [...prev, response]); }, []); // 使用 useCallback 缓存 handleSubmit const handleSubmit = () => { const text = inputValue; if (text) { setUserMessages(pre => ([...pre, { content: { text: text }, role: 'User', timestamp: new Date().toISOString() } ])); if (!conversationId) { createNewConversation(text); setIsHello(false); } else { getConversation({ session_id: conversationId, user_text: text }); } setInputValue(''); } } return ( {/* console.log('Left icon pressed')} className={`absolute left-2 top-1/2 -translate-y-1/2 p-2 bg-white rounded-full ${isVoiceStart ? "opacity-100" : "opacity-0"}`} // 使用绝对定位将按钮放在输入框内右侧 > */} { setInputValue(text); }} onSubmitEditing={handleSubmit} editable={!isVoiceStart} // 调起的键盘类型 returnKeyType="send" /> {/* {isVoiceStart ? : } */} ); } const styles = StyleSheet.create({ container: { justifyContent: 'center', backgroundColor: '#fff', }, title: { fontSize: 20, fontWeight: 'bold', marginBottom: 20, textAlign: 'center', }, recordButton: { padding: 15, borderRadius: 8, alignItems: 'center', marginBottom: 20, }, startButton: { backgroundColor: '#ff6b6b', }, stopButton: { backgroundColor: '#4CAF50', }, buttonText: { color: 'white', fontSize: 16, }, listTitle: { fontWeight: 'bold', marginBottom: 10, }, emptyText: { fontStyle: 'italic', color: '#888', marginBottom: 10, }, recordingItem: { padding: 10, borderBottomWidth: 1, borderBottomColor: '#eee', }, uriText: { fontSize: 12, color: '#777', }, leftIcon: { padding: 10, paddingLeft: 15, }, input: { borderColor: '#FF9500', borderWidth: 1, borderRadius: 25, paddingHorizontal: 20, paddingVertical: 12, fontSize: 16, width: '100%', // 确保输入框宽度撑满 paddingRight: 50 }, voiceButton: { width: 40, height: 40, borderRadius: 20, backgroundColor: '#FF9500', justifyContent: 'center', alignItems: 'center', marginRight: 8, // 添加一点右边距 }, });