import csv
import os
from datetime import datetime
from typing import Optional, Union
import gradio as gr
from huggingface_hub import HfApi, Repository
from optimum_neuron_export import convert
from gradio_huggingfacehub_search import HuggingfaceHubSearch
from apscheduler.schedulers.background import BackgroundScheduler
DATASET_REPO_URL = "https://huggingface.co/datasets/optimum/neuron-exports"
DATA_FILENAME = "exports.csv"
DATA_FILE = os.path.join("data", DATA_FILENAME)
HF_TOKEN = os.environ.get("HF_WRITE_TOKEN")
DATADIR = "neuron_exports_data"
repo: Optional[Repository] = None
# Uncomment if you want to push to dataset repo with token
# if HF_TOKEN:
# repo = Repository(local_dir=DATADIR, clone_from=DATASET_REPO_URL, token=HF_TOKEN)
def neuron_export(model_id: str, task: str, oauth_token: gr.OAuthToken) -> str:
if oauth_token.token is None:
return "You must be logged in to use this space"
if not model_id:
return f"### Invalid input 🐞 Please specify a model name, got {model_id}"
try:
api = HfApi(token=oauth_token.token)
error, commit_info = convert(api=api, model_id=model_id, task=task, token=oauth_token.token)
if error != "0":
return error
print("[commit_info]", commit_info)
# Save in a private dataset if repo initialized
if repo is not None:
repo.git_pull(rebase=True)
with open(os.path.join(DATADIR, DATA_FILE), "a") as csvfile:
writer = csv.DictWriter(
csvfile, fieldnames=["model_id", "pr_url", "time"]
)
writer.writerow(
{
"model_id": model_id,
"pr_url": commit_info.pr_url,
"time": str(datetime.now()),
}
)
commit_url = repo.push_to_hub()
print("[dataset]", commit_url)
pr_revision = commit_info.pr_revision.replace("/", "%2F")
return f"#### Success 🔥 Yay! This model was successfully exported and a PR was opened using your token: [{commit_info.pr_url}]({commit_info.pr_url}). If you would like to use the exported model without waiting for the PR to be approved, head to https://huggingface.co/{model_id}/tree/{pr_revision}"
except Exception as e:
return f"#### Error: {e}"
TITLE_IMAGE = """
"""
TITLE = """
🤗 Optimum Neuron Model Exporter 🏎️ (WIP)
"""
DESCRIPTION = """
This Space allows you to automatically export 🤗 transformers models hosted on the Hugging Face Hub to AWS Neuron-optimized format for Inferentia/Trainium acceleration. It opens a PR on the target model, and it is up to the owner of the original model to merge the PR to allow people to leverage Neuron optimization!
**Features:**
- Automatically opens PR with Neuron-optimized model
- Preserves original model weights
- Adds proper tags to model card
**Requirements:**
- Model must be compatible with [Optimum Neuron](https://huggingface.co/docs/optimum-neuron)
- User must be logged in with write token
"""
# Custom CSS to fix dark mode compatibility and transparency issues
CUSTOM_CSS = """
/* Fix for HuggingfaceHubSearch component visibility in both light and dark modes */
.gradio-container .gr-form {
background: var(--background-fill-primary) !important;
border: 1px solid var(--border-color-primary) !important;
}
/* Ensure text is visible in both modes */
.gradio-container input[type="text"],
.gradio-container textarea,
.gradio-container .gr-textbox input {
color: var(--body-text-color) !important;
background: var(--input-background-fill) !important;
border: 1px solid var(--border-color-primary) !important;
}
/* Fix dropdown/search results visibility */
.gradio-container .gr-dropdown,
.gradio-container .gr-dropdown .gr-box,
.gradio-container [data-testid="textbox"] {
background: var(--background-fill-primary) !important;
color: var(--body-text-color) !important;
border: 1px solid var(--border-color-primary) !important;
}
/* Fix for search component specifically */
.gradio-container .gr-form > div,
.gradio-container .gr-form input {
background: var(--input-background-fill) !important;
color: var(--body-text-color) !important;
}
/* Ensure proper contrast for placeholder text */
.gradio-container input::placeholder {
color: var(--body-text-color-subdued) !important;
opacity: 0.7;
}
/* Fix any remaining transparent backgrounds */
.gradio-container .gr-box,
.gradio-container .gr-panel {
background: var(--background-fill-primary) !important;
}
/* Make sure search results are visible */
.gradio-container .gr-dropdown-item {
color: var(--body-text-color) !important;
background: var(--background-fill-primary) !important;
}
.gradio-container .gr-dropdown-item:hover {
background: var(--background-fill-secondary) !important;
}
"""
with gr.Blocks(css=CUSTOM_CSS) as demo:
# Login requirement notice and button
gr.Markdown("**You must be logged in to use this space**")
gr.LoginButton(min_width=250)
# Centered title and image
gr.HTML(TITLE_IMAGE)
gr.HTML(TITLE)
# Full-width description
gr.Markdown(DESCRIPTION)
# Input controls in a row at the bottom
with gr.Row():
input_model = HuggingfaceHubSearch(
label="Hub model ID",
placeholder="Search for model ID on the hub",
search_type="model",
)
input_task = gr.Textbox(
value="auto",
max_lines=1,
label='Task (can be left to "auto", will be automatically inferred)',
)
# Export button below the inputs
btn = gr.Button("Export to Neuron", size="lg")
# Output section
output = gr.Markdown(label="Output")
btn.click(
fn=neuron_export,
inputs=[input_model, input_task],
outputs=output,
)
if __name__ == "__main__":
def restart_space():
if HF_TOKEN:
HfApi().restart_space(repo_id="optimum/neuron-export", token=HF_TOKEN, factory_reboot=True)
scheduler = BackgroundScheduler()
scheduler.add_job(restart_space, "interval", seconds=21600)
scheduler.start()
demo.launch()