Zulk / app.py
Milindu Kumarage
rename file
87f782f
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)