hvoss-techfak commited on
Commit
c214ec0
·
1 Parent(s): 2c24bbf

trying with logging file and thread

Browse files
Files changed (1) hide show
  1. app.py +59 -47
app.py CHANGED
@@ -310,27 +310,28 @@ if os.path.exists(DEFAULT_MATERIALS_CSV):
310
  else:
311
  initial_df.to_csv(DEFAULT_MATERIALS_CSV, index=False)
312
 
313
- @spaces.GPU()
314
- def run_autoforge_process(cmd, q):
315
  """
316
- Start the Autoforge CLI, stream its stdout to Queue *q*,
317
- then drop a sentinel ('__RC__', return_code) at the end.
 
318
  """
319
- import subprocess, os, sys
320
-
321
- proc = subprocess.Popen(
322
- cmd,
323
- stdout=subprocess.PIPE,
324
- stderr=subprocess.STDOUT,
325
- text=True,
326
- bufsize=1,
327
- universal_newlines=True,
328
- )
329
-
330
- for line in proc.stdout: # line-by-line streaming
331
- q.put(line)
332
- proc.wait()
333
- q.put(("__RC__", proc.returncode))
334
 
335
 
336
  # Helper for creating an empty 10-tuple for error returns
@@ -750,15 +751,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
750
  )
751
 
752
  yield create_empty_error_outputs(log_output) # clear UI and show header
753
- cmd_str = " ".join(command)
754
- sentry_sdk.capture_event(
755
- {
756
- "message": "Autoforge process started",
757
- "level": "info",
758
- "fingerprint": ["autoforge-process-start"], # every start groups here
759
- "extra": {"command": cmd_str}, # still searchable
760
- }
761
- )
762
 
763
  def _maybe_new_preview():
764
  """
@@ -784,31 +777,47 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
784
  from threading import Thread
785
  from queue import Queue, Empty
786
 
787
- q_out = Queue()
788
- worker = Thread(
789
- target=run_autoforge_process,
790
- args=(command, q_out),
791
- daemon=True,
 
 
 
 
 
792
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
  worker.start()
794
 
795
  preview_mtime = 0
796
  last_push = 0
797
- return_code = None
798
-
799
- while worker.is_alive() or not q_out.empty():
800
- try:
801
- while True: # drain whatever is ready
802
- msg = q_out.get_nowait()
803
- if isinstance(msg, tuple): # ('__RC__', code) sentinel
804
- return_code = msg[1]
805
- else:
806
- log_output += msg
807
- except Empty:
808
- pass
809
 
810
  now = time.time()
811
- if now - last_push >= 1.0: # 1-second UI tick
812
  current_preview = _maybe_new_preview()
813
  yield (
814
  log_output,
@@ -817,7 +826,10 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
817
  )
818
  last_push = now
819
 
820
- time.sleep(0.05) # keep CPU load low
 
 
 
821
 
822
  if return_code != 0:
823
  err = RuntimeError(f"Autoforge exited with code {return_code} \n {log_output}")
 
310
  else:
311
  initial_df.to_csv(DEFAULT_MATERIALS_CSV, index=False)
312
 
313
+ @spaces.GPU() # GPU reserved only for this call
314
+ def run_autoforge_process(cmd, log_path):
315
  """
316
+ Launch the external `autoforge` CLI.
317
+ All stdout/stderr lines are appended (line-buffered) to *log_path*.
318
+ Returns the CLI's exit-code.
319
  """
320
+ import subprocess, io, os, sys
321
+
322
+ with open(log_path, "w", buffering=1, encoding="utf-8") as log_f: # line-buffered
323
+ proc = subprocess.Popen(
324
+ cmd,
325
+ stdout=subprocess.PIPE,
326
+ stderr=subprocess.STDOUT,
327
+ text=True,
328
+ bufsize=1,
329
+ universal_newlines=True,
330
+ )
331
+ for line in proc.stdout: # live streaming to the file
332
+ log_f.write(line)
333
+ proc.wait()
334
+ return proc.returncode
335
 
336
 
337
  # Helper for creating an empty 10-tuple for error returns
 
751
  )
752
 
753
  yield create_empty_error_outputs(log_output) # clear UI and show header
754
+
 
 
 
 
 
 
 
 
755
 
756
  def _maybe_new_preview():
757
  """
 
777
  from threading import Thread
778
  from queue import Queue, Empty
779
 
780
+ log_file = os.path.join(run_output_dir_val, "autoforge_live.log")
781
+
782
+ cmd_str = " ".join(command)
783
+ sentry_sdk.capture_event(
784
+ {
785
+ "message": "Autoforge process started",
786
+ "level": "info",
787
+ "fingerprint": ["autoforge-process-start"], # every start groups here
788
+ "extra": {"command": cmd_str}, # still searchable
789
+ }
790
  )
791
+
792
+ # simple thread that just calls the GPU helper and stores the exit code
793
+ import threading
794
+
795
+ class Worker(threading.Thread):
796
+ def __init__(self, cmd, log_path):
797
+ super().__init__(daemon=True)
798
+ self.cmd, self.log_path = cmd, log_path
799
+ self.returncode = None
800
+
801
+ def run(self):
802
+ self.returncode = run_autoforge_process(self.cmd, self.log_path)
803
+
804
+ worker = Worker(command, log_file)
805
  worker.start()
806
 
807
  preview_mtime = 0
808
  last_push = 0
809
+ file_pos = 0 # how far we've read
810
+
811
+ while worker.is_alive() or file_pos < os.path.getsize(log_file):
812
+ # read any new console text
813
+ with open(log_file, "r", encoding="utf-8") as lf:
814
+ lf.seek(file_pos)
815
+ new_txt = lf.read()
816
+ file_pos = lf.tell()
817
+ log_output += new_txt
 
 
 
818
 
819
  now = time.time()
820
+ if now - last_push >= 1.0: # one-second UI tick
821
  current_preview = _maybe_new_preview()
822
  yield (
823
  log_output,
 
826
  )
827
  last_push = now
828
 
829
+ time.sleep(0.05)
830
+
831
+ worker.join() # make sure it’s done
832
+ return_code = worker.returncode
833
 
834
  if return_code != 0:
835
  err = RuntimeError(f"Autoforge exited with code {return_code} \n {log_output}")