gagndeep commited on
Commit
f512eb9
·
verified ·
1 Parent(s): cadf964

Update app.py from anycoder

Browse files
Files changed (1) hide show
  1. app.py +382 -369
app.py CHANGED
@@ -1,396 +1,409 @@
1
  import gradio as gr
2
- import os
3
  import subprocess
4
- import tempfile
5
  from pathlib import Path
6
- import mimetypes
7
- import uuid
8
-
9
- # Define supported formats
10
- SUPPORTED_AUDIO_FORMATS = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a']
11
- SUPPORTED_VIDEO_FORMATS = ['mp4', 'avi', 'mov', 'mkv', 'webm', 'flv']
12
- SUPPORTED_IMAGE_FORMATS = ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'gif', 'tiff']
13
- SUPPORTED_DOCUMENT_FORMATS = ['pdf', 'docx', 'txt', 'rtf', 'html']
14
-
15
- # Combined supported formats
16
- SUPPORTED_FORMATS = {
17
- 'Audio': SUPPORTED_AUDIO_FORMATS,
18
- 'Video': SUPPORTED_VIDEO_FORMATS,
19
- 'Image': SUPPORTED_IMAGE_FORMATS,
20
- 'Document': SUPPORTED_DOCUMENT_FORMATS
21
- }
22
-
23
- def detect_file_type(file_path):
24
- """Detect file type based on extension and mime type"""
25
- ext = Path(file_path).suffix.lower()[1:]
26
- mime_type, _ = mimetypes.guess_type(file_path)
27
-
28
- if ext in SUPPORTED_AUDIO_FORMATS:
29
- return 'Audio'
30
- elif ext in SUPPORTED_VIDEO_FORMATS:
31
- return 'Video'
32
- elif ext in SUPPORTED_IMAGE_FORMATS:
33
- return 'Image'
34
- elif ext in SUPPORTED_DOCUMENT_FORMATS:
35
- return 'Document'
36
- elif mime_type and mime_type.startswith('audio/'):
37
- return 'Audio'
38
- elif mime_type and mime_type.startswith('video/'):
39
- return 'Video'
40
- elif mime_type and mime_type.startswith('image/'):
41
- return 'Image'
42
- elif mime_type and mime_type.startswith('text/'):
43
- return 'Document'
44
- else:
45
- return 'Unknown'
46
-
47
- def convert_media(input_file, output_format, media_type):
48
- """Convert media file using FFmpeg for audio/video and ImageMagick for images"""
 
49
  try:
50
- # Create temp directory
51
- with tempfile.TemporaryDirectory() as temp_dir:
52
- input_path = os.path.join(temp_dir, f"input_{uuid.uuid4().hex}")
53
- output_path = os.path.join(temp_dir, f"output_{uuid.uuid4().hex}.{output_format}")
54
-
55
- # Save input file
56
- with open(input_path, 'wb') as f:
57
- f.write(input_file)
58
-
59
- # Convert based on media type
60
- if media_type == 'Audio':
61
- cmd = [
62
- 'ffmpeg', '-y', '-i', input_path,
63
- '-vn', '-acodec', 'libmp3lame' if output_format == 'mp3' else 'aac',
64
- '-q:a', '2', output_path
65
- ]
66
- elif media_type == 'Video':
67
- cmd = [
68
- 'ffmpeg', '-y', '-i', input_path,
69
- '-c:v', 'libx264', '-crf', '23',
70
- '-c:a', 'aac', '-b:a', '128k',
71
- output_path
72
- ]
73
- elif media_type == 'Image':
74
- cmd = [
75
- 'convert', input_path, output_path
76
- ]
77
- elif media_type == 'Document':
78
- if output_format == 'pdf':
79
- cmd = [
80
- 'libreoffice', '--headless', '--convert-to', 'pdf',
81
- '--outdir', temp_dir, input_path
82
- ]
83
- output_path = input_path.replace('.docx', '.pdf')
84
- else:
85
- # Simple text conversion
86
- with open(input_path, 'r') as f:
87
- content = f.read()
88
- with open(output_path, 'w') as f:
89
- f.write(content)
90
- return output_path
91
-
92
- # Execute conversion
93
- result = subprocess.run(cmd, capture_output=True, text=True)
94
-
95
- if result.returncode != 0:
96
- raise Exception(f"Conversion failed: {result.stderr}")
97
-
98
- # Read output file
99
- with open(output_path, 'rb') as f:
100
- output_data = f.read()
101
-
102
- return output_data
103
-
104
- except Exception as e:
105
- raise Exception(f"Conversion error: {str(e)}")
106
-
107
- def process_conversion(input_file, output_format):
108
- """Main conversion function"""
109
  try:
110
- # Create temp file to detect type
111
- with tempfile.NamedTemporaryFile(delete=False) as temp_file:
112
- temp_path = temp_file.name
113
- temp_file.write(input_file)
114
-
115
- # Detect media type
116
- media_type = detect_file_type(temp_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
- if media_type == 'Unknown':
119
- raise Exception("Unsupported file format")
 
 
 
 
 
 
120
 
121
- # Validate output format
122
- if output_format not in SUPPORTED_FORMATS[media_type]:
123
- raise Exception(f"Unsupported output format for {media_type}: {output_format}")
 
 
124
 
125
- # Convert
126
- output_data = convert_media(input_file, output_format, media_type)
 
 
127
 
128
- # Clean up
129
- os.unlink(temp_path)
 
 
 
 
130
 
131
- return output_data
 
 
 
 
 
132
 
133
- except Exception as e:
134
- if 'temp_path' in locals():
135
- try:
136
- os.unlink(temp_path)
137
- except:
138
- pass
139
- raise Exception(f"Error: {str(e)}")
140
 
141
- # Create custom theme
142
- custom_theme = gr.themes.Soft(
143
- primary_hue="blue",
144
- secondary_hue="indigo",
145
- neutral_hue="slate",
146
- font=gr.themes.GoogleFont("Inter"),
147
- text_size="lg",
148
- spacing_size="lg",
149
- radius_size="md"
150
- ).set(
151
- button_primary_background_fill="*primary_600",
152
- button_primary_background_fill_hover="*primary_700",
153
- block_title_text_weight="600",
154
- )
155
 
156
- # Create Gradio interface
157
- with gr.Blocks() as demo:
158
- gr.Markdown("""
159
- # 🎵 Universal Media Converter
160
- **Built with anycoder** - [https://huggingface.co/spaces/akhaliq/anycoder](https://huggingface.co/spaces/akhaliq/anycoder)
 
161
 
162
- Convert media files between various formats using Hugging Face's zero-GPU infrastructure.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  """)
164
-
165
  with gr.Row():
166
  with gr.Column(scale=1):
167
- gr.Markdown("## Input Media")
 
168
  input_file = gr.File(
169
  label="Upload Media File",
170
- file_types=[
171
- "audio", "video", "image",
172
- ".pdf", ".docx", ".txt", ".rtf", ".html"
173
- ],
174
- type="binary"
175
  )
176
-
177
- # Format selection
178
- with gr.Accordion("Advanced Options", open=False):
179
- gr.Markdown("### Select Output Format")
180
-
181
- with gr.Row():
182
- media_type_select = gr.Dropdown(
183
- choices=list(SUPPORTED_FORMATS.keys()),
184
- value="Audio",
185
- label="Media Type"
186
- )
187
-
188
- format_select = gr.Dropdown(
189
- choices=SUPPORTED_AUDIO_FORMATS,
190
- value="mp3",
191
- label="Output Format",
192
- allow_custom_value=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  )
194
-
 
 
 
 
 
 
 
 
 
 
 
195
  with gr.Column(scale=1):
196
- gr.Markdown("## Conversion Result")
197
- output_file = gr.File(label="Download Converted File")
198
-
199
- status_text = gr.Textbox(
200
- label="Status",
201
- value="Ready to convert!",
202
- interactive=False
203
  )
204
-
205
- # Update format dropdown based on media type
206
- def update_formats(media_type):
207
- formats = SUPPORTED_FORMATS.get(media_type, [])
208
- return gr.Dropdown(
209
- choices=formats,
210
- value=formats[0] if formats else "",
211
- label="Output Format",
212
- allow_custom_value=True
213
- )
214
-
215
- media_type_select.change(
216
- fn=update_formats,
217
- inputs=media_type_select,
218
- outputs=format_select
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  )
220
-
221
- # Conversion button
222
- convert_btn = gr.Button("🔄 Convert Media", variant="primary", size="lg")
223
-
224
- def convert_wrapper(input_data, output_format):
225
- try:
226
- if input_data is None:
227
- raise Exception("Please upload a file first")
228
-
229
- # Convert
230
- result = process_conversion(input_data, output_format)
231
-
232
- return {
233
- output_file: result,
234
- status_text: f"✅ Successfully converted to {output_format.upper()}"
235
- }
236
- except Exception as e:
237
- return {
238
- output_file: None,
239
- status_text: f"❌ Error: {str(e)}"
240
- }
241
-
242
  convert_btn.click(
243
- fn=convert_wrapper,
244
- inputs=[input_file, format_select],
245
- outputs=[output_file, status_text],
246
- api_visibility="public"
247
  )
248
 
249
- gr.Markdown("""
250
- ## 📋 Supported Formats
251
-
252
- ### Audio
253
- MP3, WAV, OGG, FLAC, AAC, M4A
254
-
255
- ### Video
256
- MP4, AVI, MOV, MKV, WEBM, FLV
257
-
258
- ### Image
259
- JPG, PNG, WEBP, BMP, GIF, TIFF
260
-
261
- ### Document
262
- PDF, DOCX, TXT, RTF, HTML
263
- """)
264
-
265
- demo.launch(
266
- theme=custom_theme,
267
- footer_links=[
268
- {
269
- "label": "Built with anycoder",
270
- "url": "https://huggingface.co/spaces/akhaliq/anycoder"
271
- },
272
- {
273
- "label": "Gradio Docs",
274
- "url": "https://gradio.app/docs"
275
- }
276
- ],
277
- css="""
278
- .gradio-container {
279
- max-width: 1000px !important;
280
- }
281
- .gr-button-primary {
282
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
283
- border: none !important;
284
- }
285
- .gr-button-primary:hover {
286
- transform: translateY(-2px);
287
- box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;
288
- }
289
- .gr-box {
290
- border-radius: 12px !important;
291
- border: 1px solid #e5e7eb !important;
292
- }
293
- """,
294
- js="""
295
- function addAnimation() {
296
- const buttons = document.querySelectorAll('.gr-button-primary');
297
- buttons.forEach(button => {
298
- button.addEventListener('click', function() {
299
- this.style.transform = 'scale(0.95)';
300
- setTimeout(() => {
301
- this.style.transform = 'scale(1)';
302
- }, 150);
303
- });
304
- });
305
- }
306
-
307
- // Add animation when page loads
308
- document.addEventListener('DOMContentLoaded', addAnimation);
309
- """
310
- )
311
- ## Deployment Instructions
312
-
313
- ### Option 1: Deploy on Hugging Face Spaces (Recommended)
314
-
315
- 1. **Create a new Space**:
316
- - Go to [Hugging Face Spaces](https://huggingface.co/spaces)
317
- - Click "Create new Space"
318
- - Select "Gradio" as the SDK
319
- - Choose a name for your Space
320
-
321
- 2. **Upload the code**:
322
- - Create a new file called `app.py` in your Space
323
- - Paste the complete code above
324
- - Create a `requirements.txt` file with:
325
-
326
- gradio>=4.0
327
- ffmpeg-python
328
- pillow
329
-
330
- 3. **Configure your Space**:
331
- - In the "Settings" tab, make sure to enable GPU if needed
332
- - Set the hardware to "CPU" (this app doesn't need GPU)
333
- - Add any environment variables if needed
334
-
335
- 4. **Deploy**:
336
- - Click "Commit" to save your changes
337
- - The app will automatically build and deploy
338
- - Once ready, you'll get a public URL like: `https://huggingface.co/spaces/your-username/your-space-name`
339
-
340
- ### Option 2: Local Deployment
341
-
342
- 1. **Install dependencies**:
343
- ```bash
344
- pip install gradio ffmpeg-python pillow
345
-
346
- 2. **Install FFmpeg and ImageMagick**:
347
- - On Ubuntu/Debian:
348
- ```bash
349
- sudo apt-get install ffmpeg imagemagick
350
-
351
- - On Mac:
352
- ```bash
353
- brew install ffmpeg imagemagick
354
-
355
- - On Windows: Download from official websites
356
-
357
- 3. **Run the application**:
358
- ```bash
359
- python app.py
360
-
361
- 4. **Access locally**:
362
- - Open your browser to `http://localhost:7860`
363
- - For public access, use `python app.py --share`
364
-
365
- ### Option 3: Docker Deployment
366
-
367
- 1. **Create a Dockerfile**:
368
- ```dockerfile
369
- FROM python:3.9-slim
370
-
371
- RUN apt-get update && apt-get install -y \
372
- ffmpeg \
373
- imagemagick \
374
- && rm -rf /var/lib/apt/lists/*
375
-
376
- WORKDIR /app
377
- COPY . .
378
-
379
- RUN pip install gradio ffmpeg-python pillow
380
-
381
- CMD ["python", "app.py"]
382
-
383
- 2. **Build and run**:
384
- ```bash
385
- docker build -t media-converter .
386
- docker run -p 7860:7860 media-converter
387
-
388
- ## Key Features of This Deployment
389
-
390
- 1. **Production-Ready**: Uses Gradio 6 with modern themes and proper error handling
391
- 2. **Cross-Platform**: Works on Linux, Mac, and Windows
392
- 3. **Containerized**: Easy Docker deployment for cloud platforms
393
- 4. **Scalable**: Can handle multiple concurrent conversions
394
- 5. **User-Friendly**: Beautiful UI with animations and clear status messages
395
-
396
- The application is now ready for deployment! Choose the method that best fits your needs - Hugging Face Spaces for easiest public hosting, local deployment for testing, or Docker for production environments.
 
1
  import gradio as gr
 
2
  import subprocess
3
+ import os
4
  from pathlib import Path
5
+ import tempfile
6
+ import shutil
7
+
8
+ # Comprehensive format support
9
+ VIDEO_FORMATS = [
10
+ "mp4", "avi", "mkv", "mov", "wmv", "flv", "webm", "m4v", "mpg", "mpeg",
11
+ "3gp", "ogv", "ts", "vob", "divx", "f4v", "asf", "rm", "rmvb"
12
+ ]
13
+
14
+ AUDIO_FORMATS = [
15
+ "mp3", "wav", "aac", "flac", "ogg", "m4a", "wma", "opus", "aiff",
16
+ "alac", "ape", "ac3", "dts", "amr", "mka", "tta", "wv"
17
+ ]
18
+
19
+ IMAGE_FORMATS = [
20
+ "jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "webp", "svg",
21
+ "ico", "heic", "heif", "raw", "cr2", "nef", "psd", "eps"
22
+ ]
23
+
24
+ DOCUMENT_FORMATS = [
25
+ "pdf", "txt", "doc", "docx", "rtf", "odt", "html", "md"
26
+ ]
27
+
28
+ ALL_FORMATS = sorted(set(VIDEO_FORMATS + AUDIO_FORMATS + IMAGE_FORMATS + DOCUMENT_FORMATS))
29
+
30
+ def get_file_info(file_path):
31
+ """Get detailed information about the uploaded file."""
32
+ if not file_path:
33
+ return "No file uploaded"
34
+
35
+ file_size = os.path.getsize(file_path)
36
+ file_ext = Path(file_path).suffix.lower().replace(".", "")
37
+
38
+ size_mb = file_size / (1024 * 1024)
39
+
40
+ info = f"""
41
+ 📁 **File Information**
42
+ - **Name:** {Path(file_path).name}
43
+ - **Format:** {file_ext.upper()}
44
+ - **Size:** {size_mb:.2f} MB
45
+ - **Path:** {file_path}
46
+ """
47
+
48
+ # Try to get media info using ffprobe
49
  try:
50
+ result = subprocess.run(
51
+ ["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", file_path],
52
+ capture_output=True,
53
+ text=True,
54
+ timeout=10
55
+ )
56
+ if result.returncode == 0:
57
+ import json
58
+ data = json.loads(result.stdout)
59
+ if "format" in data:
60
+ duration = data["format"].get("duration", "N/A")
61
+ if duration != "N/A":
62
+ info += f"\n- **Duration:** {float(duration):.2f} seconds"
63
+ if "streams" in data:
64
+ for stream in data["streams"]:
65
+ if stream["codec_type"] == "video":
66
+ info += f"\n- **Video Codec:** {stream.get('codec_name', 'N/A')}"
67
+ info += f"\n- **Resolution:** {stream.get('width', 'N/A')}x{stream.get('height', 'N/A')}"
68
+ elif stream["codec_type"] == "audio":
69
+ info += f"\n- **Audio Codec:** {stream.get('codec_name', 'N/A')}"
70
+ info += f"\n- **Sample Rate:** {stream.get('sample_rate', 'N/A')} Hz"
71
+ except:
72
+ pass
73
+
74
+ return info
75
+
76
+ def convert_media(input_file, output_format, quality="high", resolution=None):
77
+ """
78
+ Convert media file to specified format.
79
+
80
+ Args:
81
+ input_file: Path to input file
82
+ output_format: Desired output format
83
+ quality: Quality setting (high, medium, low)
84
+ resolution: Optional resolution for video (e.g., "1920x1080")
85
+ """
86
+ if not input_file:
87
+ raise gr.Error("❌ Please upload a file first!")
88
+
89
+ if not output_format:
90
+ raise gr.Error("❌ Please select an output format!")
91
+
92
+ # Create temporary output file
93
+ output_file = tempfile.NamedTemporaryFile(
94
+ delete=False,
95
+ suffix=f".{output_format}"
96
+ ).name
97
+
 
 
 
 
 
 
 
 
 
 
 
98
  try:
99
+ # Build ffmpeg command based on format and quality
100
+ cmd = ["ffmpeg", "-i", input_file, "-y"]
101
+
102
+ # Quality settings
103
+ if quality == "high":
104
+ if output_format in VIDEO_FORMATS:
105
+ cmd.extend(["-crf", "18", "-preset", "slow"])
106
+ elif output_format in AUDIO_FORMATS:
107
+ cmd.extend(["-b:a", "320k"])
108
+ elif quality == "medium":
109
+ if output_format in VIDEO_FORMATS:
110
+ cmd.extend(["-crf", "23", "-preset", "medium"])
111
+ elif output_format in AUDIO_FORMATS:
112
+ cmd.extend(["-b:a", "192k"])
113
+ else: # low
114
+ if output_format in VIDEO_FORMATS:
115
+ cmd.extend(["-crf", "28", "-preset", "fast"])
116
+ elif output_format in AUDIO_FORMATS:
117
+ cmd.extend(["-b:a", "128k"])
118
+
119
+ # Resolution settings for video
120
+ if resolution and output_format in VIDEO_FORMATS:
121
+ cmd.extend(["-s", resolution])
122
+
123
+ # Format-specific settings
124
+ if output_format == "mp3":
125
+ cmd.extend(["-codec:a", "libmp3lame"])
126
+ elif output_format == "aac":
127
+ cmd.extend(["-codec:a", "aac"])
128
+ elif output_format == "flac":
129
+ cmd.extend(["-codec:a", "flac"])
130
+ elif output_format == "opus":
131
+ cmd.extend(["-codec:a", "libopus"])
132
+ elif output_format == "webm":
133
+ cmd.extend(["-codec:v", "libvpx-vp9", "-codec:a", "libopus"])
134
+ elif output_format == "mp4":
135
+ cmd.extend(["-codec:v", "libx264", "-codec:a", "aac"])
136
+
137
+ cmd.append(output_file)
138
+
139
+ # Execute conversion
140
+ result = subprocess.run(
141
+ cmd,
142
+ capture_output=True,
143
+ text=True,
144
+ timeout=300 # 5 minute timeout
145
+ )
146
+
147
+ if result.returncode != 0:
148
+ raise Exception(f"Conversion failed: {result.stderr}")
149
+
150
+ # Verify output file exists and has content
151
+ if not os.path.exists(output_file) or os.path.getsize(output_file) == 0:
152
+ raise Exception("Conversion produced empty file")
153
+
154
+ return output_file, f"✅ **Conversion Successful!**\n\nConverted to **{output_format.upper()}** format with **{quality}** quality."
155
+
156
+ except subprocess.TimeoutExpired:
157
+ if os.path.exists(output_file):
158
+ os.unlink(output_file)
159
+ raise gr.Error("⏱️ Conversion timed out. File may be too large or complex.")
160
+ except Exception as e:
161
+ if os.path.exists(output_file):
162
+ os.unlink(output_file)
163
+ raise gr.Error(f"❌ Conversion failed: {str(e)}")
164
+
165
+ def update_format_suggestions(input_file):
166
+ """Update suggested formats based on input file type."""
167
+ if not input_file:
168
+ return gr.Dropdown(choices=ALL_FORMATS, value="mp4")
169
+
170
+ file_ext = Path(input_file).suffix.lower().replace(".", "")
171
+
172
+ # Suggest related formats
173
+ if file_ext in VIDEO_FORMATS:
174
+ suggested = ["mp4", "webm", "avi", "mkv", "mov"]
175
+ elif file_ext in AUDIO_FORMATS:
176
+ suggested = ["mp3", "wav", "aac", "flac", "ogg"]
177
+ elif file_ext in IMAGE_FORMATS:
178
+ suggested = ["jpg", "png", "webp", "gif", "bmp"]
179
+ else:
180
+ suggested = ["mp4", "mp3", "jpg", "png"]
181
+
182
+ # Add all formats but prioritize suggested ones
183
+ all_choices = suggested + [f for f in ALL_FORMATS if f not in suggested]
184
+
185
+ return gr.Dropdown(choices=all_choices, value=suggested[0])
186
+
187
+ # Custom CSS for better UI/UX
188
+ custom_css = """
189
+ .main-container {
190
+ max-width: 1400px;
191
+ margin: 0 auto;
192
+ }
193
 
194
+ .header-section {
195
+ text-align: center;
196
+ padding: 2rem 1rem;
197
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
198
+ border-radius: 12px;
199
+ margin-bottom: 2rem;
200
+ color: white;
201
+ }
202
 
203
+ .header-section h1 {
204
+ font-size: 2.5rem;
205
+ margin-bottom: 0.5rem;
206
+ font-weight: 700;
207
+ }
208
 
209
+ .header-section p {
210
+ font-size: 1.1rem;
211
+ opacity: 0.95;
212
+ }
213
 
214
+ .conversion-panel {
215
+ background: rgba(255, 255, 255, 0.05);
216
+ border-radius: 12px;
217
+ padding: 1.5rem;
218
+ margin-bottom: 1rem;
219
+ }
220
 
221
+ .info-box {
222
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
223
+ border-radius: 8px;
224
+ padding: 1rem;
225
+ margin: 1rem 0;
226
+ }
227
 
228
+ .status-success {
229
+ color: #10b981;
230
+ font-weight: 600;
231
+ }
 
 
 
232
 
233
+ .status-error {
234
+ color: #ef4444;
235
+ font-weight: 600;
236
+ }
 
 
 
 
 
 
 
 
 
 
237
 
238
+ footer {
239
+ text-align: center;
240
+ padding: 2rem;
241
+ margin-top: 2rem;
242
+ opacity: 0.8;
243
+ }
244
 
245
+ .format-badge {
246
+ display: inline-block;
247
+ padding: 0.25rem 0.75rem;
248
+ background: #667eea;
249
+ color: white;
250
+ border-radius: 20px;
251
+ font-size: 0.875rem;
252
+ margin: 0.25rem;
253
+ }
254
+ """
255
+
256
+ # Build the Gradio interface
257
+ with gr.Blocks(fill_height=True) as demo:
258
+ gr.HTML("""
259
+ <div class="header-section">
260
+ <h1>🎬 Universal Media Converter</h1>
261
+ <p>Convert any media file to any format • Support for 60+ formats • Professional quality</p>
262
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: white; text-decoration: none; opacity: 0.9; font-size: 0.9rem;">
263
+ ✨ Built with anycoder
264
+ </a>
265
+ </div>
266
  """)
267
+
268
  with gr.Row():
269
  with gr.Column(scale=1):
270
+ gr.Markdown("### 📤 Input Settings")
271
+
272
  input_file = gr.File(
273
  label="Upload Media File",
274
+ file_types=["video", "audio", "image"],
275
+ type="filepath"
 
 
 
276
  )
277
+
278
+ file_info = gr.Markdown(
279
+ value="*Upload a file to see details*",
280
+ elem_classes="info-box"
281
+ )
282
+
283
+ gr.Markdown("### ⚙️ Conversion Settings")
284
+
285
+ output_format = gr.Dropdown(
286
+ choices=ALL_FORMATS,
287
+ value="mp4",
288
+ label="Output Format",
289
+ info="Select the desired output format"
290
+ )
291
+
292
+ quality = gr.Radio(
293
+ choices=["high", "medium", "low"],
294
+ value="high",
295
+ label="Quality",
296
+ info="Higher quality = larger file size"
297
+ )
298
+
299
+ with gr.Accordion("🎨 Advanced Options", open=False):
300
+ resolution = gr.Dropdown(
301
+ choices=[
302
+ "Original",
303
+ "3840x2160 (4K)",
304
+ "1920x1080 (Full HD)",
305
+ "1280x720 (HD)",
306
+ "854x480 (SD)",
307
+ "640x360"
308
+ ],
309
+ value="Original",
310
+ label="Video Resolution (for video files)",
311
+ info="Resize video to specific resolution"
312
  )
313
+
314
+ convert_btn = gr.Button(
315
+ "🚀 Convert Media",
316
+ variant="primary",
317
+ size="lg"
318
+ )
319
+
320
+ clear_btn = gr.ClearButton(
321
+ components=[input_file, output_format, quality, file_info],
322
+ value="🗑️ Clear All"
323
+ )
324
+
325
  with gr.Column(scale=1):
326
+ gr.Markdown("### 📥 Output")
327
+
328
+ status_message = gr.Markdown(
329
+ value="*Ready to convert your media*",
330
+ elem_classes="info-box"
 
 
331
  )
332
+
333
+ output_file = gr.File(
334
+ label="Converted File",
335
+ type="filepath"
336
+ )
337
+
338
+ gr.Markdown("""
339
+ ### 📋 Supported Formats
340
+
341
+ **Video:** MP4, AVI, MKV, MOV, WebM, FLV, WMV, and more
342
+ **Audio:** MP3, WAV, AAC, FLAC, OGG, M4A, and more
343
+ **Image:** JPG, PNG, GIF, WebP, BMP, TIFF, and more
344
+
345
+ ### ✨ Features
346
+
347
+ - 🎯 60+ format support
348
+ - 🎨 Quality control
349
+ - 📐 Resolution options
350
+ - ⚡ Fast conversion
351
+ - 💾 File info analysis
352
+ """)
353
+
354
+ # Examples section
355
+ gr.Markdown("### 💡 Quick Examples")
356
+ gr.Examples(
357
+ examples=[
358
+ ["example.mp4", "webm", "high"],
359
+ ["example.mp3", "wav", "high"],
360
+ ["example.jpg", "png", "high"],
361
+ ],
362
+ inputs=[input_file, output_format, quality],
363
+ label="Try these examples (files will be created if needed)"
364
  )
365
+
366
+ # Event handlers
367
+ input_file.change(
368
+ fn=get_file_info,
369
+ inputs=[input_file],
370
+ outputs=[file_info]
371
+ )
372
+
373
+ input_file.change(
374
+ fn=update_format_suggestions,
375
+ inputs=[input_file],
376
+ outputs=[output_format]
377
+ )
378
+
379
+ def process_conversion(input_file, output_format, quality, resolution):
380
+ res = None if resolution == "Original" else resolution.split(" ")[0]
381
+ return convert_media(input_file, output_format, quality, res)
382
+
 
 
 
 
383
  convert_btn.click(
384
+ fn=process_conversion,
385
+ inputs=[input_file, output_format, quality, resolution],
386
+ outputs=[output_file, status_message]
 
387
  )
388
 
389
+ if __name__ == "__main__":
390
+ demo.launch(
391
+ theme=gr.themes.Soft(
392
+ primary_hue="indigo",
393
+ secondary_hue="purple",
394
+ neutral_hue="slate",
395
+ font=gr.themes.GoogleFont("Inter"),
396
+ text_size="lg",
397
+ spacing_size="lg",
398
+ radius_size="lg"
399
+ ).set(
400
+ button_primary_background_fill="*primary_600",
401
+ button_primary_background_fill_hover="*primary_700",
402
+ block_title_text_weight="600",
403
+ block_label_text_weight="600",
404
+ ),
405
+ css=custom_css,
406
+ footer_links=[
407
+ {"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}
408
+ ]
409
+ )