Spaces:
Running
on
Zero
Running
on
Zero
Commit
·
c214ec0
1
Parent(s):
2c24bbf
trying with logging file and thread
Browse files
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,
|
315 |
"""
|
316 |
-
|
317 |
-
|
|
|
318 |
"""
|
319 |
-
import subprocess, os, sys
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
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 |
-
|
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 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
|
|
|
|
|
|
|
|
|
|
792 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
793 |
worker.start()
|
794 |
|
795 |
preview_mtime = 0
|
796 |
last_push = 0
|
797 |
-
|
798 |
-
|
799 |
-
while worker.is_alive() or
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
log_output += msg
|
807 |
-
except Empty:
|
808 |
-
pass
|
809 |
|
810 |
now = time.time()
|
811 |
-
if now - last_push >= 1.0: #
|
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)
|
|
|
|
|
|
|
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}")
|