<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>iPhone対応・音声変換</title>
<style>
/* 画面全体の設定:スクロール禁止・1画面に収める */
body {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
text-align: center;
background: #f0f0f0;
margin: 0;
padding: 0;
height: 100vh; /* 画面の高さいっぱい */
overflow: hidden; /* スクロール禁止 */
display: flex;
justify-content: center;
align-items: center;
}
/* コンテナ:縦に並べて均等配置 */
.container {
width: 90%;
height: 95%; /* 画面の95%を使う */
max-width: 600px;
display: flex;
flex-direction: column;
justify-content: space-evenly; /* 上下の隙間を均等に */
align-items: center;
}
/* ボタン:高さを半分に(paddingを減らす) */
.big-btn {
width: 100%;
padding: 15px 0; /* 高さを減らしました */
font-size: 20px;
font-weight: bold;
color: white;
border: none;
border-radius: 15px;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
cursor: pointer;
transition: transform 0.1s;
-webkit-tap-highlight-color: transparent;
}
.big-btn:active { transform: scale(0.96); }
#recBtn { background-color: #ff4757; }
#playBtn { background-color: #2ed573; display: none; } /* 最初は非表示 */
/* 選択ボックス */
select {
width: 100%;
padding: 10px;
font-size: 16px;
border-radius: 10px;
border: 1px solid #ccc;
background: white;
}
/* テキスト表示エリア */
#output-container {
width: 100%;
flex-grow: 1; /* 余ったスペースをこれに使う */
max-height: 40%; /* 大きくなりすぎないように制限 */
display: flex;
flex-direction: column;
}
#output {
width: 100%;
height: 100%;
background: white;
padding: 15px;
box-sizing: border-box;
border-radius: 15px;
font-size: 18px;
border: 1px solid #ddd;
text-align: left;
overflow-y: auto; /* 文字が多い時だけここをスクロール */
}
.label {
font-size: 14px;
color: #666;
margin-bottom: 5px;
text-align: left;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<h2>音声変換器</h2>
<div style="width:100%">
<div class="label">声の種類 (日本語のみ)</div>
<select id="voiceSelect"><option>読み込み中...</option></select>
</div>
<button id="recBtn" class="big-btn">① 録音する</button>
<div id="output-container">
<div class="label">聞き取り結果:</div>
<div id="output">(ここに文字が出ます)</div>
</div>
<button id="playBtn" class="big-btn">② 再生する</button>
</div>
<script>
const voiceSelect = document.getElementById('voiceSelect');
const recBtn = document.getElementById('recBtn');
const playBtn = document.getElementById('playBtn');
const output = document.getElementById('output');
let availableVoices = [];
let recognizedText = "";
// 音声リスト読み込み
function loadVoices() {
const allVoices = window.speechSynthesis.getVoices();
if (allVoices.length === 0) return;
// ★修正: lang が 'ja-JP' のものだけに限定
availableVoices = allVoices.filter(v => v.lang === 'ja-JP');
if (availableVoices.length === 0) {
voiceSelect.innerHTML = '<option>日本語の声が見つかりません</option>';
return;
}
voiceSelect.innerHTML = availableVoices
.map((voice, index) => `<option value="${index}">${voice.name}</option>`)
.join('');
}
window.speechSynthesis.onvoiceschanged = loadVoices;
loadVoices();
// 音声認識の設定
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SpeechRecognition) {
output.innerText = "このブラウザは対応していません。Safariを使ってください。";
recBtn.disabled = true;
recBtn.style.backgroundColor = "#ccc";
} else {
const recognition = new SpeechRecognition();
recognition.lang = 'ja-JP';
recognition.interimResults = false;
recBtn.onclick = () => {
// 音声コンテキストの開放(iOS対策)
window.speechSynthesis.cancel();
try {
recognition.start();
recBtn.innerText = "聞いています...";
recBtn.style.opacity = "0.7";
playBtn.style.display = "none"; // 録音し直すときは再生ボタンを隠す
} catch(e) {
console.log("Recognition error/restart");
}
};
recognition.onresult = (event) => {
recognizedText = event.results[0][0].transcript;
output.innerText = recognizedText;
recBtn.innerText = "① 録音する";
recBtn.style.opacity = "1";
playBtn.style.display = "block"; // 録音完了でボタン出現
};
recognition.onend = () => {
if(recBtn.innerText === "聞いています...") {
recBtn.innerText = "① 録音する";
recBtn.style.opacity = "1";
}
};
recognition.onerror = () => {
recBtn.innerText = "エラー:もう一度";
recBtn.style.opacity = "1";
};
}
playBtn.onclick = () => {
if (!recognizedText) return;
const uttr = new SpeechSynthesisUtterance(recognizedText);
// 選択された声を設定
const selectedVoice = availableVoices[voiceSelect.value];
if (selectedVoice) {
uttr.voice = selectedVoice;
}
uttr.pitch = 1.3;
uttr.rate = 1.0;
window.speechSynthesis.cancel();
window.speechSynthesis.speak(uttr);
};
</script>
</body>
</html>
使用変数
| allVoices | |
| availableVoices | |
| backgroundColor | |
| charset | |
| class | |
| content | |
| disabled | |
| display | |
| id | |
| innerHTML | |
| innerText | |
| interimResults | |
| lang | |
| length | |
| loadVoices -------( Function ) | |
| name | |
| onclick | |
| onend | |
| onerror | |
| onresult | |
| onvoiceschanged | |
| opacity | |
| output | |
| pitch | |
| playBtn | |
| rate | |
| recBtn | |
| recognition | |
| recognizedText | |
| scalable | |
| scale | |
| selectedVoice | |
| SpeechRecognition | |
| style | |
| uttr | |
| v | |
| value | |
| voice | |
| voiceSelect | |
| width |