cstr commited on
Commit
f15e7de
·
verified ·
1 Parent(s): bbdf35e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -91
app.py CHANGED
@@ -8,9 +8,8 @@ import gradio as gr
8
  import http.client
9
  import urllib.parse
10
  import xml.etree.ElementTree as ET
 
11
  import shutil
12
- import re
13
- import glob
14
 
15
  # =============================================================================
16
  # CONFIGURATION
@@ -18,10 +17,15 @@ import glob
18
  REPO_URL = "https://github.com/Automattic/atd-server-next.git"
19
  SERVER_DIR = "atd-server-next"
20
  MODELS_DIR = os.path.join(SERVER_DIR, "models")
21
- MODEL_BASE_URL = "https://openatd.svn.wordpress.org/atd-server/models/"
22
  HOST = "127.0.0.1"
23
  PORT = 1049
24
 
 
 
 
 
 
25
  MODEL_FILES = [
26
  "cnetwork.bin", "cnetwork2.bin", "dictionary.txt", "edits.bin",
27
  "endings.bin", "hnetwork.bin", "hnetwork2.bin", "hnetwork4.bin",
@@ -30,49 +34,58 @@ MODEL_FILES = [
30
  ]
31
 
32
  # =============================================================================
33
- # PHASE 1: SETUP & PATCHING
34
  # =============================================================================
35
- def recursive_patch_code():
36
- """
37
- Aggressively finds AND removes incompatible imports in ALL .sl files.
38
- The syntax 'from: jarfile.jar' breaks on Java 9+.
39
- We replace it with nothing, relying on the classpath passed to the java command.
40
- """
41
- print("--- [PHASE 1.5] RECURSIVE CODE PATCHING (JAVA 17 COMPATIBILITY) ---")
42
-
43
- # Find all .sl files in the server directory
44
- sl_files = glob.glob(f"{SERVER_DIR}/**/*.sl", recursive=True)
45
 
46
- patched_count = 0
47
- # Regex explanation:
48
- # from: Matches the keyword
49
- # \s* Matches whitespace
50
- # [^;\n]+ Matches anything that ISN'T a semicolon or newline (the jar path)
51
- # (?=;) Lookahead to ensure we stop at the semicolon
52
- regex = re.compile(r'from:\s*[^;\n]+(?=;)', re.IGNORECASE)
53
 
54
- for file_path in sl_files:
55
- try:
56
- with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
57
- content = f.read()
58
-
59
- # Apply the regex
60
- new_content = regex.sub('', content)
61
-
62
- if content != new_content:
63
- print(f"Patching {file_path}...")
64
- with open(file_path, "w", encoding="utf-8") as f:
65
- f.write(new_content)
66
- patched_count += 1
67
- except Exception as e:
68
- print(f"Warning: Could not patch {file_path}: {e}")
69
-
70
- print(f"-> Successfully patched {patched_count} files.")
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
 
 
 
72
  def setup_server():
73
- print("--- [PHASE 0] CHECKING REPOSITORY ---")
 
 
 
74
  if not os.path.exists(SERVER_DIR):
75
- print(f"Repository not found. Cloning from {REPO_URL}...")
76
  subprocess.run(["git", "clone", "--depth", "1", REPO_URL, SERVER_DIR], check=True)
77
 
78
  print("\n--- [PHASE 1] CHECKING MODELS ---")
@@ -82,60 +95,47 @@ def setup_server():
82
  for filename in MODEL_FILES:
83
  filepath = os.path.join(MODELS_DIR, filename)
84
  if not os.path.exists(filepath):
85
- url = MODEL_BASE_URL + filename
86
  print(f"Downloading {filename}...")
87
  try:
88
- urllib.request.urlretrieve(url, filepath)
89
  except Exception as e:
90
  print(f" -> FAILED: {e}")
91
- sys.exit(1)
92
-
93
- # Patch code BEFORE compiling
94
- recursive_patch_code()
95
 
96
  print("\n--- [PHASE 2] COMPILING RULES ---")
97
- # We compile if rules.bin is missing.
98
- # Note: The compiler output is actually rules.bin (or parts of it loaded into memory)
99
- # The previous error showed FileNotFound for models/rules.bin.
100
-
101
- # Classpath separator: ':' for Linux (Hugging Face), ';' for Windows
102
- cp_sep = ";" if os.name == 'nt' else ":"
103
-
104
- try:
105
- # We explicitly add the JARs to the compiler classpath too
106
- cp = f"lib/sleep.jar{cp_sep}lib/moconti.jar{cp_sep}lib/spellutils.jar"
107
-
108
- cmd = [
109
- "java",
110
- "-Datd.lowmem=true",
111
- "-Xmx1024M",
112
- "-classpath", cp,
113
- "sleep.console.TextConsole", # Run the console directly to avoid jar limits
114
- "utils/rules/rules.sl"
115
- ]
116
 
117
- print("Executing Rule Compiler...")
118
- subprocess.run(cmd, cwd=SERVER_DIR, check=True)
119
- print("Rules compiled successfully.")
120
-
121
- except subprocess.CalledProcessError as e:
122
- print(f"\nFATAL ERROR: Rule compilation failed with code {e.returncode}.")
123
- print("This usually means the code patch failed or Java is incompatible.")
124
- sys.exit(1)
 
 
 
 
 
 
 
 
125
 
126
  # =============================================================================
127
  # PHASE 2: SERVER RUNNER
128
  # =============================================================================
129
  def start_backend():
130
  print("\n--- [PHASE 3] STARTING SERVER ---")
131
- cp_sep = ";" if os.name == 'nt' else ":"
132
 
133
- # Robust Classpath
134
- classpath = f"lib/sleep.jar{cp_sep}lib/moconti.jar{cp_sep}lib/spellutils.jar"
135
- sleep_cp = f"lib{cp_sep}service/code"
136
 
137
  cmd = [
138
- "java",
139
  "-Dfile.encoding=UTF-8",
140
  "-XX:+AggressiveHeap",
141
  "-XX:+UseParallelGC",
@@ -149,7 +149,7 @@ def start_backend():
149
  "atdconfig.sl"
150
  ]
151
 
152
- print("Launching Java subprocess...")
153
  return subprocess.Popen(cmd, cwd=SERVER_DIR)
154
 
155
  def wait_for_port(timeout=60):
@@ -175,14 +175,9 @@ class AtDClient:
175
  headers = {"Content-Type": "application/x-www-form-urlencoded"}
176
  conn.request("POST", "/checkDocument", params, headers)
177
  resp = conn.getresponse()
178
-
179
- # If server is still warming up, it might return 503 or connection drop
180
  if resp.status != 200: return []
181
 
182
- # Read response
183
  xml_text = resp.read().decode('utf-8', errors='ignore')
184
-
185
- # Basic XML validation
186
  if not xml_text.strip().startswith("<"): return []
187
 
188
  root = ET.fromstring(xml_text)
@@ -240,20 +235,18 @@ if __name__ == "__main__":
240
  setup_server()
241
  server_proc = start_backend()
242
 
243
- # Monitoring loop
244
- # We check the process status before starting the UI
245
- time.sleep(3)
246
  if server_proc.poll() is not None:
247
- print("FATAL: Java server exited immediately. Check console for ClassCastException.")
248
  sys.exit(1)
249
 
250
- if wait_for_port(timeout=120): # Give it 2 minutes to load models
251
  with gr.Blocks(title="AtD Self-Hosted") as demo:
252
  gr.Markdown("# 🛡️ After The Deadline")
253
- gr.Markdown("Running on Java 17 (Patched)")
254
 
255
  with gr.Row():
256
- inp = gr.Textbox(label="Input", placeholder="Type text here...", lines=6)
257
  out = gr.HighlightedText(label="Analysis", combine_adjacent=True)
258
 
259
  btn = gr.Button("Check Text", variant="primary")
 
8
  import http.client
9
  import urllib.parse
10
  import xml.etree.ElementTree as ET
11
+ import tarfile
12
  import shutil
 
 
13
 
14
  # =============================================================================
15
  # CONFIGURATION
 
17
  REPO_URL = "https://github.com/Automattic/atd-server-next.git"
18
  SERVER_DIR = "atd-server-next"
19
  MODELS_DIR = os.path.join(SERVER_DIR, "models")
20
+ JAVA_DIR = "jdk8" # Folder to install portable Java
21
  HOST = "127.0.0.1"
22
  PORT = 1049
23
 
24
+ # Official Adoptium Java 8 (LTS) Linux x64 URL
25
+ JAVA_URL = "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u392-b08/OpenJDK8U-jre_x64_linux_hotspot_8u392b08.tar.gz"
26
+ JAVA_BIN = os.path.join(os.getcwd(), JAVA_DIR, "bin", "java")
27
+
28
+ MODEL_BASE_URL = "https://openatd.svn.wordpress.org/atd-server/models/"
29
  MODEL_FILES = [
30
  "cnetwork.bin", "cnetwork2.bin", "dictionary.txt", "edits.bin",
31
  "endings.bin", "hnetwork.bin", "hnetwork2.bin", "hnetwork4.bin",
 
34
  ]
35
 
36
  # =============================================================================
37
+ # PHASE -1: INSTALL JAVA 8 (The "Time Machine" Fix)
38
  # =============================================================================
39
+ def install_java8():
40
+ """Downloads and installs portable Java 8."""
41
+ print("--- [PHASE -1] CHECKING JAVA RUNTIME ---")
 
 
 
 
 
 
 
42
 
43
+ # If our local java binary exists, we assume it's installed
44
+ if os.path.exists(JAVA_BIN):
45
+ print(f"Portable Java 8 found at: {JAVA_BIN}")
46
+ return
 
 
 
47
 
48
+ print("Java 8 not found. Downloading portable runtime (approx 40MB)...")
49
+ tar_path = "java8.tar.gz"
50
+
51
+ try:
52
+ # Download
53
+ urllib.request.urlretrieve(JAVA_URL, tar_path)
54
+ print("Download complete. Extracting...")
55
+
56
+ # Extract
57
+ with tarfile.open(tar_path, "r:gz") as tar:
58
+ # Find the root folder name inside the tar
59
+ root_name = tar.getnames()[0].split('/')[0]
60
+ tar.extractall()
61
+
62
+ # Rename extracted folder to 'jdk8' for simplicity
63
+ if os.path.exists(JAVA_DIR):
64
+ shutil.rmtree(JAVA_DIR)
65
+ os.rename(root_name, JAVA_DIR)
66
+
67
+ # Cleanup
68
+ os.remove(tar_path)
69
+
70
+ # Set execute permissions
71
+ subprocess.run(["chmod", "+x", JAVA_BIN], check=True)
72
+
73
+ print(f"Java 8 successfully installed to {JAVA_DIR}")
74
+
75
+ except Exception as e:
76
+ print(f"FATAL: Failed to install Java 8. Error: {e}")
77
+ sys.exit(1)
78
 
79
+ # =============================================================================
80
+ # PHASE 1: REPO & MODELS
81
+ # =============================================================================
82
  def setup_server():
83
+ # Ensure Java is ready first
84
+ install_java8()
85
+
86
+ print("\n--- [PHASE 0] CHECKING REPOSITORY ---")
87
  if not os.path.exists(SERVER_DIR):
88
+ print(f"Cloning {REPO_URL}...")
89
  subprocess.run(["git", "clone", "--depth", "1", REPO_URL, SERVER_DIR], check=True)
90
 
91
  print("\n--- [PHASE 1] CHECKING MODELS ---")
 
95
  for filename in MODEL_FILES:
96
  filepath = os.path.join(MODELS_DIR, filename)
97
  if not os.path.exists(filepath):
 
98
  print(f"Downloading {filename}...")
99
  try:
100
+ urllib.request.urlretrieve(MODEL_BASE_URL + filename, filepath)
101
  except Exception as e:
102
  print(f" -> FAILED: {e}")
 
 
 
 
103
 
104
  print("\n--- [PHASE 2] COMPILING RULES ---")
105
+ # Only compile if grammar.bin doesn't exist (heuristic check)
106
+ if not os.path.exists(os.path.join(SERVER_DIR, "models", "grammar.bin")):
107
+ print("Compiling rules using Java 8...")
108
+ # Classpath separator is ':' on Linux
109
+ cp = "lib/sleep.jar:lib/moconti.jar:lib/spellutils.jar"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
+ try:
112
+ subprocess.run(
113
+ [
114
+ JAVA_BIN,
115
+ "-Datd.lowmem=true",
116
+ "-Xmx1024M",
117
+ "-classpath", cp,
118
+ "sleep.console.TextConsole",
119
+ "utils/rules/rules.sl"
120
+ ],
121
+ cwd=SERVER_DIR,
122
+ check=True
123
+ )
124
+ print("Rules compiled successfully.")
125
+ except subprocess.CalledProcessError as e:
126
+ print(f"Rule compilation warning: {e}")
127
 
128
  # =============================================================================
129
  # PHASE 2: SERVER RUNNER
130
  # =============================================================================
131
  def start_backend():
132
  print("\n--- [PHASE 3] STARTING SERVER ---")
 
133
 
134
+ classpath = "lib/sleep.jar:lib/moconti.jar:lib/spellutils.jar"
135
+ sleep_cp = "lib:service/code"
 
136
 
137
  cmd = [
138
+ JAVA_BIN,
139
  "-Dfile.encoding=UTF-8",
140
  "-XX:+AggressiveHeap",
141
  "-XX:+UseParallelGC",
 
149
  "atdconfig.sl"
150
  ]
151
 
152
+ print(f"Launching with: {JAVA_BIN}")
153
  return subprocess.Popen(cmd, cwd=SERVER_DIR)
154
 
155
  def wait_for_port(timeout=60):
 
175
  headers = {"Content-Type": "application/x-www-form-urlencoded"}
176
  conn.request("POST", "/checkDocument", params, headers)
177
  resp = conn.getresponse()
 
 
178
  if resp.status != 200: return []
179
 
 
180
  xml_text = resp.read().decode('utf-8', errors='ignore')
 
 
181
  if not xml_text.strip().startswith("<"): return []
182
 
183
  root = ET.fromstring(xml_text)
 
235
  setup_server()
236
  server_proc = start_backend()
237
 
238
+ time.sleep(5)
 
 
239
  if server_proc.poll() is not None:
240
+ print("FATAL: Java server exited immediately.")
241
  sys.exit(1)
242
 
243
+ if wait_for_port(timeout=120):
244
  with gr.Blocks(title="AtD Self-Hosted") as demo:
245
  gr.Markdown("# 🛡️ After The Deadline")
246
+ gr.Markdown("Running on Portable Java 8")
247
 
248
  with gr.Row():
249
+ inp = gr.Textbox(label="Input", placeholder="Type here... e.g., I has a error.", lines=6)
250
  out = gr.HighlightedText(label="Analysis", combine_adjacent=True)
251
 
252
  btn = gr.Button("Check Text", variant="primary")