udbhav
Recreate Trame_app branch with clean history
67fb03c
# trame_timer_full_demo_v2.py
# Trame (Vuetify v2) – robust, reusable ticking timers for any long-running task
import time
import threading
from trame.app import get_server
from trame.ui.vuetify import SinglePageLayout
from trame.widgets import vuetify as v
# -----------------------------------------------------------------------------
# Server / State
# -----------------------------------------------------------------------------
server = get_server() # Vuetify v2 stack
state = server.state
# Upload stage
state.is_uploading = False
state.upload_elapsed = 0.0
state.upload_progress = 0 # 0..100
state.upload_msg = ""
# Predict stage
state.is_predicting = False
state.predict_elapsed = 0.0
state.predict_progress = 0 # 0..100
state.predict_msg = ""
def _flush_safe():
try:
state.flush()
except Exception:
# Prefer logging in real apps; avoid crashing worker thread
pass
# -----------------------------------------------------------------------------
# Generic, reusable timer helpers
# -----------------------------------------------------------------------------
def start_ticker(flag_key: str, elapsed_key: str, interval_s: float = 0.1):
"""
Start a thread that updates <elapsed_key> while <flag_key> is True.
"""
state[elapsed_key] = 0.0
state[flag_key] = True
_flush_safe()
def _tick():
t0 = time.perf_counter()
while state.get(flag_key, False):
state[elapsed_key] = time.perf_counter() - t0
_flush_safe()
time.sleep(interval_s)
threading.Thread(target=_tick, daemon=True).start()
def stop_ticker(flag_key: str):
state[flag_key] = False
_flush_safe()
def run_with_timer(flag_key: str, elapsed_key: str, work_fn, *args, **kwargs):
"""
Fire-and-forget: starts ticker, runs work_fn(*args, **kwargs) in a thread,
and always stops ticker in a finally-block. Returns the worker thread.
"""
start_ticker(flag_key, elapsed_key)
def _runner():
try:
work_fn(*args, **kwargs)
finally:
stop_ticker(flag_key)
t = threading.Thread(target=_runner, daemon=True)
t.start()
return t
# -----------------------------------------------------------------------------
# Example “work” functions (replace with your real code)
# -----------------------------------------------------------------------------
def _simulate_upload_work():
"""
Simulates an upload: increments progress 0..100 and sets a message.
If cancelled (is_uploading False), it exits cleanly.
"""
state.upload_msg = "Uploading geometry..."
state.upload_progress = 0
_flush_safe()
for i in range(101):
if not state.is_uploading:
state.upload_msg = "Upload cancelled."
_flush_safe()
return
state.upload_progress = i
_flush_safe()
time.sleep(0.05) # Simulate IO chunks
state.upload_msg = "Upload completed."
_flush_safe()
def _simulate_predict_work():
"""
Simulates prediction: increments progress 0..100 and sets a message.
"""
state.predict_msg = "Running prediction..."
state.predict_progress = 0
_flush_safe()
for i in range(101):
if not state.is_predicting:
state.predict_msg = "Prediction cancelled."
_flush_safe()
return
state.predict_progress = i
_flush_safe()
time.sleep(0.06) # Simulate compute steps
state.predict_msg = "Prediction completed."
_flush_safe()
# -----------------------------------------------------------------------------
# Controllers (button hooks)
# -----------------------------------------------------------------------------
def start_upload():
# Reset UI bits for a fresh run
state.upload_progress = 0
state.upload_msg = ""
_flush_safe()
run_with_timer("is_uploading", "upload_elapsed", _simulate_upload_work)
def cancel_upload():
# Just drop the flag; worker and ticker will stop on next loop
stop_ticker("is_uploading")
def start_predict():
state.predict_progress = 0
state.predict_msg = ""
_flush_safe()
run_with_timer("is_predicting", "predict_elapsed", _simulate_predict_work)
def cancel_predict():
stop_ticker("is_predicting")
# -----------------------------------------------------------------------------
# UI (Vuetify v2)
# -----------------------------------------------------------------------------
with SinglePageLayout(server) as layout:
layout.title.set_text("Trame Live Timer – Upload & Predict")
with layout.toolbar:
v.VBtn("Start Upload", color="primary", click=start_upload)
v.VBtn("Cancel Upload", color="error", click=cancel_upload, classes="ml-2")
v.VDivider(vertical=True, classes="mx-4")
v.VBtn("Start Predict", color="secondary", click=start_predict)
v.VBtn("Cancel Predict", color="error", click=cancel_predict, classes="ml-2")
with layout.content:
# Upload panel
v.VSheet(
class_="pa-4 mx-auto",
style="max-width: 600px; margin-top: 40px;"
)(
v.VSubheader("Upload Stage"),
# Progress bar (determinate) – remove v_model & set indeterminate=True if duration unknown
v.VProgressLinear(
v_model=("upload_progress", 0),
height=14,
color="primary",
rounded=True,
v_show=("is_uploading",),
),
v.VSpacer(style="min-height:10px;"),
# Live elapsed time
v.VLabel(
"Elapsed: {{ upload_elapsed.toFixed(2) }} s",
v_show=("is_uploading",),
style="font-weight:600; font-size:14px; color:#1976d2;",
),
v.VSpacer(style="min-height:6px;"),
v.VLabel(("{{ upload_msg }}",), style="opacity:0.8;"),
)
# Predict panel
v.VSheet(
class_="pa-4 mx-auto",
style="max-width: 600px; margin-top: 20px;"
)(
v.VSubheader("Prediction Stage"),
v.VProgressLinear(
v_model=("predict_progress", 0),
height=14,
color="secondary",
rounded=True,
v_show=("is_predicting",),
),
v.VSpacer(style="min-height:10px;"),
v.VLabel(
"Elapsed: {{ predict_elapsed.toFixed(2) }} s",
v_show=("is_predicting",),
style="font-weight:600; font-size:14px;",
),
v.VSpacer(style="min-height:6px;"),
v.VLabel(("{{ predict_msg }}",), style="opacity:0.8;"),
)
# -----------------------------------------------------------------------------
# Run
# -----------------------------------------------------------------------------
if __name__ == "__main__":
server.start()