import gradio as gr
import boto3
import os
import shutil
import uuid
custom_css = """
footer {display: none !important;}
.gradio-container {min-height: 0px !important;}
#download-header {text-align: center; margin-bottom: 20px;}
"""
# --- CONFIGURATION ---
STORAGE_PATH = "/data"
APP_TOKEN = os.environ.get("APP_TOKEN")
# Setup Amazon SES
ses = boto3.client(
'ses',
aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID"),
aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY"),
region_name=os.environ.get("AWS_REGION")
)
def process_submission(name, company, message, files, url_token):
if url_token != APP_TOKEN:
return gr.update(visible=True, value="### ❌ Access Denied: Invalid Security Token")
if not files:
return gr.update(visible=True, value="### ⚠️ Please select at least one file to upload.")
job_id = str(uuid.uuid4())[:8]
job_folder = os.path.join(STORAGE_PATH, job_id)
os.makedirs(job_folder, exist_ok=True)
space_id = os.environ.get('SPACE_ID', 'vocalmetric/storage')
direct_url = f"https://{space_id.replace('/', '-')}.hf.space"
file_links = []
for file in files:
file_name = os.path.basename(file.name)
dest_path = os.path.join(job_folder, file_name)
shutil.copy(file.name, dest_path)
proxy_link = f"{direct_url}?job={job_id}&file={file_name}"
file_links.append(f"
{file_name}")
email_body = f"""
Vocalmetric: New Evidence Submission
Name: {name}
Company: {company}
Instructions:
{message}
Click to Download Files:
"""
try:
ses.send_email(
Source='noreply@songevolution.com',
Destination={'ToAddresses': ['ettiennelane@gmail.com', 'riaanrsteyn@gmail.com']},
Message={
'Subject': {'Data': f'Vocalmetric: New Submission from {name}'},
'Body': {'Html': {'Data': email_body}}
}
)
except Exception as e:
return gr.update(visible=True, value=f"### ❌ Email Error: {str(e)}")
return gr.update(visible=True, value="### ✅ Success! Files securely uploaded.")
# --- UI HELPER FUNCTIONS ---
def disable_ui():
# Instantly disable the button and show a loading message
return gr.update(interactive=False, value="Sending..."), gr.update(visible=True, value="### ⏳ Encrypting and sending. Please wait...")
def enable_ui():
# Re-enable the button after the process finishes
return gr.update(interactive=True, value="Send Files")
# --- USER INTERFACE ---
theme = gr.themes.Soft(primary_hue="blue", neutral_hue="slate").set(
body_background_fill="#0f172a",
block_background_fill="#1e293b",
block_label_text_color="#94a3b8",
button_primary_background_fill="#3b82f6"
)
with gr.Blocks() as demo:
url_token = gr.State()
# Download Screen (Hidden by default)
with gr.Column(visible=False) as download_ui:
gr.Markdown("## 📥 Download Forensic Evidence", elem_id="download-header")
gr.Markdown("This file was securely retrieved from the Vocalmetric private bucket.")
file_display = gr.File(label="Ready for Download")
back_btn = gr.Button("Return to Upload Page", variant="secondary", size="sm")
# Upload Screen (Shown by default)
with gr.Column(visible=True) as upload_ui:
gr.Markdown("# Evidence Upload")
with gr.Row():
name = gr.Textbox(label="Your Name")
company = gr.Textbox(label="Company Name")
message = gr.TextArea(label="Forensic Analysis Instructions", lines=4)
file_input = gr.File(label="Select Audio Files", file_count="multiple")
send_btn = gr.Button("Send Files", variant="primary")
status = gr.Markdown(visible=False)
def on_load(request: gr.Request):
token = request.query_params.get("token", "")
job = request.query_params.get("job")
filename = request.query_params.get("file")
if job and filename:
file_path = os.path.join(STORAGE_PATH, job, filename)
if os.path.exists(file_path):
return gr.update(visible=False), gr.update(visible=True), gr.update(value=file_path), token, gr.update(visible=False)
else:
return gr.update(visible=True), gr.update(visible=False), gr.update(value=None), token, gr.update(visible=True, value=f"### ❌ Error: File '{filename}' not found. It may have been deleted.")
return gr.update(visible=True), gr.update(visible=False), gr.update(value=None), token, gr.update(visible=False)
demo.load(on_load, outputs=[upload_ui, download_ui, file_display, url_token, status])
# --- CHAINED CLICK EVENTS ---
send_btn.click(
disable_ui, None, [send_btn, status]
).then(
process_submission, [name, company, message, file_input, url_token], [status]
).then(
enable_ui, None, [send_btn]
)
back_btn.click(lambda: (gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)), outputs=[upload_ui, download_ui, status])
demo.launch(theme=theme, css=custom_css, allowed_paths=[STORAGE_PATH])