|
import gradio as gr |
|
import io |
|
import random |
|
import time |
|
import json |
|
import base64 |
|
import requests |
|
import os |
|
from mistralai import Mistral |
|
from PIL import Image |
|
from io import BytesIO |
|
from deep_translator import GoogleTranslator |
|
from datetime import datetime |
|
from theme import theme |
|
from fastapi import FastAPI |
|
|
|
app = FastAPI() |
|
|
|
API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-3.5-large-turbo" |
|
API_TOKEN = os.getenv("HF_READ_TOKEN") |
|
headers = {"Authorization": f"Bearer {API_TOKEN}"} |
|
timeout = 100 |
|
|
|
api_key = os.getenv("MISTRAL_API_KEY") |
|
Mistralclient = Mistral(api_key=api_key) |
|
|
|
def flip_image(x): |
|
return np.fliplr(x) |
|
|
|
def clear(): |
|
return None |
|
|
|
|
|
|
|
def query(prompt, is_negative=False, steps=35, cfg_scale=7, sampler="DPM++ 2M Karras", seed=-1, strength=0.7, width=896, height=1152): |
|
if prompt == "" or prompt is None: |
|
return None |
|
|
|
key = random.randint(0, 999) |
|
|
|
API_TOKEN = random.choice([os.getenv("HF_READ_TOKEN")]) |
|
headers = {"Authorization": f"Bearer {API_TOKEN}"} |
|
|
|
|
|
prompt = GoogleTranslator(source='ru', target='en').translate(prompt) |
|
print(f'\033[1mGeneration {key} translation:\033[0m {prompt}') |
|
|
|
|
|
prompt = f"{prompt} | ultra detail, ultra elaboration, ultra quality, perfect." |
|
print(f'\033[1mGeneration {key}:\033[0m {prompt}') |
|
|
|
|
|
payload = { |
|
"inputs": prompt, |
|
"is_negative": is_negative, |
|
"steps": steps, |
|
"cfg_scale": cfg_scale, |
|
"seed": seed if seed != -1 else random.randint(1, 1000000000), |
|
"strength": strength, |
|
"parameters": { |
|
"width": width, |
|
"height": height |
|
} |
|
} |
|
|
|
|
|
response = requests.post(API_URL, headers=headers, json=payload, timeout=timeout) |
|
if response.status_code != 200: |
|
print(f"Error: Failed to get image. Response status: {response.status_code}") |
|
print(f"Response content: {response.text}") |
|
if response.status_code == 503: |
|
raise gr.Error(f"{response.status_code} : The model is being loaded") |
|
raise gr.Error(f"{response.status_code}") |
|
|
|
try: |
|
|
|
image_bytes = response.content |
|
image = Image.open(io.BytesIO(image_bytes)) |
|
print(f'\033[1mGeneration {key} completed!\033[0m ({prompt})') |
|
return image |
|
except Exception as e: |
|
print(f"Error when trying to open the image: {e}") |
|
return None |
|
|
|
examples = [ |
|
"a beautiful woman with blonde hair and blue eyes", |
|
"a beautiful woman with brown hair and grey eyes", |
|
"a beautiful woman with black hair and brown eyes", |
|
] |
|
|
|
def encode_image(image_path): |
|
"""Encode the image to base64.""" |
|
try: |
|
|
|
image = Image.open(image_path).convert("RGB") |
|
|
|
|
|
base_height = 512 |
|
h_percent = (base_height / float(image.size[1])) |
|
w_size = int((float(image.size[0]) * float(h_percent))) |
|
image = image.resize((w_size, base_height), Image.LANCZOS) |
|
|
|
|
|
buffered = BytesIO() |
|
image.save(buffered, format="JPEG") |
|
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8") |
|
|
|
return img_str |
|
except FileNotFoundError: |
|
print(f"Error: The file {image_path} was not found.") |
|
return None |
|
except Exception as e: |
|
print(f"Error: {e}") |
|
return None |
|
|
|
def feifeichat(image): |
|
try: |
|
model = "pixtral-large-2411" |
|
|
|
base64_image = encode_image(image) |
|
messages = [{ |
|
"role": |
|
"user", |
|
"content": [ |
|
{ |
|
"type": "text", |
|
"text": "Please provide a detailed description of this photo" |
|
}, |
|
{ |
|
"type": "image_url", |
|
"image_url": f"data:image/jpeg;base64,{base64_image}" |
|
}, |
|
], |
|
"stream": False, |
|
}] |
|
|
|
partial_message = "" |
|
for chunk in Mistralclient.chat.stream(model=model, messages=messages): |
|
if chunk.data.choices[0].delta.content is not None: |
|
partial_message = partial_message + chunk.data.choices[ |
|
0].delta.content |
|
yield partial_message |
|
except Exception as e: |
|
print(f"Error: {e}") |
|
return "Please upload a photo" |
|
|
|
|
|
css = """ |
|
.gradio-container {background-color: MediumAquaMarine} |
|
footer{display:none !important} |
|
#app-container { |
|
max-width: 930px; |
|
margin-left: auto; |
|
margin-right: auto; |
|
} |
|
""" |
|
|
|
|
|
with gr.Blocks(theme=theme, css=css) as app: |
|
|
|
gr.HTML("<center><h1>π¨ Stable Diffusion 3.5 Large Turbo + π¬π§</h1></center>") |
|
|
|
with gr.Tabs() as tabs: |
|
with gr.TabItem(label="πΌ Image To Prompt π", visible=True): |
|
with gr.Row(): |
|
with gr.Column(): |
|
input_img = gr.Image(label="Input Picture πΌοΈ",height=320,type="filepath") |
|
submit_btn = gr.Button(value="Submit", variant='primary') |
|
with gr.Column(): |
|
output_text = gr.Textbox(label="Flux Prompt βοΈ", show_copy_button = True) |
|
clr_button =gr.Button("Clear ποΈ ",variant="primary", elem_id="clear_button") |
|
clr_button.click(lambda: (None, None), None, [input_img, output_text], queue=False, show_api=False) |
|
|
|
submit_btn.click(feifeichat, [input_img], [output_text]) |
|
|
|
with gr.TabItem("βοΈ Text to Image πΌ", visible=True): |
|
|
|
with gr.Column(elem_id="app-container"): |
|
|
|
with gr.Row(): |
|
with gr.Column(elem_id="prompt-container"): |
|
with gr.Group(): |
|
with gr.Row(): |
|
text_prompt = gr.Textbox(label="Image Prompt βοΈ", placeholder="Enter a prompt here", lines=2, show_copy_button = True, elem_id="prompt-text-input") |
|
|
|
|
|
with gr.Row(): |
|
with gr.Accordion("Advanced Settings", open=False): |
|
negative_prompt = gr.Textbox(label="Negative Prompt", lines=4, placeholder="What should not be in the image", value="(hands:-1.25), physical-defects:2, unhealthy-deformed-joints:2, unhealthy-hands:2, out of frame, bad face, (bad-image-v2-39000:1.3), (((out of frame))), deformed body features, poor facial details, (poorly drawn face:1.3), jpeg artifacts, (missing arms:1.1), (missing legs:1.1), (extra arms:1.2), (extra legs:1.2)") |
|
with gr.Row(): |
|
width = gr.Slider(label="ImageWidth", value=896, minimum=64, maximum=1216, step=32) |
|
height = gr.Slider(label="Image Height", value=1152, minimum=64, maximum=1216, step=32) |
|
steps = gr.Slider(label="Sampling steps", value=50, minimum=1, maximum=100, step=1) |
|
cfg = gr.Slider(label="CFG Scale", value=3.5, minimum=1, maximum=20, step=1) |
|
strength = gr.Slider(label="PromptStrength", value=100, minimum=0, maximum=100, step=1) |
|
seed = gr.Slider(label="Seed", value=-1, minimum=-1, maximum=1000000000, step=1) |
|
method = gr.Radio(label="Sampling method", value="DPM++ 2M Karras", choices=["DPM++ 2M Karras", "DPM++ 2S a Karras", "DPM2 a Karras", "DPM2 Karras", "DPM++ SDE Karras", "DEIS", "LMS", "DPM Adaptive", "DPM++ 2M", "DPM2 Ancestral", "DPM++ S", "DPM++ SDE", "DDPM", "DPM Fast", "dpmpp_2s_ancestral", "Euler", "Euler CFG PP", "Euler a", "Euler Ancestral", "Euler+beta", "Heun", "Heun PP2", "DDIM", "LMS Karras", "PLMS", "UniPC", "UniPC BH2"]) |
|
|
|
|
|
with gr.Row(): |
|
text_button = gr.Button("Generate Image π¨", variant='primary', elem_id="gen-button") |
|
clear_prompt =gr.Button("Clear Prompt ποΈ",variant="primary", elem_id="clear_button") |
|
clear_prompt.click(lambda: (None), None, [text_prompt], queue=False, show_api=False) |
|
|
|
with gr.Column(elem_id="app-container"): |
|
|
|
with gr.Row(): |
|
image_output = gr.Image(type="pil", label="Image Output", format="png", show_share_button=False, elem_id="gallery") |
|
|
|
|
|
with gr.Row(): |
|
clear_results = gr.Button(value="Clear Image ποΈ", variant="primary", elem_id="clear_button") |
|
clear_results.click(lambda: (None), None, [image_output], queue=False, show_api=False) |
|
|
|
with gr.Row(): |
|
gr.Examples( |
|
examples = examples, |
|
inputs = [text_prompt], |
|
) |
|
|
|
|
|
text_button.click(query, inputs=[text_prompt, negative_prompt, steps, cfg, method, seed, strength, width, height], outputs=image_output) |
|
|
|
with gr.TabItem("π Flip Image", visible=False): |
|
with gr.Row(): |
|
image_input = gr.Image(label="Upload Image", height=320, type="filepath") |
|
image_output = gr.Image(format="png") |
|
with gr.Row(): |
|
image_button = gr.Button("Run", variant='primary') |
|
image_button.click(flip_image, inputs=image_input, outputs=image_output) |
|
with gr.Row(): |
|
clear_results = gr.Button(value="Clear Image", variant="primary", elem_id="clear_button") |
|
clear_results.click(lambda: (None, None), None, [image_input, image_output]) |
|
|
|
with gr.TabItem("βΉοΈ Tips", visible=True): |
|
with gr.Column(): |
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.Markdown( |
|
""" |
|
<div style="max-width: 650px; margin: 2rem auto; padding: 1rem; border-radius: 10px; background-color: #f0f0f0;"> |
|
<h2 style="float: left; font-size: 1.5rem; margin-bottom: 1rem;">How to Use</h2> |
|
<ol style="padding-left: 1.5rem;"> |
|
<li>Add an image to generate a prompt, this is optional.</li> |
|
<li>If using an image to prompt, copy the prompt and paste into the prompt on tab 2</li> |
|
<li>Enter a detailed description of the image you want to create.</li> |
|
<li>Adjust advanced settings if desired (tap to expand).</li> |
|
<li>Tap "Generate Image" and wait for your creation!</li> |
|
</ol> |
|
<p style="margin-top: 1rem; font-style: italic;">Tip: Be specific in your description for best results!</p> |
|
<p style="margin-top: 1rem; font-style: italic;">*Note: Some LoRA models will not work every time (not sure why), refresh the page and try again</p> |
|
<p style="margin-top: 1rem; font-style: italic;">**I'm still playing around to try to sort the issue, feel free to let me know if you find a fix**</p> |
|
</div> |
|
""" |
|
) |
|
|
|
app.queue(default_concurrency_limit=200, max_size=200) |
|
if __name__ == "__main__": |
|
app.launch(show_api=False, share=False) |
|
|
|
|