Skip to content

Commit c2a3db9

Browse files
committed
chore: rebrand project to realtime-dual-transcriber
1 parent b59670c commit c2a3db9

8 files changed

Lines changed: 171 additions & 119 deletions

File tree

.env.example

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ GROQ_TRANSLATION_MODEL=llama-3.1-8b-instant
88
# GROQ_TRANSCRIPTION_PROMPT=Conversation with technical terms and product names.
99

1010
# Optional realtime tuning
11-
# ECOUTE_RECORD_TIMEOUT=1.4
12-
# ECOUTE_PHRASE_TIMEOUT=5.0
13-
# ECOUTE_PAUSE_THRESHOLD=0.65
14-
# ECOUTE_MIN_AUDIO_SECONDS=0.45
15-
# ECOUTE_MIN_AUDIO_RMS=120
16-
# ECOUTE_TRANSLATION_SILENCE_DELAY=5.0
11+
# RTDT_RECORD_TIMEOUT=1.4
12+
# RTDT_PHRASE_TIMEOUT=5.0
13+
# RTDT_PAUSE_THRESHOLD=0.65
14+
# RTDT_MIN_AUDIO_SECONDS=0.45
15+
# RTDT_MIN_AUDIO_RMS=120
16+
# RTDT_TRANSLATION_SILENCE_DELAY=5.0

.github/FUNDING.yml

Lines changed: 0 additions & 1 deletion
This file was deleted.

AudioRecorder.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ def get_config(name, default):
4646
return str(value)
4747

4848

49-
RECORD_TIMEOUT = float(get_config("ECOUTE_RECORD_TIMEOUT", "1.4"))
50-
ENERGY_THRESHOLD = int(get_config("ECOUTE_ENERGY_THRESHOLD", "300"))
51-
DYNAMIC_ENERGY_THRESHOLD = get_config("ECOUTE_DYNAMIC_ENERGY_THRESHOLD", "1") != "0"
52-
PAUSE_THRESHOLD = float(get_config("ECOUTE_PAUSE_THRESHOLD", "0.65"))
53-
PHRASE_THRESHOLD = float(get_config("ECOUTE_PHRASE_THRESHOLD_SECONDS", "0.25"))
54-
NON_SPEAKING_DURATION = float(get_config("ECOUTE_NON_SPEAKING_DURATION", "0.35"))
55-
NOISE_ADJUST_SECONDS = float(get_config("ECOUTE_NOISE_ADJUST_SECONDS", "0.6"))
49+
RECORD_TIMEOUT = float(get_config("RTDT_RECORD_TIMEOUT", "1.4"))
50+
ENERGY_THRESHOLD = int(get_config("RTDT_ENERGY_THRESHOLD", "300"))
51+
DYNAMIC_ENERGY_THRESHOLD = get_config("RTDT_DYNAMIC_ENERGY_THRESHOLD", "1") != "0"
52+
PAUSE_THRESHOLD = float(get_config("RTDT_PAUSE_THRESHOLD", "0.65"))
53+
PHRASE_THRESHOLD = float(get_config("RTDT_PHRASE_THRESHOLD_SECONDS", "0.25"))
54+
NON_SPEAKING_DURATION = float(get_config("RTDT_NON_SPEAKING_DURATION", "0.35"))
55+
NOISE_ADJUST_SECONDS = float(get_config("RTDT_NOISE_ADJUST_SECONDS", "0.6"))
5656

5757

5858
class BaseRecorder:

AudioTranscriber.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ def get_config(name, default):
5454
return str(value)
5555

5656

57-
PHRASE_TIMEOUT = float(get_config("ECOUTE_PHRASE_TIMEOUT", "5.0"))
58-
MAX_PHRASES = int(get_config("ECOUTE_MAX_PHRASES", "12"))
59-
MIN_AUDIO_SECONDS = float(get_config("ECOUTE_MIN_AUDIO_SECONDS", "0.45"))
60-
MIN_AUDIO_RMS = int(get_config("ECOUTE_MIN_AUDIO_RMS", "120"))
57+
PHRASE_TIMEOUT = float(get_config("RTDT_PHRASE_TIMEOUT", "5.0"))
58+
MAX_PHRASES = int(get_config("RTDT_MAX_PHRASES", "12"))
59+
MIN_AUDIO_SECONDS = float(get_config("RTDT_MIN_AUDIO_SECONDS", "0.45"))
60+
MIN_AUDIO_RMS = int(get_config("RTDT_MIN_AUDIO_RMS", "120"))
6161
TRANSLATION_SILENCE_DELAY = max(
6262
PHRASE_TIMEOUT,
63-
float(get_config("ECOUTE_TRANSLATION_SILENCE_DELAY", str(PHRASE_TIMEOUT))),
63+
float(get_config("RTDT_TRANSLATION_SILENCE_DELAY", str(PHRASE_TIMEOUT))),
6464
)
6565
TRANSLATION_WAITING_TEXT = "⏳ Menunggu pembicara berhenti..."
6666
TRANSLATION_RUNNING_TEXT = "Menerjemahkan..."
@@ -85,7 +85,7 @@ def __init__(self, mic_source, speaker_source, model):
8585
self.transcript_data = {"You": [], "Speaker": []}
8686
self.transcript_changed_event = threading.Event()
8787
self.audio_model = model
88-
self.debug = os.environ.get("ECOUTE_DEBUG", "0") == "1"
88+
self.debug = os.environ.get("RTDT_DEBUG", "0") == "1"
8989
self.lock = threading.RLock()
9090
self.revision = 0
9191
self.next_transcript_id = 1

README.md

Lines changed: 145 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,204 @@
1+
# realtime-dual-transcriber
12

2-
# 🎧 Ecoute
3+
realtime-dual-transcriber is a Windows desktop application for live transcription from two audio sources at the same time:
34

4-
Ecoute is a live transcription tool that provides real-time transcripts for both the user's microphone input (You) and the user's speakers output (Speaker) in a textbox.
5+
- microphone input, shown as `You`
6+
- system speaker output, shown as `Speaker`
57

6-
## Sponsored By: Recall.ai - Meeting Transcription API
8+
The application displays a real-time transcript in a desktop UI and can optionally use an OpenAI-compatible API provider such as Groq for faster multilingual transcription and Indonesian translation.
79

8-
If you’re working with speech detection or transcription for meetings, consider checking out [Recall.ai](https://www.recall.ai/product/meeting-transcription-api/?utm_source=github&utm_medium=sponsorship&utm_campaign=sevask-ecoute), an API that works with Zoom, Google Meet, Microsoft Teams, and more. Recall.ai diarizes by pulling the speaker data and separate audio streams from the meeting platforms, which means 100% accurate speaker diarization with actual speaker names and speaker emails.
10+
## Key Features
911

10-
## 📖 Demo
12+
- Dual-source transcription for microphone and speaker audio
13+
- Desktop interface built with CustomTkinter
14+
- WASAPI loopback support for capturing default speaker output on Windows
15+
- Local transcription mode with Faster Whisper
16+
- API transcription mode with Groq or another OpenAI-compatible endpoint
17+
- Optional Indonesian translation for each finalized transcript block
18+
- Configurable silence delay, phrase timeout, audio filtering, and transcription model
19+
- Secret-safe local configuration through `.env` or `keys.py`
20+
- Built-in unit tests for transcript state and API authentication handling
1121

12-
https://github.com/user-attachments/assets/5616421f-838d-439f-8b15-0df7b8d33459
22+
## Repository
1323

14-
Ecoute is designed to help users in their conversations by providing live transcriptions.
24+
```powershell
25+
git clone https://github.com/Diyoncrz18/realtime-dual-transcriber.git
26+
cd realtime-dual-transcriber
27+
```
1528

16-
## 🚀 Getting Started
29+
## Requirements
1730

18-
Follow these steps to set up and run Ecoute on your local machine.
31+
- Windows 10 or Windows 11
32+
- Python 3.8 or newer
33+
- FFmpeg available on `PATH`
34+
- Working microphone and default speaker device
35+
- Optional: Groq or OpenAI-compatible API key for API mode
1936

20-
### 📋 Prerequisites
37+
Install FFmpeg with Chocolatey:
2138

22-
- Python >=3.8.0
23-
- (Optional) An OpenAI API key that can access Whisper API (set up a paid account OpenAI account)
24-
- Windows OS (Not tested on others)
25-
- FFmpeg
39+
```powershell
40+
choco install ffmpeg
41+
```
2642

27-
If FFmpeg is not installed in your system, you can follow the steps below to install it.
43+
Or install FFmpeg manually and make sure `ffmpeg.exe` is available from PowerShell:
2844

29-
First, you need to install Chocolatey, a package manager for Windows. Open your PowerShell as Administrator and run the following command:
45+
```powershell
46+
ffmpeg -version
3047
```
31-
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
32-
```
33-
Once Chocolatey is installed, you can install FFmpeg by running the following command in your PowerShell:
34-
```
35-
choco install ffmpeg
48+
49+
## Installation
50+
51+
Create and activate a virtual environment:
52+
53+
```powershell
54+
python -m venv .venv
55+
.\.venv\Scripts\Activate.ps1
3656
```
37-
Please ensure that you run these commands in a PowerShell window with administrator privileges. If you face any issues during the installation, you can visit the official Chocolatey and FFmpeg websites for troubleshooting.
3857

39-
### 🔧 Installation
58+
Install dependencies:
4059

41-
1. Clone the repository:
60+
```powershell
61+
python -m pip install --upgrade pip
62+
pip install -r requirements.txt
63+
```
4264

43-
```
44-
git clone https://github.com/SevaSk/ecoute
45-
```
65+
## Configuration
4666

47-
2. Navigate to the `ecoute` folder:
67+
The recommended configuration method is `.env`.
4868

49-
```
50-
cd ecoute
51-
```
69+
```powershell
70+
Copy-Item .env.example .env
71+
```
5272

53-
3. Install the required packages:
73+
Edit `.env` and replace placeholder values with your own credentials.
5474

55-
```
56-
pip install -r requirements.txt
57-
```
58-
59-
4. (Optional) Configure API credentials locally.
75+
Groq example:
6076

61-
The safest option is to copy the example environment file and add your real API key to `.env`:
77+
```env
78+
GROQ_API_KEY=your-groq-api-key-here
79+
GROQ_TRANSCRIPTION_MODEL=whisper-large-v3-turbo
80+
GROQ_TRANSLATION_MODEL=llama-3.1-8b-instant
81+
```
6282

63-
```
64-
Copy-Item .env.example .env
65-
```
83+
OpenAI-compatible endpoint example:
6684

67-
Example Groq setup:
85+
```env
86+
OPENAI_API_KEY=your-openai-compatible-api-key
87+
OPENAI_BASE_URL=https://your-provider.example/v1
88+
OPENAI_TRANSCRIPTION_MODEL=whisper-1
89+
```
6890

69-
```
70-
GROQ_API_KEY=your-groq-api-key-here
71-
GROQ_TRANSCRIPTION_MODEL=whisper-large-v3-turbo
72-
GROQ_TRANSLATION_MODEL=llama-3.1-8b-instant
73-
```
91+
You can also configure credentials through `keys.py`:
7492

75-
Example OpenAI-compatible setup:
93+
```powershell
94+
Copy-Item keys.example.py keys.py
95+
```
7696

77-
```
78-
OPENAI_API_KEY=your-openai-api-key-here
79-
OPENAI_BASE_URL=https://your-custom-api.example/v1
80-
OPENAI_TRANSCRIPTION_MODEL=whisper-1
81-
```
97+
Keep real credentials local. `.env` and `keys.py` are ignored by Git and should never be committed.
8298

83-
You can also use `CUSTOM_API_KEY`, `CUSTOM_API_URL`, and `CUSTOM_API_TRANSCRIPTION_MODEL` with the same values.
99+
## Runtime Tuning
84100

85-
If you prefer Python config, copy `keys.example.py` to `keys.py` and put your real values there.
86-
Do not commit `.env` or `keys.py`; both files are ignored by `.gitignore`.
101+
These values are optional and can be added to `.env` when needed:
87102

88-
If you see `Invalid API Key` or `expired_api_key`, create a new provider key and replace the old value in `.env` or `keys.py`, then restart Ecoute.
103+
```env
104+
GROQ_TRANSCRIPTION_LANGUAGE=id
105+
GROQ_TRANSCRIPTION_TEMPERATURE=0
106+
GROQ_TRANSCRIPTION_PROMPT=Conversation with technical terms and product names.
89107
90-
Optional tuning:
108+
RTDT_RECORD_TIMEOUT=1.4
109+
RTDT_PHRASE_TIMEOUT=5.0
110+
RTDT_PAUSE_THRESHOLD=0.65
111+
RTDT_MIN_AUDIO_SECONDS=0.45
112+
RTDT_MIN_AUDIO_RMS=120
113+
RTDT_TRANSLATION_SILENCE_DELAY=5.0
114+
```
91115

92-
```
93-
GROQ_TRANSCRIPTION_MODEL=whisper-large-v3
94-
GROQ_TRANSCRIPTION_LANGUAGE=id
95-
GROQ_TRANSCRIPTION_TEMPERATURE=0
96-
GROQ_TRANSCRIPTION_PROMPT=Conversation with technical terms and product names.
97-
```
116+
Model recommendation:
98117

99-
Use `whisper-large-v3-turbo` for lower latency, or `whisper-large-v3` when accuracy matters more.
118+
- `whisper-large-v3-turbo` for lower latency
119+
- `whisper-large-v3` for higher accuracy
100120

101-
A new transcript block is created only after a mic or speaker segment has been quiet for about 5 seconds. Tune that delay with:
121+
## Running the Application
102122

103-
```
104-
ECOUTE_RECORD_TIMEOUT=1.4
105-
ECOUTE_PHRASE_TIMEOUT=5.0
106-
ECOUTE_TRANSLATION_SILENCE_DELAY=5.0
107-
```
123+
Run local transcription mode:
108124

109-
### 🎬 Running Ecoute
125+
```powershell
126+
.\.venv\Scripts\python.exe main.py
127+
```
110128

111-
Run the main script:
129+
Run API transcription mode:
112130

131+
```powershell
132+
.\.venv\Scripts\python.exe main.py --api
113133
```
114-
python main.py
134+
135+
API mode is recommended when you need better multilingual support, faster transcription, and Indonesian translation.
136+
137+
## How It Works
138+
139+
1. `AudioRecorder.py` captures microphone audio and default speaker loopback audio.
140+
2. `AudioTranscriber.py` filters short or silent audio, merges phrase fragments, and manages transcript state.
141+
3. `TranscriberModels.py` routes transcription to either Faster Whisper or an OpenAI-compatible API provider.
142+
4. `main.py` renders the live transcript UI and refreshes it as transcript revisions change.
143+
144+
## Project Structure
145+
146+
```text
147+
.
148+
|-- AudioRecorder.py # Microphone and speaker recording
149+
|-- AudioTranscriber.py # Transcript state, merging, filtering, translation queue
150+
|-- TranscriberModels.py # Local and API transcription providers
151+
|-- main.py # Desktop UI entry point
152+
|-- custom_speech_recognition/ # Speech recognition compatibility layer
153+
|-- tests/ # Unit tests
154+
|-- .env.example # Environment variable template
155+
|-- keys.example.py # Python credential template
156+
|-- requirements.txt # Python dependencies
157+
`-- README.md # Project documentation
115158
```
116159

117-
For a more better and faster version that also works with most languages, use:
160+
## Testing
161+
162+
Run the unit test suite:
118163

164+
```powershell
165+
.\.venv\Scripts\python.exe -m unittest discover -s tests
119166
```
120-
python main.py --api
167+
168+
Compile-check the main Python files:
169+
170+
```powershell
171+
.\.venv\Scripts\python.exe -m py_compile main.py AudioRecorder.py AudioTranscriber.py TranscriberModels.py
121172
```
122173

123-
Upon initiation, Ecoute will begin transcribing your microphone input and speaker output in real-time. Please note that it might take a few seconds for the system to warm up before the transcription becomes real-time.
174+
## Troubleshooting
124175

125-
The --api flag will use the whisper api for transcriptions. This significantly enhances transcription speed and accuracy, and it works in most languages (rather than just English without the flag). It's expected to become the default option in future releases. However, keep in mind that using the Whisper API will consume more OpenAI credits than using the local model. This increased cost is attributed to the advanced features and capabilities that the Whisper API provides. Despite the additional expense, the substantial improvements in speed and transcription accuracy may make it a worthwhile investment for your use case.
176+
### Invalid or expired API key
126177

127-
### ✅ Testing
178+
If the terminal shows `Invalid API Key` or `expired_api_key`, create a new provider key, update `.env` or `keys.py`, and restart the application.
128179

129-
Run the unit tests with:
180+
### FFmpeg not found
130181

131-
```
132-
python -m unittest discover -s tests
133-
```
182+
Make sure FFmpeg is installed and available from PowerShell:
134183

135-
### ⚠️ Limitations
184+
```powershell
185+
ffmpeg -version
186+
```
136187

137-
While Ecoute provides real-time transcription and response suggestions, there are several known limitations to its functionality that you should be aware of:
188+
### Speaker audio is not captured
138189

139-
**Default Mic and Speaker:** Ecoute is currently configured to listen only to the default microphone and speaker set in your system. It will not detect sound from other devices or systems. If you wish to use a different mic or speaker, you will need to set it as your default device in your system settings.
190+
The application captures the default Windows speaker output through WASAPI loopback. Set the target output device as the Windows default speaker before starting the app.
140191

141-
**Whisper Model**: If the --api flag is not used, we utilize the 'tiny' version of the Whisper ASR model, due to its low resource consumption and fast response times. However, this model may not be as accurate as the larger models in transcribing certain types of speech, including accents or uncommon words.
192+
### Transcription is delayed
142193

143-
**Language**: If you are not using the --api flag the Whisper model used in Ecoute is set to English. As a result, it may not accurately transcribe non-English languages or dialects. We are actively working to add multi-language support to future versions of the program.
194+
Transcript blocks are finalized after a silence delay. Lower `RTDT_TRANSLATION_SILENCE_DELAY` and `RTDT_PHRASE_TIMEOUT` for faster updates, or increase them for more stable sentence grouping.
144195

145-
## 📖 License
196+
## Security Notes
146197

147-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
198+
- Do not commit `.env`, `keys.py`, model files, recordings, or logs.
199+
- The repository includes a GitHub Actions secret scan for common API key patterns.
200+
- If a real API key was ever committed, revoke it immediately and create a new one.
148201

149-
## 🤝 Contributing
202+
## Maintainer
150203

151-
Contributions are welcome! Feel free to open issues or submit pull requests to improve Ecoute.
204+
Maintained by `Diyoncrz18`.

TranscriberModels.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def __init__(self, api_key=None, base_url=None, model=None):
109109
"CUSTOM_API_TRANSCRIPTION_TEMPERATURE",
110110
default=0.0,
111111
)
112-
self.translation_enabled = self._get_config("ECOUTE_ENABLE_TRANSLATION", default="1") != "0"
112+
self.translation_enabled = self._get_config("RTDT_ENABLE_TRANSLATION", default="1") != "0"
113113
self.last_error = None
114114
self.last_error_time = 0
115115
self.api_available = True
@@ -282,7 +282,7 @@ def _disable_api_after_auth_error(self, error):
282282
self.auth_error_logged = True
283283
print(
284284
"[ERROR] API key rejected by provider. "
285-
"Update GROQ_API_KEY in .env or keys.py, then restart Ecoute. "
285+
"Update GROQ_API_KEY in .env or keys.py, then restart realtime-dual-transcriber. "
286286
f"Provider response: {error}"
287287
)
288288

keys.example.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
# GROQ_TRANSCRIPTION_LANGUAGE = "id"
77
# GROQ_TRANSCRIPTION_TEMPERATURE = "0"
88
# GROQ_TRANSCRIPTION_PROMPT = "Conversation with technical terms and product names."
9-
# ECOUTE_RECORD_TIMEOUT = "1.4"
10-
# ECOUTE_PHRASE_TIMEOUT = "5.0"
11-
# ECOUTE_TRANSLATION_SILENCE_DELAY = "5.0"
9+
# RTDT_RECORD_TIMEOUT = "1.4"
10+
# RTDT_PHRASE_TIMEOUT = "5.0"
11+
# RTDT_TRANSLATION_SILENCE_DELAY = "5.0"

0 commit comments

Comments
 (0)