Skip to content

Commit 1dd43c6

Browse files
authored
Merge pull request #3156 from arm-bhanuarya/add/voice-sentiment-aware-llm-learning-path
Add voice sentiment analysis learning path
2 parents c338c60 + e96c4a0 commit 1dd43c6

11 files changed

Lines changed: 1195 additions & 0 deletions
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: Overview
3+
weight: 2
4+
layout: learningpathall
5+
---
6+
Voice-based LLM applications often rely primarily on transcribed text from speech input, such as in interactions with non-player characters in games or voice assistants. This approach can overlook vocal cues—like tone, pitch, and emotion—present in a speaker’s voice. As a result, responses may feel less natural and may not fully capture the user’s underlying intent.
7+
8+
To address this, voice-based sentiment classification analyzes audio input to determine the user’s emotional state, which is then incorporated into the LLM prompt to enable more context-aware responses. In this Learning Path, we will build a sentiment-aware voice assistant that runs entirely on-device. The application records audio, performs transcription—converting speech into written text—using Whisper, classifies sentiment directly from the voice signal, and combines the transcript and voice-based sentiment to guide responses from a local LLM running with llama.cpp.
9+
10+
![Voice sentiment classification pipeline#center](1_vsapipeline2.png "Voice sentiment classification pipeline")
11+
12+
You will start by building a baseline voice-to-LLM pipeline—capturing audio, transcribing it into text, and using it to generate responses with an LLM. You will then extend this pipeline with a voice-based sentiment classification model. This involves training the model, optimizing it for efficient on-device inference, and integrating it into a unified application.
23.5 KB
Loading
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
---
2+
title: Set up your environment
3+
weight: 3
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
Before building the voice assistant, create a project workspace and set up an isolated `UV` environment. This keeps project dependencies separate from your system installation and makes it easier to reproduce the steps in the rest of the Learning Path.
10+
11+
These instructions support Ubuntu, macOS, and Windows, with Python 3.9 or later and a working microphone.
12+
13+
Check your Python version before continuing:
14+
15+
**Ubuntu or macOS**
16+
17+
```bash
18+
python3 --version
19+
```
20+
21+
**Windows PowerShell**
22+
23+
```powershell
24+
py -3 --version
25+
```
26+
27+
## Set up the Python environment with UV
28+
29+
Install `UV` first from PyPI using `pip`. `UV` is a fast Python package and environment manager that we will use throughout this Learning Path to create the project environment and install dependencies.
30+
31+
**Ubuntu or macOS**
32+
33+
```bash
34+
mkdir -p ~/voice-sentiment-assistant
35+
cd ~/voice-sentiment-assistant
36+
python3 -m pip install uv
37+
uv venv .venv
38+
source .venv/bin/activate
39+
```
40+
41+
**Windows PowerShell**
42+
43+
```powershell
44+
mkdir $HOME\voice-sentiment-assistant -Force
45+
cd $HOME\voice-sentiment-assistant
46+
py -3 -m pip install uv
47+
uv venv .venv
48+
.\.venv\Scripts\Activate.ps1
49+
```
50+
51+
Keep this virtual environment activated while you complete the rest of the Learning Path.
52+
53+
Create a `requirements.txt` file for the packages used across the rest of the Learning Path:
54+
55+
```txt
56+
gradio
57+
openai-whisper
58+
requests
59+
torch
60+
transformers
61+
pandas
62+
numpy
63+
librosa
64+
scikit-learn
65+
onnx
66+
onnxruntime
67+
```
68+
69+
Install the dependencies into your active `UV` virtual environment:
70+
71+
```console
72+
uv pip install -r requirements.txt
73+
```
74+
75+
This installs the libraries needed for the Gradio interface, Whisper transcription, model training, and ONNX Runtime inference. Some packages in this list are used later in the Learning Path when you optimize and export the sentiment model.
76+
77+
## Download, build, and run llama.cpp
78+
79+
Next, clone the [llama.cpp GitHub repository](https://github.com/ggml-org/llama.cpp), build the local inference server, and start it. This server exposes an OpenAI-compatible API that the Python application will call later in the Learning Path.
80+
81+
**Ubuntu or macOS**
82+
83+
```bash
84+
git clone https://github.com/ggml-org/llama.cpp
85+
cd llama.cpp
86+
cmake -B build
87+
cmake --build build --config Release
88+
```
89+
90+
**Windows PowerShell**
91+
92+
```powershell
93+
git clone https://github.com/ggml-org/llama.cpp
94+
cd llama.cpp
95+
cmake -B build
96+
cmake --build build --config Release
97+
```
98+
99+
When the build completes, the `llama-server` executable should be available in the build output directory. This Learning Path uses a quantized [Gemma 3 1B instruction-tuned model](https://huggingface.co/google/gemma-3-1b-it) served locally through `llama.cpp`.
100+
101+
The first time you run this command, `llama.cpp` will download the model from Hugging Face. This can take several minutes depending on your network connection.
102+
103+
**Ubuntu or macOS**
104+
105+
Run the following command from the `llama.cpp` directory:
106+
107+
```bash
108+
./build/bin/llama-server -hf ggml-org/gemma-3-1b-it-GGUF
109+
```
110+
111+
**Windows PowerShell**
112+
113+
```powershell
114+
.\build\bin\Release\llama-server.exe -hf ggml-org/gemma-3-1b-it-GGUF
115+
```
116+
117+
Leave this terminal running while you test the application in later steps. The server listens on a local OpenAI-compatible endpoint that your app will call to generate responses.
118+
119+
At this point, your development environment is ready. You have installed the required audio and build tools, created a `UV` environment, installed the Python dependencies, and started a local `llama.cpp` server. In the next section, you will use this setup to build the baseline voice-to-LLM pipeline by creating a simple Gradio interface, transcribing microphone input with Whisper, and sending the transcript to the local LLM.
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
---
2+
title: Build the voice-to-LLM pipeline
3+
weight: 4
4+
layout: learningpathall
5+
---
6+
7+
In this section, you will build an end-to-end pipeline that:
8+
9+
1. Records audio from your microphone
10+
2. Transcribes it to text using Whisper
11+
3. Sends the text to a locally hosted LLM
12+
4. Displays the model's response
13+
14+
This forms the foundation of your voice assistant.
15+
16+
![Baseline voice-to-LLM pipeline#center](3_vsapipeline1.png "Baseline voice-to-LLM pipeline")
17+
18+
Before you begin, make sure you have completed the environment setup in the previous section and that your `llama-server` is still running.
19+
20+
### Step 1.1 - Create a basic Gradio UI
21+
22+
Start by creating a simple web interface that captures microphone input.
23+
Gradio is a Python library for building simple browser-based interfaces. Here, you use it to create a small front end that records audio from your microphone.
24+
25+
This is a good first step because it lets you confirm that microphone capture works before you add transcription and model inference.
26+
27+
Create a file called `app.py`:
28+
29+
```python
30+
import gradio as gr
31+
32+
with gr.Blocks() as demo:
33+
mic = gr.Audio(sources="microphone", type="filepath")
34+
35+
demo.launch()
36+
```
37+
38+
Run the app:
39+
40+
```bash
41+
python app.py
42+
```
43+
44+
Open your browser at:
45+
46+
`http://127.0.0.1:7860`
47+
48+
You should now see a simple interface that allows you to record audio.
49+
At this stage, the app only captures audio. It does not yet transcribe speech or send anything to the LLM.
50+
51+
### Step 1.2 - Add speech-to-text with Whisper
52+
53+
Next, add transcription using the Whisper model.
54+
Whisper is a speech-to-text model. It takes audio as input and returns a text transcript. In this pipeline, it converts spoken input into text before anything is sent to the LLM.
55+
56+
Update `app.py` with the following code:
57+
58+
```python
59+
import whisper
60+
61+
# Load a small Whisper model for local transcription
62+
model = whisper.load_model("base")
63+
64+
def transcribe(audio):
65+
return model.transcribe(audio)["text"]
66+
```
67+
68+
The first time you run this, Whisper will download the model, which may take a few minutes.
69+
70+
At this stage, your app can convert recorded audio into text.
71+
The output of this step is a text transcript that represents what the user said.
72+
73+
### Step 1.3 - Connect to the local LLM
74+
75+
Define the OpenAI-compatible endpoint exposed by `llama-server`.
76+
An endpoint is the URL your program uses to talk to another service. In this case, `llama-server` exposes a local API on your machine, and your app sends the transcript there to get a response.
77+
78+
Because the server is OpenAI-compatible, the request format looks like a standard chat completions API.
79+
80+
Update `app.py` with the following import and endpoint definition:
81+
82+
```python
83+
import requests
84+
85+
LOCAL_LLM_URL = "http://127.0.0.1:8080/v1/chat/completions"
86+
```
87+
88+
Make sure your `llama-server` from the previous section is running before continuing.
89+
Without the local server running, the next step will not be able to generate an answer.
90+
91+
### Step 1.4 - Build the full pipeline
92+
93+
Now combine transcription and LLM interaction into a single function.
94+
This function becomes the core of the application. Audio goes in, text is extracted, that text is sent to the model, and the response comes back out.
95+
96+
Keeping the logic in one function makes it easier to connect the pipeline to the user interface in the next step.
97+
98+
Update `app.py` by adding the following function:
99+
100+
```python
101+
def handle_audio(audio):
102+
# Step 1: Transcribe audio
103+
text = transcribe(audio)
104+
105+
# Step 2: Send transcript to local LLM
106+
response = requests.post(
107+
LOCAL_LLM_URL,
108+
json={
109+
"model": "local-model",
110+
"messages": [{"role": "user", "content": text}],
111+
},
112+
)
113+
114+
if response.status_code != 200:
115+
return text, "Error: LLM request failed"
116+
117+
data = response.json()
118+
answer = data["choices"][0]["message"]["content"]
119+
120+
return text, answer
121+
```
122+
123+
### Step 1.5 - Connect the UI to the pipeline
124+
125+
Update your UI so that recorded audio triggers the full pipeline and displays results.
126+
This is the final integration step. You now connect the interface, transcription, and model request so the app behaves like a real voice assistant.
127+
128+
When the user records audio, Gradio calls your pipeline function. The app then shows both the transcript and the assistant response in the browser.
129+
130+
Update `app.py` so it contains the following complete version:
131+
132+
```python
133+
import gradio as gr
134+
import whisper
135+
import requests
136+
137+
model = whisper.load_model("base")
138+
139+
LOCAL_LLM_URL = "http://127.0.0.1:8080/v1/chat/completions"
140+
141+
def transcribe(audio):
142+
return model.transcribe(audio)["text"]
143+
144+
def handle_audio(audio):
145+
text = transcribe(audio)
146+
147+
response = requests.post(
148+
LOCAL_LLM_URL,
149+
json={
150+
"model": "local-model",
151+
"messages": [{"role": "user", "content": text}],
152+
},
153+
)
154+
155+
if response.status_code != 200:
156+
return text, "Error: LLM request failed"
157+
158+
data = response.json()
159+
answer = data["choices"][0]["message"]["content"]
160+
161+
return text, answer
162+
163+
with gr.Blocks() as demo:
164+
mic = gr.Audio(sources="microphone", type="filepath")
165+
transcript = gr.Textbox(label="Transcript")
166+
response = gr.Textbox(label="LLM Response")
167+
168+
mic.change(fn=handle_audio, inputs=mic, outputs=[transcript, response])
169+
170+
demo.launch()
171+
```
172+
173+
## What you should see
174+
175+
After recording audio in the browser:
176+
177+
- Your speech is transcribed into text
178+
- The transcript is sent to the local LLM
179+
- The LLM response is displayed in the interface
180+
181+
## Troubleshooting
182+
183+
- No response from LLM: ensure `llama-server` is still running.
184+
- Whisper is slow on first run: this is expected due to model download and initialization.
185+
- Microphone not working: check browser permissions for microphone access.
186+
187+
At this point, you have a working voice-to-LLM pipeline. In the next section, you will extend this pipeline by adding a voice sentiment classification model.
15.4 KB
Loading
113 KB
Loading

0 commit comments

Comments
 (0)