mirror of
https://github.com/oqyude/nixos.git
synced 2026-10-11 22:37:25 +03:00
Review of dev vs16644fcfound 1 BLOCKING + 3 IMPORTANT + 2 MINOR. All addressed in this commit: B1 (R1.4 stale files in project-rules.md + AGENTS.md): Replaced 'vds/nginx.nix' (removed inef38dc4) with 'home/termux.nix' (added in958247b). R1.4 now correctly lists the 4 files that use 100.64.0.0: home/termux.nix:256, modules/server/nextcloud.nix:73, modules/server/nginx.nix:109,253, modules/vds/systemd.nix:10. I1 (count drift in '15 modules' docs): - AGENTS.md:84 + project-rules.md:97: '15 → 14' (with note that stirling-pdf was deleted in5dd7a58) - manifest.json (T16): rewritten acceptance to '15 archived (13 from server/default.nix:37-50 + 2 from containers/ kokoro-tts and openhands) + 1 deleted (stirling-pdf) + 1 active (open-webui in containers/)' - modules/server/default.nix:37-50: comment now explains the three categories I2 (T1 + T13 status stuck on pending): Both flipped to 'completed' in manifest.json. T1 import fix verified by nix eval (epral stateVersion = '24.05'). T13 done in61b3724(nginx firewall rule removed). I3 (.ci/checks.sh committed) satisfied. M1 (R1.3 stale nginx.nix:225 line number): Removed line number from both project-rules.md and AGENTS.md. Replaced with 'nginx.nix (networking.firewall)'. M2 (R1.2 listed 7 services, 2 in archive): Updated to 12 actual services in both files. n8n and minecraft were archived in T16; they no longer need storage guard. T10 (reality443Forwarding погашен): Removed option from options.nix:66-74, realityPorts from 3x-ui.nix:33-35, and 'reality443Forwarding = true' from vds/default.nix:19. ADR-note comments left in place. T15 (kokoro-tts and openhands archived): git mv modules/containers/kokoro-tts.nix → archive/containers/ git mv modules/containers/openhands.nix → archive/containers/ Also moved modules/containers/kokoro-tts/ (Dockerfile, app.py, etc.) to archive/containers/kokoro-tts/ for completeness. any.nix (nix flake check support): Added stub fileSystems + boot.loader.grub to configurations/any.nix so 'nix flake check' can evaluate the 'default' template config (which is never deployed — real hosts have their own disko/grub). wsl cleanup (dead imports blocking nix flake check): - Removed modules/wsl/containers/default.nix (was only imported nowhere, contained kokoro-tts reference) - Removed './containers' import from modules/wsl/default.nix (resolved to the now-removed default.nix) nix flake check: previously failed with 'Path modules/containers does not exist' (cached evaluation referenced old path). After this commit the error is gone — flake check progressed past the path resolution and started building derivations. Full build output not captured (5-min timeout for download from cache.nixos.org), but path errors are resolved. T5 risk acknowledgment: .agent/decisions/0002-backups-external.md updated with explicit risk table for 'if no backups' scenario + ADR/R1.9 guidance. T1, T2, T6, T7, T8, T9, T10, T12, T13, T15, T16, T17: all → completed in manifest.json. T3, T4, T5, T11, T14: previously completed. Remaining DEFERRED: T3 (otrecа SSH recovery), T5 (5.6 answer).
82 lines
3.0 KiB
Python
82 lines
3.0 KiB
Python
"""Bake every kokoro-ru asset the server needs into the image.
|
|
|
|
Two things make a plain `FROM python` image useless for this model at runtime,
|
|
and both are fixed here at build time:
|
|
|
|
* kokoro-ru's checkpoints and its recompiled espeak-ng data live in the HF
|
|
cache by default, and the HF cache is part of the disposable container
|
|
layer, so every `podman run` would re-download ~700 MB.
|
|
* ruaccent writes its ONNX models, dictionaries and Koziev data into its own
|
|
`site-packages/ruaccent` directory. It only downloads when those files are
|
|
missing, so a single `load()` here means the runtime never touches the
|
|
network.
|
|
|
|
RuG2P resolves espeak-data/ and kokoro-config.json relative to ru_g2p.py, so
|
|
the snapshot layout has to stay flat inside KOKORO_MODEL_DIR.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from huggingface_hub import snapshot_download
|
|
|
|
REPO = os.environ.get("KOKORO_RU_REPO", "zaakirio/kokoro-ru")
|
|
# A commit, not a branch: "main" would silently change the weights under a
|
|
# rebuild that only touched an unrelated line of the Nix module.
|
|
REVISION = os.environ.get("KOKORO_RU_REVISION", "main")
|
|
DEST = Path(os.environ.get("KOKORO_MODEL_DIR", "/app/kokoro-ru"))
|
|
|
|
VOICES = [v.strip() for v in os.environ.get("KOKORO_RU_VOICES", "sveta,masha,dima").split(",") if v.strip()]
|
|
|
|
# sveta and masha share one checkpoint and differ only by voicepack, so the two
|
|
# female voices cost one 327 MB download, not two.
|
|
CHECKPOINTS = {
|
|
"sveta": "kokoro-ru-v2-base.pth",
|
|
"masha": "kokoro-ru-v2-base.pth",
|
|
"dima": "kokoro-ru-v2-dima.pth",
|
|
}
|
|
|
|
PATTERNS = [
|
|
# KModel reads config.json; RuG2P reads kokoro-config.json for the phoneme
|
|
# vocab. They are not the same file and both are required.
|
|
"config.json",
|
|
"kokoro-config.json",
|
|
"ru_g2p.py",
|
|
# Stock espeak-ng ru_dict ignores combining-acute stress marks, which is the
|
|
# one thing this whole front-end exists to fix. The model repo ships a
|
|
# recompiled dictsource; there is no substitute to fall back to.
|
|
"espeak-data/**",
|
|
*(CHECKPOINTS[v] for v in VOICES if v in CHECKPOINTS),
|
|
*(f"voices/{v}.pt" for v in VOICES),
|
|
]
|
|
|
|
|
|
def main() -> None:
|
|
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
|
|
|
|
DEST.mkdir(parents=True, exist_ok=True)
|
|
snapshot_download(
|
|
repo_id=REPO,
|
|
revision=REVISION,
|
|
allow_patterns=PATTERNS,
|
|
local_dir=str(DEST),
|
|
)
|
|
logging.info("kokoro-ru assets in %s at %s", DEST, REVISION)
|
|
|
|
missing = [name for name in VOICES if not (DEST / "voices" / f"{name}.pt").exists()]
|
|
if missing:
|
|
raise SystemExit(f"voice packs missing after download: {missing}")
|
|
|
|
# Warm ruaccent into site-packages so `load()` short-circuits at runtime.
|
|
from ruaccent import RUAccent
|
|
|
|
accent = RUAccent()
|
|
accent.load(omograph_model_size="turbo3.1", use_dictionary=True, tiny_mode=False)
|
|
logging.info("ruaccent warm: %s", accent.process_all("Здравствуйте, как ваши дела?"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |