Spaces:
Sleeping
Sleeping
# app.py | |
import streamlit as st | |
import pandas as pd | |
import plotly.express as px | |
import subprocess | |
import threading | |
import re | |
from io import StringIO | |
# ----------------------------- | |
# Data Preparation using Provided Data | |
# ----------------------------- | |
data_str = """ | |
Original (Source) Audio Target Audio number of speakers whisper model Time required video length run comments | |
french(fr) english(en) 2 large-v3 12:20 min 30s Subsequent Run Harshad | |
french(fr) korean(ko) 2 large-v3 0:13 min 30s Subsequent Run Harshad | |
french(fr) japanes(ja) 2 large-v3 3:05 min 30s Subsequent Run Harshad | |
french(fr) chinese(zh) 2 large-v3 9:02 min 30s Subsequent Run Harshad | |
french(fr) german(de) 2 large-v3 17:48 min 30s First Run Harshad | |
french(fr) spanish(es) 2 large-v3 0:14 min 30s Subsequent Run Harshad | |
french(fr) korean(ko) 2 large-v3 2:47 min 30s Subsequent Run Harshad | |
french(fr) english(en) 2 medium 2:16 min 30s First Run om | |
french(fr) korean(ko) 2 medium 20s 30s Subsequent Run om | |
french(fr) japanes(ja) 2 medium 30s 30s Subsequent Run om | |
french(fr) chinese(zh) 2 medium 17s 30s Subsequent Run om | |
french(fr) german(de) 2 medium 19s 30s Subsequent Run om | |
french(fr) spanish(es) 2 medium 12s 30s Subsequent Run om | |
french(fr) spanish(es) 2 small 2:51 min 30s First Run Harshad | |
french(fr) korean(ko) 2 small 0:09 min 30s Subsequent Run "Harshad,As per our observation for the 30 seconds video, the change in models is just affecting the processing time and the quality is not much affected" | |
french(fr) english(en) 2 base 3min 28s 1 min First Run om | |
french(fr) korean(ko) 2 base 3min 21s 1 min First Run om | |
french(fr) japanes(ja) 2 base 18s 1 min Subsequent Run om | |
french(fr) chinese(zh) 2 base 27s 1 min Subsequent Run om | |
french(fr) german(de) 2 base 25s 1 min Subsequent Run om | |
french(fr) spanish(es) 2 base 24s 1 min Subsequent Run om | |
french(fr) korean(ko) 2 base 15s 1 min Subsequent Run om | |
french(fr) english(en) 2 medium 24s 1 min Subsequent Run "om, It starts from translating step, skipping upto the diarization step in the subsequent run" | |
french(fr) korean(ko) 2 medium 17s 1 min Subsequent Run om | |
french(fr) japanes(ja) 2 medium 28s 1 min Subsequent Run om | |
french(fr) chinese(zh) 2 medium 20s 1 min Subsequent Run om | |
french(fr) german(de) 2 medium 30s 1 min Subsequent Run om | |
french(fr) spanish(es) 2 medium 4min 57s 1 min First Run om | |
french(fr) english(en) 2 medium 3min 31s 2 min First Run om | |
french(fr) korean(ko) 2 medium 10min 41s 2 min Subsequent Run om | |
french(fr) japanes(ja) 2 medium 1min 18s 2 min Subsequent Run om | |
french(fr) chinese(zh) 2 medium 1min 23s 2 min Subsequent Run om | |
french(fr) german(de) 2 medium 0:40 min 2 min Subsequent Run Harshad | |
french(fr) spanish(es) 2 medium 10:16 min 2 min First Run Harshad | |
french(fr) english(en) 2 small 8:53 min 2 min First Run Harshad | |
french(fr) korean(ko) 2 small 1:09 min 2 min Subsequent Run Harshad | |
french(fr) japanes(ja) 2 small 1:10 min 2 min Subsequent Run Harshad | |
french(fr) german(de) 2 small 0:42 min 2 min Subsequent Run Harshad | |
french(fr) spanish(es) 2 small 0:43 min 2 min Subsequent Run Harshad | |
french(fr) chinese(zh) 2 small 0:22 min 2 min Subsequent Run Harshad | |
french(fr) english(en) 2 small 18:42 min 5 min First Run Harshad | |
french(fr) korean(ko) 2 small 1:33 min 5 min Subsequent Run "Harshad, Saw some error but processing continued" | |
french(fr) japanes(ja) 2 small 1:50 min 5 min Subsequent Run Harshad | |
french(fr) german(de) 2 small 2:11 min 5 min Subsequent Run Harshad | |
french(fr) spanish(es) 2 small 2:06 min 5 min Subsequent Run Harshad | |
french(fr) chinese(zh) 2 small 1:34 min 5 min Subsequent Run Harshad | |
""" | |
# Read the provided data from the string | |
df = pd.read_csv(StringIO(data_str), delimiter='\t') | |
# Rename "Original (Source) Audio" to "Original Audio" for consistency | |
df = df.rename(columns={"Original (Source) Audio": "Original Audio"}) | |
# ----------------------------- | |
# Utility Function: Parse Time Strings | |
# ----------------------------- | |
def parse_time(time_str): | |
""" | |
Convert a time string (e.g., '17:48 min', '3min 28s', '30s', or '1 min') | |
into total seconds. | |
""" | |
if pd.isna(time_str): | |
return 0 | |
time_str = str(time_str).strip() | |
if not time_str: | |
return 0 | |
# If the string contains a colon, assume mm:ss or hh:mm:ss format. | |
if ":" in time_str: | |
clean_str = re.sub(r"[^\d:]", "", time_str) | |
parts = clean_str.split(":") | |
try: | |
parts = [int(p) for p in parts] | |
except ValueError: | |
return 0 | |
if len(parts) == 2: | |
minutes, seconds = parts | |
return minutes * 60 + seconds | |
elif len(parts) == 3: | |
hours, minutes, seconds = parts | |
return hours * 3600 + minutes * 60 + seconds | |
else: | |
# Use regex to capture hours, minutes, seconds if available. | |
pattern = r'(?:(?P<hours>\d+)\s*hr)?\s*(?:(?P<minutes>\d+)\s*min)?\s*(?:(?P<seconds>\d+)\s*s)?' | |
match = re.search(pattern, time_str) | |
if match: | |
hours = int(match.group("hours")) if match.group("hours") else 0 | |
minutes = int(match.group("minutes")) if match.group("minutes") else 0 | |
seconds = int(match.group("seconds")) if match.group("seconds") else 0 | |
return hours * 3600 + minutes * 60 + seconds | |
return 0 | |
# Create new numeric columns (processing times in seconds) | |
df["Time_required_seconds"] = df["Time required"].apply(parse_time) | |
df["Video_length_seconds"] = df["video length"].apply(parse_time) | |
# ----------------------------- | |
# Compute Aggregated Insights | |
# ----------------------------- | |
# Overall average processing time by whisper model | |
avg_time_by_model = df.groupby("whisper model")["Time_required_seconds"].mean().reset_index() | |
# Average processing time by target audio | |
avg_time_by_target = df.groupby("Target Audio")["Time_required_seconds"].mean().reset_index() | |
# Mark run type based on the "run" column (if "First" appears then it's First Run) | |
df["Run_type"] = df["run"].apply(lambda x: "First Run" if "First" in str(x) else "Subsequent Run") | |
# Run counts by whisper model and run type | |
run_counts = df.groupby(["whisper model", "Run_type"]).size().reset_index(name="count") | |
# ----------------------------- | |
# Create Plotly Figures | |
# ----------------------------- | |
# 1. Bar chart: Average Processing Time by Whisper Model | |
fig_model = px.bar( | |
avg_time_by_model, | |
x="whisper model", | |
y="Time_required_seconds", | |
title="Average Processing Time by Whisper Model", | |
labels={"Time_required_seconds": "Avg Time (seconds)", "whisper model": "Whisper Model"} | |
) | |
# 2. Bar chart: Average Processing Time by Target Audio | |
fig_target = px.bar( | |
avg_time_by_target, | |
x="Target Audio", | |
y="Time_required_seconds", | |
title="Average Processing Time by Target Audio", | |
labels={"Time_required_seconds": "Avg Time (seconds)", "Target Audio": "Target Audio"} | |
) | |
# 3. Scatter Plot: Processing Time vs Video Length | |
fig_scatter = px.scatter( | |
df, | |
x="Video_length_seconds", | |
y="Time_required_seconds", | |
color="whisper model", | |
title="Processing Time vs Video Length", | |
labels={"Video_length_seconds": "Video Length (seconds)", "Time_required_seconds": "Processing Time (seconds)"} | |
) | |
# 4. Bar chart: Run Counts by Whisper Model and Run Type | |
fig_run = px.bar( | |
run_counts, | |
x="whisper model", | |
y="count", | |
color="Run_type", | |
barmode="group", | |
title="Run Counts by Whisper Model", | |
labels={"count": "Number of Runs", "whisper model": "Whisper Model", "Run_type": "Run Type"} | |
) | |
# Additional Graphs | |
# Histogram of Processing Times | |
fig_hist_time = px.histogram( | |
df, | |
x="Time_required_seconds", | |
nbins=10, | |
title="Distribution of Processing Times", | |
labels={"Time_required_seconds": "Processing Time (seconds)"} | |
) | |
# Box Plot of Processing Times by Whisper Model | |
fig_box_model = px.box( | |
df, | |
x="whisper model", | |
y="Time_required_seconds", | |
title="Processing Time Distribution by Whisper Model", | |
labels={"Time_required_seconds": "Processing Time (seconds)"} | |
) | |
# Pie Chart for Distribution of Whisper Models | |
model_counts = df["whisper model"].value_counts().reset_index() | |
model_counts.columns = ["whisper model", "count"] | |
fig_pie_model = px.pie( | |
model_counts, | |
names="whisper model", | |
values="count", | |
title="Distribution of Whisper Models" | |
) | |
# Histogram of Video Lengths | |
fig_hist_video = px.histogram( | |
df, | |
x="Video_length_seconds", | |
nbins=5, | |
title="Distribution of Video Lengths", | |
labels={"Video_length_seconds": "Video Length (seconds)"} | |
) | |
# Scatter Plot: Processing Time vs Video Length by Run Type | |
fig_scatter_run = px.scatter( | |
df, | |
x="Video_length_seconds", | |
y="Time_required_seconds", | |
color="Run_type", | |
title="Processing Time vs Video Length by Run Type", | |
labels={"Video_length_seconds": "Video Length (seconds)", "Time_required_seconds": "Processing Time (seconds)"} | |
) | |
# Correlation Heatmap (using only numeric columns) | |
corr = df[["Time_required_seconds", "Video_length_seconds"]].corr() | |
fig_corr = px.imshow( | |
corr, | |
text_auto=True, | |
title="Correlation Matrix: Processing Time & Video Length", | |
labels=dict(color="Correlation") | |
) | |
# 3D Scatter Plot: Whisper Model vs Processing Time vs Video Length | |
fig_model_time_video = px.scatter_3d( | |
df, | |
x="whisper model", | |
y="Time_required_seconds", | |
z="Video_length_seconds", | |
color="whisper model", | |
title="Whisper Model vs Processing Time vs Video Length", | |
labels={ | |
"whisper model": "Whisper Model", | |
"Time_required_seconds": "Processing Time (seconds)", | |
"Video_length_seconds": "Video Length (seconds)" | |
} | |
) | |
# Enlarge the 3D graph layout | |
fig_model_time_video.update_layout(height=1000, width=1200) | |
# New Graph: | |
# First Run Average Processing Time by Whisper Model Grouped by Video Duration | |
first_run_df = df[df["Run_type"] == "First Run"] | |
avg_time_first_run = first_run_df.groupby(["whisper model", "video length"])["Time_required_seconds"].mean().reset_index() | |
fig_first_run = px.bar( | |
avg_time_first_run, | |
x="whisper model", | |
y="Time_required_seconds", | |
color="video length", | |
barmode="group", | |
title="First Run Average Processing Time by Whisper Model (Grouped by Video Duration)", | |
labels={"Time_required_seconds": "Avg Time (seconds)", "whisper model": "Whisper Model"} | |
) | |
# ----------------------------- | |
# Build the Streamlit App Layout | |
# ----------------------------- | |
st.title("Video Processing Dashboard") | |
st.markdown(""" | |
This dashboard provides insights into audio processing tasks using different Whisper models. | |
It displays processing times, target languages, video lengths, run types, and more. | |
""") | |
# Display the raw data | |
st.subheader("Raw Data") | |
st.dataframe(df) | |
# Display the original Plotly figures | |
st.subheader("Average Processing Time by Whisper Model") | |
st.plotly_chart(fig_model, use_container_width=True) | |
st.subheader("Average Processing Time by Target Audio") | |
st.plotly_chart(fig_target, use_container_width=True) | |
st.subheader("Processing Time vs Video Length") | |
st.plotly_chart(fig_scatter, use_container_width=True) | |
st.subheader("Run Counts by Whisper Model") | |
st.plotly_chart(fig_run, use_container_width=True) | |
# Display the additional graphs | |
st.subheader("Distribution of Processing Times") | |
st.plotly_chart(fig_hist_time, use_container_width=True) | |
st.subheader("Processing Time Distribution by Whisper Model (Box Plot)") | |
st.plotly_chart(fig_box_model, use_container_width=True) | |
st.subheader("Distribution of Whisper Models") | |
st.plotly_chart(fig_pie_model, use_container_width=True) | |
st.subheader("Distribution of Video Lengths") | |
st.plotly_chart(fig_hist_video, use_container_width=True) | |
st.subheader("Processing Time vs Video Length by Run Type") | |
st.plotly_chart(fig_scatter_run, use_container_width=True) | |
st.subheader("Correlation Matrix: Processing Time & Video Length") | |
st.plotly_chart(fig_corr, use_container_width=True) | |
st.subheader("Whisper Model vs Processing Time vs Video Length (3D)") | |
st.plotly_chart(fig_model_time_video, use_container_width=True) | |
st.subheader("First Run Avg Processing Time by Whisper Model and Video Duration") | |
st.plotly_chart(fig_first_run, use_container_width=True) | |
# ----------------------------- | |
# Optional: Start LocalTunnel for Public Access | |
# ----------------------------- | |
def start_localtunnel(port=8501): | |
""" | |
Launch LocalTunnel via the command line. | |
(Make sure you have it installed: npm install -g localtunnel) | |
""" | |
try: | |
proc = subprocess.Popen( | |
["lt", "--port", str(port)], | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
text=True, | |
) | |
def read_tunnel_output(process): | |
while True: | |
line = process.stdout.readline() | |
if not line: | |
break | |
st.write(line.strip()) | |
if "your url is:" in line.lower(): | |
public_url = line.split("your url is:")[-1].strip() | |
st.success(f"LocalTunnel URL: {public_url}") | |
thread = threading.Thread(target=read_tunnel_output, args=(proc,), daemon=True) | |
thread.start() | |
except Exception as e: | |
st.error(f"Error starting LocalTunnel: {e}") | |
# Uncomment the following line to start LocalTunnel when the app runs. | |
# start_localtunnel(port=8501) | |