Spaces:
Runtime error
Runtime error
sanjay7178
commited on
Commit
•
e972367
1
Parent(s):
26c4ccc
Upload 3 files
Browse files- Dockerfile.txt +17 -0
- app.py +254 -0
- requirements.txt +21 -0
Dockerfile.txt
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11
|
2 |
+
|
3 |
+
RUN useradd -m -u 1000 user
|
4 |
+
USER user
|
5 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
6 |
+
|
7 |
+
WORKDIR /app
|
8 |
+
|
9 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
10 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
11 |
+
RUN sudo apt-get update
|
12 |
+
RUN sudo apt-get install python3-pypdf2
|
13 |
+
|
14 |
+
COPY --chown=user . /app
|
15 |
+
EXPOSE 7860
|
16 |
+
|
17 |
+
CMD ["python", "app.py"]
|
app.py
ADDED
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import cv2
|
3 |
+
import numpy as np
|
4 |
+
from PIL import Image, ImageDraw
|
5 |
+
import ffmpeg
|
6 |
+
import gradio as gr
|
7 |
+
from tqdm import tqdm
|
8 |
+
import zstandard as zstd
|
9 |
+
import brotli
|
10 |
+
import torch
|
11 |
+
import torchvision.transforms as transforms
|
12 |
+
from torch.nn import functional as F
|
13 |
+
import cupy as cp
|
14 |
+
import io
|
15 |
+
import mimetypes
|
16 |
+
from pydub import AudioSegment
|
17 |
+
from PyPDF2 import PdfFileReader, PdfFileWriter
|
18 |
+
import docx
|
19 |
+
import openpyxl
|
20 |
+
|
21 |
+
class GPUAcceleratedCompressionToolkit:
|
22 |
+
def __init__(self):
|
23 |
+
self.supported_formats = {
|
24 |
+
'image': ['.jpg', '.jpeg', '.png', '.bmp', '.tiff'],
|
25 |
+
'video': ['.mp4', '.avi', '.mov', '.mkv'],
|
26 |
+
'audio': ['.mp3', '.wav', '.ogg', '.flac'],
|
27 |
+
'document': ['.txt', '.pdf', '.doc', '.docx'],
|
28 |
+
'spreadsheet': ['.xlsx', '.xls', '.csv']
|
29 |
+
}
|
30 |
+
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
31 |
+
|
32 |
+
def detect_file_type(self, file_path):
|
33 |
+
mime_type, _ = mimetypes.guess_type(file_path)
|
34 |
+
if mime_type:
|
35 |
+
type_category = mime_type.split('/')[0]
|
36 |
+
if type_category in ['image', 'video', 'audio']:
|
37 |
+
return type_category
|
38 |
+
elif type_category == 'application':
|
39 |
+
if mime_type in ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']:
|
40 |
+
return 'document'
|
41 |
+
elif mime_type in ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']:
|
42 |
+
return 'spreadsheet'
|
43 |
+
return 'other'
|
44 |
+
|
45 |
+
def compress_image(self, input_path, output_path, compression_level, use_gpu=False, output_format='original'):
|
46 |
+
img = Image.open(input_path)
|
47 |
+
original_format = img.format if img.format else 'JPEG'
|
48 |
+
|
49 |
+
if output_format == 'original':
|
50 |
+
save_format = original_format
|
51 |
+
else:
|
52 |
+
save_format = output_format.upper()
|
53 |
+
|
54 |
+
quality = int(compression_level)
|
55 |
+
|
56 |
+
if use_gpu:
|
57 |
+
tensor = transforms.ToTensor()(img).unsqueeze(0).to(self.device)
|
58 |
+
|
59 |
+
compressed = F.interpolate(tensor, scale_factor=quality/100, mode='bilinear', align_corners=False)
|
60 |
+
compressed = F.interpolate(compressed, size=tensor.shape[2:], mode='bilinear', align_corners=False)
|
61 |
+
|
62 |
+
result = transforms.ToPILImage()(compressed.squeeze(0).cpu())
|
63 |
+
result.save(output_path, format=save_format, quality=quality)
|
64 |
+
else:
|
65 |
+
img.save(output_path, format=save_format, quality=quality)
|
66 |
+
|
67 |
+
def compress_video(self, input_path, output_path, compression_level, use_gpu=False, output_format=None):
|
68 |
+
if use_gpu:
|
69 |
+
vcodec = 'h264_nvenc'
|
70 |
+
else:
|
71 |
+
vcodec = 'libx264'
|
72 |
+
|
73 |
+
crf = int(100 - compression_level) # Invert the scale for CRF
|
74 |
+
|
75 |
+
if output_format is None:
|
76 |
+
output_format = os.path.splitext(input_path)[1][1:]
|
77 |
+
|
78 |
+
(
|
79 |
+
ffmpeg
|
80 |
+
.input(input_path)
|
81 |
+
.output(output_path, vcodec=vcodec, crf=str(crf), acodec='aac', **{'preset': 'slow'})
|
82 |
+
.overwrite_output()
|
83 |
+
.run(capture_stdout=True, capture_stderr=True)
|
84 |
+
)
|
85 |
+
|
86 |
+
def compress_audio(self, input_path, output_path, compression_level, output_format=None):
|
87 |
+
if output_format is None:
|
88 |
+
output_format = os.path.splitext(input_path)[1][1:]
|
89 |
+
|
90 |
+
bitrate = f"{int(compression_level * 3.2)}k" # Scale compression_level to bitrate
|
91 |
+
|
92 |
+
audio = AudioSegment.from_file(input_path)
|
93 |
+
audio.export(output_path, format=output_format, bitrate=bitrate)
|
94 |
+
|
95 |
+
def compress_document(self, input_path, output_path, compression_level, output_format=None):
|
96 |
+
if output_format is None:
|
97 |
+
output_format = os.path.splitext(input_path)[1][1:]
|
98 |
+
|
99 |
+
if output_format == 'pdf':
|
100 |
+
with open(input_path, 'rb') as file:
|
101 |
+
reader = PdfFileReader(file)
|
102 |
+
writer = PdfFileWriter()
|
103 |
+
for page in range(reader.getNumPages()):
|
104 |
+
page = reader.getPage(page)
|
105 |
+
page.compressContentStreams() # This is CPU intensive!
|
106 |
+
writer.addPage(page)
|
107 |
+
with open(output_path, 'wb') as output_file:
|
108 |
+
writer.write(output_file)
|
109 |
+
elif output_format in ['doc', 'docx']:
|
110 |
+
doc = docx.Document(input_path)
|
111 |
+
doc.save(output_path)
|
112 |
+
else:
|
113 |
+
# For other document types, use generic file compression
|
114 |
+
self.compress_file_gpu(input_path, output_path, compression_level)
|
115 |
+
|
116 |
+
def compress_spreadsheet(self, input_path, output_path, compression_level, output_format=None):
|
117 |
+
if output_format is None:
|
118 |
+
output_format = os.path.splitext(input_path)[1][1:]
|
119 |
+
|
120 |
+
wb = openpyxl.load_workbook(input_path)
|
121 |
+
wb.save(output_path)
|
122 |
+
|
123 |
+
def compress_file_gpu(self, input_path, output_path, compression_level):
|
124 |
+
level = int(compression_level / 10) # Scale compression_level to Zstandard level
|
125 |
+
|
126 |
+
with open(input_path, 'rb') as f_in:
|
127 |
+
data = f_in.read()
|
128 |
+
|
129 |
+
d_data = cp.asarray(bytearray(data))
|
130 |
+
cctx = zstd.ZstdCompressor(level=level)
|
131 |
+
d_compressed = cp.asarray(bytearray(cctx.compress(d_data.get())))
|
132 |
+
compressed = d_compressed.get().tobytes()
|
133 |
+
|
134 |
+
with open(output_path, 'wb') as f_out:
|
135 |
+
f_out.write(compressed)
|
136 |
+
|
137 |
+
def batch_compress_gpu(self, input_files, output_dir, use_gpu, output_format, compression_level):
|
138 |
+
if not os.path.exists(output_dir):
|
139 |
+
os.makedirs(output_dir)
|
140 |
+
|
141 |
+
results = []
|
142 |
+
for file in tqdm(input_files):
|
143 |
+
input_path = file.name
|
144 |
+
file_type = self.detect_file_type(input_path)
|
145 |
+
|
146 |
+
# Determine output format and path
|
147 |
+
if output_format == 'original':
|
148 |
+
_, ext = os.path.splitext(input_path)
|
149 |
+
output_path = os.path.join(output_dir, f"compressed_{os.path.basename(input_path)}")
|
150 |
+
else:
|
151 |
+
output_path = os.path.join(output_dir, f"compressed_{os.path.splitext(os.path.basename(input_path))[0]}.{output_format}")
|
152 |
+
|
153 |
+
if file_type == 'image':
|
154 |
+
self.compress_image(input_path, output_path, compression_level, use_gpu=use_gpu, output_format=output_format)
|
155 |
+
elif file_type == 'video':
|
156 |
+
self.compress_video(input_path, output_path, compression_level, use_gpu=use_gpu, output_format=output_format if output_format != 'original' else None)
|
157 |
+
elif file_type == 'audio':
|
158 |
+
self.compress_audio(input_path, output_path, compression_level, output_format=output_format if output_format != 'original' else None)
|
159 |
+
elif file_type == 'document':
|
160 |
+
self.compress_document(input_path, output_path, compression_level, output_format=output_format if output_format != 'original' else None)
|
161 |
+
elif file_type == 'spreadsheet':
|
162 |
+
self.compress_spreadsheet(input_path, output_path, compression_level, output_format=output_format if output_format != 'original' else None)
|
163 |
+
else:
|
164 |
+
self.compress_file_gpu(input_path, output_path, compression_level)
|
165 |
+
|
166 |
+
results.append(output_path)
|
167 |
+
|
168 |
+
return results
|
169 |
+
|
170 |
+
def real_time_preview_gpu(self, input_path, compression_level, use_gpu=False):
|
171 |
+
file_type = self.detect_file_type(input_path)
|
172 |
+
|
173 |
+
if file_type == 'image':
|
174 |
+
img = Image.open(input_path)
|
175 |
+
if use_gpu:
|
176 |
+
tensor = transforms.ToTensor()(img).unsqueeze(0).to(self.device)
|
177 |
+
tensor = F.interpolate(tensor, size=(300, 300), mode='bilinear', align_corners=False)
|
178 |
+
compressed = F.interpolate(tensor, scale_factor=compression_level/100, mode='bilinear', align_corners=False)
|
179 |
+
compressed = F.interpolate(compressed, size=tensor.shape[2:], mode='bilinear', align_corners=False)
|
180 |
+
result = transforms.ToPILImage()(compressed.squeeze(0).cpu())
|
181 |
+
else:
|
182 |
+
img = img.resize((300, 300))
|
183 |
+
buffer = io.BytesIO()
|
184 |
+
img.save(buffer, format='JPEG', quality=int(compression_level))
|
185 |
+
buffer.seek(0)
|
186 |
+
result = Image.open(buffer)
|
187 |
+
return result
|
188 |
+
elif file_type == 'video':
|
189 |
+
video = cv2.VideoCapture(input_path)
|
190 |
+
ret, frame = video.read()
|
191 |
+
if ret:
|
192 |
+
if use_gpu:
|
193 |
+
d_frame = cp.asarray(frame)
|
194 |
+
d_frame = cp.resize(d_frame, (300, 300))
|
195 |
+
_, d_buffer = cv2.imencode('.jpg', cp.asnumpy(d_frame), [cv2.IMWRITE_JPEG_QUALITY, int(compression_level)])
|
196 |
+
else:
|
197 |
+
frame = cv2.resize(frame, (300, 300))
|
198 |
+
_, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, int(compression_level)])
|
199 |
+
return Image.open(io.BytesIO(buffer.tobytes()))
|
200 |
+
elif file_type in ['audio', 'document', 'spreadsheet', 'other']:
|
201 |
+
placeholder = Image.new('RGB', (300, 300), color='lightgray')
|
202 |
+
draw = ImageDraw.Draw(placeholder)
|
203 |
+
draw.text((10, 150), f"{file_type.capitalize()} Preview\nNot Available", fill='black')
|
204 |
+
return placeholder
|
205 |
+
|
206 |
+
return None
|
207 |
+
|
208 |
+
def gradio_interface(toolkit):
|
209 |
+
def process_files(files, use_gpu, output_format, compression_level):
|
210 |
+
output_dir = "compressed_output"
|
211 |
+
return toolkit.batch_compress_gpu(files, output_dir, use_gpu, output_format, compression_level)
|
212 |
+
|
213 |
+
def update_preview(file, compression_level, use_gpu):
|
214 |
+
if file is None:
|
215 |
+
return None
|
216 |
+
return toolkit.real_time_preview_gpu(file.name, compression_level, use_gpu)
|
217 |
+
|
218 |
+
iface = gr.Interface(
|
219 |
+
fn=process_files,
|
220 |
+
inputs=[
|
221 |
+
gr.File(label="Input Files", file_count="multiple"),
|
222 |
+
gr.Checkbox(label="Use GPU Acceleration"),
|
223 |
+
gr.Dropdown(
|
224 |
+
choices=["original", "jpg", "png", "mp4", "mp3", "pdf", "docx", "xlsx"],
|
225 |
+
label="Output Format",
|
226 |
+
value="original"
|
227 |
+
),
|
228 |
+
gr.Slider(1, 100, 50, step=1, label="Compression Level")
|
229 |
+
],
|
230 |
+
outputs=gr.File(label="Compressed Files", file_count="multiple"),
|
231 |
+
title="GPU-Accelerated Compression Toolkit",
|
232 |
+
description="Drag and drop files for compression of images, videos, audio, documents, spreadsheets, and other files. File type is automatically detected.",
|
233 |
+
allow_flagging="never"
|
234 |
+
)
|
235 |
+
|
236 |
+
preview = gr.Interface(
|
237 |
+
fn=update_preview,
|
238 |
+
inputs=[
|
239 |
+
gr.File(label="Input File"),
|
240 |
+
gr.Slider(1, 100, 50, step=1, label="Compression Level"),
|
241 |
+
gr.Checkbox(label="Use GPU Acceleration")
|
242 |
+
],
|
243 |
+
outputs=gr.Image(label="Preview"),
|
244 |
+
title="Real-time Compression Preview",
|
245 |
+
live=True,
|
246 |
+
allow_flagging="never"
|
247 |
+
)
|
248 |
+
|
249 |
+
return gr.TabbedInterface([iface, preview], ["Compress", "Preview"])
|
250 |
+
|
251 |
+
if __name__ == "__main__":
|
252 |
+
toolkit = GPUAcceleratedCompressionToolkit()
|
253 |
+
interface = gradio_interface(toolkit)
|
254 |
+
interface.launch(share=True)
|
requirements.txt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Automatically generated by https://github.com/damnever/pigar.
|
2 |
+
|
3 |
+
Brotli==1.1.0
|
4 |
+
cupy-cuda12x==13.3.0
|
5 |
+
ffmpeg==1.4
|
6 |
+
gradio==4.44.0
|
7 |
+
numpy==1.24.4
|
8 |
+
openpyxl==3.1.5
|
9 |
+
Pillow==9.4.0
|
10 |
+
pydub==0.25.1
|
11 |
+
python-docx==1.1.2
|
12 |
+
torch
|
13 |
+
torchvision
|
14 |
+
tqdm==4.66.5
|
15 |
+
zstandard==0.23.0
|
16 |
+
python-docx
|
17 |
+
|
18 |
+
|
19 |
+
opencv-contrib-python==4.10.0.84
|
20 |
+
opencv-python==4.10.0.84
|
21 |
+
#opencv-python-headless==4.10.0.84
|