diff --git a/README.md b/README.md index 9d335a8..553b4ec 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ docker pull ghcr.io/tatertotterson/microwakeword:latest Tagged releases also publish matching immutable image tags: ```bash -docker pull ghcr.io/tatertotterson/microwakeword:v16 +docker pull ghcr.io/tatertotterson/microwakeword:v17 ``` The release tag must match `VERSION`. Update `WHATS_NEW.md` before tagging; the Docker workflow prepends it to GitHub's automatically generated release notes. @@ -32,7 +32,7 @@ Python 3.13 TensorFlow build for `sm_120`: ```bash docker pull ghcr.io/tatertotterson/microwakeword:blackwell -docker pull ghcr.io/tatertotterson/microwakeword:v16-blackwell +docker pull ghcr.io/tatertotterson/microwakeword:v17-blackwell ``` Use the Blackwell image only for RTX 50-series cards. It includes the @@ -53,9 +53,9 @@ docker run -d \ ghcr.io/tatertotterson/microwakeword:latest ``` -Use a version tag such as `ghcr.io/tatertotterson/microwakeword:v16` when you want to pin a known release instead of tracking `latest`. +Use a version tag such as `ghcr.io/tatertotterson/microwakeword:v17` when you want to pin a known release instead of tracking `latest`. For RTX 50-series cards, use `ghcr.io/tatertotterson/microwakeword:blackwell` -or a pinned tag such as `ghcr.io/tatertotterson/microwakeword:v16-blackwell` +or a pinned tag such as `ghcr.io/tatertotterson/microwakeword:v17-blackwell` in the same `docker run` command. The flags: diff --git a/VERSION b/VERSION index b6a7d89..98d9bcb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -16 +17 diff --git a/WHATS_NEW.md b/WHATS_NEW.md index bbd30f0..ebf2aa8 100644 --- a/WHATS_NEW.md +++ b/WHATS_NEW.md @@ -1,2 +1,2 @@ -- Fixed a startup crash caused by newer pip-installed NVIDIA cuBLAS and cuDNN namespace packages not providing a module file path. -- CUDA library discovery now works across both the standard NVIDIA and Blackwell images and safely allows startup when the optional libraries are unavailable. +- Fixed the training-status endpoint crashing after a training log was created because its log-tail limits were missing. +- Restored bounded, incremental training-log updates so the UI can continue showing live progress without repeatedly reading the entire log. diff --git a/tests/test_auto_train.py b/tests/test_auto_train.py index c5837ba..a18edd1 100644 --- a/tests/test_auto_train.py +++ b/tests/test_auto_train.py @@ -425,6 +425,39 @@ class AutoTrainTests(unittest.TestCase): self.assertEqual(trainer.AUTO_TRAIN_STATE["last_stt_device"], "cuda") self.assertEqual(trainer.AUTO_TRAIN_STATE["last_stt_compute_type"], "float16") + def test_train_status_reads_and_increments_training_log_tail(self): + log_path = Path(self.tempdir.name) / "training.log" + log_path.write_text("first\nsecond\nthird\n", encoding="utf-8") + with trainer.STATE_LOCK: + original_training = dict(trainer.STATE["training"]) + trainer.STATE["training"].update( + { + "log_path": str(log_path), + "last_sent_tail": [], + "last_log_size": 0, + } + ) + + try: + with ( + patch.object(trainer, "TRAIN_LOG_TAIL_LINES", 2), + patch.object(trainer, "TRAIN_LOG_MAX_BYTES", 1024), + ): + first_status = trainer.train_status() + self.assertEqual(first_status["training"]["log_lines"], ["second", "third"]) + self.assertEqual(first_status["training"]["log_text"], "second\nthird") + + with log_path.open("a", encoding="utf-8") as log_file: + log_file.write("fourth\n") + + next_status = trainer.train_status() + self.assertEqual(next_status["training"]["log_lines"], ["third", "fourth"]) + self.assertEqual(next_status["training"]["log_text"], "fourth") + finally: + with trainer.STATE_LOCK: + trainer.STATE["training"].clear() + trainer.STATE["training"].update(original_training) + if __name__ == "__main__": unittest.main() diff --git a/trainer_server.py b/trainer_server.py index de0e047..fa1bafb 100644 --- a/trainer_server.py +++ b/trainer_server.py @@ -70,6 +70,8 @@ PIPER_CATALOG_CACHE_FILE = Path( str(DATA_DIR / ".cache" / "piper_voices_catalog.json"), ) ).resolve() +TRAIN_LOG_TAIL_LINES = int(os.environ.get("REC_TRAIN_LOG_TAIL_LINES", "400")) +TRAIN_LOG_MAX_BYTES = int(os.environ.get("REC_TRAIN_LOG_MAX_BYTES", str(512 * 1024))) DATASET_CLEANUP_ARCHIVES = os.environ.get("REC_DATASET_CLEANUP_ARCHIVES", "false").lower() in ("1", "true", "yes", "y") DATASET_CLEANUP_INTERMEDIATE = os.environ.get("REC_DATASET_CLEANUP_INTERMEDIATE_FILES", "false").lower() in ("1", "true", "yes", "y")