Spaces:
Runtime error
Runtime error
| """ | |
| Main application file for Hugging Face Space Creator | |
| Enterprise-grade Gradio application for converting Python code to deployable Gradio apps | |
| """ | |
| import gradio as gr | |
| import tempfile | |
| import os | |
| import sys | |
| from pathlib import Path | |
| # Add utils and components to path | |
| sys.path.append(str(Path(__file__).parent)) | |
| from utils.converter import convert_code | |
| from utils.deployer import deploy_to_space | |
| from utils.file_handler import ( | |
| create_zip_archive, | |
| read_file_content, | |
| parse_notebook, | |
| save_individual_file | |
| ) | |
| from utils.validator import validate_inputs | |
| from components.header import create_header | |
| from components.sidebar import create_sidebar | |
| from components.api_guide import create_api_guide | |
| from components.file_downloader import create_file_download_section | |
| # Constants | |
| MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB | |
| SUPPORTED_EXTENSIONS = ['.py', '.ipynb', '.txt'] | |
| class SpaceCreatorApp: | |
| """Main application class for Hugging Face Space Creator""" | |
| def __init__(self): | |
| self.temp_files = [] | |
| self.current_step = 1 | |
| self.generated_files = {} | |
| def cleanup(self): | |
| """Clean up temporary files""" | |
| for file_path in self.temp_files: | |
| try: | |
| if os.path.exists(file_path): | |
| os.remove(file_path) | |
| except: | |
| pass | |
| self.temp_files = [] | |
| def process_step1(self, input_text, input_file, groq_api_key): | |
| """Step 1: Convert code to Gradio app""" | |
| try: | |
| # Validate inputs | |
| validation_errors = validate_inputs(groq_api_key, None, None, "Convert Only") | |
| if validation_errors: | |
| return None, None, None, None, self._format_errors(validation_errors), 1 | |
| # Get source code | |
| code_content = self._extract_code(input_text, input_file) | |
| if not code_content.strip(): | |
| return None, None, None, None, "Please provide Python code to convert.", 1 | |
| # Convert code | |
| conversion_result = convert_code(code_content, groq_api_key) | |
| # Store generated files | |
| self.generated_files = { | |
| "app.py": conversion_result["app_py"], | |
| "requirements.txt": conversion_result["requirements_txt"], | |
| "README.md": conversion_result["readme_md"] | |
| } | |
| # Create individual files for download | |
| file_paths = {} | |
| for filename, content in self.generated_files.items(): | |
| file_path = save_individual_file(filename, content) | |
| self.temp_files.append(file_path) | |
| file_paths[filename] = file_path | |
| status = self._create_status_message("success", "Code conversion successful!") | |
| return (file_paths["app.py"], file_paths["requirements.txt"], | |
| file_paths["README.md"], None, status, 2) | |
| except Exception as e: | |
| error_msg = self._create_status_message("error", f"Conversion failed: {str(e)}") | |
| return None, None, None, None, error_msg, 1 | |
| def process_step2(self, hf_token, space_name, deploy_mode): | |
| """Step 2: Deploy to Hugging Face""" | |
| try: | |
| if deploy_mode != "Deploy to Hugging Face Space": | |
| status = self._create_status_message("info", "Skipping deployment as requested.") | |
| return None, status, 2 | |
| # Validate deployment inputs | |
| validation_errors = validate_inputs(None, hf_token, space_name, "Deploy") | |
| if validation_errors: | |
| return None, self._format_errors(validation_errors), 2 | |
| # Deploy to Hugging Face | |
| deploy_url = deploy_to_space(hf_token, space_name, self.generated_files) | |
| # Create zip archive of all files | |
| zip_bytes = create_zip_archive(self.generated_files) | |
| zip_path = save_individual_file("gradio_app_full_package.zip", zip_bytes, binary=True) | |
| self.temp_files.append(zip_path) | |
| status = self._create_status_message("success", | |
| f"Deployment successful! Space URL: {deploy_url}") | |
| return zip_path, status, 3 | |
| except Exception as e: | |
| error_msg = self._create_status_message("error", f"Deployment failed: {str(e)}") | |
| return None, error_msg, 2 | |
| def _extract_code(self, input_text, input_file): | |
| """Extract code from text or file""" | |
| code_content = "" | |
| if input_file is not None: | |
| file_content = read_file_content(input_file) | |
| if input_file.name.endswith('.ipynb') if hasattr(input_file, 'name') else False: | |
| with tempfile.NamedTemporaryFile(mode='w', suffix='.ipynb', delete=False, encoding='utf-8') as tmp: | |
| tmp.write(file_content) | |
| tmp_path = tmp.name | |
| try: | |
| code_content = parse_notebook(tmp_path) | |
| finally: | |
| os.unlink(tmp_path) | |
| else: | |
| code_content = file_content | |
| elif input_text.strip(): | |
| code_content = input_text | |
| return code_content | |
| def _format_errors(self, errors): | |
| """Format validation errors""" | |
| error_html = '<div class="error-message"><h4>Validation Errors:</h4><ul>' | |
| for error in errors: | |
| error_html += f'<li>{error}</li>' | |
| error_html += '</ul></div>' | |
| return error_html | |
| def _create_status_message(self, msg_type, message): | |
| """Create formatted status message""" | |
| icons = { | |
| "success": "check_circle", | |
| "error": "error", | |
| "warning": "warning", | |
| "info": "info" | |
| } | |
| colors = { | |
| "success": "#10B981", | |
| "error": "#EF4444", | |
| "warning": "#F59E0B", | |
| "info": "#3B82F6" | |
| } | |
| return f''' | |
| <div class="status-message {msg_type}"> | |
| <span class="material-icons" style="color: {colors[msg_type]}; vertical-align: middle;"> | |
| {icons[msg_type]} | |
| </span> | |
| <span style="vertical-align: middle; margin-left: 8px;">{message}</span> | |
| </div> | |
| ''' | |
| def create_app(): | |
| """Create the Gradio application interface""" | |
| app = SpaceCreatorApp() | |
| with gr.Blocks( | |
| title="Hugging Face Space Creator", | |
| theme=gr.themes.Soft(primary_hue="yellow"), | |
| css="static/css/style.css" | |
| ) as demo: | |
| # Custom CSS | |
| gr.HTML('<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">') | |
| # Header | |
| create_header() | |
| with gr.Row(): | |
| # Sidebar with steps | |
| with gr.Column(scale=1, min_width=300): | |
| current_step = gr.State(1) | |
| sidebar = create_sidebar(current_step) | |
| # Main content area | |
| with gr.Column(scale=3): | |
| # Step 1: Code Input and Conversion | |
| with gr.Group(visible=True) as step1_group: | |
| gr.Markdown("### Step 1: Provide Your Code") | |
| with gr.Tabs(): | |
| with gr.Tab("Upload File", id="upload_tab"): | |
| file_input = gr.File( | |
| label="Upload Python or Jupyter Notebook", | |
| file_types=SUPPORTED_EXTENSIONS, | |
| type="filepath" | |
| ) | |
| with gr.Tab("Paste Code", id="paste_tab"): | |
| text_input = gr.Textbox( | |
| label="Python Code", | |
| lines=20, | |
| placeholder="# Paste your Python code here...\n\n# Example:\ndef add(a, b):\n return a + b\n\ndef greet(name):\n return f\"Hello, {name}!\"", | |
| elem_id="code_editor" | |
| ) | |
| gr.Markdown("### Step 1b: API Configuration") | |
| with gr.Row(): | |
| with gr.Column(): | |
| groq_api_key = gr.Textbox( | |
| label="Groq API Key", | |
| type="password", | |
| placeholder="Enter your Groq API key starting with gsk_", | |
| info="Required for AI-powered conversion" | |
| ) | |
| # API Key Creation Guide | |
| api_guide = create_api_guide() | |
| with gr.Row(): | |
| convert_btn = gr.Button( | |
| "Convert Code", | |
| variant="primary", | |
| size="lg", | |
| elem_id="convert_btn" | |
| ) | |
| # Step 2: Generated Files | |
| with gr.Group(visible=False) as step2_group: | |
| gr.Markdown("### Step 2: Generated Files") | |
| with gr.Row(): | |
| with gr.Column(): | |
| app_py_download = gr.File( | |
| label="app.py", | |
| file_types=[".py"], | |
| interactive=False | |
| ) | |
| with gr.Column(): | |
| requirements_download = gr.File( | |
| label="requirements.txt", | |
| file_types=[".txt"], | |
| interactive=False | |
| ) | |
| with gr.Column(): | |
| readme_download = gr.File( | |
| label="README.md", | |
| file_types=[".md"], | |
| interactive=False | |
| ) | |
| gr.Markdown("### Step 2b: Deployment Options") | |
| with gr.Row(): | |
| with gr.Column(): | |
| hf_token = gr.Textbox( | |
| label="Hugging Face Token", | |
| type="password", | |
| placeholder="Enter your Hugging Face token starting with hf_", | |
| info="Required for deployment" | |
| ) | |
| with gr.Column(): | |
| space_name = gr.Textbox( | |
| label="Space Name", | |
| placeholder="my-gradio-application", | |
| info="Lowercase letters, numbers, and hyphens only" | |
| ) | |
| deploy_mode = gr.Radio( | |
| choices=["Download Only", "Deploy to Hugging Face Space"], | |
| label="Select Action", | |
| value="Download Only", | |
| elem_id="deploy_mode" | |
| ) | |
| with gr.Row(): | |
| back_btn_step2 = gr.Button("Back", variant="secondary") | |
| deploy_btn = gr.Button("Proceed to Deployment", variant="primary") | |
| # Step 3: Deployment Results | |
| with gr.Group(visible=False) as step3_group: | |
| gr.Markdown("### Step 3: Deployment Complete") | |
| with gr.Row(): | |
| with gr.Column(): | |
| full_package_download = gr.File( | |
| label="Complete Application Package", | |
| file_types=[".zip"], | |
| interactive=False | |
| ) | |
| deployment_status = gr.Markdown() | |
| with gr.Row(): | |
| back_btn_step3 = gr.Button("Start New Project", variant="secondary") | |
| finish_btn = gr.Button("Finish", variant="primary") | |
| # Status output | |
| status_output = gr.HTML( | |
| value='<div class="status-container"></div>', | |
| elem_id="status_output" | |
| ) | |
| # Event handlers | |
| convert_btn.click( | |
| fn=app.process_step1, | |
| inputs=[text_input, file_input, groq_api_key], | |
| outputs=[ | |
| app_py_download, | |
| requirements_download, | |
| readme_download, | |
| full_package_download, | |
| status_output, | |
| current_step | |
| ] | |
| ).then( | |
| fn=lambda step: (gr.update(visible=step==1), gr.update(visible=step==2), gr.update(visible=step==3)), | |
| inputs=[current_step], | |
| outputs=[step1_group, step2_group, step3_group] | |
| ) | |
| deploy_btn.click( | |
| fn=app.process_step2, | |
| inputs=[hf_token, space_name, deploy_mode], | |
| outputs=[full_package_download, status_output, current_step] | |
| ).then( | |
| fn=lambda step: (gr.update(visible=step==1), gr.update(visible=step==2), gr.update(visible=step==3)), | |
| inputs=[current_step], | |
| outputs=[step1_group, step2_group, step3_group] | |
| ) | |
| back_btn_step2.click( | |
| fn=lambda: (1, gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)), | |
| outputs=[current_step, step1_group, step2_group, step3_group] | |
| ) | |
| back_btn_step3.click( | |
| fn=lambda: (1, gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)), | |
| outputs=[current_step, step1_group, step2_group, step3_group] | |
| ).then( | |
| fn=app.cleanup, | |
| inputs=None, | |
| outputs=None | |
| ) | |
| finish_btn.click( | |
| fn=app.cleanup, | |
| inputs=None, | |
| outputs=None | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| print("Starting Hugging Face Space Creator...") | |
| print("=" * 50) | |
| print("Enterprise-grade Python to Gradio App Converter") | |
| print("=" * 50) | |
| app = create_app() | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| debug=True, | |
| favicon_path=None | |
| ) |