-
Notifications
You must be signed in to change notification settings - Fork 12
Added multilingual caption support #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| """ | ||
| Shared subtitle utilities for Smallest AI Speech-to-Text applications. | ||
|
|
||
| This module provides reusable functions for generating SRT and VTT subtitle | ||
| formats with proper timestamp formatting. | ||
| """ | ||
|
|
||
| from typing import List, Dict, Callable, Optional | ||
|
|
||
|
|
||
| def format_timestamp_srt(seconds: float) -> str: | ||
| """ | ||
| Format seconds to SRT timestamp format: HH:MM:SS,mmm | ||
|
|
||
| Args: | ||
| seconds: Time in seconds (can be float) | ||
|
|
||
| Returns: | ||
| Formatted timestamp string in SRT format | ||
|
|
||
| Example: | ||
| >>> format_timestamp_srt(65.123) | ||
| '00:01:05,123' | ||
| """ | ||
| ms = int(seconds * 1000) | ||
| hours, ms = divmod(ms, 3600 * 1000) | ||
| minutes, ms = divmod(ms, 60 * 1000) | ||
| secs, ms = divmod(ms, 1000) | ||
| return f"{hours:02d}:{minutes:02d}:{secs:02d},{ms:03d}" | ||
|
Comment on lines
+11
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate Code: This function 📍 Original Location: Function: 💡 Recommendation: Consider importing and reusing the existing function instead of duplicating the logic. |
||
|
|
||
|
|
||
| def format_timestamp_vtt(seconds: float) -> str: | ||
|
hemant838 marked this conversation as resolved.
|
||
| """ | ||
| Format seconds to VTT timestamp format: HH:MM:SS.mmm | ||
|
|
||
| Args: | ||
| seconds: Time in seconds (can be float) | ||
|
|
||
| Returns: | ||
| Formatted timestamp string in VTT format | ||
|
|
||
| Example: | ||
| >>> format_timestamp_vtt(65.123) | ||
| '00:01:05.123' | ||
| """ | ||
| ms = int(seconds * 1000) | ||
| hours, ms = divmod(ms, 3600 * 1000) | ||
| minutes, ms = divmod(ms, 60 * 1000) | ||
| secs, ms = divmod(ms, 1000) | ||
| return f"{hours:02d}:{minutes:02d}:{secs:02d}.{ms:03d}" | ||
|
Comment on lines
+32
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate Code: This function 📍 Original Location: Function: 💡 Recommendation: Consider importing and reusing the existing function instead of duplicating the logic. |
||
|
|
||
|
|
||
| def generate_srt( | ||
|
hemant838 marked this conversation as resolved.
|
||
| entries: List[Dict], | ||
| text_key: str = "text", | ||
| start_key: str = "start", | ||
| end_key: str = "end", | ||
| format_func: Optional[Callable[[float], str]] = None | ||
| ) -> str: | ||
| """ | ||
| Generate SRT format subtitles from a list of entries. | ||
|
|
||
| Args: | ||
| entries: List of dictionaries containing subtitle data | ||
| text_key: Key name for the text content in each entry | ||
| start_key: Key name for the start timestamp in each entry | ||
| end_key: Key name for the end timestamp in each entry | ||
| format_func: Optional custom timestamp formatting function. | ||
| Defaults to format_timestamp_srt. | ||
|
|
||
| Returns: | ||
| Complete SRT subtitle string | ||
|
|
||
| Example: | ||
| >>> entries = [ | ||
| ... {"text": "Hello", "start": 0.0, "end": 1.5}, | ||
| ... {"text": "World", "start": 1.5, "end": 3.0} | ||
| ... ] | ||
| >>> print(generate_srt(entries)) | ||
| 1 | ||
| 00:00:00,000 --> 00:00:01,500 | ||
| Hello | ||
|
|
||
| 2 | ||
| 00:00:01,500 --> 00:00:03,000 | ||
| World | ||
| """ | ||
| if format_func is None: | ||
| format_func = format_timestamp_srt | ||
|
|
||
| lines = [] | ||
| for idx, entry in enumerate(entries, start=1): | ||
| start = format_func(entry[start_key]) | ||
| end = format_func(entry[end_key]) | ||
| lines.append(str(idx)) | ||
| lines.append(f"{start} --> {end}") | ||
| lines.append(entry[text_key]) | ||
| lines.append("") | ||
|
|
||
| return "\n".join(lines).strip() | ||
|
|
||
|
|
||
| def generate_vtt( | ||
|
hemant838 marked this conversation as resolved.
|
||
| entries: List[Dict], | ||
| text_key: str = "text", | ||
| start_key: str = "start", | ||
| end_key: str = "end", | ||
| format_func: Optional[Callable[[float], str]] = None | ||
| ) -> str: | ||
| """ | ||
| Generate WebVTT format subtitles from a list of entries. | ||
|
|
||
| Args: | ||
| entries: List of dictionaries containing subtitle data | ||
| text_key: Key name for the text content in each entry | ||
| start_key: Key name for the start timestamp in each entry | ||
| end_key: Key name for the end timestamp in each entry | ||
| format_func: Optional custom timestamp formatting function. | ||
| Defaults to format_timestamp_vtt. | ||
|
|
||
| Returns: | ||
| Complete WebVTT subtitle string | ||
|
|
||
| Example: | ||
| >>> entries = [ | ||
| ... {"text": "Hello", "start": 0.0, "end": 1.5}, | ||
| ... {"text": "World", "start": 1.5, "end": 3.0} | ||
| ... ] | ||
| >>> print(generate_vtt(entries)) | ||
| WEBVTT | ||
|
|
||
| 1 | ||
| 00:00:00.000 --> 00:00:01.500 | ||
| Hello | ||
|
|
||
| 2 | ||
| 00:00:01.500 --> 00:00:03.000 | ||
| World | ||
| """ | ||
| if format_func is None: | ||
| format_func = format_timestamp_vtt | ||
|
|
||
| lines = ["WEBVTT", ""] | ||
| for idx, entry in enumerate(entries, start=1): | ||
| start = format_func(entry[start_key]) | ||
| end = format_func(entry[end_key]) | ||
| lines.append(str(idx)) | ||
| lines.append(f"{start} --> {end}") | ||
| lines.append(entry[text_key]) | ||
| lines.append("") | ||
|
|
||
| return "\n".join(lines).strip() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Smallest AI API Key | ||
| SMALLEST_API_KEY=your-smallest-api-key | ||
|
|
||
| # Optional: translation (falls back to source if unset) | ||
| OPENAI_API_KEY=your-openai-api-key |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| # Multilingual Live Captions | ||
|
|
||
| Auto-detect spoken language, translate on the fly, and preview SRT captions for live events or streams. | ||
|
|
||
| ## Features | ||
|
|
||
| - Automatic language detection (`language=multi`) with Pulse STT | ||
| - Live translation to a chosen subtitle language | ||
| - Instant SRT preview you can copy into players/overlays | ||
| - Works from your microphone via WebSocket streaming | ||
|
|
||
| ## Requirements | ||
|
|
||
| > Base dependencies are installed via the root `requirements.txt`. See the [main README](../../../README.md#usage) for setup. Add `SMALLEST_API_KEY` to your `.env`. | ||
|
|
||
| Extra dependencies: | ||
|
|
||
| ```bash | ||
| uv pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| This installs `numpy` (used for lightweight resampling). Translation uses OpenAI if `OPENAI_API_KEY` is set; otherwise it falls back to source text. | ||
|
|
||
| ## Usage | ||
|
|
||
| ```bash | ||
| uv run app.py | ||
| ``` | ||
|
|
||
| Then open http://localhost:7860 and: | ||
|
|
||
| 1. Choose subtitle language (e.g., English) | ||
| 2. Click microphone and speak — transcript + translation update live | ||
| 3. Copy SRT preview into your caption tool or player | ||
| 4. Click **Stop & Clear** to reset | ||
|
|
||
| ## Recommended Usage | ||
|
|
||
| - Live captions for multilingual events or webinars | ||
| - Streaming overlays that need translated subtitles quickly | ||
| - As a building block for hybrid ASR + translation caption services | ||
|
|
||
| ## How It Works | ||
|
|
||
| - Streams mic audio to Pulse STT over WebSocket with `language=multi` | ||
| - Receives partial/final transcripts with detected language metadata | ||
| - Runs on-the-fly translation via OpenAI (if configured) | ||
| - Accumulates segments and renders an SRT preview for copy/paste | ||
|
|
||
| ## Configuration | ||
|
|
||
| | Setting | Default | Description | | ||
| | ----------------- | --------- | ------------------------------------------------------------- | | ||
| | `language` | `multi` | Enables automatic language detection | | ||
| | Subtitle dropdown | `English` | Target translation language (`Same as source` keeps original) | | ||
| | Sample rate | 16000 Hz | Resampled client-side if needed | | ||
|
|
||
| ## Example Output (SRT) | ||
|
|
||
| ``` | ||
| 1 | ||
| 00:00:00,000 --> 00:00:03,400 | ||
| Welcome to the live demo. | ||
|
|
||
| 2 | ||
| 00:00:03,400 --> 00:00:06,200 | ||
| Here are your translated captions. | ||
| ``` | ||
|
|
||
| ## API Reference | ||
|
|
||
| - [Streaming Quickstart](https://waves-docs.smallest.ai/v4.0.0/content/speech-to-text-new/streaming/quickstart) | ||
| - [Pulse STT WebSocket API](https://waves-docs.smallest.ai/content/api-references/pulse-stt-ws) | ||
|
|
||
| ## Next Steps | ||
|
|
||
| - [Realtime Microphone Transcription](../realtime-microphone-transcription/) — Basic live STT without translation | ||
| - [Jarvis Voice Assistant](../jarvis/) — Full assistant with wake word, LLM, and TTS |
Uh oh!
There was an error while loading. Please reload this page.