Skip to content

Commit bd131e4

Browse files
committed
feat: add record feature to chat page
1 parent 8d1e3ed commit bd131e4

File tree

3 files changed

+42
-38
lines changed

3 files changed

+42
-38
lines changed
Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,66 @@
11
<template>
2-
<div>
3-
<button @click="toggleRecording">
4-
{{ recording ? 'Stop Recording' : 'Start Recording' }}
5-
</button>
6-
<button @click="playRecording" :disabled="!audioUrl">Play Recording</button>
7-
</div>
2+
<q-btn round flat :icon="recording ? matStop :matMic " :color="recording ? 'primary' : ''" @click="toggleRecording">
3+
</q-btn>
4+
<btn v-if="props.showPlay" @click="playRecording" :disabled="!audioUrl">Play Recording</btn>
85
</template>
96

107
<script setup lang="ts">
11-
import { Ref, ref } from 'vue'
12-
import { createTranscription } from 'src/lib/ai/openaiFacade'
8+
import {Ref, ref} from 'vue'
9+
import {createTranscription} from 'src/lib/ai/openaiFacade'
10+
import {matStop, matMic} from '@quasar/extras/material-icons'
1311
14-
const recording: Ref<boolean> = ref(false);
15-
const mediaRecorder: Ref<MediaRecorder | null> = ref(null);
16-
const audioUrl: Ref<string> = ref('');
12+
const recording: Ref<boolean> = ref(false)
13+
const mediaRecorder: Ref<MediaRecorder | null> = ref(null)
14+
const audioUrl: Ref<string> = ref('')
1715
const emit = defineEmits(['message'])
16+
const props = defineProps({showPlay: Boolean})
1817
1918
const toggleRecording = async () => {
2019
try {
2120
if (recording.value && mediaRecorder.value) {
22-
mediaRecorder.value.stop();
23-
recording.value = false;
21+
mediaRecorder.value.stop()
22+
recording.value = false
2423
} else {
25-
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
26-
mediaRecorder.value = new MediaRecorder(stream);
27-
recording.value = true;
28-
audioUrl.value = '';
24+
const stream = await navigator.mediaDevices.getUserMedia({audio: true})
25+
mediaRecorder.value = new MediaRecorder(stream)
26+
recording.value = true
27+
audioUrl.value = ''
2928
30-
const recordedChunks: Blob[] = [];
29+
const recordedChunks: Blob[] = []
3130
mediaRecorder.value.ondataavailable = (event) => {
3231
if (event.data.size > 0) {
33-
recordedChunks.push(event.data);
32+
recordedChunks.push(event.data)
3433
}
35-
};
34+
}
3635
3736
mediaRecorder.value.onstop = async () => {
3837
try {
39-
const blob = new Blob(recordedChunks, { type: 'audio/wav' });
40-
const file = new File([blob], 'recording.wav', { type: 'audio/wav' });
41-
audioUrl.value = URL.createObjectURL(file);
42-
const text = await createTranscription({ blob });
43-
emit('message', text);
38+
const blob = new Blob(recordedChunks, {type: 'audio/wav'})
39+
const file = new File([blob], 'recording.wav', {type: 'audio/wav'})
40+
audioUrl.value = URL.createObjectURL(file)
41+
const text = await createTranscription({blob})
42+
emit('message', text)
4443
} catch (error) {
45-
console.error('Error during transcription:', error);
44+
console.error('Error during transcription:', error)
4645
} finally {
47-
mediaRecorder.value = null;
46+
mediaRecorder.value = null
4847
}
49-
};
48+
}
5049
51-
mediaRecorder.value.start();
50+
mediaRecorder.value.start()
5251
}
5352
} catch (error) {
54-
console.error('Error accessing microphone:', error);
53+
console.error('Error accessing microphone:', error)
5554
}
56-
};
55+
}
5756
5857
const playRecording = () => {
5958
if (audioUrl.value) {
60-
const audioElement = new Audio(audioUrl.value);
61-
audioElement.play();
59+
const audioElement = new Audio(audioUrl.value)
60+
audioElement.play()
6261
audioElement.onended = () => {
63-
audioUrl.value = '';
64-
};
62+
audioUrl.value = ''
63+
}
6564
}
66-
};
65+
}
6766
</script>

src/pages/AudioPage.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<q-page>
3-
<audio-transcriber @message="onRecordedMessage"></audio-transcriber>
3+
<audio-transcriber show-play @message="onRecordedMessage"></audio-transcriber>
44
</q-page>
55
</template>
66

src/pages/ChatPage.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
v-model="newMessage"
1010
@keydown.enter="sendMessage"
1111
placeholder="Type your message"/>
12-
<q-btn disable round flat :icon="matMic"/>
12+
<audio-transcriber @message="onAudioMessage"></audio-transcriber>
1313
<q-btn disable round flat :icon="true ? matVolumeUp : matVolumeOff"/>
1414
<q-btn @click="sendMessage" flat class="q-ml-sm" icon="send" color="primary"/>
1515
</q-toolbar>
@@ -25,6 +25,7 @@ import {getOpenAIAPI, OpenAIParams} from 'src/lib/ai/config'
2525
import {v4, v4 as uuidv4} from 'uuid'
2626
import {matMic, matVolumeOff, matVolumeUp} from '@quasar/extras/material-icons'
2727
import {sendChatMessage} from 'src/lib/ai/openaiFacade'
28+
import AudioTranscriber from 'components/AudioTranscriber.vue'
2829
2930
const cache = reactive({})
3031
const getCache = async(id:string):Promise<any> => cache[id]
@@ -87,6 +88,10 @@ const sendMessage = async () => {
8788
}
8889
}
8990
91+
const onAudioMessage = (msg:string) => {
92+
newMessage.value = msg
93+
}
94+
9095
</script>
9196

9297
<style scoped>

0 commit comments

Comments
 (0)