File size: 9,951 Bytes
33adbe7
03fc011
b47a274
796cb1f
b47a274
 
796cb1f
 
 
347eac7
 
b033790
4ced464
 
cc1aefe
4ced464
 
 
cc1aefe
347eac7
b47a274
34a218b
1291091
347eac7
 
796cb1f
34a218b
 
 
 
 
796cb1f
34a218b
796cb1f
 
 
 
 
 
1291091
347eac7
 
796cb1f
347eac7
1291091
347eac7
 
796cb1f
 
 
99a9568
1291091
99a9568
41b1d8d
1291091
41b1d8d
 
 
 
 
 
 
99a9568
45b14e8
1291091
99a9568
347eac7
 
b47a274
 
 
fc2a9f2
8c55048
3eb4ddb
b47a274
8c55048
b47a274
fc2a9f2
b47a274
 
 
 
 
 
 
 
 
 
 
99a9568
b47a274
347eac7
1291091
 
 
 
 
 
b47a274
d813f96
0276c07
34a218b
 
4ced464
34a218b
cc1aefe
 
 
4ced464
cc1aefe
4ced464
7b55e59
4ced464
 
 
 
 
cc1aefe
 
 
 
 
 
 
4ced464
725fd8a
cc1aefe
 
725fd8a
cc1aefe
 
4ced464
cc1aefe
c5aa8f3
99a9568
4ced464
cc1aefe
 
 
 
 
725fd8a
 
cc1aefe
4ced464
725fd8a
4ced464
81c7641
725fd8a
41b1d8d
347eac7
7b55e59
45b14e8
347eac7
 
 
 
 
 
34a218b
 
 
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import gradio as gr
from gradio.themes.utils.colors import Color
import random, time, shared, argparse, modules.path, fooocus_version, modules.html
import modules.async_worker as worker
from math import floor
from PIL import Image, ImageDraw, ImageFont

from modules.sdxl_styles import style_keys, aspect_ratios

QM_LOGO  = Image.open("resources/qm_logo.png")
QM_COLOR = Color(name="qm", c50="#effaed",c100="#def5db",c200="#64b445",c300="#c6eec0",c400="#b9ebb3",c500="#64b445",c600="#55993b",c700="#467e30",c800="#325a23",c900="#233f18",c950="#192d11")
PROMPT_EXAMPLES = ["A family of bunnies with painted eggs on a sunny Easter afternoon", 
                   "A bunny delivering Easter eggs in a hot air balloon", 
                   "A magical Easter castle with towers made of chocolate and candy"]
EXAMPLE_GREETINGS = [ 
    "Ich wünsche dir von Herzen ein frohes Osterfest.",
    "Frohe Ostern! Möge dein Tag mit strahlendem Sonnenschein und viel Freude gefüllt sein.",
    "Zauberhafte Ostern für dich!"
]
INIT_IMAGE_PATH = "resources/init.png"

def generate(*args):
    yield gr.HTML(value=modules.html.make_progress_html(1, "0/30")), \
          gr.Image(), \
          gr.Text()

    while worker.is_working:
        time.sleep(0.1)
        
    worker.buffer=[list(args)]
    worker.outputs = []

    finished=False
    while not finished:
        time.sleep(0.01)
        if len(worker.outputs) > 0:
            flag, product = worker.outputs.pop(0)
            if flag == 'preview':
                percentage, title, image = product
                yield gr.HTML(value=modules.html.make_progress_html(percentage, title)), \
                      gr.Image(value=image) if image is not None else gr.Image(), \
                      gr.Text()
            if flag == 'results':
                image, image_path = product
                yield gr.HTML(value=""), \
                      gr.Image(value=image), \
                      gr.Text(value=image_path)
                finished = True
    return

def toggle_greet_visibility(is_visible):
    return gr.Row(visible=is_visible)

def __toggle_generate_state(is_preview):
    return gr.Image(visible=is_preview), gr.Image(visible=not is_preview), gr.Button(interactive=not is_preview)

def prepare_generate():
    return __toggle_generate_state(True)

def finish_generate():
    return __toggle_generate_state(False)

def debounce():
    time.sleep(0.5)
    return

def overlay_image(image_path, toggle_greet, greet):
    image = ImageDraw.Draw(Image.open(image_path), "RGBA")
    HEIGHT, TEXT_PADDING, TEXTBOX_HEIGHT  = 100, 32, 56
    TEXTBOX_WIDTH = 1280-HEIGHT-4*TEXT_PADDING
    
    X_RECT=1280-HEIGHT-2*TEXT_PADDING
    image.rectangle(((X_RECT, 768-HEIGHT), (1280, 766)), fill=(0, 0, 0, 75))
    image._image.paste(QM_LOGO, (1148,687), QM_LOGO)
    if (toggle_greet):
        image.rectangle(((0, 768-HEIGHT), (X_RECT-1, 768)), fill=(255, 255, 255, 190))
        txt_image = Image.new('RGBA', (4*1280, 4*TEXTBOX_HEIGHT), (255,255,255,0))
        ImageDraw.Draw(txt_image).text(xy=(0,0), text=greet, font=ImageFont.truetype('resources/Neuton-ExtralightItalic.ttf', floor(1.5*TEXTBOX_HEIGHT)), fill=(0, 0, 0))
        image_box = txt_image.getbbox()
        txt_image = txt_image.crop(image_box)
        width, height = txt_image.size
        if (height > 0 and width/height < TEXTBOX_WIDTH/TEXTBOX_HEIGHT):
            txt_image = txt_image.resize((floor((TEXTBOX_HEIGHT/height)*width), TEXTBOX_HEIGHT))
        else:
            txt_image = txt_image.resize((TEXTBOX_WIDTH, floor((TEXTBOX_WIDTH/width)*height)))
        _, height = txt_image.size
        image._image.paste(txt_image, (TEXT_PADDING, 768 - floor((HEIGHT+height)/2)), txt_image)

    return image._image

def make_overlay(image, toggle_greet, greet):
    return gr.Image(value=overlay_image(image, toggle_greet, greet)), gr.Textbox(value=greet)

def verify_latest_overlay(image, toggle_greet, greet, greet_active):
    if greet != greet_active:
        return make_overlay(image, toggle_greet, greet)
    else:
        return gr.Image(), gr.Textbox()

shared.gradio_root = gr.Blocks(title='QualityMinds AI Easter Card Maker', css=modules.html.css, theme=gr.themes.Default(primary_hue=QM_COLOR))
with shared.gradio_root:
    gr.Markdown(
    """
    # QualityMinds KI Osterkarten-Generator
    """)
    with gr.Accordion("Info", elem_classes='panel-container', open=False):
        with gr.Column():
            gr.Markdown("""
            * Beschreibe das Motiv der Osterkarte in einem Prompt (Englisch), wähle ggf. Stil und los!
            * Zur Übersetzung einer Beschreibung ins Englische eignet sich beispielsweise [deepl.com](https://www.deepl.com/translator#de/Schneekugeln) helfen.
            * Kurze persönliche Ostergrüße (bis 2 Zeilen) lassen sich auf der Vorderseite hinzufügen. 
              Längere Texte können nach Druck handschriftlich zur Rückseite hinzugefügt werden.
            * Chat-KIs wie [Bing Chat](https://www.bing.com/search?q=Bing+AI&showconv=1) können bei der Erstellung persönlicher Ostergrüße helfen, z.B. mit Prompts wie
                * Erstelle fünf unterschiedliche persönliche Ostergrüße für meinen Vater Anakin (je ca. 120 Zeichen). Erwähne dabei unseren gemeinsamen Urlaub auf Tatooine.
                * Erstelle drei unterschiedliche persönliche Ostergrüße für meinen geschätzten Arbeitskollegen Michael (je ca. 150 Zeichen). Gehe dabei Schritt für Schritt vor.
                * Erstelle fünf unterschiedliche persönliche Ostergrüße für eine Osterkarte, auf der eine Schneekugel abgebildet ist (je ca. 133 Zeichen) und erkläre diese.
            * Dieses Werkzeug basiert auf [Stable Diffusion XL](https://stability.ai/stable-diffusion) v1.0 und der Oberfläche [Fooocus](https://github.com/lllyasviel/Fooocus), der Code ist OpenSource auf [HuggingFace](https://huggingface.co./spaces/QualityMinds/Osterkarten/tree/main) verfügbar.
            """)

    with gr.Row(elem_classes='panel-container'):
        with gr.Column():
            with gr.Row():
                with gr.Column(scale=5):
                    gr.Markdown("##### Prompt (Englisch)", elem_classes="input-label")
                    prompt = gr.Textbox(value="", placeholder="Was möchtest Du auf der Osterkarte abbilden?", 
                                        autofocus=True, container=False, show_label=False, lines=2)
                with gr.Column(scale=1, min_width="80px"):
                    gr.Markdown("##### Stil", elem_classes="input-label")
                    style_selection = gr.Dropdown(choices=style_keys, value='Kinofilm', container=False, show_label=False, elem_id="style-selection")
                with gr.Column(scale=1, min_width="80px"):
                    progress_html = gr.HTML(visible=True, elem_id='progress-bar', elem_classes='progress-bar')
                    run_button = gr.Button(value="Osterkarte\nerstellen", variant='primary', elem_id='generate-button', )
            with gr.Row():
                gr.Examples(elem_id="prompt-examples", examples=PROMPT_EXAMPLES, inputs=[prompt])
    
    toggle_greet = gr.Checkbox(label="Persönliche Ostergrüße hinzufügen", elem_id="toggle-greet-checkbox",
                               container=False, value=True, interactive=True)

    greeting_row=gr.Row(elem_classes='panel-container')
    with greeting_row:
        with gr.Column():
            greet = gr.Textbox(value=EXAMPLE_GREETINGS[0], placeholder="", interactive=True, container=False, lines=2, max_lines=2, show_label=False)
            greet_active = gr.Textbox(value=EXAMPLE_GREETINGS[0], visible=False, container=False, show_label=False)
            greet_examples = gr.Examples(elem_id="greet-examples", examples=EXAMPLE_GREETINGS, inputs=[greet])
    generated_image = gr.Image(visible=False, type='pil', label="Erstelle Osterkarte...", elem_classes="generated-image", width=1280,
                               value=INIT_IMAGE_PATH, interactive=False, show_share_button=False, show_download_button=False)
    generated_image_overlayed = gr.Image(label="Osterkarte", type='pil', elem_classes="generated-image", width=1280,
                                         value=overlay_image(INIT_IMAGE_PATH, toggle_greet.value, greet.value), show_share_button=False)
    generated_image_path = gr.Text(visible=False, value=INIT_IMAGE_PATH, container=False, show_label=False)
    toggle_greet.change(fn=toggle_greet_visibility, inputs=[toggle_greet], outputs=[greeting_row], queue=False, show_progress=False)\
                .then(fn=make_overlay, inputs=[generated_image_path, toggle_greet, greet], outputs=[generated_image_overlayed, greet_active], show_progress=False, queue=False)
    greet.input(fn=None, inputs=[greet], outputs=[greet], _js="(greet) => { return greet.split('\\n').slice(0,2).join('\\n') }")
    greet.change(fn=debounce, queue=False, show_progress=False)\
         .then(fn=make_overlay, inputs=[generated_image_path, toggle_greet, greet], outputs=[generated_image_overlayed, greet_active], queue=False, show_progress=False)
    greet_active.change(fn=verify_latest_overlay, inputs=[generated_image_path, toggle_greet, greet, greet_active], outputs=[generated_image_overlayed, greet_active], queue=False,  show_progress=False)
    run_button.click(fn=prepare_generate, outputs=[generated_image, generated_image_overlayed, run_button], queue=False)\
              .then(fn=generate, inputs=[prompt, style_selection], outputs=[progress_html, generated_image, generated_image_path], queue=True)\
              .then(fn=make_overlay, inputs=[generated_image_path, toggle_greet, greet], outputs=[generated_image_overlayed, greet_active], queue=False)\
              .then(fn=finish_generate, outputs=[generated_image, generated_image_overlayed, run_button], queue=False)

shared.gradio_root.queue(concurrency_count=1, api_open=False)
shared.gradio_root.launch(server_name="0.0.0.0", show_api=False)