
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div id="Chapter2_2" class="content-wrap">
<div style="margin: 30px 0px 50px; width: 20%">
<router-link to="/MyPlan.page">
<div class="logo mb25">
<img src="../../../../resources/img/logo2.png" alt="" />
</div>
</router-link>
</div>
<div
class="title-box mb25 flex align-center mt40"
style="justify-content: space-between"
>
<div>
<span class="title mr40">1. Hello WORLD</span>
<span class="subtitle">my name is dd</span>
</div>
<button class="completeBtn" @click="complete">학습 종료</button>
</div>
<div class="flex justify-between align-center">
<div class="pre-btn" @click="goToPage('Chapter2')">
<img src="../../../../resources/img/left.png" alt="" />
</div>
<div class="content title-box">
<p class="subtitle2"></p>
<p class="title mt25 title-bg">STEP 2 - 단어로 공부하는 영어</p>
<div class="flex align-center mb30">
<p class="subtitle2 mr20">다음을 듣고 따라 말하세요.</p>
<!-- <button><img src="../../../../resources/img/btn10_s.png" alt="">
</button> -->
</div>
<div class="imgGroup box23">
<div class="con">
<img :src="currentCon.imgSrc" alt="" />
<p class="title3">
<em class="yellow">{{ currentCon.titleEm }}</em
>{{ currentCon.title }}
</p>
<div class="flex align-center justify-center mt10">
<p class="yellow-box-big">{{ currentCon.boxText }}</p>
<span class="subtitle3">{{ currentCon.subtitle }}</span>
</div>
<div class="flex justify-center">
<div class="btnGroup mt50 flex justify-between">
<button
class="popTxt"
v-for="(item, index) in items"
:key="index"
@click="updateContent(index)"
:class="{ active: selectedIndex === index }"
>
<img :src="item.imgSrc1" />
<img
:src="item.imgSrc2"
v-if="selectedIndex === index"
style="display: block"
/>
</button>
</div>
</div>
</div>
<div class="flex justify-center">
<div class="readGroup">
<section>
<div class="imgGroup flex justify-center">
<!-- 녹음 버튼 -->
<div
:class="['mic-btn', { notRecording: !isRecording }]"
@click="toggleRecording"
>
<img src="../../../../resources/img/btn11_s.png" alt="" />
</div>
</div>
<article>
<p ref="speakText" class="speakText mb25">
위의 버튼을 누른 후 단어를 말해보세요!
</p>
</article>
</section>
</div>
</div>
</div>
</div>
<div class="next-btn" @click="goToPage('Chapter2_2')">
<img src="../../../../resources/img/right.png" alt="" />
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import { mdiStop } from "@mdi/js";
export default {
data() {
return {
items: [
{
imgSrc1: "client/resources/img/img53_6_35s.png",
imgSrc2: "client/resources/img/img53_1_35s.png",
con: {
imgSrc: "client/resources/img/img54_s.png",
titleEm: "c",
title: "loud",
boxText: "명",
subtitle: "구름",
},
},
{
imgSrc1: "client/resources/img/img53_7_35s.png",
imgSrc2: "client/resources/img/img53_2_35s.png",
con: {
imgSrc: "client/resources/img/img40_s.png",
titleEm: "a",
title: "pple",
boxText: "명",
subtitle: "사과",
},
},
{
imgSrc1: "client/resources/img/img53_8_35s.png",
imgSrc2: "client/resources/img/img53_3_35s.png",
con: {
imgSrc: "client/resources/img/31img40_s.png",
titleEm: "l",
title: "og",
boxText: "명",
subtitle: "통나무",
},
},
{
imgSrc1: "client/resources/img/img53_9_35s.png",
imgSrc2: "client/resources/img/img53_4_35s.png",
con: {
imgSrc: "client/resources/img/img41_s.png",
titleEm: "g",
title: "uitar",
boxText: "명",
subtitle: "기타",
},
},
{
imgSrc1: "client/resources/img/img53_10_35s.png",
imgSrc2: "client/resources/img/img53_5_35s.png",
con: {
imgSrc: "client/resources/img/img76_41s.png",
titleEm: "w",
title: "ater melon",
boxText: "명",
subtitle: "수박",
},
},
],
currentCon: {
imgSrc: "client/resources/img/img54_s.png",
titleEm: "c",
title: "loud",
boxText: "명",
subtitle: "구름",
},
selectedIndex: 0,
timer: "00",
intervalId: null,
isRecording: false, // 녹음 중 여부
mediaRecorder: null,
audioChunks: [], // 녹음된 오디오 데이터
audioBlob: null, // 오디오 Blob 객체
stream: null, // MediaStream 객체
path: mdiStop,
nowWord: "cloud",
};
},
methods: {
complete() {
this.$router.push({ name: "Dashboard", query: { value: 2 } });
},
goToPage(page) {
this.$router.push({ name: page });
},
updateContent(index) {
this.selectedIndex = index;
this.currentCon = this.items[index].con;
this.startTimer();
},
startTimer() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
this.timer = 5;
this.intervalId = setInterval(() => {
if (this.timer > 0) {
this.timer--;
} else {
clearInterval(this.intervalId);
}
}, 1000);
},
// 녹음 시작/중지 토글
async toggleRecording() {
if (this.isRecording) {
console.log("녹음 그만!");
this.stopRecording(); // 녹음 중이면 중지
} else {
console.log("녹음 시작!");
await this.startRecording(); // 녹음 중이 아니면 녹음 시작
}
},
// 녹음 시작
async startRecording() {
this.audioChunks = []; // 오디오 초기화
this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
this.mediaRecorder = new MediaRecorder(this.stream);
this.mediaRecorder.ondataavailable = (event) => {
this.audioChunks.push(event.data); // 녹음 데이터 저장
};
this.mediaRecorder.onstop = () => {
this.audioBlob = new Blob(this.audioChunks, { type: "audio/wav" });
/******************************/
// this.audioURL = URL.createObjectURL(this.audioBlob); // 오디오 URL 생성
// console.log('Audio URL:', this.audioURL);
/******************************/
console.log("Recorded Audio Blob:", this.audioBlob); // 콘솔에 Blob 확인
this.sendAudioToServer(); // 서버로 오디오 전송
};
this.mediaRecorder.start(); // 녹음 시작
this.isRecording = true; // 녹음 상태 변경
},
// 녹음 중지
stopRecording() {
this.mediaRecorder.stop(); // 녹음 중단
if (this.stream) {
this.stream.getTracks().forEach((track) => track.stop()); // 스트림의 모든 트랙 중지
}
this.isRecording = false; // 녹음 상태 변경
},
// 오디오 전송
async sendAudioToServer() {
const formData = new FormData();
formData.append("file", this.audioBlob, "recording.wav");
try {
const response = await axios.post("/api/speechToText.json", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
this.transcription = response.data.trim().toLowerCase();
this.nowWord = this.nowWord.toLowerCase();
console.log("지금 단어: ", this.nowWord);
console.log("녹음 결과: ", this.transcription);
if (this.transcription === this.nowWord) {
this.$refs.speakText.innerText = "정답입니다! 잘했어요";
} else {
this.$refs.speakText.innerText = "다시 말해보세요!";
}
} catch (error) {
console.log("파일 전송 실패: ", error);
}
},
},
watch: {
transcription: null, // 서버에서 받아온 텍스트 결과
currentCon: {
handler(newValue) {
// Update nowWord when currentCon changes
this.nowWord = newValue.titleEm + newValue.title;
},
deep: true, // Watch for deep changes in currentCon
},
},
beforeDestroy() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
},
};
</script>
<style scoped>
.popTxt img {
position: absolute;
top: 0;
left: 0;
}
.box23 {
display: flex;
align-items: center;
gap: 80px;
justify-content: center;
}
.mic-btn {
cursor: pointer;
}
.mic-btn.notRecording {
background-image: none;
cursor: pointer;
}
.speakText {
background-color: #fff8e9;
border: 0;
}
.speakText span {
font-size: 28px;
}
.completeBtn {
margin-right: 100px;
background-color: #ffba08;
padding: 10px 30px;
border-radius: 10px;
font-size: 28px;
font-family: "ONEMobilePOPOTF";
}
</style>