Some checks failed
CodeQL / Analyze (go) (push) Successful in 6m28s
Docker Image / build-docker (push) Failing after 13m26s
Lint and Testing / lint (push) Successful in 11m17s
Lint and Testing / test (push) Successful in 11m17s
Lint and Testing / golangci (push) Successful in 2m40s
281 lines
12 KiB
Makefile
281 lines
12 KiB
Makefile
EXECUTABLE := go-whisper-api
|
|
GO ?= go
|
|
GOFILES := $(shell find . -name "*.go" -type f)
|
|
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
|
|
|
WHISPER_CPP := $(abspath third_party/whisper.cpp)
|
|
WHISPER_BUILD := $(WHISPER_CPP)/build
|
|
WHISPER_VENDOR := $(WHISPER_CPP)/bindings/go
|
|
WHISPER_LIBDIR := $(WHISPER_BUILD)/src:$(WHISPER_BUILD)/ggml/src
|
|
|
|
RUNTIME_LIB_DIR := $(abspath lib)
|
|
# $ORIGIN/lib — binary next to lib/ (e.g. ./go-whisper-api + ./lib/)
|
|
# $ORIGIN/../lib — binary in bin/ (e.g. bin/go-whisper-api + lib/)
|
|
RUNTIME_RPATH := -Wl,-rpath,$$ORIGIN/lib:$$ORIGIN/../lib
|
|
|
|
ifneq ($(shell uname), Darwin)
|
|
EXTLDFLAGS = -extldflags "$(RUNTIME_RPATH)"
|
|
else
|
|
EXTLDFLAGS =
|
|
endif
|
|
|
|
ifeq ($(HAS_GO), GO)
|
|
GOPATH ?= $(shell $(GO) env GOPATH)
|
|
export PATH := $(GOPATH)/bin:$(PATH)
|
|
|
|
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
|
|
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
|
|
endif
|
|
|
|
ifeq ($(OS), Windows_NT)
|
|
GOFLAGS := -v -buildmode=exe
|
|
EXECUTABLE ?= $(EXECUTABLE).exe
|
|
else ifeq ($(OS), Windows)
|
|
GOFLAGS := -v -buildmode=exe
|
|
EXECUTABLE ?= $(EXECUTABLE).exe
|
|
else
|
|
GOFLAGS := -v
|
|
EXECUTABLE ?= $(EXECUTABLE)
|
|
endif
|
|
|
|
ifneq ($(DRONE_TAG),)
|
|
VERSION ?= $(DRONE_TAG)
|
|
else
|
|
VERSION ?= $(shell git describe --tags --always || git rev-parse --short HEAD)
|
|
endif
|
|
|
|
TAGS ?=
|
|
UNAME_M := $(shell uname -m)
|
|
ifeq ($(UNAME_M),x86_64)
|
|
SHERPA_LIBARCH := x86_64-unknown-linux-gnu
|
|
endif
|
|
ifeq ($(UNAME_M),aarch64)
|
|
SHERPA_LIBARCH := aarch64-unknown-linux-gnu
|
|
endif
|
|
SHERPA_LINUX_VER := $(shell awk '/sherpa-onnx-go-linux/ {print $$2; exit}' go.mod)
|
|
SHERPA_LIBDIR := $(GOPATH)/pkg/mod/github.com/k2-fsa/sherpa-onnx-go-linux@$(SHERPA_LINUX_VER)/lib/$(SHERPA_LIBARCH)
|
|
ifneq ($(shell uname), Darwin)
|
|
EXTLDFLAGS_SHERPA = -extldflags "$(RUNTIME_RPATH)"
|
|
EXTLDFLAGS_XLM = -extldflags "$(RUNTIME_RPATH)"
|
|
else
|
|
EXTLDFLAGS_SHERPA =
|
|
EXTLDFLAGS_XLM =
|
|
endif
|
|
GOLDFLAGS ?= -X 'main.Version=$(VERSION)'
|
|
|
|
INCLUDE_PATH := $(WHISPER_CPP)/include:$(WHISPER_CPP)/ggml/include:$(WHISPER_VENDOR):$(INCLUDE_PATH)
|
|
LIBRARY_PATH := $(WHISPER_LIBDIR):$(LIBRARY_PATH)
|
|
export LD_LIBRARY_PATH := $(WHISPER_LIBDIR):$(LD_LIBRARY_PATH)
|
|
|
|
ifdef WHISPER_CUBLAS
|
|
CGO_CFLAGS += -DGGML_USE_CUBLAS -I/usr/local/cuda/include -I/opt/cuda/include -I$(CUDA_PATH)/targets/$(UNAME_M)-linux/include
|
|
CGO_CXXFLAGS += -DGGML_USE_CUBLAS -I/usr/local/cuda/include -I/opt/cuda/include -I$(CUDA_PATH)/targets/$(UNAME_M)-linux/include
|
|
EXTLDFLAGS = -extldflags "-lcuda -lcublas -lculibos -lcudart -lcublasLt -lpthread -ldl -lrt -L/usr/local/cuda/lib64 -L/opt/cuda/lib64 -L$(CUDA_PATH)/targets/$(UNAME_M)-linux/lib"
|
|
|
|
build: $(EXECUTABLE)
|
|
|
|
$(EXECUTABLE): $(GOFILES)
|
|
CGO_CXXFLAGS=${CGO_CXXFLAGS} CGO_CFLAGS=${CGO_CFLAGS} C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} $(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(GOLDFLAGS)' -o bin/$@
|
|
endif
|
|
|
|
MODEL_URL ?= https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin
|
|
MODEL_PATH ?= models/ggml-tiny.en.bin
|
|
VAD_MODEL ?= silero-v6.2.0
|
|
VAD_MODEL_PATH ?= models/ggml-silero-v6.2.0.bin
|
|
|
|
all: build
|
|
|
|
PUNCT_MODEL_URL ?= https://github.com/k2-fsa/sherpa-onnx/releases/download/punctuation-models/sherpa-onnx-punct-ct-transformer-zh-en-vocab272727-2024-04-12-int8.tar.bz2
|
|
PUNCT_MODEL_DIR ?= models/punctuation/ct-transformer-zh-en-int8
|
|
|
|
XLM_PUNCT_DIR ?= models/punctuation/xlm-roberta
|
|
XLM_HF_REPO ?= Salama1429/xlm-roberta_punctuation_fullstop_truecase
|
|
|
|
XLM_MODEL_CONFIG_SRC ?= config/xlm-roberta-model.yaml
|
|
ORT_LIB_SRC ?= $(shell $(GO) env GOMODCACHE 2>/dev/null)/github.com/k2-fsa/sherpa-onnx-go-linux@$(SHERPA_LINUX_VER)/lib/$(SHERPA_LIBARCH)/libonnxruntime.so
|
|
|
|
# Copy runtime .so into ./lib/. Binary rpath: $ORIGIN/lib or $ORIGIN/../lib (see RUNTIME_RPATH).
|
|
# Use cp -n where possible: existing root-owned libs in lib/ must not break the build.
|
|
install-runtime-libs: dependency
|
|
@mkdir -p "$(RUNTIME_LIB_DIR)"
|
|
@cp -an "$(WHISPER_BUILD)/src"/libwhisper.so* "$(RUNTIME_LIB_DIR)/" 2>/dev/null || true
|
|
@cp -an "$(WHISPER_BUILD)/ggml/src"/libggml*.so* "$(RUNTIME_LIB_DIR)/" 2>/dev/null || true
|
|
@echo "Whisper/ggml libs ready in $(RUNTIME_LIB_DIR)/"
|
|
|
|
install-ort-lib:
|
|
@mkdir -p "$(RUNTIME_LIB_DIR)"
|
|
@if [ ! -f "$(ORT_LIB_SRC)" ]; then echo "missing $(ORT_LIB_SRC); run: go mod download"; exit 1; fi
|
|
@dest="$(RUNTIME_LIB_DIR)/libonnxruntime.so"; \
|
|
if [ -f "$$dest" ] && cmp -s "$(ORT_LIB_SRC)" "$$dest"; then \
|
|
echo "libonnxruntime.so already up to date in $(RUNTIME_LIB_DIR)/"; \
|
|
elif cp -f "$(ORT_LIB_SRC)" "$$dest" 2>/dev/null; then \
|
|
echo "Installed $$dest"; \
|
|
elif [ -f "$$dest" ] && cmp -s "$(ORT_LIB_SRC)" "$$dest"; then \
|
|
echo "libonnxruntime.so present in $(RUNTIME_LIB_DIR)/ (unchanged, not writable)"; \
|
|
else \
|
|
echo "cannot install libonnxruntime.so to $$dest"; \
|
|
echo "fix: sudo chown -R $$USER:$$(id -gn) $(RUNTIME_LIB_DIR)"; \
|
|
exit 1; \
|
|
fi
|
|
|
|
# XLM punctuation links -lsentencepiece; bundle .so for hosts without libsentencepiece0 package.
|
|
SP_LIB_DIRS := /usr/lib/x86_64-linux-gnu /usr/lib/aarch64-linux-gnu /usr/lib64 /usr/lib
|
|
install-sp-lib:
|
|
@mkdir -p "$(RUNTIME_LIB_DIR)"
|
|
@found=0; \
|
|
for d in $(SP_LIB_DIRS); do \
|
|
if [ -e "$$d/libsentencepiece.so.0" ] || [ -L "$$d/libsentencepiece.so.0" ]; then \
|
|
cp -an "$$d"/libsentencepiece.so* "$(RUNTIME_LIB_DIR)/" 2>/dev/null || true; \
|
|
found=1; \
|
|
break; \
|
|
fi; \
|
|
done; \
|
|
if [ "$$found" = "0" ]; then \
|
|
echo "libsentencepiece.so.0 not found; install: sudo apt-get install libsentencepiece0"; \
|
|
exit 1; \
|
|
fi
|
|
@test -e "$(RUNTIME_LIB_DIR)/libsentencepiece.so.0" || (echo "missing $(RUNTIME_LIB_DIR)/libsentencepiece.so.0 after install-sp-lib"; exit 1)
|
|
@echo "Sentencepiece libs ready in $(RUNTIME_LIB_DIR)/"
|
|
|
|
# If lib/*.so were created as root (e.g. manual cp with sudo), reclaim ownership for builds.
|
|
fix-lib-perms:
|
|
@if [ -d "$(RUNTIME_LIB_DIR)" ]; then \
|
|
chown -R "$$USER:$$(id -gn)" "$(RUNTIME_LIB_DIR)" 2>/dev/null || \
|
|
sudo chown -R "$$USER:$$(id -gn)" "$(RUNTIME_LIB_DIR)"; \
|
|
echo "Ownership of $(RUNTIME_LIB_DIR)/ updated"; \
|
|
fi
|
|
|
|
install-runtime-libs-xlm: install-runtime-libs install-ort-lib install-sp-lib
|
|
|
|
# Fail fast before deploy if ./lib is incomplete (lib/ is not in git: *.so is gitignored).
|
|
verify-runtime-libs-xlm:
|
|
@test -f bin/$(EXECUTABLE) || (echo "missing bin/$(EXECUTABLE); run: make build-xlm"; exit 1)
|
|
@test -f "$(RUNTIME_LIB_DIR)/libonnxruntime.so" || (echo "missing $(RUNTIME_LIB_DIR)/libonnxruntime.so; run: make install-runtime-libs-xlm"; exit 1)
|
|
@test -e "$(RUNTIME_LIB_DIR)/libsentencepiece.so.0" || (echo "missing $(RUNTIME_LIB_DIR)/libsentencepiece.so.0; run: make install-sp-lib"; exit 1)
|
|
@test -e "$(RUNTIME_LIB_DIR)/libwhisper.so.1" || (echo "missing $(RUNTIME_LIB_DIR)/libwhisper.so.1; run: make install-runtime-libs"; exit 1)
|
|
@echo "Runtime libs OK in $(RUNTIME_LIB_DIR)/"
|
|
|
|
RUNTIME_TARBALL := dist/go-whisper-api-runtime-$(shell uname -m).tar.gz
|
|
package-runtime-xlm: verify-runtime-libs-xlm
|
|
@mkdir -p dist
|
|
tar -czf "$(RUNTIME_TARBALL)" bin/$(EXECUTABLE) lib
|
|
@echo "Created $(RUNTIME_TARBALL) — on prod: tar -xzf ... -C /opt/go-whisper-api (keeps bin/ and lib/)"
|
|
|
|
# Copy bundled label config (needs write access to $(XLM_PUNCT_DIR); fix with: sudo chown -R $$USER models/punctuation)
|
|
install-xlm-punctuation-config:
|
|
@mkdir -p $(XLM_PUNCT_DIR)
|
|
@cp "$(XLM_MODEL_CONFIG_SRC)" "$(XLM_PUNCT_DIR)/config.yaml"
|
|
@echo "Installed $(XLM_PUNCT_DIR)/config.yaml"
|
|
|
|
download-xlm-punctuation-model: install-xlm-punctuation-config
|
|
@mkdir -p $(XLM_PUNCT_DIR)
|
|
@for f in model.onnx sp.model; do \
|
|
if [ ! -f "$(XLM_PUNCT_DIR)/$$f" ]; then \
|
|
echo "Downloading $$f from $(XLM_HF_REPO)..."; \
|
|
curl -fL "https://huggingface.co/$(XLM_HF_REPO)/resolve/main/$$f" -o "$(XLM_PUNCT_DIR)/$$f"; \
|
|
else \
|
|
echo "Already have $(XLM_PUNCT_DIR)/$$f"; \
|
|
fi; \
|
|
done
|
|
|
|
DIAR_SEG_URL ?= https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-segmentation-models/sherpa-onnx-pyannote-segmentation-3-0.tar.bz2
|
|
DIAR_EMB_URL ?= https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx
|
|
DIAR_DIR ?= models/diarization
|
|
|
|
download-diarization-models:
|
|
@mkdir -p $(DIAR_DIR)
|
|
@if [ ! -f "$(DIAR_DIR)/pyannote-segmentation-3-0/model.onnx" ]; then \
|
|
echo "Downloading speaker segmentation model..."; \
|
|
curl -fL "$(DIAR_SEG_URL)" -o /tmp/diar-seg.tar.bz2; \
|
|
tar -xjf /tmp/diar-seg.tar.bz2 -C $(DIAR_DIR); \
|
|
rm -f /tmp/diar-seg.tar.bz2; \
|
|
else \
|
|
echo "Segmentation model present"; \
|
|
fi
|
|
@if [ ! -f "$(DIAR_DIR)/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx" ]; then \
|
|
echo "Downloading speaker embedding model..."; \
|
|
curl -fL "$(DIAR_EMB_URL)" -o "$(DIAR_DIR)/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx"; \
|
|
else \
|
|
echo "Embedding model present"; \
|
|
fi
|
|
|
|
download-punctuation-model:
|
|
@mkdir -p models/punctuation
|
|
@if [ ! -f "$(PUNCT_MODEL_DIR)/model.int8.onnx" ]; then \
|
|
echo "Downloading punctuation model..."; \
|
|
curl -fL "$(PUNCT_MODEL_URL)" -o /tmp/punct-model.tar.bz2; \
|
|
tar -xjf /tmp/punct-model.tar.bz2 -C models/punctuation; \
|
|
rm -f /tmp/punct-model.tar.bz2; \
|
|
if [ -d models/punctuation/sherpa-onnx-punct-ct-transformer-zh-en-vocab272727-2024-04-12-int8 ]; then \
|
|
mv models/punctuation/sherpa-onnx-punct-ct-transformer-zh-en-vocab272727-2024-04-12-int8 "$(PUNCT_MODEL_DIR)"; \
|
|
fi; \
|
|
else \
|
|
echo "Punctuation model already exists: $(PUNCT_MODEL_DIR)/model.int8.onnx"; \
|
|
fi
|
|
|
|
download-model:
|
|
@mkdir -p models
|
|
@if [ ! -f "$(MODEL_PATH)" ]; then \
|
|
echo "Downloading $(MODEL_PATH)..."; \
|
|
curl -fL "$(MODEL_URL)" -o "$(MODEL_PATH)"; \
|
|
else \
|
|
echo "Model already exists: $(MODEL_PATH)"; \
|
|
fi
|
|
|
|
download-vad-model:
|
|
@mkdir -p models
|
|
@if [ ! -f "$(VAD_MODEL_PATH)" ]; then \
|
|
echo "Downloading VAD model $(VAD_MODEL) to models/..."; \
|
|
./third_party/whisper.cpp/models/download-vad-model.sh $(VAD_MODEL) models; \
|
|
else \
|
|
echo "VAD model already exists: $(VAD_MODEL_PATH)"; \
|
|
fi
|
|
|
|
clone:
|
|
@[ -d third_party/whisper.cpp ] || git clone https://github.com/appleboy/whisper.cpp.git third_party/whisper.cpp
|
|
|
|
dependency: clone
|
|
@echo Build whisper
|
|
@if [ ! -f "$(WHISPER_BUILD)/src/libwhisper.so" ] && [ ! -f "$(WHISPER_BUILD)/src/libwhisper.a" ]; then \
|
|
cmake -S "$(WHISPER_CPP)" -B "$(WHISPER_BUILD)" -DCMAKE_BUILD_TYPE=Release && \
|
|
cmake --build "$(WHISPER_BUILD)" --config Release -j$$(nproc 2>/dev/null || echo 4); \
|
|
else \
|
|
echo "whisper library already built in $(WHISPER_BUILD)"; \
|
|
fi
|
|
|
|
test:
|
|
@C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} $(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
|
|
|
install: $(GOFILES)
|
|
C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} $(GO) install -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(GOLDFLAGS)'
|
|
|
|
build: install-runtime-libs $(EXECUTABLE)
|
|
|
|
# Build with sherpa-onnx (punctuation + speaker diarization)
|
|
build-sherpa:
|
|
@$(MAKE) build TAGS=sherpa
|
|
|
|
# XLM-RoBERTa punctuation (47 languages); requires libsentencepiece-dev
|
|
build-xlm:
|
|
@$(MAKE) install-runtime-libs-xlm
|
|
@$(MAKE) build TAGS=xlm
|
|
|
|
$(EXECUTABLE): $(GOFILES)
|
|
ifneq (,$(findstring xlm,$(TAGS)))
|
|
C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=$(SHERPA_LIBDIR):${LIBRARY_PATH} $(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS_XLM) -s -w $(GOLDFLAGS)' -o bin/$@
|
|
else ifneq (,$(findstring sherpa,$(TAGS)))
|
|
C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=$(SHERPA_LIBDIR):${LIBRARY_PATH} $(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS_SHERPA) -s -w $(GOLDFLAGS)' -o bin/$@
|
|
else
|
|
C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} $(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(GOLDFLAGS)' -o bin/$@
|
|
endif
|
|
|
|
clean:
|
|
$(GO) clean -x -i ./...
|
|
rm -rf coverage.txt $(EXECUTABLE) $(DIST) bin/$(EXECUTABLE)
|
|
|
|
clean-whisper:
|
|
rm -rf "$(WHISPER_BUILD)"
|
|
|
|
version:
|
|
@echo $(VERSION)
|