Spaces:
Running
Running
Update templates/index.html
Browse files- templates/index.html +67 -47
templates/index.html
CHANGED
@@ -166,19 +166,13 @@
|
|
166 |
let recordingInterval;
|
167 |
let count_voice = 0;
|
168 |
let before_rate = [];
|
169 |
-
const RECORDING_INTERVAL_MS = 1000; //
|
|
|
170 |
// メンバーとチャートの初期化
|
171 |
let members = [];
|
172 |
let voiceData = [];
|
173 |
-
let baseMemberColors = [
|
174 |
-
|
175 |
-
"#007bff",
|
176 |
-
"#ffc107",
|
177 |
-
"#dc3545",
|
178 |
-
"#28a745",
|
179 |
-
"#9c27b0",
|
180 |
-
"#ff9800",
|
181 |
-
];
|
182 |
// Chart.js の初期化
|
183 |
const ctx = document.getElementById("speechChart").getContext("2d");
|
184 |
const speechChart = new Chart(ctx, {
|
@@ -203,6 +197,7 @@
|
|
203 |
},
|
204 |
},
|
205 |
});
|
|
|
206 |
// サーバーからメンバー情報を取得してチャートを更新する関数
|
207 |
async function updateChartFrom() {
|
208 |
try {
|
@@ -211,6 +206,7 @@
|
|
211 |
throw new Error(`HTTP error! status: ${response.status}`);
|
212 |
}
|
213 |
const data = await response.json();
|
|
|
214 |
if (!data || !data.members || !Array.isArray(data.members)) {
|
215 |
console.error("Invalid member data received:", data);
|
216 |
members = ["member1"];
|
@@ -218,11 +214,13 @@
|
|
218 |
updateChart();
|
219 |
return;
|
220 |
}
|
|
|
221 |
members = data.members;
|
222 |
voiceData = [];
|
223 |
for (let i = 0; i < members.length; i++) {
|
224 |
voiceData.push(100 / members.length);
|
225 |
}
|
|
|
226 |
updateChart();
|
227 |
} catch (error) {
|
228 |
console.error("Failed to fetch member data:", error);
|
@@ -231,6 +229,7 @@
|
|
231 |
updateChart();
|
232 |
}
|
233 |
}
|
|
|
234 |
function updateChart() {
|
235 |
// 一人モードの場合は、ユーザーとグレー(無音)の比率をチャートに表示
|
236 |
if (members.length === 1) {
|
@@ -240,37 +239,40 @@
|
|
240 |
} else {
|
241 |
// 複数メンバーの場合は通常通りの処理
|
242 |
speechChart.data.labels = members;
|
243 |
-
speechChart.data.datasets[0].backgroundColor = getMemberColors(
|
244 |
-
members.length
|
245 |
-
);
|
246 |
}
|
|
|
247 |
speechChart.data.datasets[0].data = voiceData;
|
248 |
speechChart.update();
|
249 |
}
|
|
|
250 |
// ページ読み込み時にチャート情報を更新
|
251 |
updateChartFrom();
|
|
|
252 |
// 録音ボタンの録音開始/停止処理
|
253 |
async function toggleRecording() {
|
254 |
const recordButton = document.getElementById("recordButton");
|
|
|
255 |
if (!isRecording) {
|
256 |
// 録音開始
|
257 |
isRecording = true;
|
258 |
recordButton.classList.add("recording");
|
259 |
try {
|
260 |
-
const stream = await navigator.mediaDevices.getUserMedia({
|
261 |
-
audio: true,
|
262 |
-
});
|
263 |
mediaRecorder = new MediaRecorder(stream);
|
264 |
audioChunks = [];
|
|
|
265 |
mediaRecorder.ondataavailable = (event) => {
|
266 |
if (event.data.size > 0) {
|
267 |
audioChunks.push(event.data);
|
268 |
}
|
269 |
};
|
|
|
270 |
mediaRecorder.onstop = () => {
|
271 |
sendAudioChunks([...audioChunks]);
|
272 |
audioChunks = [];
|
273 |
};
|
|
|
274 |
mediaRecorder.start();
|
275 |
// 5秒ごとに録音を停止して送信するインターバルを設定
|
276 |
recordingInterval = setInterval(() => {
|
@@ -296,6 +298,7 @@
|
|
296 |
before_rate = [];
|
297 |
}
|
298 |
}
|
|
|
299 |
function sendAudioChunks(chunks) {
|
300 |
const audioBlob = new Blob(chunks, { type: "audio/wav" });
|
301 |
const reader = new FileReader();
|
@@ -326,6 +329,7 @@
|
|
326 |
};
|
327 |
reader.readAsDataURL(audioBlob);
|
328 |
}
|
|
|
329 |
function getMemberColors(memberCount) {
|
330 |
// 一人モードの場合は特別な処理をしない(updateChartで処理するため)
|
331 |
if (memberCount <= 1) {
|
@@ -338,6 +342,7 @@
|
|
338 |
return colors;
|
339 |
}
|
340 |
}
|
|
|
341 |
function updateChartData(newRate) {
|
342 |
// 一人モードの時の処理
|
343 |
if (members.length === 1) {
|
@@ -346,56 +351,71 @@
|
|
346 |
before_rate = [newRate];
|
347 |
} else {
|
348 |
// 一人モードでは、過去のデータと現在のデータを加重平均する
|
349 |
-
let tmp_rate =
|
350 |
-
(newRate + before_rate[0] * count_voice) / (count_voice + 1);
|
351 |
speechChart.data.datasets[0].data = [tmp_rate, 100 - tmp_rate];
|
352 |
before_rate = [tmp_rate];
|
353 |
}
|
354 |
count_voice++;
|
|
|
|
|
|
|
|
|
355 |
} else {
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
|
|
360 |
}
|
361 |
-
|
362 |
-
|
363 |
-
|
|
|
|
|
|
|
|
|
364 |
}
|
365 |
-
updateChart();
|
366 |
-
}
|
367 |
-
}
|
368 |
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
menu.classList.toggle("open");
|
374 |
-
}
|
375 |
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
381 |
}
|
382 |
-
}
|
383 |
|
384 |
-
|
385 |
-
function showUserRegister() {
|
386 |
-
console.log("ユーザー登録画面を表示");
|
387 |
}
|
388 |
|
389 |
function showTalkdetail() {
|
390 |
-
|
391 |
}
|
392 |
|
393 |
function showResults() {
|
394 |
-
|
395 |
}
|
396 |
|
397 |
-
function
|
398 |
-
|
|
|
399 |
}
|
400 |
</script>
|
401 |
</body>
|
|
|
166 |
let recordingInterval;
|
167 |
let count_voice = 0;
|
168 |
let before_rate = [];
|
169 |
+
const RECORDING_INTERVAL_MS = 1000; // 5秒
|
170 |
+
|
171 |
// メンバーとチャートの初期化
|
172 |
let members = [];
|
173 |
let voiceData = [];
|
174 |
+
let baseMemberColors = ["#4caf50", "#007bff", "#ffc107", "#dc3545", "#28a745", "#9c27b0", "#ff9800"];
|
175 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
// Chart.js の初期化
|
177 |
const ctx = document.getElementById("speechChart").getContext("2d");
|
178 |
const speechChart = new Chart(ctx, {
|
|
|
197 |
},
|
198 |
},
|
199 |
});
|
200 |
+
|
201 |
// サーバーからメンバー情報を取得してチャートを更新する関数
|
202 |
async function updateChartFrom() {
|
203 |
try {
|
|
|
206 |
throw new Error(`HTTP error! status: ${response.status}`);
|
207 |
}
|
208 |
const data = await response.json();
|
209 |
+
|
210 |
if (!data || !data.members || !Array.isArray(data.members)) {
|
211 |
console.error("Invalid member data received:", data);
|
212 |
members = ["member1"];
|
|
|
214 |
updateChart();
|
215 |
return;
|
216 |
}
|
217 |
+
|
218 |
members = data.members;
|
219 |
voiceData = [];
|
220 |
for (let i = 0; i < members.length; i++) {
|
221 |
voiceData.push(100 / members.length);
|
222 |
}
|
223 |
+
|
224 |
updateChart();
|
225 |
} catch (error) {
|
226 |
console.error("Failed to fetch member data:", error);
|
|
|
229 |
updateChart();
|
230 |
}
|
231 |
}
|
232 |
+
|
233 |
function updateChart() {
|
234 |
// 一人モードの場合は、ユーザーとグレー(無音)の比率をチャートに表示
|
235 |
if (members.length === 1) {
|
|
|
239 |
} else {
|
240 |
// 複数メンバーの場合は通常通りの処理
|
241 |
speechChart.data.labels = members;
|
242 |
+
speechChart.data.datasets[0].backgroundColor = getMemberColors(members.length);
|
|
|
|
|
243 |
}
|
244 |
+
|
245 |
speechChart.data.datasets[0].data = voiceData;
|
246 |
speechChart.update();
|
247 |
}
|
248 |
+
|
249 |
// ページ読み込み時にチャート情報を更新
|
250 |
updateChartFrom();
|
251 |
+
|
252 |
// 録音ボタンの録音開始/停止処理
|
253 |
async function toggleRecording() {
|
254 |
const recordButton = document.getElementById("recordButton");
|
255 |
+
|
256 |
if (!isRecording) {
|
257 |
// 録音開始
|
258 |
isRecording = true;
|
259 |
recordButton.classList.add("recording");
|
260 |
try {
|
261 |
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
|
|
|
262 |
mediaRecorder = new MediaRecorder(stream);
|
263 |
audioChunks = [];
|
264 |
+
|
265 |
mediaRecorder.ondataavailable = (event) => {
|
266 |
if (event.data.size > 0) {
|
267 |
audioChunks.push(event.data);
|
268 |
}
|
269 |
};
|
270 |
+
|
271 |
mediaRecorder.onstop = () => {
|
272 |
sendAudioChunks([...audioChunks]);
|
273 |
audioChunks = [];
|
274 |
};
|
275 |
+
|
276 |
mediaRecorder.start();
|
277 |
// 5秒ごとに録音を停止して送信するインターバルを設定
|
278 |
recordingInterval = setInterval(() => {
|
|
|
298 |
before_rate = [];
|
299 |
}
|
300 |
}
|
301 |
+
|
302 |
function sendAudioChunks(chunks) {
|
303 |
const audioBlob = new Blob(chunks, { type: "audio/wav" });
|
304 |
const reader = new FileReader();
|
|
|
329 |
};
|
330 |
reader.readAsDataURL(audioBlob);
|
331 |
}
|
332 |
+
|
333 |
function getMemberColors(memberCount) {
|
334 |
// 一人モードの場合は特別な処理をしない(updateChartで処理するため)
|
335 |
if (memberCount <= 1) {
|
|
|
342 |
return colors;
|
343 |
}
|
344 |
}
|
345 |
+
|
346 |
function updateChartData(newRate) {
|
347 |
// 一人モードの時の処理
|
348 |
if (members.length === 1) {
|
|
|
351 |
before_rate = [newRate];
|
352 |
} else {
|
353 |
// 一人モードでは、過去のデータと現在のデータを加重平均する
|
354 |
+
let tmp_rate = (newRate + before_rate[0] * count_voice) / (count_voice + 1);
|
|
|
355 |
speechChart.data.datasets[0].data = [tmp_rate, 100 - tmp_rate];
|
356 |
before_rate = [tmp_rate];
|
357 |
}
|
358 |
count_voice++;
|
359 |
+
|
360 |
+
// 一人モードでは常に緑色とグレーの組み合わせを使用
|
361 |
+
speechChart.data.labels = [members[0], "無音"];
|
362 |
+
speechChart.data.datasets[0].backgroundColor = ["#4caf50", "#757575"];
|
363 |
} else {
|
364 |
+
console.log(before_rate)
|
365 |
+
// 複数人モードの処理
|
366 |
+
if (!Array.isArray(newRate)) {
|
367 |
+
console.error("newRate is not an array:", newRate);
|
368 |
+
return;
|
369 |
}
|
370 |
+
if (newRate.length !== members.length) {
|
371 |
+
console.error(
|
372 |
+
"newRate length does not match members length:",
|
373 |
+
newRate,
|
374 |
+
members
|
375 |
+
);
|
376 |
+
return;
|
377 |
}
|
|
|
|
|
|
|
378 |
|
379 |
+
let averagedRates = new Array(newRate.length);
|
380 |
+
|
381 |
+
for (let i = 0; i < newRate.length; i++) {
|
382 |
+
let tmp_rate;
|
|
|
|
|
383 |
|
384 |
+
if (count_voice === 0) {
|
385 |
+
// 初回はそのまま
|
386 |
+
tmp_rate = newRate[i];
|
387 |
+
} else {
|
388 |
+
// 2回目以降は、過去の平均値と現在の値を加重平均する
|
389 |
+
tmp_rate = (newRate[i] + before_rate[i] * count_voice) / (count_voice + 1);
|
390 |
+
}
|
391 |
+
averagedRates[i] = tmp_rate;
|
392 |
+
}
|
393 |
+
|
394 |
+
// before_rateを更新
|
395 |
+
before_rate = averagedRates;
|
396 |
+
|
397 |
+
//グラフに反映
|
398 |
+
speechChart.data.datasets[0].data = averagedRates;
|
399 |
+
count_voice++;
|
400 |
+
speechChart.data.datasets[0].backgroundColor = getMemberColors(
|
401 |
+
members.length
|
402 |
+
);
|
403 |
}
|
|
|
404 |
|
405 |
+
speechChart.update();
|
|
|
|
|
406 |
}
|
407 |
|
408 |
function showTalkdetail() {
|
409 |
+
window.location.href = "talk_detail";
|
410 |
}
|
411 |
|
412 |
function showResults() {
|
413 |
+
window.location.href = "feedback";
|
414 |
}
|
415 |
|
416 |
+
function showUserRegister() {
|
417 |
+
fetch("/reset");
|
418 |
+
window.location.href = "userregister";
|
419 |
}
|
420 |
</script>
|
421 |
</body>
|