import gradio as gr import requests import json # Zu.lk API Base URL API_BASE_URL = "https://api.zu.lk" def parse_auth_header(auth_header): """Parse authorization header to extract API key and secret""" if not auth_header or auth_header.strip() == "": return None, None # Format: "Bearer OfNJsl3lmt:$2b$10$qf2ZMINlvw" try: # Split by space and get the second part (after "Bearer ") parts = auth_header.strip().split(" ", 1) if len(parts) != 2 or parts[0] != "Bearer": return None, None # Split the credentials by colon credentials = parts[1] api_key, api_secret = credentials.split(":", 1) return api_key, api_secret except ValueError: return None, None def make_api_request(endpoint, method="GET", data=None, api_key=None, api_secret=None): """Make authenticated request to Zu.lk API""" if not api_key or not api_secret: return {"error": "Invalid authentication credentials"} headers = { "X-API-KEY": api_key, "X-API-Secret": api_secret, "Content-Type": "application/json" } url = f"{API_BASE_URL}{endpoint}" try: if method == "GET": response = requests.get(url, headers=headers) elif method == "POST": response = requests.post(url, headers=headers, json=data) elif method == "PUT": response = requests.put(url, headers=headers, json=data) elif method == "DELETE": response = requests.delete(url, headers=headers) else: return {"error": f"Unsupported method: {method}"} return response.json() except requests.exceptions.RequestException as e: return {"error": f"Request failed: {str(e)}"} except json.JSONDecodeError: return {"error": "Invalid JSON response"} def get_organizations(request: gr.Request): """Get user organizations""" api_key, api_secret = parse_auth_header(request.headers.get('authorization', '')) if not api_key or not api_secret: return "Error: Authorization is required (format: Bearer api_key:api_secret)" result = make_api_request("/v1/organizations", api_key=api_key, api_secret=api_secret) return json.dumps(result, indent=2) def create_link(org_id, url, custom_key, length, request: gr.Request): """Create a new short link""" api_key, api_secret = parse_auth_header(request.headers.get('authorization', '')) if not api_key or not api_secret: return "Error: Authorization is required (format: Bearer api_key:api_secret)" if not org_id or not url: return "Error: Organization ID and URL are required" data = {"url": url} if custom_key: data["key"] = custom_key if length and length > 0: data["length"] = length result = make_api_request(f"/v1/organizations/{org_id}/links", method="POST", data=data, api_key=api_key, api_secret=api_secret) return json.dumps(result, indent=2) def get_org_links(org_id, request: gr.Request): """Get all links for an organization""" api_key, api_secret = parse_auth_header(request.headers.get('authorization', '')) if not api_key or not api_secret: return "Error: Authorization is required (format: Bearer api_key:api_secret)" if not org_id: return "Error: Organization ID is required" result = make_api_request(f"/v1/organizations/{org_id}/links", api_key=api_key, api_secret=api_secret) return json.dumps(result, indent=2) def get_analytics(org_id, date_from, date_to, interval, request: gr.Request): """Get organization analytics""" api_key, api_secret = parse_auth_header(request.headers.get('authorization', '')) if not api_key or not api_secret: return "Error: Authorization is required (format: Bearer api_key:api_secret)" if not org_id: return "Error: Organization ID is required" params = [] if date_from: params.append(f"date_from={date_from}") if date_to: params.append(f"date_to={date_to}") if interval: params.append(f"interval={interval}") query_string = "&".join(params) endpoint = f"/v1/organizations/{org_id}/analytics/clicks" if query_string: endpoint += f"?{query_string}" result = make_api_request(endpoint, api_key=api_key, api_secret=api_secret) return json.dumps(result, indent=2) def update_link(org_id, link_id, new_url, new_key, request: gr.Request): """Update an existing link""" api_key, api_secret = parse_auth_header(request.headers.get('authorization', '')) if not api_key or not api_secret: return "Error: Authorization is required (format: Bearer api_key:api_secret)" if not org_id or not link_id or not new_url or not new_key: return "Error: Organization ID, Link ID, URL, and Key are required" data = {"url": new_url, "key": new_key} result = make_api_request(f"/v1/organizations/{org_id}/links/{link_id}", method="PUT", data=data, api_key=api_key, api_secret=api_secret) return json.dumps(result, indent=2) # Create Gradio interface with tabs with gr.Blocks(title="Zu.lk API Client") as demo: gr.Markdown("# Zu.lk API Client") gr.Markdown("Authorization format: `Bearer api_key:api_secret`") with gr.Tab("Organizations"): with gr.Row(): org_btn = gr.Button("Get My Organizations") org_output = gr.Textbox(label="Organizations", lines=10) org_btn.click(get_organizations, outputs=org_output) with gr.Tab("Create Link"): with gr.Column(): create_org_id = gr.Textbox(label="Organization ID", placeholder="1") create_url = gr.Textbox(label="URL to Shorten", placeholder="https://example.com") create_key = gr.Textbox(label="Custom Key (optional)", placeholder="my-link") create_length = gr.Number(label="Key Length (3-10)", value=6, minimum=3, maximum=10) create_btn = gr.Button("Create Link") create_output = gr.Textbox(label="Result", lines=8) create_btn.click(create_link, inputs=[create_org_id, create_url, create_key, create_length], outputs=create_output) with gr.Tab("Manage Links"): with gr.Column(): links_org_id = gr.Textbox(label="Organization ID", placeholder="1") get_links_btn = gr.Button("Get All Links") links_output = gr.Textbox(label="Links", lines=10) get_links_btn.click(get_org_links, inputs=[links_org_id], outputs=links_output) with gr.Tab("Update Link"): with gr.Column(): update_org_id = gr.Textbox(label="Organization ID", placeholder="1") update_link_id = gr.Textbox(label="Link ID", placeholder="1") update_url = gr.Textbox(label="New URL", placeholder="https://updated-example.com") update_key = gr.Textbox(label="New Key", placeholder="updated-key") update_btn = gr.Button("Update Link") update_output = gr.Textbox(label="Result", lines=8) update_btn.click(update_link, inputs=[update_org_id, update_link_id, update_url, update_key], outputs=update_output) with gr.Tab("Analytics"): with gr.Column(): analytics_org_id = gr.Textbox(label="Organization ID", placeholder="1") analytics_from = gr.Textbox(label="Date From (optional)", placeholder="-7d") analytics_to = gr.Textbox(label="Date To (optional)", placeholder="today") analytics_interval = gr.Textbox(label="Interval (optional)", placeholder="day") analytics_btn = gr.Button("Get Analytics") analytics_output = gr.Textbox(label="Analytics", lines=12) analytics_btn.click(get_analytics, inputs=[analytics_org_id, analytics_from, analytics_to, analytics_interval], outputs=analytics_output) if __name__ == "__main__": demo.launch(mcp_server=True, share=True)