Spaces:
Sleeping
Sleeping
| 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() |