-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathapp.py
More file actions
104 lines (80 loc) · 3.28 KB
/
app.py
File metadata and controls
104 lines (80 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"""
Flask API for PDF flattening and compression.
"""
import os
import tempfile
import uuid
from pathlib import Path
from flask import Flask, render_template, request, send_file, jsonify
from werkzeug.utils import secure_filename
from spool_optimizer import DocumentSpoolOptimizer
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 100 * 1024 * 1024 # 100 MB
app.config["UPLOAD_FOLDER"] = tempfile.gettempdir()
ALLOWED_EXTENSIONS = {"pdf"}
def allowed_file(filename: str) -> bool:
return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route("/")
def index():
return render_template("index.html")
@app.route("/api/process", methods=["POST"])
def process_pdf():
if "file" not in request.files:
return jsonify({"error": "No file provided"}), 400
file = request.files["file"]
if file.filename == "":
return jsonify({"error": "No file selected"}), 400
if not allowed_file(file.filename):
return jsonify({"error": "Only PDF files are allowed"}), 400
dpi = request.form.get("dpi", 100, type=int)
dpi = max(72, min(300, dpi))
workers = request.form.get("workers", 0, type=int)
workers = max(0, workers)
# In a web-server context cap unconstrained (0) requests to half the
# available cores so concurrent uploads don't saturate the machine.
if workers == 0:
workers = max(1, (os.cpu_count() or 2) // 2)
job_id = str(uuid.uuid4())
input_path = Path(app.config["UPLOAD_FOLDER"]) / f"{job_id}_input.pdf"
output_path = Path(app.config["UPLOAD_FOLDER"]) / f"{job_id}_output.pdf"
try:
file.save(input_path)
optimizer = DocumentSpoolOptimizer(dpi=dpi, workers=workers)
success = optimizer.process_document(input_path, output_path)
input_path.unlink(missing_ok=True)
if not success:
output_path.unlink(missing_ok=True)
return jsonify({"error": "Failed to process PDF. The file may be corrupted, password-protected, or invalid."}), 422
return jsonify({
"success": True,
"download_id": job_id,
"original_name": secure_filename(file.filename),
})
except MemoryError:
input_path.unlink(missing_ok=True)
output_path.unlink(missing_ok=True)
return jsonify({"error": "File is too large to process. Insufficient memory."}), 413
except Exception as e:
input_path.unlink(missing_ok=True)
output_path.unlink(missing_ok=True)
return jsonify({"error": f"An unexpected error occurred: {str(e)}"}), 500
@app.route("/api/download/<job_id>")
def download_pdf(job_id):
output_path = Path(app.config["UPLOAD_FOLDER"]) / f"{job_id}_output.pdf"
if not output_path.exists():
return jsonify({"error": "File not found or expired"}), 404
try:
return send_file(
output_path,
as_attachment=True,
download_name="flattened.pdf",
mimetype="application/pdf",
)
finally:
output_path.unlink(missing_ok=True)
if __name__ == "__main__":
import os
host = os.environ.get("FLASK_HOST", "127.0.0.1")
port = int(os.environ.get("FLASK_PORT", 5000))
debug = os.environ.get("FLASK_ENV", "development") != "production"
app.run(host=host, port=port, debug=debug)