Spaces:
Paused
Paused
| import gradio as gr | |
| import json | |
| import os | |
| from datetime import datetime, timedelta | |
| from huggingface_hub import HfApi, upload_file | |
| # -------------------------------------------------- | |
| # HF CONFIG | |
| # -------------------------------------------------- | |
| HF_REPO_ID = "rahul7star/ohamlab-pro" | |
| HF_REPO_TYPE = "model" | |
| HF_TOKEN = os.getenv("HF_TOKEN") | |
| api = HfApi(token=HF_TOKEN) | |
| # -------------------------------------------------- | |
| # FILE PATHS | |
| # -------------------------------------------------- | |
| SLOTS_FILE = "/tmp/slots.json" | |
| BOOKINGS_FILE = "/tmp/bookings.json" | |
| # -------------------------------------------------- | |
| # INIT SLOTS (RUN ONCE) | |
| # -------------------------------------------------- | |
| def init_slots(): | |
| if os.path.exists(SLOTS_FILE): | |
| with open(SLOTS_FILE) as f: | |
| return json.load(f) | |
| slots = [] | |
| base = datetime.now().replace(hour=11, minute=0, second=0, microsecond=0) | |
| for d in range(5): # next 5 days | |
| for h in [11, 15, 18]: # 3 slots per day | |
| slot = (base + timedelta(days=d)).replace(hour=h) | |
| slots.append(slot.strftime("%Y-%m-%d %H:%M")) | |
| with open(SLOTS_FILE, "w") as f: | |
| json.dump(slots, f, indent=2) | |
| return slots | |
| def load_bookings(): | |
| if not os.path.exists(BOOKINGS_FILE): | |
| return [] | |
| with open(BOOKINGS_FILE) as f: | |
| return json.load(f) | |
| AVAILABLE_SLOTS = init_slots() | |
| # -------------------------------------------------- | |
| # UPLOAD JSON TO HF HUB | |
| # -------------------------------------------------- | |
| def upload_to_hf(local_path, repo_path): | |
| upload_file( | |
| path_or_fileobj=local_path, | |
| path_in_repo=repo_path, | |
| repo_id=HF_REPO_ID, | |
| repo_type=HF_REPO_TYPE, | |
| token=HF_TOKEN, | |
| commit_message=f"Update {repo_path}" | |
| ) | |
| # -------------------------------------------------- | |
| # BOOKING LOGIC | |
| # -------------------------------------------------- | |
| def book_slot(slot, name, email): | |
| if not slot or not name or not email: | |
| return gr.update(), "❌ Please fill all fields" | |
| if slot not in AVAILABLE_SLOTS: | |
| return gr.update(), "❌ Slot already booked" | |
| # remove slot | |
| AVAILABLE_SLOTS.remove(slot) | |
| with open(SLOTS_FILE, "w") as f: | |
| json.dump(AVAILABLE_SLOTS, f, indent=2) | |
| bookings = load_bookings() | |
| bookings.append({ | |
| "slot": slot, | |
| "name": name, | |
| "email": email, | |
| "booked_at": datetime.utcnow().isoformat() | |
| }) | |
| with open(BOOKINGS_FILE, "w") as f: | |
| json.dump(bookings, f, indent=2) | |
| # upload both files | |
| upload_to_hf(SLOTS_FILE, "slots.json") | |
| upload_to_hf(BOOKINGS_FILE, "bookings.json") | |
| return ( | |
| gr.update(choices=AVAILABLE_SLOTS, value=None), | |
| "✅ Booking confirmed! We’ll contact you shortly." | |
| ) | |
| # -------------------------------------------------- | |
| # UI | |
| # -------------------------------------------------- | |
| CSS = """ | |
| footer, .gradio-footer { display: none !important; } | |
| #ohamlab-footer { | |
| position: fixed; | |
| bottom: 0; | |
| width: 100%; | |
| text-align: center; | |
| padding: 8px; | |
| font-size: 12px; | |
| background: #f8f9fb; | |
| border-top: 1px solid #e5e7eb; | |
| } | |
| """ | |
| with gr.Blocks(css=CSS, theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("## 📅 Book a Meeting with OhamLab") | |
| gr.Markdown("Select an available slot and confirm instantly.") | |
| slot_dd = gr.Dropdown( | |
| choices=AVAILABLE_SLOTS, | |
| label="Available Time Slots" | |
| ) | |
| name = gr.Textbox(label="Your Name") | |
| email = gr.Textbox(label="Your Email") | |
| book_btn = gr.Button("Confirm Booking") | |
| status = gr.Markdown() | |
| book_btn.click( | |
| book_slot, | |
| inputs=[slot_dd, name, email], | |
| outputs=[slot_dd, status] | |
| ) | |
| gr.HTML("<div id='ohamlab-footer'>© OhamLab</div>") | |
| demo.queue() | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |