Skip to content

Commit 5400cac

Browse files
Merge pull request #2847 from odinshen-git/feature/dgx_spark_voicechatbot
New LP: Offline Voice Chatbot with FasterWhisper and vLLM on DGX Spark
2 parents 604d836 + c40db57 commit 5400cac

10 files changed

Lines changed: 1982 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
title: Understanding Offline Voice Assistants
3+
weight: 2
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
## Why Build an Offline Voice Assistant?
10+
11+
Voice-based AI assistants are becoming essential in customer support, productivity tools, and embedded interfaces. For example, a retail kiosk might need to answer product-related questions verbally without relying on internet access. However, many of these systems depend heavily on cloud services for speech recognition and language understanding, raising concerns around latency, cost, and data privacy.
12+
13+
In addition, a healthcare terminal or legal consultation assistant may need to handle voice queries involving sensitive personal information, where sending audio data to the cloud would violate privacy requirements. Running your voice assistant entirely offline solves these problems.
14+
15+
You avoid unpredictable latency caused by network fluctuations, prevent sensitive voice data from leaving the local machine, and eliminate recurring API costs that make large-scale deployment expensive. It also boosts trust for on-device deployments and compliance-sensitive industries.
16+
17+
By combining local speech-to-text (STT) with a locally hosted large language model (LLM), you gain full control over the pipeline and eliminate API dependencies. This gives you full control to experiment, customize, and scale—without relying on external APIs.
18+
19+
## Common Development Challenges:
20+
21+
While the benefits are clear, building a local voice assistant involves several engineering challenges:
22+
23+
- Managing audio stream segmentation and speech detection in real-time: It's hard to reliably identify when the user starts and stops speaking, especially with natural pauses and background noise.
24+
25+
- Avoiding latency or misfires in STT/LLM integration: Timing mismatches can cause delayed responses or repeated input, reducing the conversational quality.
26+
27+
- Keeping the pipeline responsive on local hardware without overloading resources: You need to carefully balance CPU/GPU workloads so that inference doesn't block audio capture or processing.
28+
29+
## Why use Arm and DGX Spark?
30+
31+
Arm-powered platforms like [DGX Spark](https://www.nvidia.com/en-gb/products/workstations/dgx-spark/) allow efficient parallelism: use CPU cores for audio preprocessing and whisper inference, while offloading LLM reasoning to powerful GPUs. This architecture balances throughput and energy efficiency—ideal for private, on-prem AI workloads. Check this [learning path](https://learn.arm.com/learning-paths/laptops-and-desktops/dgx_spark_llamacpp/1_gb10_introduction/) to understand the CPU and GPU architecture of DGX Spark.
32+
33+
DGX Spark also supports standard USB interfaces, making it easy to connect consumer-grade microphones for development or deployment. This makes it viable not just for data center use, but also for edge inference or desktop-style prototyping.
34+
35+
In this Learning Path, you’ll build a complete, offline voice chatbot prototype using PyAudio, faster-whisper, and vLLM on an Arm-based system—resulting in a fully functional assistant that runs entirely on local hardware with no internet dependency.
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
---
2+
title: Installing faster-whisper for Local Speech Recognition
3+
weight: 3
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
## Installing faster-whisper for Local Speech Recognition
10+
11+
[Faster‑whisper](https://github.com/SYSTRAN/faster-whisper) is a high‑performance reimplementation of OpenAI Whisper, designed to significantly reduce transcription latency and memory usage. It is well suited for local and real‑time speech‑to‑text (STT) pipelines, especially when running on CPU‑only systems or hybrid CPU/GPU environments.
12+
13+
In this Learning Path, faster‑whisper serves as the STT engine that converts raw microphone input into structured text. At this stage, the goal is to install faster‑whisper correctly and verify that it can transcribe audio reliably. Detailed tuning and integration will be covered in later modules.
14+
15+
### Install build dependencies
16+
17+
While some Python packages such as sounddevice and webrtcvad previously had compatibility issues with newer Python versions, these have been resolved. This Learning Path uses ***Python 3.12***, which has been tested and confirmed to work reliably with all required dependencies.
18+
19+
Install Python 3.12 and build dependencies:
20+
21+
```bash
22+
sudo apt update
23+
sudo apt install python3.12 python3.12-venv python3.12-dev -y
24+
sudo apt install portaudio19-dev ffmpeg -y
25+
```
26+
27+
### Create and Activate Python Environment
28+
29+
In particular, [pyaudio](https://pypi.org/project/PyAudio/) (used for real-time microphone capture) depends on the PortAudio library and the Python C API. These must match the version of Python you're using.
30+
31+
Now that the system libraries are in place and audio input is verified, it's time to set up an isolated Python environment for your voice assistant project. This will prevent dependency conflicts and make your installation reproducible.
32+
33+
```bash
34+
python3.12 -m venv voice_ass_env
35+
source voice_ass_env/bin/activate
36+
python3 -m pip install --upgrade pip
37+
```
38+
39+
Before install the package, it will be worst to check the Python version in your virtual environment.
40+
41+
```bash
42+
python3 --version
43+
```
44+
45+
Expected output should be `3.12.x` or higher.
46+
```log
47+
Python 3.12.3
48+
```
49+
50+
Install required Python packages:
51+
52+
```bash
53+
pip install pyaudio numpy torch faster-whisper
54+
pip install requests webrtcvad sounddevice==0.5.3
55+
```
56+
57+
{{% notice Note %}}
58+
While sounddevice==0.5.4 is available, it introduces callback-related errors during audio stream cleanup that may confuse beginners.
59+
For this Learning Path, we recommend sounddevice==0.5.3, which is stable and avoids these warnings.
60+
{{% /notice %}}
61+
62+
Verify the pyaudio version by:
63+
```bash
64+
python -c "import pyaudio; print(pyaudio.__version__)"
65+
```
66+
67+
Expected output should be:
68+
```log
69+
0.2.14
70+
```
71+
72+
### Verify microphone input
73+
74+
Once your system dependencies are installed, you can test that your audio hardware is functioning properly. This ensures that your audio input is accessible by Python through the sounddevice module.
75+
76+
Now plug in your USB microphone and run the following Python code to verify that it is detected and functioning correctly:
77+
78+
```python
79+
import sounddevice as sd
80+
import numpy as np
81+
82+
SAMPLE_RATE = 16000
83+
DURATION = 5
84+
85+
print(" Start recording for 5 seconds...")
86+
with sd.InputStream(samplerate=SAMPLE_RATE, channels=1, dtype='float32') as stream:
87+
audio = stream.read(int(SAMPLE_RATE * DURATION))[0]
88+
print(" Recording complete.")
89+
90+
print(" Playing back...")
91+
sd.play(audio, samplerate=SAMPLE_RATE)
92+
sd.wait()
93+
print(" Playback complete.")
94+
```
95+
96+
DGX Spark will record the audio for 5 seconds and immediately play back the captured audio.
97+
If you do not hear any playback, check your USB connection and verify the installation steps above.
98+
99+
Once you’ve confirmed that your microphone is working and your environment is set up, you’re ready to test real-time transcription and move on to the next phase.
100+
101+
### Sample: Real-time Transcription with faster-whisper
102+
103+
Now let's verify that your Whisper model works with live microphone input. This example records a 10-second audio clip using the system microphone, transcribes it using faster-whisper, and prints the transcribed text with timestamps.
104+
105+
This script records a fixed-duration mono audio clip using the sounddevice module and transcribes it using the faster-whisper model. The overall flow includes several key steps:
106+
- The `record_audio()` function starts the microphone and records a 10-second audio segment, returning the data as a NumPy array.
107+
- The `WhisperModel("small.en")` call loads the ***small English model*** from faster-whisper, using `compute_type`=***"int8"*** to ensure compatibility with CPU-only systems.
108+
- The `transcribe_audio()` function processes the recorded audio and prints the transcription results along with start and end timestamps for each spoken segment.
109+
- The while True loop continuously records and transcribes in real time until interrupted, allowing the user to speak multiple utterances across iterations.
110+
- The script will continue running in 10-second cycles until stopped with ***Ctrl+C***.
111+
112+
```python
113+
import sounddevice as sd
114+
import numpy as np
115+
from faster_whisper import WhisperModel
116+
117+
SAMPLE_RATE = 16000
118+
DURATION = 10 # seconds per loop
119+
120+
def record_audio():
121+
print(" Recording for 10 seconds...")
122+
with sd.InputStream(samplerate=SAMPLE_RATE, channels=1, dtype='float32') as stream:
123+
audio = stream.read(int(SAMPLE_RATE * DURATION))[0] # returns (data, overflow)
124+
sd.wait()
125+
print(" Recording complete.")
126+
return audio.flatten()
127+
128+
def transcribe_audio(audio):
129+
model = WhisperModel("small.en", device="cpu", compute_type="int8")
130+
print(" Transcribing...")
131+
segments, _ = model.transcribe(audio, language="en")
132+
for segment in segments:
133+
print(f"[{segment.start:.2f}s - {segment.end:.2f}s] {segment.text.strip()}")
134+
print(" Done.\n")
135+
136+
if __name__ == "__main__":
137+
try:
138+
while True:
139+
audio_data = record_audio()
140+
transcribe_audio(audio_data)
141+
except KeyboardInterrupt:
142+
print(" Stopped by user.")
143+
```
144+
145+
{{% notice Note %}}
146+
To stop the script, press ***Ctrl+C*** during any transcription loop.The current 10-second recording will complete and transcribe before the program exits cleanly.
147+
Avoid using ***Ctrl+Z***, which suspends the process instead of terminating it.
148+
{{% /notice %}}
149+
150+
151+
### Troubleshooting
152+
153+
This section lists common issues you may encounter when setting up local speech-to-text, along with clear checks and fixes.
154+
155+
***Problem 1: Callback-related errors with sounddevice***
156+
157+
If you encounter errors like:
158+
159+
```log
160+
AttributeError: '_CallbackContext' object has no attribute 'data'
161+
```
162+
163+
***Cause***
164+
This is a known issue introduced in sounddevice==0.5.4, related to internal callback cleanup.
165+
166+
***Fix***
167+
Use the stable version recommended in this Learning Path:
168+
```bash
169+
pip install sounddevice==0.5.3
170+
```
171+
172+
***Problem 2: No sound playback after recording***
173+
174+
You can record audio without errors, but nothing is played back.
175+
176+
***Check:***
177+
- Verify that your USB microphone or headset is selected as the default input/output device.
178+
- Ensure the system volume is not muted.
179+
180+
***Fix***
181+
List all available audio devices:
182+
183+
```bash
184+
python -m sounddevice
185+
```
186+
187+
You should see an output similar to:
188+
```log
189+
0 NVIDIA: HDMI 0 (hw:0,3), ALSA (0 in, 8 out)
190+
1 NVIDIA: HDMI 1 (hw:0,7), ALSA (0 in, 8 out)
191+
2 NVIDIA: HDMI 2 (hw:0,8), ALSA (0 in, 8 out)
192+
3 NVIDIA: HDMI 3 (hw:0,9), ALSA (0 in, 8 out)
193+
4 Plantronics Blackwire 3225 Seri: USB Audio (hw:1,0), ALSA (2 in, 2 out)
194+
5 hdmi, ALSA (0 in, 8 out)
195+
6 pipewire, ALSA (64 in, 64 out)
196+
7 pulse, ALSA (32 in, 32 out)
197+
* 8 default, ALSA (64 in, 64 out)
198+
```
199+
200+
If your microphone or headset is listed but not active, try explicitly selecting it in Python:
201+
202+
```bash
203+
import sounddevice as sd
204+
205+
sd.default.device = 4 # Set to your desired device index
206+
```
207+
208+
Other fixes to try:
209+
- Increase system volume
210+
- Replug the device
211+
- Reboot your system to refresh device mappings
212+
213+
214+
### Next Module
215+
216+
Once your transcription prints correctly in the terminal and playback works as expected, you’ve successfully completed the setup for local STT using faster-whisper.
217+
218+
In the next module, you’ll enhance this basic transcription loop by adding real-time audio segmentation, turn detection, and background threading to support natural voice interactions.

0 commit comments

Comments
 (0)