Spaces:
Sleeping
Sleeping
Upload app_english.py
Browse files- app_english.py +257 -0
app_english.py
ADDED
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
# -*- coding: utf-8 -*-
|
3 |
+
import os, sys, shutil, subprocess, tempfile, uuid
|
4 |
+
from pathlib import Path
|
5 |
+
import gradio as gr
|
6 |
+
|
7 |
+
# Import font installation function
|
8 |
+
from install_fonts import install_fonts_from_repository
|
9 |
+
|
10 |
+
BASE_DIR = Path(__file__).parent.resolve()
|
11 |
+
BINARY_PATH = BASE_DIR / "PptxToJpgZip"
|
12 |
+
os.chmod(BINARY_PATH, 0o755) # Ignore exceptions
|
13 |
+
|
14 |
+
def _safe_name() -> str:
|
15 |
+
"""Generate ASCII-only temporary filename"""
|
16 |
+
return f"input_{uuid.uuid4().hex}.pptx"
|
17 |
+
|
18 |
+
def convert_pptx_to_zip(pptx_file) -> str:
|
19 |
+
"""Call PptxToJpgZip to convert PPTX to JPG images ZIP; auto-zip if only folder exists."""
|
20 |
+
tmpdir = Path(tempfile.mkdtemp())
|
21 |
+
src = tmpdir / _safe_name()
|
22 |
+
shutil.copy(pptx_file.name, src)
|
23 |
+
|
24 |
+
# Call external executable
|
25 |
+
proc = subprocess.run(
|
26 |
+
[str(BINARY_PATH), str(src)],
|
27 |
+
cwd=tmpdir,
|
28 |
+
stdout=subprocess.PIPE,
|
29 |
+
stderr=subprocess.PIPE,
|
30 |
+
)
|
31 |
+
if proc.returncode != 0:
|
32 |
+
raise RuntimeError(
|
33 |
+
f"PptxToJpgZip failed with exit code {proc.returncode}\n"
|
34 |
+
f"stderr:\n{proc.stderr.decode(errors='ignore')}"
|
35 |
+
)
|
36 |
+
|
37 |
+
# ---- β Priority: find *_images.zip ----
|
38 |
+
zips = list(tmpdir.glob("*_images.zip"))
|
39 |
+
if zips:
|
40 |
+
return str(zips[0])
|
41 |
+
|
42 |
+
# ---- β‘ If no ZIP, find *_images directory and auto-package ----
|
43 |
+
img_dirs = [p for p in tmpdir.glob("*_images") if p.is_dir()]
|
44 |
+
if img_dirs:
|
45 |
+
folder = img_dirs[0]
|
46 |
+
zip_path = folder.with_suffix(".zip") # <name>_images.zip
|
47 |
+
shutil.make_archive(zip_path.with_suffix(""), "zip", folder)
|
48 |
+
return str(zip_path)
|
49 |
+
|
50 |
+
# ---- β’ Still not found: list tmpdir contents for debugging ----
|
51 |
+
contents = "\n".join([" β’ " + p.name for p in tmpdir.iterdir()])
|
52 |
+
raise FileNotFoundError(
|
53 |
+
"Output ZIP not found, and no *_images folder discovered.\n"
|
54 |
+
f"Temporary directory contents:\n{contents}"
|
55 |
+
)
|
56 |
+
|
57 |
+
# ----------------- Enhanced Gradio UI with English Interface ----------------- #
|
58 |
+
with gr.Blocks(
|
59 |
+
title="PPTX to JPG ZIP Converter",
|
60 |
+
theme=gr.themes.Soft(),
|
61 |
+
css="""
|
62 |
+
.download-btn {
|
63 |
+
background: linear-gradient(45deg, #4CAF50, #45a049) !important;
|
64 |
+
color: white !important;
|
65 |
+
font-weight: bold !important;
|
66 |
+
font-size: 16px !important;
|
67 |
+
padding: 12px 24px !important;
|
68 |
+
border-radius: 8px !important;
|
69 |
+
border: none !important;
|
70 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.2) !important;
|
71 |
+
transition: all 0.3s ease !important;
|
72 |
+
}
|
73 |
+
.download-btn:hover {
|
74 |
+
background: linear-gradient(45deg, #45a049, #4CAF50) !important;
|
75 |
+
transform: translateY(-2px) !important;
|
76 |
+
box-shadow: 0 6px 12px rgba(0,0,0,0.3) !important;
|
77 |
+
}
|
78 |
+
.main-container {
|
79 |
+
max-width: 800px;
|
80 |
+
margin: 0 auto;
|
81 |
+
padding: 20px;
|
82 |
+
}
|
83 |
+
.header-section {
|
84 |
+
text-align: center;
|
85 |
+
margin-bottom: 30px;
|
86 |
+
padding: 20px;
|
87 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
88 |
+
border-radius: 12px;
|
89 |
+
color: white;
|
90 |
+
}
|
91 |
+
.instructions-section {
|
92 |
+
background: #f8f9fa;
|
93 |
+
padding: 20px;
|
94 |
+
border-radius: 8px;
|
95 |
+
margin-bottom: 20px;
|
96 |
+
border-left: 4px solid #007bff;
|
97 |
+
}
|
98 |
+
"""
|
99 |
+
) as demo:
|
100 |
+
|
101 |
+
with gr.Column(elem_classes="main-container"):
|
102 |
+
# Header Section
|
103 |
+
with gr.Column(elem_classes="header-section"):
|
104 |
+
gr.Markdown(
|
105 |
+
"""
|
106 |
+
# π― PPTX to JPG ZIP Converter
|
107 |
+
### Transform your PowerPoint presentations into high-quality JPG images
|
108 |
+
**Fast β’ Reliable β’ Easy to Use**
|
109 |
+
""",
|
110 |
+
elem_classes="header-content"
|
111 |
+
)
|
112 |
+
|
113 |
+
# Instructions Section
|
114 |
+
with gr.Column(elem_classes="instructions-section"):
|
115 |
+
gr.Markdown(
|
116 |
+
"""
|
117 |
+
## π How to Use
|
118 |
+
|
119 |
+
**Step 1:** Click "Upload PPTX File" and select your PowerPoint presentation (.pptx)
|
120 |
+
|
121 |
+
**Step 2:** Click "π Convert to JPG ZIP" to start the conversion process
|
122 |
+
|
123 |
+
**Step 3:** Wait for processing to complete (usually takes 10-30 seconds)
|
124 |
+
|
125 |
+
**Step 4:** Click the green "π₯ Download ZIP" button to get your converted images
|
126 |
+
|
127 |
+
### β¨ Features
|
128 |
+
- **High Quality**: Converts each slide to crisp JPG images
|
129 |
+
- **Batch Processing**: All slides converted in one go
|
130 |
+
- **ZIP Package**: Convenient download as a single ZIP file
|
131 |
+
- **Font Support**: Automatic font installation for better rendering
|
132 |
+
"""
|
133 |
+
)
|
134 |
+
|
135 |
+
# Main Conversion Interface
|
136 |
+
gr.Markdown("## π Conversion Interface")
|
137 |
+
|
138 |
+
with gr.Row():
|
139 |
+
with gr.Column(scale=2):
|
140 |
+
pptx_input = gr.File(
|
141 |
+
label="π Upload PPTX File",
|
142 |
+
file_types=[".pptx"],
|
143 |
+
elem_id="pptx_upload"
|
144 |
+
)
|
145 |
+
with gr.Column(scale=1):
|
146 |
+
convert_btn = gr.Button(
|
147 |
+
"π Convert to JPG ZIP",
|
148 |
+
variant="primary",
|
149 |
+
size="lg",
|
150 |
+
elem_id="convert_button"
|
151 |
+
)
|
152 |
+
|
153 |
+
# Download Section
|
154 |
+
gr.Markdown("## π₯ Download Results")
|
155 |
+
|
156 |
+
with gr.Row():
|
157 |
+
with gr.Column(scale=2):
|
158 |
+
zip_output = gr.File(
|
159 |
+
label="π¦ Converted ZIP File",
|
160 |
+
elem_id="zip_output"
|
161 |
+
)
|
162 |
+
with gr.Column(scale=1):
|
163 |
+
download_btn = gr.Button(
|
164 |
+
"π₯ Download ZIP",
|
165 |
+
variant="secondary",
|
166 |
+
size="lg",
|
167 |
+
elem_classes="download-btn",
|
168 |
+
elem_id="download_button"
|
169 |
+
)
|
170 |
+
|
171 |
+
# Status Section
|
172 |
+
with gr.Row():
|
173 |
+
status_text = gr.Textbox(
|
174 |
+
label="π Status",
|
175 |
+
interactive=False,
|
176 |
+
value="π Please upload a PPTX file to begin conversion...",
|
177 |
+
elem_id="status_display"
|
178 |
+
)
|
179 |
+
|
180 |
+
# Footer Section
|
181 |
+
gr.Markdown(
|
182 |
+
"""
|
183 |
+
---
|
184 |
+
### π‘ Tips
|
185 |
+
- **Supported Format**: Only .pptx files (PowerPoint 2007+)
|
186 |
+
- **File Size**: Works best with files under 100MB
|
187 |
+
- **Processing Time**: Depends on slide count and complexity
|
188 |
+
- **Output**: High-resolution JPG images (300 DPI)
|
189 |
+
|
190 |
+
### π§ Technical Info
|
191 |
+
- **Engine**: PptxToJpgZip binary converter
|
192 |
+
- **Image Format**: JPG (JPEG)
|
193 |
+
- **Compression**: ZIP archive
|
194 |
+
- **Font Rendering**: Enhanced with system fonts
|
195 |
+
""",
|
196 |
+
elem_classes="footer-info"
|
197 |
+
)
|
198 |
+
|
199 |
+
# Event Handlers
|
200 |
+
def process_conversion(pptx_file):
|
201 |
+
if pptx_file is None:
|
202 |
+
return None, "β Please upload a PPTX file first"
|
203 |
+
|
204 |
+
try:
|
205 |
+
# Update status
|
206 |
+
yield None, "π Processing your PPTX file..."
|
207 |
+
|
208 |
+
# Perform conversion
|
209 |
+
result_zip = convert_pptx_to_zip(pptx_file)
|
210 |
+
|
211 |
+
# Success
|
212 |
+
yield result_zip, "β
Conversion completed successfully! Click 'Download ZIP' to get your files."
|
213 |
+
|
214 |
+
except Exception as e:
|
215 |
+
yield None, f"β Conversion failed: {str(e)}"
|
216 |
+
|
217 |
+
def handle_download(zip_file):
|
218 |
+
"""Handle download button - create a new downloadable file"""
|
219 |
+
if zip_file and hasattr(zip_file, 'name') and os.path.exists(zip_file.name):
|
220 |
+
return gr.File(value=zip_file.name), "π₯ Download started! File will be downloaded automatically."
|
221 |
+
elif zip_file and isinstance(zip_file, str) and os.path.exists(zip_file):
|
222 |
+
return gr.File(value=zip_file), "π₯ Download started! File will be downloaded automatically."
|
223 |
+
else:
|
224 |
+
return None, "β No file available for download. Please convert a file first."
|
225 |
+
|
226 |
+
# Connect events
|
227 |
+
convert_btn.click(
|
228 |
+
fn=process_conversion,
|
229 |
+
inputs=[pptx_input],
|
230 |
+
outputs=[zip_output, status_text],
|
231 |
+
show_progress=True
|
232 |
+
)
|
233 |
+
|
234 |
+
# Download button - creates a downloadable file output
|
235 |
+
download_output = gr.File(label="Download", visible=False)
|
236 |
+
|
237 |
+
download_btn.click(
|
238 |
+
fn=handle_download,
|
239 |
+
inputs=[zip_output],
|
240 |
+
outputs=[download_output, status_text],
|
241 |
+
show_progress=False
|
242 |
+
)
|
243 |
+
|
244 |
+
if __name__ == "__main__":
|
245 |
+
# Install fonts before starting the application
|
246 |
+
print("π§ Installing fonts for better rendering...")
|
247 |
+
install_fonts_from_repository()
|
248 |
+
print("β
Font installation completed!")
|
249 |
+
|
250 |
+
print("π Starting PPTX to JPG ZIP Converter...")
|
251 |
+
demo.launch(
|
252 |
+
server_name="0.0.0.0",
|
253 |
+
server_port=7860,
|
254 |
+
share=False,
|
255 |
+
show_error=True,
|
256 |
+
quiet=False
|
257 |
+
)
|