Coin_Flipper / app.py
SmokeyBandit's picture
Update app.py
868552c verified
import gradio as gr
import random
import threading
import time
from datetime import datetime
FLIP_LOG = "flips.md"
is_flipping = False
start_time = None
heads_count = 0
tails_count = 0
flip_lock = threading.Lock()
# Make sure the flip log exists
with open(FLIP_LOG, "a") as f:
f.write("## Eternal Coin Flips\n\n") # Add header once if not present
# Flip forever in the background
def flip_forever():
global heads_count, tails_count
while True:
result = random.choice(["Heads", "Tails"])
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
# Update counters thread-safely
with flip_lock:
if result == "Heads":
heads_count += 1
else:
tails_count += 1
with open(FLIP_LOG, "a") as f:
f.write(f"- {timestamp}: {result}\n")
time.sleep(1)
# Trigger flipping once
def start_flipping():
global is_flipping, start_time
if not is_flipping:
is_flipping = True
start_time = datetime.utcnow()
threading.Thread(target=flip_forever, daemon=True).start()
return "Started flipping! No going back now."
return "Already flipping."
# Get runtime duration
def get_runtime():
if start_time is None:
return "Not started yet"
current_time = datetime.utcnow()
runtime = current_time - start_time
# Format runtime nicely
total_seconds = int(runtime.total_seconds())
hours = total_seconds // 3600
minutes = (total_seconds % 3600) // 60
seconds = total_seconds % 60
if hours > 0:
return f"{hours}h {minutes}m {seconds}s"
elif minutes > 0:
return f"{minutes}m {seconds}s"
else:
return f"{seconds}s"
# Get current tally
def get_tally():
with flip_lock:
total_flips = heads_count + tails_count
if total_flips == 0:
return "No flips yet"
heads_percent = (heads_count / total_flips) * 100
tails_percent = (tails_count / total_flips) * 100
return f"πŸͺ™ **Total Flips:** {total_flips}\n" \
f"πŸ‘‘ **Heads:** {heads_count} ({heads_percent:.1f}%)\n" \
f"πŸ”„ **Tails:** {tails_count} ({tails_percent:.1f}%)"
# Load last 20 flips from the log
def get_latest_flips():
try:
with open(FLIP_LOG, "r") as f:
lines = f.readlines()
return "".join(lines[-20:]) if lines else "No flips yet."
except FileNotFoundError:
return "No flips yet."
# Combined update function for all stats
def update_all_stats():
return get_tally(), get_runtime(), get_latest_flips()
# Load existing data on startup (count flips from log)
def load_existing_data():
global heads_count, tails_count
try:
with open(FLIP_LOG, "r") as f:
lines = f.readlines()
# Count existing flips
for line in lines:
if ": Heads" in line:
heads_count += 1
elif ": Tails" in line:
tails_count += 1
except FileNotFoundError:
pass
# Load existing data on startup
load_existing_data()
# Build UI
with gr.Blocks(theme=gr.themes.Soft()) as app:
gr.Markdown("# πŸͺ™ Eternal Coin Flipper")
gr.Markdown("⚠️ **Zero CPU Limitation**: Click 'Refresh' to see updates (no real-time on free tier)")
with gr.Row():
with gr.Column():
flip_button = gr.Button("πŸš€ Start Flipping", variant="primary", size="lg")
refresh_button = gr.Button("πŸ”„ Refresh Stats", variant="secondary")
gr.Markdown("πŸ’‘ *Tip: Bookmark and check back later to see progress!*")
with gr.Column():
# Stats display
tally_display = gr.Markdown(value=get_tally(), label="Flip Tally")
runtime_display = gr.Markdown(value=f"⏱️ **Runtime:** {get_runtime()}")
# Flip log
gr.Markdown("## Recent Flips")
flip_log = gr.Textbox(label="Last 20 Flips", lines=15, max_lines=20)
# Event handlers
flip_button.click(
fn=lambda: (start_flipping(), *update_all_stats()),
outputs=[gr.Textbox(visible=False), tally_display, runtime_display, flip_log]
)
refresh_button.click(
fn=update_all_stats,
outputs=[tally_display, runtime_display, flip_log]
)
# Auto-refresh when page loads
app.load(fn=update_all_stats, outputs=[tally_display, runtime_display, flip_log])
if __name__ == "__main__":
app.launch()