# Import Gradio dan client API
import gradio as gr
from PIL import Image
import numpy as np
import tempfile
from gradio_client import Client, handle_file
from themes import IndonesiaTheme # Impor tema custom
import os
# Siapkan URL untuk permintaan API Virtual Try-On
url_api = os.environ['url_api']
# Fungsi untuk memanggil API /generate_image
def generate_image(prompt, id_image, start_step, guidance, seed, true_cfg, width, height, num_steps, id_weight, neg_prompt, timestep_to_start_cfg, max_sequence_length):
client = Client(url_api)
try:
# Jika id_image adalah numpy array, konversikan ke gambar menggunakan PIL
if isinstance(id_image, np.ndarray):
id_image_pil = Image.fromarray(id_image.astype('uint8')) # Konversi ke format gambar dari numpy array
# Simpan gambar sebagai file sementara
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_file:
id_image_pil.save(temp_file.name) # Simpan gambar PIL ke file sementara
# Panggil API dengan file gambar
result = client.predict(
prompt=prompt,
id_image=handle_file(temp_file.name), # Kirim file gambar ke API
start_step=start_step,
guidance=guidance,
seed=seed,
true_cfg=true_cfg,
width=width,
height=height,
num_steps=num_steps,
id_weight=id_weight,
neg_prompt=neg_prompt,
timestep_to_start_cfg=timestep_to_start_cfg,
max_sequence_length=max_sequence_length,
api_name="/generate_image"
)
else:
raise ValueError("Gambar yang diunggah tidak valid.")
# Proses keluaran dari API
generated_image_path = result[0] # Ambil path gambar yang dihasilkan
used_seed = result[1] # Ambil seed yang digunakan
output_gallery_items = [] # List untuk menampung item galeri
# Ekstrak daftar gambar dari hasil API (jika ada lebih dari satu gambar)
if isinstance(result[2], list):
for item in result[2]:
if 'image' in item:
output_gallery_items.append((item['image'], item.get('caption', ''))) # Tambahkan gambar dan keterangan ke galeri
# Jika tidak ada error, kembalikan hasil gambar dan seed
return generated_image_path, used_seed, "Success: Image generated successfully."
except Exception as e:
# Jika terjadi error, kembalikan pesan error ke "system_result"
error_message = f"Error: {str(e)}"
return None, None, error_message
# CSS untuk styling antarmuka
css = """
#col-left, #col-mid {
margin: 0 auto;
max-width: 400px;
padding: 10px;
border-radius: 15px;
background-color: #f9f9f9;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
#col-right {
margin: 0 auto;
max-width: 400px;
padding: 10px;
border-radius: 15px;
background: linear-gradient(180deg, #B6BBC4, #EEEEEE);
color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
#col-bott {
margin: 0 auto;
padding: 10px;
border-radius: 15px;
background-color: #f9f9f9;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
#banner {
width: 100%;
text-align: center;
margin-bottom: 20px;
}
#run-button {
background-color: #ff4b5c;
color: white;
font-weight: bold;
padding: 30px;
border-radius: 10px;
cursor: pointer;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
#footer {
text-align: center;
margin-top: 20px;
color: silver;
}
#markdown-silver {
color: silver; /* Mengatur warna font Markdown menjadi silver */
}
"""
# Antarmuka Gradio
with gr.Blocks(css=css, theme=IndonesiaTheme()) as PuLidFluxApp:
# Tambahkan banner
gr.HTML("""
""")
gr.HTML("Aplikasi Pembuatan Gambar Menggunakan PuLID-FLUX
")
with gr.Row():
with gr.Column(elem_id="col-left"):
gr.Markdown("### ➡️ Deskripsi Gambar")
prompt = gr.Textbox(label="Prompt", value="portrait, color, cinematic")
gr.Markdown("### ➡️ Sumber Wajah")
id_image = gr.Image(label="Foto Wajah")
neg_prompt = gr.Textbox(label="Negative Prompt", value="bad quality, worst quality, text, signature, watermark, extra limbs")
with gr.Column(elem_id="col-mid"):
gr.Markdown("### ➡️ Advanced Parameters")
start_step = gr.Slider(label="Timestep to Start", minimum=0, maximum=10, value=0)
guidance = gr.Slider(label="Guidance", minimum=0, maximum=10, value=4)
seed = gr.Textbox(label="Seed (-1 for random)", value="-1")
true_cfg = gr.Slider(label="True CFG Scale", minimum=0, maximum=10, value=1)
width = gr.Slider(label="Width", minimum=100, maximum=2000, value=896)
height = gr.Slider(label="Height", minimum=100, maximum=2000, value=1152)
num_steps = gr.Slider(label="Number of Steps", minimum=1, maximum=100, value=20)
id_weight = gr.Slider(label="ID Weight", minimum=0, maximum=1, value=1)
timestep_to_start_cfg = gr.Slider(label="Timestep to Start CFG", minimum=0, maximum=10, value=1)
max_sequence_length = gr.Slider(label="Max Sequence Length", minimum=1, maximum=512, value=128)
with gr.Column(elem_id="col-right"):
gr.Markdown("""
### Paper: PuLID: [Pure and Lightning ID Customization via Contrastive Alignment](https://arxiv.org/abs/2404.16022) | [Codes: GitHub](https://github.com/ToTheBeginning/PuLID)
### 💡Tips:
- **Timestep to start inserting ID**:
- Semakin kecil nilainya, semakin tinggi kesetiaannya, namun semakin rendah kemampuan untuk mengedit; semakin tinggi nilainya, semakin rendah kesetiaannya, namun semakin tinggi kemampuan untuk mengedit.
- Rentang yang disarankan untuk nilai ini adalah antara 0 hingga 4. Untuk adegan fotorealistik, kami merekomendasikan menggunakan 4; untuk adegan bergaya, kami merekomendasikan menggunakan 0-1.
- Jika Anda tidak puas dengan kemiripannya, Anda dapat menurunkan nilai ini; sebaliknya, jika Anda tidak puas dengan kemampuan pengeditan, Anda dapat menaikkan nilai ini.
- **True CFG scale**:
- Dalam sebagian besar skenario, disarankan menggunakan fake CFG, yaitu dengan mengatur true CFG scale ke 1, dan hanya menyesuaikan guidance scale. Hal ini juga lebih efisien.
- Namun, dalam beberapa kasus, penggunaan true CFG dapat menghasilkan hasil yang lebih baik. Untuk informasi lebih detail, silakan merujuk ke dokumentasi.
- **Pelajari lebih lanjut tentang model**:
- Silakan merujuk ke dokumentasi GitHub untuk detail lebih lanjut dan informasi tentang model. Kami menyediakan penjelasan detail tentang kedua parameter di atas dalam dokumen.
- **Contoh**:
- Kami menyediakan beberapa contoh (sudah di-cache, jadi cukup klik untuk melihat apa yang dapat dilakukan model) di bagian bawah. Anda bisa mencoba prompt contoh tersebut terlebih dahulu.
""", elem_id="markdown-silver")
# Tombol untuk memulai proses
with gr.Row():
with gr.Column(elem_id="col-bott"):
run_button = gr.Button("⭐ Mulai Generate Image ⭐", elem_id="run-button")
gr.Markdown("### ✅ Hasil Generated PuLID")
generated_image = gr.Image(label="Generated Image")
used_seed = gr.Textbox(label="Used Seed")
system_result = gr.Textbox(label="System Result") # Output tambahan untuk menampilkan hasil/error
# Menghubungkan tombol dengan fungsi pemanggilan API
run_button.click(
fn=generate_image,
inputs=[prompt, id_image, start_step, guidance, seed, true_cfg, width, height, num_steps, id_weight, neg_prompt, timestep_to_start_cfg, max_sequence_length],
outputs=[generated_image, used_seed, system_result] # Tambahkan system_result sebagai output
)
# Tambahkan footer di bagian bawah
gr.HTML("""
""")
# Menjalankan aplikasi
if __name__ == "__main__":
PuLidFluxApp.queue(api_open=False).launch(show_api=False)