From f1c95e445d1241babafc19c20ff778ee21a18fe3 Mon Sep 17 00:00:00 2001 From: gufengc Date: Mon, 13 Oct 2025 14:21:33 +0800 Subject: [PATCH 1/7] update --- src/parallax/cli.py | 111 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/src/parallax/cli.py b/src/parallax/cli.py index 6281a9ef..adfaafc6 100644 --- a/src/parallax/cli.py +++ b/src/parallax/cli.py @@ -71,12 +71,17 @@ def run_command(args): if args.use_relay: cmd.extend(get_relay_params()) + # Append any passthrough args (unrecognized by this CLI) directly to the command + if passthrough_args: + cmd.extend(passthrough_args) + logger.info(f"Running command: {' '.join(cmd)}") # Use Popen instead of run to control the subprocess sub_process = None try: - sub_process = subprocess.Popen(cmd) + # Start in a new session so we can signal the entire process group + sub_process = subprocess.Popen(cmd, start_new_session=True) # Wait for the subprocess to finish return_code = sub_process.wait() if return_code != 0: @@ -84,24 +89,53 @@ def run_command(args): sys.exit(return_code) except KeyboardInterrupt: logger.info("Received interrupt signal, shutting down...") + # If another Ctrl-C arrives during cleanup, force-kill the whole group immediately + def _force_kill_handler(signum, frame): + try: + os.killpg(sub_process.pid, signal.SIGKILL) + except Exception: + try: + sub_process.kill() + except Exception: + pass + os._exit(130) + try: + signal.signal(signal.SIGINT, _force_kill_handler) + except Exception: + pass if sub_process is not None: try: - # Gracefully terminate the subprocess - sub_process.send_signal(signal.SIGINT) + # Gracefully terminate the entire process group + try: + os.killpg(sub_process.pid, signal.SIGINT) + except Exception: + # Fall back to signaling just the child process + sub_process.send_signal(signal.SIGINT) + # Wait for the subprocess to exit gracefully try: sub_process.wait(timeout=5) except subprocess.TimeoutExpired: - # If the process does not exit in 5 seconds, force kill - logger.info("Process didn't terminate gracefully, forcing kill...") - sub_process.kill() - sub_process.wait() + logger.info("SIGINT timeout; sending SIGTERM to process group...") + try: + os.killpg(sub_process.pid, signal.SIGTERM) + except Exception: + sub_process.terminate() + try: + sub_process.wait(timeout=5) + except subprocess.TimeoutExpired: + logger.info("SIGTERM timeout; forcing SIGKILL on process group...") + try: + os.killpg(sub_process.pid, signal.SIGKILL) + except Exception: + sub_process.kill() + sub_process.wait() except Exception as e: logger.error(f"Failed to terminate subprocess: {e}") sys.exit(0) -def join_command(args): +def join_command(args, passthrough_args: list[str] | None = None): """Join a distributed cluster (equivalent to scripts/join.sh).""" check_python_version() @@ -145,13 +179,18 @@ def join_command(args): logger.info("Using public relay servers") cmd.extend(get_relay_params()) + # Append any passthrough args (unrecognized by this CLI) directly to the command + if passthrough_args: + cmd.extend(passthrough_args) + logger.info(f"Running command: {' '.join(cmd)}") logger.info(f"Scheduler address: {args.scheduler_addr}") # Use Popen instead of run to control the subprocess sub_process = None try: - sub_process = subprocess.Popen(cmd, env=env) + # Start in a new session so we can signal the entire process group + sub_process = subprocess.Popen(cmd, env=env, start_new_session=True) # Wait for the subprocess to finish return_code = sub_process.wait() if return_code != 0: @@ -159,21 +198,50 @@ def join_command(args): sys.exit(return_code) except KeyboardInterrupt: logger.info("Received interrupt signal, shutting down...") + # If another Ctrl-C arrives during cleanup, force-kill the whole group immediately + def _force_kill_handler(signum, frame): + try: + os.killpg(sub_process.pid, signal.SIGKILL) + except Exception: + try: + sub_process.kill() + except Exception: + pass + os._exit(130) + try: + signal.signal(signal.SIGINT, _force_kill_handler) + except Exception: + pass if sub_process is not None: try: - logger.info("Terminating subprocess...") - # Gracefully terminate the subprocess - sub_process.send_signal(signal.SIGINT) - logger.info("Subprocess terminated, waiting for exit...") + logger.info("Terminating subprocess group...") + # Gracefully terminate the entire process group + try: + os.killpg(sub_process.pid, signal.SIGINT) + except Exception: + # Fall back to signaling just the child process + sub_process.send_signal(signal.SIGINT) + + logger.info("Waiting for subprocess to exit...") # Wait for the subprocess to exit gracefully try: sub_process.wait(timeout=5) except subprocess.TimeoutExpired: - # If the process does not exit in 5 seconds, force kill - logger.info("Process didn't terminate gracefully, forcing kill...") - sub_process.kill() - sub_process.wait() - logger.info("Subprocess exited gracefully.") + logger.info("SIGINT timeout; sending SIGTERM to process group...") + try: + os.killpg(sub_process.pid, signal.SIGTERM) + except Exception: + sub_process.terminate() + try: + sub_process.wait(timeout=5) + except subprocess.TimeoutExpired: + logger.info("SIGTERM timeout; forcing SIGKILL on process group...") + try: + os.killpg(sub_process.pid, signal.SIGKILL) + except Exception: + sub_process.kill() + sub_process.wait() + logger.info("Subprocess exited.") except Exception as e: logger.error(f"Failed to terminate subprocess: {e}") else: @@ -224,16 +292,17 @@ def main(): "-r", "--use-relay", action="store_true", help="Use public relay servers" ) - args = parser.parse_args() + # Accept unknown args and pass them through to the underlying python command + args, passthrough_args = parser.parse_known_args() if not args.command: parser.print_help() sys.exit(1) if args.command == "run": - run_command(args) + run_command(args, passthrough_args) elif args.command == "join": - join_command(args) + join_command(args, passthrough_args) else: parser.print_help() sys.exit(1) From 776f105200b886a645feed223503d573a9edff77 Mon Sep 17 00:00:00 2001 From: gufengc Date: Wed, 15 Oct 2025 11:55:26 +0800 Subject: [PATCH 2/7] update --- src/parallax/cli.py | 235 ++++++++++++++++++++++---------------------- 1 file changed, 117 insertions(+), 118 deletions(-) diff --git a/src/parallax/cli.py b/src/parallax/cli.py index adfaafc6..f23f702c 100644 --- a/src/parallax/cli.py +++ b/src/parallax/cli.py @@ -42,46 +42,57 @@ def get_project_root(): return Path.cwd() -def run_command(args): - """Run the scheduler (equivalent to scripts/start.sh).""" - check_python_version() - - project_root = get_project_root() - backend_main = project_root / "src" / "backend" / "main.py" - - if not backend_main.exists(): - print(f"Error: Backend main.py not found at {backend_main}") - sys.exit(1) - - # Build the command to run the backend main.py - cmd = [ - sys.executable, - str(backend_main), - "--dht-port", - "5001", - "--port", - "3001", - ] - - # Add optional arguments if provided - if args.model_name: - cmd.extend(["--model-name", args.model_name]) - if args.init_nodes_num: - cmd.extend(["--init-nodes-num", str(args.init_nodes_num)]) - if args.use_relay: - cmd.extend(get_relay_params()) - - # Append any passthrough args (unrecognized by this CLI) directly to the command - if passthrough_args: - cmd.extend(passthrough_args) - +def _flag_present(args_list: list[str], flag_names: list[str]) -> bool: + """Return True if any of the given flags is present in args_list. + + Supports forms: "--flag value", "--flag=value", "-f value", "-f=value". + """ + if not args_list: + return False + flags_set = set(flag_names) + for i, token in enumerate(args_list): + if token in flags_set: + return True + for flag in flags_set: + if token.startswith(flag + "="): + return True + return False + + +def _find_flag_value(args_list: list[str], flag_names: list[str]) -> str | None: + """Find the value for the first matching flag in args_list, if present. + + Returns the associated value for forms: "--flag value" or "--flag=value" or + "-f value" or "-f=value". Returns None if not found or value is missing. + """ + if not args_list: + return None + flags_set = set(flag_names) + for i, token in enumerate(args_list): + if token in flags_set: + # expect value in next token if exists and is not another flag + if i + 1 < len(args_list) and not args_list[i + 1].startswith("-"): + return args_list[i + 1] + return None + for flag in flags_set: + prefix = flag + "=" + if token.startswith(prefix): + return token[len(prefix) :] + return None + + +def _execute_with_graceful_shutdown(cmd: list[str], env: dict[str, str] | None = None) -> None: + """Execute a command in a subprocess and handle graceful shutdown on Ctrl-C. + + This centralizes the common Popen + signal handling logic shared by + run_command and join_command. + """ logger.info(f"Running command: {' '.join(cmd)}") - # Use Popen instead of run to control the subprocess sub_process = None try: # Start in a new session so we can signal the entire process group - sub_process = subprocess.Popen(cmd, start_new_session=True) + sub_process = subprocess.Popen(cmd, env=env, start_new_session=True) # Wait for the subprocess to finish return_code = sub_process.wait() if return_code != 0: @@ -89,6 +100,7 @@ def run_command(args): sys.exit(return_code) except KeyboardInterrupt: logger.info("Received interrupt signal, shutting down...") + # If another Ctrl-C arrives during cleanup, force-kill the whole group immediately def _force_kill_handler(signum, frame): try: @@ -99,12 +111,15 @@ def _force_kill_handler(signum, frame): except Exception: pass os._exit(130) + try: signal.signal(signal.SIGINT, _force_kill_handler) except Exception: pass + if sub_process is not None: try: + logger.info("Terminating subprocess group...") # Gracefully terminate the entire process group try: os.killpg(sub_process.pid, signal.SIGINT) @@ -112,6 +127,7 @@ def _force_kill_handler(signum, frame): # Fall back to signaling just the child process sub_process.send_signal(signal.SIGINT) + logger.info("Waiting for subprocess to exit...") # Wait for the subprocess to exit gracefully try: sub_process.wait(timeout=5) @@ -130,11 +146,48 @@ def _force_kill_handler(signum, frame): except Exception: sub_process.kill() sub_process.wait() + logger.info("Subprocess exited.") except Exception as e: logger.error(f"Failed to terminate subprocess: {e}") + else: + logger.info("Subprocess not found, skipping shutdown...") sys.exit(0) +def run_command(args, passthrough_args: list[str] | None = None): + """Run the scheduler (equivalent to scripts/start.sh).""" + check_python_version() + + project_root = get_project_root() + backend_main = project_root / "src" / "backend" / "main.py" + + if not backend_main.exists(): + print(f"Error: Backend main.py not found at {backend_main}") + sys.exit(1) + + # Build the command to run the backend main.py + passthrough_args = passthrough_args or [] + cmd = [sys.executable, str(backend_main)] + if not _flag_present(passthrough_args, ["--dht-port"]): + cmd.extend(["--dht-port", "5001"]) + if not _flag_present(passthrough_args, ["--port"]): + cmd.extend(["--port", "3001"]) + + # Add optional arguments if provided + if args.model_name: + cmd.extend(["--model-name", args.model_name]) + if args.init_nodes_num: + cmd.extend(["--init-nodes-num", str(args.init_nodes_num)]) + if args.use_relay: + cmd.extend(get_relay_params()) + + # Append any passthrough args (unrecognized by this CLI) directly to the command + if passthrough_args: + cmd.extend(passthrough_args) + + _execute_with_graceful_shutdown(cmd) + + def join_command(args, passthrough_args: list[str] | None = None): """Join a distributed cluster (equivalent to scripts/join.sh).""" check_python_version() @@ -155,26 +208,34 @@ def join_command(args, passthrough_args: list[str] | None = None): env["SGL_ENABLE_JIT_DEEPGEMM"] = "0" # Build the command to run the launch.py script - cmd = [ - sys.executable, - str(launch_script), - "--max-num-tokens-per-batch", - "4096", - "--max-sequence-length", - "2048", - "--max-batch-size", - "8", - "--kv-block-size", - "1024", - "--host", - "0.0.0.0", - "--port", - "3000", - "--scheduler-addr", - args.scheduler_addr, - ] + passthrough_args = passthrough_args or [] + + # Determine effective scheduler address (prefer passthrough if provided) + effective_scheduler_addr = _find_flag_value( + passthrough_args, ["--scheduler-addr", "-s"] + ) + if effective_scheduler_addr is None: + effective_scheduler_addr = args.scheduler_addr + + cmd = [sys.executable, str(launch_script)] + if not _flag_present(passthrough_args, ["--max-num-tokens-per-batch"]): + cmd.extend(["--max-num-tokens-per-batch", "4096"]) + if not _flag_present(passthrough_args, ["--max-sequence-length"]): + cmd.extend(["--max-sequence-length", "2048"]) + if not _flag_present(passthrough_args, ["--max-batch-size"]): + cmd.extend(["--max-batch-size", "8"]) + if not _flag_present(passthrough_args, ["--kv-block-size"]): + cmd.extend(["--kv-block-size", "1024"]) + if not _flag_present(passthrough_args, ["--host"]): + cmd.extend(["--host", "0.0.0.0"]) + if not _flag_present(passthrough_args, ["--port"]): + cmd.extend(["--port", "3000"]) + if not _flag_present(passthrough_args, ["--scheduler-addr", "-s"]): + cmd.extend(["--scheduler-addr", effective_scheduler_addr]) + + # Relay logic based on effective scheduler address if args.use_relay or ( - args.scheduler_addr != "auto" and not str(args.scheduler_addr).startswith("/") + effective_scheduler_addr != "auto" and not str(effective_scheduler_addr).startswith("/") ): logger.info("Using public relay servers") cmd.extend(get_relay_params()) @@ -183,70 +244,8 @@ def join_command(args, passthrough_args: list[str] | None = None): if passthrough_args: cmd.extend(passthrough_args) - logger.info(f"Running command: {' '.join(cmd)}") - logger.info(f"Scheduler address: {args.scheduler_addr}") - - # Use Popen instead of run to control the subprocess - sub_process = None - try: - # Start in a new session so we can signal the entire process group - sub_process = subprocess.Popen(cmd, env=env, start_new_session=True) - # Wait for the subprocess to finish - return_code = sub_process.wait() - if return_code != 0: - logger.error(f"Command failed with exit code {return_code}") - sys.exit(return_code) - except KeyboardInterrupt: - logger.info("Received interrupt signal, shutting down...") - # If another Ctrl-C arrives during cleanup, force-kill the whole group immediately - def _force_kill_handler(signum, frame): - try: - os.killpg(sub_process.pid, signal.SIGKILL) - except Exception: - try: - sub_process.kill() - except Exception: - pass - os._exit(130) - try: - signal.signal(signal.SIGINT, _force_kill_handler) - except Exception: - pass - if sub_process is not None: - try: - logger.info("Terminating subprocess group...") - # Gracefully terminate the entire process group - try: - os.killpg(sub_process.pid, signal.SIGINT) - except Exception: - # Fall back to signaling just the child process - sub_process.send_signal(signal.SIGINT) - - logger.info("Waiting for subprocess to exit...") - # Wait for the subprocess to exit gracefully - try: - sub_process.wait(timeout=5) - except subprocess.TimeoutExpired: - logger.info("SIGINT timeout; sending SIGTERM to process group...") - try: - os.killpg(sub_process.pid, signal.SIGTERM) - except Exception: - sub_process.terminate() - try: - sub_process.wait(timeout=5) - except subprocess.TimeoutExpired: - logger.info("SIGTERM timeout; forcing SIGKILL on process group...") - try: - os.killpg(sub_process.pid, signal.SIGKILL) - except Exception: - sub_process.kill() - sub_process.wait() - logger.info("Subprocess exited.") - except Exception as e: - logger.error(f"Failed to terminate subprocess: {e}") - else: - logger.info("Subprocess not found, skipping shutdown...") - sys.exit(0) + logger.info(f"Scheduler address: {effective_scheduler_addr}") + _execute_with_graceful_shutdown(cmd, env=env) def main(): From cec8e31623bd692580bedcba1d87c1ed9fea9c0e Mon Sep 17 00:00:00 2001 From: gufengc Date: Thu, 16 Oct 2025 21:13:44 +0800 Subject: [PATCH 3/7] update --- src/parallax/cli.py | 23 ++++------------------- src/parallax/launch.py | 6 ++++-- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/parallax/cli.py b/src/parallax/cli.py index f23f702c..18bb719a 100644 --- a/src/parallax/cli.py +++ b/src/parallax/cli.py @@ -192,10 +192,6 @@ def join_command(args, passthrough_args: list[str] | None = None): """Join a distributed cluster (equivalent to scripts/join.sh).""" check_python_version() - if not args.scheduler_addr: - print("Error: Scheduler address is required. Use -s or --scheduler-addr") - sys.exit(1) - project_root = get_project_root() launch_script = project_root / "src" / "parallax" / "launch.py" @@ -210,13 +206,6 @@ def join_command(args, passthrough_args: list[str] | None = None): # Build the command to run the launch.py script passthrough_args = passthrough_args or [] - # Determine effective scheduler address (prefer passthrough if provided) - effective_scheduler_addr = _find_flag_value( - passthrough_args, ["--scheduler-addr", "-s"] - ) - if effective_scheduler_addr is None: - effective_scheduler_addr = args.scheduler_addr - cmd = [sys.executable, str(launch_script)] if not _flag_present(passthrough_args, ["--max-num-tokens-per-batch"]): cmd.extend(["--max-num-tokens-per-batch", "4096"]) @@ -226,16 +215,12 @@ def join_command(args, passthrough_args: list[str] | None = None): cmd.extend(["--max-batch-size", "8"]) if not _flag_present(passthrough_args, ["--kv-block-size"]): cmd.extend(["--kv-block-size", "1024"]) - if not _flag_present(passthrough_args, ["--host"]): - cmd.extend(["--host", "0.0.0.0"]) - if not _flag_present(passthrough_args, ["--port"]): - cmd.extend(["--port", "3000"]) - if not _flag_present(passthrough_args, ["--scheduler-addr", "-s"]): - cmd.extend(["--scheduler-addr", effective_scheduler_addr]) + # The scheduler address is now taken directly from the parsed arguments. + cmd.extend(["--scheduler-addr", args.scheduler_addr]) # Relay logic based on effective scheduler address if args.use_relay or ( - effective_scheduler_addr != "auto" and not str(effective_scheduler_addr).startswith("/") + args.scheduler_addr != "auto" and not str(args.scheduler_addr).startswith("/") ): logger.info("Using public relay servers") cmd.extend(get_relay_params()) @@ -244,7 +229,7 @@ def join_command(args, passthrough_args: list[str] | None = None): if passthrough_args: cmd.extend(passthrough_args) - logger.info(f"Scheduler address: {effective_scheduler_addr}") + logger.info(f"Scheduler address: {args.scheduler_addr}") _execute_with_graceful_shutdown(cmd, env=env) diff --git a/src/parallax/launch.py b/src/parallax/launch.py index a68e16d7..27156cfb 100644 --- a/src/parallax/launch.py +++ b/src/parallax/launch.py @@ -63,7 +63,8 @@ args.model_path = mlx_model_repo logger.debug(f"Replace mlx model path: {mlx_model_repo}") if args.scheduler_addr is None: - display_parallax_join(args.model_path) + if args.log_level != "DEBUG": + display_parallax_join(args.model_path) # only launch http server on head node if args.start_layer == 0: @@ -122,7 +123,8 @@ ) gradient_server.status = ServerState.INITIALIZING - display_parallax_join(args.model_path) + if args.log_level != "DEBUG": + display_parallax_join(args.model_path) # only launch http server on head node if args.start_layer == 0: From 8671a6a9e12fc97815bd1997b5585ab49a7cfa28 Mon Sep 17 00:00:00 2001 From: gufengc Date: Thu, 16 Oct 2025 21:21:50 +0800 Subject: [PATCH 4/7] update --- src/parallax/launch.py | 6 ++---- src/parallax_utils/ascii_anime.py | 11 ++++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/parallax/launch.py b/src/parallax/launch.py index 27156cfb..99838426 100644 --- a/src/parallax/launch.py +++ b/src/parallax/launch.py @@ -63,8 +63,7 @@ args.model_path = mlx_model_repo logger.debug(f"Replace mlx model path: {mlx_model_repo}") if args.scheduler_addr is None: - if args.log_level != "DEBUG": - display_parallax_join(args.model_path) + display_parallax_join(args.model_path, clean=args.log_level != "DEBUG") # only launch http server on head node if args.start_layer == 0: @@ -123,8 +122,7 @@ ) gradient_server.status = ServerState.INITIALIZING - if args.log_level != "DEBUG": - display_parallax_join(args.model_path) + display_parallax_join(args.model_path, clean=args.log_level != "DEBUG") # only launch http server on head node if args.start_layer == 0: diff --git a/src/parallax_utils/ascii_anime.py b/src/parallax_utils/ascii_anime.py index 38ffbffe..cc8d4f1d 100755 --- a/src/parallax_utils/ascii_anime.py +++ b/src/parallax_utils/ascii_anime.py @@ -161,7 +161,7 @@ def display_ascii_animation_run(animation_data): # time.sleep(delay) -def display_ascii_animation_join(animation_data, model_name): +def display_ascii_animation_join(animation_data, model_name, clean=True): frames = animation_data.get("frames", []) # loop = animation_data.get('loop', False) @@ -178,8 +178,9 @@ def display_ascii_animation_join(animation_data, model_name): if content: res = process_context_color_join(content, colors, model_name) - res = "\n".join(res) - clear_screen() + res = "\n".join(res).replace("#", " ") + if clean: + clear_screen() print(res) # for frame_data in frames: @@ -211,7 +212,7 @@ def display_parallax_run(): display_ascii_animation_run(animation_data) -def display_parallax_join(model_name): +def display_parallax_join(model_name, clean=True): file_path = "./src/parallax_utils/anime/parallax_join.json" try: with open(file_path, "r") as f: @@ -222,4 +223,4 @@ def display_parallax_join(model_name): except json.JSONDecodeError: print(f"Error: The file '{file_path}' contains invalid JSON.") return - display_ascii_animation_join(animation_data, model_name) + display_ascii_animation_join(animation_data, model_name, clean) From 969b4c52a19698787ab836268cf65aa0e51f02ba Mon Sep 17 00:00:00 2001 From: gufengc Date: Thu, 16 Oct 2025 21:29:56 +0800 Subject: [PATCH 5/7] update --- src/backend/main.py | 4 ++-- src/backend/server/server_args.py | 2 ++ src/parallax/launch.py | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/backend/main.py b/src/backend/main.py index 899df926..d71b0672 100644 --- a/src/backend/main.py +++ b/src/backend/main.py @@ -127,8 +127,8 @@ async def serve_index(): if __name__ == "__main__": args = parse_args() logger.info(f"args: {args}") - - display_parallax_run() + if args.log_level != "DEBUG": + display_parallax_run() host_maddrs = args.host_maddrs dht_port = args.dht_port if args.dht_port is not None: diff --git a/src/backend/server/server_args.py b/src/backend/server/server_args.py index 43faab6c..06ed058c 100644 --- a/src/backend/server/server_args.py +++ b/src/backend/server/server_args.py @@ -29,6 +29,8 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--port", type=int, default=5000, help="Port to listen on") + parser.add_argument("--log-level", type=str, default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR"], help="Log level") + parser.add_argument("--model-name", type=str, default=None, help="Model name") parser.add_argument("--init-nodes-num", type=int, default=None, help="Number of initial nodes") diff --git a/src/parallax/launch.py b/src/parallax/launch.py index 99838426..98b20ad3 100644 --- a/src/parallax/launch.py +++ b/src/parallax/launch.py @@ -63,7 +63,8 @@ args.model_path = mlx_model_repo logger.debug(f"Replace mlx model path: {mlx_model_repo}") if args.scheduler_addr is None: - display_parallax_join(args.model_path, clean=args.log_level != "DEBUG") + if args.log_level != "DEBUG": + display_parallax_join(args.model_path) # only launch http server on head node if args.start_layer == 0: @@ -122,7 +123,8 @@ ) gradient_server.status = ServerState.INITIALIZING - display_parallax_join(args.model_path, clean=args.log_level != "DEBUG") + if args.log_level != "DEBUG": + display_parallax_join(args.model_path) # only launch http server on head node if args.start_layer == 0: From 436094315d3f1ab920e04b75bcf5b7ffd9899ef4 Mon Sep 17 00:00:00 2001 From: gufengc Date: Thu, 16 Oct 2025 21:32:27 +0800 Subject: [PATCH 6/7] update --- src/parallax_utils/ascii_anime.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/parallax_utils/ascii_anime.py b/src/parallax_utils/ascii_anime.py index cc8d4f1d..38ffbffe 100755 --- a/src/parallax_utils/ascii_anime.py +++ b/src/parallax_utils/ascii_anime.py @@ -161,7 +161,7 @@ def display_ascii_animation_run(animation_data): # time.sleep(delay) -def display_ascii_animation_join(animation_data, model_name, clean=True): +def display_ascii_animation_join(animation_data, model_name): frames = animation_data.get("frames", []) # loop = animation_data.get('loop', False) @@ -178,9 +178,8 @@ def display_ascii_animation_join(animation_data, model_name, clean=True): if content: res = process_context_color_join(content, colors, model_name) - res = "\n".join(res).replace("#", " ") - if clean: - clear_screen() + res = "\n".join(res) + clear_screen() print(res) # for frame_data in frames: @@ -212,7 +211,7 @@ def display_parallax_run(): display_ascii_animation_run(animation_data) -def display_parallax_join(model_name, clean=True): +def display_parallax_join(model_name): file_path = "./src/parallax_utils/anime/parallax_join.json" try: with open(file_path, "r") as f: @@ -223,4 +222,4 @@ def display_parallax_join(model_name, clean=True): except json.JSONDecodeError: print(f"Error: The file '{file_path}' contains invalid JSON.") return - display_ascii_animation_join(animation_data, model_name, clean) + display_ascii_animation_join(animation_data, model_name) From 151eeddca8c150b60a0ffa7a19ec16baca5b6cd0 Mon Sep 17 00:00:00 2001 From: gufengc Date: Thu, 16 Oct 2025 21:38:19 +0800 Subject: [PATCH 7/7] update --- src/backend/server/server_args.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/backend/server/server_args.py b/src/backend/server/server_args.py index 06ed058c..9624eb11 100644 --- a/src/backend/server/server_args.py +++ b/src/backend/server/server_args.py @@ -29,7 +29,13 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--port", type=int, default=5000, help="Port to listen on") - parser.add_argument("--log-level", type=str, default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR"], help="Log level") + parser.add_argument( + "--log-level", + type=str, + default="INFO", + choices=["DEBUG", "INFO", "WARNING", "ERROR"], + help="Log level", + ) parser.add_argument("--model-name", type=str, default=None, help="Model name")