Skip to content

Commit 4dcacb7

Browse files
committed
feat: now it is for real, all of the files included
1 parent c493478 commit 4dcacb7

33 files changed

+2049
-5156
lines changed

.github/workflows/build.yaml

Lines changed: 0 additions & 64 deletions
This file was deleted.

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
# Build output
2+
tts/
3+
build/
4+
15
# .NET
26
bin/
37
obj/
48
*.user
59
*.suo
610
.vs/
711
publish/
12+
server/HonkTTS.Installer.exe
813

914
# Python
1015
__pycache__/

README.md

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,51 @@
11
# HonkTTS
22

3-
This repo will be the future local TTS server for Unitystation. Idea is for the client to run locally their own instance of
4-
HonkTTS and their game to request audio data from it, then deserialize and convert into ``wav`` so they can be set as clip
5-
in an AudioSource and played using the same pipeline any ingame sound uses, being affected by ambient, spatial and
6-
following their source.
3+
HonkTTS is the text-to-speech service used by Unitystation to generate immersive in-game voices.
4+
It is an optional module that runs alongside the game and is orchestrated by StationHub.
75

8-
## Development Requirements
6+
This repository contains:
7+
- The Python TTS server (`server/tts_server.py`)
8+
- Scripts to run and test the server
9+
- A cross-platform .NET installer (`installer/`) that packages and sets up everything
910

10-
- [Python 3.11](https://www.python.org/downloads/release/python-3110/)
11-
- [espeak-ng installed](https://github.com/espeak-ng/espeak-ng/blob/master/docs/guide.md)
11+
## Latest Installer
1212

13-
## User requirements
14-
Idea is to compile the application using Nuitka and uploading an artifact for each supported platform. The final users
15-
would need to download this executable and set its path inside the game for it to establish communication with it.
13+
Download the latest installer build from GitHub Releases:
1614

17-
Sadly, the final user also needs [espeak-ng installed](https://github.com/espeak-ng/espeak-ng/blob/master/docs/guide.md).
18-
In the case of a Mac user, they would have to [use this homebrew](https://formulae.brew.sh/formula/espeak-ng) (untested).
15+
`https://github.com/unitystation/honk_tts/releases`
16+
17+
If you only want to use HonkTTS (not develop it), start there.
18+
19+
## Contributing Prerequisites
20+
21+
Required:
22+
- Git (clone/push workflow)
23+
- `.NET SDK 10` (project targets `net10.0`)
24+
25+
Useful depending on what you change:
26+
- Python 3.10+ (for direct server work and local script testing)
27+
28+
## Start Contributing
29+
30+
1. Clone the repo.
31+
2. Build and run the local end-to-end flow:
32+
- Windows: `dev.bat`
33+
- Linux/macOS: `./dev.sh`
34+
3. This will:
35+
- Build the installer
36+
- Install into `./tts` (including Python runtime and dependencies)
37+
- Run server tests (`test_tts`)
38+
39+
The `dev` flow is enough to start iterating even without a system Python install.
40+
You can edit the checked-in scripts/source in this repo, rerun `dev`, and validate changes against the locally installed `./tts` instance.
41+
42+
If you only want to build artifacts:
43+
- Windows: `build.bat`
44+
- Linux/macOS: `./build.sh`
45+
46+
## Project Layout
47+
48+
- `server/` - TTS API server and runtime scripts
49+
- `installer/` - Native AOT .NET installer source
50+
- `build*.{bat,sh}` - local build/package scripts
51+
- `dev*.{bat,sh}` - quick contributor workflow scripts

build.bat

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@echo off
2+
setlocal
3+
4+
set "ROOT=%~dp0"
5+
set "OUT=%ROOT%build"
6+
7+
echo Cleaning output directory...
8+
if exist "%OUT%" rmdir /s /q "%OUT%"
9+
mkdir "%OUT%"
10+
mkdir "%OUT%\scripts"
11+
12+
echo Copying server files...
13+
copy "%ROOT%server\tts_server.py" "%OUT%\" >nul
14+
copy "%ROOT%server\requirements.txt" "%OUT%\" >nul
15+
copy "%ROOT%server\scripts\start_tts.bat" "%OUT%\scripts\" >nul
16+
copy "%ROOT%server\scripts\start_tts.sh" "%OUT%\scripts\" >nul
17+
copy "%ROOT%server\scripts\test_server.py" "%OUT%\scripts\" >nul
18+
copy "%ROOT%server\scripts\test_tts.bat" "%OUT%\scripts\" >nul
19+
copy "%ROOT%server\scripts\test_tts.sh" "%OUT%\scripts\" >nul
20+
21+
echo Building installer (Release, Native AOT, win-x64)...
22+
dotnet publish "%ROOT%installer\src\HonkTTS.Installer\HonkTTS.Installer.csproj" ^
23+
-r win-x64 -c Release ^
24+
-o "%OUT%" ^
25+
--nologo
26+
27+
if %errorlevel% neq 0 (
28+
echo Build failed.
29+
exit /b 1
30+
)
31+
32+
echo.
33+
echo Build complete: %OUT%
34+
dir /b "%OUT%"

build.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT="$(cd "$(dirname "$0")" && pwd)"
5+
OUT="$ROOT/build"
6+
7+
echo "Cleaning output directory..."
8+
rm -rf "$OUT"
9+
mkdir -p "$OUT/scripts"
10+
11+
echo "Copying server files..."
12+
cp "$ROOT/server/tts_server.py" "$OUT/"
13+
cp "$ROOT/server/requirements.txt" "$OUT/"
14+
cp "$ROOT/server/scripts/start_tts.bat" "$OUT/scripts/"
15+
cp "$ROOT/server/scripts/start_tts.sh" "$OUT/scripts/"
16+
cp "$ROOT/server/scripts/test_server.py" "$OUT/scripts/"
17+
cp "$ROOT/server/scripts/test_tts.bat" "$OUT/scripts/"
18+
cp "$ROOT/server/scripts/test_tts.sh" "$OUT/scripts/"
19+
20+
ARCH="$(uname -m)"
21+
case "$(uname -s)" in
22+
Linux*) RID="linux-x64"; [ "$ARCH" = "aarch64" ] && RID="linux-arm64" ;;
23+
Darwin*) RID="osx-x64"; [ "$ARCH" = "arm64" ] && RID="osx-arm64" ;;
24+
*) echo "Unsupported OS"; exit 1 ;;
25+
esac
26+
27+
echo "Building installer (Release, Native AOT, $RID)..."
28+
dotnet publish "$ROOT/installer/src/HonkTTS.Installer/HonkTTS.Installer.csproj" \
29+
-r "$RID" -c Release \
30+
-o "$OUT" \
31+
--nologo
32+
33+
echo ""
34+
echo "Build complete: $OUT"
35+
ls "$OUT"

dev.bat

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@echo off
2+
setlocal
3+
4+
set "ROOT=%~dp0"
5+
set "TARGET=%ROOT%tts"
6+
7+
call "%ROOT%build.bat"
8+
if errorlevel 1 exit /b %errorlevel%
9+
10+
"%ROOT%build\HonkTTS.Installer.exe" "%TARGET%"
11+
if errorlevel 1 exit /b %errorlevel%
12+
13+
call "%ROOT%tts\test_tts.bat" --keep %*
14+
exit /b %errorlevel%

dev.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT="$(cd "$(dirname "$0")" && pwd)"
5+
TARGET="$ROOT/tts"
6+
7+
"$ROOT/build.sh"
8+
9+
INSTALLER="$ROOT/build/HonkTTS.Installer"
10+
if [ -x "$INSTALLER" ]; then
11+
"$INSTALLER" "$TARGET"
12+
elif [ -x "$INSTALLER.exe" ]; then
13+
"$INSTALLER.exe" "$TARGET"
14+
else
15+
echo "Installer binary not found in $ROOT/build"
16+
exit 1
17+
fi
18+
19+
"$ROOT/tts/test_tts.sh" --keep "$@"

installer/HonkTTS.Installer.sln

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
VisualStudioVersion = 17.0.31903.59
4+
MinimumVisualStudioVersion = 10.0.40219.1
5+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HonkTTS.Installer", "src\HonkTTS.Installer\HonkTTS.Installer.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
6+
EndProject
7+
Global
8+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
9+
Debug|Any CPU = Debug|Any CPU
10+
Release|Any CPU = Release|Any CPU
11+
EndGlobalSection
12+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
13+
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14+
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
15+
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
16+
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
17+
EndGlobalSection
18+
EndGlobal
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<PublishAot>true</PublishAot>
9+
<InvariantGlobalization>true</InvariantGlobalization>
10+
<RootNamespace>HonkTTS.Installer</RootNamespace>
11+
<AssemblyName>HonkTTS.Installer</AssemblyName>
12+
</PropertyGroup>
13+
14+
</Project>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
namespace HonkTTS.Installer.Models;
2+
3+
public sealed class InstallConfig
4+
{
5+
public string BaseDir { get; }
6+
7+
public string PythonDir => Path.Combine(BaseDir, "python");
8+
public string VenvDir => Path.Combine(BaseDir, "venv");
9+
public string EspeakDir => Path.Combine(BaseDir, "espeak-ng");
10+
public string ServerDir => Path.Combine(BaseDir, "server");
11+
public string TempDir => Path.Combine(BaseDir, ".tmp");
12+
13+
public string PythonExe => Path.Combine(PythonDir, PlatformInfo.PythonExeRelative);
14+
public string PipExe => Path.Combine(PythonDir, PlatformInfo.PipExeRelative);
15+
public string VenvPythonExe => Path.Combine(VenvDir, PlatformInfo.VenvPythonRelative);
16+
public string VenvPipExe => Path.Combine(VenvDir, PlatformInfo.VenvPipRelative);
17+
18+
public string EspeakExe => Path.Combine(EspeakDir, PlatformInfo.IsWindows ? "espeak-ng.exe" : "espeak-ng");
19+
public string EspeakDataDir => Path.Combine(EspeakDir, "espeak-ng-data");
20+
21+
public string StartScript => PlatformInfo.IsWindows
22+
? Path.Combine(BaseDir, "start_tts.bat")
23+
: Path.Combine(BaseDir, "start_tts.sh");
24+
public string TestScript => PlatformInfo.IsWindows
25+
? Path.Combine(BaseDir, "test_tts.bat")
26+
: Path.Combine(BaseDir, "test_tts.sh");
27+
public string MetadataFile => Path.Combine(BaseDir, "config.json");
28+
29+
public string SourceServerDir { get; }
30+
31+
public InstallManifest? InstalledManifest { get; set; }
32+
33+
public InstallManifest ExpectedManifest { get; set; } = new();
34+
35+
public static InstallConfig FromArgs(string[] args)
36+
{
37+
var baseDir = args.Length > 0
38+
? args[0]
39+
: Path.Combine(
40+
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
41+
"StationHub", "Installations", "tts");
42+
43+
return new InstallConfig(baseDir);
44+
}
45+
46+
private InstallConfig(string baseDir)
47+
{
48+
BaseDir = Path.GetFullPath(baseDir);
49+
50+
// The server source is located relative to the installer binary or CWD.
51+
var candidates = new[]
52+
{
53+
Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "server"),
54+
Path.Combine(AppContext.BaseDirectory, "server"),
55+
Path.Combine(Directory.GetCurrentDirectory(), "server"),
56+
Path.Combine(Directory.GetCurrentDirectory(), "..", "server"),
57+
};
58+
59+
SourceServerDir = candidates
60+
.Select(d => Path.GetFullPath(d))
61+
.FirstOrDefault(d => File.Exists(Path.Combine(d, "tts_server.py")))
62+
?? throw new DirectoryNotFoundException(
63+
"Could not locate server/tts_server.py relative to the installer.");
64+
}
65+
}

0 commit comments

Comments
 (0)