({
onSubmit,
loading,
showSourceButton = true,
showToolButton = true,
autoFocus = true,
}: MessageInputProps)
| 296 | }; |
| 297 | |
| 298 | export default function MessageInput({ |
| 299 | onSubmit, |
| 300 | loading, |
| 301 | showSourceButton = true, |
| 302 | showToolButton = true, |
| 303 | autoFocus = true, |
| 304 | }: MessageInputProps) { |
| 305 | const { t } = useTranslation(); |
| 306 | const [value, setValue] = useState(''); |
| 307 | const inputRef = useRef<HTMLTextAreaElement>(null); |
| 308 | const voiceFileInputRef = useRef<HTMLInputElement>(null); |
| 309 | const [isSourcesPopupOpen, setIsSourcesPopupOpen] = useState(false); |
| 310 | const [isToolsPopupOpen, setIsToolsPopupOpen] = useState(false); |
| 311 | const [userTools, setUserTools] = useState<UserToolType[]>([]); |
| 312 | const [toolsLoading, setToolsLoading] = useState(false); |
| 313 | const [uploadModalState, setUploadModalState] = |
| 314 | useState<ActiveState>('INACTIVE'); |
| 315 | const [handleDragActive, setHandleDragActive] = useState<boolean>(false); |
| 316 | const [recordingState, setRecordingState] = useState<RecordingState>('idle'); |
| 317 | const [voiceError, setVoiceError] = useState<string | null>(null); |
| 318 | |
| 319 | const selectedDocs = useSelector(selectSelectedDocs); |
| 320 | const sourceDocs = useSelector(selectSourceDocs); |
| 321 | const token = useSelector(selectToken); |
| 322 | const attachments = useSelector(selectAttachments); |
| 323 | |
| 324 | const dispatch = useDispatch(); |
| 325 | const store = useStore<RootState>(); |
| 326 | const mediaStreamRef = useRef<MediaStream | null>(null); |
| 327 | const audioContextRef = useRef<AudioContext | null>(null); |
| 328 | const audioSourceNodeRef = useRef<MediaStreamAudioSourceNode | null>(null); |
| 329 | const audioProcessorNodeRef = useRef<ScriptProcessorNode | null>(null); |
| 330 | const audioSilenceGainRef = useRef<GainNode | null>(null); |
| 331 | const snapshotIntervalRef = useRef<number | null>(null); |
| 332 | const pcmChunksRef = useRef<Float32Array[]>([]); |
| 333 | const totalBufferedSamplesRef = useRef(0); |
| 334 | const totalCapturedSamplesRef = useRef(0); |
| 335 | const lastSnapshotCapturedSamplesRef = useRef(0); |
| 336 | const recentWindowRmsRef = useRef({ sumSquares: 0, sampleCount: 0 }); |
| 337 | const liveSessionIdRef = useRef<string | null>(null); |
| 338 | const livePendingSnapshotRef = useRef<LiveAudioSnapshot | null>(null); |
| 339 | const liveChunkIndexRef = useRef(0); |
| 340 | const liveUploadInFlightRef = useRef(false); |
| 341 | const liveStopRequestedRef = useRef(false); |
| 342 | const voiceBaseValueRef = useRef(''); |
| 343 | const liveTranscriptRef = useRef(''); |
| 344 | |
| 345 | const isTouch = isTouchDevice(); |
| 346 | |
| 347 | const stopMediaStream = () => { |
| 348 | mediaStreamRef.current?.getTracks().forEach((track) => track.stop()); |
| 349 | mediaStreamRef.current = null; |
| 350 | }; |
| 351 | |
| 352 | const stopAudioProcessing = () => { |
| 353 | if (snapshotIntervalRef.current !== null) { |
| 354 | window.clearInterval(snapshotIntervalRef.current); |
| 355 | snapshotIntervalRef.current = null; |
nothing calls this directly
no test coverage detected