rein0421 commited on
Commit
99daaaf
·
verified ·
1 Parent(s): 3b67cd9

Upload 5 files

Browse files
Files changed (3) hide show
  1. Dockerfile +3 -7
  2. app.py +4 -77
  3. process.py +81 -0
Dockerfile CHANGED
@@ -12,11 +12,7 @@ RUN apt-get update && \
12
  RUN python3 -m pip install --upgrade pip
13
 
14
  WORKDIR /app
15
- COPY requirements.txt .
16
 
17
- # requirements.txtのインストール
18
- RUN python3 -m pip install --no-cache-dir -r requirements.txt
19
-
20
- COPY . .
21
-
22
- CMD ["python3", "app.py"]
 
12
  RUN python3 -m pip install --upgrade pip
13
 
14
  WORKDIR /app
 
15
 
16
+ # requirements.txt をコンテナ内にコピーして、必要なパッケージをインストール
17
+ COPY requirements.txt /app/
18
+ RUN pip install --no-cache-dir -r requirements.txt
 
 
 
app.py CHANGED
@@ -1,84 +1,11 @@
1
  from flask import Flask, request, jsonify, render_template, send_from_directory
2
  import base64
 
3
  import os
4
  import shutil
5
- import numpy as np
6
- import string
7
- import random
8
- from datetime import datetime
9
- from pyannote.audio import Model, Inference
10
- from pydub import AudioSegment
11
-
12
- # Hugging Face のトークン取得(環境変数 HF に設定)
13
- hf_token = os.environ.get("HF")
14
- if hf_token is None:
15
- raise ValueError("HUGGINGFACE_HUB_TOKEN が設定されていません。")
16
-
17
- # キャッシュディレクトリの作成(書き込み可能な /tmp を利用)
18
- cache_dir = "/tmp/hf_cache"
19
- os.makedirs(cache_dir, exist_ok=True)
20
-
21
- # pyannote モデルの読み込み
22
- model = Model.from_pretrained("pyannote/embedding", use_auth_token=hf_token, cache_dir=cache_dir)
23
- inference = Inference(model)
24
-
25
- def cosine_similarity(vec1, vec2):
26
- vec1 = vec1 / np.linalg.norm(vec1)
27
- vec2 = vec2 / np.linalg.norm(vec2)
28
- return np.dot(vec1, vec2)
29
-
30
- def segment_audio(path, target_path='/tmp/setup_voice', seg_duration=1.0):
31
- """
32
- 音声を指定秒数ごとに分割する。
33
- target_path に分割したファイルを保存し、元の音声の総長(ミリ秒)を返す。
34
- """
35
- os.makedirs(target_path, exist_ok=True)
36
- base_sound = AudioSegment.from_file(path)
37
- duration_ms = len(base_sound)
38
- seg_duration_ms = int(seg_duration * 1000)
39
-
40
- for i, start in enumerate(range(0, duration_ms, seg_duration_ms)):
41
- end = min(start + seg_duration_ms, duration_ms)
42
- segment = base_sound[start:end]
43
- segment.export(os.path.join(target_path, f'{i}.wav'), format="wav")
44
-
45
- return target_path, duration_ms
46
-
47
- def calculate_similarity(path1, path2):
48
- embedding1 = inference(path1)
49
- embedding2 = inference(path2)
50
- return float(cosine_similarity(embedding1.data.flatten(), embedding2.data.flatten()))
51
-
52
- def process_audio(reference_path, input_path, output_folder='/tmp/data/matched_segments', seg_duration=1.0, threshold=0.5):
53
- """
54
- 入力音声ファイルを seg_duration 秒ごとに分割し、各セグメントと参照音声の類似度を計算。
55
- 類似度が threshold を超えたセグメントを output_folder にコピーし、マッチした時間(ms)と
56
- マッチしなかった時間(ms)を返す。
57
- """
58
- os.makedirs(output_folder, exist_ok=True)
59
- segmented_path, total_duration_ms = segment_audio(input_path, seg_duration=seg_duration)
60
-
61
- matched_time_ms = 0
62
- for file in sorted(os.listdir(segmented_path)):
63
- segment_file = os.path.join(segmented_path, file)
64
- similarity = calculate_similarity(segment_file, reference_path)
65
- if similarity > threshold:
66
- shutil.copy(segment_file, output_folder)
67
- matched_time_ms += len(AudioSegment.from_file(segment_file))
68
-
69
- unmatched_time_ms = total_duration_ms - matched_time_ms
70
- return matched_time_ms, unmatched_time_ms
71
-
72
- def generate_random_string(length):
73
- letters = string.ascii_letters + string.digits
74
- return ''.join(random.choice(letters) for i in range(length))
75
-
76
- def generate_filename(random_length):
77
- random_string = generate_random_string(random_length)
78
- current_time = datetime.now().strftime("%Y%m%d%H%M%S")
79
- filename = f"{current_time}_{random_string}.wav"
80
- return filename
81
 
 
82
  app = Flask(__name__)
83
 
84
  # トップページ(テンプレート: index.html)
@@ -121,7 +48,7 @@ def upload_audio():
121
 
122
  # 音声解析:参照音声とアップロードされた音声との類似度をセグメント毎に計算
123
  # threshold の値は調整可能です(例: 0.1)
124
- matched_time, unmatched_time = process_audio(reference_audio, audio_path, threshold=0.1)
125
  total_time = matched_time + unmatched_time
126
  rate = (matched_time / total_time) * 100 if total_time > 0 else 0
127
 
 
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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ process=AudioProcessor()
9
  app = Flask(__name__)
10
 
11
  # トップページ(テンプレート: index.html)
 
48
 
49
  # 音声解析:参照音声とアップロードされた音声との類似度をセグメント毎に計算
50
  # threshold の値は調整可能です(例: 0.1)
51
+ matched_time, unmatched_time = process.process_audio(reference_audio, audio_path, threshold=0.1)
52
  total_time = matched_time + unmatched_time
53
  rate = (matched_time / total_time) * 100 if total_time > 0 else 0
54
 
process.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import shutil
4
+ import numpy as np
5
+ import string
6
+ import random
7
+ from datetime import datetime
8
+ from pyannote.audio import Model, Inference
9
+ from pydub import AudioSegment
10
+ 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 モデルの読み込み
18
+ model = Model.from_pretrained("pyannote/embedding", use_auth_token=hf_token, cache_dir=cache_dir)
19
+ self.inference = Inference(model)
20
+
21
+ def cosine_similarity(self,vec1, vec2):
22
+ vec1 = vec1 / np.linalg.norm(vec1)
23
+ vec2 = vec2 / np.linalg.norm(vec2)
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
+ os.makedirs(target_path, exist_ok=True)
31
+ base_sound = AudioSegment.from_file(path)
32
+ duration_ms = len(base_sound)
33
+ seg_duration_ms = int(seg_duration * 1000)
34
+
35
+ for i, start in enumerate(range(0, duration_ms, seg_duration_ms)):
36
+ end = min(start + seg_duration_ms, duration_ms)
37
+ segment = base_sound[start:end]
38
+ # セグメントが指定長さに満たない場合、無音でパディングする
39
+ if len(segment) < seg_duration_ms:
40
+ silence = AudioSegment.silent(duration=(seg_duration_ms - len(segment)))
41
+ segment = segment + silence
42
+
43
+ segment.export(os.path.join(target_path, f'{i}.wav'), format="wav")
44
+
45
+ return target_path, duration_ms
46
+
47
+
48
+ def calculate_similarity(self,path1, path2):
49
+ embedding1 = self.inference(path1)
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
+ 入力音声ファイルを seg_duration 秒ごとに分割し、各セグメントと参照音声の類似度を計算。
56
+ 類似度が threshold を超えたセグメントを output_folder にコピーし、マッチした時間(ms)と
57
+ マッチしなかった時間(ms)を返す。
58
+ """
59
+ os.makedirs(output_folder, exist_ok=True)
60
+ segmented_path, total_duration_ms = self.segment_audio(input_path, seg_duration=seg_duration)
61
+
62
+ matched_time_ms = 0
63
+ for file in sorted(os.listdir(segmented_path)):
64
+ segment_file = os.path.join(segmented_path, file)
65
+ similarity = self.calculate_similarity(segment_file, reference_path)
66
+ if similarity > threshold:
67
+ shutil.copy(segment_file, output_folder)
68
+ matched_time_ms += len(AudioSegment.from_file(segment_file))
69
+
70
+ unmatched_time_ms = total_duration_ms - matched_time_ms
71
+ return matched_time_ms, unmatched_time_ms
72
+
73
+ def generate_random_string(self,length):
74
+ letters = string.ascii_letters + string.digits
75
+ return ''.join(random.choice(letters) for i in range(length))
76
+
77
+ def generate_filename(self,random_length):
78
+ random_string = self.generate_random_string(random_length)
79
+ current_time = datetime.now().strftime("%Y%m%d%H%M%S")
80
+ filename = f"{current_time}_{random_string}.wav"
81
+ return filename