build-space / app.py
broadfield-dev's picture
Update app.py
ba9e0a6 verified
raw
history blame
7.7 kB
import gradio as gr
from app_logic import (
create_space,
view_space_files,
update_space_file,
load_token_from_image_and_set_env, # New import
KEYLOCK_DECODE_AVAILABLE # New import
)
# PIL Image for type hint if needed, though gr.Image handles it
# from PIL import Image
# Gradio interface
def main_ui():
with gr.Blocks(theme=gr.themes.Soft(primary_hue=gr.themes.colors.blue, secondary_hue=gr.themes.colors.sky), title="Hugging Face Space Builder") as demo:
gr.Markdown(
"""
# πŸ› οΈ Hugging Face Space Builder
Create, view, and update Hugging Face Spaces.
Provide your Hugging Face API token directly or load it from a steganographic image.
"""
)
# --- Authentication Section ---
with gr.Accordion("πŸ”‘ Authentication Methods", open=True):
gr.Markdown(
"""
**Token Precedence:**
1. If a token is successfully loaded from an image (and `HF_TOKEN` is set in the environment), it will be used.
2. Otherwise, the token entered in the 'Enter API Token Directly' textbox will be used.
3. If a system-wide `HF_TOKEN` environment variable was already set when this app started, it might also be used if methods 1 & 2 don't yield a token.
"""
)
gr.Markdown("---")
gr.Markdown("### Method 1: Enter API Token Directly")
api_token_ui_input = gr.Textbox( # Renamed to avoid confusion with resolved_api_token
label="Hugging Face API Token (hf_xxx)",
type="password",
placeholder="Enter your HF token OR load from image below",
info="Get from hf.co/settings/tokens. Needs 'write' access. This is used if image loading fails or is not used."
)
if KEYLOCK_DECODE_AVAILABLE:
gr.Markdown("---")
gr.Markdown("### Method 2: Load API Token from Steganographic Image")
with gr.Row():
keylock_image_input = gr.Image(
label="Stego Image (PNG containing HF_TOKEN)",
type="pil",
image_mode="RGBA", # << TRY ADDING THIS. Use "RGB" if your images are RGB.
# If you're unsure, you can omit it first to see if the debug saving helps.
# sources=["upload"],
)
keylock_password_input = gr.Textbox(
label="Image Password",
type="password",
placeholder="Password for image decryption"
)
keylock_decode_button = gr.Button("Load Token from Image", variant="secondary")
keylock_status_output = gr.Markdown(label="Image Decoding Status", value="Status will appear here...")
keylock_decode_button.click(
fn=load_token_from_image_and_set_env,
inputs=[keylock_image_input, keylock_password_input],
outputs=[keylock_status_output]
)
else:
gr.Markdown(
"_(Image decoding feature (KeyLock-Decode) is disabled as the library could not be imported.)_"
)
# --- Main Application Tabs ---
with gr.Tabs():
with gr.TabItem("πŸš€ Create New Space"):
# ... (rest of the Create Space UI, inputs will use api_token_ui_input)
with gr.Row():
space_name_create_input = gr.Textbox(label="Space Name", placeholder="my-awesome-app (no slashes)", scale=2)
owner_create_input = gr.Textbox(label="Owner Username/Org", placeholder="Leave blank for your HF username", scale=1)
sdk_create_input = gr.Dropdown(
label="Space SDK", choices=["gradio", "streamlit", "docker", "static"], value="gradio",
info="Select the type of Space."
)
markdown_input_create = gr.Textbox(
label="Markdown File Structure & Content",
placeholder="""Define files using '### File: path/to/file.ext'
followed by content, optionally in code blocks.
Example:
### File: app.py
# ```python
print("Hello World!")
# ```
""",
lines=15, interactive=True,
info="Define files using '### File: path/to/your/file.ext' followed by content."
)
create_btn = gr.Button("Create Space", variant="primary")
create_output_md = gr.Markdown(label="Result")
with gr.TabItem("πŸ“„ View Space Files"):
# ... (rest of the View Space Files UI, inputs will use api_token_ui_input)
with gr.Row():
space_name_view_input = gr.Textbox(label="Space Name", placeholder="my-existing-app (no slashes)", scale=2)
owner_view_input = gr.Textbox(label="Owner Username/Org", placeholder="Leave blank if it's your space", scale=1)
view_btn = gr.Button("List Files", variant="primary")
view_output_md = gr.Markdown(label="Files in Space")
with gr.TabItem("✏️ Update Space File"):
# ... (rest of the Update Space File UI, inputs will use api_token_ui_input)
with gr.Row():
space_name_update_input = gr.Textbox(label="Space Name", placeholder="my-target-app (no slashes)", scale=2)
owner_update_input = gr.Textbox(label="Owner Username/Org", placeholder="Leave blank if it's your space", scale=1)
file_path_update_input = gr.Textbox(
label="File Path in Repository", placeholder="e.g., app.py or src/utils.py",
info="The full path to the file within the space."
)
file_content_update_input = gr.Textbox(
label="New File Content", placeholder="Enter the complete new content for the file.",
lines=10, interactive=True
)
commit_message_update_input = gr.Textbox(
label="Commit Message", placeholder="e.g., Update app.py with new feature",
info="Describe the changes."
)
update_btn = gr.Button("Update File", variant="primary")
update_output_md = gr.Markdown(label="Result")
# Event handlers
# Pass the UI token input to all backend functions.
# The backend's _get_api_token helper will decide the actual token to use.
create_btn.click(
fn=create_space,
inputs=[api_token_ui_input, space_name_create_input, owner_create_input, sdk_create_input, markdown_input_create],
outputs=create_output_md,
)
view_btn.click(
fn=view_space_files,
inputs=[api_token_ui_input, space_name_view_input, owner_view_input],
outputs=view_output_md,
)
update_btn.click(
fn=update_space_file,
inputs=[
api_token_ui_input,
space_name_update_input,
owner_update_input,
file_path_update_input,
file_content_update_input,
commit_message_update_input,
],
outputs=update_output_md,
)
return demo
if __name__ == "__main__":
demo = main_ui()
demo.launch()