Bundle mission speech with an admin mute option and fix live audio downloads
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
"""One-off speech asset generation on the credential-owning speech host.
|
||||
|
||||
Resumes completed files and reuses the live helper's existing cache. It never
|
||||
changes that cache, credentials, mission config or the running helper.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from welcome_voice import ENDPOINT, VETERAN_PROMPT, save_clip, synthesize, validate_wav
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--manifest', type=Path, required=True)
|
||||
parser.add_argument('--output', type=Path, required=True)
|
||||
parser.add_argument('--cache', type=Path)
|
||||
parser.add_argument('--project')
|
||||
args = parser.parse_args()
|
||||
manifest = json.loads(args.manifest.read_text())
|
||||
voice, language = manifest['voice'], manifest['language']
|
||||
identity = [ENDPOINT, voice, language, '', VETERAN_PROMPT]
|
||||
args.output.mkdir(parents=True, exist_ok=True)
|
||||
report = []
|
||||
for entry in manifest['clips']:
|
||||
name, text = entry['id'], entry['text']
|
||||
assert name.replace('_', '').isalnum() and 1 <= len(text) <= 800
|
||||
path = args.output / (name + '.wav')
|
||||
marker = args.output / (name + '.json')
|
||||
key = hashlib.sha256(json.dumps([identity, text], ensure_ascii=False).encode()).hexdigest()
|
||||
origin = 'generated'
|
||||
if path.exists() and marker.exists() and json.loads(marker.read_text())['cache_key'] == key:
|
||||
audio = validate_wav(path.read_bytes())
|
||||
origin = 'resumed'
|
||||
elif args.cache and (args.cache / (key + '.wav')).is_file():
|
||||
audio = validate_wav((args.cache / (key + '.wav')).read_bytes())
|
||||
origin = 'cached'
|
||||
else:
|
||||
import google.auth
|
||||
from google.auth.transport.requests import AuthorizedSession
|
||||
credentials, _ = google.auth.default(
|
||||
scopes=['https://www.googleapis.com/auth/cloud-platform'], quota_project_id=args.project)
|
||||
with AuthorizedSession(credentials, max_refresh_attempts=0) as session:
|
||||
audio = synthesize(session, ENDPOINT, voice, language, text)
|
||||
save_clip(path, audio)
|
||||
record = {'id': name, 'cache_key': key, 'sha256': hashlib.sha256(audio).hexdigest(),
|
||||
'bytes': len(audio), 'origin': origin, 'voice': voice}
|
||||
marker.write_text(json.dumps(record, indent=2) + '\n')
|
||||
report.append(record)
|
||||
print(f"{name}: {origin}, {len(audio)} bytes", flush=True)
|
||||
(args.output / 'generation.json').write_text(json.dumps(report, indent=2) + '\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except Exception as exc:
|
||||
# Provider exceptions can contain credentials/URLs; retain a fixed error.
|
||||
raise SystemExit(f'Bundled speech generation failed ({type(exc).__name__}); completed assets retained.') from None
|
||||
Reference in New Issue
Block a user