taejinp's picture
Update Nemotron streaming multispeaker ASR Space
2dd1cd7 verified
Raw
History Blame Contribute Delete
5.63 kB
import numpy as np
SPEAKER_COLORS = [
"#76B900", # Green
"#49A4DE", # Blue
"#E06C75", # Red
"#C678DD", # Purple
"#E5A84B", # Orange
"#36CFC9", # Cyan
"#FF7AB2", # Pink
"#F5F5F5", # White
]
def array_to_gradient_html(arr=None, num_frames=125, num_of_speakers=4, partitions=None):
"""
Convert num_of_speakers by num_frames numpy array to HTML gradient boxes.
Parameters:
-----------
arr : numpy.ndarray, optional
num_of_speakers by num_frames array with values from 0.0 to 1.0
Shape: (num_of_speakers, num_frames)
If None, creates a default random array
num_frames : int, default 125
Number of frames/columns (only used if arr is None)
num_of_speakers : int, default 4
Number of speakers/rows (only used if arr is None)
partitions : list of dict, optional
Named activity arrays rendered as proportional sections. Each dictionary contains
``name``, ``values``, ``capacity``, and optionally ``valid_frames``.
Returns:
--------
str : HTML string with colored gradient boxes
Example:
--------
>>> arr = np.array([[0.0, 0.25, 0.5, 0.75, 1.0]]) # 1 speaker, 5 frames
>>> html = array_to_gradient_html(arr)
>>> print(html)
"""
# Color map for different speakers (black background to full color)
# Matching the app.py color scheme for dark theme
color_map = {
speaker_idx: tuple(int(color[offset : offset + 2], 16) for offset in (1, 3, 5))
for speaker_idx, color in enumerate(SPEAKER_COLORS)
}
def value_to_color(value, speaker_idx):
"""
Convert a value from 0.0 to 1.0 to a color gradient for a specific speaker.
0.0 -> #000000 (black background)
1.0 -> speaker's color (green, blue, gray, or red)
"""
# Clamp value between 0 and 1
value = max(0.0, min(1.0, value))
# Get speaker's target color (cycle through colors if more speakers than colors)
speaker_color = color_map.get(speaker_idx % len(color_map), (0, 0, 0))
target_r, target_g, target_b = speaker_color
# Gradient from black (0, 0, 0) to speaker's color
# Linear interpolation between black and target color
r = int(target_r * value)
g = int(target_g * value)
b = int(target_b * value)
return f"#{r:02X}{g:02X}{b:02X}"
if partitions is None:
if arr is None:
arr = np.random.rand(num_of_speakers, num_frames)
partitions = [{"name": "DIARIZATION", "values": arr, "capacity": num_frames}]
prepared_partitions = []
for partition in partitions:
capacity = max(1, int(partition["capacity"]))
values = partition.get("values")
if values is None:
values = np.zeros((num_of_speakers, 0), dtype=np.float32)
values = np.asarray(values)
if values.ndim != 2:
raise ValueError(f"Expected a 2-D speaker activity array, but received shape {values.shape}")
if values.shape[0] < num_of_speakers:
values = np.pad(values, ((0, num_of_speakers - values.shape[0]), (0, 0)), mode='constant')
else:
values = values[:num_of_speakers]
if values.shape[1] < capacity:
values = np.pad(values, ((0, 0), (capacity - values.shape[1], 0)), mode='constant')
else:
values = values[:, -capacity:]
prepared_partitions.append(
{
"name": partition["name"],
"values": values,
"capacity": capacity,
"valid_frames": min(int(partition.get("valid_frames", values.shape[1])), capacity),
}
)
column_weights = " ".join(f"{partition['capacity']}fr" for partition in prepared_partitions)
html = '<div class="diar-partition-labels">'
for partition in prepared_partitions:
html += (
f'<span class="diar-partition-label">{partition["name"]} '
f'{partition["valid_frames"]}/{partition["capacity"]}</span>'
)
html += '</div>'
html += '<div class="diar-map">'
for speaker_idx in range(num_of_speakers):
html += (
f'<div class="diar-row" style="grid-template-columns:{column_weights};" '
f'title="Speaker {speaker_idx + 1}">'
)
for partition in prepared_partitions:
html += (
f'<div class="diar-partition" title="{partition["name"]}" '
f'style="grid-template-columns:repeat({partition["capacity"]}, minmax(0, 1fr));">'
)
for val in partition["values"][speaker_idx]:
color = value_to_color(val, speaker_idx)
html += f'<span class="diar-cell" style="background-color:{color};"></span>'
html += '</div>'
html += '</div>'
html += '</div>'
return html
if __name__ == "__main__":
# Example 3: Default parameters
print("Example 3: Using default parameters (4 speakers x 125 frames)")
html3 = array_to_gradient_html()
# print(html3[:500] + "...") # Print first 500 chars
print(html3)
print(f"\nTotal HTML length: {len(html3)} characters")
# Example 4: Show the 20-step gradient like in the original example
# print("\n" + "="*50 + "\n")
# print("Example 4: 20-step gradient (like the original) - 1 speaker x 20 frames")
# gradient_arr = np.linspace(0, 1, 20).reshape(1, 20) # Shape: (1, 20)
# html4 = array_to_gradient_html(gradient_arr)
# print(html4)