Spaces:
Running
Running
ArrcttacsrjksX
commited on
Update app.py
Browse files
app.py
CHANGED
@@ -8,6 +8,9 @@ from huggingface_hub import upload_file
|
|
8 |
from typing import Optional, Tuple, List, Union
|
9 |
import logging
|
10 |
import shutil
|
|
|
|
|
|
|
11 |
|
12 |
# Configure logging
|
13 |
logging.basicConfig(
|
@@ -46,23 +49,48 @@ class ImageToDxfConverter:
|
|
46 |
'temp_debug': output_folder / "_debug.png"
|
47 |
}
|
48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
def convert_image(self,
|
50 |
-
|
51 |
use_lines: bool = False) -> Tuple[Optional[str], Optional[str], List[str]]:
|
52 |
"""Convert image to DXF format."""
|
53 |
try:
|
54 |
# Input validation
|
55 |
-
if not
|
56 |
return None, None, []
|
57 |
|
58 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
output_dir = self._ensure_directory("OutputPDF")
|
60 |
timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
61 |
paths = self._generate_output_paths(output_dir, timestamp)
|
62 |
|
63 |
# Prepare conversion command
|
64 |
command = [
|
65 |
-
f"./{self.executable_path}",
|
66 |
f"--imagePath={image_path}",
|
67 |
f"--outputPath={paths['temp_dxf']}",
|
68 |
f"--debug-output={paths['temp_debug']}"
|
@@ -124,6 +152,13 @@ class ImageToDxfConverter:
|
|
124 |
except Exception as e:
|
125 |
logger.error(f"Upload failed: {str(e)}")
|
126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
return (
|
128 |
str(paths['output_dxf']),
|
129 |
str(paths['debug_png']) if use_lines and os.path.exists(paths['debug_png']) else None,
|
@@ -142,6 +177,7 @@ def create_gradio_interface():
|
|
142 |
gr.Markdown("""
|
143 |
# Image to DXF Converter
|
144 |
Convert your images to DXF format for CAD software.
|
|
|
145 |
""")
|
146 |
|
147 |
with gr.Row():
|
@@ -149,7 +185,8 @@ def create_gradio_interface():
|
|
149 |
image_input = gr.Image(
|
150 |
type="filepath",
|
151 |
label="Input Image",
|
152 |
-
elem_id="image_input"
|
|
|
153 |
)
|
154 |
with gr.Column(scale=1):
|
155 |
use_lines_checkbox = gr.Checkbox(
|
@@ -159,7 +196,8 @@ def create_gradio_interface():
|
|
159 |
)
|
160 |
convert_btn = gr.Button(
|
161 |
"Convert to DXF",
|
162 |
-
variant="primary"
|
|
|
163 |
)
|
164 |
|
165 |
with gr.Row():
|
@@ -172,10 +210,53 @@ def create_gradio_interface():
|
|
172 |
debug_output = gr.Image(
|
173 |
type="filepath",
|
174 |
label="Debug Preview",
|
175 |
-
elem_id="debug_output"
|
|
|
176 |
)
|
177 |
|
178 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
179 |
convert_btn.click(
|
180 |
fn=converter.convert_image,
|
181 |
inputs=[image_input, use_lines_checkbox],
|
@@ -188,9 +269,12 @@ def main():
|
|
188 |
"""Main entry point with proper error handling."""
|
189 |
try:
|
190 |
demo = create_gradio_interface()
|
|
|
191 |
demo.launch(
|
192 |
server_name="0.0.0.0",
|
193 |
-
server_port=7860
|
|
|
|
|
194 |
)
|
195 |
except Exception as e:
|
196 |
logger.critical(f"Application failed to start: {str(e)}")
|
|
|
8 |
from typing import Optional, Tuple, List, Union
|
9 |
import logging
|
10 |
import shutil
|
11 |
+
import base64
|
12 |
+
from PIL import Image
|
13 |
+
import io
|
14 |
|
15 |
# Configure logging
|
16 |
logging.basicConfig(
|
|
|
49 |
'temp_debug': output_folder / "_debug.png"
|
50 |
}
|
51 |
|
52 |
+
def _save_base64_image(self, base64_data: str) -> str:
|
53 |
+
"""Save base64 image data to temporary file."""
|
54 |
+
try:
|
55 |
+
# Extract actual base64 data after comma
|
56 |
+
img_data = base64_data.split(',')[1]
|
57 |
+
img_bytes = base64.b64decode(img_data)
|
58 |
+
|
59 |
+
# Create temporary file
|
60 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_file:
|
61 |
+
temp_file.write(img_bytes)
|
62 |
+
return temp_file.name
|
63 |
+
|
64 |
+
except Exception as e:
|
65 |
+
logger.error(f"Failed to save base64 image: {str(e)}")
|
66 |
+
return None
|
67 |
+
|
68 |
def convert_image(self,
|
69 |
+
image_input: Union[str, None],
|
70 |
use_lines: bool = False) -> Tuple[Optional[str], Optional[str], List[str]]:
|
71 |
"""Convert image to DXF format."""
|
72 |
try:
|
73 |
# Input validation
|
74 |
+
if not image_input:
|
75 |
return None, None, []
|
76 |
|
77 |
+
# Handle base64 data
|
78 |
+
if isinstance(image_input, str) and image_input.startswith('data:image'):
|
79 |
+
temp_image_path = self._save_base64_image(image_input)
|
80 |
+
if not temp_image_path:
|
81 |
+
return None, None, []
|
82 |
+
image_path = temp_image_path
|
83 |
+
else:
|
84 |
+
image_path = image_input
|
85 |
+
|
86 |
+
# Setup output directory
|
87 |
output_dir = self._ensure_directory("OutputPDF")
|
88 |
timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
89 |
paths = self._generate_output_paths(output_dir, timestamp)
|
90 |
|
91 |
# Prepare conversion command
|
92 |
command = [
|
93 |
+
f"./{self.executable_path}",
|
94 |
f"--imagePath={image_path}",
|
95 |
f"--outputPath={paths['temp_dxf']}",
|
96 |
f"--debug-output={paths['temp_debug']}"
|
|
|
152 |
except Exception as e:
|
153 |
logger.error(f"Upload failed: {str(e)}")
|
154 |
|
155 |
+
# Clean up temporary file if it was created from base64
|
156 |
+
if isinstance(image_input, str) and image_input.startswith('data:image'):
|
157 |
+
try:
|
158 |
+
os.unlink(image_path)
|
159 |
+
except Exception as e:
|
160 |
+
logger.error(f"Failed to clean up temporary file: {str(e)}")
|
161 |
+
|
162 |
return (
|
163 |
str(paths['output_dxf']),
|
164 |
str(paths['debug_png']) if use_lines and os.path.exists(paths['debug_png']) else None,
|
|
|
177 |
gr.Markdown("""
|
178 |
# Image to DXF Converter
|
179 |
Convert your images to DXF format for CAD software.
|
180 |
+
Press Ctrl+V to paste image from clipboard.
|
181 |
""")
|
182 |
|
183 |
with gr.Row():
|
|
|
185 |
image_input = gr.Image(
|
186 |
type="filepath",
|
187 |
label="Input Image",
|
188 |
+
elem_id="image_input",
|
189 |
+
height=300
|
190 |
)
|
191 |
with gr.Column(scale=1):
|
192 |
use_lines_checkbox = gr.Checkbox(
|
|
|
196 |
)
|
197 |
convert_btn = gr.Button(
|
198 |
"Convert to DXF",
|
199 |
+
variant="primary",
|
200 |
+
elem_id="convert_btn"
|
201 |
)
|
202 |
|
203 |
with gr.Row():
|
|
|
210 |
debug_output = gr.Image(
|
211 |
type="filepath",
|
212 |
label="Debug Preview",
|
213 |
+
elem_id="debug_output",
|
214 |
+
height=300
|
215 |
)
|
216 |
|
217 |
+
# Thêm JavaScript để xử lý paste từ clipboard
|
218 |
+
demo.load(js="""
|
219 |
+
function setupPasteHandler() {
|
220 |
+
document.addEventListener('paste', async function(e) {
|
221 |
+
e.preventDefault();
|
222 |
+
const items = e.clipboardData.items;
|
223 |
+
|
224 |
+
for (let i = 0; i < items.length; i++) {
|
225 |
+
if (items[i].type.indexOf('image') !== -1) {
|
226 |
+
const blob = items[i].getAsFile();
|
227 |
+
const reader = new FileReader();
|
228 |
+
|
229 |
+
reader.onload = function(event) {
|
230 |
+
const base64data = event.target.result;
|
231 |
+
const imgElement = document.querySelector('#image_input img');
|
232 |
+
if (imgElement) {
|
233 |
+
imgElement.src = base64data;
|
234 |
+
|
235 |
+
// Trigger conversion after image is loaded
|
236 |
+
imgElement.onload = function() {
|
237 |
+
const convertBtn = document.querySelector('#convert_btn');
|
238 |
+
if (convertBtn) {
|
239 |
+
convertBtn.click();
|
240 |
+
}
|
241 |
+
}
|
242 |
+
}
|
243 |
+
};
|
244 |
+
|
245 |
+
reader.readAsDataURL(blob);
|
246 |
+
break;
|
247 |
+
}
|
248 |
+
}
|
249 |
+
});
|
250 |
+
}
|
251 |
+
|
252 |
+
if (document.readyState === 'complete') {
|
253 |
+
setupPasteHandler();
|
254 |
+
} else {
|
255 |
+
window.addEventListener('load', setupPasteHandler);
|
256 |
+
}
|
257 |
+
""")
|
258 |
+
|
259 |
+
# Event handlers
|
260 |
convert_btn.click(
|
261 |
fn=converter.convert_image,
|
262 |
inputs=[image_input, use_lines_checkbox],
|
|
|
269 |
"""Main entry point with proper error handling."""
|
270 |
try:
|
271 |
demo = create_gradio_interface()
|
272 |
+
demo.queue() # Enable queuing for better handling of concurrent requests
|
273 |
demo.launch(
|
274 |
server_name="0.0.0.0",
|
275 |
+
server_port=7860,
|
276 |
+
show_api=False, # Disable API documentation page
|
277 |
+
share=False, # Disable public URL generation
|
278 |
)
|
279 |
except Exception as e:
|
280 |
logger.critical(f"Application failed to start: {str(e)}")
|