The Problem
Content creators must localise video for dozens of platforms (YouTube, TikTok, Bilibili, etc.). Each stage—download, transcription, translation, TTS dubbing, re‑formatting, cover generation—normally requires separate tools, manual file handling and platform‑specific tweaks. The resulting workflow is error‑prone and hard to automate.
What This Does
KrillinAI delivers a single Go‑based pipeline that orchestrates the whole localisation chain. The CLI (cmd/cli/main.go) can invoke each stage independently, while the desktop (cmd/desktop/main.go) and server (cmd/server/main.go) binaries expose the same logic through UI or HTTP. Core services live under internal/ (e.g., internal/service/youtube_subtitle.go for subtitle download, internal/service/dubbing/runner.go for TTS dubbing) and reusable utilities are in pkg/ (e.g., pkg/aliyun/tts.go for Aliyun TTS, pkg/util/subtitle.go for subtitle parsing). Configuration defaults are in config/config-example.toml; concrete style files are under config/.
How It Is Wired
Execution begins at the CLI entry point main in cmd/cli/main.go (line 16). main builds a Service (via internal/cli/commands.go:Parse) and calls Execute. Execute (line 241) dispatches sub‑commands that ultimately invoke the most‑used hub GetLogger (called from 93 locations) for consistent diagnostics.
Typical end‑to‑end flow for a full localisation run:
- Video acquisition –
internal/service/downloader.go(not listed but referenced) downloads viayt‑dlpor local file. - Transcription –
internal/service/audio2subtitle.go:transcribeAudiocalls the OpenAI client (openai.NewClient) to produce a raw transcript. - Subtitle processing –
internal/service/youtube_subtitle.go:Processparses VTT, thensrtToAss(called 13 times) converts to ASS for styling. - Translation –
internal/service/translate.go:BatchTranslateSrtBlocksinvokes the LLM service, logging throughGetLogger. - TTS dubbing –
internal/service/dubbing/runner.go:Runcallspkg/aliyun/tts.go:Text2Speech, which contacts Aliyun’s TTS endpoint. - Embedding & rendering –
internal/service/srt_embed.go:embedSubtitlesruns an externalffmpegcommand to burn subtitles into the video. - Cover generation –
internal/desktop/subtitle.go:GenerateCoverwrites an image file viaos.WriteFile.
All filesystem writes (WriteFile) and external command executions (ffmpeg, yt‑dlp) are routed through the above functions. The most “blast‑radius” functions are GetLogger (93 callers), Close (44), and Parse (34), meaning changes to their signatures affect large portions of the codebase.
The desktop UI (internal/desktop/ui.go) and server router (internal/server/server.go) both import the same service layer, so UI changes do not duplicate business logic. No circular import cycles were detected, but deep nesting (max indentation depth 8) appears in files such as internal/desktop/ui.go and internal/service/youtube_subtitle.go, making those files harder to modify safely.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/KrillinAI
cd KrillinAI
# Build the CLI binary (requires Go 1.22+)
go build -o krillin ./cmd/cli
# Prepare a config (copy the example and edit keys)
cp config/config-example.toml config/config.toml
# Edit config/config.toml to add your OpenAI and Aliyun credentials
# Run a single stage, e.g. transcription
./krillin transcribe --input path/to/video.mp4 --output transcript.srt
A Docker build is also supported:
docker build -t krillinai .
docker run --rm -v $(pwd):/work -w /work krillinai ./krillin transcribe …
The server can be started with go run ./cmd/server and will listen on the port defined in config/config.toml. The desktop binary (cmd/desktop/main.go) launches the UI; no additional build steps are required.
Real‑World Use
A media agency can script a full localisation run:
./krillin download --url https://youtu.be/xyz --out raw.mp4
./krillin transcribe --input raw.mp4 --out raw.srt
./krillin translate --input raw.srt --lang zh --out zh.srt
./krillin dub --input raw.mp4 --subtitle zh.srt --out zh_dubbed.mp4
./krillin cover --input zh_dubbed.mp4 --template "Travel in {lang}" --out cover.jpg
Each command writes its artifacts to the working directory, allowing downstream stages to reuse them without re‑processing.
Code Health & Issues
- Critical – Secrets in workflow:
.github/workflows/gpt-translate.ymlcontainsOPENAI_API_KEYetc. Fix by moving secret‑using steps to aworkflow_runjob or gating on a protected environment. - High – Pin third‑party actions to commit SHA (e.g.,
PairZhu/gpt-translate@master). Replace tags with SHAs. - High – CI never runs tests: workflows lack a test step despite 41 test files. Add a
go test ./...step. - Medium – No explicit
permissionsforGITHUB_TOKENin the same workflow. Declare least‑privilege permissions. - Medium – No Dependabot/Renovate configuration. Add
.github/dependabot.yml. - Medium – Dockerfile uses mutable base
ubuntu:latest. Pin to a digest. - Medium – No dependency‑vulnerability gate in CI. Add
dependency-review-actionorosv-scanner. - Medium – Container runs as root. Create a non‑root
USER. - Low – Jobs lack
timeout-minutes. Set reasonable timeouts.
Additional observations: deep nesting and oversized files (e.g., internal/service/youtube_subtitle.go ~ 2.5 k LOC) increase cognitive load; duplicated 6‑line blocks appear across 36 files, suggesting DRY refactoring.
The Bottom Line
KrillinAI offers a concrete, Go‑native end‑to‑end video localisation pipeline with CLI, desktop, and server front‑ends. It is functional but suffers from maintainability issues—deeply nested, oversized files and duplicated code—plus several CI and security gaps that should be addressed before production deployment. Teams comfortable with Go and needing a customizable, self‑hosted translation/dubbing stack will find it usable after the listed health fixes.