Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# app.py (Hugging Face Spaces
|
| 2 |
|
| 3 |
import os
|
| 4 |
import gradio as gr
|
|
@@ -11,16 +11,13 @@ import shutil
|
|
| 11 |
import time
|
| 12 |
|
| 13 |
# --- Configuration (Hardcoded for Hugging Face Spaces) ---
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
FORCE_CPU = True # Hugging Face free-tier hardware သည် CPU ဖြစ်သောကြောင့် True ဟု သတ်မှတ်ပါသည်
|
| 17 |
|
| 18 |
# --- Initialize Refacer ---
|
| 19 |
-
# Refacer ကို သတ်မှတ်ထားသော settings များဖြင့် စတင်ပါသည်
|
| 20 |
refacer = Refacer(force_cpu=FORCE_CPU)
|
| 21 |
|
| 22 |
-
# --- Functions
|
| 23 |
-
|
| 24 |
def run_image(*vars):
|
| 25 |
image_path = vars[0]
|
| 26 |
origins = vars[1:(NUM_FACES + 1)]
|
|
@@ -28,22 +25,12 @@ def run_image(*vars):
|
|
| 28 |
thresholds = vars[(NUM_FACES * 2) + 1:-2]
|
| 29 |
face_mode = vars[-2]
|
| 30 |
partial_reface_ratio = vars[-1]
|
| 31 |
-
|
| 32 |
disable_similarity = (face_mode in ["Single Face", "Multiple Faces"])
|
| 33 |
multiple_faces_mode = (face_mode == "Multiple Faces")
|
| 34 |
-
|
| 35 |
-
faces = []
|
| 36 |
-
for k in range(NUM_FACES):
|
| 37 |
-
if destinations[k] is not None:
|
| 38 |
-
faces.append({
|
| 39 |
-
'origin': origins[k] if not multiple_faces_mode else None,
|
| 40 |
-
'destination': destinations[k],
|
| 41 |
-
'threshold': thresholds[k] if not multiple_faces_mode else 0.0
|
| 42 |
-
})
|
| 43 |
-
|
| 44 |
return refacer.reface_image(image_path, faces, disable_similarity=disable_similarity, multiple_faces_mode=multiple_faces_mode, partial_reface_ratio=partial_reface_ratio)
|
| 45 |
|
| 46 |
-
def
|
| 47 |
video_path = vars[0]
|
| 48 |
origins = vars[1:(NUM_FACES + 1)]
|
| 49 |
destinations = vars[(NUM_FACES + 1):(NUM_FACES * 2) + 1]
|
|
@@ -51,37 +38,22 @@ def run(*vars):
|
|
| 51 |
preview = vars[-3]
|
| 52 |
face_mode = vars[-2]
|
| 53 |
partial_reface_ratio = vars[-1]
|
| 54 |
-
|
| 55 |
disable_similarity = (face_mode in ["Single Face", "Multiple Faces"])
|
| 56 |
multiple_faces_mode = (face_mode == "Multiple Faces")
|
| 57 |
-
|
| 58 |
-
faces = []
|
| 59 |
-
for k in range(NUM_FACES):
|
| 60 |
-
if destinations[k] is not None:
|
| 61 |
-
faces.append({
|
| 62 |
-
'origin': origins[k] if not multiple_faces_mode else None,
|
| 63 |
-
'destination': destinations[k],
|
| 64 |
-
'threshold': thresholds[k] if not multiple_faces_mode else 0.0
|
| 65 |
-
})
|
| 66 |
-
|
| 67 |
mp4_path, gif_path = refacer.reface(video_path, faces, preview=preview, disable_similarity=disable_similarity, multiple_faces_mode=multiple_faces_mode, partial_reface_ratio=partial_reface_ratio)
|
| 68 |
-
return mp4_path, gif_path
|
| 69 |
|
| 70 |
def load_first_frame(filepath):
|
| 71 |
-
if filepath is None:
|
| 72 |
-
return None
|
| 73 |
with imageio.get_reader(filepath) as reader:
|
| 74 |
return reader.get_data(0)
|
| 75 |
|
| 76 |
def extract_faces_auto(filepath, max_faces=5, isvideo=False):
|
| 77 |
-
if filepath is None:
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
# Video ဖိုင်ကြီးလျှင် performance မကျစေရန် auto-extract ကို ကျော်ပါသည်
|
| 81 |
-
if isvideo and os.path.getsize(filepath) > 5 * 1024 * 1024:
|
| 82 |
-
print("Video is too large for auto-extract, skipping face extraction.")
|
| 83 |
return [None] * max_faces
|
| 84 |
-
|
| 85 |
try:
|
| 86 |
frame = load_first_frame(filepath)
|
| 87 |
faces = refacer.extract_faces_from_image(frame, max_faces=max_faces)
|
|
@@ -92,96 +64,81 @@ def extract_faces_auto(filepath, max_faces=5, isvideo=False):
|
|
| 92 |
|
| 93 |
def toggle_tabs_and_faces(mode):
|
| 94 |
if mode == "Single Face":
|
| 95 |
-
|
| 96 |
-
origin_updates = [gr.update(visible=False)] * NUM_FACES
|
| 97 |
elif mode == "Multiple Faces":
|
| 98 |
-
|
| 99 |
-
origin_updates = [gr.update(visible=False)] * NUM_FACES
|
| 100 |
else: # Faces By Match
|
| 101 |
-
|
| 102 |
-
origin_updates = [gr.update(visible=True)] * NUM_FACES
|
| 103 |
-
return tab_updates + origin_updates
|
| 104 |
|
| 105 |
def handle_tif_preview(filepath):
|
| 106 |
-
if filepath is None:
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
with Image.open(filepath) as img:
|
| 111 |
-
img_rgb = img.convert('RGB')
|
| 112 |
-
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as temp_file:
|
| 113 |
-
img_rgb.save(temp_file.name)
|
| 114 |
-
return temp_file.name
|
| 115 |
|
| 116 |
# --- UI ---
|
| 117 |
theme = gr.themes.Base(primary_hue="blue", secondary_hue="cyan")
|
| 118 |
|
| 119 |
with gr.Blocks(theme=theme, title="NeoRefacer - AI Refacer") as demo:
|
| 120 |
-
# Icon ကို base64 encode လုပ်ပြီး HTML ထဲမှာ တိုက်ရိုက်ထည့်သွင်းခြင်း
|
| 121 |
with open("icon.png", "rb") as f:
|
| 122 |
icon_data = base64.b64encode(f.read()).decode()
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
gr.
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
with gr.Tab("Video Mode"):
|
| 180 |
-
# (UI code is repetitive, so I'll omit it for brevity)
|
| 181 |
-
# Ensure all instances of `num_faces` are replaced with `NUM_FACES`.
|
| 182 |
-
# ... (Video UI Code Here) ...
|
| 183 |
-
pass
|
| 184 |
|
| 185 |
# --- Launch app ---
|
| 186 |
-
|
| 187 |
-
|
|
|
|
| 1 |
+
# app.py (Complete Version for Hugging Face Spaces)
|
| 2 |
|
| 3 |
import os
|
| 4 |
import gradio as gr
|
|
|
|
| 11 |
import time
|
| 12 |
|
| 13 |
# --- Configuration (Hardcoded for Hugging Face Spaces) ---
|
| 14 |
+
NUM_FACES = 8
|
| 15 |
+
FORCE_CPU = True
|
|
|
|
| 16 |
|
| 17 |
# --- Initialize Refacer ---
|
|
|
|
| 18 |
refacer = Refacer(force_cpu=FORCE_CPU)
|
| 19 |
|
| 20 |
+
# --- Core Functions ---
|
|
|
|
| 21 |
def run_image(*vars):
|
| 22 |
image_path = vars[0]
|
| 23 |
origins = vars[1:(NUM_FACES + 1)]
|
|
|
|
| 25 |
thresholds = vars[(NUM_FACES * 2) + 1:-2]
|
| 26 |
face_mode = vars[-2]
|
| 27 |
partial_reface_ratio = vars[-1]
|
|
|
|
| 28 |
disable_similarity = (face_mode in ["Single Face", "Multiple Faces"])
|
| 29 |
multiple_faces_mode = (face_mode == "Multiple Faces")
|
| 30 |
+
faces = [{'origin': origins[k] if not multiple_faces_mode else None, 'destination': destinations[k], 'threshold': thresholds[k] if not multiple_faces_mode else 0.0} for k in range(NUM_FACES) if destinations[k] is not None]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
return refacer.reface_image(image_path, faces, disable_similarity=disable_similarity, multiple_faces_mode=multiple_faces_mode, partial_reface_ratio=partial_reface_ratio)
|
| 32 |
|
| 33 |
+
def run_video(*vars):
|
| 34 |
video_path = vars[0]
|
| 35 |
origins = vars[1:(NUM_FACES + 1)]
|
| 36 |
destinations = vars[(NUM_FACES + 1):(NUM_FACES * 2) + 1]
|
|
|
|
| 38 |
preview = vars[-3]
|
| 39 |
face_mode = vars[-2]
|
| 40 |
partial_reface_ratio = vars[-1]
|
|
|
|
| 41 |
disable_similarity = (face_mode in ["Single Face", "Multiple Faces"])
|
| 42 |
multiple_faces_mode = (face_mode == "Multiple Faces")
|
| 43 |
+
faces = [{'origin': origins[k] if not multiple_faces_mode else None, 'destination': destinations[k], 'threshold': thresholds[k] if not multiple_faces_mode else 0.0} for k in range(NUM_FACES) if destinations[k] is not None]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
mp4_path, gif_path = refacer.reface(video_path, faces, preview=preview, disable_similarity=disable_similarity, multiple_faces_mode=multiple_faces_mode, partial_reface_ratio=partial_reface_ratio)
|
| 45 |
+
return mp4_path, gif_path
|
| 46 |
|
| 47 |
def load_first_frame(filepath):
|
| 48 |
+
if filepath is None: return None
|
|
|
|
| 49 |
with imageio.get_reader(filepath) as reader:
|
| 50 |
return reader.get_data(0)
|
| 51 |
|
| 52 |
def extract_faces_auto(filepath, max_faces=5, isvideo=False):
|
| 53 |
+
if filepath is None: return [None] * max_faces
|
| 54 |
+
if isvideo and os.path.getsize(filepath) > 10 * 1024 * 1024:
|
| 55 |
+
print("Video too large for auto-extract.")
|
|
|
|
|
|
|
|
|
|
| 56 |
return [None] * max_faces
|
|
|
|
| 57 |
try:
|
| 58 |
frame = load_first_frame(filepath)
|
| 59 |
faces = refacer.extract_faces_from_image(frame, max_faces=max_faces)
|
|
|
|
| 64 |
|
| 65 |
def toggle_tabs_and_faces(mode):
|
| 66 |
if mode == "Single Face":
|
| 67 |
+
return [gr.update(visible=(i == 0)) for i in range(NUM_FACES)] + [gr.update(visible=False)] * NUM_FACES
|
|
|
|
| 68 |
elif mode == "Multiple Faces":
|
| 69 |
+
return [gr.update(visible=True)] * NUM_FACES + [gr.update(visible=False)] * NUM_FACES
|
|
|
|
| 70 |
else: # Faces By Match
|
| 71 |
+
return [gr.update(visible=True)] * NUM_FACES + [gr.update(visible=True)] * NUM_FACES
|
|
|
|
|
|
|
| 72 |
|
| 73 |
def handle_tif_preview(filepath):
|
| 74 |
+
if filepath is None: return None
|
| 75 |
+
with Image.open(filepath) as img, tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as temp_file:
|
| 76 |
+
img.convert('RGB').save(temp_file.name)
|
| 77 |
+
return temp_file.name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
# --- UI ---
|
| 80 |
theme = gr.themes.Base(primary_hue="blue", secondary_hue="cyan")
|
| 81 |
|
| 82 |
with gr.Blocks(theme=theme, title="NeoRefacer - AI Refacer") as demo:
|
|
|
|
| 83 |
with open("icon.png", "rb") as f:
|
| 84 |
icon_data = base64.b64encode(f.read()).decode()
|
| 85 |
+
gr.Markdown(f'<div style="display: flex; align-items: center;"><img src="data:image/png;base64,{icon_data}" style="width:40px;height:40px;margin-right:10px;"><span style="font-size: 2em; font-weight: bold; color:#2563eb;">NeoRefacer</span></div>')
|
| 86 |
+
|
| 87 |
+
for mode in ["Image", "GIF", "TIFF", "Video"]:
|
| 88 |
+
with gr.Tab(f"{mode} Mode"):
|
| 89 |
+
is_video_or_gif = mode in ["Video", "GIF"]
|
| 90 |
+
|
| 91 |
+
with gr.Row():
|
| 92 |
+
if is_video_or_gif:
|
| 93 |
+
input_component = gr.Video(label=f"Original {mode}")
|
| 94 |
+
if mode == "GIF":
|
| 95 |
+
output_main = gr.Video(label="Refaced GIF (MP4)", interactive=False, format="mp4")
|
| 96 |
+
output_secondary = gr.Image(label="Refaced GIF (GIF)", type="filepath")
|
| 97 |
+
else: # Video
|
| 98 |
+
output_main = gr.Video(label="Refaced Video", interactive=False, format="mp4")
|
| 99 |
+
output_secondary = gr.File(visible=False) # Dummy component
|
| 100 |
+
elif mode == "TIFF":
|
| 101 |
+
input_component = gr.File(label="Original TIF", file_types=[".tif", ".tiff"])
|
| 102 |
+
output_main = gr.Image(label="Refaced TIF Preview", type="filepath")
|
| 103 |
+
output_secondary = gr.File(label="Refaced TIF (Download)", interactive=False)
|
| 104 |
+
else: # Image
|
| 105 |
+
input_component = gr.Image(label="Original image", type="filepath")
|
| 106 |
+
output_main = gr.Image(label="Refaced image", interactive=False, type="filepath")
|
| 107 |
+
|
| 108 |
+
with gr.Row():
|
| 109 |
+
face_mode_radio = gr.Radio(["Single Face", "Multiple Faces", "Faces By Match"], value="Single Face", label="Replacement Mode")
|
| 110 |
+
partial_reface_slider = gr.Slider(label="Reface Ratio (0=Full, 0.5=Half)", minimum=0.0, maximum=0.5, value=0.0, step=0.1)
|
| 111 |
+
reface_btn = gr.Button(f"Reface {mode}", variant="primary")
|
| 112 |
+
if is_video_or_gif:
|
| 113 |
+
preview_checkbox = gr.Checkbox(label="Preview (fast)", value=False)
|
| 114 |
+
|
| 115 |
+
origins, destinations, thresholds, face_tabs = [], [], [], []
|
| 116 |
+
for i in range(NUM_FACES):
|
| 117 |
+
with gr.Tab(f"Face #{i+1}", visible=(i==0)) as tab:
|
| 118 |
+
with gr.Row():
|
| 119 |
+
origin_img = gr.Image(label="Face to replace (Match)", visible=False)
|
| 120 |
+
dest_img = gr.Image(label="Destination face (Target)")
|
| 121 |
+
thresh_slider = gr.Slider(label="Threshold (for Match mode)", minimum=0.0, maximum=1.0, value=0.2)
|
| 122 |
+
origins.append(origin_img); destinations.append(dest_img); thresholds.append(thresh_slider); face_tabs.append(tab)
|
| 123 |
+
|
| 124 |
+
# Event Handlers
|
| 125 |
+
face_mode_radio.change(toggle_tabs_and_faces, inputs=face_mode_radio, outputs=face_tabs + origins)
|
| 126 |
+
|
| 127 |
+
if mode == "TIFF":
|
| 128 |
+
tif_preview = gr.Image(label="TIF Preview", type="filepath") # Specific for TIFF
|
| 129 |
+
input_component.change(handle_tif_preview, inputs=input_component, outputs=tif_preview)
|
| 130 |
+
input_component.change(lambda fp: extract_faces_auto(fp, max_faces=NUM_FACES), inputs=input_component, outputs=destinations)
|
| 131 |
+
reface_btn.click(lambda fp, *args: (handle_tif_preview(run_image(fp, *args)), run_image(fp, *args)), inputs=[input_component] + origins + destinations + thresholds + [face_mode_radio, partial_reface_slider], outputs=[output_main, output_secondary])
|
| 132 |
+
elif is_video_or_gif:
|
| 133 |
+
input_component.change(lambda fp: extract_faces_auto(fp, max_faces=NUM_FACES, isvideo=True), inputs=input_component, outputs=destinations)
|
| 134 |
+
reface_btn.click(run_video, inputs=[input_component] + origins + destinations + thresholds + [preview_checkbox, face_mode_radio, partial_reface_slider], outputs=[output_main, output_secondary])
|
| 135 |
+
else: # Image
|
| 136 |
+
input_component.change(lambda fp: extract_faces_auto(fp, max_faces=NUM_FACES), inputs=input_component, outputs=destinations)
|
| 137 |
+
reface_btn.click(run_image, inputs=[input_component] + origins + destinations + thresholds + [face_mode_radio, partial_reface_slider], outputs=[output_main])
|
| 138 |
+
|
| 139 |
+
# Load initial state for all tabs
|
| 140 |
+
demo.load(lambda: toggle_tabs_and_faces("Single Face"), outputs=face_tabs + origins)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
# --- Launch app ---
|
| 143 |
+
demo.queue().launch()
|
| 144 |
+
|