File size: 5,871 Bytes
5ee72d2
fe84436
5ee72d2
c2389fb
5ee72d2
ea232a6
5ee72d2
7d9e5d0
 
7e96cef
66c272f
 
 
7d9e5d0
8c14ebe
7d9e5d0
 
 
 
 
 
7e96cef
7d9e5d0
 
 
 
 
 
 
 
 
 
 
 
7e96cef
 
 
 
 
 
 
 
 
 
4f85e22
7e96cef
4f85e22
7e96cef
 
 
 
8c14ebe
7e96cef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4f85e22
 
 
 
 
 
 
 
 
7e96cef
 
 
 
 
 
 
 
 
 
 
 
 
 
39754cf
 
7e96cef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4f85e22
7e96cef
 
 
 
 
 
 
 
 
 
 
 
 
66c272f
4f85e22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ea232a6
7e96cef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# pyrefly: ignore [missing-import]
import gradio as gr
# pyrefly: ignore [missing-import]
import spaces
# pyrefly: ignore [missing-import]
import numpy as np
# pyrefly: ignore [missing-import]
from PIL import Image
from rembg import remove, new_session
import base64
import io

# ── Cache model ───────────────────────────────────────────────────────────────
_SESSIONS = {}

def get_session(model_name: str):
    if model_name not in _SESSIONS:
        print(f"[INFO] Sedang download/load model: {model_name} ...")
        _SESSIONS[model_name] = new_session(model_name)
    return _SESSIONS[model_name]

def process_image(img: Image.Image, model_name: str, alpha_matting: bool) -> Image.Image:
    img = img.convert("RGB")
    session = get_session(model_name)
    kwargs = {}
    if alpha_matting:
        kwargs.update(
            alpha_matting=True,
            alpha_matting_foreground_threshold=240,
            alpha_matting_background_threshold=10,
            alpha_matting_erode_size=10,
        )
    return remove(img, session=session, **kwargs)

# ── Handler untuk HuggingFace Web UI ──────────────────────────────────────────
@spaces.GPU(duration=60)
def remove_bg_ui(img, model_name, alpha_matting):
    if img is None:
        return None
    if not isinstance(img, Image.Image):
        img = Image.fromarray(np.uint8(img))
    return process_image(img, model_name, alpha_matting)

# ── Handler untuk API Eksternal (Vercel / Next.js) ────────────────────────────
def process_api_image(img_data, model_name, alpha_matting):
    """
    Helper untuk memproses base64 data URL atau objek {path: ...}.
    Mengembalikan data:image/png;base64,... secara langsung tanpa perlu file upload terpisah.
    """
    if not img_data:
        return None

    try:
        if isinstance(img_data, str):
            # Jika berupa data URL atau base64 murni
            if "," in img_data:
                img_data = img_data.split(",", 1)[1]
            img_bytes = base64.b64decode(img_data)
            pil_img = Image.open(io.BytesIO(img_bytes))
        elif isinstance(img_data, dict) and "path" in img_data:
            pil_img = Image.open(img_data["path"])
        else:
            return None

        result_img = process_image(pil_img, model_name, alpha_matting)

        # Encode hasil ke base64 PNG
        buffered = io.BytesIO()
        result_img.save(buffered, format="PNG")
        b64_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
        return f"data:image/png;base64,{b64_str}"
    except Exception as e:
        print(f"[ERROR] API processing failed: {e}")
        raise e

@spaces.GPU(duration=60)
def remove_bg_api(img_data, model_name, alpha_matting):
    """Endpoint API GPU untuk Vercel / Next.js (akselerasi ZeroGPU)."""
    return process_api_image(img_data, model_name, alpha_matting)

def remove_bg_cpu_api(img_data, model_name, alpha_matting):
    """Endpoint API CPU fallback jika ZeroGPU quota tercapai atau sedang antre."""
    return process_api_image(img_data, model_name, alpha_matting)

# ── Gradio Blocks Interface ───────────────────────────────────────────────────
with gr.Blocks(title="Background Remover AI") as demo:
    gr.Markdown("# πŸš€ AI Background Remover")
    gr.Markdown("Hapus background gambar dengan presisi tinggi menggunakan ZeroGPU.")

    # Tampilan UI untuk pengunjung HuggingFace Space
    with gr.Row():
        with gr.Column():
            ui_input = gr.Image(type="pil", label="Upload Gambar")
            ui_model = gr.Dropdown(
                choices=[
                    "birefnet-portrait",
                    "birefnet-general",
                    "isnet-general-use",
                    "isnet-anime",
                    "u2net",
                    "u2net_human_seg",
                ],
                value="birefnet-portrait",
                label="Model AI",
            )
            ui_alpha = gr.Checkbox(value=False, label="Alpha Matting (haluskan edge rambut)")
            ui_btn = gr.Button("Hapus Background", variant="primary")
        with gr.Column():
            ui_output = gr.Image(type="pil", label="Hasil (PNG Transparan)")

    ui_btn.click(
        fn=remove_bg_ui,
        inputs=[ui_input, ui_model, ui_alpha],
        outputs=ui_output,
    )

    # Komponen API untuk Vercel / endpoint /gradio_api/call/remove_bg (ZeroGPU)
    with gr.Row(visible=False):
        api_input = gr.Textbox(label="Image Base64")
        api_model = gr.Textbox(value="birefnet-portrait", label="Model")
        api_alpha = gr.Checkbox(value=False, label="Alpha Matting")
        api_output = gr.Textbox(label="Result Base64")
        api_btn = gr.Button("API Trigger")

    api_btn.click(
        fn=remove_bg_api,
        inputs=[api_input, api_model, api_alpha],
        outputs=api_output,
        api_name="remove_bg",
    )

    # Komponen API CPU Fallback / endpoint /gradio_api/call/remove_bg_cpu (Bebas Quota ZeroGPU)
    with gr.Row(visible=False):
        cpu_input = gr.Textbox(label="Image Base64 CPU")
        cpu_model = gr.Textbox(value="birefnet-portrait", label="Model CPU")
        cpu_alpha = gr.Checkbox(value=False, label="Alpha Matting CPU")
        cpu_output = gr.Textbox(label="Result Base64 CPU")
        cpu_btn = gr.Button("API CPU Trigger")

    cpu_btn.click(
        fn=remove_bg_cpu_api,
        inputs=[cpu_input, cpu_model, cpu_alpha],
        outputs=cpu_output,
        api_name="remove_bg_cpu",
    )

if __name__ == "__main__":
    demo.launch()