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:

  1. Video acquisitioninternal/service/downloader.go (not listed but referenced) downloads via yt‑dlp or local file.
  2. Transcriptioninternal/service/audio2subtitle.go:transcribeAudio calls the OpenAI client (openai.NewClient) to produce a raw transcript.
  3. Subtitle processinginternal/service/youtube_subtitle.go:Process parses VTT, then srtToAss (called 13 times) converts to ASS for styling.
  4. Translationinternal/service/translate.go:BatchTranslateSrtBlocks invokes the LLM service, logging through GetLogger.
  5. TTS dubbinginternal/service/dubbing/runner.go:Run calls pkg/aliyun/tts.go:Text2Speech, which contacts Aliyun’s TTS endpoint.
  6. Embedding & renderinginternal/service/srt_embed.go:embedSubtitles runs an external ffmpeg command to burn subtitles into the video.
  7. Cover generationinternal/desktop/subtitle.go:GenerateCover writes an image file via os.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.yml contains OPENAI_API_KEY etc. Fix by moving secret‑using steps to a workflow_run job 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 permissions for GITHUB_TOKEN in 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-action or osv-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.