broadfield-dev commited on
Commit
c1a64ad
·
verified ·
1 Parent(s): e160fa0

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +144 -0
app.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import logging
4
+ import tempfile
5
+ import core # Import our new core module
6
+
7
+ # --- Configure Logging ---
8
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
9
+ logger = logging.getLogger(__name__)
10
+
11
+ # ==============================================================================
12
+ # UI HELPER FUNCTIONS
13
+ # ==============================================================================
14
+
15
+ def update_service_dropdown(json_config_string: str):
16
+ """Parses the JSON config and updates the dropdown choices."""
17
+ if not json_config_string.strip():
18
+ return gr.Dropdown(choices=[], value=None, label="Decoder Service (Paste JSON config)"), "Status: Waiting for JSON configuration."
19
+
20
+ try:
21
+ endpoints = json.loads(json_config_string)
22
+ if not isinstance(endpoints, list):
23
+ raise TypeError("JSON root must be a list of objects.")
24
+
25
+ service_names = []
26
+ for service in endpoints:
27
+ # Validate that each service has the required keys
28
+ if not all(k in service for k in ("name", "link", "public_key")):
29
+ raise ValueError("Each service object must contain 'name', 'link', and 'public_key' keys.")
30
+ service_names.append(service["name"])
31
+
32
+ # If valid, update the dropdown with the new choices
33
+ if not service_names:
34
+ return gr.Dropdown(choices=[], value=None, label="Decoder Service (No services found)"), "Status: JSON parsed, but no services were found."
35
+
36
+ logger.info(f"Updated dropdown with services: {service_names}")
37
+ return gr.Dropdown(choices=service_names, value=service_names[0], label="Select Decoder Service"), f"Status: Loaded {len(service_names)} services. '{service_names[0]}' selected."
38
+ except (json.JSONDecodeError, TypeError, ValueError) as e:
39
+ logger.error(f"JSON parsing error: {e}")
40
+ return gr.Dropdown(choices=[], value=None, label="Decoder Service (Invalid JSON)"), f"Status: Error parsing JSON - {e}"
41
+
42
+ def generate_image(json_config_string: str, selected_service_name: str, secret_data_str: str):
43
+ """
44
+ The main function called by the 'Create' button.
45
+ It finds the selected service's public key and calls the core encryption logic.
46
+ """
47
+ if not all([json_config_string, selected_service_name, secret_data_str]):
48
+ raise gr.Error("Configuration, a selected service, and secret data are all required.")
49
+
50
+ try:
51
+ endpoints = json.loads(json_config_string)
52
+
53
+ # Find the public key for the selected service
54
+ public_key = None
55
+ for service in endpoints:
56
+ if service.get("name") == selected_service_name:
57
+ public_key = service.get("public_key")
58
+ break
59
+
60
+ if not public_key:
61
+ raise gr.Error(f"Could not find the service '{selected_service_name}' in the provided JSON.")
62
+
63
+ # Call the core function to do the heavy lifting
64
+ encrypted_image = core.create_encrypted_image(secret_data_str, public_key)
65
+
66
+ # Save to a temporary file for download
67
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
68
+ encrypted_image.save(tmp_file.name)
69
+ logger.info(f"Generated image saved to temporary file: {tmp_file.name}")
70
+ return encrypted_image, tmp_file.name, f"✅ Success! Image created for '{selected_service_name}'. You can now download it."
71
+
72
+ except Exception as e:
73
+ logger.error(f"Image creation failed: {e}", exc_info=True)
74
+ # Return empty outputs on failure
75
+ return None, None, f"❌ Error: {e}"
76
+
77
+ # ==============================================================================
78
+ # GRADIO INTERFACE
79
+ # ==============================================================================
80
+
81
+ # Example JSON for the user to copy
82
+ EXAMPLE_JSON = """
83
+ [
84
+ {
85
+ "name": "My Python Decoder API",
86
+ "link": "https://huggingface.co/spaces/YOUR_USERNAME/KeyLock-API-Python",
87
+ "public_key": "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy2sWjB1iQ3vK03U7e/9E\\nO6J1K/s0tBq4Pz8F3r9/i8s7t9R1p8Z4Y6h4f4O7w9p9Z0c8t7m4J1e9g7K9m6f3\\nR1k3y7v1w0l7z6s5v2l8l4t9v8z7y6t5k2x1c9v7z3k1y9w8r5t3s1v9a8d7g6f5\\ne4d3c2b1a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2\\nc1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0\\na9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8\\ne7d6\\n-----END PUBLIC KEY-----"
88
+ }
89
+ ]
90
+ """
91
+
92
+ with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock Image Creator") as demo:
93
+ gr.Markdown("# 🏭 KeyLock Image Creator")
94
+ gr.Markdown("Create secure, encrypted images by providing a JSON configuration of decoder endpoints and your secret data.")
95
+
96
+ with gr.Row():
97
+ with gr.Column(scale=2):
98
+ gr.Markdown("### 1. Configure Decoder Services")
99
+ json_config = gr.Textbox(
100
+ lines=10,
101
+ label="JSON Configuration",
102
+ placeholder="Paste your JSON list of services here...",
103
+ info="Each service must have a 'name', 'link', and 'public_key'."
104
+ )
105
+ gr.Markdown("### 2. Enter Your Secret Data")
106
+ secret_data = gr.Textbox(
107
+ lines=5,
108
+ label="Secret Data (Key-Value Pairs)",
109
+ placeholder="USERNAME: user@example.com\nAPI_KEY: sk-12345..."
110
+ )
111
+
112
+ with gr.Column(scale=1):
113
+ gr.Markdown("### 3. Select Service and Create")
114
+ service_dropdown = gr.Dropdown(
115
+ label="Decoder Service (Paste JSON config)",
116
+ choices=[],
117
+ interactive=True
118
+ )
119
+ create_button = gr.Button("Create Encrypted Image", variant="primary")
120
+
121
+ status_output = gr.Textbox(label="Status", interactive=False)
122
+ image_output = gr.Image(label="Generated Image", type="pil")
123
+ download_output = gr.File(label="Download Image")
124
+
125
+ # --- Interactivity ---
126
+ # When the JSON config textbox changes, update the dropdown menu
127
+ json_config.change(
128
+ fn=update_service_dropdown,
129
+ inputs=[json_config],
130
+ outputs=[service_dropdown, status_output]
131
+ )
132
+
133
+ # When the create button is clicked, run the main generation function
134
+ create_button.click(
135
+ fn=generate_image,
136
+ inputs=[json_config, service_dropdown, secret_data],
137
+ outputs=[image_output, download_output, status_output]
138
+ )
139
+
140
+ with gr.Accordion("Example JSON Configuration", open=False):
141
+ gr.Code(value=EXAMPLE_JSON, language="json")
142
+
143
+ if __name__ == "__main__":
144
+ demo.launch()