in jukebox/save_html.py [0:0]
def _save_item_html(item_dir, item_id, item_name, data):
# replace gs:// with /root/samples/
# an html for each sample. Main html has a selector to get us id of this?
if not os.path.exists(item_dir):
os.makedirs(item_dir)
with open(f'{item_dir}/index.html', 'w') as html:
print(f"<html><head><title>{item_name}</title></head><body style='font-family: sans-serif; font-size: 1.4em; font-weight: bold; text-align: center; max-width:1024px; width: 100%; margin: auto;'>",
file=html)
print("<link rel='icon' href='data:;base64,iVBORw0KGgo='>", file=html)
total_length = data['total_length']
total_tokens = data['total_tokens']
alignment = data['alignment']
lyrics = data["info"]["lyrics"]
wav, sr = data['wav'], data['sr']
genre, artist = data["info"]["genre"], data["info"]["artist"]
# Strip unused columns
if alignment is not None:
assert alignment.shape == (total_length, total_tokens)
assert len(lyrics) == total_tokens, f'Total_tokens: {total_tokens}, Lyrics Len: {len(lyrics)}. Lyrics: {lyrics}'
max_attn_at_token = np.max(alignment, axis=0)
assert len(max_attn_at_token) == total_tokens
for token in reversed(range(total_tokens)):
if max_attn_at_token[token] > 0:
break
alignment = alignment[:,:token+1]
lyrics = lyrics[:token+1]
total_tokens = token+1
# Small alignment image
im = Image.fromarray(np.uint8(alignment * 255)).resize((512, 1024)).transpose(Image.ROTATE_90)
img_src = f'align.png'
im.save(f'{item_dir}/{img_src}')
print(f"<img id='{img_src}' src='{img_src}' \>", file=html)
# Smaller alignment json for animation
total_alignment_length = total_length // 16
alignment = Image.fromarray(np.uint8(alignment * 255)).resize((total_tokens, total_alignment_length))
alignment = alignment.filter(ImageFilter.GaussianBlur(radius=1.5))
alignment = np.asarray(alignment).tolist()
align_src = f'align.json'
with open(f'{item_dir}/{align_src}', 'w') as f:
json.dump(alignment, f)
# Audio
wav_src = f'audio.wav'
soundfile.write(f'{item_dir}/{wav_src}', wav, samplerate=sr, format='wav')
print(f"<audio id='{wav_src}' src='{wav_src}' style='width: 100%;' controls></audio>", file=html)
# Labels and Lyrics
print(f"<pre style='white-space: pre-wrap;'>", end="", file=html)
print(f"<div>Artist {artist}, Genre {genre}</div>", file=html)
lyrics = [c for c in lyrics] # already characters actually
lyrics = [''] + lyrics[:-1] # input lyrics are shifted by 1
for i, c in enumerate(lyrics):
print(f"<span id='{item_id}/{i}'>{c}</span>", end="", file=html)
print(f"</pre>", file=html)
with open(f'{item_dir}/lyrics.json', 'w') as f:
json.dump(lyrics, f)
if alignment is not None:
# JS for alignment animation
print("""<script>
async function fetchAsync (url) {
let response = await fetch(url);
let data = await response.json();
return data;
}
var audio = document.getElementById('""" + f'{wav_src}' + """');
audio.onplay = function () {
track = '""" + f'{item_id}' + """'
fetchAsync('""" + f'{align_src}' + """')
.then(data => animateLyrics(data, track, this))
.catch(reason => console.log(reason.message))
};
function animateLyrics(data, track, audio) {
var animate = setInterval(function () {
var time = Math.floor(audio.currentTime*""" + f'{total_alignment_length}' + """/audio.duration);
if (!(time == 0 || time == """ + f'{total_alignment_length}' + """)) {