ArrcttacsrjksX commited on
Commit
3bcc021
·
verified ·
1 Parent(s): 6ebda09

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -233
app.py CHANGED
@@ -7,9 +7,7 @@ from pathlib import Path
7
  from huggingface_hub import upload_file
8
  from typing import Optional, Tuple, List, Union
9
  import logging
10
- from functools import partial
11
  import shutil
12
- import sys
13
 
14
  # Configure logging
15
  logging.basicConfig(
@@ -21,47 +19,17 @@ logger = logging.getLogger(__name__)
21
  class ImageToDxfConverter:
22
  def __init__(self):
23
  """Initialize the converter with configuration."""
24
- self.executable_path = self._find_executable()
 
25
  self.hf_token = os.getenv("HF_TOKEN")
26
  self.repo_id = "ArrcttacsrjksX/ImageToAutocadData"
27
 
28
- # Validate HF token
29
- if not self.hf_token:
30
- logger.warning("HF_TOKEN environment variable not set")
31
-
32
- def _find_executable(self) -> Optional[Path]:
33
- """Find the converter executable in various possible locations."""
34
- possible_paths = [
35
- Path("./SimpleImageToDxfHavePass"),
36
- Path("./SimpleImageToDxfHavePass.exe"),
37
- Path("/app/SimpleImageToDxfHavePass"), # Common Docker path
38
- Path(os.path.dirname(os.path.abspath(__file__))) / "SimpleImageToDxfHavePass",
39
- Path.home() / "SimpleImageToDxfHavePass"
40
- ]
41
-
42
- # Add system PATH locations
43
- if sys.platform == "win32":
44
- if "PATH" in os.environ:
45
- for path in os.environ["PATH"].split(os.pathsep):
46
- possible_paths.append(Path(path) / "SimpleImageToDxfHavePass.exe")
47
- else:
48
- for path in ["/usr/local/bin", "/usr/bin", "/bin"]:
49
- possible_paths.append(Path(path) / "SimpleImageToDxfHavePass")
50
-
51
- for path in possible_paths:
52
- if path.exists():
53
- try:
54
- # Make executable on Unix-like systems
55
- if sys.platform != "win32":
56
- path.chmod(path.stat().st_mode | 0o111)
57
- logger.info(f"Found executable at: {path}")
58
- return path
59
- except Exception as e:
60
- logger.warning(f"Found executable at {path} but couldn't set permissions: {e}")
61
- continue
62
-
63
- logger.error("SimpleImageToDxfHavePass executable not found in any standard location")
64
- return None
65
 
66
  def _ensure_directory(self, path: Union[str, Path]) -> Path:
67
  """Ensure directory exists and return Path object."""
@@ -78,76 +46,15 @@ class ImageToDxfConverter:
78
  'temp_debug': output_folder / "_debug.png"
79
  }
80
 
81
- def _execute_conversion(self, command_args: List[str]) -> subprocess.CompletedProcess:
82
- """Execute the conversion command with proper error handling."""
83
- if not self.executable_path:
84
- raise RuntimeError(
85
- "SimpleImageToDxfHavePass executable not found. Please ensure it's installed "
86
- "and available in your system PATH or in the same directory as the script."
87
- )
88
-
89
- try:
90
- # Add executable verification step
91
- if not os.access(str(self.executable_path), os.X_OK) and sys.platform != "win32":
92
- logger.warning(f"Setting executable permissions for {self.executable_path}")
93
- os.chmod(str(self.executable_path), 0o755)
94
-
95
- result = subprocess.run(
96
- command_args,
97
- check=True,
98
- capture_output=True,
99
- text=True
100
- )
101
- logger.info(f"Conversion output: {result.stdout}")
102
- return result
103
- except subprocess.CalledProcessError as e:
104
- error_msg = f"Conversion failed: {e.stderr}"
105
- logger.error(error_msg)
106
- raise RuntimeError(error_msg)
107
- except Exception as e:
108
- error_msg = f"Unexpected error during conversion: {str(e)}"
109
- logger.error(error_msg)
110
- raise RuntimeError(error_msg)
111
-
112
- def _upload_to_huggingface(self,
113
- file_path: Path,
114
- date_folder: str,
115
- filename: str) -> Optional[str]:
116
- """Upload a file to Hugging Face with error handling."""
117
- if not self.hf_token:
118
- return None
119
-
120
- try:
121
- repo_path = f"datasets/{self.repo_id}/{date_folder}/{filename}"
122
- uploaded_file = upload_file(
123
- path_or_fileobj=str(file_path),
124
- path_in_repo=repo_path,
125
- repo_id=self.repo_id,
126
- token=self.hf_token
127
- )
128
- logger.info(f"Successfully uploaded {filename}")
129
- return uploaded_file
130
- except Exception as e:
131
- logger.error(f"Failed to upload {filename}: {str(e)}")
132
- return None
133
-
134
  def convert_image(self,
135
  image_path: Optional[str],
136
  output_folder: Optional[str] = None,
137
  use_lines: bool = False) -> Tuple[Optional[str], Optional[str], List[str]]:
138
- """
139
- Convert image to DXF format with improved error handling and logging.
140
- """
141
  try:
142
  # Input validation
143
  if not image_path:
144
- raise ValueError("No image provided")
145
-
146
- if not self.executable_path:
147
- raise RuntimeError(
148
- "SimpleImageToDxfHavePass executable not found. Please ensure it's installed "
149
- "and available in your system PATH or in the same directory as the script."
150
- )
151
 
152
  # Setup output directory
153
  output_dir = self._ensure_directory(output_folder if output_folder else tempfile.mkdtemp())
@@ -155,166 +62,138 @@ class ImageToDxfConverter:
155
  paths = self._generate_output_paths(output_dir, timestamp)
156
 
157
  # Prepare conversion command
158
- command_args = [
159
- str(self.executable_path),
160
  f"--imagePath={image_path}",
161
  f"--outputPath={paths['temp_dxf']}",
162
  f"--debug-output={paths['temp_debug']}"
163
  ]
164
  if use_lines:
165
- command_args.append("--use-lines")
166
 
167
  # Execute conversion
168
- self._execute_conversion(command_args)
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  # Move temporary files to final locations
171
  shutil.move(paths['temp_dxf'], paths['output_dxf'])
172
- if use_lines:
173
  shutil.move(paths['temp_debug'], paths['debug_png'])
174
 
175
  # Upload files to Hugging Face
176
  uploaded_files = []
177
- date_folder = timestamp
178
-
179
- # Upload input image
180
- if uploaded_input := self._upload_to_huggingface(
181
- Path(image_path),
182
- date_folder,
183
- Path(image_path).name
184
- ):
185
- uploaded_files.append(uploaded_input)
186
-
187
- # Upload DXF output
188
- if uploaded_dxf := self._upload_to_huggingface(
189
- paths['output_dxf'],
190
- date_folder,
191
- paths['output_dxf'].name
192
- ):
193
- uploaded_files.append(uploaded_dxf)
194
-
195
- # Upload debug image if available
196
- if use_lines and (uploaded_debug := self._upload_to_huggingface(
197
- paths['debug_png'],
198
- date_folder,
199
- paths['debug_png'].name
200
- )):
201
- uploaded_files.append(uploaded_debug)
 
 
 
 
 
 
 
 
202
 
203
  return (
204
  str(paths['output_dxf']),
205
- str(paths['debug_png']) if use_lines else None,
206
  uploaded_files
207
  )
208
 
209
  except Exception as e:
210
- logger.error(f"Conversion failed: {str(e)}")
211
- return str(e), None, []
 
212
 
213
  def create_gradio_interface():
214
  """Create and configure the Gradio interface."""
215
  converter = ImageToDxfConverter()
216
 
217
- # Early validation of executable
218
- if not converter.executable_path:
219
- logger.error("No valid executable found - interface will show error message")
220
-
221
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
222
- with gr.Tabs():
223
- with gr.TabItem("Image to DXF"):
224
- if not converter.executable_path:
225
- gr.Markdown("""
226
- # ⚠️ System Configuration Error
227
-
228
- The SimpleImageToDxfHavePass executable was not found. Please ensure:
229
- 1. The executable is in the same directory as this script
230
- 2. The executable has proper permissions
231
- 3. The executable is available in your system PATH
232
-
233
- Check the logs for more details.
234
- """)
235
- else:
236
- gr.Markdown("""
237
- # Image to DXF Converter
238
- Convert your images to DXF format for CAD software.
239
- """)
240
-
241
- with gr.Row():
242
- with gr.Column(scale=2):
243
- image_input = gr.Image(
244
- type="filepath",
245
- label="Input Image",
246
- elem_id="image_input"
247
- )
248
- with gr.Column(scale=1):
249
- output_folder = gr.Textbox(
250
- label="Output Folder (optional)",
251
- placeholder="Leave blank for temporary folder",
252
- elem_id="output_folder"
253
- )
254
- use_lines_checkbox = gr.Checkbox(
255
- label="Enable line detection",
256
- value=False,
257
- elem_id="use_lines"
258
- )
259
- convert_btn = gr.Button(
260
- "Convert to DXF",
261
- variant="primary",
262
- elem_id="convert_btn",
263
- interactive=bool(converter.executable_path)
264
- )
265
-
266
- with gr.Row():
267
- with gr.Column():
268
- dxf_output = gr.File(
269
- label="DXF Output",
270
- elem_id="dxf_output"
271
- )
272
- with gr.Column():
273
- debug_output = gr.Image(
274
- type="filepath",
275
- label="Debug Preview",
276
- elem_id="debug_output"
277
- )
278
-
279
- # Add error message display
280
- error_output = gr.Textbox(
281
- label="Status",
282
- interactive=False,
283
- visible=True,
284
- elem_id="error_output"
285
  )
286
 
287
- with gr.TabItem("About"):
288
- gr.Markdown("""
289
- ## Image to DXF Converter
290
-
291
- This application converts images to DXF format using the SimpleImageToDxfHavePass tool.
292
-
293
- ### Features:
294
- - Supports PNG and JPG input formats
295
- - Optional line detection mode
296
- - Debug preview output
297
- - Automatic file organization
298
- - Hugging Face integration for result sharing
299
-
300
- ### Usage:
301
- 1. Upload an image
302
- 2. (Optional) Specify output folder
303
- 3. Toggle line detection if needed
304
- 4. Click Convert
305
-
306
- ### System Requirements:
307
- - SimpleImageToDxfHavePass executable must be available
308
- - Proper file permissions
309
- - HF_TOKEN environment variable for Hugging Face integration
310
- """)
311
 
312
- # Setup event handlers
313
  convert_btn.click(
314
  fn=converter.convert_image,
315
  inputs=[image_input, output_folder, use_lines_checkbox],
316
- outputs=[error_output, debug_output, dxf_output],
317
- api_name="convert"
318
  )
319
 
320
  return demo
@@ -322,12 +201,10 @@ def create_gradio_interface():
322
  def main():
323
  """Main entry point with proper error handling."""
324
  try:
325
- # Create and launch the interface
326
  demo = create_gradio_interface()
327
  demo.launch(
328
  server_name="0.0.0.0",
329
- server_port=7860,
330
- show_error=True
331
  )
332
  except Exception as e:
333
  logger.critical(f"Application failed to start: {str(e)}")
 
7
  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(
 
19
  class ImageToDxfConverter:
20
  def __init__(self):
21
  """Initialize the converter with configuration."""
22
+ # For Hugging Face Spaces, executable should be in the root directory
23
+ self.executable_path = Path("SimpleImageToDxfHavePass")
24
  self.hf_token = os.getenv("HF_TOKEN")
25
  self.repo_id = "ArrcttacsrjksX/ImageToAutocadData"
26
 
27
+ # Make executable file executable (Hugging Face Spaces specific)
28
+ try:
29
+ os.chmod(self.executable_path, 0o755)
30
+ logger.info(f"Set executable permissions for {self.executable_path}")
31
+ except Exception as e:
32
+ logger.error(f"Failed to set executable permissions: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  def _ensure_directory(self, path: Union[str, Path]) -> Path:
35
  """Ensure directory exists and return Path object."""
 
46
  'temp_debug': output_folder / "_debug.png"
47
  }
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def convert_image(self,
50
  image_path: Optional[str],
51
  output_folder: Optional[str] = None,
52
  use_lines: bool = False) -> Tuple[Optional[str], Optional[str], List[str]]:
53
+ """Convert image to DXF format."""
 
 
54
  try:
55
  # Input validation
56
  if not image_path:
57
+ return "No image provided", None, []
 
 
 
 
 
 
58
 
59
  # Setup output directory
60
  output_dir = self._ensure_directory(output_folder if output_folder else tempfile.mkdtemp())
 
62
  paths = self._generate_output_paths(output_dir, timestamp)
63
 
64
  # Prepare conversion command
65
+ command = [
66
+ f"./{self.executable_path}", # Use relative path with ./
67
  f"--imagePath={image_path}",
68
  f"--outputPath={paths['temp_dxf']}",
69
  f"--debug-output={paths['temp_debug']}"
70
  ]
71
  if use_lines:
72
+ command.append("--use-lines")
73
 
74
  # Execute conversion
75
+ try:
76
+ result = subprocess.run(
77
+ command,
78
+ check=True,
79
+ capture_output=True,
80
+ text=True
81
+ )
82
+ logger.info(f"Conversion output: {result.stdout}")
83
+ except subprocess.CalledProcessError as e:
84
+ error_msg = f"Conversion failed: {e.stderr}"
85
+ logger.error(error_msg)
86
+ return error_msg, None, []
87
 
88
  # Move temporary files to final locations
89
  shutil.move(paths['temp_dxf'], paths['output_dxf'])
90
+ if use_lines and os.path.exists(paths['temp_debug']):
91
  shutil.move(paths['temp_debug'], paths['debug_png'])
92
 
93
  # Upload files to Hugging Face
94
  uploaded_files = []
95
+ if self.hf_token:
96
+ try:
97
+ date_folder = timestamp
98
+
99
+ # Upload input image
100
+ uploaded_input = upload_file(
101
+ path_or_fileobj=image_path,
102
+ path_in_repo=f"datasets/{self.repo_id}/{date_folder}/{Path(image_path).name}",
103
+ repo_id=self.repo_id,
104
+ token=self.hf_token
105
+ )
106
+ uploaded_files.append(uploaded_input)
107
+
108
+ # Upload DXF output
109
+ uploaded_dxf = upload_file(
110
+ path_or_fileobj=str(paths['output_dxf']),
111
+ path_in_repo=f"datasets/{self.repo_id}/{date_folder}/{paths['output_dxf'].name}",
112
+ repo_id=self.repo_id,
113
+ token=self.hf_token
114
+ )
115
+ uploaded_files.append(uploaded_dxf)
116
+
117
+ # Upload debug image if available
118
+ if use_lines and os.path.exists(paths['debug_png']):
119
+ uploaded_debug = upload_file(
120
+ path_or_fileobj=str(paths['debug_png']),
121
+ path_in_repo=f"datasets/{self.repo_id}/{date_folder}/{paths['debug_png'].name}",
122
+ repo_id=self.repo_id,
123
+ token=self.hf_token
124
+ )
125
+ uploaded_files.append(uploaded_debug)
126
+ except Exception as e:
127
+ logger.error(f"Upload failed: {str(e)}")
128
 
129
  return (
130
  str(paths['output_dxf']),
131
+ str(paths['debug_png']) if use_lines and os.path.exists(paths['debug_png']) else None,
132
  uploaded_files
133
  )
134
 
135
  except Exception as e:
136
+ error_msg = f"Conversion failed: {str(e)}"
137
+ logger.error(error_msg)
138
+ return error_msg, None, []
139
 
140
  def create_gradio_interface():
141
  """Create and configure the Gradio interface."""
142
  converter = ImageToDxfConverter()
143
 
 
 
 
 
144
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
145
+ gr.Markdown("""
146
+ # Image to DXF Converter
147
+ Convert your images to DXF format for CAD software.
148
+ """)
149
+
150
+ with gr.Row():
151
+ with gr.Column(scale=2):
152
+ image_input = gr.Image(
153
+ type="filepath",
154
+ label="Input Image",
155
+ elem_id="image_input"
156
+ )
157
+ with gr.Column(scale=1):
158
+ output_folder = gr.Textbox(
159
+ label="Output Folder (optional)",
160
+ placeholder="Leave blank for temporary folder",
161
+ elem_id="output_folder"
162
+ )
163
+ use_lines_checkbox = gr.Checkbox(
164
+ label="Enable line detection",
165
+ value=False,
166
+ elem_id="use_lines"
167
+ )
168
+ convert_btn = gr.Button(
169
+ "Convert to DXF",
170
+ variant="primary"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  )
172
 
173
+ with gr.Row():
174
+ with gr.Column():
175
+ dxf_output = gr.File(
176
+ label="DXF Output",
177
+ elem_id="dxf_output"
178
+ )
179
+ with gr.Column():
180
+ debug_output = gr.Image(
181
+ type="filepath",
182
+ label="Debug Preview",
183
+ elem_id="debug_output"
184
+ )
185
+
186
+ status_output = gr.Textbox(
187
+ label="Status",
188
+ value="Ready",
189
+ interactive=False
190
+ )
 
 
 
 
 
 
191
 
192
+ # Event handler
193
  convert_btn.click(
194
  fn=converter.convert_image,
195
  inputs=[image_input, output_folder, use_lines_checkbox],
196
+ outputs=[dxf_output, debug_output, status_output]
 
197
  )
198
 
199
  return demo
 
201
  def main():
202
  """Main entry point with proper error handling."""
203
  try:
 
204
  demo = create_gradio_interface()
205
  demo.launch(
206
  server_name="0.0.0.0",
207
+ server_port=7860
 
208
  )
209
  except Exception as e:
210
  logger.critical(f"Application failed to start: {str(e)}")