Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -278,182 +278,79 @@ def update_all_users():
|
|
278 |
@app.route('/upload_audio', methods=['POST'])
|
279 |
def upload_audio():
|
280 |
global total_audio
|
281 |
-
global users
|
282 |
-
|
283 |
try:
|
284 |
data = request.get_json()
|
285 |
if not data or 'audio_data' not in data:
|
286 |
-
print("エラー: リクエストに audio_data が含まれていません。")
|
287 |
return jsonify({"error": "音声データがありません"}), 400
|
288 |
-
|
289 |
# リクエストからユーザーリストを取得(指定がなければ現在のusersを使用)
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
else:
|
296 |
-
# グローバル変数を使う場合(非推奨)
|
297 |
-
# current_users = users
|
298 |
-
# print(f"グローバル変数からユーザーを使用: {current_users}")
|
299 |
-
# グローバル変数ではなく、エラーにする方が安全
|
300 |
-
print("エラー: リクエストに selected_users が指定されていません。")
|
301 |
-
return jsonify({"error": "選択されたユーザーが指定されていません"}), 400
|
302 |
-
|
303 |
-
if not current_users:
|
304 |
-
print("エラー: 処理対象のユーザーがいません。")
|
305 |
return jsonify({"error": "選択されたユーザーがいません"}), 400
|
306 |
|
307 |
# Base64デコードして音声バイナリを取得
|
308 |
audio_binary = base64.b64decode(data['audio_data'])
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
audio_dir = "/tmp/justalk_audio_data" # 一時ディレクトリ名(環境に合わせて変更可)
|
313 |
os.makedirs(audio_dir, exist_ok=True)
|
314 |
audio_path = os.path.join(audio_dir, f"{upload_name}.wav")
|
315 |
with open(audio_path, 'wb') as f:
|
316 |
f.write(audio_binary)
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
# 各ユーザーの参照音声ファイルのパスをリストに格納
|
326 |
reference_paths = []
|
327 |
-
|
328 |
-
for user in current_users:
|
329 |
try:
|
330 |
-
ref_path = os.path.join(
|
331 |
-
# 参照ファイルがローカルになければクラウドから取得試行
|
332 |
if not os.path.exists(ref_path):
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
# 再度存在確認 (ダウンロード成功したか)
|
342 |
-
if os.path.exists(ref_path):
|
343 |
-
reference_paths.append(ref_path)
|
344 |
-
else:
|
345 |
-
# 最終的にファイルが見つからなかった場合
|
346 |
-
print(f"エラー: ユーザー '{user}' の参照音声ファイルが見つかりません: {ref_path}")
|
347 |
-
missing_files.append(user)
|
348 |
-
|
349 |
except Exception as e:
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
if missing_files:
|
358 |
-
return jsonify({"error": f"一部ユーザーの参照音声が見つかりません: {', '.join(missing_files)}"}), 500
|
359 |
-
# 処理に必要なユーザー数と参照ファイル数が一致しない場合もエラー
|
360 |
-
if len(reference_paths) != len(current_users):
|
361 |
-
return jsonify({"error": f"参照音声ファイルの数({len(reference_paths)})がユーザー数({len(current_users)})と一致しません"}), 500
|
362 |
-
|
363 |
-
|
364 |
-
# --- ユーザー数に応じて処理分岐 ---
|
365 |
-
if len(current_users) > 1:
|
366 |
-
# --- 複数人処理 ---
|
367 |
-
print(f"複数人 ({len(current_users)}人) の音声処理を開始します。")
|
368 |
-
try:
|
369 |
-
matched_times, merged_segments = process.process_multi_audio(
|
370 |
-
reference_paths, audio_path, current_users, threshold=0.05
|
371 |
-
)
|
372 |
-
# total_audio = transcripter.save_marged_segments(merged_segments) # 必要なら有効化
|
373 |
-
except Exception as proc_e:
|
374 |
-
print(f"エラー: process_multi_audio でエラーが発生しました: {proc_e}")
|
375 |
-
traceback.print_exc()
|
376 |
-
return jsonify({"error": "音声処理中にエラーが発生しました(multi)", "details": str(proc_e)}), 500
|
377 |
-
|
378 |
# 各メンバーのrateを計算
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
# 各ユーザーの割合を計算
|
386 |
-
for i in range(len(current_users)):
|
387 |
-
user = current_users[i]
|
388 |
-
time = matched_times[i]
|
389 |
-
# 発話合計時間が0より大きい場合のみ割合計算
|
390 |
-
rate = (time / total_matched_time) * 100 if total_matched_time > 0 else 0
|
391 |
-
# 念のため rate が 0 未満にならないようにする
|
392 |
-
user_rates[user] = max(0, rate)
|
393 |
-
|
394 |
-
print(f"計算直後の user_rates: {user_rates}")
|
395 |
-
|
396 |
-
# --- 'その他' の計算と追加 ---
|
397 |
-
current_total_rate = sum(user_rates.values()) # 計算されたレートの合計
|
398 |
-
print(f"計算後の合計レート: {current_total_rate:.2f}%")
|
399 |
-
|
400 |
-
# 合計が100%未満の場合 (浮動小数点誤差を考慮)
|
401 |
-
# かつ合計が負でないことを確認(通常ありえないが念のため)
|
402 |
-
if current_total_rate < 99.99 and current_total_rate >= 0:
|
403 |
-
other_rate = 100.0 - current_total_rate
|
404 |
-
user_rates['その他'] = other_rate # 'その他' を追加
|
405 |
-
print(f"'その他' ({other_rate:.2f}%) を追加しました。")
|
406 |
-
|
407 |
-
# オプション: 合計が100%をわずかに超える場合の正規化 (必要に応じてコメント解除)
|
408 |
-
elif current_total_rate > 100.01:
|
409 |
-
print(f"警告: 合計レートが {current_total_rate:.2f}% で100%を超えました。正規化します。")
|
410 |
-
factor = 100.0 / current_total_rate
|
411 |
-
normalized_rates = {}
|
412 |
-
temp_sum = 0
|
413 |
-
keys = list(user_rates.keys())
|
414 |
-
for i, user in enumerate(keys):
|
415 |
-
if i < len(keys) - 1:
|
416 |
-
normalized_rate = user_rates[user] * factor
|
417 |
-
normalized_rates[user] = normalized_rate
|
418 |
-
temp_sum += normalized_rate
|
419 |
-
else:
|
420 |
-
normalized_rates[user] = max(0, 100.0 - temp_sum) # 最後の要素で調整、0未満防止
|
421 |
-
user_rates = normalized_rates
|
422 |
-
print(f"正規化後の user_rates: {user_rates}")
|
423 |
-
|
424 |
-
print(f"最終的に返す user_rates: {user_rates}")
|
425 |
-
# React側が扱いやすい user_rates 形式で返す
|
426 |
-
return jsonify({"user_rates": user_rates}), 200
|
427 |
-
|
428 |
else:
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
matched_time, unmatched_time, merged_segments = process.process_audio(
|
433 |
-
reference_paths[0], audio_path, current_users[0], threshold=0.05
|
434 |
-
)
|
435 |
-
# total_audio = transcripter.save_marged_segments(merged_segments) # 必要なら有効化
|
436 |
-
except Exception as proc_e:
|
437 |
-
print(f"エラー: process_audio でエラーが発生しました: {proc_e}")
|
438 |
-
traceback.print_exc()
|
439 |
-
return jsonify({"error": "音声処理中にエラーが発生しました(single)", "details": str(proc_e)}), 500
|
440 |
-
|
441 |
total_time = matched_time + unmatched_time
|
442 |
rate = (matched_time / total_time) * 100 if total_time > 0 else 0
|
443 |
-
|
444 |
-
|
445 |
-
silent_rate = 100.0 - rate
|
446 |
-
|
447 |
-
# シングルユーザーでも user_rates 形式で統一して返す
|
448 |
-
user_rates = {current_users[0]: rate, '無音': silent_rate}
|
449 |
-
print(f"単一ユーザー、user_rates形式で返す: {user_rates}")
|
450 |
-
return jsonify({"user_rates": user_rates}), 200
|
451 |
-
|
452 |
except Exception as e:
|
453 |
-
print(
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
|
458 |
# ユーザー選択画面(テンプレート: userSelect.html)
|
459 |
@app.route('/')
|
|
|
278 |
@app.route('/upload_audio', methods=['POST'])
|
279 |
def upload_audio():
|
280 |
global total_audio
|
281 |
+
global users
|
282 |
+
|
283 |
try:
|
284 |
data = request.get_json()
|
285 |
if not data or 'audio_data' not in data:
|
|
|
286 |
return jsonify({"error": "音声データがありません"}), 400
|
287 |
+
|
288 |
# リクエストからユーザーリストを取得(指定がなければ現在のusersを使用)
|
289 |
+
if 'selected_users' in data and data['selected_users']:
|
290 |
+
users = data['selected_users']
|
291 |
+
print(f"選択されたユーザー: {users}")
|
292 |
+
|
293 |
+
if not users:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
return jsonify({"error": "選択されたユーザーがいません"}), 400
|
295 |
|
296 |
# Base64デコードして音声バイナリを取得
|
297 |
audio_binary = base64.b64decode(data['audio_data'])
|
298 |
+
|
299 |
+
upload_name = 'tmp'
|
300 |
+
audio_dir = "/tmp/data"
|
|
|
301 |
os.makedirs(audio_dir, exist_ok=True)
|
302 |
audio_path = os.path.join(audio_dir, f"{upload_name}.wav")
|
303 |
with open(audio_path, 'wb') as f:
|
304 |
f.write(audio_binary)
|
305 |
+
|
306 |
+
print(f"処理を行うユーザー: {users}")
|
307 |
+
|
308 |
+
# ベース音声を一時ディレクトリにダウンロード
|
309 |
+
temp_dir = "/tmp/data/base_audio"
|
310 |
+
os.makedirs(temp_dir, exist_ok=True)
|
311 |
+
|
|
|
312 |
# 各ユーザーの参照音声ファイルのパスをリストに格納
|
313 |
reference_paths = []
|
314 |
+
for user in users:
|
|
|
315 |
try:
|
316 |
+
ref_path = os.path.join(temp_dir, f"{user}.wav")
|
|
|
317 |
if not os.path.exists(ref_path):
|
318 |
+
# クラウドから取得
|
319 |
+
download_from_cloud(f"{user}.wav", ref_path)
|
320 |
+
print(f"クラウドから {user}.wav をダウンロードしました")
|
321 |
+
|
322 |
+
if not os.path.exists(ref_path):
|
323 |
+
return jsonify({"error": "参照音声ファイルが見つかりません", "details": ref_path}), 500
|
324 |
+
|
325 |
+
reference_paths.append(ref_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
except Exception as e:
|
327 |
+
return jsonify({"error": f"ユーザー {user} の音声取得に失敗しました", "details": str(e)}), 500
|
328 |
+
|
329 |
+
# 複数人の場合は参照パスのリストを、1人の場合は単一のパスを渡す
|
330 |
+
if len(users) > 1:
|
331 |
+
print("複数人の場合の処理")
|
332 |
+
matched_times, merged_segments = process.process_multi_audio(reference_paths, audio_path, users, threshold=0.05)
|
333 |
+
total_audio = transcripter.save_marged_segments(merged_segments)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
334 |
# 各メンバーのrateを計算
|
335 |
+
total_time = sum(matched_times)
|
336 |
+
rates = [(time / total_time) * 100 if total_time > 0 else 0 for time in matched_times]
|
337 |
+
|
338 |
+
# ユーザー名と話した割合をマッピング
|
339 |
+
user_rates = {users[i]: rates[i] for i in range(len(users))}
|
340 |
+
return jsonify({"rates": rates, "user_rates": user_rates}), 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
else:
|
342 |
+
matched_time, unmatched_time, merged_segments = process.process_audio(reference_paths[0], audio_path, users[0], threshold=0.05)
|
343 |
+
total_audio = transcripter.save_marged_segments(merged_segments)
|
344 |
+
print("単一ユーザーの処理")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
345 |
total_time = matched_time + unmatched_time
|
346 |
rate = (matched_time / total_time) * 100 if total_time > 0 else 0
|
347 |
+
return jsonify({"rate": rate, "user": users[0]}), 200
|
348 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
349 |
except Exception as e:
|
350 |
+
print("Error in /upload_audio:", str(e))
|
351 |
+
return jsonify({"error": "サーバーエラー", "details": str(e)}), 500
|
352 |
+
|
353 |
+
# ユーザー選択画面(テンプレート: userSelect.html)
|
354 |
|
355 |
# ユーザー選択画面(テンプレート: userSelect.html)
|
356 |
@app.route('/')
|