Spaces:
Running
Running
Upload 2 files
Browse files- app.py +39 -8
- process.py +19 -12
app.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
from flask import Flask, request, jsonify, render_template, send_from_directory
|
2 |
import base64
|
3 |
-
|
4 |
import os
|
5 |
import shutil
|
6 |
from process import AudioProcessor
|
@@ -24,11 +24,6 @@ def feedback():
|
|
24 |
def talk_detail():
|
25 |
return render_template('talkDetail.html')
|
26 |
|
27 |
-
# 会話履歴画面(テンプレート: history.html)
|
28 |
-
@app.route('/history', methods=['GET', 'POST'])
|
29 |
-
def history():
|
30 |
-
return render_template('history.html')
|
31 |
-
|
32 |
# 音声アップロード&解析エンドポイント
|
33 |
@app.route('/upload_audio', methods=['POST'])
|
34 |
def upload_audio():
|
@@ -47,13 +42,13 @@ def upload_audio():
|
|
47 |
f.write(audio_binary)
|
48 |
|
49 |
# 参照音声ファイルのパスを指定(sample.wav を正しい場所に配置すること)
|
50 |
-
reference_audio = os.path.abspath('
|
51 |
if not os.path.exists(reference_audio):
|
52 |
return jsonify({"error": "参照音声ファイルが見つかりません", "details": reference_audio}), 500
|
53 |
|
54 |
# 音声解析:参照音声とアップロードされた音声との類似度をセグメント毎に計算
|
55 |
# threshold の値は調整可能です(例: 0.1)
|
56 |
-
matched_time, unmatched_time = process.process_audio(reference_audio, audio_path, threshold=0.
|
57 |
total_time = matched_time + unmatched_time
|
58 |
rate = (matched_time / total_time) * 100 if total_time > 0 else 0
|
59 |
|
@@ -61,6 +56,42 @@ def upload_audio():
|
|
61 |
except Exception as e:
|
62 |
print("Error in /upload_audio:", str(e))
|
63 |
return jsonify({"error": "サーバーエラー", "details": str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
if __name__ == '__main__':
|
66 |
port = int(os.environ.get("PORT", 7860))
|
|
|
1 |
from flask import Flask, request, jsonify, render_template, send_from_directory
|
2 |
import base64
|
3 |
+
from pydub import AudioSegment # 変換用にpydubをインポート
|
4 |
import os
|
5 |
import shutil
|
6 |
from process import AudioProcessor
|
|
|
24 |
def talk_detail():
|
25 |
return render_template('talkDetail.html')
|
26 |
|
|
|
|
|
|
|
|
|
|
|
27 |
# 音声アップロード&解析エンドポイント
|
28 |
@app.route('/upload_audio', methods=['POST'])
|
29 |
def upload_audio():
|
|
|
42 |
f.write(audio_binary)
|
43 |
|
44 |
# 参照音声ファイルのパスを指定(sample.wav を正しい場所に配置すること)
|
45 |
+
reference_audio = os.path.abspath('/tmp/data/base_audio/recorded_base_audio.wav')
|
46 |
if not os.path.exists(reference_audio):
|
47 |
return jsonify({"error": "参照音声ファイルが見つかりません", "details": reference_audio}), 500
|
48 |
|
49 |
# 音声解析:参照音声とアップロードされた音声との類似度をセグメント毎に計算
|
50 |
# threshold の値は調整可能です(例: 0.1)
|
51 |
+
matched_time, unmatched_time = process.process_audio(reference_audio, audio_path, threshold=0.05)
|
52 |
total_time = matched_time + unmatched_time
|
53 |
rate = (matched_time / total_time) * 100 if total_time > 0 else 0
|
54 |
|
|
|
56 |
except Exception as e:
|
57 |
print("Error in /upload_audio:", str(e))
|
58 |
return jsonify({"error": "サーバーエラー", "details": str(e)}), 500
|
59 |
+
@app.route('/upload_base_audio', methods=['POST'])
|
60 |
+
def upload_base_audio():
|
61 |
+
try:
|
62 |
+
data = request.get_json()
|
63 |
+
if not data or 'audio_data' not in data:
|
64 |
+
return jsonify({"error": "音声データがありません"}), 400
|
65 |
+
|
66 |
+
# Base64デコードして音声バイナリを取得
|
67 |
+
audio_binary = base64.b64decode(data['audio_data'])
|
68 |
+
|
69 |
+
# 保存先ディレクトリの作成
|
70 |
+
audio_dir = "/tmp/data/base_audio"
|
71 |
+
os.makedirs(audio_dir, exist_ok=True)
|
72 |
+
|
73 |
+
# 一時ファイルに保存(実際の形式は WebM などと仮定)
|
74 |
+
temp_audio_path = os.path.join(audio_dir, "temp_audio")
|
75 |
+
with open(temp_audio_path, 'wb') as f:
|
76 |
+
f.write(audio_binary)
|
77 |
+
|
78 |
+
# pydub を使って一時ファイルを WAV に変換
|
79 |
+
# ※ここでは WebM 形式と仮定していますが、実際の形式に合わせて format の指定を変更してください
|
80 |
+
try:
|
81 |
+
audio = AudioSegment.from_file(temp_audio_path, format="webm")
|
82 |
+
except Exception as e:
|
83 |
+
# 形式が不明な場合は自動判別させる(ただし変換できない場合もあり)
|
84 |
+
audio = AudioSegment.from_file(temp_audio_path)
|
85 |
+
wav_audio_path = os.path.join(audio_dir, "recorded_base_audio.wav")
|
86 |
+
audio.export(wav_audio_path, format="wav")
|
87 |
+
|
88 |
+
# 一時ファイルを削除
|
89 |
+
os.remove(temp_audio_path)
|
90 |
+
|
91 |
+
return jsonify({"state": "Registration Success!"}), 200
|
92 |
+
except Exception as e:
|
93 |
+
print("Error in /upload_base_audio:", str(e))
|
94 |
+
return jsonify({"error": "サーバーエラー", "details": str(e)}), 500
|
95 |
|
96 |
if __name__ == '__main__':
|
97 |
port = int(os.environ.get("PORT", 7860))
|
process.py
CHANGED
@@ -11,7 +11,6 @@ class AudioProcessor():
|
|
11 |
def __init__(self,cache_dir = "/tmp/hf_cache"):
|
12 |
hf_token = os.environ.get("HF")
|
13 |
if hf_token is None:
|
14 |
-
print('3')
|
15 |
raise ValueError("HUGGINGFACE_HUB_TOKEN が設定されていません。")
|
16 |
os.makedirs(cache_dir, exist_ok=True)
|
17 |
# pyannote モデルの読み込み
|
@@ -24,10 +23,15 @@ class AudioProcessor():
|
|
24 |
return np.dot(vec1, vec2)
|
25 |
|
26 |
def segment_audio(self, path, target_path='/tmp/setup_voice', seg_duration=1.0):
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
31 |
base_sound = AudioSegment.from_file(path)
|
32 |
duration_ms = len(base_sound)
|
33 |
seg_duration_ms = int(seg_duration * 1000)
|
@@ -50,13 +54,16 @@ class AudioProcessor():
|
|
50 |
embedding2 = self.inference(path2)
|
51 |
return float(self.cosine_similarity(embedding1.data.flatten(), embedding2.data.flatten()))
|
52 |
|
53 |
-
def process_audio(self,reference_path, input_path, output_folder='/tmp/data/matched_segments', seg_duration=1.0, threshold=0.5):
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
|
|
|
|
|
|
60 |
segmented_path, total_duration_ms = self.segment_audio(input_path, seg_duration=seg_duration)
|
61 |
|
62 |
matched_time_ms = 0
|
|
|
11 |
def __init__(self,cache_dir = "/tmp/hf_cache"):
|
12 |
hf_token = os.environ.get("HF")
|
13 |
if hf_token is None:
|
|
|
14 |
raise ValueError("HUGGINGFACE_HUB_TOKEN が設定されていません。")
|
15 |
os.makedirs(cache_dir, exist_ok=True)
|
16 |
# pyannote モデルの読み込み
|
|
|
23 |
return np.dot(vec1, vec2)
|
24 |
|
25 |
def segment_audio(self, path, target_path='/tmp/setup_voice', seg_duration=1.0):
|
26 |
+
# 出力先ディレクトリが存在していれば中身をクリアする
|
27 |
+
if os.path.exists(target_path):
|
28 |
+
for file in os.listdir(target_path):
|
29 |
+
file_path = os.path.join(target_path, file)
|
30 |
+
if os.path.isfile(file_path):
|
31 |
+
os.remove(file_path)
|
32 |
+
else:
|
33 |
+
os.makedirs(target_path, exist_ok=True)
|
34 |
+
|
35 |
base_sound = AudioSegment.from_file(path)
|
36 |
duration_ms = len(base_sound)
|
37 |
seg_duration_ms = int(seg_duration * 1000)
|
|
|
54 |
embedding2 = self.inference(path2)
|
55 |
return float(self.cosine_similarity(embedding1.data.flatten(), embedding2.data.flatten()))
|
56 |
|
57 |
+
def process_audio(self, reference_path, input_path, output_folder='/tmp/data/matched_segments', seg_duration=1.0, threshold=0.5):
|
58 |
+
# 出力先ディレクトリの中身をクリアする
|
59 |
+
if os.path.exists(output_folder):
|
60 |
+
for file in os.listdir(output_folder):
|
61 |
+
file_path = os.path.join(output_folder, file)
|
62 |
+
if os.path.isfile(file_path):
|
63 |
+
os.remove(file_path)
|
64 |
+
else:
|
65 |
+
os.makedirs(output_folder, exist_ok=True)
|
66 |
+
|
67 |
segmented_path, total_duration_ms = self.segment_audio(input_path, seg_duration=seg_duration)
|
68 |
|
69 |
matched_time_ms = 0
|