Spaces:
Sleeping
Sleeping
Add timestamp code
Browse files- README.md +2 -4
- app.py +1087 -3
- packages.txt +2 -0
- requirements.txt +3 -0
- runtime.txt +1 -0
- transcription_format_1.json +1 -0
- transcription_format_2.json +1 -0
- transcription_format_3.json +899 -0
README.md
CHANGED
|
@@ -4,10 +4,8 @@ emoji: 🏃
|
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
-
short_description: '
|
| 11 |
---
|
| 12 |
-
|
| 13 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 5.49.1
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
+
short_description: 'Testing word timestamps from any transcript'
|
| 11 |
---
|
|
|
|
|
|
app.py
CHANGED
|
@@ -1,7 +1,1091 @@
|
|
|
|
|
| 1 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
def greet(name):
|
| 4 |
-
return "Hello " + name + "!!"
|
| 5 |
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
demo.launch()
|
|
|
|
| 1 |
+
# Timestamps Tester - Test word timestamps from any transcript
|
| 2 |
import gradio as gr
|
| 3 |
+
import soundfile as sf
|
| 4 |
+
import numpy as np
|
| 5 |
+
import base64
|
| 6 |
+
import io
|
| 7 |
+
import json
|
| 8 |
+
import time
|
| 9 |
+
import traceback
|
| 10 |
+
from ten_vad import TenVad
|
| 11 |
+
import matplotlib
|
| 12 |
+
matplotlib.use('Agg')
|
| 13 |
+
import matplotlib.pyplot as plt
|
| 14 |
|
|
|
|
|
|
|
| 15 |
|
| 16 |
+
def detect_silence_periods(audio_data, sample_rate, prob_threshold=0.5, min_off_ms=48, min_on_ms=64):
|
| 17 |
+
"""Run TEN VAD to detect silence periods in audio.
|
| 18 |
+
|
| 19 |
+
Args:
|
| 20 |
+
audio_data: numpy array of audio samples (float, mono, 16kHz)
|
| 21 |
+
sample_rate: sample rate (must be 16000)
|
| 22 |
+
prob_threshold: VAD probability threshold (0.0-1.0), higher = less sensitive
|
| 23 |
+
min_off_ms: Minimum silence duration in ms - shorter silences are filled in as voice
|
| 24 |
+
min_on_ms: Minimum voice duration in ms - shorter voice bursts are removed
|
| 25 |
+
|
| 26 |
+
Returns:
|
| 27 |
+
List of dicts with 'start' and 'end' times for each silence period
|
| 28 |
+
"""
|
| 29 |
+
TARGET_SR = 16000 # TEN VAD requires 16kHz
|
| 30 |
+
HOP_SIZE = 256 # 16ms at 16kHz
|
| 31 |
+
FRAME_MS = 16.0 # Each frame is 16ms
|
| 32 |
+
|
| 33 |
+
print(f"[VAD] Settings: prob_threshold={prob_threshold}, min_off_ms={min_off_ms}, min_on_ms={min_on_ms}")
|
| 34 |
+
|
| 35 |
+
if sample_rate != TARGET_SR:
|
| 36 |
+
print(f"[VAD] Warning: Expected 16kHz audio, got {sample_rate}Hz")
|
| 37 |
+
|
| 38 |
+
# Convert float audio to int16 (TEN VAD expects int16)
|
| 39 |
+
if audio_data.dtype == np.float32 or audio_data.dtype == np.float64:
|
| 40 |
+
audio_int16 = (audio_data * 32767).astype(np.int16)
|
| 41 |
+
else:
|
| 42 |
+
audio_int16 = audio_data.astype(np.int16)
|
| 43 |
+
|
| 44 |
+
# Create VAD instance
|
| 45 |
+
vad = TenVad(hop_size=HOP_SIZE, threshold=prob_threshold)
|
| 46 |
+
|
| 47 |
+
frame_duration = HOP_SIZE / TARGET_SR # 0.016s = 16ms
|
| 48 |
+
|
| 49 |
+
# Process frame by frame and collect raw flags
|
| 50 |
+
num_frames = len(audio_int16) // HOP_SIZE
|
| 51 |
+
|
| 52 |
+
# Use list for mutable flags (will be modified by post-processing)
|
| 53 |
+
is_voice = [0] * num_frames
|
| 54 |
+
|
| 55 |
+
for i in range(num_frames):
|
| 56 |
+
frame_start = i * HOP_SIZE
|
| 57 |
+
frame = audio_int16[frame_start:frame_start + HOP_SIZE]
|
| 58 |
+
|
| 59 |
+
result = vad.process(frame)
|
| 60 |
+
# TEN VAD returns tuple: (probability, flag) or has .flag attribute
|
| 61 |
+
if isinstance(result, tuple):
|
| 62 |
+
flag = result[1] # (probability, flag)
|
| 63 |
+
else:
|
| 64 |
+
flag = result.flag
|
| 65 |
+
is_voice[i] = flag
|
| 66 |
+
|
| 67 |
+
# Convert ms thresholds to frame counts
|
| 68 |
+
min_off_frames = int(min_off_ms / FRAME_MS + 0.1)
|
| 69 |
+
min_on_frames = int(min_on_ms / FRAME_MS + 0.1)
|
| 70 |
+
|
| 71 |
+
# Post-processing loop (matches VadPipeline.cpp logic)
|
| 72 |
+
while True:
|
| 73 |
+
# Pass 1: Fill in short silence gaps (minOff)
|
| 74 |
+
# If silence duration <= min_off_frames, convert to voice
|
| 75 |
+
if min_off_frames > 0:
|
| 76 |
+
start_off = -1
|
| 77 |
+
for i in range(num_frames):
|
| 78 |
+
if is_voice[i]: # Voice detected
|
| 79 |
+
if start_off >= 0 and (i - start_off) <= min_off_frames:
|
| 80 |
+
# Short silence gap - fill it in as voice
|
| 81 |
+
for j in range(start_off, i):
|
| 82 |
+
is_voice[j] = 1
|
| 83 |
+
start_off = -1
|
| 84 |
+
elif start_off < 0:
|
| 85 |
+
start_off = i
|
| 86 |
+
|
| 87 |
+
# Pass 2: Remove short voice bursts (minOn)
|
| 88 |
+
# If voice duration <= min_on_frames, convert to silence
|
| 89 |
+
changed = False
|
| 90 |
+
if min_on_frames > 0:
|
| 91 |
+
start_on = -1
|
| 92 |
+
for i in range(num_frames):
|
| 93 |
+
if not is_voice[i]: # Silence detected
|
| 94 |
+
if start_on >= 0 and (i - start_on) <= min_on_frames:
|
| 95 |
+
# Short voice burst - remove it
|
| 96 |
+
changed = True
|
| 97 |
+
for j in range(start_on, i):
|
| 98 |
+
is_voice[j] = 0
|
| 99 |
+
start_on = -1
|
| 100 |
+
elif start_on < 0:
|
| 101 |
+
start_on = i
|
| 102 |
+
|
| 103 |
+
# Handle case where audio ends with short voice burst
|
| 104 |
+
if start_on >= 0 and (num_frames - start_on) <= min_on_frames:
|
| 105 |
+
changed = True
|
| 106 |
+
for j in range(start_on, num_frames):
|
| 107 |
+
is_voice[j] = 0
|
| 108 |
+
|
| 109 |
+
# Exit loop if no changes or minOff is disabled
|
| 110 |
+
if not changed or min_off_frames == 0:
|
| 111 |
+
break
|
| 112 |
+
|
| 113 |
+
# Convert frame flags to silence periods
|
| 114 |
+
silence_periods = []
|
| 115 |
+
in_silence = False
|
| 116 |
+
silence_start = 0.0
|
| 117 |
+
|
| 118 |
+
for i in range(num_frames):
|
| 119 |
+
current_time = i * frame_duration
|
| 120 |
+
if is_voice[i]:
|
| 121 |
+
# Voice frame
|
| 122 |
+
if in_silence:
|
| 123 |
+
# End of silence period
|
| 124 |
+
silence_periods.append({
|
| 125 |
+
'start': round(silence_start, 3),
|
| 126 |
+
'end': round(current_time, 3)
|
| 127 |
+
})
|
| 128 |
+
in_silence = False
|
| 129 |
+
else:
|
| 130 |
+
# Silence frame
|
| 131 |
+
if not in_silence:
|
| 132 |
+
# Start of silence period
|
| 133 |
+
silence_start = current_time
|
| 134 |
+
in_silence = True
|
| 135 |
+
|
| 136 |
+
# Handle case where audio ends in silence
|
| 137 |
+
if in_silence:
|
| 138 |
+
silence_periods.append({
|
| 139 |
+
'start': round(silence_start, 3),
|
| 140 |
+
'end': round(num_frames * frame_duration, 3)
|
| 141 |
+
})
|
| 142 |
+
|
| 143 |
+
return silence_periods
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def print_speech_silence_log(timestamps_data, silence_periods):
|
| 147 |
+
"""Print interleaved speech and silence log sorted by start time."""
|
| 148 |
+
|
| 149 |
+
# Build unified list
|
| 150 |
+
entries = []
|
| 151 |
+
|
| 152 |
+
# Add speech entries (word timestamps)
|
| 153 |
+
for item in timestamps_data:
|
| 154 |
+
entries.append({
|
| 155 |
+
'type': 'speech',
|
| 156 |
+
'start': item['start'],
|
| 157 |
+
'end': item['end'],
|
| 158 |
+
'word': item['word']
|
| 159 |
+
})
|
| 160 |
+
|
| 161 |
+
# Add silence entries
|
| 162 |
+
for item in silence_periods:
|
| 163 |
+
entries.append({
|
| 164 |
+
'type': 'silence',
|
| 165 |
+
'start': item['start'],
|
| 166 |
+
'end': item['end']
|
| 167 |
+
})
|
| 168 |
+
|
| 169 |
+
# Sort by start time
|
| 170 |
+
entries.sort(key=lambda x: x['start'])
|
| 171 |
+
|
| 172 |
+
# Print log
|
| 173 |
+
print("\n=== SPEECH & SILENCE LOG ===")
|
| 174 |
+
for entry in entries:
|
| 175 |
+
if entry['type'] == 'speech':
|
| 176 |
+
print(f"[Speech] [{entry['start']:.3f}-{entry['end']:.3f}] {entry['word']}")
|
| 177 |
+
else:
|
| 178 |
+
duration_ms = int((entry['end'] - entry['start']) * 1000)
|
| 179 |
+
print(f"[Silence] [{entry['start']:.3f}-{entry['end']:.3f}] [{duration_ms}ms]")
|
| 180 |
+
|
| 181 |
+
# Calculate summary
|
| 182 |
+
total_silence = sum(p['end'] - p['start'] for p in silence_periods)
|
| 183 |
+
print(f"\n=== SUMMARY ===")
|
| 184 |
+
print(f"Words: {len(timestamps_data)}, Silence periods: {len(silence_periods)}, Total silence: {total_silence:.2f}s")
|
| 185 |
+
print("=" * 30 + "\n")
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def parse_transcript_file(file_path):
|
| 189 |
+
"""Parse a transcript JSON file and extract word timestamps.
|
| 190 |
+
|
| 191 |
+
Supports three formats:
|
| 192 |
+
- Format 1: segments[].words[] with {start, end, word}
|
| 193 |
+
- Format 2: Top-level words[] with {start, end, word}
|
| 194 |
+
- Format 3: segments[] with {start, end, text} (text treated as single word)
|
| 195 |
+
|
| 196 |
+
Args:
|
| 197 |
+
file_path: Path to the JSON transcript file
|
| 198 |
+
|
| 199 |
+
Returns:
|
| 200 |
+
Tuple of (full_text, timestamps_data) where timestamps_data is list of
|
| 201 |
+
{word, start, end} dicts
|
| 202 |
+
|
| 203 |
+
Raises:
|
| 204 |
+
ValueError if format not recognized
|
| 205 |
+
"""
|
| 206 |
+
with open(file_path, 'r', encoding='utf-8') as f:
|
| 207 |
+
data = json.load(f)
|
| 208 |
+
|
| 209 |
+
timestamps_data = []
|
| 210 |
+
full_text_parts = []
|
| 211 |
+
|
| 212 |
+
# Try Format 1: segments[].words[] with {start, end, word}
|
| 213 |
+
if 'segments' in data and len(data['segments']) > 0:
|
| 214 |
+
first_segment = data['segments'][0]
|
| 215 |
+
if 'words' in first_segment and isinstance(first_segment['words'], list):
|
| 216 |
+
# Format 1: Nested words inside segments
|
| 217 |
+
print("[IMPORT] Detected Format 1: segments[].words[]")
|
| 218 |
+
for segment in data['segments']:
|
| 219 |
+
for word_entry in segment.get('words', []):
|
| 220 |
+
word = word_entry.get('word', '').strip()
|
| 221 |
+
if word:
|
| 222 |
+
timestamps_data.append({
|
| 223 |
+
'word': word,
|
| 224 |
+
'start': float(word_entry.get('start', 0)),
|
| 225 |
+
'end': float(word_entry.get('end', 0))
|
| 226 |
+
})
|
| 227 |
+
full_text_parts.append(word)
|
| 228 |
+
return ' '.join(full_text_parts), timestamps_data
|
| 229 |
+
|
| 230 |
+
# Try Format 3: segments[] with {start, end, text} (text as word)
|
| 231 |
+
if 'text' in first_segment and 'start' in first_segment and 'end' in first_segment:
|
| 232 |
+
print("[IMPORT] Detected Format 3: segments[] with {start, end, text}")
|
| 233 |
+
for segment in data['segments']:
|
| 234 |
+
text = segment.get('text', '').strip()
|
| 235 |
+
if text:
|
| 236 |
+
timestamps_data.append({
|
| 237 |
+
'word': text,
|
| 238 |
+
'start': float(segment.get('start', 0)),
|
| 239 |
+
'end': float(segment.get('end', 0))
|
| 240 |
+
})
|
| 241 |
+
full_text_parts.append(text)
|
| 242 |
+
# Use top-level text if available, otherwise join segments
|
| 243 |
+
full_text = data.get('text', ' '.join(full_text_parts))
|
| 244 |
+
return full_text, timestamps_data
|
| 245 |
+
|
| 246 |
+
# Try Format 2: Top-level words[] with {start, end, word}
|
| 247 |
+
if 'words' in data and isinstance(data['words'], list):
|
| 248 |
+
print("[IMPORT] Detected Format 2: words[]")
|
| 249 |
+
for word_entry in data['words']:
|
| 250 |
+
word = word_entry.get('word', '').strip()
|
| 251 |
+
if word:
|
| 252 |
+
timestamps_data.append({
|
| 253 |
+
'word': word,
|
| 254 |
+
'start': float(word_entry.get('start', 0)),
|
| 255 |
+
'end': float(word_entry.get('end', 0))
|
| 256 |
+
})
|
| 257 |
+
full_text_parts.append(word)
|
| 258 |
+
# Use top-level text if available, otherwise join words
|
| 259 |
+
full_text = data.get('text', ' '.join(full_text_parts))
|
| 260 |
+
return full_text, timestamps_data
|
| 261 |
+
|
| 262 |
+
raise ValueError("Unrecognized transcript format. Expected segments[].words[], words[], or segments[] with {start, end, text}")
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
def load_transcript(audio, transcript_file, prob_threshold=0.5, min_off_ms=48, min_on_ms=64):
|
| 266 |
+
"""Load external transcript and run VAD on audio.
|
| 267 |
+
|
| 268 |
+
Args:
|
| 269 |
+
audio: Path to audio file
|
| 270 |
+
transcript_file: Path to JSON transcript file
|
| 271 |
+
prob_threshold: VAD probability threshold
|
| 272 |
+
min_off_ms: Minimum silence duration in ms
|
| 273 |
+
min_on_ms: Minimum voice duration in ms
|
| 274 |
+
|
| 275 |
+
Returns:
|
| 276 |
+
Tuple of (text, timestamps_data, audio_data_tuple, raw_text, export_metadata, silence_periods)
|
| 277 |
+
"""
|
| 278 |
+
try:
|
| 279 |
+
# Check if audio is provided
|
| 280 |
+
if audio is None:
|
| 281 |
+
return "No audio provided. Please upload audio first.", [], None, "", {}, []
|
| 282 |
+
|
| 283 |
+
# Check if transcript file is provided
|
| 284 |
+
if transcript_file is None:
|
| 285 |
+
return "No transcript file provided.", [], None, "", {}, []
|
| 286 |
+
|
| 287 |
+
# Parse the transcript file
|
| 288 |
+
try:
|
| 289 |
+
text, timestamps_data = parse_transcript_file(transcript_file)
|
| 290 |
+
print(f"[IMPORT] Loaded {len(timestamps_data)} word timestamps from transcript")
|
| 291 |
+
except Exception as e:
|
| 292 |
+
return f"Error parsing transcript file: {str(e)}", [], None, "", {}, []
|
| 293 |
+
|
| 294 |
+
# Preprocess audio: convert to mono if stereo
|
| 295 |
+
audio_data, sample_rate = sf.read(audio)
|
| 296 |
+
|
| 297 |
+
# Convert stereo to mono by averaging channels
|
| 298 |
+
if len(audio_data.shape) > 1 and audio_data.shape[1] == 2:
|
| 299 |
+
audio_data = np.mean(audio_data, axis=1)
|
| 300 |
+
|
| 301 |
+
# Resample to 16kHz if needed (required by TEN VAD)
|
| 302 |
+
TARGET_SR = 16000
|
| 303 |
+
if sample_rate != TARGET_SR:
|
| 304 |
+
duration = len(audio_data) / sample_rate
|
| 305 |
+
new_length = int(duration * TARGET_SR)
|
| 306 |
+
x_old = np.linspace(0, duration, len(audio_data), endpoint=False)
|
| 307 |
+
x_new = np.linspace(0, duration, new_length, endpoint=False)
|
| 308 |
+
audio_data = np.interp(x_new, x_old, audio_data).astype(np.float32)
|
| 309 |
+
print(f"[AUDIO] Resampled from {sample_rate}Hz to {TARGET_SR}Hz")
|
| 310 |
+
sample_rate = TARGET_SR
|
| 311 |
+
|
| 312 |
+
# Run VAD to detect silence periods
|
| 313 |
+
silence_periods = []
|
| 314 |
+
try:
|
| 315 |
+
silence_periods = detect_silence_periods(audio_data, sample_rate, prob_threshold, min_off_ms, min_on_ms)
|
| 316 |
+
print_speech_silence_log(timestamps_data, silence_periods)
|
| 317 |
+
except Exception as e:
|
| 318 |
+
print(f"[VAD] Error during silence detection: {str(e)}\n{traceback.format_exc()}")
|
| 319 |
+
|
| 320 |
+
# Calculate audio duration
|
| 321 |
+
audio_duration = len(audio_data) / sample_rate
|
| 322 |
+
|
| 323 |
+
# Build export metadata
|
| 324 |
+
export_metadata = {
|
| 325 |
+
'model': 'imported-transcript',
|
| 326 |
+
'audio_duration': round(audio_duration, 2),
|
| 327 |
+
'word_count': len(timestamps_data),
|
| 328 |
+
'token_count': 0,
|
| 329 |
+
'hypothesis_score': None,
|
| 330 |
+
'frame_duration': None
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
# Return text, timestamps, audio data, raw_text (same as text for imports), export metadata, and silence periods
|
| 334 |
+
return text, timestamps_data, (audio_data, sample_rate), text, export_metadata, silence_periods
|
| 335 |
+
|
| 336 |
+
except Exception as e:
|
| 337 |
+
return f"Error loading transcript: {str(e)}\n{traceback.format_exc()}", [], None, "", {}, []
|
| 338 |
+
|
| 339 |
+
|
| 340 |
+
def extract_audio_segment(audio_state, intervals, current_window=None):
|
| 341 |
+
"""Fast audio extraction from memory with waveform visualization.
|
| 342 |
+
|
| 343 |
+
Args:
|
| 344 |
+
audio_state: Tuple of (audio_data, sample_rate)
|
| 345 |
+
intervals: List of (start_time, end_time) tuples to play
|
| 346 |
+
current_window: Dict with 'start' and 'end' of current waveform window, or None
|
| 347 |
+
|
| 348 |
+
Returns:
|
| 349 |
+
Tuple of (html_output, new_window_state)
|
| 350 |
+
"""
|
| 351 |
+
# Wrapper to ensure controls never collapse
|
| 352 |
+
def wrap_output(content, window_state=None):
|
| 353 |
+
return f'<div style="min-height: 200px;">{content}</div>', window_state
|
| 354 |
+
|
| 355 |
+
try:
|
| 356 |
+
if audio_state is None:
|
| 357 |
+
return wrap_output("<p style='color: red; padding: 20px;'>No audio loaded. Please upload audio and load a transcript first.</p>")
|
| 358 |
+
|
| 359 |
+
if not intervals:
|
| 360 |
+
return wrap_output("<p style='color: red; padding: 20px;'>No intervals provided.</p>")
|
| 361 |
+
|
| 362 |
+
audio_data, sample_rate = audio_state
|
| 363 |
+
audio_duration = len(audio_data) / sample_rate
|
| 364 |
+
|
| 365 |
+
# Calculate overall bounds from all intervals
|
| 366 |
+
overall_start = min(iv[0] for iv in intervals)
|
| 367 |
+
overall_end = max(iv[1] for iv in intervals)
|
| 368 |
+
|
| 369 |
+
# Default context padding is 160ms
|
| 370 |
+
DEFAULT_PADDING = 0.16
|
| 371 |
+
|
| 372 |
+
# Determine if we need to redraw the waveform or just update the shaded area
|
| 373 |
+
need_redraw = True
|
| 374 |
+
if current_window is not None:
|
| 375 |
+
# Check if ALL intervals fit within the current window
|
| 376 |
+
if overall_start >= current_window['start'] and overall_end <= current_window['end']:
|
| 377 |
+
need_redraw = False
|
| 378 |
+
# Reuse the current window boundaries
|
| 379 |
+
padded_start = current_window['start']
|
| 380 |
+
padded_end = current_window['end']
|
| 381 |
+
|
| 382 |
+
if need_redraw:
|
| 383 |
+
# Calculate new window with ±160ms padding around overall bounds
|
| 384 |
+
padded_start = max(0, overall_start - DEFAULT_PADDING)
|
| 385 |
+
padded_end = min(audio_duration, overall_end + DEFAULT_PADDING)
|
| 386 |
+
|
| 387 |
+
# Extract padded segment for waveform visualization
|
| 388 |
+
start_sample_padded = int(padded_start * sample_rate)
|
| 389 |
+
end_sample_padded = int(padded_end * sample_rate)
|
| 390 |
+
segment_for_waveform = audio_data[start_sample_padded:end_sample_padded]
|
| 391 |
+
|
| 392 |
+
# Generate waveform visualization with padded segment (reduced height)
|
| 393 |
+
fig, ax = plt.subplots(figsize=(12, 2.25))
|
| 394 |
+
|
| 395 |
+
# Downsample for visualization using block averaging (more accurate than skipping)
|
| 396 |
+
max_points = 8000
|
| 397 |
+
if len(segment_for_waveform) > max_points:
|
| 398 |
+
# Reshape into blocks and take mean of each block
|
| 399 |
+
# Pad to multiple of block_size to avoid losing end samples
|
| 400 |
+
block_size = len(segment_for_waveform) // max_points
|
| 401 |
+
remainder = len(segment_for_waveform) % block_size
|
| 402 |
+
if remainder > 0:
|
| 403 |
+
# Pad with the last value to make it divisible
|
| 404 |
+
padding_needed = block_size - remainder
|
| 405 |
+
segment_padded = np.pad(segment_for_waveform, (0, padding_needed), mode='edge')
|
| 406 |
+
else:
|
| 407 |
+
segment_padded = segment_for_waveform
|
| 408 |
+
segment_vis = segment_padded.reshape(-1, block_size).mean(axis=1)
|
| 409 |
+
# Generate matching time points spanning the FULL padded range
|
| 410 |
+
times_vis = np.linspace(padded_start, padded_end, len(segment_vis))
|
| 411 |
+
else:
|
| 412 |
+
segment_vis = segment_for_waveform
|
| 413 |
+
times_vis = np.linspace(padded_start, padded_end, len(segment_for_waveform))
|
| 414 |
+
|
| 415 |
+
ax.plot(times_vis, segment_vis, linewidth=0.5, color='#666')
|
| 416 |
+
ax.fill_between(times_vis, segment_vis, alpha=0.3, color='#ccc')
|
| 417 |
+
|
| 418 |
+
# Highlight context areas (gray) - areas outside all playback regions
|
| 419 |
+
# First, shade the entire padded area as context
|
| 420 |
+
ax.axvspan(padded_start, padded_end, alpha=0.1, color='#888', label='Context (not played)')
|
| 421 |
+
|
| 422 |
+
# Then highlight each playback interval in green (overwrites context shading)
|
| 423 |
+
for i, (start_time, end_time) in enumerate(intervals):
|
| 424 |
+
label = 'Playback region' if i == 0 else None
|
| 425 |
+
ax.axvspan(start_time, end_time, alpha=0.3, color='#4CAF50', label=label)
|
| 426 |
+
|
| 427 |
+
ax.set_xlabel('Time (seconds)', fontsize=10)
|
| 428 |
+
ax.set_ylabel('Amplitude', fontsize=10)
|
| 429 |
+
|
| 430 |
+
# Calculate context on each side in ms
|
| 431 |
+
left_context_ms = int((overall_start - padded_start) * 1000)
|
| 432 |
+
right_context_ms = int((padded_end - overall_end) * 1000)
|
| 433 |
+
|
| 434 |
+
# Format context string - symmetric or asymmetric
|
| 435 |
+
if left_context_ms == right_context_ms:
|
| 436 |
+
context_str = f'(±{left_context_ms}ms context)'
|
| 437 |
+
else:
|
| 438 |
+
context_str = f'(-{left_context_ms}ms / +{right_context_ms}ms context)'
|
| 439 |
+
|
| 440 |
+
# Build title showing intervals
|
| 441 |
+
if len(intervals) == 1:
|
| 442 |
+
interval_str = f'{intervals[0][0]:.3f}s – {intervals[0][1]:.3f}s'
|
| 443 |
+
else:
|
| 444 |
+
interval_str = f'{len(intervals)} intervals: {overall_start:.3f}s – {overall_end:.3f}s'
|
| 445 |
+
|
| 446 |
+
ax.set_title(f'Audio Segment: {interval_str} {context_str}', fontsize=11)
|
| 447 |
+
ax.legend(fontsize=9)
|
| 448 |
+
ax.grid(True, alpha=0.3)
|
| 449 |
+
|
| 450 |
+
# Convert plot to base64 image
|
| 451 |
+
buf = io.BytesIO()
|
| 452 |
+
plt.tight_layout()
|
| 453 |
+
plt.savefig(buf, format='png', dpi=100)
|
| 454 |
+
buf.seek(0)
|
| 455 |
+
img_base64 = base64.b64encode(buf.read()).decode()
|
| 456 |
+
plt.close(fig)
|
| 457 |
+
|
| 458 |
+
# Extract and concatenate all interval segments for playback
|
| 459 |
+
audio_segments = []
|
| 460 |
+
SILENCE_GAP_MS = 50 # Gap between intervals in ms
|
| 461 |
+
silence_samples = int(SILENCE_GAP_MS / 1000 * sample_rate)
|
| 462 |
+
silence_gap = np.zeros(silence_samples, dtype=audio_data.dtype)
|
| 463 |
+
|
| 464 |
+
for i, (start_time, end_time) in enumerate(intervals):
|
| 465 |
+
start_sample = int(start_time * sample_rate)
|
| 466 |
+
end_sample = int(end_time * sample_rate)
|
| 467 |
+
audio_segments.append(audio_data[start_sample:end_sample])
|
| 468 |
+
# Add silence gap between intervals (not after the last one)
|
| 469 |
+
if i < len(intervals) - 1:
|
| 470 |
+
audio_segments.append(silence_gap)
|
| 471 |
+
|
| 472 |
+
combined_playback = np.concatenate(audio_segments)
|
| 473 |
+
|
| 474 |
+
# Convert PLAYBACK segments (concatenated) to base64 WAV
|
| 475 |
+
audio_buf = io.BytesIO()
|
| 476 |
+
sf.write(audio_buf, combined_playback, sample_rate, format='WAV')
|
| 477 |
+
audio_buf.seek(0)
|
| 478 |
+
audio_base64 = base64.b64encode(audio_buf.read()).decode()
|
| 479 |
+
audio_data_url = f"data:audio/wav;base64,{audio_base64}"
|
| 480 |
+
|
| 481 |
+
# Add unique ID to force Gradio to re-render (triggers autoplay)
|
| 482 |
+
unique_id = int(time.time() * 1000)
|
| 483 |
+
|
| 484 |
+
# Calculate context on each side in ms for the info text
|
| 485 |
+
left_context_ms = int((overall_start - padded_start) * 1000)
|
| 486 |
+
right_context_ms = int((padded_end - overall_end) * 1000)
|
| 487 |
+
|
| 488 |
+
# Format context string - symmetric or asymmetric
|
| 489 |
+
if left_context_ms == right_context_ms:
|
| 490 |
+
context_info = f'±{left_context_ms}ms'
|
| 491 |
+
else:
|
| 492 |
+
context_info = f'-{left_context_ms}ms / +{right_context_ms}ms'
|
| 493 |
+
|
| 494 |
+
# Calculate total playback duration
|
| 495 |
+
total_duration_ms = sum((end - start) * 1000 for start, end in intervals)
|
| 496 |
+
if len(intervals) > 1:
|
| 497 |
+
total_duration_ms += SILENCE_GAP_MS * (len(intervals) - 1) # Include gaps
|
| 498 |
+
|
| 499 |
+
# Build segment info text
|
| 500 |
+
if len(intervals) == 1:
|
| 501 |
+
segment_info = f'{intervals[0][0]:.3f}s – {intervals[0][1]:.3f}s'
|
| 502 |
+
else:
|
| 503 |
+
segment_info = f'{len(intervals)} intervals'
|
| 504 |
+
|
| 505 |
+
# Create HTML with waveform and native audio controls
|
| 506 |
+
html_output = f'''
|
| 507 |
+
<div style="margin: 10px 0;" data-render-id="{unique_id}">
|
| 508 |
+
<img src="data:image/png;base64,{img_base64}" style="width: 100%; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
| 509 |
+
|
| 510 |
+
<div style="margin-top: 10px; display: flex; align-items: center; gap: 15px;">
|
| 511 |
+
<audio id="segment-audio" controls autoplay style="flex: 1;">
|
| 512 |
+
<source src="{audio_data_url}" type="audio/wav">
|
| 513 |
+
</audio>
|
| 514 |
+
</div>
|
| 515 |
+
|
| 516 |
+
<div style="margin-top: 8px; text-align: center;">
|
| 517 |
+
<span style="font-size: 14px; font-weight: bold; color: #333;">
|
| 518 |
+
Segment: {segment_info}
|
| 519 |
+
</span>
|
| 520 |
+
<span style="font-size: 12px; color: #666; margin-left: 15px;">
|
| 521 |
+
Duration: {total_duration_ms:.0f}ms | Context shown: {context_info}
|
| 522 |
+
</span>
|
| 523 |
+
</div>
|
| 524 |
+
</div>
|
| 525 |
+
'''
|
| 526 |
+
|
| 527 |
+
# Return HTML and new window state
|
| 528 |
+
new_window = {'start': padded_start, 'end': padded_end}
|
| 529 |
+
return wrap_output(html_output, new_window)
|
| 530 |
+
|
| 531 |
+
except Exception as e:
|
| 532 |
+
return wrap_output(f"<pre style='padding: 20px;'>Error: {str(e)}\n{traceback.format_exc()}</pre>", current_window)
|
| 533 |
+
|
| 534 |
+
|
| 535 |
+
def build_timestamps_iframe_html(entries_json, export_json_str):
|
| 536 |
+
"""Build the interactive word timestamps iframe HTML.
|
| 537 |
+
|
| 538 |
+
Args:
|
| 539 |
+
entries_json: JSON string of word/silence entries
|
| 540 |
+
export_json_str: JSON string of full export data for download
|
| 541 |
+
|
| 542 |
+
Returns:
|
| 543 |
+
Complete iframe HTML for embedding in Gradio
|
| 544 |
+
"""
|
| 545 |
+
iframe_html = f'''
|
| 546 |
+
<!DOCTYPE html>
|
| 547 |
+
<html>
|
| 548 |
+
<head>
|
| 549 |
+
<style>
|
| 550 |
+
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
|
| 551 |
+
body {{ font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 10px; background: #f9f9f9; }}
|
| 552 |
+
h3 {{ margin-bottom: 8px; font-size: 16px; }}
|
| 553 |
+
.help {{ font-size: 11px; color: #666; margin-bottom: 10px; }}
|
| 554 |
+
.container {{ max-height: 180px; overflow-y: auto; background: #fff; border-radius: 8px; padding: 8px; border: 1px solid #ddd; }}
|
| 555 |
+
.word-btn {{
|
| 556 |
+
display: inline-block;
|
| 557 |
+
background: #e8f4f8;
|
| 558 |
+
padding: 5px 10px;
|
| 559 |
+
margin: 3px;
|
| 560 |
+
border-radius: 4px;
|
| 561 |
+
cursor: pointer;
|
| 562 |
+
border: 1px solid #cde;
|
| 563 |
+
font-size: 13px;
|
| 564 |
+
transition: all 0.15s;
|
| 565 |
+
}}
|
| 566 |
+
.word-btn:hover {{ background: #c5e5f5; }}
|
| 567 |
+
.word-btn.selected {{ background: #4CAF50; color: white; border-color: #3a9; }}
|
| 568 |
+
.silence-btn {{
|
| 569 |
+
display: inline-block;
|
| 570 |
+
background: #ffe4c4;
|
| 571 |
+
padding: 5px 8px;
|
| 572 |
+
margin: 3px;
|
| 573 |
+
border-radius: 4px;
|
| 574 |
+
cursor: pointer;
|
| 575 |
+
border: 1px solid #dca;
|
| 576 |
+
font-size: 11px;
|
| 577 |
+
transition: all 0.15s;
|
| 578 |
+
}}
|
| 579 |
+
.silence-btn:hover {{ background: #ffd4a4; }}
|
| 580 |
+
.silence-btn.selected {{ background: #ff9800; color: white; border-color: #e68a00; }}
|
| 581 |
+
.checkbox-container {{
|
| 582 |
+
display: inline-flex;
|
| 583 |
+
align-items: center;
|
| 584 |
+
margin-left: 15px;
|
| 585 |
+
font-size: 12px;
|
| 586 |
+
cursor: pointer;
|
| 587 |
+
}}
|
| 588 |
+
.checkbox-container input {{
|
| 589 |
+
margin-right: 5px;
|
| 590 |
+
cursor: pointer;
|
| 591 |
+
}}
|
| 592 |
+
.checkbox-container:hover {{
|
| 593 |
+
color: #0066cc;
|
| 594 |
+
}}
|
| 595 |
+
.time {{ color: #0066cc; font-size: 10px; font-weight: bold; }}
|
| 596 |
+
.silence-time {{ color: #996600; font-size: 10px; font-weight: bold; }}
|
| 597 |
+
.duration {{ color: #666; font-size: 10px; margin-left: 3px; }}
|
| 598 |
+
.word {{ margin-left: 4px; }}
|
| 599 |
+
</style>
|
| 600 |
+
</head>
|
| 601 |
+
<body>
|
| 602 |
+
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
| 603 |
+
<div style="display: flex; align-items: center;">
|
| 604 |
+
<h3 style="margin: 0;">Word Timestamps</h3>
|
| 605 |
+
<label class="checkbox-container" title="Extends word end times toward midpoint of gap to next word (max 120ms). Helps capture word endings that may be cut off.">
|
| 606 |
+
<input type="checkbox" id="adjust-intervals">
|
| 607 |
+
Apply Time Interval Adjustment
|
| 608 |
+
</label>
|
| 609 |
+
</div>
|
| 610 |
+
<a href="#" id="download-json" style="font-size: 12px; color: #0066cc; text-decoration: none;">📥 Download JSON</a>
|
| 611 |
+
</div>
|
| 612 |
+
<script>var exportJsonStr = {json.dumps(export_json_str)};</script>
|
| 613 |
+
<p class="help"><b>Click</b> = select | <b>Ctrl+Click</b> = toggle | <b>Shift+Click</b> = range <span style="background: #ffe4c4; padding: 2px 8px; border-radius: 3px; border: 1px solid #dca;"></span> = detected non speech</p>
|
| 614 |
+
<div class="container" id="words"></div>
|
| 615 |
+
<script>
|
| 616 |
+
var entries = {entries_json};
|
| 617 |
+
var container = document.getElementById('words');
|
| 618 |
+
|
| 619 |
+
// Merge consecutive silence periods (no word between them)
|
| 620 |
+
function mergeConsecutiveSilences(entryList) {{
|
| 621 |
+
var merged = [];
|
| 622 |
+
var pendingSilence = null;
|
| 623 |
+
|
| 624 |
+
entryList.forEach(function(entry) {{
|
| 625 |
+
if (entry.type === 'silence') {{
|
| 626 |
+
if (pendingSilence === null) {{
|
| 627 |
+
pendingSilence = {{ type: 'silence', start: entry.start, end: entry.end }};
|
| 628 |
+
}} else {{
|
| 629 |
+
pendingSilence.end = entry.end;
|
| 630 |
+
}}
|
| 631 |
+
}} else {{
|
| 632 |
+
if (pendingSilence !== null) {{
|
| 633 |
+
merged.push(pendingSilence);
|
| 634 |
+
pendingSilence = null;
|
| 635 |
+
}}
|
| 636 |
+
merged.push(entry);
|
| 637 |
+
}}
|
| 638 |
+
}});
|
| 639 |
+
|
| 640 |
+
if (pendingSilence !== null) {{
|
| 641 |
+
merged.push(pendingSilence);
|
| 642 |
+
}}
|
| 643 |
+
|
| 644 |
+
return merged;
|
| 645 |
+
}}
|
| 646 |
+
|
| 647 |
+
entries = mergeConsecutiveSilences(entries);
|
| 648 |
+
|
| 649 |
+
var words = entries.filter(function(e) {{ return e.type === 'word'; }});
|
| 650 |
+
var silences = entries.filter(function(e) {{ return e.type === 'silence'; }});
|
| 651 |
+
|
| 652 |
+
function calculateAdjustedEnd(wordIndex) {{
|
| 653 |
+
var word = words[wordIndex];
|
| 654 |
+
var nextWord = words[wordIndex + 1];
|
| 655 |
+
|
| 656 |
+
if (!nextWord) return word.end;
|
| 657 |
+
|
| 658 |
+
var gap = nextWord.start - word.end;
|
| 659 |
+
var extension = Math.min(gap / 2, 0.12);
|
| 660 |
+
|
| 661 |
+
return word.end + extension;
|
| 662 |
+
}}
|
| 663 |
+
|
| 664 |
+
var adjustedEnds = words.map(function(w, i) {{ return calculateAdjustedEnd(i); }});
|
| 665 |
+
|
| 666 |
+
var lastClickedIndex = -1;
|
| 667 |
+
|
| 668 |
+
function getAllButtons() {{
|
| 669 |
+
return Array.from(container.querySelectorAll('.word-btn, .silence-btn'));
|
| 670 |
+
}}
|
| 671 |
+
|
| 672 |
+
function handleItemClick(btn, e) {{
|
| 673 |
+
var allBtns = getAllButtons();
|
| 674 |
+
var clickedIndex = allBtns.indexOf(btn);
|
| 675 |
+
|
| 676 |
+
if (e.shiftKey && lastClickedIndex >= 0) {{
|
| 677 |
+
var start = Math.min(lastClickedIndex, clickedIndex);
|
| 678 |
+
var end = Math.max(lastClickedIndex, clickedIndex);
|
| 679 |
+
allBtns.forEach(function(b, i) {{
|
| 680 |
+
if (i >= start && i <= end) {{
|
| 681 |
+
b.classList.add('selected');
|
| 682 |
+
}}
|
| 683 |
+
}});
|
| 684 |
+
}} else if (e.ctrlKey) {{
|
| 685 |
+
btn.classList.toggle('selected');
|
| 686 |
+
}} else {{
|
| 687 |
+
allBtns.forEach(function(b) {{ b.classList.remove('selected'); }});
|
| 688 |
+
btn.classList.add('selected');
|
| 689 |
+
}}
|
| 690 |
+
|
| 691 |
+
lastClickedIndex = clickedIndex;
|
| 692 |
+
updateInterval();
|
| 693 |
+
}}
|
| 694 |
+
|
| 695 |
+
var wordIndex = 0;
|
| 696 |
+
entries.forEach(function(entry, i) {{
|
| 697 |
+
var btn = document.createElement('span');
|
| 698 |
+
|
| 699 |
+
if (entry.type === 'word') {{
|
| 700 |
+
var wi = wordIndex;
|
| 701 |
+
btn.className = 'word-btn';
|
| 702 |
+
btn.dataset.origS = entry.start;
|
| 703 |
+
btn.dataset.origE = entry.end;
|
| 704 |
+
btn.dataset.adjE = adjustedEnds[wi];
|
| 705 |
+
btn.dataset.s = entry.start;
|
| 706 |
+
btn.dataset.e = entry.end;
|
| 707 |
+
btn.dataset.word = entry.word;
|
| 708 |
+
btn.innerHTML = '<span class="time">[' + entry.start.toFixed(3) + '-' + entry.end.toFixed(3) + 's]</span><span class="word"> ' + entry.word + '</span>';
|
| 709 |
+
|
| 710 |
+
btn.onclick = function(e) {{ handleItemClick(this, e); }};
|
| 711 |
+
wordIndex++;
|
| 712 |
+
}} else {{
|
| 713 |
+
btn.className = 'silence-btn';
|
| 714 |
+
btn.dataset.s = entry.start;
|
| 715 |
+
btn.dataset.e = entry.end;
|
| 716 |
+
var durationMs = Math.round((entry.end - entry.start) * 1000);
|
| 717 |
+
btn.innerHTML = '<span class="silence-time">[' + entry.start.toFixed(3) + '-' + entry.end.toFixed(3) + 's]</span><span class="duration">' + durationMs + 'ms</span>';
|
| 718 |
+
btn.onclick = function(e) {{ handleItemClick(this, e); }};
|
| 719 |
+
}}
|
| 720 |
+
|
| 721 |
+
container.appendChild(btn);
|
| 722 |
+
|
| 723 |
+
// Add vertical space after sentence-ending punctuation
|
| 724 |
+
if (entry.type === 'word') {{
|
| 725 |
+
var lastChar = entry.word.slice(-1);
|
| 726 |
+
if (lastChar === '.' || lastChar === '!' || lastChar === '?') {{
|
| 727 |
+
var spacer = document.createElement('div');
|
| 728 |
+
spacer.style.height = '15px';
|
| 729 |
+
container.appendChild(spacer);
|
| 730 |
+
}}
|
| 731 |
+
}}
|
| 732 |
+
}});
|
| 733 |
+
|
| 734 |
+
function updateWordLabels() {{
|
| 735 |
+
var adjusted = document.getElementById('adjust-intervals').checked;
|
| 736 |
+
document.querySelectorAll('.word-btn').forEach(function(btn) {{
|
| 737 |
+
var s = parseFloat(btn.dataset.origS);
|
| 738 |
+
var e = adjusted ? parseFloat(btn.dataset.adjE) : parseFloat(btn.dataset.origE);
|
| 739 |
+
btn.dataset.s = s;
|
| 740 |
+
btn.dataset.e = e;
|
| 741 |
+
btn.innerHTML = '<span class="time">[' + s.toFixed(3) + '-' + e.toFixed(3) + 's]</span><span class="word"> ' + btn.dataset.word + '</span>';
|
| 742 |
+
}});
|
| 743 |
+
updateInterval();
|
| 744 |
+
}}
|
| 745 |
+
|
| 746 |
+
document.getElementById('adjust-intervals').addEventListener('change', updateWordLabels);
|
| 747 |
+
|
| 748 |
+
function updateInterval() {{
|
| 749 |
+
var sel = Array.from(document.querySelectorAll('.word-btn.selected, .silence-btn.selected'));
|
| 750 |
+
if (sel.length === 0) return;
|
| 751 |
+
|
| 752 |
+
// Sort selected items by start time
|
| 753 |
+
sel.sort(function(a, b) {{
|
| 754 |
+
return parseFloat(a.dataset.s) - parseFloat(b.dataset.s);
|
| 755 |
+
}});
|
| 756 |
+
|
| 757 |
+
// Group into contiguous intervals based on DOM adjacency
|
| 758 |
+
var allBtns = getAllButtons();
|
| 759 |
+
var intervals = [];
|
| 760 |
+
var currentStart = null;
|
| 761 |
+
var currentEnd = null;
|
| 762 |
+
var lastIndex = -2;
|
| 763 |
+
|
| 764 |
+
sel.forEach(function(btn) {{
|
| 765 |
+
var idx = allBtns.indexOf(btn);
|
| 766 |
+
var s = parseFloat(btn.dataset.s);
|
| 767 |
+
var e = parseFloat(btn.dataset.e);
|
| 768 |
+
|
| 769 |
+
if (currentStart === null) {{
|
| 770 |
+
// First item
|
| 771 |
+
currentStart = s;
|
| 772 |
+
currentEnd = e;
|
| 773 |
+
lastIndex = idx;
|
| 774 |
+
}} else if (idx === lastIndex + 1) {{
|
| 775 |
+
// Adjacent item - extend current interval
|
| 776 |
+
currentEnd = e;
|
| 777 |
+
lastIndex = idx;
|
| 778 |
+
}} else {{
|
| 779 |
+
// Non-adjacent - save current interval, start new one
|
| 780 |
+
intervals.push(currentStart.toFixed(3) + '-' + currentEnd.toFixed(3));
|
| 781 |
+
currentStart = s;
|
| 782 |
+
currentEnd = e;
|
| 783 |
+
lastIndex = idx;
|
| 784 |
+
}}
|
| 785 |
+
}});
|
| 786 |
+
|
| 787 |
+
// Don't forget the last interval
|
| 788 |
+
if (currentStart !== null) {{
|
| 789 |
+
intervals.push(currentStart.toFixed(3) + '-' + currentEnd.toFixed(3));
|
| 790 |
+
}}
|
| 791 |
+
|
| 792 |
+
var intervalStr = intervals.join(' , ');
|
| 793 |
+
try {{
|
| 794 |
+
var boxes = parent.document.querySelectorAll('input[data-testid="textbox"], textarea');
|
| 795 |
+
boxes.forEach(function(box) {{
|
| 796 |
+
if (box.placeholder && box.placeholder.indexOf('start-end') !== -1) {{
|
| 797 |
+
box.value = intervalStr;
|
| 798 |
+
box.dispatchEvent(new Event('input', {{bubbles: true}}));
|
| 799 |
+
}}
|
| 800 |
+
}});
|
| 801 |
+
}} catch(err) {{ console.log('Could not update parent:', err); }}
|
| 802 |
+
}}
|
| 803 |
+
|
| 804 |
+
function highlightFromInterval(intervalStr) {{
|
| 805 |
+
if (!intervalStr) return;
|
| 806 |
+
|
| 807 |
+
// Parse multiple intervals separated by commas
|
| 808 |
+
var intervalParts = intervalStr.split(',');
|
| 809 |
+
var intervals = [];
|
| 810 |
+
|
| 811 |
+
intervalParts.forEach(function(part) {{
|
| 812 |
+
part = part.trim();
|
| 813 |
+
var match = part.match(/^([\d.]+)\s*-\s*([\d.]+)$/);
|
| 814 |
+
if (match) {{
|
| 815 |
+
var s = parseFloat(match[1]);
|
| 816 |
+
var e = parseFloat(match[2]);
|
| 817 |
+
if (!isNaN(s) && !isNaN(e)) {{
|
| 818 |
+
intervals.push({{start: s, end: e}});
|
| 819 |
+
}}
|
| 820 |
+
}}
|
| 821 |
+
}});
|
| 822 |
+
|
| 823 |
+
if (intervals.length === 0) return;
|
| 824 |
+
|
| 825 |
+
document.querySelectorAll('.word-btn').forEach(function(btn) {{
|
| 826 |
+
var ws = parseFloat(btn.dataset.s);
|
| 827 |
+
var we = parseFloat(btn.dataset.e);
|
| 828 |
+
var itemDuration = we - ws;
|
| 829 |
+
var isSelected = false;
|
| 830 |
+
|
| 831 |
+
// Check if this word overlaps with any interval
|
| 832 |
+
intervals.forEach(function(iv) {{
|
| 833 |
+
var overlapStart = Math.max(ws, iv.start);
|
| 834 |
+
var overlapEnd = Math.min(we, iv.end);
|
| 835 |
+
var overlap = Math.max(0, overlapEnd - overlapStart);
|
| 836 |
+
if (itemDuration > 0 && (overlap / itemDuration) > 0.5) {{
|
| 837 |
+
isSelected = true;
|
| 838 |
+
}}
|
| 839 |
+
}});
|
| 840 |
+
|
| 841 |
+
if (isSelected) {{
|
| 842 |
+
btn.classList.add('selected');
|
| 843 |
+
}} else {{
|
| 844 |
+
btn.classList.remove('selected');
|
| 845 |
+
}}
|
| 846 |
+
}});
|
| 847 |
+
}}
|
| 848 |
+
|
| 849 |
+
function setupParentWatcher() {{
|
| 850 |
+
try {{
|
| 851 |
+
var boxes = parent.document.querySelectorAll('input[data-testid="textbox"], textarea');
|
| 852 |
+
boxes.forEach(function(box) {{
|
| 853 |
+
if (box.placeholder && box.placeholder.indexOf('start-end') !== -1) {{
|
| 854 |
+
box.addEventListener('blur', function() {{
|
| 855 |
+
highlightFromInterval(this.value);
|
| 856 |
+
}});
|
| 857 |
+
box.addEventListener('keydown', function(e) {{
|
| 858 |
+
if (e.key === 'Enter') {{
|
| 859 |
+
highlightFromInterval(this.value);
|
| 860 |
+
}}
|
| 861 |
+
}});
|
| 862 |
+
}}
|
| 863 |
+
}});
|
| 864 |
+
}} catch(err) {{ console.log('Could not setup parent watcher:', err); }}
|
| 865 |
+
}}
|
| 866 |
+
|
| 867 |
+
setTimeout(setupParentWatcher, 500);
|
| 868 |
+
|
| 869 |
+
document.getElementById('download-json').onclick = function(e) {{
|
| 870 |
+
e.preventDefault();
|
| 871 |
+
var dataUrl = 'data:application/json;charset=utf-8,' + encodeURIComponent(exportJsonStr);
|
| 872 |
+
var a = document.createElement('a');
|
| 873 |
+
a.href = dataUrl;
|
| 874 |
+
a.download = 'transcript.json';
|
| 875 |
+
document.body.appendChild(a);
|
| 876 |
+
a.click();
|
| 877 |
+
document.body.removeChild(a);
|
| 878 |
+
return false;
|
| 879 |
+
}};
|
| 880 |
+
</script>
|
| 881 |
+
</body>
|
| 882 |
+
</html>
|
| 883 |
+
'''
|
| 884 |
+
iframe_srcdoc = iframe_html.replace('"', '"')
|
| 885 |
+
return f'''
|
| 886 |
+
<iframe srcdoc="{iframe_srcdoc}" style="width: 100%; height: 250px; border: none; border-radius: 8px;"></iframe>
|
| 887 |
+
'''
|
| 888 |
+
|
| 889 |
+
|
| 890 |
+
with gr.Blocks() as demo:
|
| 891 |
+
gr.Markdown(
|
| 892 |
+
"""# Timestamps Tester"""
|
| 893 |
+
)
|
| 894 |
+
gr.Markdown(
|
| 895 |
+
"""Testing word timestamps from any transcript. Upload audio and a transcript JSON in one of the supported formats. See [examples of supported formats here](https://drive.google.com/drive/folders/1qrjfHjfssAZQIvSLJi36rLjpuqw3eOjj)."""
|
| 896 |
+
)
|
| 897 |
+
|
| 898 |
+
# State to store audio data in memory for fast extraction
|
| 899 |
+
audio_state = gr.State()
|
| 900 |
+
timestamps_state = gr.State([]) # Store timestamps for dropdown
|
| 901 |
+
|
| 902 |
+
audio_input = gr.Audio(
|
| 903 |
+
type="filepath",
|
| 904 |
+
label="Upload or record your audio",
|
| 905 |
+
sources=["upload", "microphone"],
|
| 906 |
+
format="wav"
|
| 907 |
+
)
|
| 908 |
+
|
| 909 |
+
# VAD Controls - inline labels with number inputs
|
| 910 |
+
with gr.Row():
|
| 911 |
+
gr.Markdown("**VAD: Probability Threshold**")
|
| 912 |
+
vad_prob_threshold = gr.Number(
|
| 913 |
+
show_label=False,
|
| 914 |
+
value=0.5,
|
| 915 |
+
minimum=0.0,
|
| 916 |
+
maximum=1.0,
|
| 917 |
+
step=0.05,
|
| 918 |
+
scale=0,
|
| 919 |
+
min_width=80
|
| 920 |
+
)
|
| 921 |
+
gr.Markdown("**Min Voice Off (ms)**")
|
| 922 |
+
vad_min_off = gr.Number(
|
| 923 |
+
show_label=False,
|
| 924 |
+
value=48,
|
| 925 |
+
minimum=16,
|
| 926 |
+
maximum=1000,
|
| 927 |
+
step=16,
|
| 928 |
+
scale=0,
|
| 929 |
+
min_width=80
|
| 930 |
+
)
|
| 931 |
+
gr.Markdown("**Min Voice On (ms)**")
|
| 932 |
+
vad_min_on = gr.Number(
|
| 933 |
+
show_label=False,
|
| 934 |
+
value=64,
|
| 935 |
+
minimum=16,
|
| 936 |
+
maximum=1000,
|
| 937 |
+
step=16,
|
| 938 |
+
scale=0,
|
| 939 |
+
min_width=80
|
| 940 |
+
)
|
| 941 |
+
|
| 942 |
+
transcript_file_input = gr.File(
|
| 943 |
+
label="Load Transcript (JSON)",
|
| 944 |
+
file_types=[".json"]
|
| 945 |
+
)
|
| 946 |
+
|
| 947 |
+
transcription_output = gr.Textbox(label="Transcription", lines=5)
|
| 948 |
+
|
| 949 |
+
timestamps_output = gr.HTML(label="Word Timestamps")
|
| 950 |
+
|
| 951 |
+
# Time interval input - directly under timestamps (single row, no label)
|
| 952 |
+
with gr.Row():
|
| 953 |
+
time_input = gr.Textbox(
|
| 954 |
+
label="",
|
| 955 |
+
show_label=False,
|
| 956 |
+
container=False,
|
| 957 |
+
placeholder="Time interval(s): start-end (e.g., 0.56-1.20 or 0.5-1.2 , 3.0-4.5)",
|
| 958 |
+
scale=3,
|
| 959 |
+
elem_id="time-interval-box"
|
| 960 |
+
)
|
| 961 |
+
play_interval_button = gr.Button("▶ Play Interval", scale=1)
|
| 962 |
+
|
| 963 |
+
# Track last played interval for smart replay
|
| 964 |
+
last_interval_state = gr.State("")
|
| 965 |
+
|
| 966 |
+
# Track current waveform window boundaries for smart redraw
|
| 967 |
+
waveform_window_state = gr.State(None)
|
| 968 |
+
|
| 969 |
+
# Waveform player - below interval controls
|
| 970 |
+
waveform_player = gr.HTML(label="Segment Player")
|
| 971 |
+
|
| 972 |
+
def load_transcript_and_setup(audio, transcript_file, prob_threshold, min_off_ms, min_on_ms):
|
| 973 |
+
"""Load external transcript and setup UI."""
|
| 974 |
+
if transcript_file is None:
|
| 975 |
+
# Return empty/unchanged outputs if no file selected
|
| 976 |
+
return gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
|
| 977 |
+
|
| 978 |
+
text, timestamps_data, audio_data, raw_text, export_metadata, silence_periods = load_transcript(
|
| 979 |
+
audio, transcript_file, prob_threshold, int(min_off_ms), int(min_on_ms)
|
| 980 |
+
)
|
| 981 |
+
|
| 982 |
+
# Check for errors
|
| 983 |
+
if audio_data is None:
|
| 984 |
+
# Error case - text contains error message
|
| 985 |
+
return text, "", None, [], gr.update()
|
| 986 |
+
|
| 987 |
+
# Build combined entries (words + silence) sorted by start time
|
| 988 |
+
entries = []
|
| 989 |
+
for item in timestamps_data:
|
| 990 |
+
entries.append({
|
| 991 |
+
'type': 'word',
|
| 992 |
+
'word': item['word'],
|
| 993 |
+
'start': round(item['start'], 3),
|
| 994 |
+
'end': round(item['end'], 3)
|
| 995 |
+
})
|
| 996 |
+
for item in silence_periods:
|
| 997 |
+
entries.append({
|
| 998 |
+
'type': 'silence',
|
| 999 |
+
'start': round(item['start'], 3),
|
| 1000 |
+
'end': round(item['end'], 3)
|
| 1001 |
+
})
|
| 1002 |
+
entries.sort(key=lambda x: x['start'])
|
| 1003 |
+
entries_json = json.dumps(entries)
|
| 1004 |
+
|
| 1005 |
+
# Build word data as JSON for the iframe
|
| 1006 |
+
words_json = json.dumps([{
|
| 1007 |
+
'word': item['word'],
|
| 1008 |
+
'start': round(item['start'], 3),
|
| 1009 |
+
'end': round(item['end'], 3)
|
| 1010 |
+
} for item in timestamps_data])
|
| 1011 |
+
|
| 1012 |
+
# Pre-generate full export JSON
|
| 1013 |
+
segments = [{
|
| 1014 |
+
'word': item['word'],
|
| 1015 |
+
'start': round(item['start'], 3),
|
| 1016 |
+
'end': round(item['end'], 3),
|
| 1017 |
+
'word_index': i
|
| 1018 |
+
} for i, item in enumerate(timestamps_data)]
|
| 1019 |
+
|
| 1020 |
+
export_data = {
|
| 1021 |
+
'metadata': export_metadata,
|
| 1022 |
+
'text': text,
|
| 1023 |
+
'raw_text': raw_text,
|
| 1024 |
+
'segments': segments
|
| 1025 |
+
}
|
| 1026 |
+
export_json_str = json.dumps(export_data, ensure_ascii=False, indent=2)
|
| 1027 |
+
|
| 1028 |
+
# Build iframe HTML using helper function
|
| 1029 |
+
timestamps_html = build_timestamps_iframe_html(entries_json, export_json_str)
|
| 1030 |
+
|
| 1031 |
+
initial_player = '''
|
| 1032 |
+
<div style="padding: 20px; text-align: center; background: #f5f5f5; border-radius: 8px; color: #666;">
|
| 1033 |
+
<p>Select words above and click <b>▶ Play Interval</b> to hear the segment</p>
|
| 1034 |
+
</div>
|
| 1035 |
+
'''
|
| 1036 |
+
|
| 1037 |
+
return text, timestamps_html, audio_data, timestamps_data, initial_player
|
| 1038 |
+
|
| 1039 |
+
def play_time_interval_fast(audio_state, time_interval, last_interval, current_window):
|
| 1040 |
+
"""Fast extraction using preloaded audio from memory. Supports multiple intervals."""
|
| 1041 |
+
def wrap_error(msg):
|
| 1042 |
+
return f'<div style="min-height: 150px; padding: 20px; text-align: center; background: #f5f5f5; border-radius: 8px;"><p style="color: #666;">{msg}</p></div>', last_interval, current_window
|
| 1043 |
+
|
| 1044 |
+
try:
|
| 1045 |
+
if not time_interval or not audio_state:
|
| 1046 |
+
return wrap_error("No interval or audio loaded. Select words and try again.")
|
| 1047 |
+
|
| 1048 |
+
# Parse multiple intervals separated by commas
|
| 1049 |
+
# Format: "0.000-2.224 , 4.752-5.696 , 7.216-7.856"
|
| 1050 |
+
intervals = []
|
| 1051 |
+
interval_parts = time_interval.split(',')
|
| 1052 |
+
|
| 1053 |
+
for part in interval_parts:
|
| 1054 |
+
part = part.strip()
|
| 1055 |
+
if '-' in part:
|
| 1056 |
+
times = part.split('-')
|
| 1057 |
+
if len(times) == 2:
|
| 1058 |
+
try:
|
| 1059 |
+
start_time = float(times[0].strip())
|
| 1060 |
+
end_time = float(times[1].strip())
|
| 1061 |
+
if start_time < end_time:
|
| 1062 |
+
intervals.append((start_time, end_time))
|
| 1063 |
+
except ValueError:
|
| 1064 |
+
pass
|
| 1065 |
+
|
| 1066 |
+
if not intervals:
|
| 1067 |
+
return wrap_error("Invalid interval format. Use: start-end (e.g., 1.20-2.50) or multiple: 0.5-1.0 , 2.0-3.0")
|
| 1068 |
+
|
| 1069 |
+
# Load/reload audio segment (autoplay will replay even if same interval)
|
| 1070 |
+
# Pass current window state for smart redraw logic
|
| 1071 |
+
result_html, new_window = extract_audio_segment(audio_state, intervals, current_window)
|
| 1072 |
+
return result_html, time_interval, new_window
|
| 1073 |
+
|
| 1074 |
+
except Exception as e:
|
| 1075 |
+
return wrap_error(f"Error: {str(e)}")
|
| 1076 |
+
|
| 1077 |
+
# Load transcript file input
|
| 1078 |
+
transcript_file_input.change(
|
| 1079 |
+
fn=load_transcript_and_setup,
|
| 1080 |
+
inputs=[audio_input, transcript_file_input, vad_prob_threshold, vad_min_off, vad_min_on],
|
| 1081 |
+
outputs=[transcription_output, timestamps_output, audio_state, timestamps_state, waveform_player]
|
| 1082 |
+
)
|
| 1083 |
+
|
| 1084 |
+
# Play interval button
|
| 1085 |
+
play_interval_button.click(
|
| 1086 |
+
fn=play_time_interval_fast,
|
| 1087 |
+
inputs=[audio_state, time_input, last_interval_state, waveform_window_state],
|
| 1088 |
+
outputs=[waveform_player, last_interval_state, waveform_window_state]
|
| 1089 |
+
)
|
| 1090 |
+
|
| 1091 |
demo.launch()
|
packages.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ffmpeg
|
| 2 |
+
libc++1
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
soundfile
|
| 2 |
+
matplotlib
|
| 3 |
+
ten-vad
|
runtime.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
python-3.12
|
transcription_format_1.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"segments":[{"id":1,"seek":2470,"start":0.92,"end":5.86,"text":" With Canvid, every recording becomes smarter and easier to work with.","tokens":[50364,2022,1664,6833,11,633,6613,3643,20294,293,3571,281,589,365,13,50636],"temperature":0,"avg_logprob":-0.17021649568638902,"compression_ratio":1.6085271317829457,"no_speech_prob":0.37931445240974426,"words":[{"start":0.92,"end":1.76,"word":" With","probability":0.7823007702827454},{"start":1.76,"end":2.22,"word":" Canvid,","probability":0.7138348519802094},{"start":2.58,"end":2.94,"word":" every","probability":0.9812575578689575},{"start":2.94,"end":3.42,"word":" recording","probability":0.9973837733268738},{"start":3.42,"end":3.82,"word":" becomes","probability":0.9680418372154236},{"start":3.82,"end":4.32,"word":" smarter","probability":0.9817298650741577},{"start":4.32,"end":4.66,"word":" and","probability":0.9885828495025635},{"start":4.66,"end":5.08,"word":" easier","probability":0.9871406555175781},{"start":5.08,"end":5.42,"word":" to","probability":0.9985585808753967},{"start":5.42,"end":5.62,"word":" work","probability":0.9991933703422546},{"start":5.62,"end":5.86,"word":" with.","probability":0.9975357055664062}]},{"id":2,"seek":2470,"start":6.22,"end":10.62,"text":" It automatically generates a full transcript of your video, complete with time-accurate","tokens":[50636,467,6772,23815,257,1577,24444,295,428,960,11,3566,365,565,12,8476,33144,50852],"temperature":0,"avg_logprob":-0.17021649568638902,"compression_ratio":1.6085271317829457,"no_speech_prob":0.37931445240974426,"words":[{"start":6.22,"end":6.38,"word":" It","probability":0.985668420791626},{"start":6.38,"end":6.9,"word":" automatically","probability":0.9961374402046204},{"start":6.9,"end":7.6,"word":" generates","probability":0.992417573928833},{"start":7.6,"end":7.8,"word":" a","probability":0.9854802489280701},{"start":7.8,"end":7.96,"word":" full","probability":0.9979129433631897},{"start":7.96,"end":8.36,"word":" transcript","probability":0.9969101548194885},{"start":8.36,"end":8.7,"word":" of","probability":0.9967479705810547},{"start":8.7,"end":8.84,"word":" your","probability":0.992317795753479},{"start":8.84,"end":9.2,"word":" video,","probability":0.9946815371513367},{"start":9.32,"end":9.66,"word":" complete","probability":0.9576844573020935},{"start":9.66,"end":9.86,"word":" with","probability":0.9958441853523254},{"start":9.86,"end":10.18,"word":" time","probability":0.8104842305183411},{"start":10.18,"end":10.62,"word":"-accurate","probability":0.8353971242904663}]},{"id":3,"seek":2470,"start":10.62,"end":11.56,"text":" word timestamps.","tokens":[50852,1349,49108,23150,13,50930],"temperature":0,"avg_logprob":-0.17021649568638902,"compression_ratio":1.6085271317829457,"no_speech_prob":0.37931445240974426,"words":[{"start":10.62,"end":10.92,"word":" word","probability":0.7148622870445251},{"start":10.92,"end":11.56,"word":" timestamps.","probability":0.8938511908054352}]},{"id":4,"seek":2470,"start":12.14,"end":16.98,"text":" You can simply click any word to jump straight into that exact moment, perfect for precise","tokens":[50930,509,393,2935,2052,604,1349,281,3012,2997,666,300,1900,1623,11,2176,337,13600,51178],"temperature":0,"avg_logprob":-0.17021649568638902,"compression_ratio":1.6085271317829457,"no_speech_prob":0.37931445240974426,"words":[{"start":12.14,"end":12.24,"word":" You","probability":0.9906122088432312},{"start":12.24,"end":12.36,"word":" can","probability":0.9973468780517578},{"start":12.36,"end":12.66,"word":" simply","probability":0.9944220185279846},{"start":12.66,"end":12.92,"word":" click","probability":0.9955753087997437},{"start":12.92,"end":13.26,"word":" any","probability":0.9569084644317627},{"start":13.26,"end":13.56,"word":" word","probability":0.9966071844100952},{"start":13.56,"end":13.72,"word":" to","probability":0.993604838848114},{"start":13.72,"end":13.94,"word":" jump","probability":0.9978285431861877},{"start":13.94,"end":14.3,"word":" straight","probability":0.9646062850952148},{"start":14.3,"end":14.54,"word":" into","probability":0.990403413772583},{"start":14.54,"end":14.8,"word":" that","probability":0.984435498714447},{"start":14.8,"end":15.08,"word":" exact","probability":0.9961676001548767},{"start":15.08,"end":15.46,"word":" moment,","probability":0.9979813694953918},{"start":15.9,"end":16.26,"word":" perfect","probability":0.9824923276901245},{"start":16.26,"end":16.54,"word":" for","probability":0.9983140230178833},{"start":16.54,"end":16.98,"word":" precise","probability":0.996726393699646}]},{"id":5,"seek":2470,"start":16.98,"end":18.72,"text":" edits and effortless navigation.","tokens":[51178,41752,293,4630,1832,17346,13,51298],"temperature":0,"avg_logprob":-0.17021649568638902,"compression_ratio":1.6085271317829457,"no_speech_prob":0.37931445240974426,"words":[{"start":16.98,"end":17.48,"word":" edits","probability":0.9982725381851196},{"start":17.48,"end":17.7,"word":" and","probability":0.9857107996940613},{"start":17.7,"end":18.22,"word":" effortless","probability":0.9974649846553802},{"start":18.22,"end":18.72,"word":" navigation.","probability":0.9965900182723999}]},{"id":6,"seek":2470,"start":19.44,"end":24.34,"text":" Canvid's noise cancellation cleans up your audio by removing background noise and enhancing","tokens":[51298,1664,6833,311,5658,45867,16912,493,428,6278,538,12720,3678,5658,293,36579,51540],"temperature":0,"avg_logprob":-0.17021649568638902,"compression_ratio":1.6085271317829457,"no_speech_prob":0.37931445240974426,"words":[{"start":19.44,"end":20.08,"word":" Canvid's","probability":0.9171913067499796},{"start":20.08,"end":20.22,"word":" noise","probability":0.7357814311981201},{"start":20.22,"end":20.94,"word":" cancellation","probability":0.9655009508132935},{"start":20.94,"end":21.32,"word":" cleans","probability":0.9885962605476379},{"start":21.32,"end":21.52,"word":" up","probability":0.9915648698806763},{"start":21.52,"end":21.64,"word":" your","probability":0.9975951313972473},{"start":21.64,"end":22,"word":" audio","probability":0.9179521799087524},{"start":22,"end":22.22,"word":" by","probability":0.9946245551109314},{"start":22.22,"end":22.58,"word":" removing","probability":0.9975009560585022},{"start":22.58,"end":23.02,"word":" background","probability":0.99535071849823},{"start":23.02,"end":23.48,"word":" noise","probability":0.9975759387016296},{"start":23.48,"end":23.96,"word":" and","probability":0.946117639541626},{"start":23.96,"end":24.34,"word":" enhancing","probability":0.9908022284507751}]},{"id":7,"seek":2470,"start":24.34,"end":25.62,"text":" your voice in real time.","tokens":[51540,428,3177,294,957,565,13,51640],"temperature":0,"avg_logprob":-0.17021649568638902,"compression_ratio":1.6085271317829457,"no_speech_prob":0.37931445240974426,"words":[{"start":24.34,"end":24.56,"word":" your","probability":0.9974861145019531},{"start":24.56,"end":24.84,"word":" voice","probability":0.9988904595375061},{"start":24.84,"end":25.06,"word":" in","probability":0.9953886270523071},{"start":25.06,"end":25.28,"word":" real","probability":0.9973974227905273},{"start":25.28,"end":25.62,"word":" time.","probability":0.537711501121521}]},{"id":8,"seek":5468,"start":26.14,"end":31.06,"text":" You can also use AI background blur or full background removal to stay focused and fully","tokens":[50402,509,393,611,764,7318,3678,14257,420,1577,3678,17933,281,1754,5178,293,4498,50638],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":26.14,"end":26.44,"word":" You","probability":0.5414830446243286},{"start":26.44,"end":26.62,"word":" can","probability":0.9829677939414978},{"start":26.62,"end":26.84,"word":" also","probability":0.9638456702232361},{"start":26.84,"end":27.12,"word":" use","probability":0.9931013584136963},{"start":27.12,"end":27.44,"word":" AI","probability":0.9324751496315002},{"start":27.44,"end":27.86,"word":" background","probability":0.6952386498451233},{"start":27.86,"end":28.12,"word":" blur","probability":0.9974852800369263},{"start":28.12,"end":28.36,"word":" or","probability":0.9533637166023254},{"start":28.36,"end":28.56,"word":" full","probability":0.9764475226402283},{"start":28.56,"end":28.9,"word":" background","probability":0.9884167313575745},{"start":28.9,"end":29.32,"word":" removal","probability":0.9939894676208496},{"start":29.32,"end":29.76,"word":" to","probability":0.9747978448867798},{"start":29.76,"end":29.98,"word":" stay","probability":0.9970933198928833},{"start":29.98,"end":30.38,"word":" focused","probability":0.951511800289154},{"start":30.38,"end":30.82,"word":" and","probability":0.9859418272972107},{"start":30.82,"end":31.06,"word":" fully","probability":0.997599184513092}]},{"id":9,"seek":5468,"start":31.06,"end":32.6,"text":" immersed in your presentation.","tokens":[50638,35416,294,428,5860,13,50776],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":31.06,"end":31.44,"word":" immersed","probability":0.988663375377655},{"start":31.44,"end":31.78,"word":" in","probability":0.9948458671569824},{"start":31.78,"end":31.98,"word":" your","probability":0.9943114519119263},{"start":31.98,"end":32.6,"word":" presentation.","probability":0.9933533668518066}]},{"id":10,"seek":5468,"start":33.26,"end":36.16,"text":" And if you make a small mistake, no problem.","tokens":[50776,400,498,291,652,257,1359,6146,11,572,1154,13,50920],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":33.26,"end":33.82,"word":" And","probability":0.940563440322876},{"start":33.82,"end":34.16,"word":" if","probability":0.5281017422676086},{"start":34.16,"end":34.26,"word":" you","probability":0.9976662397384644},{"start":34.26,"end":34.44,"word":" make","probability":0.9972223043441772},{"start":34.44,"end":34.58,"word":" a","probability":0.995194137096405},{"start":34.58,"end":34.76,"word":" small","probability":0.9956401586532593},{"start":34.76,"end":35.12,"word":" mistake,","probability":0.9976315498352051},{"start":35.5,"end":35.76,"word":" no","probability":0.9710552096366882},{"start":35.76,"end":36.16,"word":" problem.","probability":0.9858748316764832}]},{"id":11,"seek":5468,"start":36.56,"end":40.86,"text":" With AI audio retakes, just highlight the part you want to fix, then record or type","tokens":[50920,2022,7318,6278,1533,3419,11,445,5078,264,644,291,528,281,3191,11,550,2136,420,2010,51126],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":36.56,"end":36.76,"word":" With","probability":0.9903624653816223},{"start":36.76,"end":37.1,"word":" AI","probability":0.9924909472465515},{"start":37.1,"end":37.46,"word":" audio","probability":0.8897120356559753},{"start":37.46,"end":38,"word":" retakes,","probability":0.9872439205646515},{"start":38.3,"end":38.42,"word":" just","probability":0.9755398631095886},{"start":38.42,"end":38.72,"word":" highlight","probability":0.9990407824516296},{"start":38.72,"end":38.94,"word":" the","probability":0.9959554672241211},{"start":38.94,"end":39.14,"word":" part","probability":0.9102027416229248},{"start":39.14,"end":39.3,"word":" you","probability":0.9910547137260437},{"start":39.3,"end":39.46,"word":" want","probability":0.9591130614280701},{"start":39.46,"end":39.56,"word":" to","probability":0.9967060685157776},{"start":39.56,"end":39.78,"word":" fix,","probability":0.9987348914146423},{"start":40,"end":40.2,"word":" then","probability":0.9834949374198914},{"start":40.2,"end":40.48,"word":" record","probability":0.9892204403877258},{"start":40.48,"end":40.64,"word":" or","probability":0.9840781688690186},{"start":40.64,"end":40.86,"word":" type","probability":0.9976154565811157}]},{"id":12,"seek":5468,"start":40.86,"end":41.36,"text":" your correction.","tokens":[51126,428,19984,13,51176],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":40.86,"end":40.98,"word":" your","probability":0.9869692325592041},{"start":40.98,"end":41.36,"word":" correction.","probability":0.9645764827728271}]},{"id":13,"seek":5468,"start":41.8,"end":43.82,"text":" No need to re-record the entire video.","tokens":[51176,883,643,281,319,12,38500,264,2302,960,13,51318],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":41.8,"end":42.02,"word":" No","probability":0.992559552192688},{"start":42.02,"end":42.16,"word":" need","probability":0.9987194538116455},{"start":42.16,"end":42.34,"word":" to","probability":0.9982567429542542},{"start":42.34,"end":42.5,"word":" re","probability":0.8223015666007996},{"start":42.5,"end":42.8,"word":"-record","probability":0.9892989993095398},{"start":42.8,"end":43.14,"word":" the","probability":0.9953472018241882},{"start":43.14,"end":43.44,"word":" entire","probability":0.9937765598297119},{"start":43.44,"end":43.82,"word":" video.","probability":0.9984459280967712}]},{"id":14,"seek":5468,"start":44.38,"end":50.04,"text":" Best of all, even without a live webcam, Canvid can create a realistic synthetic camera","tokens":[51318,9752,295,439,11,754,1553,257,1621,39490,11,1664,6833,393,1884,257,12465,23420,2799,51588],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":44.38,"end":44.64,"word":" Best","probability":0.9908847212791443},{"start":44.64,"end":44.82,"word":" of","probability":0.9984235763549805},{"start":44.82,"end":45.04,"word":" all,","probability":0.9989323019981384},{"start":45.32,"end":45.5,"word":" even","probability":0.9940084218978882},{"start":45.5,"end":45.88,"word":" without","probability":0.9899681806564331},{"start":45.88,"end":46.12,"word":" a","probability":0.7982197403907776},{"start":46.12,"end":46.32,"word":" live","probability":0.9628170728683472},{"start":46.32,"end":46.74,"word":" webcam,","probability":0.9965049028396606},{"start":47.3,"end":47.72,"word":" Canvid","probability":0.6870472431182861},{"start":47.72,"end":47.96,"word":" can","probability":0.9909351468086243},{"start":47.96,"end":48.32,"word":" create","probability":0.9938556551933289},{"start":48.32,"end":48.56,"word":" a","probability":0.9904357194900513},{"start":48.56,"end":48.92,"word":" realistic","probability":0.9882749319076538},{"start":48.92,"end":49.4,"word":" synthetic","probability":0.8551467061042786},{"start":49.4,"end":50.04,"word":" camera","probability":0.9845417737960815}]},{"id":15,"seek":5468,"start":50.04,"end":55.6,"text":" feed from your best previous recording, giving your videos a professional, personal touch","tokens":[51588,3154,490,428,1151,3894,6613,11,2902,428,2145,257,4843,11,2973,2557,51860],"temperature":0,"avg_logprob":-0.1665485081465348,"compression_ratio":1.6394557823129252,"no_speech_prob":0.1486709862947464,"words":[{"start":50.04,"end":50.36,"word":" feed","probability":0.9969772100448608},{"start":50.36,"end":50.88,"word":" from","probability":0.9819400906562805},{"start":50.88,"end":51.16,"word":" your","probability":0.9955233335494995},{"start":51.16,"end":51.52,"word":" best","probability":0.9430131912231445},{"start":51.52,"end":51.96,"word":" previous","probability":0.9610211849212646},{"start":51.96,"end":52.58,"word":" recording,","probability":0.9957404136657715},{"start":53,"end":53.3,"word":" giving","probability":0.9944908618927002},{"start":53.3,"end":53.48,"word":" your","probability":0.9938317537307739},{"start":53.48,"end":53.78,"word":" videos","probability":0.9474282264709473},{"start":53.78,"end":53.96,"word":" a","probability":0.9789287447929382},{"start":53.96,"end":54.4,"word":" professional,","probability":0.9963812828063965},{"start":54.78,"end":55.18,"word":" personal","probability":0.996509850025177},{"start":55.18,"end":55.6,"word":" touch","probability":0.9927807450294495}]},{"id":16,"seek":5851,"start":55.6,"end":56.32,"text":" every time.","tokens":[50368,633,565,13,50404],"temperature":0,"avg_logprob":-0.6175005435943604,"compression_ratio":0.5789473684210527,"no_speech_prob":0.3447488248348236,"words":[{"start":55.6,"end":55.98,"word":" every","probability":0.4578200876712799},{"start":55.98,"end":56.32,"word":" time.","probability":0.7729238867759705}]}]}
|
transcription_format_2.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"task":"transcribe","language":"en","text":"With Canvid, every recording becomes smarter and easier to work with. It automatically generates a full transcript of your video, complete with time-accurate word timestamps. You can simply click any word to jump straight into that exact moment, perfect for precise edits and effortless navigation. Canvid's noise cancellation cleans up your audio by removing background noise and enhancing your voice in real time. You can also use AI background blur or full background removal to stay focused and fully immersed in your presentation. And if you make a small mistake, no problem. With AI audio retakes, just highlight the part you want to fix, then record or type your correction. No need to rerecord the entire video. Best of all, even without a live webcam, Canvid can create a realistic synthetic camera feed from your best previous recording. giving your videos a professional, personal touch every time.","request_id":"64819cd3-863a-4d47-a01b-a56c9d16854f","words":[{"word":"With","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":1.654,"end":1.794,"retry_count":0},{"word":"Canvid,","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":1.834,"end":2.295,"retry_count":0},{"word":"every","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":2.715,"end":2.935,"retry_count":0},{"word":"recording","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":3.015,"end":3.536,"retry_count":0},{"word":"becomes","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":3.596,"end":3.936,"retry_count":0},{"word":"smarter","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":3.976,"end":4.416,"retry_count":0},{"word":"and","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":4.556,"end":4.676,"retry_count":0},{"word":"easier","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":4.817,"end":5.217,"retry_count":0},{"word":"to","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":5.297,"end":5.377,"retry_count":0},{"word":"work","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":5.457,"end":5.637,"retry_count":0},{"word":"with.","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":5.697,"end":5.897,"retry_count":0},{"word":"It","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":6.298,"end":6.378,"retry_count":0},{"word":"automatically","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":6.478,"end":7.138,"retry_count":0},{"word":"generates","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":7.219,"end":7.699,"retry_count":0},{"word":"a","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":7.739,"end":7.759,"retry_count":0},{"word":"full","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":7.819,"end":7.979,"retry_count":0},{"word":"transcript","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":8.039,"end":8.54,"retry_count":0},{"word":"of","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":8.62,"end":8.7,"retry_count":0},{"word":"your","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":8.74,"end":8.88,"retry_count":0},{"word":"video,","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":8.92,"end":9.2,"retry_count":0},{"word":"complete","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":9.34,"end":9.761,"retry_count":0},{"word":"with","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":9.781,"end":9.921,"retry_count":0},{"word":"time-accurate","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":9.961,"end":10.742,"retry_count":0},{"word":"word","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":10.802,"end":10.962,"retry_count":0},{"word":"timestamps.","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":11.002,"end":11.662,"retry_count":0},{"word":"You","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":12.163,"end":12.263,"retry_count":0},{"word":"can","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":12.263,"end":12.383,"retry_count":0},{"word":"simply","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":12.443,"end":12.743,"retry_count":0},{"word":"click","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":12.783,"end":12.983,"retry_count":0},{"word":"any","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":13.143,"end":13.284,"retry_count":0},{"word":"word","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":13.424,"end":13.624,"retry_count":0},{"word":"to","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":13.644,"end":13.704,"retry_count":0},{"word":"jump","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":13.784,"end":13.984,"retry_count":0},{"word":"straight","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":14.024,"end":14.364,"retry_count":0},{"word":"into","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":14.445,"end":14.585,"retry_count":0},{"word":"that","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":14.645,"end":14.805,"retry_count":0},{"word":"exact","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":14.865,"end":15.225,"retry_count":0},{"word":"moment,","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":15.285,"end":15.605,"retry_count":0},{"word":"perfect","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":15.986,"end":16.426,"retry_count":0},{"word":"for","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":16.446,"end":16.586,"retry_count":0},{"word":"precise","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":16.626,"end":17.147,"retry_count":0},{"word":"edits","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":17.247,"end":17.527,"retry_count":0},{"word":"and","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":17.627,"end":17.727,"retry_count":0},{"word":"effortless","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":17.807,"end":18.228,"retry_count":0},{"word":"navigation.","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":18.308,"end":18.968,"retry_count":0},{"word":"Canvid's","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":19.609,"end":20.049,"retry_count":0},{"word":"noise","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":20.089,"end":20.329,"retry_count":0},{"word":"cancellation","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":20.369,"end":21.07,"retry_count":0},{"word":"cleans","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":21.15,"end":21.43,"retry_count":0},{"word":"up","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":21.45,"end":21.53,"retry_count":0},{"word":"your","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":21.57,"end":21.691,"retry_count":0},{"word":"audio","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":21.771,"end":22.011,"retry_count":0},{"word":"by","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":22.131,"end":22.251,"retry_count":0},{"word":"removing","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":22.331,"end":22.771,"retry_count":0},{"word":"background","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":22.831,"end":23.252,"retry_count":0},{"word":"noise","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":23.312,"end":23.592,"retry_count":0},{"word":"and","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":23.892,"end":23.972,"retry_count":0},{"word":"enhancing","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":24.012,"end":24.493,"retry_count":0},{"word":"your","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":24.493,"end":24.613,"retry_count":0},{"word":"voice","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":24.633,"end":24.913,"retry_count":0},{"word":"in","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":24.993,"end":25.073,"retry_count":0},{"word":"real","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":25.073,"end":25.464,"retry_count":0},{"word":"time.","language":"en","probability":0.9532690923369119,"hallucination_score":0,"start":25.464,"end":25.854,"retry_count":0},{"word":"You","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":26.39,"end":26.49,"retry_count":0},{"word":"can","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":26.49,"end":26.61,"retry_count":0},{"word":"also","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":26.67,"end":26.87,"retry_count":0},{"word":"use","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":27.01,"end":27.17,"retry_count":0},{"word":"AI","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":27.27,"end":27.511,"retry_count":0},{"word":"background","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":27.57,"end":27.971,"retry_count":0},{"word":"blur","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":27.971,"end":28.191,"retry_count":0},{"word":"or","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":28.311,"end":28.371,"retry_count":0},{"word":"full","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":28.411,"end":28.591,"retry_count":0},{"word":"background","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":28.631,"end":29.011,"retry_count":0},{"word":"removal","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":29.031,"end":29.431,"retry_count":0},{"word":"to","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":29.692,"end":29.752,"retry_count":0},{"word":"stay","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":29.832,"end":30.032,"retry_count":0},{"word":"focused","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":30.112,"end":30.592,"retry_count":0},{"word":"and","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":30.732,"end":30.832,"retry_count":0},{"word":"fully","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":30.872,"end":31.092,"retry_count":0},{"word":"immersed","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":31.152,"end":31.572,"retry_count":0},{"word":"in","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":31.672,"end":31.752,"retry_count":0},{"word":"your","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":31.832,"end":32.013,"retry_count":0},{"word":"presentation.","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":32.073,"end":32.873,"retry_count":0},{"word":"And","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":33.633,"end":33.853,"retry_count":0},{"word":"if","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":34.074,"end":34.154,"retry_count":0},{"word":"you","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":34.194,"end":34.274,"retry_count":0},{"word":"make","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":34.314,"end":34.494,"retry_count":0},{"word":"a","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":34.534,"end":34.554,"retry_count":0},{"word":"small","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":34.594,"end":34.814,"retry_count":0},{"word":"mistake,","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":34.854,"end":35.234,"retry_count":0},{"word":"no","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":35.594,"end":35.694,"retry_count":0},{"word":"problem.","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":35.854,"end":36.255,"retry_count":0},{"word":"With","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":36.635,"end":36.775,"retry_count":0},{"word":"AI","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":36.875,"end":37.175,"retry_count":0},{"word":"audio","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":37.295,"end":37.515,"retry_count":0},{"word":"retakes,","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":37.595,"end":38.075,"retry_count":0},{"word":"just","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":38.295,"end":38.456,"retry_count":0},{"word":"highlight","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":38.495,"end":38.836,"retry_count":0},{"word":"the","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":38.856,"end":38.936,"retry_count":0},{"word":"part","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":38.976,"end":39.196,"retry_count":0},{"word":"you","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":39.236,"end":39.316,"retry_count":0},{"word":"want","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":39.336,"end":39.456,"retry_count":0},{"word":"to","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":39.476,"end":39.516,"retry_count":0},{"word":"fix,","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":39.576,"end":39.776,"retry_count":0},{"word":"then","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":40.096,"end":40.196,"retry_count":0},{"word":"record","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":40.236,"end":40.536,"retry_count":0},{"word":"or","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":40.576,"end":40.657,"retry_count":0},{"word":"type","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":40.676,"end":40.897,"retry_count":0},{"word":"your","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":40.897,"end":40.997,"retry_count":0},{"word":"correction.","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":41.017,"end":41.497,"retry_count":0},{"word":"No","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":41.877,"end":41.957,"retry_count":0},{"word":"need","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":42.077,"end":42.217,"retry_count":0},{"word":"to","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":42.257,"end":42.317,"retry_count":0},{"word":"rerecord","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":42.397,"end":42.898,"retry_count":0},{"word":"the","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":43.058,"end":43.118,"retry_count":0},{"word":"entire","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":43.178,"end":43.538,"retry_count":0},{"word":"video.","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":43.578,"end":43.818,"retry_count":0},{"word":"Best","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":44.498,"end":44.698,"retry_count":0},{"word":"of","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":44.738,"end":44.818,"retry_count":0},{"word":"all,","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":44.878,"end":45.038,"retry_count":0},{"word":"even","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":45.359,"end":45.559,"retry_count":0},{"word":"without","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":45.639,"end":45.979,"retry_count":0},{"word":"a","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":46.059,"end":46.079,"retry_count":0},{"word":"live","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":46.139,"end":46.419,"retry_count":0},{"word":"webcam,","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":46.459,"end":46.859,"retry_count":0},{"word":"Canvid","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":47.3,"end":47.78,"retry_count":0},{"word":"can","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":47.86,"end":47.98,"retry_count":0},{"word":"create","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":48.02,"end":48.42,"retry_count":0},{"word":"a","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":48.46,"end":48.48,"retry_count":0},{"word":"realistic","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":48.58,"end":49.14,"retry_count":0},{"word":"synthetic","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":49.18,"end":49.701,"retry_count":0},{"word":"camera","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":49.801,"end":50.101,"retry_count":0},{"word":"feed","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":50.201,"end":50.441,"retry_count":0},{"word":"from","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":50.701,"end":50.881,"retry_count":0},{"word":"your","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":51.001,"end":51.221,"retry_count":0},{"word":"best","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":51.361,"end":51.621,"retry_count":0},{"word":"previous","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":51.621,"end":52.162,"retry_count":0},{"word":"recording.","language":"en","probability":0.9611267416981295,"hallucination_score":0,"start":52.162,"end":52.702,"retry_count":0},{"word":"giving","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":53.123,"end":53.385,"retry_count":0},{"word":"your","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":53.385,"end":53.485,"retry_count":0},{"word":"videos","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":53.525,"end":53.867,"retry_count":0},{"word":"a","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":53.927,"end":53.947,"retry_count":0},{"word":"professional,","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":53.987,"end":54.57,"retry_count":0},{"word":"personal","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":54.851,"end":55.233,"retry_count":0},{"word":"touch","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":55.313,"end":55.614,"retry_count":0},{"word":"every","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":55.795,"end":55.996,"retry_count":0},{"word":"time.","language":"en","probability":0.9440868528107329,"hallucination_score":0,"start":55.996,"end":56.478,"retry_count":0}],"duration":59.4346875}
|
transcription_format_3.json
ADDED
|
@@ -0,0 +1,899 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"text": "With CANVID, every recording becomes smarter and easier to work with. It automatically generates a full transcript of your video, complete with time -accurate word timestamps. You can simply click any word to jump straight into that exact moment, perfect for precise edits and effortless navigation. CANVID's noise cancellation cleans up your audio by removing background noise and enhancing your voice in real time. You can also use AI background blur or full background removal to stay focused and fully immersed in your presentation. And if you make a small mistake, no problem. With AI audio retakes, just highlight the part you want to fix, then record or type your correction. No need to re -record the entire video. Best of all, even without a live webcam, CANVID can create a realistic synthetic camera feed from your best previous recording, giving your videos a professional, personal touch every time.",
|
| 3 |
+
"segments": [
|
| 4 |
+
{
|
| 5 |
+
"start": 1.64,
|
| 6 |
+
"end": 1.8,
|
| 7 |
+
"text": "With",
|
| 8 |
+
"score": -0.08151979744434357
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"start": 1.8,
|
| 12 |
+
"end": 2.5,
|
| 13 |
+
"text": "CANVID,",
|
| 14 |
+
"score": -0.610592782497406
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"start": 2.5,
|
| 18 |
+
"end": 2.96,
|
| 19 |
+
"text": "every",
|
| 20 |
+
"score": -0.08097043633460999
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"start": 2.96,
|
| 24 |
+
"end": 3.56,
|
| 25 |
+
"text": "recording",
|
| 26 |
+
"score": -0.05543423444032669
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"start": 3.56,
|
| 30 |
+
"end": 3.94,
|
| 31 |
+
"text": "becomes",
|
| 32 |
+
"score": -2.1648306846618652
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"start": 3.94,
|
| 36 |
+
"end": 4.48,
|
| 37 |
+
"text": "smarter",
|
| 38 |
+
"score": -0.387157678604126
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"start": 4.48,
|
| 42 |
+
"end": 4.74,
|
| 43 |
+
"text": "and",
|
| 44 |
+
"score": -0.119212806224823
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"start": 4.74,
|
| 48 |
+
"end": 5.24,
|
| 49 |
+
"text": "easier",
|
| 50 |
+
"score": -0.10670951753854752
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"start": 5.24,
|
| 54 |
+
"end": 5.38,
|
| 55 |
+
"text": "to",
|
| 56 |
+
"score": -0.006726465187966824
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"start": 5.38,
|
| 60 |
+
"end": 5.66,
|
| 61 |
+
"text": "work",
|
| 62 |
+
"score": -0.005453118588775396
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"start": 5.66,
|
| 66 |
+
"end": 6.08,
|
| 67 |
+
"text": "with.",
|
| 68 |
+
"score": -0.1591891050338745
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"start": 6.08,
|
| 72 |
+
"end": 6.42,
|
| 73 |
+
"text": "It",
|
| 74 |
+
"score": -0.01639869064092636
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"start": 6.42,
|
| 78 |
+
"end": 7.16,
|
| 79 |
+
"text": "automatically",
|
| 80 |
+
"score": -1.1396892070770264
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"start": 7.16,
|
| 84 |
+
"end": 7.7,
|
| 85 |
+
"text": "generates",
|
| 86 |
+
"score": -0.37663596868515015
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"start": 7.7,
|
| 90 |
+
"end": 7.76,
|
| 91 |
+
"text": "a",
|
| 92 |
+
"score": -0.0067606340162456036
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"start": 7.76,
|
| 96 |
+
"end": 8.0,
|
| 97 |
+
"text": "full",
|
| 98 |
+
"score": -0.7901870012283325
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"start": 8.0,
|
| 102 |
+
"end": 8.56,
|
| 103 |
+
"text": "transcript",
|
| 104 |
+
"score": -0.6918596029281616
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"start": 8.56,
|
| 108 |
+
"end": 8.7,
|
| 109 |
+
"text": "of",
|
| 110 |
+
"score": -0.008518156595528126
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"start": 8.7,
|
| 114 |
+
"end": 8.88,
|
| 115 |
+
"text": "your",
|
| 116 |
+
"score": -0.07631964236497879
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"start": 8.88,
|
| 120 |
+
"end": 9.26,
|
| 121 |
+
"text": "video,",
|
| 122 |
+
"score": -0.09540645778179169
|
| 123 |
+
},
|
| 124 |
+
{
|
| 125 |
+
"start": 9.26,
|
| 126 |
+
"end": 9.74,
|
| 127 |
+
"text": "complete",
|
| 128 |
+
"score": -0.4760415554046631
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"start": 9.74,
|
| 132 |
+
"end": 9.92,
|
| 133 |
+
"text": "with",
|
| 134 |
+
"score": -0.17475254833698273
|
| 135 |
+
},
|
| 136 |
+
{
|
| 137 |
+
"start": 9.92,
|
| 138 |
+
"end": 10.26,
|
| 139 |
+
"text": "time",
|
| 140 |
+
"score": -0.12442675977945328
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"start": 10.26,
|
| 144 |
+
"end": 10.74,
|
| 145 |
+
"text": "-accurate",
|
| 146 |
+
"score": -0.8242716789245605
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"start": 10.74,
|
| 150 |
+
"end": 10.96,
|
| 151 |
+
"text": "word",
|
| 152 |
+
"score": -1.8274222612380981
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"start": 10.96,
|
| 156 |
+
"end": 11.88,
|
| 157 |
+
"text": "timestamps.",
|
| 158 |
+
"score": -0.9761462211608887
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"start": 11.88,
|
| 162 |
+
"end": 12.24,
|
| 163 |
+
"text": "You",
|
| 164 |
+
"score": -0.011501493863761425
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"start": 12.24,
|
| 168 |
+
"end": 12.4,
|
| 169 |
+
"text": "can",
|
| 170 |
+
"score": -0.053069207817316055
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"start": 12.4,
|
| 174 |
+
"end": 12.74,
|
| 175 |
+
"text": "simply",
|
| 176 |
+
"score": -1.0623061656951904
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"start": 12.74,
|
| 180 |
+
"end": 13.04,
|
| 181 |
+
"text": "click",
|
| 182 |
+
"score": -0.16563200950622559
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"start": 13.04,
|
| 186 |
+
"end": 13.32,
|
| 187 |
+
"text": "any",
|
| 188 |
+
"score": -0.05466760694980621
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"start": 13.32,
|
| 192 |
+
"end": 13.6,
|
| 193 |
+
"text": "word",
|
| 194 |
+
"score": -0.0955428034067154
|
| 195 |
+
},
|
| 196 |
+
{
|
| 197 |
+
"start": 13.6,
|
| 198 |
+
"end": 13.72,
|
| 199 |
+
"text": "to",
|
| 200 |
+
"score": -0.012247011996805668
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"start": 13.72,
|
| 204 |
+
"end": 13.98,
|
| 205 |
+
"text": "jump",
|
| 206 |
+
"score": -0.07913355529308319
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"start": 13.98,
|
| 210 |
+
"end": 14.38,
|
| 211 |
+
"text": "straight",
|
| 212 |
+
"score": -4.182260513305664
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"start": 14.38,
|
| 216 |
+
"end": 14.6,
|
| 217 |
+
"text": "into",
|
| 218 |
+
"score": -0.1293237805366516
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"start": 14.6,
|
| 222 |
+
"end": 14.82,
|
| 223 |
+
"text": "that",
|
| 224 |
+
"score": -0.2660076916217804
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"start": 14.82,
|
| 228 |
+
"end": 15.22,
|
| 229 |
+
"text": "exact",
|
| 230 |
+
"score": -0.03551250696182251
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"start": 15.22,
|
| 234 |
+
"end": 15.78,
|
| 235 |
+
"text": "moment,",
|
| 236 |
+
"score": -0.1617247611284256
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"start": 15.78,
|
| 240 |
+
"end": 16.4,
|
| 241 |
+
"text": "perfect",
|
| 242 |
+
"score": -0.13937878608703613
|
| 243 |
+
},
|
| 244 |
+
{
|
| 245 |
+
"start": 16.4,
|
| 246 |
+
"end": 16.58,
|
| 247 |
+
"text": "for",
|
| 248 |
+
"score": -0.015207158401608467
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"start": 16.58,
|
| 252 |
+
"end": 17.18,
|
| 253 |
+
"text": "precise",
|
| 254 |
+
"score": -0.04675090312957764
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"start": 17.18,
|
| 258 |
+
"end": 17.54,
|
| 259 |
+
"text": "edits",
|
| 260 |
+
"score": -2.1705334186553955
|
| 261 |
+
},
|
| 262 |
+
{
|
| 263 |
+
"start": 17.54,
|
| 264 |
+
"end": 17.74,
|
| 265 |
+
"text": "and",
|
| 266 |
+
"score": -0.04188178852200508
|
| 267 |
+
},
|
| 268 |
+
{
|
| 269 |
+
"start": 17.74,
|
| 270 |
+
"end": 18.24,
|
| 271 |
+
"text": "effortless",
|
| 272 |
+
"score": -0.9298043251037598
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"start": 18.24,
|
| 276 |
+
"end": 19.26,
|
| 277 |
+
"text": "navigation.",
|
| 278 |
+
"score": -0.5522932410240173
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"start": 19.26,
|
| 282 |
+
"end": 20.04,
|
| 283 |
+
"text": "CANVID's",
|
| 284 |
+
"score": -1.7257797718048096
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"start": 20.04,
|
| 288 |
+
"end": 20.32,
|
| 289 |
+
"text": "noise",
|
| 290 |
+
"score": -1.081925392150879
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"start": 20.32,
|
| 294 |
+
"end": 21.08,
|
| 295 |
+
"text": "cancellation",
|
| 296 |
+
"score": -0.7568238377571106
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"start": 21.08,
|
| 300 |
+
"end": 21.4,
|
| 301 |
+
"text": "cleans",
|
| 302 |
+
"score": -0.24307142198085785
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
"start": 21.4,
|
| 306 |
+
"end": 21.52,
|
| 307 |
+
"text": "up",
|
| 308 |
+
"score": -0.04906478151679039
|
| 309 |
+
},
|
| 310 |
+
{
|
| 311 |
+
"start": 21.52,
|
| 312 |
+
"end": 21.7,
|
| 313 |
+
"text": "your",
|
| 314 |
+
"score": -0.760680079460144
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"start": 21.7,
|
| 318 |
+
"end": 22.04,
|
| 319 |
+
"text": "audio",
|
| 320 |
+
"score": -3.6923694610595703
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"start": 22.04,
|
| 324 |
+
"end": 22.26,
|
| 325 |
+
"text": "by",
|
| 326 |
+
"score": -0.010336088947951794
|
| 327 |
+
},
|
| 328 |
+
{
|
| 329 |
+
"start": 22.26,
|
| 330 |
+
"end": 22.76,
|
| 331 |
+
"text": "removing",
|
| 332 |
+
"score": -0.06585686653852463
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"start": 22.76,
|
| 336 |
+
"end": 23.24,
|
| 337 |
+
"text": "background",
|
| 338 |
+
"score": -1.7343212366104126
|
| 339 |
+
},
|
| 340 |
+
{
|
| 341 |
+
"start": 23.24,
|
| 342 |
+
"end": 23.72,
|
| 343 |
+
"text": "noise",
|
| 344 |
+
"score": -0.8788498640060425
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"start": 23.72,
|
| 348 |
+
"end": 23.96,
|
| 349 |
+
"text": "and",
|
| 350 |
+
"score": -0.03457999229431152
|
| 351 |
+
},
|
| 352 |
+
{
|
| 353 |
+
"start": 23.96,
|
| 354 |
+
"end": 24.46,
|
| 355 |
+
"text": "enhancing",
|
| 356 |
+
"score": -1.0168116092681885
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"start": 24.46,
|
| 360 |
+
"end": 24.58,
|
| 361 |
+
"text": "your",
|
| 362 |
+
"score": -0.45429959893226624
|
| 363 |
+
},
|
| 364 |
+
{
|
| 365 |
+
"start": 24.58,
|
| 366 |
+
"end": 24.92,
|
| 367 |
+
"text": "voice",
|
| 368 |
+
"score": -0.021240152418613434
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"start": 24.92,
|
| 372 |
+
"end": 25.06,
|
| 373 |
+
"text": "in",
|
| 374 |
+
"score": -0.01202479936182499
|
| 375 |
+
},
|
| 376 |
+
{
|
| 377 |
+
"start": 25.06,
|
| 378 |
+
"end": 25.34,
|
| 379 |
+
"text": "real",
|
| 380 |
+
"score": -0.012947533279657364
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"start": 25.34,
|
| 384 |
+
"end": 26.06,
|
| 385 |
+
"text": "time.",
|
| 386 |
+
"score": -0.17728735506534576
|
| 387 |
+
},
|
| 388 |
+
{
|
| 389 |
+
"start": 26.06,
|
| 390 |
+
"end": 26.48,
|
| 391 |
+
"text": "You",
|
| 392 |
+
"score": -0.034842006862163544
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"start": 26.48,
|
| 396 |
+
"end": 26.64,
|
| 397 |
+
"text": "can",
|
| 398 |
+
"score": -0.028295230120420456
|
| 399 |
+
},
|
| 400 |
+
{
|
| 401 |
+
"start": 26.64,
|
| 402 |
+
"end": 26.92,
|
| 403 |
+
"text": "also",
|
| 404 |
+
"score": -0.005661904811859131
|
| 405 |
+
},
|
| 406 |
+
{
|
| 407 |
+
"start": 26.92,
|
| 408 |
+
"end": 27.2,
|
| 409 |
+
"text": "use",
|
| 410 |
+
"score": -0.18630290031433105
|
| 411 |
+
},
|
| 412 |
+
{
|
| 413 |
+
"start": 27.2,
|
| 414 |
+
"end": 27.54,
|
| 415 |
+
"text": "AI",
|
| 416 |
+
"score": -1.145396113395691
|
| 417 |
+
},
|
| 418 |
+
{
|
| 419 |
+
"start": 27.54,
|
| 420 |
+
"end": 27.96,
|
| 421 |
+
"text": "background",
|
| 422 |
+
"score": -5.4883527755737305
|
| 423 |
+
},
|
| 424 |
+
{
|
| 425 |
+
"start": 27.96,
|
| 426 |
+
"end": 28.22,
|
| 427 |
+
"text": "blur",
|
| 428 |
+
"score": -6.778469562530518
|
| 429 |
+
},
|
| 430 |
+
{
|
| 431 |
+
"start": 28.22,
|
| 432 |
+
"end": 28.38,
|
| 433 |
+
"text": "or",
|
| 434 |
+
"score": -0.031012453138828278
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"start": 28.38,
|
| 438 |
+
"end": 28.6,
|
| 439 |
+
"text": "full",
|
| 440 |
+
"score": -0.531334400177002
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"start": 28.6,
|
| 444 |
+
"end": 29.0,
|
| 445 |
+
"text": "background",
|
| 446 |
+
"score": -4.3894829750061035
|
| 447 |
+
},
|
| 448 |
+
{
|
| 449 |
+
"start": 29.0,
|
| 450 |
+
"end": 29.54,
|
| 451 |
+
"text": "removal",
|
| 452 |
+
"score": -0.19233684241771698
|
| 453 |
+
},
|
| 454 |
+
{
|
| 455 |
+
"start": 29.54,
|
| 456 |
+
"end": 29.76,
|
| 457 |
+
"text": "to",
|
| 458 |
+
"score": -0.01742566004395485
|
| 459 |
+
},
|
| 460 |
+
{
|
| 461 |
+
"start": 29.76,
|
| 462 |
+
"end": 30.04,
|
| 463 |
+
"text": "stay",
|
| 464 |
+
"score": -0.05717923492193222
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"start": 30.04,
|
| 468 |
+
"end": 30.64,
|
| 469 |
+
"text": "focused",
|
| 470 |
+
"score": -0.22116851806640625
|
| 471 |
+
},
|
| 472 |
+
{
|
| 473 |
+
"start": 30.64,
|
| 474 |
+
"end": 30.82,
|
| 475 |
+
"text": "and",
|
| 476 |
+
"score": -0.09630168229341507
|
| 477 |
+
},
|
| 478 |
+
{
|
| 479 |
+
"start": 30.82,
|
| 480 |
+
"end": 31.12,
|
| 481 |
+
"text": "fully",
|
| 482 |
+
"score": -0.08033610880374908
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"start": 31.12,
|
| 486 |
+
"end": 31.6,
|
| 487 |
+
"text": "immersed",
|
| 488 |
+
"score": -10.911242485046387
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"start": 31.6,
|
| 492 |
+
"end": 31.78,
|
| 493 |
+
"text": "in",
|
| 494 |
+
"score": -0.007256546523422003
|
| 495 |
+
},
|
| 496 |
+
{
|
| 497 |
+
"start": 31.78,
|
| 498 |
+
"end": 32.02,
|
| 499 |
+
"text": "your",
|
| 500 |
+
"score": -0.20859788358211517
|
| 501 |
+
},
|
| 502 |
+
{
|
| 503 |
+
"start": 32.02,
|
| 504 |
+
"end": 33.24,
|
| 505 |
+
"text": "presentation.",
|
| 506 |
+
"score": -0.0495038777589798
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"start": 33.24,
|
| 510 |
+
"end": 33.94,
|
| 511 |
+
"text": "And",
|
| 512 |
+
"score": -0.022549446672201157
|
| 513 |
+
},
|
| 514 |
+
{
|
| 515 |
+
"start": 33.94,
|
| 516 |
+
"end": 34.16,
|
| 517 |
+
"text": "if",
|
| 518 |
+
"score": -0.0015337379882112145
|
| 519 |
+
},
|
| 520 |
+
{
|
| 521 |
+
"start": 34.16,
|
| 522 |
+
"end": 34.28,
|
| 523 |
+
"text": "you",
|
| 524 |
+
"score": -0.02903260476887226
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"start": 34.28,
|
| 528 |
+
"end": 34.5,
|
| 529 |
+
"text": "make",
|
| 530 |
+
"score": -0.08994806557893753
|
| 531 |
+
},
|
| 532 |
+
{
|
| 533 |
+
"start": 34.5,
|
| 534 |
+
"end": 34.56,
|
| 535 |
+
"text": "a",
|
| 536 |
+
"score": -0.23658980429172516
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"start": 34.56,
|
| 540 |
+
"end": 34.82,
|
| 541 |
+
"text": "small",
|
| 542 |
+
"score": -0.14645498991012573
|
| 543 |
+
},
|
| 544 |
+
{
|
| 545 |
+
"start": 34.82,
|
| 546 |
+
"end": 35.4,
|
| 547 |
+
"text": "mistake,",
|
| 548 |
+
"score": -0.18949539959430695
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"start": 35.4,
|
| 552 |
+
"end": 35.76,
|
| 553 |
+
"text": "no",
|
| 554 |
+
"score": -0.017768744379281998
|
| 555 |
+
},
|
| 556 |
+
{
|
| 557 |
+
"start": 35.76,
|
| 558 |
+
"end": 36.44,
|
| 559 |
+
"text": "problem.",
|
| 560 |
+
"score": -0.05042130872607231
|
| 561 |
+
},
|
| 562 |
+
{
|
| 563 |
+
"start": 36.44,
|
| 564 |
+
"end": 36.8,
|
| 565 |
+
"text": "With",
|
| 566 |
+
"score": -0.1474059373140335
|
| 567 |
+
},
|
| 568 |
+
{
|
| 569 |
+
"start": 36.8,
|
| 570 |
+
"end": 37.22,
|
| 571 |
+
"text": "AI",
|
| 572 |
+
"score": -0.06544703245162964
|
| 573 |
+
},
|
| 574 |
+
{
|
| 575 |
+
"start": 37.22,
|
| 576 |
+
"end": 37.54,
|
| 577 |
+
"text": "audio",
|
| 578 |
+
"score": -13.273054122924805
|
| 579 |
+
},
|
| 580 |
+
{
|
| 581 |
+
"start": 37.54,
|
| 582 |
+
"end": 38.16,
|
| 583 |
+
"text": "retakes,",
|
| 584 |
+
"score": -0.5604587197303772
|
| 585 |
+
},
|
| 586 |
+
{
|
| 587 |
+
"start": 38.16,
|
| 588 |
+
"end": 38.46,
|
| 589 |
+
"text": "just",
|
| 590 |
+
"score": -0.9325882196426392
|
| 591 |
+
},
|
| 592 |
+
{
|
| 593 |
+
"start": 38.46,
|
| 594 |
+
"end": 38.82,
|
| 595 |
+
"text": "highlight",
|
| 596 |
+
"score": -2.3691790103912354
|
| 597 |
+
},
|
| 598 |
+
{
|
| 599 |
+
"start": 38.82,
|
| 600 |
+
"end": 38.94,
|
| 601 |
+
"text": "the",
|
| 602 |
+
"score": -3.0330090522766113
|
| 603 |
+
},
|
| 604 |
+
{
|
| 605 |
+
"start": 38.94,
|
| 606 |
+
"end": 39.18,
|
| 607 |
+
"text": "part",
|
| 608 |
+
"score": -0.06596189737319946
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"start": 39.18,
|
| 612 |
+
"end": 39.28,
|
| 613 |
+
"text": "you",
|
| 614 |
+
"score": -0.24581721425056458
|
| 615 |
+
},
|
| 616 |
+
{
|
| 617 |
+
"start": 39.3,
|
| 618 |
+
"end": 39.44,
|
| 619 |
+
"text": "want",
|
| 620 |
+
"score": -20.85184097290039
|
| 621 |
+
},
|
| 622 |
+
{
|
| 623 |
+
"start": 39.44,
|
| 624 |
+
"end": 39.52,
|
| 625 |
+
"text": "to",
|
| 626 |
+
"score": -10.273269653320312
|
| 627 |
+
},
|
| 628 |
+
{
|
| 629 |
+
"start": 39.52,
|
| 630 |
+
"end": 39.9,
|
| 631 |
+
"text": "fix,",
|
| 632 |
+
"score": -1.9346206188201904
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"start": 39.9,
|
| 636 |
+
"end": 40.2,
|
| 637 |
+
"text": "then",
|
| 638 |
+
"score": -0.6613729596138
|
| 639 |
+
},
|
| 640 |
+
{
|
| 641 |
+
"start": 40.2,
|
| 642 |
+
"end": 40.54,
|
| 643 |
+
"text": "record",
|
| 644 |
+
"score": -0.5808069705963135
|
| 645 |
+
},
|
| 646 |
+
{
|
| 647 |
+
"start": 40.54,
|
| 648 |
+
"end": 40.64,
|
| 649 |
+
"text": "or",
|
| 650 |
+
"score": -2.4585094451904297
|
| 651 |
+
},
|
| 652 |
+
{
|
| 653 |
+
"start": 40.64,
|
| 654 |
+
"end": 40.86,
|
| 655 |
+
"text": "type",
|
| 656 |
+
"score": -0.46192866563796997
|
| 657 |
+
},
|
| 658 |
+
{
|
| 659 |
+
"start": 40.88,
|
| 660 |
+
"end": 40.98,
|
| 661 |
+
"text": "your",
|
| 662 |
+
"score": -11.288326263427734
|
| 663 |
+
},
|
| 664 |
+
{
|
| 665 |
+
"start": 40.98,
|
| 666 |
+
"end": 41.66,
|
| 667 |
+
"text": "correction.",
|
| 668 |
+
"score": -0.29610687494277954
|
| 669 |
+
},
|
| 670 |
+
{
|
| 671 |
+
"start": 41.66,
|
| 672 |
+
"end": 42.0,
|
| 673 |
+
"text": "No",
|
| 674 |
+
"score": -0.011340784840285778
|
| 675 |
+
},
|
| 676 |
+
{
|
| 677 |
+
"start": 42.0,
|
| 678 |
+
"end": 42.22,
|
| 679 |
+
"text": "need",
|
| 680 |
+
"score": -0.24456846714019775
|
| 681 |
+
},
|
| 682 |
+
{
|
| 683 |
+
"start": 42.22,
|
| 684 |
+
"end": 42.34,
|
| 685 |
+
"text": "to",
|
| 686 |
+
"score": -0.08203698694705963
|
| 687 |
+
},
|
| 688 |
+
{
|
| 689 |
+
"start": 42.34,
|
| 690 |
+
"end": 42.48,
|
| 691 |
+
"text": "re",
|
| 692 |
+
"score": -0.013280842453241348
|
| 693 |
+
},
|
| 694 |
+
{
|
| 695 |
+
"start": 42.48,
|
| 696 |
+
"end": 42.96,
|
| 697 |
+
"text": "-record",
|
| 698 |
+
"score": -0.04457765817642212
|
| 699 |
+
},
|
| 700 |
+
{
|
| 701 |
+
"start": 42.96,
|
| 702 |
+
"end": 43.12,
|
| 703 |
+
"text": "the",
|
| 704 |
+
"score": -0.041737157851457596
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"start": 43.12,
|
| 708 |
+
"end": 43.54,
|
| 709 |
+
"text": "entire",
|
| 710 |
+
"score": -0.9720736145973206
|
| 711 |
+
},
|
| 712 |
+
{
|
| 713 |
+
"start": 43.54,
|
| 714 |
+
"end": 44.14,
|
| 715 |
+
"text": "video.",
|
| 716 |
+
"score": -0.028474120423197746
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"start": 44.14,
|
| 720 |
+
"end": 44.7,
|
| 721 |
+
"text": "Best",
|
| 722 |
+
"score": -0.5948593020439148
|
| 723 |
+
},
|
| 724 |
+
{
|
| 725 |
+
"start": 44.7,
|
| 726 |
+
"end": 44.84,
|
| 727 |
+
"text": "of",
|
| 728 |
+
"score": -0.007257105316966772
|
| 729 |
+
},
|
| 730 |
+
{
|
| 731 |
+
"start": 44.84,
|
| 732 |
+
"end": 45.18,
|
| 733 |
+
"text": "all,",
|
| 734 |
+
"score": -0.21771717071533203
|
| 735 |
+
},
|
| 736 |
+
{
|
| 737 |
+
"start": 45.18,
|
| 738 |
+
"end": 45.56,
|
| 739 |
+
"text": "even",
|
| 740 |
+
"score": -0.042969994246959686
|
| 741 |
+
},
|
| 742 |
+
{
|
| 743 |
+
"start": 45.56,
|
| 744 |
+
"end": 46.0,
|
| 745 |
+
"text": "without",
|
| 746 |
+
"score": -1.3420182466506958
|
| 747 |
+
},
|
| 748 |
+
{
|
| 749 |
+
"start": 46.0,
|
| 750 |
+
"end": 46.08,
|
| 751 |
+
"text": "a",
|
| 752 |
+
"score": -0.13044703006744385
|
| 753 |
+
},
|
| 754 |
+
{
|
| 755 |
+
"start": 46.08,
|
| 756 |
+
"end": 46.4,
|
| 757 |
+
"text": "live",
|
| 758 |
+
"score": -0.05106182396411896
|
| 759 |
+
},
|
| 760 |
+
{
|
| 761 |
+
"start": 46.4,
|
| 762 |
+
"end": 47.06,
|
| 763 |
+
"text": "webcam,",
|
| 764 |
+
"score": -5.140846252441406
|
| 765 |
+
},
|
| 766 |
+
{
|
| 767 |
+
"start": 47.06,
|
| 768 |
+
"end": 47.8,
|
| 769 |
+
"text": "CANVID",
|
| 770 |
+
"score": -0.5264605283737183
|
| 771 |
+
},
|
| 772 |
+
{
|
| 773 |
+
"start": 47.8,
|
| 774 |
+
"end": 47.98,
|
| 775 |
+
"text": "can",
|
| 776 |
+
"score": -0.5820391774177551
|
| 777 |
+
},
|
| 778 |
+
{
|
| 779 |
+
"start": 47.98,
|
| 780 |
+
"end": 48.42,
|
| 781 |
+
"text": "create",
|
| 782 |
+
"score": -0.2533574402332306
|
| 783 |
+
},
|
| 784 |
+
{
|
| 785 |
+
"start": 48.42,
|
| 786 |
+
"end": 48.5,
|
| 787 |
+
"text": "a",
|
| 788 |
+
"score": -0.009362409822642803
|
| 789 |
+
},
|
| 790 |
+
{
|
| 791 |
+
"start": 48.5,
|
| 792 |
+
"end": 49.12,
|
| 793 |
+
"text": "realistic",
|
| 794 |
+
"score": -0.3582625687122345
|
| 795 |
+
},
|
| 796 |
+
{
|
| 797 |
+
"start": 49.12,
|
| 798 |
+
"end": 49.72,
|
| 799 |
+
"text": "synthetic",
|
| 800 |
+
"score": -3.055950403213501
|
| 801 |
+
},
|
| 802 |
+
{
|
| 803 |
+
"start": 49.72,
|
| 804 |
+
"end": 50.12,
|
| 805 |
+
"text": "camera",
|
| 806 |
+
"score": -0.5360308289527893
|
| 807 |
+
},
|
| 808 |
+
{
|
| 809 |
+
"start": 50.12,
|
| 810 |
+
"end": 50.54,
|
| 811 |
+
"text": "feed",
|
| 812 |
+
"score": -0.047034528106451035
|
| 813 |
+
},
|
| 814 |
+
{
|
| 815 |
+
"start": 50.54,
|
| 816 |
+
"end": 50.92,
|
| 817 |
+
"text": "from",
|
| 818 |
+
"score": -0.00998612493276596
|
| 819 |
+
},
|
| 820 |
+
{
|
| 821 |
+
"start": 50.92,
|
| 822 |
+
"end": 51.26,
|
| 823 |
+
"text": "your",
|
| 824 |
+
"score": -1.1579375267028809
|
| 825 |
+
},
|
| 826 |
+
{
|
| 827 |
+
"start": 51.26,
|
| 828 |
+
"end": 51.64,
|
| 829 |
+
"text": "best",
|
| 830 |
+
"score": -0.008270579390227795
|
| 831 |
+
},
|
| 832 |
+
{
|
| 833 |
+
"start": 51.64,
|
| 834 |
+
"end": 52.08,
|
| 835 |
+
"text": "previous",
|
| 836 |
+
"score": -0.07053256779909134
|
| 837 |
+
},
|
| 838 |
+
{
|
| 839 |
+
"start": 52.08,
|
| 840 |
+
"end": 52.88,
|
| 841 |
+
"text": "recording,",
|
| 842 |
+
"score": -0.04316838085651398
|
| 843 |
+
},
|
| 844 |
+
{
|
| 845 |
+
"start": 52.88,
|
| 846 |
+
"end": 53.36,
|
| 847 |
+
"text": "giving",
|
| 848 |
+
"score": -0.05326300114393234
|
| 849 |
+
},
|
| 850 |
+
{
|
| 851 |
+
"start": 53.38,
|
| 852 |
+
"end": 53.5,
|
| 853 |
+
"text": "your",
|
| 854 |
+
"score": -0.6395745277404785
|
| 855 |
+
},
|
| 856 |
+
{
|
| 857 |
+
"start": 53.5,
|
| 858 |
+
"end": 53.88,
|
| 859 |
+
"text": "videos",
|
| 860 |
+
"score": -0.6830635666847229
|
| 861 |
+
},
|
| 862 |
+
{
|
| 863 |
+
"start": 53.88,
|
| 864 |
+
"end": 53.94,
|
| 865 |
+
"text": "a",
|
| 866 |
+
"score": -0.03618127107620239
|
| 867 |
+
},
|
| 868 |
+
{
|
| 869 |
+
"start": 53.94,
|
| 870 |
+
"end": 54.68,
|
| 871 |
+
"text": "professional,",
|
| 872 |
+
"score": -0.36633795499801636
|
| 873 |
+
},
|
| 874 |
+
{
|
| 875 |
+
"start": 54.68,
|
| 876 |
+
"end": 55.24,
|
| 877 |
+
"text": "personal",
|
| 878 |
+
"score": -0.6981226801872253
|
| 879 |
+
},
|
| 880 |
+
{
|
| 881 |
+
"start": 55.24,
|
| 882 |
+
"end": 55.68,
|
| 883 |
+
"text": "touch",
|
| 884 |
+
"score": -0.7542499899864197
|
| 885 |
+
},
|
| 886 |
+
{
|
| 887 |
+
"start": 55.68,
|
| 888 |
+
"end": 56.02,
|
| 889 |
+
"text": "every",
|
| 890 |
+
"score": -0.4383160471916199
|
| 891 |
+
},
|
| 892 |
+
{
|
| 893 |
+
"start": 56.02,
|
| 894 |
+
"end": 56.4,
|
| 895 |
+
"text": "time.",
|
| 896 |
+
"score": -0.043773457407951355
|
| 897 |
+
}
|
| 898 |
+
]
|
| 899 |
+
}
|