Skip to content

Commit 18a3ee8

Browse files
authored
Merge branch 'ggerganov:master' into wyoming
2 parents 2ffc125 + ef40950 commit 18a3ee8

File tree

9 files changed

+152
-68
lines changed

9 files changed

+152
-68
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ cmake-build-debug/
5858
.cxx/
5959
.gradle/
6060
local.properties
61+
.log
62+
.exe

bindings/go/examples/go-model-download/context.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@ import (
99
// ContextForSignal returns a context object which is cancelled when a signal
1010
// is received. It returns nil if no signal parameter is provided
1111
func ContextForSignal(signals ...os.Signal) context.Context {
12-
if len(signals) == 0 {
13-
return nil
14-
}
12+
if len(signals) == 0 {
13+
return nil
14+
}
1515

16-
ch := make(chan os.Signal)
17-
ctx, cancel := context.WithCancel(context.Background())
16+
ch := make(chan os.Signal, 1) // Buffered channel with space for 1 signal
17+
ctx, cancel := context.WithCancel(context.Background())
1818

19-
// Send message on channel when signal received
20-
signal.Notify(ch, signals...)
19+
// Send message on channel when signal received
20+
signal.Notify(ch, signals...)
2121

22-
// When any signal received, call cancel
23-
go func() {
24-
<-ch
25-
cancel()
26-
}()
22+
// When any signal is received, call cancel
23+
go func() {
24+
<-ch
25+
cancel()
26+
}()
2727

28-
// Return success
29-
return ctx
28+
// Return success
29+
return ctx
3030
}
31+

bindings/go/examples/go-model-download/main.go

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/url"
1010
"os"
1111
"path/filepath"
12+
"strings"
1213
"syscall"
1314
"time"
1415
)
@@ -17,14 +18,27 @@ import (
1718
// CONSTANTS
1819

1920
const (
20-
srcUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main" // The location of the models
21-
srcExt = ".bin" // Filename extension
22-
bufSize = 1024 * 64 // Size of the buffer used for downloading the model
21+
srcUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/" // The location of the models
22+
srcExt = ".bin" // Filename extension
23+
bufSize = 1024 * 64 // Size of the buffer used for downloading the model
2324
)
2425

2526
var (
2627
// The models which will be downloaded, if no model is specified as an argument
27-
modelNames = []string{"ggml-tiny.en", "ggml-tiny", "ggml-base.en", "ggml-base", "ggml-small.en", "ggml-small", "ggml-medium.en", "ggml-medium", "ggml-large-v1", "ggml-large-v2", "ggml-large-v3", "large-v3-turbo"}
28+
modelNames = []string{
29+
"tiny", "tiny-q5_1", "tiny-q8_0",
30+
"tiny.en", "tiny.en-q5_1", "tiny.en-q8_0",
31+
"base", "base-q5_1", "base-q8_0",
32+
"base.en", "base.en-q5_1", "base.en-q8_0",
33+
"small", "small-q5_1", "small-q8_0",
34+
"small.en", "small.en-q5_1", "small.en-q8_0",
35+
"medium", "medium-q5_0", "medium-q8_0",
36+
"medium.en", "medium.en-q5_0", "medium.en-q8_0",
37+
"large-v1",
38+
"large-v2", "large-v2-q5_0", "large-v2-q8_0",
39+
"large-v3", "large-v3-q5_0",
40+
"large-v3-turbo", "large-v3-turbo-q5_0", "large-v3-turbo-q8_0",
41+
}
2842
)
2943

3044
var (
@@ -44,7 +58,25 @@ var (
4458
func main() {
4559
flag.Usage = func() {
4660
name := filepath.Base(flag.CommandLine.Name())
47-
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] <model>\n\n", name)
61+
fmt.Fprintf(flag.CommandLine.Output(), `
62+
Usage: %s [options] [<model>...]
63+
64+
Options:
65+
-out string Specify the output folder where models will be saved.
66+
Default: Current working directory.
67+
-timeout duration Set the maximum duration for downloading a model.
68+
Example: 10m, 1h (default: 30m0s).
69+
-quiet Suppress all output except errors.
70+
71+
Examples:
72+
1. Download a specific model:
73+
%s -out ./models tiny-q8_0
74+
75+
2. Download all models:
76+
%s -out ./models
77+
78+
`, name, name, name)
79+
4880
flag.PrintDefaults()
4981
}
5082
flag.Parse()
@@ -114,23 +146,87 @@ func GetOut() (string, error) {
114146
// GetModels returns the list of models to download
115147
func GetModels() []string {
116148
if flag.NArg() == 0 {
117-
return modelNames
118-
} else {
119-
return flag.Args()
149+
fmt.Println("No model specified.")
150+
fmt.Println("Preparing to download all models...")
151+
152+
// Calculate total download size
153+
fmt.Println("Calculating total download size...")
154+
totalSize, err := CalculateTotalDownloadSize(modelNames)
155+
if err != nil {
156+
fmt.Println("Error calculating download sizes:", err)
157+
os.Exit(1)
158+
}
159+
160+
fmt.Println("View available models: https://huggingface.co/ggerganov/whisper.cpp/tree/main")
161+
fmt.Printf("Total download size: %.2f GB\n", float64(totalSize)/(1024*1024*1024))
162+
fmt.Println("Would you like to download all models? (y/N)")
163+
164+
// Prompt for user input
165+
var response string
166+
fmt.Scanln(&response)
167+
if response != "y" && response != "Y" {
168+
fmt.Println("Aborting. Specify a model to download.")
169+
os.Exit(0)
170+
}
171+
172+
return modelNames // Return all models if confirmed
120173
}
174+
return flag.Args() // Return specific models if arguments are provided
175+
}
176+
177+
func CalculateTotalDownloadSize(models []string) (int64, error) {
178+
var totalSize int64
179+
client := http.Client{}
180+
181+
for _, model := range models {
182+
modelURL, err := URLForModel(model)
183+
if err != nil {
184+
return 0, err
185+
}
186+
187+
// Issue a HEAD request to get the file size
188+
req, err := http.NewRequest("HEAD", modelURL, nil)
189+
if err != nil {
190+
return 0, err
191+
}
192+
193+
resp, err := client.Do(req)
194+
if err != nil {
195+
return 0, err
196+
}
197+
resp.Body.Close()
198+
199+
if resp.StatusCode != http.StatusOK {
200+
fmt.Printf("Warning: Unable to fetch size for %s (HTTP %d)\n", model, resp.StatusCode)
201+
continue
202+
}
203+
204+
size := resp.ContentLength
205+
totalSize += size
206+
}
207+
return totalSize, nil
121208
}
122209

123210
// URLForModel returns the URL for the given model on huggingface.co
124211
func URLForModel(model string) (string, error) {
212+
// Ensure "ggml-" prefix is added only once
213+
if !strings.HasPrefix(model, "ggml-") {
214+
model = "ggml-" + model
215+
}
216+
217+
// Ensure ".bin" extension is added only once
125218
if filepath.Ext(model) != srcExt {
126219
model += srcExt
127220
}
221+
222+
// Parse the base URL
128223
url, err := url.Parse(srcUrl)
129224
if err != nil {
130225
return "", err
131-
} else {
132-
url.Path = filepath.Join(url.Path, model)
133226
}
227+
228+
// Ensure no trailing slash in the base URL
229+
url.Path = fmt.Sprintf("%s/%s", strings.TrimSuffix(url.Path, "/"), model)
134230
return url.String(), nil
135231
}
136232

examples/addon.node/addon.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "napi.h"
22
#include "common.h"
3+
#include "common-whisper.h"
34

45
#include "whisper.h"
56

examples/common-sdl.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,11 @@ void audio_async::callback(uint8_t * stream, int len) {
159159

160160
memcpy(&m_audio[m_audio_pos], stream, n0 * sizeof(float));
161161
memcpy(&m_audio[0], stream + n0 * sizeof(float), (n_samples - n0) * sizeof(float));
162-
163-
m_audio_pos = (m_audio_pos + n_samples) % m_audio.size();
164-
m_audio_len = m_audio.size();
165162
} else {
166163
memcpy(&m_audio[m_audio_pos], stream, n_samples * sizeof(float));
167-
168-
m_audio_pos = (m_audio_pos + n_samples) % m_audio.size();
169-
m_audio_len = std::min(m_audio_len + n_samples, m_audio.size());
170164
}
165+
m_audio_pos = (m_audio_pos + n_samples) % m_audio.size();
166+
m_audio_len = std::min(m_audio_len + n_samples, m_audio.size());
171167
}
172168
}
173169

examples/common-whisper.cpp

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,30 +76,25 @@ bool read_audio_data(const std::string & fname, std::vector<float>& pcmf32, std:
7676

7777
fprintf(stderr, "%s: read %zu bytes from stdin\n", __func__, audio_data.size());
7878
}
79-
else if (is_wav_buffer(fname)) {
80-
if ((result = ma_decoder_init_memory(audio_data.data(), audio_data.size(), &decoder_config, &decoder)) != MA_SUCCESS) {
81-
fprintf(stderr, "Error: failed to open audio data from fname buffer (%s)\n", ma_result_description(result));
82-
83-
return false;
84-
}
85-
}
86-
else if ((result = ma_decoder_init_file(fname.c_str(), &decoder_config, &decoder)) != MA_SUCCESS) {
79+
else if (((result = ma_decoder_init_file(fname.c_str(), &decoder_config, &decoder)) != MA_SUCCESS)) {
8780
#if defined(WHISPER_FFMPEG)
88-
if (ffmpeg_decode_audio(fname, audio_data) != 0) {
89-
fprintf(stderr, "error: failed to ffmpeg decode '%s'\n", fname.c_str());
81+
if (ffmpeg_decode_audio(fname, audio_data) != 0) {
82+
fprintf(stderr, "error: failed to ffmpeg decode '%s'\n", fname.c_str());
9083

91-
return false;
92-
}
84+
return false;
85+
}
9386

94-
if ((result = ma_decoder_init_memory(audio_data.data(), audio_data.size(), &decoder_config, &decoder)) != MA_SUCCESS) {
95-
fprintf(stderr, "error: failed to read audio data as wav (%s)\n", ma_result_description(result));
87+
if ((result = ma_decoder_init_memory(audio_data.data(), audio_data.size(), &decoder_config, &decoder)) != MA_SUCCESS) {
88+
fprintf(stderr, "error: failed to read audio data as wav (%s)\n", ma_result_description(result));
9689

97-
return false;
98-
}
90+
return false;
91+
}
9992
#else
100-
fprintf(stderr, "error: failed to open '%s' file (%s)\n", fname.c_str(), ma_result_description(result));
93+
if ((result = ma_decoder_init_memory(fname.c_str(), fname.size(), &decoder_config, &decoder)) != MA_SUCCESS) {
94+
fprintf(stderr, "error: failed to read audio data as wav (%s)\n", ma_result_description(result));
10195

102-
return false;
96+
return false;
97+
}
10398
#endif
10499
}
105100

examples/common.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -609,21 +609,6 @@ gpt_vocab::id gpt_sample_top_k_top_p_repeat(
609609

610610
}
611611

612-
bool is_wav_buffer(const std::string buf) {
613-
// RIFF ref: https://en.wikipedia.org/wiki/Resource_Interchange_File_Format
614-
// WAV ref: https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
615-
if (buf.size() < 12 || buf.substr(0, 4) != "RIFF" || buf.substr(8, 4) != "WAVE") {
616-
return false;
617-
}
618-
619-
uint32_t chunk_size = *reinterpret_cast<const uint32_t*>(buf.data() + 4);
620-
if (chunk_size + 8 != buf.size()) {
621-
return false;
622-
}
623-
624-
return true;
625-
}
626-
627612
void high_pass_filter(std::vector<float> & data, float cutoff, float sample_rate) {
628613
const float rc = 1.0f / (2.0f * M_PI * cutoff);
629614
const float dt = 1.0f / sample_rate;

examples/common.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,6 @@ gpt_vocab::id gpt_sample_top_k_top_p_repeat(
134134
// Audio utils
135135
//
136136

137-
// Check if a buffer is a WAV audio file
138-
bool is_wav_buffer(const std::string buf);
139-
140137
// Write PCM data into WAV audio file
141138
class wav_writer {
142139
private:

models/download-ggml-model.cmd

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,18 @@ popd
88
set argc=0
99
for %%x in (%*) do set /A argc+=1
1010

11-
set models=tiny.en tiny base.en base small.en small medium.en medium large-v1 large-v2 large-v3 large-v3-turbo
11+
set models=tiny tiny-q5_1 tiny-q8_0 ^
12+
tiny.en tiny.en-q5_1 tiny.en-q8_0 ^
13+
base base-q5_1 base-q8_0 ^
14+
base.en base.en-q5_1 base.en-q8_0 ^
15+
small small-q5_1 small-q8_0 ^
16+
small.en small.en-q5_1 small.en-q8_0 ^
17+
medium medium-q5_0 medium-q8_0 ^
18+
medium.en medium.en-q5_0 medium.en-q8_0 ^
19+
large-v1 ^
20+
large-v2 large-v2-q5_0 large-v2-q8_0 ^
21+
large-v3 large-v3-q5_0 ^
22+
large-v3-turbo large-v3-turbo-q5_0 large-v3-turbo-q8_0
1223

1324
if %argc% neq 1 (
1425
echo.
@@ -50,7 +61,7 @@ if %ERRORLEVEL% neq 0 (
5061

5162
echo Done! Model %model% saved in %root_path%\models\ggml-%model%.bin
5263
echo You can now use it like this:
53-
echo build\bin\Release\whisper-cli.exe -m %root_path%\models\ggml-%model%.bin -f %root_path%\samples\jfk.wav
64+
echo %~dp0build\bin\Release\whisper-cli.exe -m %root_path%\models\ggml-%model%.bin -f %root_path%\samples\jfk.wav
5465

5566
goto :eof
5667

0 commit comments

Comments
 (0)