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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -61
app.py CHANGED
@@ -10,6 +10,7 @@ import urllib.parse
10
  import xml.etree.ElementTree as ET
11
  import shutil
12
  import re
 
13
 
14
  # =============================================================================
15
  # CONFIGURATION
@@ -29,43 +30,44 @@ MODEL_FILES = [
29
  ]
30
 
31
  # =============================================================================
32
- # PHASE 1: AUTO-INSTALLATION & SETUP
33
  # =============================================================================
34
- def patch_server_code():
35
  """
36
- Patches legacy Sleep code to run on modern Java (JDK 9+).
37
- Removes 'from: lib/spellutils.jar' syntax which causes ClassCastException.
 
38
  """
39
- print("--- [PHASE 1.5] PATCHING CODE FOR JAVA 17+ ---")
40
 
41
- # Files that are known to contain the incompatible import syntax
42
- files_to_check = [
43
- os.path.join(SERVER_DIR, "lib", "spellcheck.sl"),
44
- os.path.join(SERVER_DIR, "utils", "spell", "trainspell.sl") # Potentially here too
45
- ]
46
 
47
- for file_path in files_to_check:
48
- if not os.path.exists(file_path):
49
- continue
 
 
 
 
50
 
 
51
  try:
52
- with open(file_path, "r") as f:
53
  content = f.read()
54
 
55
- # Regex to remove 'from: lib/spellutils.jar' but keep the semicolon
56
- # Matches: from: [whitespace] lib/spellutils.jar
57
- new_content = re.sub(r'from:\s*lib/spellutils\.jar', '', content)
58
 
59
  if content != new_content:
60
  print(f"Patching {file_path}...")
61
- with open(file_path, "w") as f:
62
  f.write(new_content)
63
- print("-> Success: Code patched for modern Java.")
64
- else:
65
- print(f"-> {file_path} already clean.")
66
-
67
  except Exception as e:
68
- print(f"Error patching {file_path}: {e}")
 
 
69
 
70
  def setup_server():
71
  print("--- [PHASE 0] CHECKING REPOSITORY ---")
@@ -86,31 +88,49 @@ def setup_server():
86
  urllib.request.urlretrieve(url, filepath)
87
  except Exception as e:
88
  print(f" -> FAILED: {e}")
89
-
90
- # RUN THE PATCH BEFORE COMPILING
91
- patch_server_code()
 
92
 
93
  print("\n--- [PHASE 2] COMPILING RULES ---")
94
- # Only compile if the output file doesn't exist to save startup time on reboots
95
- if not os.path.exists(os.path.join(SERVER_DIR, "models", "grammar.bin")): # Heuristic check
96
- try:
97
- subprocess.run(
98
- ["java", "-Datd.lowmem=true", "-Xmx1024M", "-jar", "lib/sleep.jar", "utils/rules/rules.sl"],
99
- cwd=SERVER_DIR,
100
- check=True
101
- )
102
- print("Rules compiled successfully.")
103
- except subprocess.CalledProcessError:
104
- print("Rule compilation warning (ignoring)...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  # =============================================================================
107
- # PHASE 2: SERVER MANAGEMENT
108
  # =============================================================================
109
  def start_backend():
110
  print("\n--- [PHASE 3] STARTING SERVER ---")
111
  cp_sep = ";" if os.name == 'nt' else ":"
112
 
113
- # We explicitly add spellutils.jar to classpath here, rendering the 'from:' syntax obsolete
114
  classpath = f"lib/sleep.jar{cp_sep}lib/moconti.jar{cp_sep}lib/spellutils.jar"
115
  sleep_cp = f"lib{cp_sep}service/code"
116
 
@@ -129,7 +149,7 @@ def start_backend():
129
  "atdconfig.sl"
130
  ]
131
 
132
- # Start in SERVER_DIR so relative paths (./models) work
133
  return subprocess.Popen(cmd, cwd=SERVER_DIR)
134
 
135
  def wait_for_port(timeout=60):
@@ -157,16 +177,15 @@ class AtDClient:
157
  resp = conn.getresponse()
158
 
159
  # If server is still warming up, it might return 503 or connection drop
160
- if resp.status != 200:
161
- print(f"Server returned status: {resp.status}")
162
- return []
 
163
 
164
- data = resp.read()
165
- # Basic check for valid XML
166
- if not data.strip().startswith(b"<"):
167
- return []
168
 
169
- root = ET.fromstring(data)
170
  errors = []
171
  for e in root.findall('error'):
172
  err = {
@@ -196,8 +215,6 @@ def analyze_text(text):
196
  for err in errors:
197
  word = err['string']
198
  search_start = last_pos
199
-
200
- # Context aware search
201
  if err['precontext']:
202
  context_idx = text.find(err['precontext'], last_pos)
203
  if context_idx != -1:
@@ -223,27 +240,26 @@ if __name__ == "__main__":
223
  setup_server()
224
  server_proc = start_backend()
225
 
226
- # Give it a moment to fail if java crashes immediately
227
- time.sleep(2)
 
228
  if server_proc.poll() is not None:
229
- print("Java server crashed immediately. Checking logs...")
230
- print(server_proc.stdout)
231
- print(server_proc.stderr)
232
  sys.exit(1)
233
 
234
- if wait_for_port():
235
  with gr.Blocks(title="AtD Self-Hosted") as demo:
236
- gr.Markdown("# 🛡️ After The Deadline (Self-Installing)")
237
- gr.Markdown("Java 17 Compatible | Auto-Patching | Auto-Models")
238
 
239
  with gr.Row():
240
- inp = gr.Textbox(label="Input", placeholder="Type here... e.g., I has a error.", lines=6)
241
- out = gr.HighlightedText(label="Corrections", combine_adjacent=True)
242
 
243
  btn = gr.Button("Check Text", variant="primary")
244
  btn.click(analyze_text, inputs=inp, outputs=out)
245
 
246
  demo.launch(server_name="0.0.0.0", server_port=7860)
247
  else:
248
- print("FATAL: Server did not start.")
249
  server_proc.kill()
 
10
  import xml.etree.ElementTree as ET
11
  import shutil
12
  import re
13
+ import glob
14
 
15
  # =============================================================================
16
  # CONFIGURATION
 
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 ---")
 
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
 
 
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):
 
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)
189
  errors = []
190
  for e in root.findall('error'):
191
  err = {
 
215
  for err in errors:
216
  word = err['string']
217
  search_start = last_pos
 
 
218
  if err['precontext']:
219
  context_idx = text.find(err['precontext'], last_pos)
220
  if context_idx != -1:
 
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")
260
  btn.click(analyze_text, inputs=inp, outputs=out)
261
 
262
  demo.launch(server_name="0.0.0.0", server_port=7860)
263
  else:
264
+ print("FATAL: Server did not start (Timeout).")
265
  server_proc.kill()