Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -4,33 +4,31 @@ import base64
|
|
4 |
import json
|
5 |
from PIL import Image
|
6 |
import io
|
|
|
7 |
|
8 |
-
#
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
# This is the full URL to the MCP (base64) endpoint of your SERVER Space.
|
13 |
-
# Replace this with the URL of your deployed Python API server.
|
14 |
-
DECODER_API_ENDPOINT = "https://https://broadfield-dev-keylock-auth.hf.space/run/mcp_decode"
|
15 |
-
# Example: "https://broadfield-dev-keylock-api-python.hf.space/run/mcp_decode"
|
16 |
-
|
17 |
-
# Link to the server space for user reference
|
18 |
-
SERVER_SPACE_URL = "https://huggingface.co/spaces/broadfield-dev/keylock-auth"
|
19 |
-
# Example: "https://huggingface.co/spaces/broadfield-dev/KeyLock-API-Python"
|
20 |
-
|
21 |
|
22 |
# ==============================================================================
|
23 |
# API CALL LOGIC
|
24 |
# ==============================================================================
|
25 |
|
26 |
-
def call_decoder_api(image: Image.Image) -> dict:
|
27 |
"""
|
28 |
-
Takes a PIL image, converts it to base64, sends it to the
|
29 |
and returns the decrypted JSON data.
|
30 |
"""
|
|
|
|
|
|
|
31 |
if image is None:
|
32 |
raise gr.Error("Please upload an encrypted image.")
|
33 |
|
|
|
|
|
|
|
|
|
34 |
try:
|
35 |
# 1. Convert the PIL Image to a base64 string
|
36 |
buffer = io.BytesIO()
|
@@ -39,7 +37,7 @@ def call_decoder_api(image: Image.Image) -> dict:
|
|
39 |
image_base64 = base64.b64encode(image_bytes).decode('utf-8')
|
40 |
|
41 |
# 2. Prepare the JSON payload for the Gradio API
|
42 |
-
# Gradio's /run/predict endpoint expects this specific structure
|
43 |
payload = {
|
44 |
"data": [
|
45 |
image_base64
|
@@ -48,28 +46,28 @@ def call_decoder_api(image: Image.Image) -> dict:
|
|
48 |
|
49 |
# 3. Make the POST request to the server API
|
50 |
headers = {"Content-Type": "application/json"}
|
51 |
-
response = requests.post(
|
52 |
|
53 |
-
# Raise an error for bad status codes (4xx or 5xx)
|
54 |
-
response.raise_for_status()
|
55 |
-
|
56 |
# 4. Process the response
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
|
|
65 |
else:
|
66 |
-
|
|
|
|
|
67 |
|
68 |
except requests.exceptions.RequestException as e:
|
69 |
logger.error(f"Network error calling API: {e}")
|
70 |
-
raise gr.Error(f"Could not connect to the
|
71 |
except Exception as e:
|
72 |
-
logger.error(f"An unexpected error occurred: {e}")
|
73 |
raise gr.Error(f"An unexpected error occurred: {e}")
|
74 |
|
75 |
# ==============================================================================
|
@@ -77,33 +75,37 @@ def call_decoder_api(image: Image.Image) -> dict:
|
|
77 |
# ==============================================================================
|
78 |
|
79 |
with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock API Client") as demo:
|
80 |
-
gr.Markdown(
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
""")
|
86 |
|
87 |
with gr.Row():
|
88 |
with gr.Column(scale=1):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
image_input = gr.Image(
|
90 |
type="pil",
|
91 |
label="Upload Encrypted PNG Image",
|
92 |
sources=["upload", "clipboard"]
|
93 |
)
|
94 |
submit_button = gr.Button("Decrypt via API", variant="primary")
|
95 |
-
|
96 |
-
gr.Markdown("---")
|
97 |
-
gr.Markdown(f"This client sends requests to the following API endpoint: `{DECODER_API_ENDPOINT}`")
|
98 |
|
99 |
with gr.Column(scale=2):
|
100 |
-
gr.Markdown("
|
101 |
json_output = gr.JSON(label="Result from Server")
|
102 |
|
103 |
# Connect the UI components to the API call function
|
104 |
submit_button.click(
|
105 |
fn=call_decoder_api,
|
106 |
-
inputs=[image_input],
|
107 |
outputs=[json_output]
|
108 |
)
|
109 |
|
|
|
4 |
import json
|
5 |
from PIL import Image
|
6 |
import io
|
7 |
+
import logging
|
8 |
|
9 |
+
# --- Configure Logging ---
|
10 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
11 |
+
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
# ==============================================================================
|
14 |
# API CALL LOGIC
|
15 |
# ==============================================================================
|
16 |
|
17 |
+
def call_decoder_api(server_base_url: str, image: Image.Image) -> dict:
|
18 |
"""
|
19 |
+
Takes a PIL image, converts it to base64, sends it to the specified server API,
|
20 |
and returns the decrypted JSON data.
|
21 |
"""
|
22 |
+
# --- Input Validation ---
|
23 |
+
if not server_base_url or "hf.space" not in server_base_url:
|
24 |
+
raise gr.Error("Please provide a valid Hugging Face Space URL for the server API.")
|
25 |
if image is None:
|
26 |
raise gr.Error("Please upload an encrypted image.")
|
27 |
|
28 |
+
# The specific endpoint for our Gradio API
|
29 |
+
api_endpoint = f"{server_base_url.strip('/')}/run/mcp_decode"
|
30 |
+
logger.info(f"Attempting to call API at: {api_endpoint}")
|
31 |
+
|
32 |
try:
|
33 |
# 1. Convert the PIL Image to a base64 string
|
34 |
buffer = io.BytesIO()
|
|
|
37 |
image_base64 = base64.b64encode(image_bytes).decode('utf-8')
|
38 |
|
39 |
# 2. Prepare the JSON payload for the Gradio API
|
40 |
+
# Gradio's /run/predict endpoint expects this specific structure: {"data": [input1, input2, ...]}
|
41 |
payload = {
|
42 |
"data": [
|
43 |
image_base64
|
|
|
46 |
|
47 |
# 3. Make the POST request to the server API
|
48 |
headers = {"Content-Type": "application/json"}
|
49 |
+
response = requests.post(api_endpoint, headers=headers, json=payload, timeout=30)
|
50 |
|
|
|
|
|
|
|
51 |
# 4. Process the response
|
52 |
+
if response.status_code == 200:
|
53 |
+
response_json = response.json()
|
54 |
+
if "data" in response_json and len(response_json["data"]) > 0:
|
55 |
+
# Gradio API wraps results in a "data" list. The actual result is the first element.
|
56 |
+
return response_json["data"][0]
|
57 |
+
elif "error" in response_json:
|
58 |
+
raise gr.Error(f"API returned an error: {response_json['error']}")
|
59 |
+
else:
|
60 |
+
raise gr.Error(f"API returned an unexpected response format: {response_json}")
|
61 |
else:
|
62 |
+
# Handle non-200 responses with more detail
|
63 |
+
error_text = response.text
|
64 |
+
raise gr.Error(f"API Error (Status {response.status_code}): {error_text}")
|
65 |
|
66 |
except requests.exceptions.RequestException as e:
|
67 |
logger.error(f"Network error calling API: {e}")
|
68 |
+
raise gr.Error(f"Could not connect to the API. Check the URL and server status. Error: {e}")
|
69 |
except Exception as e:
|
70 |
+
logger.error(f"An unexpected error occurred: {e}", exc_info=True)
|
71 |
raise gr.Error(f"An unexpected error occurred: {e}")
|
72 |
|
73 |
# ==============================================================================
|
|
|
75 |
# ==============================================================================
|
76 |
|
77 |
with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock API Client") as demo:
|
78 |
+
gr.Markdown("# π KeyLock API Client")
|
79 |
+
gr.Markdown(
|
80 |
+
"This is a user interface for the **Secure Decoder API**. It sends an encrypted image "
|
81 |
+
"to the server for decryption."
|
82 |
+
)
|
|
|
83 |
|
84 |
with gr.Row():
|
85 |
with gr.Column(scale=1):
|
86 |
+
gr.Markdown("### 1. Configure Server URL")
|
87 |
+
server_url_input = gr.Textbox(
|
88 |
+
label="Decoder API Server URL",
|
89 |
+
placeholder="Enter the direct URL of your Python server space...",
|
90 |
+
info="Example: https://your-name-keylock-api-python.hf.space"
|
91 |
+
)
|
92 |
+
|
93 |
+
gr.Markdown("### 2. Upload Encrypted Image")
|
94 |
image_input = gr.Image(
|
95 |
type="pil",
|
96 |
label="Upload Encrypted PNG Image",
|
97 |
sources=["upload", "clipboard"]
|
98 |
)
|
99 |
submit_button = gr.Button("Decrypt via API", variant="primary")
|
|
|
|
|
|
|
100 |
|
101 |
with gr.Column(scale=2):
|
102 |
+
gr.Markdown("### 3. Decrypted Data")
|
103 |
json_output = gr.JSON(label="Result from Server")
|
104 |
|
105 |
# Connect the UI components to the API call function
|
106 |
submit_button.click(
|
107 |
fn=call_decoder_api,
|
108 |
+
inputs=[server_url_input, image_input],
|
109 |
outputs=[json_output]
|
110 |
)
|
111 |
|