Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
@@ -54,93 +54,19 @@ app.layout = dbc.Container([
|
|
54 |
], className="my-3"),
|
55 |
dbc.Button("Split PDF", id='split-button', color="primary", className="mt-3", disabled=True),
|
56 |
dbc.Progress(id='progress-bar', className="my-3"),
|
57 |
-
dbc.Spinner(html.Div(id='processing-spinner'), color="primary", type="grow"),
|
58 |
dbc.Button("Download ZIP", id='download-button', color="success", className="mt-3", disabled=True),
|
59 |
dcc.Download(id="download-zip"),
|
60 |
html.Div(id='log-output', style={'whiteSpace': 'pre-line'}),
|
61 |
], fluid=True)
|
62 |
|
63 |
-
|
64 |
-
Output('pdf-name', 'children'),
|
65 |
-
Output('split-button', 'disabled'),
|
66 |
-
Input('upload-pdf', 'contents'),
|
67 |
-
State('upload-pdf', 'filename')
|
68 |
-
)
|
69 |
-
def update_output(contents, filename):
|
70 |
-
if contents is not None:
|
71 |
-
logger.info(f"PDF file uploaded: {filename}")
|
72 |
-
return f"Selected file: {filename}", False
|
73 |
-
return "No file selected", True
|
74 |
-
|
75 |
-
@callback(
|
76 |
-
Output('ranges-container', 'children'),
|
77 |
-
Input('add-range', 'n_clicks'),
|
78 |
-
Input({'type': 'remove-range', 'index': ALL}, 'n_clicks'),
|
79 |
-
State('ranges-container', 'children'),
|
80 |
-
prevent_initial_call=True
|
81 |
-
)
|
82 |
-
def manage_ranges(add_clicks, remove_clicks, existing_ranges):
|
83 |
-
ctx = dash.callback_context
|
84 |
-
triggered_id = ctx.triggered[0]['prop_id'].split('.')[0]
|
85 |
-
|
86 |
-
if triggered_id == 'add-range':
|
87 |
-
logger.info("Adding new range input")
|
88 |
-
new_index = len(existing_ranges)
|
89 |
-
new_range = dbc.Row([
|
90 |
-
dbc.Col(dbc.Input(id={'type': 'range-input', 'index': new_index}, type='text', placeholder='Enter page range (e.g., 1-3)'), width=10),
|
91 |
-
dbc.Col(dbc.Button("Remove", id={'type': 'remove-range', 'index': new_index}, color="danger", size="sm"), width=2),
|
92 |
-
], className="mb-2")
|
93 |
-
existing_ranges.append(new_range)
|
94 |
-
elif 'remove-range' in triggered_id:
|
95 |
-
remove_index = json.loads(triggered_id)['index']
|
96 |
-
logger.info(f"Removing range input at index {remove_index}")
|
97 |
-
existing_ranges = [range for range in existing_ranges if json.loads(range['props']['children'][1]['props']['children']['props']['id'])['index'] != remove_index]
|
98 |
-
|
99 |
-
return existing_ranges
|
100 |
-
|
101 |
-
def process_pdf(contents, filename, ranges):
|
102 |
-
global generated_file, progress
|
103 |
-
progress = 0
|
104 |
-
logger.info(f"Starting PDF processing for file: {filename}")
|
105 |
-
|
106 |
-
try:
|
107 |
-
content_type, content_string = contents.split(',')
|
108 |
-
decoded = base64.b64decode(content_string)
|
109 |
-
pdf = PdfReader(io.BytesIO(decoded))
|
110 |
-
logger.info(f"PDF loaded successfully. Total pages: {len(pdf.pages)}")
|
111 |
-
|
112 |
-
writers = []
|
113 |
-
for range_str in ranges:
|
114 |
-
start, end = map(int, range_str.split('-'))
|
115 |
-
logger.info(f"Processing range: {start}-{end}")
|
116 |
-
writer = PdfWriter()
|
117 |
-
for i in range(start - 1, min(end, len(pdf.pages))):
|
118 |
-
writer.add_page(pdf.pages[i])
|
119 |
-
writers.append(writer)
|
120 |
-
|
121 |
-
zip_buffer = io.BytesIO()
|
122 |
-
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zf:
|
123 |
-
for i, writer in enumerate(writers):
|
124 |
-
progress = (i + 1) / len(writers) * 100
|
125 |
-
logger.info(f"Creating split PDF {i+1}/{len(writers)}")
|
126 |
-
pdf_buffer = io.BytesIO()
|
127 |
-
writer.write(pdf_buffer)
|
128 |
-
pdf_buffer.seek(0)
|
129 |
-
zf.writestr(f"split_{i+1}.pdf", pdf_buffer.getvalue())
|
130 |
-
|
131 |
-
zip_buffer.seek(0)
|
132 |
-
generated_file = zip_buffer.getvalue()
|
133 |
-
progress = 100
|
134 |
-
logger.info("PDF processing completed successfully")
|
135 |
-
except Exception as e:
|
136 |
-
logger.error(f"Error processing PDF: {str(e)}", exc_info=True)
|
137 |
-
progress = -1
|
138 |
|
139 |
@callback(
|
140 |
Output('progress-bar', 'value'),
|
141 |
Output('download-button', 'disabled'),
|
142 |
Output('log-output', 'children'),
|
143 |
-
Output('processing-spinner', 'children'),
|
144 |
Input('split-button', 'n_clicks'),
|
145 |
State('upload-pdf', 'contents'),
|
146 |
State('upload-pdf', 'filename'),
|
@@ -165,7 +91,7 @@ def split_pdf(n_clicks, contents, filename, ranges):
|
|
165 |
Output('progress-bar', 'value', allow_duplicate=True),
|
166 |
Output('download-button', 'disabled', allow_duplicate=True),
|
167 |
Output('log-output', 'children', allow_duplicate=True),
|
168 |
-
Output('processing-spinner', 'children', allow_duplicate=True),
|
169 |
Input('progress-bar', 'value'),
|
170 |
prevent_initial_call=True
|
171 |
)
|
@@ -176,7 +102,7 @@ def update_progress(value):
|
|
176 |
return 100, False, "PDF splitting completed. Click 'Download ZIP' to get your files.", ""
|
177 |
elif progress == -1:
|
178 |
logger.error("PDF splitting failed")
|
179 |
-
return 0,
|
180 |
else:
|
181 |
return progress, True, f"Processing... {progress:.0f}% complete", "Processing..."
|
182 |
|
|
|
54 |
], className="my-3"),
|
55 |
dbc.Button("Split PDF", id='split-button', color="primary", className="mt-3", disabled=True),
|
56 |
dbc.Progress(id='progress-bar', className="my-3"),
|
57 |
+
dbc.Spinner(html.Div(id='processing-spinner'), color="primary", type="grow"),
|
58 |
dbc.Button("Download ZIP", id='download-button', color="success", className="mt-3", disabled=True),
|
59 |
dcc.Download(id="download-zip"),
|
60 |
html.Div(id='log-output', style={'whiteSpace': 'pre-line'}),
|
61 |
], fluid=True)
|
62 |
|
63 |
+
# ... (keep all other callbacks and functions as they were) ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
@callback(
|
66 |
Output('progress-bar', 'value'),
|
67 |
Output('download-button', 'disabled'),
|
68 |
Output('log-output', 'children'),
|
69 |
+
Output('processing-spinner', 'children'),
|
70 |
Input('split-button', 'n_clicks'),
|
71 |
State('upload-pdf', 'contents'),
|
72 |
State('upload-pdf', 'filename'),
|
|
|
91 |
Output('progress-bar', 'value', allow_duplicate=True),
|
92 |
Output('download-button', 'disabled', allow_duplicate=True),
|
93 |
Output('log-output', 'children', allow_duplicate=True),
|
94 |
+
Output('processing-spinner', 'children', allow_duplicate=True),
|
95 |
Input('progress-bar', 'value'),
|
96 |
prevent_initial_call=True
|
97 |
)
|
|
|
102 |
return 100, False, "PDF splitting completed. Click 'Download ZIP' to get your files.", ""
|
103 |
elif progress == -1:
|
104 |
logger.error("PDF splitting failed")
|
105 |
+
return 0, False, "Error occurred during PDF splitting. Check console for details.", ""
|
106 |
else:
|
107 |
return progress, True, f"Processing... {progress:.0f}% complete", "Processing..."
|
108 |
|