1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
"""Standalone terminal frontend for the shared Parley core."""
import sys
import tempfile
import termios
import tty
from pathlib import Path
from .config import Config
from .errors import ParleyError
from .persistence import save_transcript
from .recording import Recorder
from .transcription import Transcriber
def wait_for_stop() -> bool:
"""Wait for Enter/Escape and return True when cancellation was requested."""
if not sys.stdin.isatty():
return input() == "\x1b"
descriptor = sys.stdin.fileno()
previous_settings = termios.tcgetattr(descriptor)
try:
tty.setcbreak(descriptor)
while True:
key = sys.stdin.read(1)
if key in ("\r", "\n", ""):
return False
if key == "\x1b":
return True
finally:
termios.tcsetattr(descriptor, termios.TCSADRAIN, previous_settings)
def run_once(config: Config) -> tuple[str, Path]:
config.validate()
recorder = Recorder(config)
with tempfile.TemporaryDirectory(prefix="parley-") as temporary:
workspace = Path(temporary)
recorder.start(workspace / "recording.wav")
print(
"Recording; press Enter to transcribe or Escape to cancel.",
file=sys.stderr,
flush=True,
)
try:
cancelled = wait_for_stop()
except BaseException:
recorder.cancel()
raise
if cancelled:
recorder.cancel()
raise KeyboardInterrupt
wav_path = recorder.stop()
transcript = Transcriber(config).transcribe(wav_path, workspace)
path = save_transcript(transcript, config.transcript_dir)
return transcript, path
def main() -> int:
try:
transcript, path = run_once(Config.from_environment())
print(transcript)
print(f"Saved to {path}", file=sys.stderr)
return 0
except KeyboardInterrupt:
print("Cancelled.", file=sys.stderr)
return 130
except (OSError, ParleyError) as error:
print(f"error: {error}", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())
|