from tkinter import ttk, messagebox
from datetime import datetime
SERVICE_NAME = "DeepseekDashboardApp"
TOKEN_KEY = "user_api_token"
# API endpoints for your Hugging Face endpoint actions
RESUME_URL = "https://api.endpoints.huggingface.cloud/v2/endpoint/george-adamon/deepseek-r1-distill-qwen-32b-isu/resume"
PAUSE_URL = "https://api.endpoints.huggingface.cloud/v2/endpoint/george-adamon/deepseek-r1-distill-qwen-32b-isu/pause"
STATUS_URL = "https://api.endpoints.huggingface.cloud/v2/endpoint/george-adamon/deepseek-r1-distill-qwen-32b-isu/replica"
def save_token(token: str):
keyring.set_password(SERVICE_NAME, TOKEN_KEY, token)
stored = keyring.get_password(SERVICE_NAME, TOKEN_KEY)
return stored if stored is not None else ""
# -----------------------------
# -----------------------------
def call_api(url, token, method="POST"):
'accept': 'application/json',
'authorization': f'Bearer {token}'
if method.upper() == "POST":
response = requests.post(url, headers=headers)
elif method.upper() == "GET":
response = requests.get(url, headers=headers)
return response.json() if response.text else {"status": response.status_code}
def get_latest_replica(data):
items = data.get('items', [])
time_str = item.get("status", {}).get("startedAt", "")
return datetime.fromisoformat(time_str.replace("Z", "+00:00"))
return max(items, key=parse_time)
# -----------------------------
# -----------------------------
def update_status_ui(replica):
label_replica_id.config(text="N/A")
label_version_id.config(text="N/A")
label_started_at.config(text="N/A")
label_stopped_at.config(text="N/A")
label_stage.config(text="N/A")
label_updating.config(text="N/A")
label_time_to_running.config(text="N/A")
label_replica_id.config(text=replica.get('id', ''))
label_version_id.config(text=replica.get('versionId', ''))
status = replica.get('status', {})
label_started_at.config(text=status.get('startedAt', 'N/A'))
label_stopped_at.config(text=status.get('stoppedAt', 'N/A'))
label_stage.config(text=status.get('stage', 'N/A'))
label_updating.config(text=str(status.get('updating', 'N/A')))
update_led(status.get('live', False))
# Calculate elapsed time if stage becomes "running".
if status.get("stage", "").lower() == "running" and resume_start_time is not None:
elapsed = datetime.now() - resume_start_time
elapsed_str = str(elapsed).split('.')[0] # Format H:MM:SS (remove microseconds)
label_time_to_running.config(text=elapsed_str)
resume_start_time = None # Reset timer after success.
label_time_to_running.config(text="Waiting...")
color = "green" if is_live else "red"
canvas_led.create_oval(2, 2, 22, 22, fill=color, outline=color)
# -----------------------------
# Functions to Interact with the Endpoint
# -----------------------------
def resume_endpoint(token):
resume_start_time = datetime.now()
call_api(RESUME_URL, token, "POST")
poll_status() # Immediately update status after resume.
threading.Thread(target=task, daemon=True).start()
def pause_endpoint(token):
call_api(PAUSE_URL, token, "POST")
poll_status() # Immediately update status after pause.
threading.Thread(target=task, daemon=True).start()
def fetch_status(token, callback):
result = call_api(STATUS_URL, token, "GET")
if isinstance(result, dict) and "items" in result:
latest = get_latest_replica(result)
token = token_var.get().strip()
target=lambda: fetch_status(token, lambda replica: root.after(0, update_status_ui, replica)),
root.after(30000, poll_status)
# -----------------------------
# -----------------------------
def validate_and_save_token():
token = token_var.get().strip()
messagebox.showwarning("Token Validation", "Please enter a token first.")
result = call_api(STATUS_URL, token, "GET")
messagebox.showerror("Token Validation", f"Token not accepted: {result['error']}")
elif isinstance(result, dict) and "items" in result:
messagebox.showinfo("Token Validation", "Token accepted and saved.")
messagebox.showerror("Token Validation", "Token not accepted by the API.")
# -----------------------------
# -----------------------------
root.title("Hugging Face Endpoint Control Dashboard")
# Configure grid so the main frame expands.
root.columnconfigure(0, weight=1)
root.rowconfigure(3, weight=1)
# -------------- Links Frame --------------
# This frame contains clickable URLs for easy access.
frame_links = ttk.Frame(root, padding="10")
frame_links.grid(row=0, column=0, sticky="ew")
# Inference Endpoint link
link_label1 = ttk.Label(frame_links, text="Visit Inference Endpoint", foreground="blue", cursor="hand2")
link_label1.grid(row=0, column=0, padx=5)
link_label1.bind("<Button-1>", lambda e: open_url("https://endpoints.huggingface.co/george-adamon/endpoints/deepseek-r1-distill-qwen-32b-isu"))
link_label2 = ttk.Label(frame_links, text="Visit Interactive LLM", foreground="blue", cursor="hand2")
link_label2.grid(row=0, column=1, padx=5)
link_label2.bind("<Button-1>", lambda e: open_url("https://interactivellm.tree-correspondents.com/"))
# -------------- Token & Validation Frame --------------
frame_top = ttk.Frame(root, padding="10")
frame_top.grid(row=1, column=0, sticky="ew")
ttk.Label(frame_top, text="API Token:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
token_var = tk.StringVar(value=load_token())
token_entry = ttk.Entry(frame_top, textvariable=token_var, width=50, show="*")
token_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
frame_top.columnconfigure(1, weight=1)
validate_btn = ttk.Button(frame_top, text="Validate & Save Token", command=validate_and_save_token)
validate_btn.grid(row=0, column=2, padx=5, pady=5)
# -------------- Controls Frame --------------
button_frame = ttk.Frame(root, padding="10")
button_frame.grid(row=2, column=0, sticky="ew")
resume_btn = ttk.Button(button_frame, text="Resume Endpoint", command=lambda: resume_endpoint(token_var.get()))
resume_btn.grid(row=0, column=0, padx=5)
pause_btn = ttk.Button(button_frame, text="Pause Endpoint", command=lambda: pause_endpoint(token_var.get()))
pause_btn.grid(row=0, column=1, padx=5)
# -------------- Status Panel --------------
status_frame = ttk.LabelFrame(root, text="Replica Status", padding="10")
status_frame.grid(row=3, column=0, padx=10, pady=10, sticky="nsew")
status_frame.columnconfigure(1, weight=1)
ttk.Label(status_frame, text="Live:").grid(row=0, column=0, sticky="w", padx=5, pady=5)
canvas_led = tk.Canvas(status_frame, width=24, height=24)
canvas_led.grid(row=0, column=1, sticky="w", padx=5, pady=5)
ttk.Label(status_frame, text="Replica ID:").grid(row=1, column=0, sticky="e", padx=5, pady=5)
label_replica_id = ttk.Label(status_frame, text="N/A")
label_replica_id.grid(row=1, column=1, sticky="w", padx=5, pady=5)
ttk.Label(status_frame, text="Version ID:").grid(row=2, column=0, sticky="e", padx=5, pady=5)
label_version_id = ttk.Label(status_frame, text="N/A")
label_version_id.grid(row=2, column=1, sticky="w", padx=5, pady=5)
ttk.Label(status_frame, text="Started At:").grid(row=3, column=0, sticky="e", padx=5, pady=5)
label_started_at = ttk.Label(status_frame, text="N/A")
label_started_at.grid(row=3, column=1, sticky="w", padx=5, pady=5)
ttk.Label(status_frame, text="Stopped At:").grid(row=4, column=0, sticky="e", padx=5, pady=5)
label_stopped_at = ttk.Label(status_frame, text="N/A")
label_stopped_at.grid(row=4, column=1, sticky="w", padx=5, pady=5)
ttk.Label(status_frame, text="Stage:").grid(row=5, column=0, sticky="e", padx=5, pady=5)
label_stage = ttk.Label(status_frame, text="N/A")
label_stage.grid(row=5, column=1, sticky="w", padx=5, pady=5)
ttk.Label(status_frame, text="Updating:").grid(row=6, column=0, sticky="e", padx=5, pady=5)
label_updating = ttk.Label(status_frame, text="N/A")
label_updating.grid(row=6, column=1, sticky="w", padx=5, pady=5)
ttk.Label(status_frame, text="Time to Running:").grid(row=7, column=0, sticky="e", padx=5, pady=5)
label_time_to_running = ttk.Label(status_frame, text="N/A")
label_time_to_running.grid(row=7, column=1, sticky="w", padx=5, pady=5)