codeboosterstech commited on
Commit
fcd463d
·
verified ·
1 Parent(s): 016df9e

Upload 12 files

Browse files
README.md CHANGED
@@ -1,12 +1,38 @@
1
- ---
2
- title: Pydeploy Studio
3
- emoji: 🔥
4
- colorFrom: purple
5
- colorTo: red
6
- sdk: gradio
7
- sdk_version: 6.2.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Space Creator
2
+
3
+ An enterprise-grade application for converting Python code into deployable Gradio web applications with one-click deployment to Hugging Face Spaces.
4
+
5
+ ## Features
6
+
7
+ ### 🚀 **Core Features**
8
+ - **AI-Powered Conversion**: Convert Python/Notebook code to complete Gradio apps using Groq's Llama 3.3
9
+ - **Enterprise-Grade UI**: Professional, responsive interface with step-by-step workflow
10
+ - **Individual File Downloads**: Download each component separately (app.py, requirements.txt, README.md)
11
+ - **One-Click Deployment**: Direct deployment to Hugging Face Spaces
12
+ - **Secure API Handling**: User-provided API keys with no storage
13
+
14
+ ### 🛡️ **Security**
15
+ - User-managed API keys (Groq & Hugging Face)
16
+ - No key storage or logging
17
+ - Input validation and sanitization
18
+ - Secure file handling
19
+
20
+ ### 📊 **Enterprise Ready**
21
+ - Modular architecture
22
+ - Comprehensive error handling
23
+ - Detailed logging
24
+ - Scalable design
25
+
26
+ ## Installation
27
+
28
+ ### Prerequisites
29
+ - Python 3.8 or higher
30
+ - Groq API Key (for conversion)
31
+ - Hugging Face Write Token (for deployment)
32
+
33
+ ### Quick Start
34
+
35
+ 1. Clone the repository:
36
+ ```bash
37
+ git clone <repository-url>
38
+ cd huggingface-space-creator
app.py ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Main application file for Hugging Face Space Creator
3
+ Enterprise-grade Gradio application for converting Python code to deployable Gradio apps
4
+ """
5
+
6
+ import gradio as gr
7
+ import tempfile
8
+ import os
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ # Add utils and components to path
13
+ sys.path.append(str(Path(__file__).parent))
14
+
15
+ from utils.converter import convert_code
16
+ from utils.deployer import deploy_to_space
17
+ from utils.file_handler import (
18
+ create_zip_archive,
19
+ read_file_content,
20
+ parse_notebook,
21
+ save_individual_file
22
+ )
23
+ from utils.validator import validate_inputs
24
+
25
+ from components.header import create_header
26
+ from components.sidebar import create_sidebar
27
+ from components.api_guide import create_api_guide
28
+ from components.file_downloader import create_file_download_section
29
+
30
+ # Constants
31
+ MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
32
+ SUPPORTED_EXTENSIONS = ['.py', '.ipynb', '.txt']
33
+
34
+
35
+ class SpaceCreatorApp:
36
+ """Main application class for Hugging Face Space Creator"""
37
+
38
+ def __init__(self):
39
+ self.temp_files = []
40
+ self.current_step = 1
41
+ self.generated_files = {}
42
+
43
+ def cleanup(self):
44
+ """Clean up temporary files"""
45
+ for file_path in self.temp_files:
46
+ try:
47
+ if os.path.exists(file_path):
48
+ os.remove(file_path)
49
+ except:
50
+ pass
51
+ self.temp_files = []
52
+
53
+ def process_step1(self, input_text, input_file, groq_api_key):
54
+ """Step 1: Convert code to Gradio app"""
55
+ try:
56
+ # Validate inputs
57
+ validation_errors = validate_inputs(groq_api_key, None, None, "Convert Only")
58
+ if validation_errors:
59
+ return None, None, None, None, self._format_errors(validation_errors), 1
60
+
61
+ # Get source code
62
+ code_content = self._extract_code(input_text, input_file)
63
+ if not code_content.strip():
64
+ return None, None, None, None, "Please provide Python code to convert.", 1
65
+
66
+ # Convert code
67
+ conversion_result = convert_code(code_content, groq_api_key)
68
+
69
+ # Store generated files
70
+ self.generated_files = {
71
+ "app.py": conversion_result["app_py"],
72
+ "requirements.txt": conversion_result["requirements_txt"],
73
+ "README.md": conversion_result["readme_md"]
74
+ }
75
+
76
+ # Create individual files for download
77
+ file_paths = {}
78
+ for filename, content in self.generated_files.items():
79
+ file_path = save_individual_file(filename, content)
80
+ self.temp_files.append(file_path)
81
+ file_paths[filename] = file_path
82
+
83
+ status = self._create_status_message("success", "Code conversion successful!")
84
+ return (file_paths["app.py"], file_paths["requirements.txt"],
85
+ file_paths["README.md"], None, status, 2)
86
+
87
+ except Exception as e:
88
+ error_msg = self._create_status_message("error", f"Conversion failed: {str(e)}")
89
+ return None, None, None, None, error_msg, 1
90
+
91
+ def process_step2(self, hf_token, space_name, deploy_mode):
92
+ """Step 2: Deploy to Hugging Face"""
93
+ try:
94
+ if deploy_mode != "Deploy to Hugging Face Space":
95
+ status = self._create_status_message("info", "Skipping deployment as requested.")
96
+ return None, status, 2
97
+
98
+ # Validate deployment inputs
99
+ validation_errors = validate_inputs(None, hf_token, space_name, "Deploy")
100
+ if validation_errors:
101
+ return None, self._format_errors(validation_errors), 2
102
+
103
+ # Deploy to Hugging Face
104
+ deploy_url = deploy_to_space(hf_token, space_name, self.generated_files)
105
+
106
+ # Create zip archive of all files
107
+ zip_bytes = create_zip_archive(self.generated_files)
108
+ zip_path = save_individual_file("gradio_app_full_package.zip", zip_bytes, binary=True)
109
+ self.temp_files.append(zip_path)
110
+
111
+ status = self._create_status_message("success",
112
+ f"Deployment successful! Space URL: {deploy_url}")
113
+ return zip_path, status, 3
114
+
115
+ except Exception as e:
116
+ error_msg = self._create_status_message("error", f"Deployment failed: {str(e)}")
117
+ return None, error_msg, 2
118
+
119
+ def _extract_code(self, input_text, input_file):
120
+ """Extract code from text or file"""
121
+ code_content = ""
122
+ if input_file is not None:
123
+ file_content = read_file_content(input_file)
124
+ if input_file.name.endswith('.ipynb') if hasattr(input_file, 'name') else False:
125
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.ipynb', delete=False, encoding='utf-8') as tmp:
126
+ tmp.write(file_content)
127
+ tmp_path = tmp.name
128
+ try:
129
+ code_content = parse_notebook(tmp_path)
130
+ finally:
131
+ os.unlink(tmp_path)
132
+ else:
133
+ code_content = file_content
134
+ elif input_text.strip():
135
+ code_content = input_text
136
+ return code_content
137
+
138
+ def _format_errors(self, errors):
139
+ """Format validation errors"""
140
+ error_html = '<div class="error-message"><h4>Validation Errors:</h4><ul>'
141
+ for error in errors:
142
+ error_html += f'<li>{error}</li>'
143
+ error_html += '</ul></div>'
144
+ return error_html
145
+
146
+ def _create_status_message(self, msg_type, message):
147
+ """Create formatted status message"""
148
+ icons = {
149
+ "success": "check_circle",
150
+ "error": "error",
151
+ "warning": "warning",
152
+ "info": "info"
153
+ }
154
+ colors = {
155
+ "success": "#10B981",
156
+ "error": "#EF4444",
157
+ "warning": "#F59E0B",
158
+ "info": "#3B82F6"
159
+ }
160
+
161
+ return f'''
162
+ <div class="status-message {msg_type}">
163
+ <span class="material-icons" style="color: {colors[msg_type]}; vertical-align: middle;">
164
+ {icons[msg_type]}
165
+ </span>
166
+ <span style="vertical-align: middle; margin-left: 8px;">{message}</span>
167
+ </div>
168
+ '''
169
+
170
+
171
+ def create_app():
172
+ """Create the Gradio application interface"""
173
+ app = SpaceCreatorApp()
174
+
175
+ with gr.Blocks(
176
+ title="Hugging Face Space Creator",
177
+ theme=gr.themes.Soft(primary_hue="yellow"),
178
+ css="static/css/style.css"
179
+ ) as demo:
180
+
181
+ # Custom CSS
182
+ gr.HTML('<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">')
183
+
184
+ # Header
185
+ create_header()
186
+
187
+ with gr.Row():
188
+ # Sidebar with steps
189
+ with gr.Column(scale=1, min_width=300):
190
+ current_step = gr.State(1)
191
+ sidebar = create_sidebar(current_step)
192
+
193
+ # Main content area
194
+ with gr.Column(scale=3):
195
+ # Step 1: Code Input and Conversion
196
+ with gr.Group(visible=True) as step1_group:
197
+ gr.Markdown("### Step 1: Provide Your Code")
198
+
199
+ with gr.Tabs():
200
+ with gr.Tab("Upload File", id="upload_tab"):
201
+ file_input = gr.File(
202
+ label="Upload Python or Jupyter Notebook",
203
+ file_types=SUPPORTED_EXTENSIONS,
204
+ type="filepath"
205
+ )
206
+
207
+ with gr.Tab("Paste Code", id="paste_tab"):
208
+ text_input = gr.Textbox(
209
+ label="Python Code",
210
+ lines=20,
211
+ 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}!\"",
212
+ elem_id="code_editor"
213
+ )
214
+
215
+ gr.Markdown("### Step 1b: API Configuration")
216
+ with gr.Row():
217
+ with gr.Column():
218
+ groq_api_key = gr.Textbox(
219
+ label="Groq API Key",
220
+ type="password",
221
+ placeholder="Enter your Groq API key starting with gsk_",
222
+ info="Required for AI-powered conversion"
223
+ )
224
+
225
+ # API Key Creation Guide
226
+ api_guide = create_api_guide()
227
+
228
+ with gr.Row():
229
+ convert_btn = gr.Button(
230
+ "Convert Code",
231
+ variant="primary",
232
+ size="lg",
233
+ elem_id="convert_btn"
234
+ )
235
+
236
+ # Step 2: Generated Files
237
+ with gr.Group(visible=False) as step2_group:
238
+ gr.Markdown("### Step 2: Generated Files")
239
+
240
+ with gr.Row():
241
+ with gr.Column():
242
+ app_py_download = gr.File(
243
+ label="app.py",
244
+ file_types=[".py"],
245
+ interactive=False
246
+ )
247
+
248
+ with gr.Column():
249
+ requirements_download = gr.File(
250
+ label="requirements.txt",
251
+ file_types=[".txt"],
252
+ interactive=False
253
+ )
254
+
255
+ with gr.Column():
256
+ readme_download = gr.File(
257
+ label="README.md",
258
+ file_types=[".md"],
259
+ interactive=False
260
+ )
261
+
262
+ gr.Markdown("### Step 2b: Deployment Options")
263
+
264
+ with gr.Row():
265
+ with gr.Column():
266
+ hf_token = gr.Textbox(
267
+ label="Hugging Face Token",
268
+ type="password",
269
+ placeholder="Enter your Hugging Face token starting with hf_",
270
+ info="Required for deployment"
271
+ )
272
+
273
+ with gr.Column():
274
+ space_name = gr.Textbox(
275
+ label="Space Name",
276
+ placeholder="my-gradio-application",
277
+ info="Lowercase letters, numbers, and hyphens only"
278
+ )
279
+
280
+ deploy_mode = gr.Radio(
281
+ choices=["Download Only", "Deploy to Hugging Face Space"],
282
+ label="Select Action",
283
+ value="Download Only",
284
+ elem_id="deploy_mode"
285
+ )
286
+
287
+ with gr.Row():
288
+ back_btn_step2 = gr.Button("Back", variant="secondary")
289
+ deploy_btn = gr.Button("Proceed to Deployment", variant="primary")
290
+
291
+ # Step 3: Deployment Results
292
+ with gr.Group(visible=False) as step3_group:
293
+ gr.Markdown("### Step 3: Deployment Complete")
294
+
295
+ with gr.Row():
296
+ with gr.Column():
297
+ full_package_download = gr.File(
298
+ label="Complete Application Package",
299
+ file_types=[".zip"],
300
+ interactive=False
301
+ )
302
+
303
+ deployment_status = gr.Markdown()
304
+
305
+ with gr.Row():
306
+ back_btn_step3 = gr.Button("Start New Project", variant="secondary")
307
+ finish_btn = gr.Button("Finish", variant="primary")
308
+
309
+ # Status output
310
+ status_output = gr.HTML(
311
+ value='<div class="status-container"></div>',
312
+ elem_id="status_output"
313
+ )
314
+
315
+ # Event handlers
316
+ convert_btn.click(
317
+ fn=app.process_step1,
318
+ inputs=[text_input, file_input, groq_api_key],
319
+ outputs=[
320
+ app_py_download,
321
+ requirements_download,
322
+ readme_download,
323
+ full_package_download,
324
+ status_output,
325
+ current_step
326
+ ]
327
+ ).then(
328
+ fn=lambda step: (gr.update(visible=step==1), gr.update(visible=step==2), gr.update(visible=step==3)),
329
+ inputs=[current_step],
330
+ outputs=[step1_group, step2_group, step3_group]
331
+ )
332
+
333
+ deploy_btn.click(
334
+ fn=app.process_step2,
335
+ inputs=[hf_token, space_name, deploy_mode],
336
+ outputs=[full_package_download, status_output, current_step]
337
+ ).then(
338
+ fn=lambda step: (gr.update(visible=step==1), gr.update(visible=step==2), gr.update(visible=step==3)),
339
+ inputs=[current_step],
340
+ outputs=[step1_group, step2_group, step3_group]
341
+ )
342
+
343
+ back_btn_step2.click(
344
+ fn=lambda: (1, gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)),
345
+ outputs=[current_step, step1_group, step2_group, step3_group]
346
+ )
347
+
348
+ back_btn_step3.click(
349
+ fn=lambda: (1, gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)),
350
+ outputs=[current_step, step1_group, step2_group, step3_group]
351
+ ).then(
352
+ fn=app.cleanup,
353
+ inputs=None,
354
+ outputs=None
355
+ )
356
+
357
+ finish_btn.click(
358
+ fn=app.cleanup,
359
+ inputs=None,
360
+ outputs=None
361
+ )
362
+
363
+ return demo
364
+
365
+
366
+ if __name__ == "__main__":
367
+ print("Starting Hugging Face Space Creator...")
368
+ print("=" * 50)
369
+ print("Enterprise-grade Python to Gradio App Converter")
370
+ print("=" * 50)
371
+
372
+ app = create_app()
373
+ app.launch(
374
+ server_name="0.0.0.0",
375
+ server_port=7860,
376
+ share=False,
377
+ debug=True,
378
+ favicon_path=None
379
+ )
components/api_guide.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ API key creation guide component
3
+ """
4
+
5
+ import gradio as gr
6
+
7
+
8
+ def create_api_guide():
9
+ """Create API key creation guide with expandable sections"""
10
+
11
+ with gr.Accordion("Need help creating API keys?", open=False):
12
+ gr.Markdown("### Step-by-Step API Key Creation Guide")
13
+
14
+ with gr.Tabs():
15
+ # Groq API Key Guide
16
+ with gr.Tab("Groq API Key"):
17
+ groq_guide = '''
18
+ <div class="api-guide">
19
+ <h4>Creating a Groq API Key</h4>
20
+ <ol>
21
+ <li>Go to <a href="https://console.groq.com" target="_blank">Groq Console</a></li>
22
+ <li>Sign up or log in to your account</li>
23
+ <li>Navigate to <strong>API Keys</strong> section</li>
24
+ <li>Click on <strong>Create API Key</strong></li>
25
+ <li>Give your key a descriptive name</li>
26
+ <li>Copy the generated key (starts with <code>gsk_</code>)</li>
27
+ <li>Paste it in the Groq API Key field above</li>
28
+ </ol>
29
+
30
+ <div class="note">
31
+ <span class="material-icons">info</span>
32
+ <p>Keep your API key secure and never share it publicly.</p>
33
+ </div>
34
+
35
+ <div class="resources">
36
+ <h5>Additional Resources:</h5>
37
+ <ul>
38
+ <li><a href="https://groq.com" target="_blank">Groq Official Website</a></li>
39
+ <li><a href="https://console.groq.com/docs/quickstart" target="_blank">Groq Quickstart Guide</a></li>
40
+ <li><a href="https://console.groq.com/docs/authentication" target="_blank">Authentication Documentation</a></li>
41
+ </ul>
42
+ </div>
43
+ </div>
44
+ '''
45
+ gr.HTML(groq_guide)
46
+
47
+ # Hugging Face Token Guide
48
+ with gr.Tab("Hugging Face Token"):
49
+ hf_guide = '''
50
+ <div class="api-guide">
51
+ <h4>Creating a Hugging Face Token</h4>
52
+ <ol>
53
+ <li>Go to <a href="https://huggingface.co" target="_blank">Hugging Face</a></li>
54
+ <li>Sign up or log in to your account</li>
55
+ <li>Click on your profile picture → <strong>Settings</strong></li>
56
+ <li>Navigate to <strong>Access Tokens</strong></li>
57
+ <li>Click on <strong>New Token</strong></li>
58
+ <li>Select token type: <strong>Write</strong></li>
59
+ <li>Give your token a descriptive name</li>
60
+ <li>Copy the generated token (starts with <code>hf_</code>)</li>
61
+ <li>Paste it in the Hugging Face Token field above</li>
62
+ </ol>
63
+
64
+ <div class="note">
65
+ <span class="material-icons">warning</span>
66
+ <p>Write token is required for creating and updating Spaces.</p>
67
+ </div>
68
+
69
+ <div class="resources">
70
+ <h5>Additional Resources:</h5>
71
+ <ul>
72
+ <li><a href="https://huggingface.co/docs/hub/security-tokens" target="_blank">Token Security Guide</a></li>
73
+ <li><a href="https://huggingface.co/docs/hub/spaces-overview" target="_blank">Spaces Documentation</a></li>
74
+ <li><a href="https://huggingface.co/docs/hub/spaces-sdks" target="_blank">SDK Reference</a></li>
75
+ </ul>
76
+ </div>
77
+ </div>
78
+ '''
79
+ gr.HTML(hf_guide)
80
+
81
+ # Best Practices
82
+ with gr.Tab("Best Practices"):
83
+ practices_guide = '''
84
+ <div class="api-guide">
85
+ <h4>API Key Security Best Practices</h4>
86
+
87
+ <div class="security-tip">
88
+ <span class="material-icons">lock</span>
89
+ <div>
90
+ <strong>Key Rotation</strong>
91
+ <p>Regularly rotate your API keys (every 90 days recommended).</p>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="security-tip">
96
+ <span class="material-icons">visibility_off</span>
97
+ <div>
98
+ <strong>Never Expose Keys</strong>
99
+ <p>Never commit API keys to version control or share in public forums.</p>
100
+ </div>
101
+ </div>
102
+
103
+ <div class="security-tip">
104
+ <span class="material-icons">shield</span>
105
+ <div>
106
+ <strong>Use Environment Variables</strong>
107
+ <p>Store keys in environment variables instead of hardcoding.</p>
108
+ </div>
109
+ </div>
110
+
111
+ <div class="security-tip">
112
+ <span class="material-icons">notifications</span>
113
+ <div>
114
+ <strong>Monitor Usage</strong>
115
+ <p>Regularly check API usage and set up alerts for unusual activity.</p>
116
+ </div>
117
+ </div>
118
+
119
+ <div class="security-tip">
120
+ <span class="material-icons">delete</span>
121
+ <div>
122
+ <strong>Revoke Unused Keys</strong>
123
+ <p>Immediately revoke keys that are no longer needed.</p>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ '''
128
+ gr.HTML(practices_guide)
129
+
130
+ return None
components/file_downloader.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ File download components
3
+ """
4
+
5
+ import gradio as gr
6
+
7
+
8
+ def create_file_download_section():
9
+ """Create file download section with individual file options"""
10
+
11
+ with gr.Column(elem_classes="download-section"):
12
+ gr.Markdown("### Generated Files")
13
+
14
+ with gr.Row():
15
+ # app.py download
16
+ with gr.Column(scale=1):
17
+ app_download = gr.File(
18
+ label="app.py",
19
+ file_types=[".py"],
20
+ interactive=False,
21
+ elem_classes="file-download"
22
+ )
23
+
24
+ gr.HTML('''
25
+ <div class="file-info">
26
+ <span class="material-icons">description</span>
27
+ <span>Main application file</span>
28
+ </div>
29
+ ''')
30
+
31
+ # requirements.txt download
32
+ with gr.Column(scale=1):
33
+ requirements_download = gr.File(
34
+ label="requirements.txt",
35
+ file_types=[".txt"],
36
+ interactive=False,
37
+ elem_classes="file-download"
38
+ )
39
+
40
+ gr.HTML('''
41
+ <div class="file-info">
42
+ <span class="material-icons">list</span>
43
+ <span>Dependencies list</span>
44
+ </div>
45
+ ''')
46
+
47
+ # README.md download
48
+ with gr.Column(scale=1):
49
+ readme_download = gr.File(
50
+ label="README.md",
51
+ file_types=[".md"],
52
+ interactive=False,
53
+ elem_classes="file-download"
54
+ )
55
+
56
+ gr.HTML('''
57
+ <div class="file-info">
58
+ <span class="material-icons">article</span>
59
+ <span>Documentation</span>
60
+ </div>
61
+ ''')
62
+
63
+ # Full package download
64
+ gr.Markdown("### Complete Package")
65
+
66
+ with gr.Row():
67
+ with gr.Column():
68
+ full_package_download = gr.File(
69
+ label="Full Application Package",
70
+ file_types=[".zip"],
71
+ interactive=False,
72
+ elem_classes="full-download"
73
+ )
74
+
75
+ gr.HTML('''
76
+ <div class="package-info">
77
+ <span class="material-icons">folder_zip</span>
78
+ <span>Contains all files for deployment</span>
79
+ </div>
80
+ ''')
81
+
82
+ return {
83
+ "app_download": app_download,
84
+ "requirements_download": requirements_download,
85
+ "readme_download": readme_download,
86
+ "full_package_download": full_package_download
87
+ }
components/header.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Header component for the application
3
+ """
4
+
5
+ import gradio as gr
6
+
7
+
8
+ def create_header():
9
+ """Create the application header"""
10
+
11
+ header_html = """
12
+ <div class="header-container">
13
+ <div class="header-content">
14
+ <div class="logo-section">
15
+ <span class="material-icons logo-icon">rocket_launch</span>
16
+ <div class="logo-text">
17
+ <h1>Hugging Face Space Creator</h1>
18
+ <p class="tagline">Enterprise-grade Python to Gradio Application Converter</p>
19
+ </div>
20
+ </div>
21
+ <div class="header-badge">
22
+ <span class="material-icons">verified</span>
23
+ <span>Enterprise Ready</span>
24
+ </div>
25
+ </div>
26
+ <div class="header-divider"></div>
27
+ </div>
28
+ """
29
+
30
+ gr.HTML(header_html)
components/sidebar.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Sidebar component with step-by-step guide
3
+ """
4
+
5
+ import gradio as gr
6
+
7
+
8
+ def create_sidebar(current_step):
9
+ """Create the sidebar with progress steps"""
10
+
11
+ with gr.Column(elem_classes="sidebar"):
12
+ gr.Markdown("### Workflow Steps")
13
+
14
+ # Step indicators
15
+ steps = [
16
+ {"number": 1, "title": "Provide Code", "description": "Upload or paste your Python code"},
17
+ {"number": 2, "title": "Generate Files", "description": "Download individual components"},
18
+ {"number": 3, "title": "Deploy", "description": "Deploy to Hugging Face"}
19
+ ]
20
+
21
+ step_html = '<div class="steps-container">'
22
+ for step in steps:
23
+ active_class = "active" if step["number"] == current_step.value else ""
24
+ step_html += f'''
25
+ <div class="step {active_class}">
26
+ <div class="step-number">{step["number"]}</div>
27
+ <div class="step-content">
28
+ <div class="step-title">{step["title"]}</div>
29
+ <div class="step-description">{step["description"]}</div>
30
+ </div>
31
+ </div>
32
+ '''
33
+ step_html += '</div>'
34
+
35
+ gr.HTML(step_html)
36
+
37
+ # Quick tips
38
+ gr.Markdown("### Quick Tips")
39
+
40
+ tips_html = '''
41
+ <div class="tips-container">
42
+ <div class="tip">
43
+ <span class="material-icons tip-icon">code</span>
44
+ <div class="tip-content">
45
+ <strong>Clean Code</strong>
46
+ <p>Ensure your Python code is well-structured for better conversion results.</p>
47
+ </div>
48
+ </div>
49
+ <div class="tip">
50
+ <span class="material-icons tip-icon">security</span>
51
+ <div class="tip-content">
52
+ <strong>API Security</strong>
53
+ <p>Your API keys are used only for conversion and are not stored.</p>
54
+ </div>
55
+ </div>
56
+ <div class="tip">
57
+ <span class="material-icons tip-icon">cloud_upload</span>
58
+ <div class="tip-content">
59
+ <strong>Easy Deployment</strong>
60
+ <p>Deploy with one click to Hugging Face Spaces.</p>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ '''
65
+
66
+ gr.HTML(tips_html)
67
+
68
+ # System requirements
69
+ gr.Markdown("### System Requirements")
70
+ requirements_html = '''
71
+ <div class="requirements">
72
+ <ul>
73
+ <li>Python 3.8 or higher</li>
74
+ <li>Valid Groq API Key</li>
75
+ <li>Hugging Face Account (for deployment)</li>
76
+ <li>Internet connection</li>
77
+ </ul>
78
+ </div>
79
+ '''
80
+
81
+ gr.HTML(requirements_html)
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio>=6.2.0
2
+ langchain-groq>=0.1.0
3
+ huggingface-hub>=0.20.0
4
+ python-dotenv>=1.0.0
5
+ nbconvert>=7.0.0
6
+ beautifulsoup4>=4.12.0
7
+ requests>=2.31.0
8
+ pillow>=10.0.0
9
+ markdown>=3.5.0
10
+ pyyaml>=6.0
static/css/style.css ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Main Theme Variables */
2
+ :root {
3
+ --primary-yellow: #FFC107;
4
+ --primary-yellow-dark: #FFA000;
5
+ --primary-yellow-light: #FFECB3;
6
+ --secondary-blue: #2196F3;
7
+ --secondary-purple: #9C27B0;
8
+ --success-green: #10B981;
9
+ --error-red: #EF4444;
10
+ --warning-orange: #F59E0B;
11
+ --info-blue: #3B82F6;
12
+ --gray-50: #F9FAFB;
13
+ --gray-100: #F3F4F6;
14
+ --gray-200: #E5E7EB;
15
+ --gray-300: #D1D5DB;
16
+ --gray-400: #9CA3AF;
17
+ --gray-500: #6B7280;
18
+ --gray-600: #4B5563;
19
+ --gray-700: #374151;
20
+ --gray-800: #1F2937;
21
+ --gray-900: #111827;
22
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
23
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
24
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
25
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
26
+ --radius-sm: 0.375rem;
27
+ --radius-md: 0.5rem;
28
+ --radius-lg: 0.75rem;
29
+ --radius-xl: 1rem;
30
+ }
31
+
32
+ /* Global Styles */
33
+ body {
34
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
35
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
36
+ min-height: 100vh;
37
+ margin: 0;
38
+ padding: 20px;
39
+ }
40
+
41
+ .gradio-container {
42
+ max-width: 1400px !important;
43
+ margin: 0 auto !important;
44
+ background: white !important;
45
+ border-radius: var(--radius-xl) !important;
46
+ box-shadow: var(--shadow-xl) !important;
47
+ overflow: hidden !important;
48
+ min-height: 90vh !important;
49
+ }
50
+
51
+ /* Header Styles */
52
+ .header-container {
53
+ background: linear-gradient(90deg, var(--gray-900) 0%, var(--gray-800) 100%);
54
+ color: white;
55
+ padding: 2rem 2.5rem;
56
+ position: relative;
57
+ overflow: hidden;
58
+ }
59
+
60
+ .header-container::before {
61
+ content: '';
62
+ position: absolute;
63
+ top: 0;
64
+ right: 0;
65
+ width: 300px;
66
+ height: 300px;
67
+ background: linear-gradient(45deg, var(--primary-yellow) 0%, transparent 70%);
68
+ border-radius: 50%;
69
+ opacity: 0.1;
70
+ }
71
+
72
+ .header-content {
73
+ display: flex;
74
+ justify-content: space-between;
75
+ align-items: center;
76
+ position: relative;
77
+ z-index: 1;
78
+ }
79
+
80
+ .logo-section {
81
+ display: flex;
82
+ align-items: center;
83
+ gap: 1.5rem;
84
+ }
85
+
86
+ .logo-icon {
87
+ font-size: 3.5rem !important;
88
+ color: var(--primary-yellow);
89
+ background: rgba(255, 193, 7, 0.1);
90
+ padding: 1rem;
91
+ border-radius: var(--radius-lg);
92
+ border: 2px solid rgba(255, 193, 7, 0.3);
93
+ }
94
+
95
+ .logo-text h1 {
96
+ margin: 0;
97
+ font-size: 2.25rem;
98
+ font-weight: 700;
99
+ background: linear-gradient(90deg, var(--primary-yellow) 0%, #FFD700 100%);
100
+ -webkit-background-clip: text;
101
+ -webkit-text-fill-color: transparent;
102
+ background-clip: text;
103
+ }
104
+
105
+ .tagline {
106
+ margin: 0.5rem 0 0 0;
107
+ color: var(--gray-300);
108
+ font-size: 1.1rem;
109
+ font-weight: 400;
110
+ }
111
+
112
+ .header-badge {
113
+ display: flex;
114
+ align-items: center;
115
+ gap: 0.5rem;
116
+ background: rgba(255, 193, 7, 0.1);
117
+ padding: 0.75rem 1.5rem;
118
+ border-radius: var(--radius-lg);
119
+ border: 1px solid rgba(255, 193, 7, 0.3);
120
+ font-weight: 600;
121
+ color: var(--primary-yellow);
122
+ }
123
+
124
+ .header-badge .material-icons {
125
+ font-size: 1.25rem;
126
+ }
127
+
128
+ .header-divider {
129
+ height: 4px;
130
+ background: linear-gradient(90deg, var(--primary-yellow) 0%, var(--secondary-blue) 50%, var(--secondary-purple) 100%);
131
+ margin-top: 1.5rem;
132
+ border-radius: 2px;
133
+ }
134
+
135
+ /* Sidebar Styles */
136
+ .sidebar {
137
+ background: var(--gray-50);
138
+ padding: 2rem 1.5rem !important;
139
+ border-right: 1px solid var(--gray-200);
140
+ height: 100%;
141
+ min-height: calc(90vh - 200px);
142
+ }
143
+
144
+ .steps-container {
145
+ margin: 2rem 0;
146
+ }
147
+
148
+ .step {
149
+ display: flex;
150
+ align-items: center;
151
+ gap: 1rem;
152
+ padding: 1.25rem;
153
+ margin-bottom: 1rem;
154
+ background: white;
155
+ border-radius: var(--radius-lg);
156
+ border: 1px solid var(--gray-200);
157
+ transition: all 0.3s ease;
158
+ cursor: pointer;
159
+ }
160
+
161
+ .step:hover {
162
+ transform: translateY(-2px);
163
+ box-shadow: var(--shadow-md);
164
+ border-color: var(--primary-yellow);
165
+ }
166
+
167
+ .step.active {
168
+ background: linear-gradient(135deg, var(--primary-yellow-light) 0%, #FFF8E1 100%);
169
+ border-color: var(--primary-yellow);
170
+ border-left: 4px solid var(--primary-yellow);
171
+ }
172
+
173
+ .step-number {
174
+ width: 2.5rem;
175
+ height: 2.5rem;
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: center;
179
+ background: var(--gray-100);
180
+ color: var(--gray-700);
181
+ border-radius: 50%;
182
+ font-weight: 700;
183
+ font-size: 1.1rem;
184
+ transition: all 0.3s ease;
185
+ }
186
+
187
+ .step.active .step-number {
188
+ background: var(--primary-yellow);
189
+ color: white;
190
+ }
191
+
192
+ .step-content {
193
+ flex: 1;
194
+ }
195
+
196
+ .step-title {
197
+ font-weight: 600;
198
+ color: var(--gray-800);
199
+ margin-bottom: 0.25rem;
200
+ font-size: 1.1rem;
201
+ }
202
+
203
+ .step.active .step-title {
204
+ color: var(--gray-900);
205
+ }
206
+
207
+ .step-description {
208
+ font-size: 0.875rem;
209
+ color: var(--gray-600);
210
+ }
211
+
212
+ .tips-container {
213
+ margin: 2rem 0;
214
+ }
215
+
216
+ .tip {
217
+ display: flex;
218
+ align-items: flex-start;
219
+ gap: 1rem;
220
+ padding: 1rem;
221
+ margin-bottom: 1rem;
222
+ background: white;
223
+ border-radius: var(--radius-lg);
224
+ border: 1px solid var(--gray-200);
225
+ }
226
+
227
+ .tip-icon {
228
+ color: var(--primary-yellow);
229
+ font-size: 1.5rem !important;
230
+ margin-top: 0.25rem;
231
+ }
232
+
233
+ .tip-content strong {
234
+ display: block;
235
+ color: var(--gray-800);
236
+ margin-bottom: 0.25rem;
237
+ }
238
+
239
+ .tip-content p {
240
+ margin: 0;
241
+ font-size: 0.875rem;
242
+ color: var(--gray-600);
243
+ line-height: 1.5;
244
+ }
245
+
246
+ .requirements ul {
247
+ margin: 0;
248
+ padding-left: 1.5rem;
249
+ }
250
+
251
+ .requirements li {
252
+ margin-bottom: 0.5rem;
253
+ color: var(--gray-700);
254
+ font-size: 0.875rem;
255
+ }
256
+
257
+ /* API Guide Styles */
258
+ .api-guide {
259
+ padding: 1.5rem;
260
+ background: var(--gray-50);
261
+ border-radius: var(--radius-lg);
262
+ margin: 1rem 0;
263
+ }
264
+
265
+ .api-guide h4 {
266
+ margin-top: 0;
267
+ color: var(--gray-800);
268
+ border-bottom: 2px solid var(--primary-yellow);
269
+ padding-bottom: 0.5rem;
270
+ }
271
+
272
+ .api-guide ol {
273
+ margin: 1rem 0 1.5rem 0;
274
+ padding-left: 1.5rem;
275
+ }
276
+
277
+ .api-guide li {
278
+ margin-bottom: 0.75rem;
279
+ color: var(--gray-700);
280
+ line-height: 1.6;
281
+ }
282
+
283
+ .api-guide code {
284
+ background: var(--gray-200);
285
+ padding: 0.125rem 0.375rem;
286
+ border-radius: var(--radius-sm);
287
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
288
+ font-size: 0.875rem;
289
+ }
290
+
291
+ .note {
292
+ display: flex;
293
+ align-items: flex-start;
294
+ gap: 0.75rem;
295
+ padding: 1rem;
296
+ background: rgba(59, 130, 246, 0.1);
297
+ border-radius: var(--radius-md);
298
+ border-left: 4px solid var(--info-blue);
299
+ margin: 1.5rem 0;
300
+ }
301
+
302
+ .note .material-icons {
303
+ color: var(--info-blue);
304
+ margin-top: 0.125rem;
305
+ }
306
+
307
+ .note p {
308
+ margin: 0;
309
+ color: var(--gray-700);
310
+ font-size: 0.875rem;
311
+ }
312
+
313
+ .security-tip {
314
+ display: flex;
315
+ align-items: flex-start;
316
+ gap: 1rem;
317
+ padding: 1rem;
318
+ margin-bottom: 1rem;
319
+ background: white;
320
+ border-radius: var(--radius-md);
321
+ border: 1px solid var(--gray-200);
322
+ }
323
+
324
+ .security-tip .material-icons {
325
+ color: var(--primary-yellow);
326
+ font-size: 1.5rem !important;
327
+ margin-top: 0.125rem;
328
+ }
329
+
330
+ .security-tip strong {
331
+ display: block;
332
+ color: var(--gray-800);
333
+ margin-bottom: 0.25rem;
334
+ }
335
+
336
+ .security-tip p {
337
+ margin: 0;
338
+ font-size: 0.875rem;
339
+ color: var(--gray-600);
340
+ line-height: 1.5;
341
+ }
342
+
343
+ .resources h5 {
344
+ margin: 1.5rem 0 0.75rem 0;
345
+ color: var(--gray-800);
346
+ }
347
+
348
+ .resources ul {
349
+ margin: 0;
350
+ padding-left: 1.5rem;
351
+ }
352
+
353
+ .resources li {
354
+ margin-bottom: 0.5rem;
355
+ }
356
+
357
+ .resources a {
358
+ color: var(--secondary-blue);
359
+ text-decoration: none;
360
+ transition: color 0.2s ease;
361
+ }
362
+
363
+ .resources a:hover {
364
+ color: var(--primary-yellow);
365
+ text-decoration: underline;
366
+ }
367
+
368
+ /* Download Section Styles */
369
+ .download-section {
370
+ padding: 2rem !important;
371
+ }
372
+
373
+ .file-download {
374
+ margin-bottom: 0.5rem !important;
375
+ }
376
+
377
+ .file-info {
378
+ display: flex;
379
+ align-items: center;
380
+ gap: 0.5rem;
381
+ padding: 0.75rem;
382
+ background: var(--gray-50);
383
+ border-radius: var(--radius-md);
384
+ font-size: 0.875rem;
385
+ color: var(--gray-700);
386
+ }
387
+
388
+ .file-info .material-icons {
389
+ color: var(--primary-yellow);
390
+ font-size: 1.125rem !important;
391
+ }
392
+
393
+ .full-download {
394
+ margin-top: 1rem !important;
395
+ }
396
+
397
+ .package-info {
398
+ display: flex;
399
+ align-items: center;
400
+ gap: 0.5rem;
401
+ padding: 1rem;
402
+ background: linear-gradient(135deg, var(--primary-yellow-light) 0%, #FFF8E1 100%);
403
+ border-radius: var(--radius-md);
404
+ border: 2px solid var(--primary-yellow);
405
+ font-weight: 600;
406
+ color: var(--gray-800);
407
+ margin-top: 0.5rem;
408
+ }
409
+
410
+ .package-info .material-icons {
411
+ color: var(--primary-yellow);
412
+ font-size: 1.5rem !important;
413
+ }
414
+
415
+ /* Status Messages */
416
+ .status-container {
417
+ padding: 1.5rem;
418
+ border-radius: var(--radius-lg);
419
+ margin: 1.5rem 0;
420
+ background: var(--gray-50);
421
+ border: 1px solid var(--gray-200);
422
+ }
423
+
424
+ .status-message {
425
+ display: flex;
426
+ align-items: center;
427
+ padding: 1rem 1.25rem;
428
+ border-radius: var(--radius-md);
429
+ background: white;
430
+ border-left: 4px solid;
431
+ margin-bottom: 1rem;
432
+ animation: slideIn 0.3s ease;
433
+ }
434
+
435
+ @keyframes slideIn {
436
+ from {
437
+ opacity: 0;
438
+ transform: translateY(-10px);
439
+ }
440
+ to {
441
+ opacity: 1;
442
+ transform: translateY(0);
443
+ }
444
+ }
445
+
446
+ .status-message.success {
447
+ border-left-color: var(--success-green);
448
+ }
449
+
450
+ .status-message.error {
451
+ border-left-color: var(--error-red);
452
+ }
453
+
454
+ .status-message.warning {
455
+ border-left-color: var(--warning-orange);
456
+ }
457
+
458
+ .status-message.info {
459
+ border-left-color: var(--info-blue);
460
+ }
461
+
462
+ .status-message .material-icons {
463
+ font-size: 1.5rem !important;
464
+ margin-right: 0.75rem;
465
+ }
466
+
467
+ .error-message {
468
+ padding: 1.5rem;
469
+ background: linear-gradient(135deg, rgba(239, 68, 68, 0.1) 0%, rgba(239, 68, 68, 0.05) 100%);
470
+ border-radius: var(--radius-lg);
471
+ border: 1px solid var(--error-red);
472
+ margin: 1.5rem 0;
473
+ }
474
+
475
+ .error-message h4 {
476
+ margin-top: 0;
477
+ color: var(--error-red);
478
+ display: flex;
479
+ align-items: center;
480
+ gap: 0.5rem;
481
+ }
482
+
483
+ .error-message ul {
484
+ margin: 0.75rem 0 0 0;
485
+ padding-left: 1.5rem;
486
+ }
487
+
488
+ .error-message li {
489
+ margin-bottom: 0.5rem;
490
+ color: var(--gray-700);
491
+ }
492
+
493
+ /* Button Styles */
494
+ button {
495
+ transition: all 0.3s ease !important;
496
+ }
497
+
498
+ button:hover {
499
+ transform: translateY(-2px) !important;
500
+ box-shadow: var(--shadow-md) !important;
501
+ }
502
+
503
+ button.primary {
504
+ background: linear-gradient(90deg, var(--primary-yellow) 0%, var(--primary-yellow-dark) 100%) !important;
505
+ border: none !important;
506
+ color: var(--gray-900) !important;
507
+ font-weight: 600 !important;
508
+ }
509
+
510
+ button.secondary {
511
+ background: white !important;
512
+ border: 2px solid var(--gray-300) !important;
513
+ color: var(--gray-700) !important;
514
+ font-weight: 600 !important;
515
+ }
516
+
517
+ /* Form Styles */
518
+ input, textarea, select {
519
+ border-radius: var(--radius-md) !important;
520
+ border: 1px solid var(--gray-300) !important;
521
+ transition: all 0.3s ease !important;
522
+ }
523
+
524
+ input:focus, textarea:focus, select:focus {
525
+ border-color: var(--primary-yellow) !important;
526
+ box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.1) !important;
527
+ outline: none !important;
528
+ }
529
+
530
+ /* Tab Styles */
531
+ .tab-nav {
532
+ border-bottom: 2px solid var(--gray-200) !important;
533
+ }
534
+
535
+ .tab-nav button {
536
+ border-radius: var(--radius-md) var(--radius-md) 0 0 !important;
537
+ margin-right: 0.25rem !important;
538
+ }
539
+
540
+ .tab-nav button.selected {
541
+ background: linear-gradient(135deg, var(--primary-yellow-light) 0%, #FFF8E1 100%) !important;
542
+ border-color: var(--primary-yellow) !important;
543
+ border-bottom-color: transparent !important;
544
+ color: var(--gray-900) !important;
545
+ font-weight: 600 !important;
546
+ }
547
+
548
+ /* Code Editor */
549
+ #code_editor {
550
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
551
+ font-size: 0.875rem !important;
552
+ line-height: 1.6 !important;
553
+ background: var(--gray-50) !important;
554
+ border: 1px solid var(--gray-300) !important;
555
+ border-radius: var(--radius-lg) !important;
556
+ padding: 1.5rem !important;
557
+ }
558
+
559
+ /* Responsive Design */
560
+ @media (max-width: 1024px) {
561
+ .gradio-container {
562
+ padding: 0.5rem !important;
563
+ }
564
+
565
+ .header-content {
566
+ flex-direction: column;
567
+ gap: 1.5rem;
568
+ text-align: center;
569
+ }
570
+
571
+ .logo-section {
572
+ flex-direction: column;
573
+ text-align: center;
574
+ }
575
+
576
+ .sidebar {
577
+ padding: 1rem !important;
578
+ }
579
+
580
+ .step {
581
+ flex-direction: column;
582
+ text-align: center;
583
+ padding: 1rem;
584
+ }
585
+
586
+ .step-number {
587
+ margin-bottom: 0.5rem;
588
+ }
589
+ }
590
+
591
+ @media (max-width: 768px) {
592
+ body {
593
+ padding: 10px;
594
+ }
595
+
596
+ .logo-text h1 {
597
+ font-size: 1.75rem;
598
+ }
599
+
600
+ .header-badge {
601
+ width: 100%;
602
+ justify-content: center;
603
+ }
604
+
605
+ .api-guide {
606
+ padding: 1rem;
607
+ }
608
+ }
609
+
610
+ /* Animation for success states */
611
+ @keyframes pulse {
612
+ 0%, 100% {
613
+ opacity: 1;
614
+ }
615
+ 50% {
616
+ opacity: 0.8;
617
+ }
618
+ }
619
+
620
+ .success-pulse {
621
+ animation: pulse 2s infinite;
622
+ }
623
+
624
+ /* Loading State */
625
+ .loading {
626
+ position: relative;
627
+ pointer-events: none;
628
+ }
629
+
630
+ .loading::after {
631
+ content: '';
632
+ position: absolute;
633
+ top: 0;
634
+ left: 0;
635
+ right: 0;
636
+ bottom: 0;
637
+ background: rgba(255, 255, 255, 0.8);
638
+ display: flex;
639
+ align-items: center;
640
+ justify-content: center;
641
+ border-radius: inherit;
642
+ z-index: 10;
643
+ }
644
+
645
+ .loading::before {
646
+ content: '';
647
+ position: absolute;
648
+ top: 50%;
649
+ left: 50%;
650
+ width: 2.5rem;
651
+ height: 2.5rem;
652
+ margin: -1.25rem 0 0 -1.25rem;
653
+ border: 3px solid var(--gray-300);
654
+ border-top-color: var(--primary-yellow);
655
+ border-radius: 50%;
656
+ animation: spin 1s linear infinite;
657
+ z-index: 11;
658
+ }
659
+
660
+ @keyframes spin {
661
+ to {
662
+ transform: rotate(360deg);
663
+ }
664
+ }
utils/converter.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Core conversion logic for transforming Python code to Gradio apps
3
+ """
4
+
5
+ import re
6
+ import traceback
7
+ from typing import Dict, Any
8
+ from langchain_groq import ChatGroq
9
+ from langchain_core.prompts import ChatPromptTemplate
10
+ from langchain_core.output_parsers import StrOutputParser
11
+
12
+
13
+ def convert_code(input_code: str, groq_api_key: str, model_name: str = "llama-3.3-70b-versatile") -> Dict[str, str]:
14
+ """
15
+ Converts input Python/IPYNB code into a Gradio app structure.
16
+ """
17
+
18
+ # Validate API key
19
+ if not groq_api_key:
20
+ raise ValueError("Groq API Key is required for conversion.")
21
+
22
+ if not groq_api_key.startswith('gsk_'):
23
+ raise ValueError("Invalid Groq API Key. It should start with 'gsk_'")
24
+
25
+ try:
26
+ # Initialize Groq client
27
+ chat = ChatGroq(
28
+ temperature=0.1,
29
+ model_name=model_name,
30
+ api_key=groq_api_key,
31
+ max_retries=2,
32
+ timeout=30
33
+ )
34
+ except Exception as e:
35
+ raise ValueError(f"Failed to initialize Groq client: {str(e)}")
36
+
37
+ # System prompt for conversion - UPDATED with Gradio 6.2.0
38
+ system_prompt = """You are an expert Python developer specializing in Gradio and Hugging Face Spaces.
39
+ Your task is to convert the provided Python code into a deployable Gradio web application.
40
+
41
+ Return your response in this exact format:
42
+
43
+ ===APP_PY===
44
+ [Complete app.py code here - NO markdown backticks or ```python]
45
+ ===APP_PY_END===
46
+
47
+ ===REQUIREMENTS_TXT===
48
+ [Requirements.txt content here, one dependency per line - NO markdown backticks]
49
+ ===REQUIREMENTS_TXT_END===
50
+
51
+ ===README_MD===
52
+ [README.md content here with proper YAML frontmatter]
53
+ ===README_MD_END===
54
+
55
+ CRITICAL RULES:
56
+ 1. app.py MUST be valid Python code ONLY
57
+ 2. requirements.txt MUST be plain text
58
+ 3. README.md MUST have YAML frontmatter at the top
59
+ 4. Include all necessary imports in app.py
60
+ 5. Always include: if __name__ == "__main__": demo.launch()
61
+ 6. requirements.txt must include: gradio>=6.2.0 # CHANGED FROM 4.0.0 TO 6.2.0
62
+
63
+ YAML frontmatter template:
64
+ ---
65
+ title: Generated Gradio App
66
+ emoji: 🚀
67
+ colorFrom: blue
68
+ colorTo: purple
69
+ sdk: gradio
70
+ sdk_version: "6.2.0" # CHANGED FROM 4.0.0 TO 6.2.0
71
+ app_file: app.py
72
+ pinned: false
73
+ ---
74
+
75
+ Do NOT include markdown code blocks (```) in any output.
76
+ """
77
+
78
+ human_template = """Convert this Python code to a complete Gradio app.
79
+
80
+ Code to convert:
81
+ ```python
82
+ {code}
83
+ ```"""
84
+
85
+ # Create the chain
86
+ prompt = ChatPromptTemplate.from_messages([
87
+ ("system", system_prompt),
88
+ ("human", human_template)
89
+ ])
90
+
91
+ chain = prompt | chat | StrOutputParser()
92
+
93
+ try:
94
+ # Invoke the chain
95
+ response = chain.invoke({"code": input_code[:50000]})
96
+
97
+ # Parse the response
98
+ result = parse_llm_response(response)
99
+
100
+ # Clean and validate outputs
101
+ result = clean_all_outputs(result)
102
+ result = post_process_conversion(result, input_code)
103
+
104
+ return result
105
+
106
+ except Exception as e:
107
+ print(f"Conversion error: {e}")
108
+ print(f"Traceback: {traceback.format_exc()}")
109
+ return create_basic_template(input_code)
110
+
111
+
112
+ def parse_llm_response(response: str) -> Dict[str, str]:
113
+ """Parse the LLM response into structured components"""
114
+
115
+ result = {
116
+ "app_py": "",
117
+ "requirements_txt": "",
118
+ "readme_md": ""
119
+ }
120
+
121
+ patterns = [
122
+ (r'===APP_PY===(.*?)===APP_PY_END===', "app_py"),
123
+ (r'===REQUIREMENTS_TXT===(.*?)===REQUIREMENTS_TXT_END===', "requirements_txt"),
124
+ (r'===README_MD===(.*?)===README_MD_END===', "readme_md")
125
+ ]
126
+
127
+ for pattern, key in patterns:
128
+ match = re.search(pattern, response, re.DOTALL)
129
+ if match:
130
+ result[key] = match.group(1).strip()
131
+
132
+ return result
133
+
134
+
135
+ def clean_all_outputs(result: Dict[str, str]) -> Dict[str, str]:
136
+ """Clean markdown backticks from all outputs"""
137
+
138
+ for key in ["app_py", "requirements_txt", "readme_md"]:
139
+ if key in result and result[key]:
140
+ content = result[key]
141
+
142
+ # Remove markdown code blocks
143
+ content = re.sub(r'^```(python|py)?\s*', '', content, flags=re.IGNORECASE)
144
+ content = re.sub(r'\s*```$', '', content)
145
+ content = re.sub(r'```(python|py)?\s*(.*?)\s*```', r'\2', content, flags=re.DOTALL | re.IGNORECASE)
146
+
147
+ # Remove any remaining stray backticks
148
+ content = content.replace('```', '')
149
+
150
+ # Strip whitespace
151
+ content = content.strip()
152
+
153
+ result[key] = content
154
+
155
+ return result
156
+
157
+
158
+ def post_process_conversion(result: Dict[str, str], original_code: str) -> Dict[str, str]:
159
+ """Post-process and validate the conversion result"""
160
+
161
+ # Ensure app.py is valid Python
162
+ if not result.get("app_py"):
163
+ result["app_py"] = create_basic_app_template(original_code)
164
+
165
+ # Ensure requirements.txt is clean
166
+ result["requirements_txt"] = clean_requirements(result.get("requirements_txt", ""))
167
+
168
+ # Ensure README has proper format
169
+ result["readme_md"] = clean_readme(result.get("readme_md", ""))
170
+
171
+ return result
172
+
173
+
174
+ def clean_requirements(req_text: str) -> str:
175
+ """Clean and format requirements.txt content"""
176
+ if not req_text:
177
+ return "gradio>=6.2.0\nlangchain-groq>=0.1.0\nhuggingface-hub>=0.20.0" # UPDATED
178
+
179
+ # Remove any markdown
180
+ req_text = re.sub(r'```.*?\n', '', req_text, flags=re.DOTALL)
181
+ req_text = req_text.replace('```', '')
182
+
183
+ lines = []
184
+ for line in req_text.strip().split('\n'):
185
+ line = line.strip()
186
+ if line and not line.startswith('#') and not line.startswith('==='):
187
+ line = re.sub(r'[\[\]"\']', '', line)
188
+ if line:
189
+ lines.append(line)
190
+
191
+ # Ensure essential packages are included - UPDATED VERSION
192
+ essential_packages = ["gradio>=6.2.0", "langchain-groq>=0.1.0", "huggingface-hub>=0.20.0"] # UPDATED
193
+ for package in essential_packages:
194
+ if not any(package.split('>=')[0] in line.lower() for line in lines):
195
+ lines.insert(0, package)
196
+
197
+ # Remove duplicates and sort
198
+ return "\n".join(sorted(set(lines)))
199
+
200
+
201
+ def clean_readme(readme_text: str) -> str:
202
+ """Clean README.md to ensure proper format"""
203
+ if not readme_text:
204
+ return create_default_readme()
205
+
206
+ # Remove markdown code blocks
207
+ readme_text = re.sub(r'```.*?\n', '', readme_text, flags=re.DOTALL)
208
+ readme_text = readme_text.replace('```', '')
209
+
210
+ # Check for proper YAML frontmatter
211
+ if not re.search(r'^---\s*$', readme_text.strip(), re.MULTILINE):
212
+ return create_default_readme()
213
+
214
+ # Update sdk_version in frontmatter if it's 4.0.0
215
+ readme_text = re.sub(
216
+ r'sdk_version:\s*["\']4\.0\.0["\']',
217
+ 'sdk_version: "6.2.0"',
218
+ readme_text
219
+ )
220
+
221
+ # Update gradio version in requirements if mentioned
222
+ readme_text = re.sub(
223
+ r'gradio>=4\.0\.0',
224
+ 'gradio>=6.2.0',
225
+ readme_text
226
+ )
227
+
228
+ return readme_text.strip()
229
+
230
+
231
+ def create_default_readme() -> str:
232
+ """Create a default README with proper YAML frontmatter"""
233
+ return """---
234
+ title: Generated Gradio App
235
+ emoji: 🚀
236
+ colorFrom: blue
237
+ colorTo: purple
238
+ sdk: gradio
239
+ sdk_version: "6.2.0" # UPDATED
240
+ app_file: app.py
241
+ pinned: false
242
+ ---
243
+
244
+ # Generated Gradio Application
245
+
246
+ This application was automatically generated using the Hugging Face Space Creator.
247
+
248
+ ## Features
249
+
250
+ - User-friendly interface built with Gradio 6.2.0
251
+ - Ready for deployment on Hugging Face Spaces
252
+ - Includes all necessary dependencies
253
+
254
+ ## How to Use
255
+
256
+ 1. Launch the application
257
+ 2. Enter your inputs in the provided fields
258
+ 3. Click submit to see results
259
+
260
+ ## Deployment
261
+
262
+ To deploy this application on Hugging Face Spaces:
263
+
264
+ 1. Create a new Space on Hugging Face
265
+ 2. Select Gradio as the SDK
266
+ 3. Upload the generated files
267
+ 4. Your app will be live automatically
268
+
269
+ ## Requirements
270
+
271
+ All dependencies are listed in requirements.txt
272
+ """
273
+
274
+
275
+ def create_basic_app_template(input_code: str) -> str:
276
+ """Create a basic, guaranteed-valid app.py template"""
277
+ code_snippet = input_code[:1000]
278
+
279
+ return f'''import gradio as gr
280
+
281
+ # Original code snippet
282
+ {code_snippet}
283
+
284
+ # Gradio interface
285
+ def process_input(input_text):
286
+ try:
287
+ # Process the input
288
+ return f"Processed: {{input_text}}"
289
+ except Exception as e:
290
+ return f"Error: {{str(e)}}"
291
+
292
+ # Create the Gradio app
293
+ with gr.Blocks(title="Generated Application", theme=gr.themes.Soft()) as demo:
294
+ gr.Markdown("# Generated Application")
295
+
296
+ with gr.Row():
297
+ with gr.Column():
298
+ input_box = gr.Textbox(
299
+ label="Input Text",
300
+ placeholder="Enter text to process...",
301
+ lines=3
302
+ )
303
+ submit_btn = gr.Button("Process", variant="primary")
304
+
305
+ with gr.Row():
306
+ output_box = gr.Textbox(
307
+ label="Output",
308
+ interactive=False,
309
+ lines=5
310
+ )
311
+
312
+ submit_btn.click(
313
+ fn=process_input,
314
+ inputs=[input_box],
315
+ outputs=[output_box]
316
+ )
317
+
318
+ if __name__ == "__main__":
319
+ demo.launch(share=False)
320
+ '''
321
+
322
+
323
+ def create_basic_template(input_code: str) -> Dict[str, str]:
324
+ """Create a basic template when conversion fails"""
325
+ return {
326
+ "app_py": create_basic_app_template(input_code),
327
+ "requirements_txt": "gradio>=6.2.0\nlangchain-groq>=0.1.0\nhuggingface-hub>=0.20.0", # UPDATED
328
+ "readme_md": create_default_readme()
329
+ }
utils/deployer.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Deployment logic for Hugging Face Spaces
3
+ """
4
+
5
+ import re
6
+ from typing import Dict, Optional
7
+ from huggingface_hub import HfApi
8
+
9
+
10
+ def deploy_to_space(
11
+ token: str,
12
+ space_name: str,
13
+ files: Dict[str, str],
14
+ username: Optional[str] = None
15
+ ) -> str:
16
+ """
17
+ Deploys the given files to a Hugging Face Space.
18
+ Returns the URL of the deployed space.
19
+ """
20
+
21
+ # Validate inputs
22
+ if not token:
23
+ raise ValueError("Hugging Face Token is required.")
24
+
25
+ if not token.startswith('hf_'):
26
+ raise ValueError("Invalid Hugging Face token. Should start with 'hf_'")
27
+
28
+ if not space_name:
29
+ raise ValueError("Space name is required.")
30
+
31
+ # Validate space name format
32
+ if not re.match(r'^[a-z0-9-]{3,30}$', space_name):
33
+ raise ValueError(
34
+ "Space name must be 3-30 characters, lowercase letters, numbers, and hyphens only."
35
+ )
36
+
37
+ # Initialize Hugging Face API
38
+ api = HfApi(token=token)
39
+
40
+ try:
41
+ # Get user information
42
+ user_info = api.whoami()
43
+ if not username:
44
+ username = user_info['name']
45
+ except Exception as e:
46
+ raise ValueError(f"Invalid Token: {str(e)}")
47
+
48
+ # Create repository ID
49
+ repo_id = f"{username}/{space_name}"
50
+
51
+ try:
52
+ # Create or update the Space
53
+ api.create_repo(
54
+ repo_id=repo_id,
55
+ repo_type="space",
56
+ space_sdk="gradio",
57
+ exist_ok=True,
58
+ private=False
59
+ )
60
+ except Exception as e:
61
+ print(f"Note: {e}")
62
+
63
+ try:
64
+ # Upload files
65
+ for filename, content in files.items():
66
+ # Ensure app.py is clean
67
+ if filename == "app.py":
68
+ if '```' in content:
69
+ content = content.replace('```', '')
70
+
71
+ api.upload_file(
72
+ path_or_fileobj=content.encode('utf-8'),
73
+ path_in_repo=filename,
74
+ repo_id=repo_id,
75
+ repo_type="space",
76
+ commit_message=f"Add {filename} via Space Creator"
77
+ )
78
+
79
+ return f"https://huggingface.co/spaces/{repo_id}"
80
+
81
+ except Exception as e:
82
+ raise RuntimeError(f"Deployment failed: {str(e)}")
utils/file_handler.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ File handling utilities
3
+ """
4
+
5
+ import io
6
+ import json
7
+ import zipfile
8
+ import tempfile
9
+ import os
10
+ from pathlib import Path
11
+ from typing import Union, Dict, Any
12
+
13
+
14
+ def create_zip_archive(files: Dict[str, Union[str, bytes]]) -> bytes:
15
+ """Creates a zip archive in memory from a dictionary of filename: content."""
16
+ zip_buffer = io.BytesIO()
17
+
18
+ with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
19
+ for filename, content in files.items():
20
+ if isinstance(content, str):
21
+ content = content.encode('utf-8')
22
+ zip_file.writestr(filename, content)
23
+
24
+ zip_buffer.seek(0)
25
+ return zip_buffer.getvalue()
26
+
27
+
28
+ def read_file_content(file_obj) -> str:
29
+ """Read content from Gradio file object or path."""
30
+ if file_obj is None:
31
+ return ""
32
+
33
+ try:
34
+ if hasattr(file_obj, 'read'):
35
+ content = file_obj.read()
36
+ if isinstance(content, bytes):
37
+ return content.decode('utf-8', errors='ignore')
38
+ return str(content)
39
+ elif isinstance(file_obj, (str, Path)):
40
+ path = Path(file_obj)
41
+ if path.exists():
42
+ return path.read_text(encoding='utf-8', errors='ignore')
43
+ except Exception as e:
44
+ print(f"Error reading file: {e}")
45
+
46
+ return ""
47
+
48
+
49
+ def parse_notebook(file_path: str) -> str:
50
+ """Extracts code cells from a Jupyter notebook file."""
51
+ try:
52
+ import nbformat
53
+ with open(file_path, 'r', encoding='utf-8') as f:
54
+ nb = nbformat.read(f, as_version=4)
55
+
56
+ code_cells = []
57
+ for cell in nb.cells:
58
+ if cell.cell_type == 'code':
59
+ source = cell.source
60
+ if source.strip():
61
+ code_cells.append(source)
62
+
63
+ return '\n\n'.join(code_cells)
64
+ except Exception as e:
65
+ try:
66
+ with open(file_path, 'r', encoding='utf-8') as f:
67
+ data = json.load(f)
68
+
69
+ code_cells = []
70
+ for cell in data.get('cells', []):
71
+ if cell.get('cell_type') == 'code':
72
+ source = cell.get('source', '')
73
+ if isinstance(source, list):
74
+ source = ''.join(source)
75
+ if source.strip():
76
+ code_cells.append(source)
77
+
78
+ return '\n\n'.join(code_cells)
79
+ except Exception:
80
+ return ""
81
+
82
+
83
+ def save_individual_file(filename: str, content: Union[str, bytes], binary: bool = False) -> str:
84
+ """Save an individual file to temporary storage and return the path."""
85
+ temp_dir = tempfile.mkdtemp()
86
+ file_path = os.path.join(temp_dir, filename)
87
+
88
+ if binary:
89
+ with open(file_path, 'wb') as f:
90
+ f.write(content)
91
+ else:
92
+ with open(file_path, 'w', encoding='utf-8') as f:
93
+ f.write(content)
94
+
95
+ return file_path
96
+
97
+
98
+ def cleanup_temp_files(file_paths: list):
99
+ """Clean up temporary files."""
100
+ for file_path in file_paths:
101
+ try:
102
+ if os.path.exists(file_path):
103
+ os.remove(file_path)
104
+ except:
105
+ pass
utils/validator.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Input validation utilities
3
+ """
4
+
5
+ import re
6
+ from typing import List
7
+
8
+
9
+ def validate_inputs(
10
+ groq_key: str = None,
11
+ hf_token: str = None,
12
+ space_name: str = None,
13
+ mode: str = "Convert Only"
14
+ ) -> List[str]:
15
+ """
16
+ Validate all inputs before processing.
17
+ Returns a list of error messages.
18
+ """
19
+ errors = []
20
+
21
+ # Groq API Key validation
22
+ if mode in ["Convert Only", "Convert & Deploy"]:
23
+ if not groq_key:
24
+ errors.append("Groq API Key is required for conversion")
25
+ elif not groq_key.startswith('gsk_'):
26
+ errors.append("Groq API Key should start with 'gsk_'")
27
+ elif len(groq_key) < 40:
28
+ errors.append("Invalid Groq API Key format")
29
+
30
+ # Hugging Face Token validation for deployment
31
+ if mode == "Deploy" and hf_token:
32
+ if not hf_token.startswith('hf_'):
33
+ errors.append("Hugging Face token should start with 'hf_'")
34
+ elif len(hf_token) < 10:
35
+ errors.append("Invalid Hugging Face token format")
36
+
37
+ # Space Name validation for deployment
38
+ if mode == "Deploy" and space_name:
39
+ if len(space_name) < 3 or len(space_name) > 30:
40
+ errors.append("Space name must be 3-30 characters")
41
+ elif not re.match(r'^[a-z0-9-]+$', space_name):
42
+ errors.append("Space name can only contain lowercase letters, numbers, and hyphens")
43
+ elif space_name.startswith('-') or space_name.endswith('-'):
44
+ errors.append("Space name cannot start or end with a hyphen")
45
+ elif '--' in space_name:
46
+ errors.append("Space name cannot contain consecutive hyphens")
47
+
48
+ return errors
49
+
50
+
51
+ def validate_python_code(code: str) -> List[str]:
52
+ """
53
+ Validate Python code for common issues.
54
+ Returns a list of warnings (not errors).
55
+ """
56
+ warnings = []
57
+
58
+ if not code.strip():
59
+ warnings.append("Code is empty")
60
+ return warnings
61
+
62
+ # Check for basic Python syntax markers
63
+ if 'import' not in code and 'def' not in code and 'class' not in code:
64
+ warnings.append("Code may not be valid Python (missing imports, functions, or classes)")
65
+
66
+ # Check for potentially dangerous imports
67
+ dangerous_imports = ['os.system', 'subprocess', 'eval', 'exec', '__import__']
68
+ for dangerous in dangerous_imports:
69
+ if dangerous in code:
70
+ warnings.append(f"Code contains potentially dangerous operation: {dangerous}")
71
+
72
+ return warnings
73
+
74
+
75
+ def validate_file_size(file_size: int, max_size_mb: int = 10) -> bool:
76
+ """Validate file size."""
77
+ max_size_bytes = max_size_mb * 1024 * 1024
78
+ return file_size <= max_size_bytes