# Copyright 2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

# LocalAI text-to-speech backend: LocalAI's Go gRPC wrapper around go-piper,
# which builds the piper TTS engine with its phonemizer and the rhasspy fork
# of espeak-ng (vendored deliberately: the fork carries phonemization patches
# and provides the espeak-ng-data this backend ships). fmt/spdlog and
# onnxruntime come from the system.

EAPI=8

inherit go-module local-ai-backend multilib

# Pins. Source of truth: backend/go/piper/Makefile (PIPER_VERSION) at the
# LocalAI release tag; the three below it are go-piper's submodule gitlinks
# at that commit.
GOPIPER_COMMIT="e10ca041a885d4a8f3871d52924b47792d5e5aa0"
PIPER_COMMIT="0987603ebd2a93c3c14289f3914cd9145a7dddb5"
PHONEMIZE_COMMIT="fccd4f335aa68ac0b72600822f34d84363daa2bf"
ESPEAK_COMMIT="8593723f10cfd9befd50de447f14bf0a9d2a14a4"
# piper-phonemize's onnxruntime pin (ONNXRUNTIME_VERSION in its CMakeLists).
ONNX_PV="1.14.1"
# The rhasspy espeak-ng fork FetchContents sonic at configure time
# (cmake/deps.cmake); pinned commit from there.
SONIC_COMMIT="fbf75c3d6d846bad3bb3d456cbc5d07d9fd8c104"

DESCRIPTION="LocalAI text-to-speech backend (piper gRPC server)"
HOMEPAGE="https://localai.io https://github.com/mudler/LocalAI"
SRC_URI="
	${LOCAL_AI_GO_SRC_URI}
	https://github.com/mudler/go-piper/archive/${GOPIPER_COMMIT}.tar.gz -> go-piper-${GOPIPER_COMMIT}.tar.gz
	https://github.com/rhasspy/piper/archive/${PIPER_COMMIT}.tar.gz -> piper-${PIPER_COMMIT}.tar.gz
	https://github.com/rhasspy/piper-phonemize/archive/${PHONEMIZE_COMMIT}.tar.gz -> piper-phonemize-${PHONEMIZE_COMMIT}.tar.gz
	https://github.com/rhasspy/espeak-ng/archive/${ESPEAK_COMMIT}.tar.gz -> rhasspy-espeak-ng-${ESPEAK_COMMIT}.tar.gz
	https://github.com/waywardgeek/sonic/archive/${SONIC_COMMIT}.tar.gz -> sonic-${SONIC_COMMIT}.tar.gz
"
S="${WORKDIR}/LocalAI-${PV}/backend/go/piper"

LICENSE="MIT"
SLOT="0"
KEYWORDS="~amd64"

RDEPEND="
	sci-ml/local-ai
	dev-libs/libfmt:=
	dev-libs/spdlog:=
	|| (
		sci-libs/onnxruntime
		sci-libs/onnxruntime-bin
	)
"
DEPEND="${RDEPEND}"
BDEPEND=">=dev-lang/go-1.26.0"

GOPIPER="${S}/sources/go-piper"

src_unpack() {
	local-ai-backend_go_unpack

	# sonic stays in WORKDIR: src_prepare points espeak's FetchContent
	# at it there.
	unpack "sonic-${SONIC_COMMIT}.tar.gz"

	# go-piper with its submodule checkouts, as upstream's clone targets
	# would lay them out; the Makefile's network-using targets are then
	# skipped because their directories already exist.
	local subs=(
		"piper-${PIPER_COMMIT}.tar.gz" "piper-${PIPER_COMMIT}" piper
		"piper-phonemize-${PHONEMIZE_COMMIT}.tar.gz" "piper-phonemize-${PHONEMIZE_COMMIT}" piper-phonemize
		"rhasspy-espeak-ng-${ESPEAK_COMMIT}.tar.gz" "espeak-ng-${ESPEAK_COMMIT}" espeak
	)
	local-ai-backend_engine_unpack "go-piper-${GOPIPER_COMMIT}.tar.gz" go-piper "${subs[@]}"
}

src_prepare() {
	default

	# The phonemize cmake invocation in go-piper's Makefile takes no
	# argument passthrough; inject the onnxruntime location so its
	# download-if-missing logic never triggers.
	# go-piper's Makefile assigns its own CFLAGS/CXXFLAGS/LDFLAGS (include
	# paths, -lucd, ...). Because Portage exports those names, make
	# re-exports the reassigned values to the espeak/phonemize/piper cmake
	# children — whose compiler sanity checks then link -lucd before it is
	# built. Rename go-piper's private copies so the children inherit the
	# real Portage flags and the recipes keep their own values.
	einfo "Renaming go-piper's private *FLAGS so Portage flags reach the cmake sub-builds"
	sed -i 's/\bCFLAGS\b/GP_CFLAGS/g; s/\bCXXFLAGS\b/GP_CXXFLAGS/g; s/\bLDFLAGS\b/GP_LDFLAGS/g' "${GOPIPER}/Makefile" || die
	grep -q 'GP_LDFLAGS' "${GOPIPER}/Makefile" || die "flags rename did not apply"

	einfo "Pointing espeak's sonic FetchContent at the unpacked source"
	sed -i "s|cd espeak/ei && cmake ..|cd espeak/ei \&\& cmake .. -DFETCHCONTENT_SOURCE_DIR_SONIC-GIT=${WORKDIR}/sonic-${SONIC_COMMIT}|" "${GOPIPER}/Makefile" || die
	grep -q 'FETCHCONTENT_SOURCE_DIR_SONIC-GIT' "${GOPIPER}/Makefile" || die "sonic redirect did not apply"

	einfo "Injecting ONNXRUNTIME_DIR into go-piper's phonemize cmake invocation"
	sed -i "s|cd piper-phonemize/pi && cmake .. --debug-output|cd piper-phonemize/pi \&\& cmake .. --debug-output -DONNXRUNTIME_DIR=${T}/onnx-prefix|" "${GOPIPER}/Makefile" || die
	grep -q "onnx-prefix" "${GOPIPER}/Makefile" || die "onnxruntime injection did not apply"
}

# Provide ${T}/onnx-prefix with include/ and lib/ as piper-phonemize expects.
setup_onnx_prefix() {
	# Real directories with only the onnxruntime pieces: phonemize's
	# install() copies both include/ and lib/ of this prefix into its
	# own tree, so symlinking /usr/include or the system libdir here
	# would sweep system-wide content into the package staging.
	mkdir -p "${T}/onnx-prefix/include" "${T}/onnx-prefix/lib" || die
	cp -rL "${ESYSROOT}/usr/include/onnxruntime/." "${T}/onnx-prefix/include/" || die
	cp -a "${ESYSROOT}/usr/$(get_libdir)"/libonnxruntime.so* "${T}/onnx-prefix/lib/" || die
}

src_compile() {
	setup_onnx_prefix

	# FMT_DIR/SPDLOG_DIR defined => piper's ExternalProject downloads are
	# skipped and the system libraries are used. CMAKE_ARGS reaches the
	# piper cmake line through go-piper's Makefile.
	local -x CMAKE_ARGS="-DFMT_DIR=${ESYSROOT}/usr -DSPDLOG_DIR=${ESYSROOT}/usr"
	emake -C "${S}" piper
}

src_install() {
	local dest="${LOCAL_AI_BACKENDS_DIR#${EPREFIX}}/piper"

	local-ai-backend_install piper "${S}/piper"

	insinto "${dest}"
	doins -r "${S}/espeak-ng-data"

	exeinto "${dest}/lib"
	# phonemize's install copies the onnxruntime lib into pi/lib; the
	# system copy must not be bundled (RDEPEND provides it).
	rm -f "${GOPIPER}"/piper-phonemize/pi/lib/libonnxruntime.so* || die
	doexe "${GOPIPER}"/piper-phonemize/pi/lib/lib*.so*
	doexe "${GOPIPER}"/espeak/ei/lib/lib*.so* 2>/dev/null || true
}