VeryOnly123 commited on
Commit
df8e971
·
1 Parent(s): 52c63f5
Files changed (3) hide show
  1. app.py +9 -0
  2. solver.py +41 -14
  3. static/solver.html +21 -1
app.py CHANGED
@@ -16,10 +16,13 @@ def api_submit():
16
  if not problem:
17
  return jsonify({'error': 'No problem provided'}), 400
18
 
 
19
  task_id = solver.submit_task(problem)
20
  if task_id is None:
 
21
  return jsonify({'error': 'Server is busy, please try again later'}), 503
22
 
 
23
  return jsonify({'task_id': task_id})
24
 
25
 
@@ -51,6 +54,12 @@ def api_tasks():
51
  return jsonify({'tasks': solver.list_tasks()})
52
 
53
 
 
 
 
 
 
 
54
  @app.route('/api/debug')
55
  def api_debug():
56
  return jsonify(solver.debug_info())
 
16
  if not problem:
17
  return jsonify({'error': 'No problem provided'}), 400
18
 
19
+ print(f"[SUBMIT] Received problem ({len(problem)} chars)", flush=True)
20
  task_id = solver.submit_task(problem)
21
  if task_id is None:
22
+ print("[SUBMIT] Server busy", flush=True)
23
  return jsonify({'error': 'Server is busy, please try again later'}), 503
24
 
25
+ print(f"[SUBMIT] Returning task_id: {task_id}", flush=True)
26
  return jsonify({'task_id': task_id})
27
 
28
 
 
54
  return jsonify({'tasks': solver.list_tasks()})
55
 
56
 
57
+ @app.route('/api/running')
58
+ def api_running():
59
+ """Return currently running tasks (for recovery after page refresh)."""
60
+ return jsonify({'tasks': solver.get_running_tasks()})
61
+
62
+
63
  @app.route('/api/debug')
64
  def api_debug():
65
  return jsonify(solver.debug_info())
solver.py CHANGED
@@ -21,19 +21,11 @@ tasks = {}
21
  tasks_lock = threading.Lock()
22
 
23
 
24
- def _now():
25
- return datetime.now(timezone.utc).isoformat()
26
-
27
-
28
- def active_count():
29
- with tasks_lock:
30
- return sum(1 for t in tasks.values() if t["status"] in ("pending", "running"))
31
-
32
-
33
  def _log(task_id, msg):
34
- """Append a line to the task's log file."""
35
  task = tasks.get(task_id)
36
  if not task:
 
37
  return
38
  log_path = os.path.join(task["workspace"], "solver.log")
39
  try:
@@ -41,6 +33,16 @@ def _log(task_id, msg):
41
  f.write(f"[{_now()}] {msg}\n")
42
  except Exception:
43
  pass
 
 
 
 
 
 
 
 
 
 
44
 
45
 
46
  def submit_task(problem_text):
@@ -88,6 +90,8 @@ def submit_task(problem_text):
88
  with open(log_path, "w", encoding="utf-8") as f:
89
  f.write(f"[{_now()}] Task {task_id} created\n")
90
 
 
 
91
  # Spawn background thread
92
  t = threading.Thread(target=_run_solver, args=(task_id, workspace), daemon=True)
93
  t.start()
@@ -95,6 +99,7 @@ def submit_task(problem_text):
95
 
96
 
97
  def _run_solver(task_id, workspace):
 
98
  with tasks_lock:
99
  tasks[task_id].update({"status": "running", "started_at": _now()})
100
 
@@ -108,8 +113,11 @@ def _run_solver(task_id, workspace):
108
  proc = None
109
 
110
  try:
 
 
 
111
  proc = subprocess.Popen(
112
- [sys.executable, os.path.join(workspace, "run.py"), workspace],
113
  stdout=subprocess.PIPE,
114
  stderr=subprocess.STDOUT,
115
  cwd=workspace,
@@ -194,7 +202,11 @@ def _run_solver(task_id, workspace):
194
  "finished_at": _now(),
195
  })
196
  except Exception as e:
 
 
197
  _log(task_id, f"Exception: {e}")
 
 
198
  with tasks_lock:
199
  tasks[task_id].update({
200
  "status": "error",
@@ -242,8 +254,9 @@ def get_task_logs(task_id, lines=100):
242
  """Read the last N lines of solver.log."""
243
  task = tasks.get(task_id)
244
  if not task:
245
- return []
246
  log_path = os.path.join(task["workspace"], "solver.log")
 
247
  if not os.path.exists(log_path):
248
  return ["No log file found."]
249
  try:
@@ -254,6 +267,22 @@ def get_task_logs(task_id, lines=100):
254
  return [f"Error reading log: {e}"]
255
 
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  def debug_info():
258
  """Return filesystem/env debug info for troubleshooting."""
259
  info = {
@@ -270,14 +299,12 @@ def debug_info():
270
  "timeout": DEFAULT_TIMEOUT,
271
  "max_tasks": MAX_TASKS,
272
  "tasks_count": len(tasks),
273
- # Dump all env var keys matching common patterns (values masked)
274
  "env_keys_found": sorted([
275
  k for k in os.environ
276
  if any(pat in k.lower() for pat in [
277
  "key", "token", "secret", "anthropic", "hf_", "hugging"
278
  ])
279
  ]),
280
- # Full env var names (first 30, for debugging HF secret injection)
281
  "all_env_keys_sample": sorted(os.environ.keys())[:30],
282
  }
283
  if os.path.isdir(SOLVER_SRC):
 
21
  tasks_lock = threading.Lock()
22
 
23
 
 
 
 
 
 
 
 
 
 
24
  def _log(task_id, msg):
25
+ """Append a line to the task's log file AND print to stdout."""
26
  task = tasks.get(task_id)
27
  if not task:
28
+ print(f"[{task_id}] {msg}", flush=True)
29
  return
30
  log_path = os.path.join(task["workspace"], "solver.log")
31
  try:
 
33
  f.write(f"[{_now()}] {msg}\n")
34
  except Exception:
35
  pass
36
+ print(f"[{task_id}] {msg}", flush=True)
37
+
38
+
39
+ def _now():
40
+ return datetime.now(timezone.utc).isoformat()
41
+
42
+
43
+ def active_count():
44
+ with tasks_lock:
45
+ return sum(1 for t in tasks.values() if t["status"] in ("pending", "running"))
46
 
47
 
48
  def submit_task(problem_text):
 
90
  with open(log_path, "w", encoding="utf-8") as f:
91
  f.write(f"[{_now()}] Task {task_id} created\n")
92
 
93
+ print(f"[SUBMIT] Created task {task_id} -> {workspace}", flush=True)
94
+
95
  # Spawn background thread
96
  t = threading.Thread(target=_run_solver, args=(task_id, workspace), daemon=True)
97
  t.start()
 
99
 
100
 
101
  def _run_solver(task_id, workspace):
102
+ print(f"[{task_id}] _run_solver thread started", flush=True)
103
  with tasks_lock:
104
  tasks[task_id].update({"status": "running", "started_at": _now()})
105
 
 
113
  proc = None
114
 
115
  try:
116
+ cmd = [sys.executable, os.path.join(workspace, "run.py"), workspace]
117
+ print(f"[{task_id}] Running: {' '.join(cmd)}", flush=True)
118
+
119
  proc = subprocess.Popen(
120
+ cmd,
121
  stdout=subprocess.PIPE,
122
  stderr=subprocess.STDOUT,
123
  cwd=workspace,
 
202
  "finished_at": _now(),
203
  })
204
  except Exception as e:
205
+ import traceback
206
+ tb = traceback.format_exc()
207
  _log(task_id, f"Exception: {e}")
208
+ _log(task_id, tb)
209
+ print(f"[{task_id}] Traceback:\n{tb}", flush=True)
210
  with tasks_lock:
211
  tasks[task_id].update({
212
  "status": "error",
 
254
  """Read the last N lines of solver.log."""
255
  task = tasks.get(task_id)
256
  if not task:
257
+ return [f"Task {task_id} not found in memory."]
258
  log_path = os.path.join(task["workspace"], "solver.log")
259
+ print(f"[LOGS] Reading {log_path} (exists={os.path.exists(log_path)})", flush=True)
260
  if not os.path.exists(log_path):
261
  return ["No log file found."]
262
  try:
 
267
  return [f"Error reading log: {e}"]
268
 
269
 
270
+ def get_running_tasks():
271
+ """Return list of currently running tasks (for frontend recovery after refresh)."""
272
+ with tasks_lock:
273
+ return [
274
+ {
275
+ "task_id": t["task_id"],
276
+ "status": t["status"],
277
+ "phase": t["phase"],
278
+ "problem": t["problem"],
279
+ "created_at": t["created_at"],
280
+ }
281
+ for t in tasks.values()
282
+ if t["status"] in ("pending", "running")
283
+ ]
284
+
285
+
286
  def debug_info():
287
  """Return filesystem/env debug info for troubleshooting."""
288
  info = {
 
299
  "timeout": DEFAULT_TIMEOUT,
300
  "max_tasks": MAX_TASKS,
301
  "tasks_count": len(tasks),
 
302
  "env_keys_found": sorted([
303
  k for k in os.environ
304
  if any(pat in k.lower() for pat in [
305
  "key", "token", "secret", "anthropic", "hf_", "hugging"
306
  ])
307
  ]),
 
308
  "all_env_keys_sample": sorted(os.environ.keys())[:30],
309
  }
310
  if os.path.isdir(SOLVER_SRC):
static/solver.html CHANGED
@@ -54,6 +54,7 @@
54
  .log-console.visible { display: block; }
55
  .log-console .log-line { padding: 1px 0; }
56
  .log-console .log-line:last-child { color: #f9e2af; }
 
57
 
58
  /* Result */
59
  .result { display: none; margin-top: 16px; }
@@ -189,10 +190,12 @@
189
  try {
190
  const resp = await fetch('/api/logs/' + currentTaskId + '?lines=50');
191
  const data = await resp.json();
 
192
  if (data.logs && data.logs.length > 0) {
193
- const el = document.getElementById('log-console');
194
  el.innerHTML = data.logs.map(l => `<div class="log-line">${escapeHtml(l)}</div>`).join('');
195
  el.scrollTop = el.scrollHeight;
 
 
196
  }
197
  } catch (e) {}
198
  }
@@ -358,6 +361,23 @@
358
  el.textContent = JSON.stringify(data, null, 2);
359
  })
360
  .catch(() => {});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  </script>
362
  </body>
363
  </html>
 
54
  .log-console.visible { display: block; }
55
  .log-console .log-line { padding: 1px 0; }
56
  .log-console .log-line:last-child { color: #f9e2af; }
57
+ .log-console .log-line.loading { color: #585b70; font-style: italic; }
58
 
59
  /* Result */
60
  .result { display: none; margin-top: 16px; }
 
190
  try {
191
  const resp = await fetch('/api/logs/' + currentTaskId + '?lines=50');
192
  const data = await resp.json();
193
+ const el = document.getElementById('log-console');
194
  if (data.logs && data.logs.length > 0) {
 
195
  el.innerHTML = data.logs.map(l => `<div class="log-line">${escapeHtml(l)}</div>`).join('');
196
  el.scrollTop = el.scrollHeight;
197
+ } else if (!el.querySelector('.loading')) {
198
+ el.innerHTML = '<div class="log-line loading">Waiting for logs...</div>';
199
  }
200
  } catch (e) {}
201
  }
 
361
  el.textContent = JSON.stringify(data, null, 2);
362
  })
363
  .catch(() => {});
364
+
365
+ // Recovery: check for running tasks on page load
366
+ fetch('/api/running')
367
+ .then(r => r.json())
368
+ .then(data => {
369
+ if (data.tasks && data.tasks.length > 0) {
370
+ const t = data.tasks[0]; // Most recent running task
371
+ document.getElementById('progress-bar').classList.add('visible');
372
+ currentTaskId = t.task_id;
373
+ startTime = Date.now();
374
+ updateProgress(t.phase || 'starting');
375
+ fetchLogs();
376
+ startElapsed();
377
+ pollStatus();
378
+ }
379
+ })
380
+ .catch(() => {});
381
  </script>
382
  </body>
383
  </html>