From 4c472af70a8e059f59acc7059163183d45a6feab Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Thu, 3 Apr 2025 16:58:31 +0900 Subject: [PATCH 01/12] =?UTF-8?q?chore:#28=20=EC=9D=B8=ED=84=B0=EB=B7=B0?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B2=BD=EB=A1=9C=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- src/app/interview-start/interview-live/page.tsx | 5 +++++ src/app/interview-start/page.tsx | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/app/interview-start/interview-live/page.tsx create mode 100644 src/app/interview-start/page.tsx diff --git a/package.json b/package.json index d607499f9..f80505816 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,6 @@ }, "engines": { "pnpm": "10.4.1" - } + }, + "packageManager": "pnpm@10.4.1+sha512.c753b6c3ad7afa13af388fa6d808035a008e30ea9993f58c6663e2bc5ff21679aa834db094987129aa4d488b86df57f7b634981b2f827cdcacc698cc0cfb88af" } diff --git a/src/app/interview-start/interview-live/page.tsx b/src/app/interview-start/interview-live/page.tsx new file mode 100644 index 000000000..6d03d67e9 --- /dev/null +++ b/src/app/interview-start/interview-live/page.tsx @@ -0,0 +1,5 @@ +const AIInterviewPage = () => { + return
AIInterviewPage
; +}; + +export default AIInterviewPage; diff --git a/src/app/interview-start/page.tsx b/src/app/interview-start/page.tsx new file mode 100644 index 000000000..e535243a1 --- /dev/null +++ b/src/app/interview-start/page.tsx @@ -0,0 +1,5 @@ +const AIInterviewStartPage = () => { + return
AIInterviewStartPage
; +}; + +export default AIInterviewStartPage; From dc2212424bb08136c8a986ef9857864fd8cd5418 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Thu, 3 Apr 2025 20:40:02 +0900 Subject: [PATCH 02/12] =?UTF-8?q?chore:#28=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(interview)/interview-live/page.tsx | 7 +++++++ src/app/(interview)/interview-start/page.tsx | 5 +++++ src/app/interview-start/interview-live/page.tsx | 5 ----- src/app/interview-start/page.tsx | 5 ----- 4 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 src/app/(interview)/interview-live/page.tsx create mode 100644 src/app/(interview)/interview-start/page.tsx delete mode 100644 src/app/interview-start/interview-live/page.tsx delete mode 100644 src/app/interview-start/page.tsx diff --git a/src/app/(interview)/interview-live/page.tsx b/src/app/(interview)/interview-live/page.tsx new file mode 100644 index 000000000..36205652f --- /dev/null +++ b/src/app/(interview)/interview-live/page.tsx @@ -0,0 +1,7 @@ +import CameraView from '@/features/interview/camera-view'; + +const InterviewPage = () => { + return ; +}; + +export default InterviewPage; diff --git a/src/app/(interview)/interview-start/page.tsx b/src/app/(interview)/interview-start/page.tsx new file mode 100644 index 000000000..d61ac77bd --- /dev/null +++ b/src/app/(interview)/interview-start/page.tsx @@ -0,0 +1,5 @@ +const InterviewStartPage = () => { + return
InterviewStartPage
; +}; + +export default InterviewStartPage; diff --git a/src/app/interview-start/interview-live/page.tsx b/src/app/interview-start/interview-live/page.tsx deleted file mode 100644 index 6d03d67e9..000000000 --- a/src/app/interview-start/interview-live/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -const AIInterviewPage = () => { - return
AIInterviewPage
; -}; - -export default AIInterviewPage; diff --git a/src/app/interview-start/page.tsx b/src/app/interview-start/page.tsx deleted file mode 100644 index e535243a1..000000000 --- a/src/app/interview-start/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -const AIInterviewStartPage = () => { - return
AIInterviewStartPage
; -}; - -export default AIInterviewStartPage; From ce879db96da9976bf1fef5c5b6a3a7c304d9d9a8 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Thu, 3 Apr 2025 20:40:31 +0900 Subject: [PATCH 03/12] =?UTF-8?q?refactor:#28=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=ED=99=94=EB=A9=B4=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/interview/camera-view.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/features/interview/camera-view.tsx diff --git a/src/features/interview/camera-view.tsx b/src/features/interview/camera-view.tsx new file mode 100644 index 000000000..c6d6e2c12 --- /dev/null +++ b/src/features/interview/camera-view.tsx @@ -0,0 +1,16 @@ +'use client'; + +import { useWebcamStream } from './hooks/useWebcamStream'; + +const CameraView = () => { + const videoRef = useWebcamStream(); + + return ( +
+
+ ); +}; + +export default CameraView; From 964d01c943c93c1337b9f63febfd9acad3e17046 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Thu, 3 Apr 2025 20:40:47 +0900 Subject: [PATCH 04/12] =?UTF-8?q?refactor:#28=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=9B=B9=EC=BA=A0=20=EB=B6=88=EB=9F=AC=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interview/hooks/useWebcamStream.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/features/interview/hooks/useWebcamStream.ts diff --git a/src/features/interview/hooks/useWebcamStream.ts b/src/features/interview/hooks/useWebcamStream.ts new file mode 100644 index 000000000..e4c7a5d75 --- /dev/null +++ b/src/features/interview/hooks/useWebcamStream.ts @@ -0,0 +1,30 @@ +import { useEffect, useRef } from 'react'; + +type StreamCallback = (stream: MediaStream) => void; + +export const useWebcamStream = () => { + const videoRef = useRef(null); + + const getWebcam = (callback: StreamCallback) => { + try { + const constraints = { video: { width: { ideal: 1280 }, height: { ideal: 720 } }, audio: false }; + + navigator.mediaDevices + .getUserMedia(constraints) + .then(callback) + .catch((error) => console.error(error)); + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + getWebcam((stream: MediaStream) => { + if (videoRef.current) { + videoRef.current.srcObject = stream; + } + }); + }, []); + + return videoRef; +}; From 64d6000951779917f7f8e5e9895aee23ecde2dd6 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Thu, 3 Apr 2025 20:56:48 +0900 Subject: [PATCH 05/12] =?UTF-8?q?chore:#28=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=83=80=EC=9E=85=20=EC=84=A4=EC=A0=95=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/interview/hooks/useWebcamStream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/interview/hooks/useWebcamStream.ts b/src/features/interview/hooks/useWebcamStream.ts index e4c7a5d75..34a33e7bb 100644 --- a/src/features/interview/hooks/useWebcamStream.ts +++ b/src/features/interview/hooks/useWebcamStream.ts @@ -19,7 +19,7 @@ export const useWebcamStream = () => { }; useEffect(() => { - getWebcam((stream: MediaStream) => { + getWebcam((stream) => { if (videoRef.current) { videoRef.current.srcObject = stream; } From a0567358693898316eeecb4184d5980702ae0e1c Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Thu, 3 Apr 2025 22:23:42 +0900 Subject: [PATCH 06/12] =?UTF-8?q?refactor:#28=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/interview/hooks/useWebcamStream.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/features/interview/hooks/useWebcamStream.ts b/src/features/interview/hooks/useWebcamStream.ts index 34a33e7bb..2361df810 100644 --- a/src/features/interview/hooks/useWebcamStream.ts +++ b/src/features/interview/hooks/useWebcamStream.ts @@ -5,14 +5,12 @@ type StreamCallback = (stream: MediaStream) => void; export const useWebcamStream = () => { const videoRef = useRef(null); - const getWebcam = (callback: StreamCallback) => { + const getWebcam = async (onStreamReady: StreamCallback) => { try { const constraints = { video: { width: { ideal: 1280 }, height: { ideal: 720 } }, audio: false }; + const stream = await navigator.mediaDevices.getUserMedia(constraints); - navigator.mediaDevices - .getUserMedia(constraints) - .then(callback) - .catch((error) => console.error(error)); + onStreamReady(stream); } catch (error) { console.error(error); } From 5441edc23f6917c7bd2fbdb0b8a7d3bb102cb9aa Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Fri, 4 Apr 2025 09:52:28 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat:#28=20=EB=85=B9=EC=9D=8C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/interview/camera-view.tsx | 6 +- .../interview/hooks/useAudioRecorder.ts | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/features/interview/hooks/useAudioRecorder.ts diff --git a/src/features/interview/camera-view.tsx b/src/features/interview/camera-view.tsx index c6d6e2c12..045bc8560 100644 --- a/src/features/interview/camera-view.tsx +++ b/src/features/interview/camera-view.tsx @@ -1,14 +1,18 @@ 'use client'; +import { useAudioRecorder } from './hooks/useAudioRecorder'; import { useWebcamStream } from './hooks/useWebcamStream'; const CameraView = () => { const videoRef = useWebcamStream(); + const { isRecording, audioURL, startRecording, stopRecording } = useAudioRecorder(); return (
); }; diff --git a/src/features/interview/hooks/useAudioRecorder.ts b/src/features/interview/hooks/useAudioRecorder.ts new file mode 100644 index 000000000..fc6c825f8 --- /dev/null +++ b/src/features/interview/hooks/useAudioRecorder.ts @@ -0,0 +1,57 @@ +import { useRef, useState } from 'react'; + +export const useAudioRecorder = () => { + // 창연님을 위한 주석이니 PR 하시는 분들은 자세히 안 읽으셔도 됩니다. + + // MediaRecorder 인스턴스를 저장할 곳, 녹음 시작/중지 때 사용됨 + const mediaRecorderRef = useRef(null); + // 녹음 중인지 아닌지의 상태 + const [isRecording, setIsRecording] = useState(false); + // 녹음이 끝난 뒤, 재생하거나 다운로드할 수 있도록 오디오 URL을 저장함 + const [audioURL, setAudioURL] = useState(null); + // MediaRecorder가 전달하는 오디오 데이터를 작은 조각(blob) 단위로 모아두는 곳 + const audioChunksRef = useRef([]); + + //녹음 시작 + const startRecording = async () => { + try { + // 사용자한테 마이크 접근 권한 요청, 승인되면 MediaStream을 받아옴 + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + + // 오디오 포맷 설정 (MIME 타입 수정) + const mediaRecorder = new MediaRecorder(stream, { + mimeType: 'audio/webm;codecs=opus', + }); + mediaRecorderRef.current = mediaRecorder; + audioChunksRef.current = []; + + // 녹음 중 MediaRecorder가 데이터를 제공할 때마다 조각(chunk)을 audioChunksRef에 추가함 + // 녹음 중 데이터가 쪼개져서 순차적으로 들어오는 구조임 + mediaRecorder.ondataavailable = (e) => { + audioChunksRef.current.push(e.data); + }; + + // 녹음이 종료되면 지금까지 모은 오디오 조각들을 하나로 하벼서 Blob으로 만듦 + // Blob을 브라우저가 이해할 수 있는 가상 URL로 변환 + mediaRecorder.onstop = () => { + const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/webm' }); + const url = URL.createObjectURL(audioBlob); + setAudioURL(url); + }; + + // 실제 녹음을 시작함 + mediaRecorder.start(); + setIsRecording(true); + } catch (error) { + console.error('마이크 접근 오류:', error); + } + }; + + // 녹음 중단 + const stopRecording = () => { + mediaRecorderRef.current?.stop(); + setIsRecording(false); + }; + + return { isRecording, audioURL, startRecording, stopRecording }; +}; From 83845a268ce25a2a83e479bb3af94928d75cdf23 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Fri, 4 Apr 2025 11:16:27 +0900 Subject: [PATCH 08/12] =?UTF-8?q?chore:#28=20import=20=EA=B2=BD=EB=A1=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/interview/camera-view.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/interview/camera-view.tsx b/src/features/interview/camera-view.tsx index 045bc8560..bd504ade6 100644 --- a/src/features/interview/camera-view.tsx +++ b/src/features/interview/camera-view.tsx @@ -1,7 +1,7 @@ 'use client'; -import { useAudioRecorder } from './hooks/useAudioRecorder'; -import { useWebcamStream } from './hooks/useWebcamStream'; +import { useAudioRecorder } from '@/features/interview/hooks/useAudioRecorder'; +import { useWebcamStream } from '@/features/interview/hooks/useWebcamStream'; const CameraView = () => { const videoRef = useWebcamStream(); From ecdb86630abcececc5ea3fd1edac4163c63382c1 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Fri, 4 Apr 2025 11:37:38 +0900 Subject: [PATCH 09/12] =?UTF-8?q?rename:#28=20=EB=B3=80=EC=88=98=EB=AA=85?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/interview/hooks/useAudioRecorder.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/features/interview/hooks/useAudioRecorder.ts b/src/features/interview/hooks/useAudioRecorder.ts index fc6c825f8..e6b83af7c 100644 --- a/src/features/interview/hooks/useAudioRecorder.ts +++ b/src/features/interview/hooks/useAudioRecorder.ts @@ -4,7 +4,7 @@ export const useAudioRecorder = () => { // 창연님을 위한 주석이니 PR 하시는 분들은 자세히 안 읽으셔도 됩니다. // MediaRecorder 인스턴스를 저장할 곳, 녹음 시작/중지 때 사용됨 - const mediaRecorderRef = useRef(null); + const audioRecorderRef = useRef(null); // 녹음 중인지 아닌지의 상태 const [isRecording, setIsRecording] = useState(false); // 녹음이 끝난 뒤, 재생하거나 다운로드할 수 있도록 오디오 URL을 저장함 @@ -22,7 +22,7 @@ export const useAudioRecorder = () => { const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm;codecs=opus', }); - mediaRecorderRef.current = mediaRecorder; + audioRecorderRef.current = mediaRecorder; audioChunksRef.current = []; // 녹음 중 MediaRecorder가 데이터를 제공할 때마다 조각(chunk)을 audioChunksRef에 추가함 @@ -49,7 +49,7 @@ export const useAudioRecorder = () => { // 녹음 중단 const stopRecording = () => { - mediaRecorderRef.current?.stop(); + audioRecorderRef.current?.stop(); setIsRecording(false); }; From b808169f0c956ed41d909fad57d9e219de6b7056 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Fri, 4 Apr 2025 12:29:49 +0900 Subject: [PATCH 10/12] =?UTF-8?q?rename:#28=20=ED=8C=8C=EC=9D=BC=EB=AA=85?= =?UTF-8?q?=20=EC=BC=80=EB=B0=A5=EC=BC=80=EC=9D=B4=EC=8A=A4=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/{useAudioRecorder.ts => use-audio-recorder.ts} | 0 .../interview/hooks/{useWebcamStream.ts => use-webcam-stream.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/features/interview/hooks/{useAudioRecorder.ts => use-audio-recorder.ts} (100%) rename src/features/interview/hooks/{useWebcamStream.ts => use-webcam-stream.ts} (100%) diff --git a/src/features/interview/hooks/useAudioRecorder.ts b/src/features/interview/hooks/use-audio-recorder.ts similarity index 100% rename from src/features/interview/hooks/useAudioRecorder.ts rename to src/features/interview/hooks/use-audio-recorder.ts diff --git a/src/features/interview/hooks/useWebcamStream.ts b/src/features/interview/hooks/use-webcam-stream.ts similarity index 100% rename from src/features/interview/hooks/useWebcamStream.ts rename to src/features/interview/hooks/use-webcam-stream.ts From 5c5d99029d29f9a99bd8871f7e074cda75981fe6 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Fri, 4 Apr 2025 12:34:47 +0900 Subject: [PATCH 11/12] =?UTF-8?q?refactor:#28=20url=20=EB=8C=80=EC=8B=A0?= =?UTF-8?q?=20audioBlob=EC=9D=84=20=EB=84=98=EA=B2=A8=EC=A3=BC=EB=8A=94=20?= =?UTF-8?q?=EA=B2=83=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/interview/camera-view.tsx | 8 ++++---- src/features/interview/hooks/use-audio-recorder.ts | 11 +++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/features/interview/camera-view.tsx b/src/features/interview/camera-view.tsx index bd504ade6..040a731f6 100644 --- a/src/features/interview/camera-view.tsx +++ b/src/features/interview/camera-view.tsx @@ -1,18 +1,18 @@ 'use client'; -import { useAudioRecorder } from '@/features/interview/hooks/useAudioRecorder'; -import { useWebcamStream } from '@/features/interview/hooks/useWebcamStream'; +import { useAudioRecorder } from '@/features/interview/hooks/use-audio-recorder'; +import { useWebcamStream } from '@/features/interview/hooks/use-webcam-stream'; const CameraView = () => { const videoRef = useWebcamStream(); - const { isRecording, audioURL, startRecording, stopRecording } = useAudioRecorder(); + const { isRecording, audioBlob, startRecording, stopRecording } = useAudioRecorder(); return (
); }; diff --git a/src/features/interview/hooks/use-audio-recorder.ts b/src/features/interview/hooks/use-audio-recorder.ts index e6b83af7c..291392dd4 100644 --- a/src/features/interview/hooks/use-audio-recorder.ts +++ b/src/features/interview/hooks/use-audio-recorder.ts @@ -7,8 +7,8 @@ export const useAudioRecorder = () => { const audioRecorderRef = useRef(null); // 녹음 중인지 아닌지의 상태 const [isRecording, setIsRecording] = useState(false); - // 녹음이 끝난 뒤, 재생하거나 다운로드할 수 있도록 오디오 URL을 저장함 - const [audioURL, setAudioURL] = useState(null); + // 녹음이 끝난 뒤, 재생하거나 다운로드할 수 있도록 오디오 Blob을 저장함 + const [audioBlob, setAudioBlob] = useState(null); // MediaRecorder가 전달하는 오디오 데이터를 작은 조각(blob) 단위로 모아두는 곳 const audioChunksRef = useRef([]); @@ -34,9 +34,8 @@ export const useAudioRecorder = () => { // 녹음이 종료되면 지금까지 모은 오디오 조각들을 하나로 하벼서 Blob으로 만듦 // Blob을 브라우저가 이해할 수 있는 가상 URL로 변환 mediaRecorder.onstop = () => { - const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/webm' }); - const url = URL.createObjectURL(audioBlob); - setAudioURL(url); + const blob = new Blob(audioChunksRef.current, { type: 'audio/webm' }); + setAudioBlob(blob); }; // 실제 녹음을 시작함 @@ -53,5 +52,5 @@ export const useAudioRecorder = () => { setIsRecording(false); }; - return { isRecording, audioURL, startRecording, stopRecording }; + return { isRecording, audioBlob, startRecording, stopRecording }; }; From 2a7d37876dda12f7a911924232e327674985f2b0 Mon Sep 17 00:00:00 2001 From: Minjo Park Date: Fri, 4 Apr 2025 12:59:25 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:#28=20=EB=85=B9=EC=9D=8C=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(interview)/interview-live/page.tsx | 8 +++++++- src/features/interview/camera-view.tsx | 5 ----- src/features/interview/voice-input-button.tsx | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 src/features/interview/voice-input-button.tsx diff --git a/src/app/(interview)/interview-live/page.tsx b/src/app/(interview)/interview-live/page.tsx index 36205652f..9ab9518b1 100644 --- a/src/app/(interview)/interview-live/page.tsx +++ b/src/app/(interview)/interview-live/page.tsx @@ -1,7 +1,13 @@ import CameraView from '@/features/interview/camera-view'; +import VoiceInputButton from '@/features/interview/voice-input-button'; const InterviewPage = () => { - return ; + return ( +
+ + +
+ ); }; export default InterviewPage; diff --git a/src/features/interview/camera-view.tsx b/src/features/interview/camera-view.tsx index 040a731f6..6b6fe412c 100644 --- a/src/features/interview/camera-view.tsx +++ b/src/features/interview/camera-view.tsx @@ -1,18 +1,13 @@ 'use client'; -import { useAudioRecorder } from '@/features/interview/hooks/use-audio-recorder'; import { useWebcamStream } from '@/features/interview/hooks/use-webcam-stream'; const CameraView = () => { const videoRef = useWebcamStream(); - const { isRecording, audioBlob, startRecording, stopRecording } = useAudioRecorder(); return (
); }; diff --git a/src/features/interview/voice-input-button.tsx b/src/features/interview/voice-input-button.tsx new file mode 100644 index 000000000..01ff8316d --- /dev/null +++ b/src/features/interview/voice-input-button.tsx @@ -0,0 +1,18 @@ +'use client'; + +import { useAudioRecorder } from '@/features/interview/hooks/use-audio-recorder'; + +const VoiceInputButton = () => { + const { isRecording, audioBlob, startRecording, stopRecording } = useAudioRecorder(); + + return ( + <> + + {audioBlob &&