tonyassi commited on
Commit
edb11e5
Β·
verified Β·
1 Parent(s): 3f2a8c9

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +209 -14
app.py CHANGED
@@ -18,31 +18,226 @@ assert insightface.__version__ >= '0.7'
18
  app = FaceAnalysis(name='buffalo_l')
19
  app.prepare(ctx_id=0, det_size=(640, 640))
20
 
21
- # ensure model downloads fully; safer with download=True and zip=True like your working version
22
  swapper = insightface.model_zoo.get_model('inswapper_128.onnx', download=True, download_zip=True)
23
 
 
 
 
24
  # ---------- Swap logic ----------
25
  def swap_faces(src_img, dest_img):
 
 
 
 
 
 
 
 
 
 
26
  src_faces = app.get(src_img)
27
  dest_faces = app.get(dest_img)
28
 
29
  if len(src_faces) == 0 or len(dest_faces) == 0:
30
- raise gr.Error("No faces detected in one of the images.")
31
 
32
  # Just swap first detected face from each image
33
  source_face = src_faces[0]
34
  dest_face = dest_faces[0]
35
  result = swapper.get(dest_img, dest_face, source_face, paste_back=True)
36
 
37
- return Image.fromarray(np.uint8(result)).convert("RGB")
38
-
39
- # ---------- Interface ----------
40
- gr.Interface(
41
- fn=swap_faces,
42
- inputs=[gr.Image(), gr.Image()],
43
- outputs=gr.Image(),
44
- description=wellcomingMessage,
45
- examples=[
46
- ['./Images/kim.jpg', './Images/marilyn.jpg'],
47
- ],
48
- ).launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  app = FaceAnalysis(name='buffalo_l')
19
  app.prepare(ctx_id=0, det_size=(640, 640))
20
 
21
+ # ensure model downloads fully
22
  swapper = insightface.model_zoo.get_model('inswapper_128.onnx', download=True, download_zip=True)
23
 
24
+ # ---------- CTA / marketing config ----------
25
+ BASE_UTM = "utm_source=hfspace_faceswap"
26
+
27
  # ---------- Swap logic ----------
28
  def swap_faces(src_img, dest_img):
29
+ # Pre-run nudge
30
+ gr.Warning(
31
+ 'Skip the limits β€” HD, priority queue & no watermark at '
32
+ '<a href="https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=warning" '
33
+ 'target="_blank" rel="noopener">face-swap.co</a>'
34
+ )
35
+
36
+ if src_img is None or dest_img is None:
37
+ raise gr.Error("Please upload both a source and a target image.")
38
+
39
  src_faces = app.get(src_img)
40
  dest_faces = app.get(dest_img)
41
 
42
  if len(src_faces) == 0 or len(dest_faces) == 0:
43
+ raise gr.Error("No faces detected in one of the images. Try clearer, front-facing photos.")
44
 
45
  # Just swap first detected face from each image
46
  source_face = src_faces[0]
47
  dest_face = dest_faces[0]
48
  result = swapper.get(dest_img, dest_face, source_face, paste_back=True)
49
 
50
+ out_img = Image.fromarray(np.uint8(result)).convert("RGB")
51
+
52
+ # Post-success promo
53
+ gr.Info(
54
+ '✨ Like this preview?<br>'
55
+ '<strong>Get HD face swaps</strong> (higher resolution, priority queue & no watermark) β€” '
56
+ '<a href="https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=info" '
57
+ 'target="_blank" rel="noopener">Upgrade on face-swap.co</a>',
58
+ duration=8
59
+ )
60
+
61
+ return out_img
62
+
63
+ def open_side():
64
+ return gr.Sidebar(open=True)
65
+
66
+ # ---------- Custom CSS (same vibe as video app) ----------
67
+ CUSTOM_CSS = """
68
+ .sticky-cta {
69
+ position: sticky; top: 0; z-index: 1000;
70
+ background: #a5b4fc;
71
+ color: #0f172a;
72
+ padding: 10px 14px;
73
+ text-align: center;
74
+ border-bottom: 1px solid #333;
75
+ display: block;
76
+ text-decoration: none;
77
+ cursor: pointer;
78
+ }
79
+ .sticky-cta:hover { filter: brightness(0.97); }
80
+ .sticky-cta .pill { background:#4f46e5; color:#fff; padding:4px 10px; border-radius:999px; margin-left:10px; }
81
+ .sticky-cta .cta-link { font-weight:600; text-decoration: underline; }
82
+
83
+ /* centered, single-label API CTA */
84
+ .api-cta-wrap { text-align:center; margin-top:10px; }
85
+ .api-cta-hero {
86
+ display:inline-flex; align-items:center; gap:10px;
87
+ padding:10px 14px; border-radius:14px;
88
+ background: linear-gradient(90deg,#0ea5e9 0%, #a8a9de 100%);
89
+ color:#fff; font-weight:800; letter-spacing:0.1px;
90
+ box-shadow: 0 6px 22px rgba(99,102,241,0.35);
91
+ border: 1px solid rgba(255,255,255,0.22);
92
+ text-decoration:none;
93
+ }
94
+ .api-cta-hero:hover { filter:brightness(1.05); transform: translateY(-1px); transition: all .15s ease; }
95
+
96
+ .api-cta-hero .new {
97
+ background:#fff; color:#0ea5e9; font-weight:900;
98
+ padding:2px 8px; border-radius:999px; font-size:12px; line-height:1;
99
+ }
100
+ .api-cta-hero .txt { font-weight:800; }
101
+ .api-cta-hero .chev { opacity:.95; }
102
+ @media (max-width: 520px){
103
+ .api-cta-hero { padding:9px 12px; gap:8px; font-size:14px; }
104
+ .api-cta-hero .new { display:none; }
105
+ }
106
+
107
+ /* floating bottom promo */
108
+ .bottom-promo {
109
+ position: fixed; left: 50%; transform: translateX(-50%);
110
+ bottom: 16px; z-index: 1001; background:#0b0b0b; color:#fff;
111
+ border: 1px solid #2a2a2a; border-radius: 12px; padding: 10px 14px;
112
+ box-shadow: 0 8px 24px rgba(0,0,0,0.3);
113
+ }
114
+ .bottom-promo a { color:#4ea1ff; text-decoration:none; font-weight:600; }
115
+
116
+ /* big CTA button */
117
+ .upgrade-btn { width: 100%; font-size: 16px; padding: 10px 14px; }
118
+
119
+ /* hero markdown centering + larger heading */
120
+ #hero-md {
121
+ text-align: center;
122
+ }
123
+ #hero-md h3,
124
+ #hero-md .prose h3 {
125
+ font-size: 2.1rem;
126
+ line-height: 1.2;
127
+ font-weight: 800;
128
+ margin-bottom: 0.25rem;
129
+ }
130
+ #hero-md p,
131
+ #hero-md .prose p {
132
+ font-size: 1.05rem;
133
+ }
134
+ """
135
+
136
+ # ---------- UI (Blocks) ----------
137
+ with gr.Blocks(title="Image Face Swap", theme=gr.themes.Soft(), css=CUSTOM_CSS) as demo:
138
+ # Sticky banner
139
+ gr.HTML(
140
+ '<a class="sticky-cta" '
141
+ 'href="https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=banner" '
142
+ 'target="_blank" rel="noopener" aria-label="Upgrade to Pro on face-swap.co">'
143
+ '⚑ <strong>Upgrade to HD</strong> β€” priority queue & higher resolution swaps!'
144
+ '<span class="pill">GPU</span>'
145
+ '</a>'
146
+ )
147
+
148
+ # Hero / intro
149
+ gr.Markdown(
150
+ f"""
151
+ ### Image Face Swap (Preview)
152
+ [face-swap.co](https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=subtitle)
153
+
154
+ **Free preview** runs on CPU and may be limited in resolution to keep it fast.
155
+ Want full-quality **HD AI face swap** with GPU speed? **[Go Pro β†—](https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=go_pro)**
156
+
157
+ {wellcomingMessage}
158
+ """,
159
+ elem_id="hero-md"
160
+ )
161
+
162
+ # API CTA
163
+ gr.HTML(
164
+ """
165
+ <div class="api-cta-wrap">
166
+ <a class="api-cta-hero"
167
+ href="https://www.face-swap.co/api?utm_source=hfspace_faceswap&utm_medium=hero_api_new"
168
+ target="_blank" rel="noopener" aria-label="Face Swap API">
169
+ <span class="new">NEW</span>
170
+ <span class="txt">Face Swap API</span>
171
+ <span class="chev">β†—</span>
172
+ </a>
173
+ </div>
174
+ """
175
+ )
176
+
177
+ with gr.Row():
178
+ with gr.Column(scale=5):
179
+ src_img = gr.Image(type="numpy", label="Source Image (face to copy)")
180
+ dest_img = gr.Image(type="numpy", label="Target Image (face to replace)")
181
+
182
+ go = gr.Button("Swap Face", variant="primary")
183
+ pro = gr.Button("⚑ Upgrade to HD on face-swap.co", elem_classes=["upgrade-btn"])
184
+
185
+ with gr.Column(scale=5):
186
+ out_img = gr.Image(label="Result")
187
+
188
+ # Examples
189
+ gr.Examples(
190
+ examples=[["./Images/kim.jpg", "./Images/marilyn.jpg"]],
191
+ inputs=[src_img, dest_img],
192
+ outputs=[out_img],
193
+ fn=swap_faces,
194
+ cache_examples=True,
195
+ run_on_click=True,
196
+ label="Try an example"
197
+ )
198
+
199
+ # Sidebar CTA
200
+ with gr.Sidebar(open=False) as side:
201
+ gr.Markdown(
202
+ "### Upgrade to HD 1920x1080\n"
203
+ "- Higher resolution face swaps\n"
204
+ "- Priority queue\n"
205
+ "- API access & automation\n"
206
+ "- No watermark"
207
+ )
208
+ pro_pro = gr.Button("Open Pro Checkout", variant="primary")
209
+ pro_api = gr.Button("API Access", variant="primary")
210
+
211
+ # Floating bottom promo
212
+ gr.HTML(
213
+ '<div class="bottom-promo">'
214
+ 'Want HD & faster processing? '
215
+ '<a href="https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=upgrade" '
216
+ 'target="_blank" rel="noopener">Upgrade</a>'
217
+ '</div>'
218
+ )
219
+
220
+ # Open sidebar on click
221
+ go.click(fn=open_side, inputs=None, outputs=side, queue=False)
222
+
223
+ # Main action
224
+ go.click(fn=swap_faces, inputs=[src_img, dest_img], outputs=out_img)
225
+
226
+ # JS-only Pro buttons
227
+ pro.click(
228
+ fn=None, inputs=None, outputs=None,
229
+ js="()=>window.open('https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=upgrade_to_hd','_blank')"
230
+ )
231
+ pro_pro.click(
232
+ fn=None, inputs=None, outputs=None,
233
+ js="()=>window.open('https://www.face-swap.co/?utm_source=hfspace_faceswap&utm_medium=sidebar_pro','_blank')"
234
+ )
235
+ pro_api.click(
236
+ fn=None, inputs=None, outputs=None,
237
+ js="()=>window.open('https://www.face-swap.co/api?utm_source=hfspace_faceswap&utm_medium=sidebar_api','_blank')"
238
+ )
239
+
240
+ demo.queue()
241
+
242
+ if __name__ == "__main__":
243
+ demo.launch()