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}")
|