kacapower commited on
Commit
2b0b869
·
verified ·
1 Parent(s): 530709c

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +90 -0
main.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+ from fastapi import FastAPI, UploadFile, File, Form, HTTPException
4
+ from fastapi.responses import FileResponse
5
+ from tempfile import NamedTemporaryFile
6
+ import uvicorn
7
+
8
+ app = FastAPI(title="Universal File Converter API")
9
+
10
+ # ---------------------------------------------------------
11
+ # The 300+ Format Routing Dictionary
12
+ # Expand this dictionary to include all 300 extensions you need.
13
+ # ---------------------------------------------------------
14
+ CONVERSION_ENGINES = {
15
+ # Documents -> LibreOffice
16
+ 'pdf': 'libreoffice', 'docx': 'libreoffice', 'odt': 'libreoffice', 'xlsx': 'libreoffice', 'pptx': 'libreoffice',
17
+
18
+ # Images -> ImageMagick
19
+ 'jpg': 'imagemagick', 'png': 'imagemagick', 'webp': 'imagemagick', 'gif': 'imagemagick', 'bmp': 'imagemagick',
20
+
21
+ # Media -> FFmpeg
22
+ 'mp4': 'ffmpeg', 'mp3': 'ffmpeg', 'wav': 'ffmpeg', 'avi': 'ffmpeg', 'mkv': 'ffmpeg', 'flac': 'ffmpeg',
23
+
24
+ # Text & Markup -> Pandoc
25
+ 'html': 'pandoc', 'md': 'pandoc', 'rst': 'pandoc', 'epub': 'pandoc', 'tex': 'pandoc'
26
+ }
27
+
28
+ def execute_conversion(input_path: str, output_path: str, target_ext: str):
29
+ """Routes the file to the correct system engine based on the target extension."""
30
+ engine = CONVERSION_ENGINES.get(target_ext)
31
+
32
+ if not engine:
33
+ raise ValueError(f"Target format '{target_ext}' is not mapped to an engine.")
34
+
35
+ # Construct the specific CLI command
36
+ if engine == 'libreoffice':
37
+ out_dir = os.path.dirname(output_path)
38
+ cmd = ['soffice', '--headless', '--convert-to', target_ext, '--outdir', out_dir, input_path]
39
+
40
+ elif engine == 'imagemagick':
41
+ cmd = ['magick', input_path, output_path]
42
+
43
+ elif engine == 'ffmpeg':
44
+ # -y overwrites output files without asking
45
+ cmd = ['ffmpeg', '-y', '-i', input_path, output_path]
46
+
47
+ elif engine == 'pandoc':
48
+ cmd = ['pandoc', input_path, '-o', output_path]
49
+
50
+ try:
51
+ # Execute the command and capture any errors
52
+ subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
53
+ except subprocess.CalledProcessError as e:
54
+ raise RuntimeError(f"Engine Error: {e.stderr.decode('utf-8')}")
55
+
56
+ @app.post("/convert")
57
+ async def convert_file(
58
+ file: UploadFile = File(...),
59
+ target_format: str = Form(...)
60
+ ):
61
+ target_format = target_format.lower().strip('.')
62
+
63
+ # Extract original extension safely
64
+ filename_parts = file.filename.rsplit('.', 1)
65
+ input_ext = filename_parts[-1] if len(filename_parts) > 1 else "tmp"
66
+ base_name = filename_parts[0] if len(filename_parts) > 1 else "file"
67
+
68
+ # Write the uploaded file to a temporary location
69
+ with NamedTemporaryFile(delete=False, suffix=f".{input_ext}") as tmp_in:
70
+ tmp_in.write(await file.read())
71
+ input_path = tmp_in.name
72
+
73
+ # Define the output path in the same temporary directory
74
+ output_path = input_path.rsplit('.', 1)[0] + f".{target_format}"
75
+
76
+ try:
77
+ execute_conversion(input_path, output_path, target_format)
78
+
79
+ # Return the file to the frontend space
80
+ return FileResponse(
81
+ path=output_path,
82
+ filename=f"{base_name}_converted.{target_format}",
83
+ media_type='application/octet-stream'
84
+ )
85
+ except Exception as e:
86
+ raise HTTPException(status_code=500, detail=str(e))
87
+
88
+ if __name__ == "__main__":
89
+ # Hugging Face binds the Space to 0.0.0.0:7860
90
+ uvicorn.run(app, host="0.0.0.0", port=7860)