broadfield-dev commited on
Commit
40493b1
·
verified ·
1 Parent(s): 5c66b3e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -44
app.py CHANGED
@@ -12,7 +12,7 @@ logger = logging.getLogger(__name__)
12
  # CONFIGURATION & DATA HANDLING
13
  # ==============================================================================
14
 
15
- DEFAULT_CONFIG_FILE = "https://huggingface.co/spaces/Space-Share/bucket/raw/main/endpoints.json"
16
 
17
  def load_config_from_file(filepath: str) -> list:
18
  """Loads and validates the JSON configuration from a file."""
@@ -31,7 +31,6 @@ def load_config_from_file(filepath: str) -> list:
31
  return []
32
  except Exception as e:
33
  logger.error(f"Error loading config file {filepath}: {e}")
34
- # Return an empty list on error to prevent crashing the app
35
  return []
36
 
37
  def save_config_to_file(filepath: str, config_data: list) -> str:
@@ -47,8 +46,6 @@ def save_config_to_file(filepath: str, config_data: list) -> str:
47
  logger.error(status_msg)
48
  return status_msg
49
 
50
- # --- Load initial configuration from the file at startup ---
51
- # The 'config_state' will hold our list of dictionaries
52
  initial_config = load_config_from_file(DEFAULT_CONFIG_FILE)
53
 
54
  # ==============================================================================
@@ -62,21 +59,17 @@ def add_new_service(current_config: list, name: str, link: str, public_key: str)
62
 
63
  new_service = {"name": name, "link": link, "public_key": public_key}
64
 
65
- # Check for duplicate names
66
  if any(service['name'] == name for service in current_config):
67
  raise gr.Error(f"A service with the name '{name}' already exists. Please use a unique name.")
68
 
69
  updated_config = current_config + [new_service]
70
-
71
- # Update dropdown choices
72
  updated_choices = [service['name'] for service in updated_config]
73
 
74
- # Clear the input forms and provide success feedback
75
  status_update = f"✅ '{name}' added. You can now use it in the 'Create Image' tab. Click 'Save to File' to make it permanent."
76
  return updated_config, gr.Dropdown(choices=updated_choices), status_update, "", "", ""
77
 
78
  def generate_image(selected_service_name: str, secret_data_str: str, current_config: list):
79
- """The main image creation function, now takes the config state as an input."""
80
  if not all([selected_service_name, secret_data_str]):
81
  raise gr.Error("A selected service and secret data are both required.")
82
 
@@ -85,6 +78,7 @@ def generate_image(selected_service_name: str, secret_data_str: str, current_con
85
  if not public_key:
86
  raise gr.Error(f"Could not find the service '{selected_service_name}'. Please check the configuration.")
87
 
 
88
  encrypted_image = core.create_encrypted_image(secret_data_str, public_key)
89
 
90
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
@@ -99,18 +93,17 @@ def generate_image(selected_service_name: str, secret_data_str: str, current_con
99
  def get_endpoints_json() -> str:
100
  """Reads and returns the content of endpoints.json as a string."""
101
  try:
102
- with open("endpoints.json", "r") as f:
103
  return f.read()
104
  except Exception as e:
105
- logger.error(f"Could not read endpoints.json: {e}")
106
- raise gr.Error("Server could not read its endpoints.json configuration file.")
 
107
  # ==============================================================================
108
  # GRADIO INTERFACE
109
  # ==============================================================================
110
 
111
  with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock Image Creator") as demo:
112
- # This gr.State object holds the current configuration (list of dicts)
113
- # It's initialized with the data loaded from endpoints.json
114
  config_state = gr.State(initial_config)
115
 
116
  gr.Markdown("# 🏭 KeyLock Image Creator")
@@ -118,6 +111,7 @@ with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock Image Creator") as demo:
118
 
119
  with gr.Tabs() as tabs:
120
  with gr.TabItem("Create Image", id=0):
 
121
  with gr.Row():
122
  with gr.Column(scale=2):
123
  gr.Markdown("### 1. Select Decoder Service")
@@ -141,62 +135,65 @@ with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock Image Creator") as demo:
141
  download_output = gr.File(label="Download Image")
142
 
143
  with gr.TabItem("Manage Configuration", id=1):
 
144
  gr.Markdown("## Decoder Service Configuration")
145
  gr.Markdown("View the current configuration, add new services, and save your changes.")
146
-
147
  with gr.Row():
148
  with gr.Column(scale=2):
149
  gr.Markdown("### Current Configuration")
150
- config_display = gr.JSON(value=initial_config, label="Loaded from endpoints.json")
151
-
152
  with gr.Column(scale=1):
153
  gr.Markdown("### Add a New Service")
154
  new_service_name = gr.Textbox(label="Service Name", placeholder="e.g., My Production API")
155
  new_service_link = gr.Textbox(label="Service Link", placeholder="https://huggingface.co/...")
156
  new_service_key = gr.Textbox(label="Public Key (PEM Format)", lines=5, placeholder="-----BEGIN PUBLIC KEY-----...")
157
  add_service_button = gr.Button("Add Service to Current Session")
158
-
159
  gr.Markdown("---")
160
  save_config_button = gr.Button("Save Current Configuration to File", variant="secondary")
161
  config_status_output = gr.Textbox(label="Configuration Status", interactive=False)
162
- with gr.Row(visible=False):
163
- # Original API for creating images
164
- api_secret_input = gr.Textbox()
165
- api_pubkey_input = gr.Textbox()
166
- api_image_output = gr.Image(type="pil")
167
- gr.Interface(
168
- fn=create_carrier_image,
169
- inputs=[api_secret_input, api_pubkey_input],
170
- outputs=api_image_output,
171
- api_name="create_image"
172
- )
173
-
174
- # NEW API to get the endpoint list
175
- api_get_endpoints_output = gr.Textbox()
176
- gr.Interface(
177
- fn=get_endpoints_json,
178
- inputs=[],
179
- outputs=api_get_endpoints_output,
180
- api_name="get_endpoints" # This creates /run/get_endpoints
181
- )
 
 
 
 
 
 
 
 
 
182
 
183
  # --- Interactivity ---
184
 
185
- # Main image creation logic
186
  create_button.click(
187
  fn=generate_image,
188
  inputs=[service_dropdown, secret_data, config_state],
189
  outputs=[image_output, download_output, status_output]
190
  )
191
 
192
- # Logic for the "Manage Configuration" tab
193
  add_service_button.click(
194
  fn=add_new_service,
195
  inputs=[config_state, new_service_name, new_service_link, new_service_key],
196
- # Outputs: update the state, the dropdown, the status, and clear the form fields
197
  outputs=[config_state, service_dropdown, config_status_output, new_service_name, new_service_link, new_service_key]
198
  ).then(
199
- # After updating the state, also update the JSON display to reflect the change
200
  lambda state: state,
201
  inputs=[config_state],
202
  outputs=[config_display]
@@ -208,8 +205,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock Image Creator") as demo:
208
  outputs=[config_status_output]
209
  )
210
 
211
- # When the configuration state changes (e.g., after adding a service),
212
- # update the JSON display on the config tab. This keeps the UI in sync.
213
  config_state.change(
214
  fn=lambda state: state,
215
  inputs=[config_state],
 
12
  # CONFIGURATION & DATA HANDLING
13
  # ==============================================================================
14
 
15
+ DEFAULT_CONFIG_FILE = "endpoints.json"
16
 
17
  def load_config_from_file(filepath: str) -> list:
18
  """Loads and validates the JSON configuration from a file."""
 
31
  return []
32
  except Exception as e:
33
  logger.error(f"Error loading config file {filepath}: {e}")
 
34
  return []
35
 
36
  def save_config_to_file(filepath: str, config_data: list) -> str:
 
46
  logger.error(status_msg)
47
  return status_msg
48
 
 
 
49
  initial_config = load_config_from_file(DEFAULT_CONFIG_FILE)
50
 
51
  # ==============================================================================
 
59
 
60
  new_service = {"name": name, "link": link, "public_key": public_key}
61
 
 
62
  if any(service['name'] == name for service in current_config):
63
  raise gr.Error(f"A service with the name '{name}' already exists. Please use a unique name.")
64
 
65
  updated_config = current_config + [new_service]
 
 
66
  updated_choices = [service['name'] for service in updated_config]
67
 
 
68
  status_update = f"✅ '{name}' added. You can now use it in the 'Create Image' tab. Click 'Save to File' to make it permanent."
69
  return updated_config, gr.Dropdown(choices=updated_choices), status_update, "", "", ""
70
 
71
  def generate_image(selected_service_name: str, secret_data_str: str, current_config: list):
72
+ """The main image creation function for the UI."""
73
  if not all([selected_service_name, secret_data_str]):
74
  raise gr.Error("A selected service and secret data are both required.")
75
 
 
78
  if not public_key:
79
  raise gr.Error(f"Could not find the service '{selected_service_name}'. Please check the configuration.")
80
 
81
+ # This call is correct and should not cause an error
82
  encrypted_image = core.create_encrypted_image(secret_data_str, public_key)
83
 
84
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
 
93
  def get_endpoints_json() -> str:
94
  """Reads and returns the content of endpoints.json as a string."""
95
  try:
96
+ with open(DEFAULT_CONFIG_FILE, "r") as f:
97
  return f.read()
98
  except Exception as e:
99
+ logger.error(f"Could not read {DEFAULT_CONFIG_FILE}: {e}")
100
+ raise gr.Error(f"Server could not read its {DEFAULT_CONFIG_FILE} configuration file.")
101
+
102
  # ==============================================================================
103
  # GRADIO INTERFACE
104
  # ==============================================================================
105
 
106
  with gr.Blocks(theme=gr.themes.Soft(), title="KeyLock Image Creator") as demo:
 
 
107
  config_state = gr.State(initial_config)
108
 
109
  gr.Markdown("# 🏭 KeyLock Image Creator")
 
111
 
112
  with gr.Tabs() as tabs:
113
  with gr.TabItem("Create Image", id=0):
114
+ # ... (Your existing UI code is fine, no changes needed here) ...
115
  with gr.Row():
116
  with gr.Column(scale=2):
117
  gr.Markdown("### 1. Select Decoder Service")
 
135
  download_output = gr.File(label="Download Image")
136
 
137
  with gr.TabItem("Manage Configuration", id=1):
138
+ # ... (Your existing config management code is fine, no changes needed here) ...
139
  gr.Markdown("## Decoder Service Configuration")
140
  gr.Markdown("View the current configuration, add new services, and save your changes.")
 
141
  with gr.Row():
142
  with gr.Column(scale=2):
143
  gr.Markdown("### Current Configuration")
144
+ config_display = gr.JSON(value=initial_config, label=f"Loaded from {DEFAULT_CONFIG_FILE}")
 
145
  with gr.Column(scale=1):
146
  gr.Markdown("### Add a New Service")
147
  new_service_name = gr.Textbox(label="Service Name", placeholder="e.g., My Production API")
148
  new_service_link = gr.Textbox(label="Service Link", placeholder="https://huggingface.co/...")
149
  new_service_key = gr.Textbox(label="Public Key (PEM Format)", lines=5, placeholder="-----BEGIN PUBLIC KEY-----...")
150
  add_service_button = gr.Button("Add Service to Current Session")
 
151
  gr.Markdown("---")
152
  save_config_button = gr.Button("Save Current Configuration to File", variant="secondary")
153
  config_status_output = gr.Textbox(label="Configuration Status", interactive=False)
154
+
155
+ # FIX: Define API endpoints clearly instead of using a hidden row
156
+ with gr.TabItem("API", id=2):
157
+ gr.Markdown("## API Endpoints")
158
+ gr.Markdown("Use these endpoints for programmatic access.")
159
+
160
+ # API for creating an image
161
+ gr.Interface(
162
+ # By passing core.create_encrypted_image directly, we ensure it runs in the correct scope
163
+ fn=core.create_encrypted_image,
164
+ inputs=[
165
+ gr.Textbox(label="Secret Data", info="Key-value pairs, one per line."),
166
+ gr.Textbox(label="Public Key PEM", info="The full PEM-formatted public key.")
167
+ ],
168
+ outputs=gr.Image(type="pil", label="Encrypted Image"),
169
+ title="Image Creation API",
170
+ description="Creates an encrypted image from secret data and a public key. Use via the `/api/create_image/` route.",
171
+ api_name="create_image"
172
+ )
173
+
174
+ # API to get the endpoint list
175
+ gr.Interface(
176
+ fn=get_endpoints_json,
177
+ inputs=[],
178
+ outputs=gr.Textbox(label="Endpoint Configuration"),
179
+ title="Get Endpoints API",
180
+ description=f"Retrieves the contents of `{DEFAULT_CONFIG_FILE}`. Use via the `/api/get_endpoints/` route.",
181
+ api_name="get_endpoints"
182
+ )
183
 
184
  # --- Interactivity ---
185
 
 
186
  create_button.click(
187
  fn=generate_image,
188
  inputs=[service_dropdown, secret_data, config_state],
189
  outputs=[image_output, download_output, status_output]
190
  )
191
 
 
192
  add_service_button.click(
193
  fn=add_new_service,
194
  inputs=[config_state, new_service_name, new_service_link, new_service_key],
 
195
  outputs=[config_state, service_dropdown, config_status_output, new_service_name, new_service_link, new_service_key]
196
  ).then(
 
197
  lambda state: state,
198
  inputs=[config_state],
199
  outputs=[config_display]
 
205
  outputs=[config_status_output]
206
  )
207
 
 
 
208
  config_state.change(
209
  fn=lambda state: state,
210
  inputs=[config_state],