slslslrhfem commited on
Commit
3e593f2
ยท
1 Parent(s): 90ddc2d

change file style

Browse files
Files changed (2) hide show
  1. app.py +104 -34
  2. inference.py +0 -43
app.py CHANGED
@@ -5,9 +5,12 @@ import librosa
5
  import numpy as np
6
  import subprocess
7
  import sys
8
- from huggingface_hub import snapshot_download
9
- from pathlib import Path
10
  import os
 
 
 
 
 
11
 
12
  # Runtime installation of madmom
13
  def install_madmom():
@@ -45,13 +48,12 @@ except ImportError as e:
45
  return {
46
  'matches': [],
47
  'message': 'madmom dependency not available'
48
- }
49
-
50
- token = os.getenv("HF_TOKEN")
51
 
52
  def download_data_from_hub():
53
  """
54
  Download covers80 and ml_models folders from Dataset repository
 
55
  """
56
  base_dir = Path(".")
57
  data_repo_id = "nininigold/music-data"
@@ -59,13 +61,24 @@ def download_data_from_hub():
59
  folders_to_check = ["covers80", "ml_models"]
60
  downloaded_folders = {}
61
 
 
 
 
 
 
 
 
 
 
 
62
  # ํด๋”๋“ค์ด ์ด๋ฏธ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
63
- all_exist = all((base_dir / folder).exists() and any((base_dir / folder).iterdir())
64
- for folder in folders_to_check)
65
 
66
- if not all_exist:
67
  print(f"๐Ÿ“ฅ Downloading data folders from dataset: {data_repo_id}")
68
  print(f" This includes covers80 and ml_models folders (~17k+ files each)")
 
69
  print(f" This may take several minutes...")
70
 
71
  try:
@@ -110,10 +123,41 @@ def download_data_from_hub():
110
 
111
  return downloaded_folders
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  @spaces.GPU
114
  def process_audio_for_matching(audio_file):
115
  """
116
- Process the uploaded audio file and return matching results
117
  """
118
  if audio_file is None:
119
  return """
@@ -127,23 +171,6 @@ def process_audio_for_matching(audio_file):
127
  # inference ํ•จ์ˆ˜ ํ˜ธ์ถœ
128
  result = inference(audio_file)
129
 
130
- # result ๊ตฌ์กฐ:
131
- # {
132
- # 'matches': [
133
- # {
134
- # 'rank': 1,
135
- # 'score': 0.95,
136
- # 'song_title': 'Song Name',
137
- # 'segment_file': 'path/to/segment.wav',
138
- # 'test_time': 23.5,
139
- # 'library_time': 45.2,
140
- # 'confidence': '95.0%',
141
- # 'time_match': 'Input: 23.5s โ†” Library: 45.2s'
142
- # }
143
- # ],
144
- # 'message': 'success' or error message
145
- # }
146
-
147
  if result.get('message') != 'success':
148
  return f"""
149
  <div style="text-align: center; padding: 25px; background: #fff3cd; border-radius: 15px; border: 1px solid #ffeaa7; margin: 10px 0;">
@@ -169,17 +196,51 @@ def process_audio_for_matching(audio_file):
169
  rank = match.get('rank', 0)
170
  song_title = match.get('song_title', 'Unknown Song')
171
  confidence = match.get('confidence', '0%')
172
- time_match = match.get('time_match', 'Unknown')
173
  test_time = match.get('test_time', 0)
174
  library_time = match.get('library_time', 0)
175
- segment_file = match.get('segment_file', '')
176
 
177
  # ๋žญํ‚น์— ๋”ฐ๋ฅธ ์ƒ‰์ƒ ์„ค์ •
178
  rank_colors = {1: '#e74c3c', 2: '#f39c12', 3: '#27ae60'}
179
  rank_color = rank_colors.get(rank, '#7f8c8d')
180
 
181
- # ์„ธ๊ทธ๋จผํŠธ ํŒŒ์ผ ์ •๋ณด
182
- segment_info = f"Found: {segment_file}" if segment_file else "No segment file found"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
  matches_html += f"""
185
  <div style="background: #ffffff; border-radius: 12px; padding: 20px; margin: 15px 0;
@@ -209,8 +270,10 @@ def process_audio_for_matching(audio_file):
209
  </div>
210
  </div>
211
 
 
 
212
  <div style="font-size: 0.9em; color: #7f8c8d; text-align: center; margin-top: 10px;">
213
- ๐Ÿ“ {segment_info}
214
  </div>
215
  </div>
216
  """
@@ -228,10 +291,17 @@ def process_audio_for_matching(audio_file):
228
  <div style="text-align: center; margin-top: 25px; padding: 15px; background: #e8f5e8; border-radius: 10px;">
229
  <p style="color: #27ae60; margin: 0; font-size: 0.95em;">
230
  ๐Ÿ’ก <strong>How to read results:</strong> The times show where similar segments were found.
231
- Higher ranked results have better similarity scores.
232
  </p>
233
  </div>
234
  </div>
 
 
 
 
 
 
 
235
  """
236
 
237
  return formatted_result
@@ -347,11 +417,11 @@ demo = gr.Interface(
347
  description="""
348
  <div style="text-align: center; font-size: 1.1em; color: #555; margin: 25px 0; line-height: 1.6;">
349
  <p><strong>๐ŸŽฏ Upload any audio clip and find similar segments in our music database!</strong></p>
350
- <p>Our AI analyzes your audio and finds the most similar segments from known songs.</p>
351
  <p style="font-size: 0.95em; color: #777; margin-top: 15px;">
352
  ๐Ÿ“ Supported formats: MP3, WAV, M4A, FLAC<br>
353
  โฑ๏ธ Processing time: ~15-30 seconds per file<br>
354
- ๐ŸŽผ Database: covers80 collection with segmented analysis
355
  </p>
356
  </div>
357
  """,
 
5
  import numpy as np
6
  import subprocess
7
  import sys
 
 
8
  import os
9
+ import glob
10
+ from pathlib import Path
11
+ from huggingface_hub import snapshot_download
12
+
13
+ token = os.getenv("HF_TOKEN")
14
 
15
  # Runtime installation of madmom
16
  def install_madmom():
 
48
  return {
49
  'matches': [],
50
  'message': 'madmom dependency not available'
51
+ }
 
 
52
 
53
  def download_data_from_hub():
54
  """
55
  Download covers80 and ml_models folders from Dataset repository
56
+ (1005_e_4 file is handled by Git LFS in the main repo)
57
  """
58
  base_dir = Path(".")
59
  data_repo_id = "nininigold/music-data"
 
61
  folders_to_check = ["covers80", "ml_models"]
62
  downloaded_folders = {}
63
 
64
+ # 1005_e_4 ํŒŒ์ผ์€ Git LFS๋กœ ์ด๋ฏธ ์žˆ๋Š”์ง€ ํ™•์ธ
65
+ lfs_file = base_dir / "1005_e_4"
66
+ if lfs_file.exists():
67
+ file_size = lfs_file.stat().st_size / (1024*1024) # MB
68
+ print(f"โœ… LFS file 1005_e_4: {file_size:.1f} MB")
69
+ downloaded_folders["1005_e_4"] = str(lfs_file)
70
+ else:
71
+ print(f"โš ๏ธ LFS file 1005_e_4 not found")
72
+ downloaded_folders["1005_e_4"] = None
73
+
74
  # ํด๋”๋“ค์ด ์ด๋ฏธ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
75
+ all_folders_exist = all((base_dir / folder).exists() and any((base_dir / folder).iterdir())
76
+ for folder in folders_to_check)
77
 
78
+ if not all_folders_exist:
79
  print(f"๐Ÿ“ฅ Downloading data folders from dataset: {data_repo_id}")
80
  print(f" This includes covers80 and ml_models folders (~17k+ files each)")
81
+ print(f" 1005_e_4 file is handled by Git LFS in main repo")
82
  print(f" This may take several minutes...")
83
 
84
  try:
 
123
 
124
  return downloaded_folders
125
 
126
+ def find_song_file_by_title(song_title):
127
+ """
128
+ covers80 ํด๋”์—์„œ ๊ณก ์ œ๋ชฉ์œผ๋กœ mp3 ํŒŒ์ผ์„ ์ฐพ์Œ
129
+ """
130
+ covers80_path = Path("covers80")
131
+
132
+ if not covers80_path.exists():
133
+ return None
134
+
135
+ # ์ •ํ™•ํ•œ ๋งค์น˜ ์‹œ๋„
136
+ exact_patterns = [
137
+ f"{song_title}.mp3",
138
+ f"*{song_title}.mp3",
139
+ f"{song_title}*.mp3"
140
+ ]
141
+
142
+ for pattern in exact_patterns:
143
+ matches = list(covers80_path.glob(pattern))
144
+ if matches:
145
+ return str(matches[0])
146
+
147
+ # ๋ถ€๋ถ„ ๋งค์น˜ ์‹œ๋„ (song_title์˜ ์ผ๋ถ€๋ถ„๋“ค๋กœ)
148
+ song_parts = song_title.replace('_', ' ').split()
149
+ for part in song_parts:
150
+ if len(part) > 3: # ๋„ˆ๋ฌด ์งง์€ ๋‹จ์–ด๋Š” ์ œ์™ธ
151
+ matches = list(covers80_path.glob(f"*{part}*.mp3"))
152
+ if matches:
153
+ return str(matches[0])
154
+
155
+ return None
156
+
157
  @spaces.GPU
158
  def process_audio_for_matching(audio_file):
159
  """
160
+ Process the uploaded audio file and return matching results with timestamp playback
161
  """
162
  if audio_file is None:
163
  return """
 
171
  # inference ํ•จ์ˆ˜ ํ˜ธ์ถœ
172
  result = inference(audio_file)
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  if result.get('message') != 'success':
175
  return f"""
176
  <div style="text-align: center; padding: 25px; background: #fff3cd; border-radius: 15px; border: 1px solid #ffeaa7; margin: 10px 0;">
 
196
  rank = match.get('rank', 0)
197
  song_title = match.get('song_title', 'Unknown Song')
198
  confidence = match.get('confidence', '0%')
 
199
  test_time = match.get('test_time', 0)
200
  library_time = match.get('library_time', 0)
 
201
 
202
  # ๋žญํ‚น์— ๋”ฐ๋ฅธ ์ƒ‰์ƒ ์„ค์ •
203
  rank_colors = {1: '#e74c3c', 2: '#f39c12', 3: '#27ae60'}
204
  rank_color = rank_colors.get(rank, '#7f8c8d')
205
 
206
+ # ๊ณก ํŒŒ์ผ ์ฐพ๊ธฐ
207
+ song_file_path = find_song_file_by_title(song_title)
208
+
209
+ # ์˜ค๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ์ƒ์„ฑ
210
+ audio_player = ""
211
+ if song_file_path and os.path.exists(song_file_path):
212
+ # ์ƒ๋Œ€ ๊ฒฝ๋กœ๋กœ ๋ณ€๊ฒฝ
213
+ rel_song_path = os.path.relpath(song_file_path)
214
+ audio_player = f"""
215
+ <div style="margin: 15px 0; padding: 15px; background: #f0f8ff; border-radius: 8px;">
216
+ <div style="text-align: center; margin-bottom: 10px;">
217
+ <strong style="color: #2c3e50;">๐ŸŽต Play from matched timestamp</strong>
218
+ </div>
219
+ <audio controls preload="metadata" style="width: 100%;">
220
+ <source src="file/{rel_song_path}#t={library_time:.1f}" type="audio/mpeg">
221
+ <source src="file/{rel_song_path}" type="audio/mpeg">
222
+ Your browser does not support the audio element.
223
+ </audio>
224
+ <div style="text-align: center; margin-top: 8px;">
225
+ <button onclick="seekToTime(this.parentElement.previousElementSibling.querySelector('audio'), {library_time})"
226
+ style="background: #3498db; color: white; border: none; padding: 5px 15px; border-radius: 15px; cursor: pointer; font-size: 0.9em;">
227
+ โญ๏ธ Jump to {library_time:.1f}s
228
+ </button>
229
+ </div>
230
+ <p style="font-size: 0.8em; color: #666; text-align: center; margin: 5px 0 0 0;">
231
+ Match found at {library_time:.1f}s in the original song
232
+ </p>
233
+ </div>
234
+ """
235
+ file_info = f"Found: {os.path.basename(song_file_path)}"
236
+ else:
237
+ audio_player = f"""
238
+ <div style="margin: 10px 0; padding: 10px; background: #fff3cd; border-radius: 8px; text-align: center;">
239
+ <p style="color: #856404; margin: 0;">๐Ÿ” Song file not found for playback</p>
240
+ <p style="font-size: 0.8em; color: #856404; margin: 5px 0 0 0;">Match at {library_time:.1f}s in "{song_title}"</p>
241
+ </div>
242
+ """
243
+ file_info = f"Song file not found: {song_title}"
244
 
245
  matches_html += f"""
246
  <div style="background: #ffffff; border-radius: 12px; padding: 20px; margin: 15px 0;
 
270
  </div>
271
  </div>
272
 
273
+ {audio_player}
274
+
275
  <div style="font-size: 0.9em; color: #7f8c8d; text-align: center; margin-top: 10px;">
276
+ ๐Ÿ“ {file_info}
277
  </div>
278
  </div>
279
  """
 
291
  <div style="text-align: center; margin-top: 25px; padding: 15px; background: #e8f5e8; border-radius: 10px;">
292
  <p style="color: #27ae60; margin: 0; font-size: 0.95em;">
293
  ๐Ÿ’ก <strong>How to read results:</strong> The times show where similar segments were found.
294
+ Use the audio player to listen from the matched timestamp.
295
  </p>
296
  </div>
297
  </div>
298
+
299
+ <script>
300
+ function seekToTime(audio, time) {{
301
+ audio.currentTime = time;
302
+ audio.play();
303
+ }}
304
+ </script>
305
  """
306
 
307
  return formatted_result
 
417
  description="""
418
  <div style="text-align: center; font-size: 1.1em; color: #555; margin: 25px 0; line-height: 1.6;">
419
  <p><strong>๐ŸŽฏ Upload any audio clip and find similar segments in our music database!</strong></p>
420
+ <p>Our AI analyzes your audio and finds the most similar segments from known songs with precise timestamps.</p>
421
  <p style="font-size: 0.95em; color: #777; margin-top: 15px;">
422
  ๐Ÿ“ Supported formats: MP3, WAV, M4A, FLAC<br>
423
  โฑ๏ธ Processing time: ~15-30 seconds per file<br>
424
+ ๐ŸŽผ Database: 160 songs with timestamp-based matching
425
  </p>
426
  </div>
427
  """,
inference.py CHANGED
@@ -9,44 +9,6 @@ def inference(audio_path):
9
  final_result = result_formatting(result)
10
  return final_result
11
 
12
- def find_closest_segment_file(song_title, target_time):
13
- """
14
- covers80 ํด๋”์—์„œ ํ•ด๋‹น ๊ณก์˜ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์‹œ๊ฐ„๋Œ€ ์„ธ๊ทธ๋จผํŠธ ํŒŒ์ผ์„ ์ฐพ์Œ
15
- """
16
- # ๊ฐ€๋Šฅํ•œ ํŒจํ„ด๋“ค๋กœ ๊ฒ€์ƒ‰
17
- patterns = [
18
- f"covers80/{song_title}_segments/*.wav",
19
- f"covers80/*{song_title}*_segments/*.wav",
20
- f"covers80/{song_title}*/*.wav"
21
- ]
22
-
23
- segment_files = []
24
- for pattern in patterns:
25
- segment_files.extend(glob.glob(pattern))
26
-
27
- if not segment_files:
28
- return None
29
-
30
- # ํŒŒ์ผ๋ช…์—์„œ ์‹œ๊ฐ„ ์ถ”์ถœํ•˜๊ณ  target_time๊ณผ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๊ฒƒ ์ฐพ๊ธฐ
31
- closest_file = None
32
- min_diff = float('inf')
33
-
34
- for file_path in segment_files:
35
- filename = os.path.basename(file_path)
36
- try:
37
- # ํŒŒ์ผ๋ช…์—์„œ ์‹œ๊ฐ„ ์ถ”์ถœ (์˜ˆ: "53.333.wav" -> 53.333)
38
- time_str = filename.replace('.wav', '')
39
- file_time = float(time_str)
40
- diff = abs(file_time - target_time)
41
-
42
- if diff < min_diff:
43
- min_diff = diff
44
- closest_file = file_path
45
- except ValueError:
46
- continue
47
-
48
- return closest_file
49
-
50
  def result_formatting(result):
51
  """
52
  get_one_result์—์„œ ๋‚˜์˜จ ๊ฒฐ๊ณผ๋ฅผ ํฌ๋งทํŒ…
@@ -79,14 +41,10 @@ def result_formatting(result):
79
  # ํ…Œ์ŠคํŠธ ๋ ˆ์ด๋ธ”์—์„œ ์ •๋ณด ์ถ”์ถœ
80
  test_time = test_label.get('time', 0) if test_label else 0 # ์ž…๋ ฅ ๊ณก์˜ ์‹œ๊ฐ„
81
 
82
- # ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์„ธ๊ทธ๋จผํŠธ ํŒŒ์ผ ์ฐพ๊ธฐ
83
- segment_file = find_closest_segment_file(song_title, library_time)
84
-
85
  match_info = {
86
  'rank': i + 1,
87
  'score': float(score),
88
  'song_title': song_title,
89
- 'segment_file': segment_file,
90
  'test_time': float(test_time), # ์ž…๋ ฅ ๊ณก์—์„œ ๋งค์น˜๋œ ์‹œ๊ฐ„
91
  'library_time': float(library_time), # ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ณก์—์„œ ๋งค์น˜๋œ ์‹œ๊ฐ„
92
  'confidence': f"{score * 100:.1f}%",
@@ -108,5 +66,4 @@ if __name__ == "__main__":
108
  print(f"Rank {match['rank']}: {match['song_title']}")
109
  print(f" Score: {match['confidence']}")
110
  print(f" Time Match: {match['time_match']}")
111
- print(f" Segment File: {match['segment_file']}")
112
  print()
 
9
  final_result = result_formatting(result)
10
  return final_result
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  def result_formatting(result):
13
  """
14
  get_one_result์—์„œ ๋‚˜์˜จ ๊ฒฐ๊ณผ๋ฅผ ํฌ๋งทํŒ…
 
41
  # ํ…Œ์ŠคํŠธ ๋ ˆ์ด๋ธ”์—์„œ ์ •๋ณด ์ถ”์ถœ
42
  test_time = test_label.get('time', 0) if test_label else 0 # ์ž…๋ ฅ ๊ณก์˜ ์‹œ๊ฐ„
43
 
 
 
 
44
  match_info = {
45
  'rank': i + 1,
46
  'score': float(score),
47
  'song_title': song_title,
 
48
  'test_time': float(test_time), # ์ž…๋ ฅ ๊ณก์—์„œ ๋งค์น˜๋œ ์‹œ๊ฐ„
49
  'library_time': float(library_time), # ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ณก์—์„œ ๋งค์น˜๋œ ์‹œ๊ฐ„
50
  'confidence': f"{score * 100:.1f}%",
 
66
  print(f"Rank {match['rank']}: {match['song_title']}")
67
  print(f" Score: {match['confidence']}")
68
  print(f" Time Match: {match['time_match']}")
 
69
  print()