File speechnote.spec of Package speechnote
#
# spec file for package speechnote
#
# Copyright (c) 2025 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
%define aname dsnote
%define __provides_exclude ^(libRHVoice.*\\.so.*|libaprilasr\\.so.*|libbergamot_api.*\\.so.*|libclblast\\.so.*|libespeak-ng\\.so.*|libkenlm\\.so.*|libonnxruntime\\.so.*|libstt\\.so.*|libtensorflowlite\\.so.*|libtflitedelegates\\.so.*|libvosk\\.so.*|libwhisper-.*\\.so.*|mimehandler\\(.*|perl\\(.*)$
%define __requires_exclude ^(libRHVoice.*\\.so.*|libaprilasr\\.so.*|libbergamot_api.*\\.so.*|libclblast\\.so.*|libespeak-ng\\.so.*|libkenlm\\.so.*|libonnxruntime\\.so.*|libstt\\.so.*|libtensorflowlite\\.so.*|libtflitedelegates\\.so.*|libvosk\\.so.*|libwhisper-.*\\.so.*|libamdhip64\\.so.*|libhipblas\\.so.*|librocblas\\.so.*)$
%if 0%{?suse_version} <= 1600
%define pythons python311
%else
%define pythons python3
%endif
%if 0%{?suse_version} < 1600
%define isLeap15 %nil
%else
%undefine isLeap15
%endif
%if 0%{?suse_version} == 1600
%define isLeap16 %nil
%else
%undefine isLeap16
%endif
%bcond_with mkl
%bcond_with download
Name: speechnote
Version: 4.7.0
Release: 0
Summary: App for note taking, reading and translating
URL: https://github.com/mkiol/dsnote
License: MPL-2.0
Group: Productivity/Office/Other
Source: %aname-%version.tar.gz
Source1: sources.tar.zst
Source2: libxkbcommon-1.6.0.tar.xz
Source3: CTranslate2-v4.3.1.tar.zst
Source4: rhvoice-71a1a8.tar.zst
Source5: bergamot-ada8c3.tar.zst
Source6: pythonmodules.tar.zst
Source7: %name.rpmlintrc
Source8: README.SUSE
BuildRequires: cmake
BuildRequires: gcc-c++
BuildRequires: cmake(Qt5LinguistTools)
BuildRequires: cmake(Qt5Multimedia)
BuildRequires: cmake(Qt5Xml)
BuildRequires: cmake(Qt5Sql)
BuildRequires: cmake(Qt5QuickControls2)
BuildRequires: cmake(Qt5X11Extras)
BuildRequires: extra-cmake-modules
%if %{defined isLeap15} || %{defined isLeap16}
BuildRequires: meson
BuildRequires: bison
BuildRequires: pkgconfig(libxml-2.0)
%else
BuildRequires: pkgconfig(xkbcommon-x11) >= 1.6
%endif
BuildRequires: cmake(KF5DBusAddons)
BuildRequires: git-core
BuildRequires: %{python_module devel}
BuildRequires: AppStream
BuildRequires: libXtst-devel
BuildRequires: libXinerama-devel
BuildRequires: libopenblas_pthreads-devel
BuildRequires: libarchive-devel
BuildRequires: fmt-devel
BuildRequires: xz-devel
BuildRequires: %{python_module pybind11-devel}
BuildRequires: librubberband-devel
BuildRequires: libtag-devel
BuildRequires: libnumbertext-devel
BuildRequires: libtool
BuildRequires: ocl-icd-devel
%if %{defined isLeap15}
BuildRequires: libboost_headers1_75_0-devel
%else
%if %{defined isLeap16}
BuildRequires: libboost_headers1_84_0-devel
%else
BuildRequires: libboost_headers-devel
%endif
%endif
BuildRequires: chrpath
BuildRequires: dos2unix
BuildRequires: fdupes
BuildRequires: site-config
BuildRequires: yq
BuildRequires: wget
BuildRequires: %{python_module pip}
BuildRequires: %{python_module Cython0}
BuildRequires: %{python_module wheel}
BuildRequires: %{python_module six}
BuildRequires: %{python_module Markdown}
BuildRequires: %{python_module setuptools}
BuildRequires: zstd
BuildRequires: onednn-devel
%if %{with mkl}
BuildRequires: intel-oneapi-mkl-devel
%endif
Recommends: %{name}-python-modules = %{version}
%description
Speech Note let you take, read and translate notes in multiple languages.
It uses Speech to Text, Text to Speech and Machine Translation to do so.
Text and voice processing take place entirely offline, locally on your
computer, without using a network connection.
%package python-modules
Summary: Extra python modules
Requires: %{name} = %{version}
Requires: libdnnl3
AutoReqProv: no
%description python-modules
Python modules for %name
%prep
%setup -q -n %{aname}-%{version}
%if %{without download}
#do not download libsst
sed -i '/DOWNLOAD/d' cmake/libstt.cmake
%endif
mkdir build build/aux external external/pythonsrc
%if %{without download}
tar fx %SOURCE1 -C build
tar fx %SOURCE4 -C external
sed -i '/GIT_REPOSITORY/d;/GIT_TAG/d;/GIT_SHALLOW/d' cmake/rhvoice.cmake
tar fx %SOURCE5 -C external
mv external/bergamot external/bergamotfallback
tar fx %SOURCE5 -C external
sed -i '/GIT_REPOSITORY/d;/GIT_TAG/d;/GIT_SHALLOW/d' cmake/bergamot.cmake
%endif
#endif without download
srcdownload () {
local n i URL DEST SHA256
n=$(yq '.modules[] | explode(.) | select(.name == "'$2'" )' $3 | yq '.sources' | grep -c -e ^-)
if ((n)); then
for ((i=0;i<n;i++)) ; do
case $(yq '.modules[] | explode(.) | select(.name == "'$2'" )' $3 | yq '.sources['$i'].type') in
git)
git -C $1 clone --recursive $(yq '.modules[] | explode(.) | select(.name == "'$2'" )' $3 | yq '.sources['$i'].url')
pushd $1/* >/dev/null
git checkout $(yq '.modules[] | explode(.) | select(.name == "'$2'" )' $3 | yq '.sources['$i'].commit')
popd >/dev/null
;;
file|archive)
URL=$(yq '.modules[] | explode(.) | select(.name == "'$2'" )' $3 | yq '.sources['$i'].url')
DEST=$(yq '.modules[] | explode(.) | select(.name == "'$2'" )' $3 | yq '.sources['$i'].dest-filename')
[[ $DEST = null ]] && DEST=${URL##*/}
SHA256=$(yq '.modules[] | explode(.) | select(.name == "'$2'" )' $3 | yq '.sources['$i'].sha256')
[[ ! -f $1/$DEST ]] && wget -q -O $1/$DEST $URL
[[ $(sha256sum $1/$DEST | cut -f1 -d" ") = $SHA256 ]]
;;&
archive)
tar fx $1/$DEST -C $1 && mv $1/$DEST $1/..
;;
patch|file) : ;;
*) false ;;
esac
done
fi
}
%if %{with download}
srcdownload build/aux ctranslate2 $PWD/flatpak/net.mkiol.SpeechNote.yaml
%else
tar fx %SOURCE3 -C build/aux
%endif
%if %{with download}
for m in $(yq '.modules[].name | explode(.)' flatpak/python3-modules-x86-64.yaml) ; do
srcdownload external/pythonsrc $m $PWD/flatpak/python3-modules-x86-64.yaml
done
%else
tar fx %SOURCE6 -C external/pythonsrc
%endif
cp %SOURCE8 .
#rpath /usr/share/dsnote/lib
sed -i '/-rpath/s@/lib@/share/%{aname}&@' CMakeLists.txt
#fix build error
sed -i 's@X11::Xtst@Xtst@;s@X11::Xinerama@Xinerama@' CMakeLists.txt
%build
export PKG_CONFIG_PATH=%{python_sitelib}/pybind11/share/pkgconfig
%if %{defined isLeap15} || %{defined isLeap16}
mkdir xkb
tar fx %SOURCE2 -C xkb
cd xkb/libxkbcommon-1.6.0
mkdir build
%meson -Denable-docs=false -Ddefault_library=static -Denable-x11=true -Denable-tools=false -Denable-bash-completion=false --buildtype=release
%meson_build
DESTDIR=$PWD/build meson install -C x86_64-suse-linux --no-rebuild
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$PWD/build%{_libdir}/pkgconfig
sed -i '/^prefix=/s@=.*@=${pcfiledir}/../../@' build%{_libdir}/pkgconfig/xkbcommon.pc
sed -i '/^prefix=/s@=.*@=${pcfiledir}/../../@' build%{_libdir}/pkgconfig/xkbcommon-x11.pc
cd ../..
%endif
%cmake \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_DESKTOP=ON \
\
-DBUILD_WHISPERCPP_CLBLAST=ON \
-DBUILD_WHISPERCPP_VULKAN=ON \
%if %{defined isLeap15} || %{defined isLeap16}
-DCMAKE_EXE_LINKER_FLAGS_RELEASE=-L$PWD/../xkb/libxkbcommon-1.6.0/build/%{_libdir} \
%endif
-DBUILD_OPENBLAS=OFF \
-DBUILD_LIBARCHIVE=OFF \
-DBUILD_XZ=OFF \
-DBUILD_FMT=OFF \
-DBUILD_RUBBERBAND=OFF \
-DBUILD_LIBNUMBERTEXT=OFF \
-DBUILD_PYBIND11=OFF \
-DBUILD_FFMPEG=ON \
-DBUILD_TAGLIB=OFF \
-DBUILD_ESPEAK=ON \
-DCMAKE_VERBOSE_MAKEFILE=OFF \
-Wno-dev
%cmake_build
cd aux/CTranslate2*
%cmake \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_CLI=OFF \
-DCUDA_DYNAMIC_LOADING=ON \
-DOPENMP_RUNTIME=COMP \
%if %{with mkl}
-DWITH_MKL=ON \
%else
-DWITH_MKL=OFF \
%endif
-DWITH_DNNL=ON \
-DWITH_RUY=ON \
-DCMAKE_CXX_FLAGS=-msse4.1 \
-DCMAKE_INSTALL_PREFIX=%{_datadir}/%{aname}/python/extensions/cpu \
%{nil}
%cmake_build
DESTDIR=$PWD/../tmpinst make install
cd ../python
sed -i '/^ldflags/s@=.*@= ["-Wl,-rpath,%_datadir/%{aname}/python/extensions/cpu/%{_lib}"]@' setup.py
CTRANSLATE2_ROOT=$PWD/../tmpinst/%{_datadir}/%{aname}/python/extensions/cpu python%{python_version} setup.py bdist_wheel
cd ../../..
%install
%cmake_install
FLATPAK_DEST=%buildroot%{_datadir}/%{aname}/python
export PYTHONPATH=$FLATPAK_DEST/extensions/cpu/%{_lib}/python%{python_version}/site-packages:$FLATPAK_DEST/lib/python%{python_version}/site-packages:$FLATPAK_DEST/%{_lib}/python%{python_version}/site-packages
YAMLSRC=$PWD/flatpak/python3-modules-x86-64.yaml
[[ -f $YAMLSRC ]]
MODSRCDIR=$PWD/external/pythonsrc
modules=$(yq '.modules[].name' $YAMLSRC)
for m in $modules ; do
DSBUILDFLAGS=
BUILDMOD=$PWD/python-modules
mkdir $BUILDMOD
pushd $MODSRCDIR >/dev/null
modsrc=$(yq '.modules[] | explode(.) | select(.name == "'$m'" )' $YAMLSRC | yq '.sources[].url' | sed 's@.*/@@;s@%2B@+@g')
for a in $modsrc ; do
[[ -f $a ]] && ln $a $BUILDMOD
done
popd >/dev/null
pushd $BUILDMOD >/dev/null
#build
%if ! ( %{defined isLeap15} || %{defined isLeap16} )
[[ $m = python3-mycroft_mimic3_tts ]] && DSBUILDFLAGS="CFLAGS=-Wno-error=incompatible-pointer-types"
%endif
eval $(yq '.modules[] | explode(.) | select(.name == "'$m'" )' $YAMLSRC | yq '.build-commands[]' | sed "s@python @python%{python_version} @;s@^pip3 @$DSBUILDFLAGS pip3 @;s@\$@;@")
#cleanup
eval $(yq '.modules[] | explode(.) | select(.name == "'$m'" )' $YAMLSRC | yq '.cleanup[]' | sed 's@^@rm -rf $FLATPAK_DEST@;s@/lib/@/lib*/@g;s@$@;@')
popd >/dev/null
rm -r $BUILDMOD
done
YAMLSRC=$(dirname $YAMLSRC)/net.mkiol.SpeechNote.yaml
cd build/aux/CTranslate2*
%cmake_install
( export PYTHONPATH=${FLATPAK_DEST}/extensions/cpu/%{_lib}/python%{python_version}/site-packages:$FLATPAK_DEST/lib/python%{python_version}/site-packages:$FLATPAK_DEST/%{_lib}/python%{python_version}/site-packages
rm -rf ${FLATPAK_DEST}/%{_lib}/python%{python_version}/site-packages/ctranslate2*
m=ctranslate2
#install
eval $(yq '.modules[] | explode(.) | select(.name == "'$m'" )' $YAMLSRC | yq '.post-install[]' | grep -A4 ^pip3 | sed 's@/lib/@/lib*/@g;s@$@;@')
#cleanup
eval $(yq '.modules[] | explode(.) | select(.name == "'$m'" )' $YAMLSRC | yq '.cleanup[]' | sed 's@^@rm -rf $FLATPAK_DEST@;s@/lib/@/lib*/@g;s@$@;@')
)
cd ../../..
rm -r $FLATPAK_DEST/lib{,64}/python%{python_version}/site-packages/__pycache__
rm -r $FLATPAK_DEST/lib/python%{python_version}/site-packages/pypinyin/__pycache__
rm -r $FLATPAK_DEST/%{_lib}/python%{python_version}/site-packages/pandas/tests
rm -r $FLATPAK_DEST/extensions/cpu/%{_lib}/python%{python_version}/site-packages/torch/{test,include}
rm $FLATPAK_DEST/%{_lib}/python%{python_version}/site-packages/numpy/*/lib/lib*.a
find $FLATPAK_DEST -name "*.so" -exec strip --strip-unneeded {} \;
find $FLATPAK_DEST -name "*.so.*" -exec strip --strip-unneeded {} \;
find $FLATPAK_DEST/extensions/cpu/%{_lib}/python%{python_version}/site-packages/torch -type f -perm -a+x -a ! -name "*.so.*" -exec strip --strip-unneeded {} \;
chmod a-x $FLATPAK_DEST/lib/python%{python_version}/site-packages/tensorboard/webfiles.zip
rm $FLATPAK_DEST/%{_lib}/python%{python_version}/site-packages/.gitignore
rm -r $FLATPAK_DEST/share
rm $FLATPAK_DEST/bin/widsindex
rmdir $FLATPAK_DEST/bin
%fdupes %buildroot%_datadir/%{aname}/python
mv %buildroot%{_bindir}/%{aname} %buildroot%{_bindir}/%{aname}.exe
#main program script
SHPRE=%_datadir/%{aname}/python/extensions
SHPOST=%{_lib}/python%{python_version}/site-packages
SHSP=
echo -e "#!/bin/bash\n" >%buildroot%{_bindir}/%{aname}
echo -e "${SHSP}export LD_LIBRARY_PATH=\${LD_LIBRARY_PATH:+\$LD_LIBRARY_PATH:}$SHPRE/cpu/%{_lib}\n${SHSP}export PYTHONPATH=\${PYTHONPATH:+\$PYTHONPATH:}$SHPRE/cpu/$SHPOST" >>%buildroot%{_bindir}/%{aname}
echo -e 'export PYTHONPATH=$PYTHONPATH:%_datadir/%{aname}/python/lib/python%{python_version}/site-packages:%_datadir/%{aname}/python/'$SHPOST'\nexec %{aname}.exe "$@"' >>%buildroot%{_bindir}/%{aname}
chmod a+x %buildroot%{_bindir}/%{aname}
ln -s %aname %buildroot%{_bindir}/%{name}
chrpath -r %_datadir/%{aname}/lib %buildroot%_datadir/%aname/bin/espeak-ng
chrpath -r %_datadir/%{aname}/lib %buildroot%_datadir/%aname/lib/libstt.so
dos2unix %buildroot%_datadir/%aname/share/uroman/bin/*
chmod u+x %buildroot%_datadir/%aname/share/uroman/bin/*.pl
export NO_BRP_CHECK_RPATH=true
%files
%doc README.md README.SUSE
%license LICENSE
%{_bindir}/%{name}
%{_bindir}/%{aname}
%{_bindir}/%{aname}.exe
%{_datadir}/applications/%{aname}.desktop
%{_datadir}/dbus-1/services/%{aname}.service
%{_datadir}/icons/hicolor/*
%{_datadir}/metainfo/%{aname}.metainfo.xml
%{_datadir}/%{aname}
%exclude %{_datadir}/%{aname}/python
%files python-modules
%{_datadir}/%{aname}/python
%changelog