bk939448 commited on
Commit
8548929
Β·
verified Β·
1 Parent(s): 80a7313

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +224 -0
app.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import io
3
+ import time
4
+ import requests
5
+ from flask import Flask, request, jsonify, render_template_string
6
+ from PIL import Image, ImageOps
7
+ from huggingface_hub import HfApi
8
+
9
+ app = Flask(__name__)
10
+
11
+ # --- βš™οΈ SECRETS (Environment Variables se aayenge) ---
12
+ HF_TOKEN = os.environ.get("HF_TOKEN")
13
+ HF_REPO = os.environ.get("HF_REPO")
14
+ Image.MAX_IMAGE_PIXELS = None
15
+
16
+ # --- 🧠 SUPER-OPTIMIZER LOGIC ---
17
+ def dynamic_optimize(image_content, level="extreme"):
18
+ """
19
+ Image ko user ke level ke hisab se optimize karta hai.
20
+ Levels: none, extreme, high, medium, low
21
+ """
22
+ # πŸ’Ž NONE MODE: Bina chhue original image wapas kar do
23
+ if level == "none":
24
+ print("πŸš€ Mode: None (Uploading Original Raw Image)")
25
+ return image_content
26
+
27
+ try:
28
+ img = Image.open(io.BytesIO(image_content))
29
+ img = ImageOps.exif_transpose(img) # EXIF data hatao aur sidha karo
30
+
31
+ if img.mode in ("RGBA", "P"):
32
+ img = img.convert("RGB")
33
+
34
+ # πŸŽ›οΈ Settings Dictionary
35
+ settings = {
36
+ "extreme": {"width": 550, "quality": 70, "method": 6, "target_kb": 60},
37
+ "high": {"width": 650, "quality": 80, "method": 5, "target_kb": 90},
38
+ "medium": {"width": 800, "quality": 85, "method": 4, "target_kb": 150},
39
+ "low": {"width": 1000, "quality": 95, "method": 3, "target_kb": 300}
40
+ }
41
+
42
+ # Default fallback 'extreme' par rahega
43
+ conf = settings.get(level, settings["extreme"])
44
+
45
+ # πŸ“ Resize Logic (Lanczos algorithm for best quality)
46
+ if img.width > conf["width"]:
47
+ ratio = conf["width"] / float(img.width)
48
+ new_height = int((float(img.height) * float(ratio)))
49
+ img = img.resize((conf["width"], new_height), Image.Resampling.LANCZOS)
50
+
51
+ # πŸ§ͺ Advanced Compression Loop
52
+ output = io.BytesIO()
53
+ curr_q = conf["quality"]
54
+
55
+ while curr_q > 10:
56
+ output.seek(0)
57
+ output.truncate(0)
58
+ img.save(
59
+ output,
60
+ format='WEBP',
61
+ quality=curr_q,
62
+ method=conf["method"], # ☒️ BEAST MODE COMPRESSION
63
+ optimize=True
64
+ )
65
+ size_kb = output.tell() / 1024
66
+
67
+ if size_kb <= conf["target_kb"]:
68
+ break
69
+ curr_q -= 5 # Dheere-dheere quality girao
70
+
71
+ output.seek(0)
72
+ return output.getvalue()
73
+
74
+ except Exception as e:
75
+ print(f"❌ Optimization Error: {e}")
76
+ return image_content # Agar error aaye to original bhej do
77
+
78
+ # --- 🌐 API ROUTE ---
79
+ @app.route('/upload-poster', methods=['GET'])
80
+ def handle_upload():
81
+ img_url = request.args.get('url')
82
+ comp_level = request.args.get('level', 'extreme').lower()
83
+
84
+ if not img_url:
85
+ return jsonify({"success": False, "error": "No URL provided"}), 400
86
+ if not HF_TOKEN or not HF_REPO:
87
+ return jsonify({"success": False, "error": "HF Secrets missing in Space Settings"}), 500
88
+
89
+ try:
90
+ # 1. Image Download
91
+ resp = requests.get(img_url, timeout=20)
92
+ if resp.status_code != 200:
93
+ return jsonify({"success": False, "error": f"Download failed (Status: {resp.status_code})"}), 400
94
+
95
+ # 2. Process Image
96
+ optimized_data = dynamic_optimize(resp.content, comp_level)
97
+
98
+ # 3. Extension and Stealth Filename Logic
99
+ # Agar mode 'none' hai to original extension rakho, warna 'webp'
100
+ ext = img_url.split('.')[-1].split('?')[0].lower()
101
+ if comp_level != "none" or ext not in ['jpg', 'jpeg', 'png', 'webp', 'gif']:
102
+ ext = "webp"
103
+
104
+ # Random name generation: img_1712345_abc123.webp
105
+ filename = f"img_{int(time.time())}_{os.urandom(3).hex()}.{ext}"
106
+ path_in_repo = f"posters/{filename}"
107
+
108
+ # 4. Upload to Hugging Face
109
+ api = HfApi()
110
+ api.upload_file(
111
+ path_or_fileobj=optimized_data,
112
+ path_in_repo=path_in_repo,
113
+ repo_id=HF_REPO,
114
+ repo_type="dataset",
115
+ token=HF_TOKEN
116
+ )
117
+
118
+ # 5. Generate Direct Link
119
+ final_url = f"https://huggingface.co/datasets/{HF_REPO}/resolve/main/{path_in_repo}"
120
+
121
+ return jsonify({
122
+ "success": True,
123
+ "url": final_url,
124
+ "level_used": comp_level,
125
+ "original_size_kb": round(len(resp.content)/1024, 2),
126
+ "new_size_kb": round(len(optimized_data)/1024, 2)
127
+ })
128
+
129
+ except Exception as e:
130
+ return jsonify({"success": False, "error": str(e)}), 500
131
+
132
+ # --- πŸ–₯️ UI ROUTE (TESTING DASHBOARD) ---
133
+ HTML_UI = """
134
+ <!DOCTYPE html>
135
+ <html lang="en">
136
+ <head>
137
+ <meta charset="UTF-8">
138
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
139
+ <title>HF Poster API | Stealth Mode</title>
140
+ <style>
141
+ body { font-family: 'Courier New', Courier, monospace; background: #0b0f19; color: #00ffcc; padding: 20px; max-width: 800px; margin: auto; }
142
+ .card { background: #111827; padding: 25px; border-radius: 12px; box-shadow: 0 0 20px rgba(0, 255, 204, 0.2); border: 1px solid #1f2937; }
143
+ h2 { color: #fff; border-bottom: 2px solid #00ffcc; padding-bottom: 10px; }
144
+ input, select, button { width: 100%; padding: 14px; margin: 12px 0; border-radius: 8px; border: 1px solid #374151; box-sizing: border-box; font-size: 16px; font-family: 'Courier New', Courier, monospace;}
145
+ input, select { background: #1f2937; color: #fff; outline: none; transition: 0.3s;}
146
+ input:focus, select:focus { border-color: #00ffcc; box-shadow: 0 0 8px rgba(0, 255, 204, 0.5);}
147
+ button { background: #00ffcc; color: #000; font-weight: bold; cursor: pointer; transition: 0.3s; text-transform: uppercase; letter-spacing: 1px;}
148
+ button:hover { background: #00ccaa; box-shadow: 0 0 15px rgba(0, 255, 204, 0.6); }
149
+ button:disabled { background: #374151; color: #9ca3af; cursor: not-allowed; box-shadow: none; }
150
+ #result { margin-top: 25px; padding: 20px; background: rgba(0, 255, 204, 0.1); border-left: 4px solid #00ffcc; border-radius: 5px; display: none; word-wrap: break-word;}
151
+ img { max-width: 100%; border-radius: 8px; margin-top: 15px; border: 1px solid #374151;}
152
+ .stats { display: flex; justify-content: space-between; font-weight: bold; font-size: 15px; margin-top: 15px; color: #fff; background: #1f2937; padding: 10px; border-radius: 5px;}
153
+ .tag { background: #00ffcc; color: #000; padding: 2px 8px; border-radius: 12px; font-size: 12px; font-weight: bold; margin-left: 10px; vertical-align: middle;}
154
+ </style>
155
+ </head>
156
+ <body>
157
+ <div class="card">
158
+ <h2>πŸš€ Skynet Poster API <span class="tag">v3.0</span></h2>
159
+ <input type="text" id="imgUrl" placeholder="πŸ”— Paste Raw Image URL here..." required>
160
+ <select id="level">
161
+ <option value="none">πŸ’Ž None (Original Quality, Bypass Compression)</option>
162
+ <option value="extreme" selected>πŸ‹ Extreme (Max Compression, ~60KB, Method 6)</option>
163
+ <option value="high">🍏 High (~90KB, Method 5)</option>
164
+ <option value="medium">🍎 Medium (~150KB, Method 4)</option>
165
+ <option value="low">πŸ‰ Low (Max Quality, ~300KB, Method 3)</option>
166
+ </select>
167
+ <button onclick="uploadImage()" id="btn">⚑ Execute API Call</button>
168
+
169
+ <div id="result">
170
+ <h3 style="margin:0 0 10px 0; color:#00ffcc;">βœ… Upload Successful!</h3>
171
+ <a id="resLink" href="#" target="_blank" style="color:#60a5fa; text-decoration: none; font-weight: bold;">[View Direct Image]</a>
172
+ <div class="stats">
173
+ <span id="oldSize">Original: -- KB</span>
174
+ <span id="newSize" style="color:#00ffcc;">Compressed: -- KB</span>
175
+ </div>
176
+ <img id="resImg" src="" alt="Compressed Output">
177
+ </div>
178
+ </div>
179
+
180
+ <script>
181
+ async function uploadImage() {
182
+ const btn = document.getElementById('btn');
183
+ const url = document.getElementById('imgUrl').value;
184
+ const level = document.getElementById('level').value;
185
+ const resDiv = document.getElementById('result');
186
+
187
+ if(!url) { alert("Bhai, URL to daal! πŸ˜‚"); return; }
188
+
189
+ btn.innerText = "⏳ Processing (HF CPUs are crushing pixels...)";
190
+ btn.disabled = true;
191
+ resDiv.style.display = "none";
192
+
193
+ try {
194
+ const response = await fetch(`/upload-poster?url=${encodeURIComponent(url)}&level=${level}`);
195
+ const data = await response.json();
196
+
197
+ if(data.success) {
198
+ document.getElementById('resLink').href = data.url;
199
+ document.getElementById('resLink').innerText = data.url;
200
+ document.getElementById('resImg').src = data.url;
201
+ document.getElementById('oldSize').innerText = `Original: ${data.original_size_kb} KB`;
202
+ document.getElementById('newSize').innerText = `New: ${data.new_size_kb} KB`;
203
+ resDiv.style.display = "block";
204
+ } else {
205
+ alert("❌ Error: " + data.error);
206
+ }
207
+ } catch (err) {
208
+ alert("❌ Network Error! Is the Space awake?");
209
+ }
210
+ btn.innerText = "⚑ Execute API Call";
211
+ btn.disabled = false;
212
+ }
213
+ </script>
214
+ </body>
215
+ </html>
216
+ """
217
+
218
+ @app.route('/')
219
+ def index():
220
+ return render_template_string(HTML_UI)
221
+
222
+ if __name__ == '__main__':
223
+ # Docker/HF Spaces uses port 7860
224
+ app.run(host='0.0.0.0', port=7860)