Added record indicator
This commit is contained in:
@@ -8,6 +8,8 @@ $c-blue: rgb(28, 176, 246)
|
|||||||
$c-blue-shadow: rgb(24, 153, 214)
|
$c-blue-shadow: rgb(24, 153, 214)
|
||||||
$c-green: rgb(88, 204, 2)
|
$c-green: rgb(88, 204, 2)
|
||||||
$c-green-shadow: rgb(88, 167, 0)
|
$c-green-shadow: rgb(88, 167, 0)
|
||||||
|
$c-red: rgb(255, 69, 58)
|
||||||
|
$c-red-shadow: darken($c-red, 10%)
|
||||||
$c-white-shadow: rgb(222, 222, 222)
|
$c-white-shadow: rgb(222, 222, 222)
|
||||||
$border-radius: 16px
|
$border-radius: 16px
|
||||||
$shadow-width: 0 4px 0
|
$shadow-width: 0 4px 0
|
||||||
@@ -164,6 +166,10 @@ h1
|
|||||||
width: calc(100% - 40px)
|
width: calc(100% - 40px)
|
||||||
padding: 10px 16px
|
padding: 10px 16px
|
||||||
|
|
||||||
|
.record-btn.red
|
||||||
|
background-color: $c-red
|
||||||
|
box-shadow: $shadow-width $c-red-shadow
|
||||||
|
|
||||||
.chat-area
|
.chat-area
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import CharacterBadge from '../components/CharacterBadge';
|
import CharacterBadge from '../components/CharacterBadge';
|
||||||
import { useState } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { speechToText, characterChatMessage, getAudio } from '../logic/sdk';
|
import { speechToText, characterChatMessage, getAudio } from '../logic/sdk';
|
||||||
|
|
||||||
export default function Character() {
|
export default function Character() {
|
||||||
@@ -11,44 +11,53 @@ export default function Character() {
|
|||||||
|
|
||||||
type Message = { text: string, sender: string };
|
type Message = { text: string, sender: string };
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
|
const [isRecording, setIsRecording] = useState(false);
|
||||||
|
|
||||||
let chunks = [] as any;
|
let chunks = [] as any;
|
||||||
let mediaRecorder = null as any;
|
const mediaRecorder = useRef<MediaRecorder | null>(null);
|
||||||
|
|
||||||
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
|
useEffect(() => {
|
||||||
mediaRecorder = new MediaRecorder(stream)
|
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
|
||||||
mediaRecorder.ondataavailable = (e: any) => {
|
mediaRecorder.current = new MediaRecorder(stream);
|
||||||
chunks.push(e.data)
|
mediaRecorder.current.ondataavailable = (e) => {
|
||||||
}
|
chunks.push(e.data);
|
||||||
|
}
|
||||||
mediaRecorder.onstop = (e: any) => {
|
|
||||||
const blob = new Blob(chunks, { type: 'audio/wav' });
|
mediaRecorder.current.onstop = (e) => {
|
||||||
chunks = [];
|
setIsRecording(false);
|
||||||
|
const blob = new Blob(chunks, { type: 'audio/wav' });
|
||||||
const audioFile = new File([blob], "audio.wav", { type: 'audio/wav' });
|
chunks = [];
|
||||||
|
|
||||||
speechToText(audioFile).then((text) => {
|
const audioFile = new File([blob], "audio.wav", { type: 'audio/wav' });
|
||||||
setMessages([...messages, { text: text, sender: 'me' }]);
|
|
||||||
characterChatMessage(sessionId, text).then((response) => {
|
speechToText(audioFile).then((text) => {
|
||||||
const { msg, audio_id } = response
|
setMessages(prevMessages => [...prevMessages, { text: text, sender: 'me' }]);
|
||||||
getAudio(audio_id).then((audioBlob) => {
|
characterChatMessage(sessionId, text).then((response) => {
|
||||||
const audioFile = new File([audioBlob], "audio.wav", { type: 'audio/wav' });
|
const { msg, audio_id } = response
|
||||||
const audioUrl = URL.createObjectURL(audioFile);
|
getAudio(audio_id).then((audioBlob) => {
|
||||||
const audio = new Audio(audioUrl);
|
const audioFile = new File([audioBlob], "audio.wav", { type: 'audio/wav' });
|
||||||
audio.play();
|
const audioUrl = URL.createObjectURL(audioFile);
|
||||||
});
|
const audio = new Audio(audioUrl);
|
||||||
setMessages(prevMessages => [...prevMessages, { text: msg, sender: 'other' }]);
|
audio.play();
|
||||||
})
|
});
|
||||||
});
|
setMessages(prevMessages => [...prevMessages, { text: msg, sender: 'other' }]);
|
||||||
}
|
})
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
function handleRecord() {
|
function handleRecord() {
|
||||||
if (mediaRecorder && mediaRecorder.state === 'inactive') {
|
if (!isRecording) {
|
||||||
mediaRecorder.start();
|
if (mediaRecorder.current) {
|
||||||
|
mediaRecorder.current.start();
|
||||||
|
}
|
||||||
|
setIsRecording(true);
|
||||||
console.log("Recording...");
|
console.log("Recording...");
|
||||||
} else if (mediaRecorder && mediaRecorder.state === 'recording') {
|
} else {
|
||||||
mediaRecorder.stop();
|
if (mediaRecorder.current) {
|
||||||
|
mediaRecorder.current.stop();
|
||||||
|
}
|
||||||
console.log("Stopped recording.");
|
console.log("Stopped recording.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +79,9 @@ export default function Character() {
|
|||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<button className="record-btn" onClick={handleRecord}>Record</button>
|
<button className={`record-btn ${isRecording ? 'red' : ''}`} onClick={handleRecord}>
|
||||||
|
{isRecording ? 'Stop Recording' : 'Record'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user