James040 commited on
Commit
fc6d4ea
·
verified ·
1 Parent(s): 4b15234

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -20
app.py CHANGED
@@ -1,25 +1,141 @@
1
- import gradio as gr
 
2
  from rembg import remove, new_session
3
  from PIL import Image
4
 
5
- # 1. Initialize the session once (Optimization)
6
  session = new_session("u2net")
 
 
7
 
8
- def remove_background(input_image):
9
- if input_image is None:
10
- return None
11
- # 2. Process the image
12
- result = remove(input_image, session=session)
13
- return result
14
-
15
- # 3. Create the Interface
16
- demo = gr.Interface(
17
- fn=remove_background,
18
- inputs=gr.Image(type="pil", label="Upload Image"),
19
- outputs=gr.Image(type="pil", label="Transparent Result"),
20
- title="AI Background Remover",
21
- description="High-speed background removal optimized for CPU."
22
- )
23
-
24
- # 4. Enable Queuing (This is the "Secret Sauce" for high traffic)
25
- demo.queue(default_concurrency_limit=1).launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, uuid, zipfile, shutil, cv2, json
2
+ from flask import Flask, request, send_file, render_template_string, jsonify
3
  from rembg import remove, new_session
4
  from PIL import Image
5
 
6
+ app = Flask(__name__)
7
  session = new_session("u2net")
8
+ JOBS_DIR = "jobs"
9
+ os.makedirs(JOBS_DIR, exist_ok=True)
10
 
11
+ HTML = """
12
+ <!DOCTYPE html>
13
+ <html>
14
+ <head>
15
+ <title>Xlnk Video Processor</title>
16
+ <style>
17
+ body { background: #0b0f19; color: white; font-family: sans-serif; text-align: center; padding: 20px; }
18
+ .container { max-width: 500px; margin: auto; border: 1px solid #334155; padding: 30px; border-radius: 10px; background: #111827; }
19
+ .progress-box { display: none; margin-top: 20px; }
20
+ #progressBar { width: 100%; background: #374151; border-radius: 5px; height: 20px; overflow: hidden; }
21
+ #progressFill { width: 0%; height: 100%; background: #3b82f6; transition: width 0.3s; }
22
+ .btn { background: #3b82f6; color: white; border: none; padding: 12px 24px; border-radius: 5px; cursor: pointer; }
23
+ </style>
24
+ </head>
25
+ <body>
26
+ <div class="container">
27
+ <h2>Video BG Remover</h2>
28
+ <form id="uploadForm">
29
+ <input type="file" id="videoFile" accept="video/*" required><br><br>
30
+ <button type="submit" class="btn" id="btn">Upload & Process</button>
31
+ </form>
32
+
33
+ <div class="progress-box" id="pbox">
34
+ <p id="statusTxt">Uploading...</p>
35
+ <div id="progressBar"><div id="progressFill"></div></div>
36
+ </div>
37
+ </div>
38
+
39
+ <script>
40
+ const form = document.getElementById('uploadForm');
41
+ let jobId = "";
42
+
43
+ form.onsubmit = async (e) => {
44
+ e.preventDefault();
45
+ document.getElementById('btn').style.display = 'none';
46
+ document.getElementById('pbox').style.display = 'block';
47
+
48
+ const formData = new FormData();
49
+ formData.append('video', document.getElementById('videoFile').files[0]);
50
+
51
+ // Start the process
52
+ const response = await fetch('/upload', { method: 'POST', body: formData });
53
+ const data = await response.json();
54
+ jobId = data.job_id;
55
+
56
+ // Start polling for progress
57
+ const interval = setInterval(async () => {
58
+ const res = await fetch(`/status/${jobId}`);
59
+ const status = await res.json();
60
+
61
+ if (status.percent) {
62
+ document.getElementById('progressFill').style.width = status.percent + '%';
63
+ document.getElementById('statusTxt').innerText = `Processing: ${status.current}/${status.total} frames`;
64
+ }
65
+
66
+ if (status.status === "completed") {
67
+ clearInterval(interval);
68
+ window.location.href = `/download/${jobId}`;
69
+ }
70
+ }, 2000);
71
+ };
72
+ </script>
73
+ </body>
74
+ </html>
75
+ """
76
+
77
+ @app.route("/")
78
+ def index(): return render_template_string(HTML)
79
+
80
+ @app.route("/upload", methods=["POST"])
81
+ def upload():
82
+ file = request.files['video']
83
+ job_id = str(uuid.uuid4())
84
+ path = os.path.join(JOBS_DIR, job_id)
85
+ os.makedirs(os.path.join(path, "frames"), exist_ok=True)
86
+
87
+ video_path = os.path.join(path, "input.mp4")
88
+ file.save(video_path)
89
+
90
+ # Save initial status
91
+ with open(os.path.join(path, "status.json"), "w") as f:
92
+ json.dump({"status": "processing", "current": 0, "total": 0, "percent": 0}, f)
93
+
94
+ # In a real app, we'd use a background thread here.
95
+ # For a simple HF Space, we'll process it in the route but
96
+ # update the file so the frontend can read it.
97
+ process_video(job_id, video_path, path)
98
+ return jsonify({"job_id": job_id})
99
+
100
+ def process_video(job_id, video_path, workspace):
101
+ cap = cv2.VideoCapture(video_path)
102
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
103
+ frames_dir = os.path.join(workspace, "frames")
104
+
105
+ count = 0
106
+ while cap.isOpened():
107
+ ret, frame = cap.read()
108
+ if not ret: break
109
+
110
+ output = remove(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), session=session)
111
+ Image.fromarray(output).save(os.path.join(frames_dir, f"f_{count:04d}.png"))
112
+ count += 1
113
+
114
+ # Update status file every 5 frames to save disk I/O
115
+ if count % 5 == 0 or count == total_frames:
116
+ with open(os.path.join(workspace, "status.json"), "w") as f:
117
+ json.dump({"status": "processing", "current": count, "total": total_frames, "percent": int((count/total_frames)*100)}, f)
118
+
119
+ cap.release()
120
+ # Zip it up
121
+ zip_path = os.path.join(JOBS_DIR, f"{job_id}.zip")
122
+ with zipfile.ZipFile(zip_path, 'w') as z:
123
+ for f in os.listdir(frames_dir):
124
+ z.write(os.path.join(frames_dir, f), f)
125
+
126
+ with open(os.path.join(workspace, "status.json"), "w") as f:
127
+ json.dump({"status": "completed"}, f)
128
+
129
+ @app.route("/status/<job_id>")
130
+ def status(job_id):
131
+ try:
132
+ with open(os.path.join(JOBS_DIR, job_id, "status.json"), "r") as f:
133
+ return jsonify(json.load(f))
134
+ except: return jsonify({"status": "not_found"})
135
+
136
+ @app.route("/download/<job_id>")
137
+ def download(job_id):
138
+ return send_file(os.path.join(JOBS_DIR, f"{job_id}.zip"), as_attachment=True)
139
+
140
+ if __name__ == "__main__":
141
+ app.run(host="0.0.0.0", port=7860)