diff --git a/.gitea/workflows/audiobook.yml b/.gitea/workflows/audiobook.yml index c3bdc8b..1904162 100644 --- a/.gitea/workflows/audiobook.yml +++ b/.gitea/workflows/audiobook.yml @@ -12,6 +12,10 @@ on: description: 'PDF path inside the repo (empty = every PDF waiting in _incoming/)' required: false default: 'books/clark-glenn/the-man-who-tapped-the-secrets-of-the-universe/The Man Who Tapped the Secrets of the Universe - by Glenn Clark (Walter Russell).pdf' + voice_endpoint: + description: 'Testing only: use this voice URL instead of the default (for example to prove a failed voice run commits nothing)' + required: false + default: '' dry_run: description: 'true = text stages only, voice reachability check, push-permission test, commit nothing' type: boolean @@ -31,7 +35,7 @@ jobs: # The commit-back commit carries [skip ci] and removes the PDF from _incoming/, so it cannot start another run. if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} env: - AUDIOBOOK_VOICE_ENDPOINT: ${{ vars.AUDIOBOOK_VOICE_ENDPOINT || 'http://192.168.1.202:8090/tts' }} + AUDIOBOOK_VOICE_ENDPOINT: ${{ (github.event_name == 'workflow_dispatch' && inputs.voice_endpoint) || vars.AUDIOBOOK_VOICE_ENDPOINT || 'http://192.168.1.202:8090/tts' }} AUDIOBOOK_WORK_DIR: /tmp/audiobook-work AUDIOBOOK_REQUIRE_OCR: '1' BRANCH: ${{ github.ref_name }} diff --git a/.gitea/workflows/netcheck.yml b/.gitea/workflows/netcheck.yml deleted file mode 100644 index 3130b11..0000000 --- a/.gitea/workflows/netcheck.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Diagnostic only: what can a job container reach? Run by hand (Run workflow). Changes nothing. -name: netcheck -on: - workflow_dispatch: -jobs: - net: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Network facts from inside the job container - run: | - set +e - echo "--- identity"; hostname; cat /etc/resolv.conf - echo "--- addr/route/mtu"; (ip addr || cat /proc/net/dev) 2>&1 | head -30; ip route 2>&1 | head - echo "--- dns gitea"; getent hosts gitea.vps1.afterthedemo.com - echo "--- server url: ${{ github.server_url }}" - echo "--- curl gitea healthz"; curl -sS -m 20 -o /dev/null -w "http=%{http_code} connect=%{time_connect}s total=%{time_total}s ip=%{remote_ip}\n" https://gitea.vps1.afterthedemo.com/api/healthz - echo "--- curl gitea repo page"; curl -sS -m 30 -o /dev/null -w "http=%{http_code} size=%{size_download} total=%{time_total}s\n" https://gitea.vps1.afterthedemo.com/Ty_Tech/old-books - echo "--- git ls-remote (token)"; time git -c http.extraheader="AUTHORIZATION: basic $(printf 'x-access-token:%s' '${{ github.token }}' | base64 -w0)" ls-remote https://gitea.vps1.afterthedemo.com/Ty_Tech/old-books 2>&1 | head -5 - echo "--- curl voice model-info"; curl -sS -m 20 -w "\nhttp=%{http_code} total=%{time_total}s\n" http://192.168.1.202:8090/api/model-info - echo "--- ping mtu probes to gitea"; for s in 1200 1400 1472; do curl -sS -m 15 -o /dev/null -w "post $s bytes: http=%{http_code}\n" -X POST --data-binary @<(head -c $s /dev/zero) https://gitea.vps1.afterthedemo.com/api/healthz; done diff --git a/_pipeline/process.py b/_pipeline/process.py index 8887bd4..98e34db 100644 --- a/_pipeline/process.py +++ b/_pipeline/process.py @@ -193,6 +193,7 @@ def run_text_stages(cfg, pdf, title, author): def run_audio_stages(cfg, book_dir, book, force): + """Returns True if any audio was rendered.""" out_dir = settings.audio_dir(cfg, book_dir) built = book.setdefault("audio_built", {}) todo = [] @@ -228,10 +229,12 @@ def run_audio_stages(cfg, book_dir, book, force): print("voice model unloaded to free the GPU") else: print("nothing to render") + rendered = bool(todo) step("ACX check") rc = acx_check.run(cfg, [out_dir]) if rc != 0: raise Failed("ACX check FAILED (see the table above); nothing should be committed") + return rendered def process(cfg, pdf, dry_run=False, force=False, title=None, author=None, compare=None, result_file=None, compare_strict=False): @@ -244,6 +247,7 @@ def process(cfg, pdf, dry_run=False, force=False, title=None, author=None, compa real_out = sys.stdout sys.stdout = Tee(real_out, log) book_dir = None + rendered = False try: print("process %s%s" % (os.path.basename(pdf), " [DRY RUN: text stages only]" if dry_run else "")) book_dir, book = run_text_stages(cfg, pdf, title, author) @@ -269,7 +273,7 @@ def process(cfg, pdf, dry_run=False, force=False, title=None, author=None, compa print("voice server reachable:", h) else: try: - run_audio_stages(cfg, book_dir, book, force) + rendered = run_audio_stages(cfg, book_dir, book, force) except voice.VoiceError as e: raise Failed("voice: %s" % e) print("\nPROCESS OK: %s" % book_dir) @@ -284,7 +288,7 @@ def process(cfg, pdf, dry_run=False, force=False, title=None, author=None, compa rc = 1 finally: sys.stdout = real_out - if rc == 0 and book_dir and not dry_run: + if rc == 0 and book_dir and not dry_run and rendered: # a re-run that renders nothing keeps the original log out_dir = settings.audio_dir(cfg, book_dir) os.makedirs(out_dir, exist_ok=True) with open(os.path.join(out_dir, "run.log"), "w", encoding="utf-8") as f: diff --git a/_pipeline/tests/test_process.py b/_pipeline/tests/test_process.py index 78b0685..bf026e7 100644 --- a/_pipeline/tests/test_process.py +++ b/_pipeline/tests/test_process.py @@ -117,6 +117,7 @@ class ProcessTests(unittest.TestCase): "book.json", "warnings.log", "LICENSE_STATUS.md"): self.assertTrue(os.path.exists(os.path.join(b, rel)), rel) self.assertIn("public domain", open(os.path.join(b, "LICENSE_STATUS.md")).read()) + log_before = open(os.path.join(b, "audio", "run.log")).read() mtimes = {n: os.path.getmtime(os.path.join(b, "audio", n)) for n in names if n.endswith(".mp3")} posts = len(Stub.posts) self.assertGreater(posts, 0) @@ -125,6 +126,7 @@ class ProcessTests(unittest.TestCase): self.assertEqual(rc, 0, out) self.assertEqual(len(Stub.posts), posts) self.assertIn("nothing to render", out) + self.assertEqual(log_before, open(os.path.join(b, "audio", "run.log")).read()) # original render log kept self.assertEqual(mtimes, {n: os.path.getmtime(os.path.join(b, "audio", n)) for n in mtimes}) rc, out = run_process(self.cfg, self.pdf, force=True) # forced: renders again self.assertEqual(rc, 0, out)