"""Persistent local Redux worker. No imports of model dependencies until explicit start. Wire protocol: unsigned LE32 payload length (max 65536), type byte, unsigned LE64 request id for T/R/E; Y (ready) and F (load failure) have no id. T refers to the fixed clip.raw in the private directory. R/E carry <=4096 UTF-8 bytes. Only one T may be outstanding. No stdout other than frames; stderr is suppressed by default, or captured privately with explicit --advanced-debug. This module never captures audio or delivers input. """ import argparse import os from pathlib import Path import stat import struct import sys import traceback MAX_FRAME = 65536 MAX_TEXT = 4096 MIN_SAMPLES = 3200 MAX_SAMPLES = 320000 try: from .model_files import DEFAULT_MANIFEST_DIR, ManifestError, check_model, load_backends except ImportError: # direct executable script from model_files import DEFAULT_MANIFEST_DIR, ManifestError, check_model, load_backends class LocalModelError(ValueError): """Missing, incomplete or wrong pinned local weights (never a download cue).""" def read_exact(fd, count): parts = bytearray() while len(parts) < count: part = os.read(fd, count - len(parts)) if not part: if not parts: return None raise ValueError("truncated worker frame") parts.extend(part) return bytes(parts) def read_frame(fd): header = read_exact(fd, 4) if header is None: return None size, = struct.unpack(" MAX_FRAME: raise ValueError("oversize response") frame = struct.pack(" MAX_TEXT: raise ValueError("transcript exceeds 4096 bytes") if advanced_debug: print(f"request {int.from_bytes(request_id, 'little')}: transcript={text!r}", file=sys.stderr, flush=True) send_frame(output_fd, b"R", request_id + encoded) except Exception as error: if advanced_debug: print(f"request {int.from_bytes(request_id, 'little')}: failure stage={stage}", file=sys.stderr, flush=True) traceback.print_exc(file=sys.stderr) # Only fixed stage/category labels cross IPC. Exception messages and # tracebacks may contain private audio/text and remain suppressed. send_frame(output_fd, b"E", request_id + safe_request_error(stage, error)) def main(argv=None): parser = argparse.ArgumentParser(description="FrameYap local offline Redux worker") parser.add_argument("--model", required=True) parser.add_argument("--manifest-dir", type=Path, default=DEFAULT_MANIFEST_DIR) parser.add_argument("--threads", type=int, default=2) parser.add_argument("--clip-dir", required=True) parser.add_argument("--advanced-debug", action="store_true", help="log full exceptions/runtime output and transcripts to stderr; may contain private speech") args = parser.parse_args(argv) if not 1 <= args.threads <= 64: parser.error("threads must be 1..64") # Native libraries sometimes print directly to fd 1. Keep those bytes out of # the framed channel, not merely Python's sys.stdout wrapper. protocol_fd = os.dup(1) os.set_inheritable(protocol_fd, False) if args.advanced_debug: # Native parent supplies a bounded private diagnostic sink. Model/native # stdout must still never corrupt the duplicated framed protocol fd. os.dup2(2, 1) print("FrameYap advanced debugging ON: private speech/text/paths may be logged; no raw clip archive.", file=sys.stderr, flush=True) else: with open(os.devnull, "wb") as null: os.dup2(null.fileno(), 1) os.dup2(null.fileno(), 2) try: try: private_dir(args.clip_dir) except Exception: send_frame(protocol_fd, b"F", b"M") return 1 try: model = load_model(args.model, args.threads, args.manifest_dir) except LocalModelError: if args.advanced_debug: traceback.print_exc(file=sys.stderr) send_frame(protocol_fd, b"F", b"M") return 1 except ImportError: if args.advanced_debug: traceback.print_exc(file=sys.stderr) send_frame(protocol_fd, b"F", b"I") return 1 except Exception: if args.advanced_debug: traceback.print_exc(file=sys.stderr) send_frame(protocol_fd, b"F", b"D") return 1 if args.advanced_debug: print("Local model ready", file=sys.stderr, flush=True) run(model, args.clip_dir, output_fd=protocol_fd, advanced_debug=args.advanced_debug) return 0 finally: os.close(protocol_fd) if __name__ == "__main__": sys.exit(main())