| import os |
| import subprocess |
| import time |
| import atexit |
| import sys |
| import re |
| import argparse |
| import shlex |
| import io |
| import select |
|
|
| |
| COMFYUI_PORT = 8188 |
|
|
| |
| |
| PYTHON_SCRIPT_DIR = "/content/py" |
|
|
| |
| TUNNEL_SCRIPT_PATH = os.path.join(PYTHON_SCRIPT_DIR, "gradio-tunnel.py") |
| |
|
|
| |
| GRADIO_TUNNEL_SCRIPT_CONTENT = r""" |
| import atexit |
| import os |
| import platform |
| import re |
| import stat |
| import subprocess |
| import sys |
| import time |
| import secrets |
| from pathlib import Path |
| from typing import List, Optional |
| |
| import requests |
| |
| VERSION = "0.2" |
| CURRENT_TUNNELS: List["Tunnel"] = [] |
| |
| machine = platform.machine() |
| if machine == "x86_64": |
| machine = "amd64" |
| |
| BINARY_REMOTE_NAME = f"frpc_{platform.system().lower()}_{machine.lower()}" |
| EXTENSION = ".exe" if os.name == "nt" else "" |
| BINARY_URL = f"https://cdn-media.huggingface.co/frpc-gradio-{VERSION}/{BINARY_REMOTE_NAME}{EXTENSION}" |
| |
| BINARY_FILENAME = f"{BINARY_REMOTE_NAME}_v{VERSION}" |
| BINARY_FOLDER = Path(__file__).parent.absolute() |
| BINARY_PATH = f"{BINARY_FOLDER / BINARY_FILENAME}" |
| |
| TUNNEL_TIMEOUT_SECONDS = 30 |
| TUNNEL_ERROR_MESSAGE = ( |
| "Could not create share URL. " |
| "Please check the appended log from frpc for more information:" |
| ) |
| |
| GRADIO_API_SERVER = "https://api.gradio.app/v2/tunnel-request" |
| GRADIO_SHARE_SERVER_ADDRESS = None |
| |
| |
| class Tunnel: |
| def __init__(self, remote_host, remote_port, local_host, local_port, share_token): |
| self.proc = None |
| self.url = None |
| self.remote_host = remote_host |
| self.remote_port = remote_port |
| self.local_host = local_host |
| self.local_port = local_port |
| self.share_token = share_token |
| |
| @staticmethod |
| def download_binary(): |
| if not Path(BINARY_PATH).exists(): |
| resp = requests.get(BINARY_URL) |
| |
| if resp.status_code == 403: |
| raise OSError( |
| f"Cannot set up a share link as this platform is incompatible. Please " |
| f"create a GitHub issue with information about your platform: {platform.uname()}" |
| ) |
| |
| resp.raise_for_status() |
| |
| # Save file data to local copy |
| with open(BINARY_PATH, "wb") as file: |
| file.write(resp.content) |
| st = os.stat(BINARY_PATH) |
| os.chmod(BINARY_PATH, st.st_mode | stat.S_IEXEC) |
| |
| def start_tunnel(self) -> str: |
| self.download_binary() |
| self.url = self._start_tunnel(BINARY_PATH) |
| return self.url |
| |
| def kill(self): |
| if self.proc is not None: |
| print(f"ํฐ๋ ์ข
๋ฃ ์ค: {self.local_host}:{self.local_port} <> {self.url}") |
| self.proc.terminate() |
| self.proc = None |
| |
| def _start_tunnel(self, binary: str) -> str: |
| CURRENT_TUNNELS.append(self) |
| command = [ |
| binary, |
| "http", |
| "-n", |
| self.share_token, |
| "-l", |
| str(self.local_port), |
| "-i", |
| self.local_host, |
| "--uc", |
| "--sd", |
| "random", |
| "--ue", |
| "--server_addr", |
| f"{self.remote_host}:{self.remote_port}", |
| "--disable_log_color", |
| ] |
| self.proc = subprocess.Popen( |
| command, stdout=subprocess.PIPE, stderr=subprocess.PIPE |
| ) |
| atexit.register(self.kill) |
| return self._read_url_from_tunnel_stream() |
| |
| def _read_url_from_tunnel_stream(self) -> str: |
| start_timestamp = time.time() |
| |
| log = [] |
| url = "" |
| |
| def _raise_tunnel_error(): |
| log_text = "\\n".join(log) |
| print(log_text, file=sys.stderr) |
| raise ValueError(f"{TUNNEL_ERROR_MESSAGE}\\n{log_text}") |
| |
| while url == "": |
| if time.time() - start_timestamp >= TUNNEL_TIMEOUT_SECONDS: |
| _raise_tunnel_error() |
| |
| assert self.proc is not None |
| if self.proc.stdout is None: |
| continue |
| |
| line = self.proc.stdout.readline() |
| try: |
| line = line.decode("utf-8") |
| except UnicodeDecodeError: |
| continue |
| |
| if line == "": |
| time.sleep(0.01) |
| continue |
| |
| log.append(line.strip()) |
| |
| if "start proxy success" in line: |
| result = re.search("start proxy success: (.+)\\n", line) |
| if result is None: |
| _raise_tunnel_error() |
| else: |
| url = result.group(1) |
| elif "login to server failed" in line: |
| _raise_tunnel_error() |
| |
| if self.proc.poll() is not None and url == "": |
| _raise_tunnel_error() |
| |
| return url |
| |
| |
| def setup_tunnel( |
| local_host: str, |
| local_port: int, |
| share_token: str, |
| share_server_address: Optional[str], |
| ) -> str: |
| share_server_address = ( |
| GRADIO_SHARE_SERVER_ADDRESS |
| if share_server_address is None |
| else share_server_address |
| ) |
| if share_server_address is None: |
| response = requests.get(GRADIO_API_SERVER) |
| if not (response and response.status_code == 200): |
| raise RuntimeError("Could not get share link from Gradio API Server.") |
| payload = response.json()[0] |
| remote_host, remote_port = payload["host"], int(payload["port"]) |
| else: |
| remote_host, remote_port = share_server_address.split(":") |
| remote_port = int(remote_port) |
| try: |
| tunnel = Tunnel(remote_host, remote_port, local_host, local_port, share_token) |
| address = tunnel.start_tunnel() |
| return address |
| except Exception as e: |
| raise RuntimeError(str(e)) from e |
| |
| # ์ด ์คํฌ๋ฆฝํธ๋ ํฌํธ ๋ฒํธ๋ฅผ ์ธ์๋ก ๋ฐ์ Gradio ํฐ๋๋ง์ ์์ํฉ๋๋ค. |
| if __name__ == "__main__": |
| if len(sys.argv) < 2: |
| print("์ฌ์ฉ๋ฒ: python gradio-tunnel.py <port_number>", file=sys.stderr) |
| sys.exit(1) |
| |
| try: |
| port = int(sys.argv[1]) |
| except ValueError: |
| print("์ค๋ฅ: ํฌํธ ๋ฒํธ๋ ์ ์์ฌ์ผ ํฉ๋๋ค.", file=sys.stderr) |
| sys.exit(1) |
| |
| # requests ์ํฌํธ ํ์ธ (Colab ํ๊ฒฝ์์ ํ์) |
| try: |
| import requests |
| except ImportError: |
| # ์ด ์ฝ๋๋ runcomfy.py์์ ์คํํ๋ subprocess์ด๋ฏ๋ก, |
| # runcomfy.py์์ requests ์ค์น๋ฅผ ๋ณด์ฅํด์ผ ํจ. |
| pass |
| |
| try: |
| address = setup_tunnel( |
| "127.0.0.1", |
| port, |
| secrets.token_urlsafe(32), |
| None, |
| ) |
| print(address, flush=True) |
| # ํฐ๋ ํ๋ก์ธ์ค๊ฐ ์ข
๋ฃ๋์ง ์๋๋ก ๋๊ธฐ |
| time.sleep(3600 * 24 * 3) |
| except Exception as e: |
| print(f"ํฐ๋ ์คํ ์ค ์น๋ช
์ ์ธ ์ค๋ฅ ๋ฐ์: {e}", file=sys.stderr) |
| sys.exit(1) |
| |
| """ |
|
|
| |
| def main(): |
| |
| try: |
| import requests |
| except ImportError: |
| print("ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ 'requests'๊ฐ ์ค์น๋์ด ์์ง ์์ต๋๋ค. ์ค์น๋ฅผ ์๋ํฉ๋๋ค.") |
| try: |
| |
| subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"]) |
| except Exception as e: |
| print(f"๊ฒฝ๊ณ : 'requests' ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น ์คํจ. ํฐ๋๋ง ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ค๋ฅ: {e}") |
|
|
| |
| comfyui_args = sys.argv[1:] |
|
|
| |
| |
| |
| comfyui_dir = "/content/ComfyUI" |
| |
| print(f"ComfyUI ๋๋ ํ ๋ฆฌ๋ก ์ด๋ ์ค: {comfyui_dir}") |
| try: |
| os.chdir(comfyui_dir) |
| except FileNotFoundError: |
| print(f"์ค๋ฅ: ๋๋ ํ ๋ฆฌ๊ฐ ์์ต๋๋ค: {comfyui_dir}. ๊ฒฝ๋ก๋ฅผ ํ์ธํด ์ฃผ์ธ์.") |
| sys.exit(1) |
|
|
| |
| print(f"ํฐ๋ ์คํฌ๋ฆฝํธ ์ ์ฅ ์ค: {TUNNEL_SCRIPT_PATH}") |
| try: |
| |
| with open(TUNNEL_SCRIPT_PATH, "w") as f: |
| f.write(GRADIO_TUNNEL_SCRIPT_CONTENT) |
| except Exception as e: |
| print(f"์ค๋ฅ: ํฐ๋ ์คํฌ๋ฆฝํธ ํ์ผ ์ ์ฅ ์คํจ. {PYTHON_SCRIPT_DIR} ๊ฒฝ๋ก๊ฐ ์กด์ฌํ๋์ง ํ์ธํด ์ฃผ์ธ์. ์ค๋ฅ: {e}") |
| sys.exit(1) |
|
|
|
|
| |
| print("\nComfyUI ์๋ฒ๋ฅผ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ์์ํฉ๋๋ค...") |
| comfyui_base_args = [ |
| "./main.py", |
| "--listen", "127.0.0.1", |
| "--port", str(COMFYUI_PORT), |
| ] |
| comfyui_command = ["python"] + comfyui_base_args + comfyui_args |
| |
| comfyui_proc = subprocess.Popen( |
| comfyui_command, |
| stdout=subprocess.PIPE, |
| stderr=subprocess.STDOUT, |
| text=True |
| ) |
| atexit.register(comfyui_proc.terminate) |
|
|
| |
| print(f"์๋ฒ๊ฐ ํฌํธ {COMFYUI_PORT}๋ฅผ ์ด ๋๊น์ง 15์ด ๋๊ธฐํฉ๋๋ค...") |
| time.sleep(15) |
|
|
| print(f"\nGradio ํฐ๋ ํด๋ผ์ด์ธํธ ์์ ์ค (ํฌํธ {COMFYUI_PORT})...") |
| |
| tunnel_command = ["python", TUNNEL_SCRIPT_PATH, str(COMFYUI_PORT)] |
| |
| tunnel_proc = subprocess.Popen( |
| tunnel_command, |
| stdout=subprocess.PIPE, |
| stderr=subprocess.STDOUT, |
| text=True |
| ) |
| atexit.register(tunnel_proc.terminate) |
|
|
| |
| share_url = None |
| start_time = time.time() |
| print("\n[ํฐ๋ ์ถ๋ ฅ - Gradio ๋ก๊ทธ]") |
|
|
| |
| while time.time() - start_time < 60 and tunnel_proc.poll() is None: |
| line = tunnel_proc.stdout.readline() |
| |
| if line: |
| line_stripped = line.strip() |
| print(f"[TUNNEL] {line_stripped}") |
| |
| |
| if line_stripped.startswith(("https://", "http://")): |
| share_url = line_stripped |
| break |
| |
| time.sleep(0.01) |
|
|
| if share_url: |
| print("\n" + "="*50) |
| print(f"๐ **ComfyUI ๊ณต์ URL์ด ์์ฑ๋์์ต๋๋ค:** {share_url}") |
| print("์ด ์ฃผ์๋ก ์ ์ํ์ธ์.") |
| print("="*50) |
|
|
| else: |
| |
| print("\n" + "="*50) |
| print("๐จ **ํฐ๋๋ง ํด๋ผ์ด์ธํธ ์คํ์ ์คํจํ์ต๋๋ค!**") |
| print("์๋ ๋ก๊ทธ์์ ์ค๋ฅ ์์ธ์ ํ์ธํ์ธ์.") |
| print("="*50) |
| |
| |
| print("\n--- ํฐ๋ ํด๋ผ์ด์ธํธ ์ต์ข
๋ก๊ทธ ---") |
| |
| try: |
| tunnel_logs = tunnel_proc.stdout.read() |
| if tunnel_logs: |
| print(tunnel_logs.strip()) |
| else: |
| print("ํฐ๋ ๋ก๊ทธ๊ฐ ๋ฐ๊ฒฌ๋์ง ์์์ต๋๋ค. ์ฆ์ ์ข
๋ฃ๋ ๊ฒ์ผ๋ก ๋ณด์
๋๋ค.") |
| except Exception as e: |
| print(f"ํฐ๋ ๋ก๊ทธ๋ฅผ ์ฝ๋ ์ค ์์ธ ๋ฐ์: {e}") |
|
|
| |
| print("\n--- ComfyUI ์ด๊ธฐ ๋ก๊ทธ ํ์ธ (ComfyUI๊ฐ ํฌํธ๋ฅผ ์ด์๋์ง ํ์ธ) ---") |
| try: |
| if comfyui_proc.stdout is not None: |
| |
| ready_to_read, _, _ = select.select([comfyui_proc.stdout], [], [], 0.5) |
| if ready_to_read: |
| comfy_logs = comfyui_proc.stdout.read() |
| print(comfy_logs.strip() if comfy_logs else "ComfyUI ๋ก๊ทธ ๋ฒํผ์ ๋ด์ฉ ์์.") |
| else: |
| print("ComfyUI ๋ก๊ทธ ๋ฒํผ์ ๋ด์ฉ ์์ (500ms ๋๊ธฐ ํ).") |
| else: |
| print("ComfyUI stdout์ด None์
๋๋ค.") |
| except Exception as e: |
| print(f"ComfyUI ๋ก๊ทธ ์ฝ๊ธฐ ์ค ์์ธ ๋ฐ์: {e}") |
|
|
| |
| if comfyui_proc.poll() is None: |
| comfyui_proc.terminate() |
| if tunnel_proc.poll() is None: |
| tunnel_proc.terminate() |
|
|
| raise RuntimeError("Gradio ํฐ๋๋ง์ ์คํจํ์ต๋๋ค. ์์ ์์ธ ๋ก๊ทธ๋ฅผ ํ์ธํด ์ฃผ์ญ์์ค.") |
|
|
|
|
| |
| try: |
| print("\n**ํ๋ก์ธ์ค๋ฅผ ์ ์งํฉ๋๋ค. Colab ์ธ์
์ด ์ฐ๊ฒฐ๋ ๋์ ํฐ๋์ด ์ ์ง๋ฉ๋๋ค.**") |
| print("์ค์งํ๋ ค๋ฉด ์ด ์
์ ์คํ์ ๋ฉ์ถ์ธ์.") |
| while True: |
| |
| comfy_line = comfyui_proc.stdout.readline() |
| if comfy_line: |
| print(comfy_line.strip()) |
|
|
| if comfyui_proc.poll() is not None: |
| print("\n[์ค๋ฅ] ComfyUI ํ๋ก์ธ์ค๊ฐ ์๊ธฐ์น ์๊ฒ ์ค์ง๋์์ต๋๋ค. ์ธ์
์ ์ข
๋ฃํฉ๋๋ค.") |
| |
| print("\n--- ComfyUI ์ถฉ๋ ๋ก๊ทธ (์์ธ ๋ถ์์ฉ) ---") |
| print(comfyui_proc.stdout.read()) |
| break |
| |
| if tunnel_proc.poll() is not None: |
| print("\n[์ค๋ฅ] ํฐ๋ ํ๋ก์ธ์ค๊ฐ ์๊ธฐ์น ์๊ฒ ์ค์ง๋์์ต๋๋ค. ์ธ์
์ ์ข
๋ฃํฉ๋๋ค.") |
| |
| print("\n--- ํฐ๋ ์ถฉ๋ ๋ก๊ทธ (์์ธ ๋ถ์์ฉ) ---") |
| print(tunnel_proc.stdout.read()) |
| break |
| |
| time.sleep(0.01) |
|
|
| except KeyboardInterrupt: |
| print("\n์ฌ์ฉ์๊ฐ ํ๋ก์ธ์ค๋ฅผ ์ค์งํ์ต๋๋ค. (KeyboardInterrupt)") |
|
|
| finally: |
| print("\n๋ฐฑ๊ทธ๋ผ์ด๋ ํ๋ก์ธ์ค ์ข
๋ฃ๋ฅผ ์๋ํฉ๋๋ค...") |
| |
| if comfyui_proc.poll() is None: |
| comfyui_proc.terminate() |
| if tunnel_proc.poll() is None: |
| tunnel_proc.terminate() |
| |
| print("๋ฐฑ๊ทธ๋ผ์ด๋ ํ๋ก์ธ์ค๊ฐ ์ข
๋ฃ๋์์ต๋๋ค.") |
|
|
| if __name__ == '__main__': |
| main() |