承弱 commited on
Commit
2d9bfd2
1 Parent(s): 4d770bd

add tracked files

Browse files
Files changed (44) hide show
  1. .gitattributes +7 -0
  2. .gitignore +25 -0
  3. app.py +273 -0
  4. css/style.css +32 -0
  5. css/style2.css +71 -0
  6. example_images/banner.png +3 -0
  7. example_images/banner2.png +3 -0
  8. example_images/example_style/2dcartoon_dragon.jpg +0 -0
  9. example_images/example_style/3dcute_dragon.jpg +0 -0
  10. example_images/example_style/blindbox.jpg +0 -0
  11. example_images/example_style/caishenye1.jpg +0 -0
  12. example_images/example_style/caishenye2.jpg +0 -0
  13. example_images/example_style/cartoon_doorgod.jpg +0 -0
  14. example_images/example_style/crayon.jpg +0 -0
  15. example_images/example_style/cute_baby_girl.jpg +0 -0
  16. example_images/example_style/cute_lantern_girl.jpg +0 -0
  17. example_images/example_style/cutegirl1.jpg +0 -0
  18. example_images/example_style/fatdragon.jpg +0 -0
  19. example_images/gallery/2dcartoon_dragon.jpg +0 -0
  20. example_images/gallery/3dcute_dragon.jpg +0 -0
  21. example_images/gallery/blindbox.jpg +0 -0
  22. example_images/gallery/caishenye1.jpg +0 -0
  23. example_images/gallery/caishenye2.jpg +0 -0
  24. example_images/gallery/cartoon_doorgod.jpg +0 -0
  25. example_images/gallery/crayon.jpg +0 -0
  26. example_images/gallery/cute_baby_girl.jpg +0 -0
  27. example_images/gallery/cute_lantern_girl.jpg +0 -0
  28. example_images/gallery/cutegirl1.jpg +0 -0
  29. example_images/gallery/fatdragon.jpg +0 -0
  30. example_images/gallery/kaimenhong.png +3 -0
  31. example_images/templates/bottom2_512_512.png +3 -0
  32. example_images/templates/bottom_512_512.png +3 -0
  33. example_images/templates/left_512_512.png +3 -0
  34. example_images/templates/left_right_512_512.png +3 -0
  35. example_images/templates/right_512_512.png +3 -0
  36. example_images/templates/top2_512_512.png +3 -0
  37. example_images/templates/top_512_512.png +3 -0
  38. example_images/templates/top_bottom_512_512.png +3 -0
  39. javascript/bboxHint.js +554 -0
  40. requirements.txt +3 -0
  41. src/__init__.py +0 -0
  42. src/generation.py +91 -0
  43. src/log.py +18 -0
  44. src/util.py +64 -0
.gitattributes CHANGED
@@ -33,3 +33,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ example_images/example_style filter=lfs diff=lfs merge=lfs -text
37
+ example_images/gallery filter=lfs diff=lfs merge=lfs -text
38
+ example_images/templates filter=lfs diff=lfs merge=lfs -text
39
+ example_images/banner.png filter=lfs diff=lfs merge=lfs -text
40
+ example_images/banner2.png filter=lfs diff=lfs merge=lfs -text
41
+ example_images filter=lfs diff=lfs merge=lfs -text
42
+ *.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ src/__pycache__/
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ bin/
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ eggs/
15
+ lib/
16
+ lib64/
17
+ parts/
18
+ sdist/
19
+ var/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+
24
+ .DS_Store
25
+ workdir/
app.py ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ AnyText: Multilingual Visual Text Generation And Editing
3
+ Paper: https://arxiv.org/abs/2311.03054
4
+ Code: https://github.com/tyxsspa/AnyText
5
+ Copyright (c) Alibaba, Inc. and its affiliates.
6
+ '''
7
+ import os
8
+ import time
9
+ import uuid
10
+ import cv2
11
+ import gradio as gr
12
+ import re
13
+ import json
14
+ import argparse
15
+ import random
16
+ from src.generation import call_generation
17
+ from src.util import upload_np_2_oss
18
+
19
+ def count_lines(prompt):
20
+ prompt = prompt.replace('“', '"')
21
+ prompt = prompt.replace('”', '"')
22
+ p = '"(.*?)"'
23
+ strs = re.findall(p, prompt)
24
+ if len(strs) == 0:
25
+ strs = [' ']
26
+ return len(strs)
27
+
28
+
29
+ def process(mode, prompt, texts, texts2, layout_radio, sort_radio, revise_pos, base_model_path, lora_path_ratio, show_debug, img_count, ddim_steps, w, h, strength, cfg_scale, seed, eta, a_prompt, n_prompt):
30
+ texts = '"' + texts + '"'
31
+ n_lines = count_lines(texts)
32
+ if texts2 != "":
33
+ texts2 = '"' + texts2 + '"'
34
+ n_lines += count_lines(texts2)
35
+ texts += texts2
36
+
37
+ layout_dict = {"top": "example_images/templates/top_512_512.png",
38
+ "down": "example_images/templates/bottom_512_512.png",
39
+ "left": "example_images/templates/left_512_512.png",
40
+ "right": "example_images/templates/right_512_512.png",
41
+ "top two": "example_images/templates/top2_512_512.png",
42
+ "down two": "example_images/templates/bottom2_512_512.png",
43
+ "left and right": "example_images/templates/left_right_512_512.png",
44
+ "top and down": "example_images/templates/top_bottom_512_512.png"}
45
+
46
+
47
+ temp_path = layout_dict[layout_radio]
48
+
49
+ pos_imgs = cv2.imread(temp_path)
50
+ pos_imgs = cv2.resize(pos_imgs, (w, h), interpolation=cv2.INTER_NEAREST)
51
+
52
+ pos_imgs_url = upload_np_2_oss(pos_imgs, 'pos_imgs.png')
53
+
54
+ print(pos_imgs_url)
55
+
56
+
57
+ results = call_generation(prompt + texts, pos_imgs_url, lora_path_ratio, w, h, img_count)
58
+
59
+ return results
60
+
61
+
62
+
63
+ is_t2i = 'true'
64
+ block = gr.Blocks(css='css/style.css', theme=gr.themes.Soft()).queue()
65
+
66
+ with open('javascript/bboxHint.js', 'r') as file:
67
+ value = file.read()
68
+ escaped_value = json.dumps(value)
69
+
70
+ with block:
71
+ block.load(fn=None,
72
+ _js=f"""() => {{
73
+ const script = document.createElement("script");
74
+ const text = document.createTextNode({escaped_value});
75
+ script.appendChild(text);
76
+ document.head.appendChild(script);
77
+ }}""")
78
+ gr.HTML('<div style="text-align: center; margin: 20px auto;"> \
79
+ <img id="banner" src="https://modelscope.cn/api/v1/studio/iic/mememaster/repo?Revision=master&FilePath=example_images/banner2.png" alt="anytext_meme"> <br> \
80
+ [<a href="https://arxiv.org/abs/2311.03054" style="color:blue; font-size:18px;">arXiv</a>] \
81
+ [<a href="https://github.com/tyxsspa/AnyText" style="color:blue; font-size:18px;">Code</a>] \
82
+ [<a href="https://modelscope.cn/models/damo/cv_anytext_text_generation_editing/summary" style="color:blue; font-size:18px;">ModelScope</a>]\
83
+ [<a href="https://huggingface.co/spaces/modelscope/AnyText" style="color:blue; font-size:18px;">HuggingFace</a>]\
84
+ version: 0.1.0 </div>')
85
+ with gr.Row(variant='compact'):
86
+ with gr.Accordion('🕹Instructions', open=True,):
87
+ with gr.Tabs():
88
+ gr.Markdown('<span style="color:black;font-size:16px">Step1: Choose meme style</span>')
89
+ gr.Markdown('<span style="color:black;font-size:16px">Step2: Write texts (support 1-2 lines/Chinese and English)</span>')
90
+ gr.Markdown('<span style="color:black;font-size:16px">Step3: Choose texts layout</span>')
91
+ gr.Markdown('<span style="color:black;font-size:16px">Step4: Generate meme</span>')
92
+
93
+
94
+ with gr.Tab("🖼Meme Gallery"):
95
+ gallery = gr.Gallery(
96
+ label="Generated images", value = [os.path.join('example_images/gallery/',path) for path in os.listdir('example_images/gallery/')],show_label=False, elem_id="gallery"
97
+ , columns=[4], rows=[1], object_fit="contain", height="auto")
98
+
99
+ with gr.Tab("🔧Meme Generation"):
100
+ with gr.Row(variant='compact'):
101
+ with gr.Column() as left_part:
102
+ pass
103
+ with gr.Column():
104
+ result_gallery = gr.Gallery(label='results', show_label=True, preview=True, columns=2, allow_preview=True, height=600)
105
+ # result_info = gr.Markdown('', visible=False)
106
+ with left_part:
107
+ with gr.Accordion('🛠Parameters', open=False):
108
+ # with gr.Row(variant='compact'):
109
+ prompt = gr.Textbox(label="Prompt", elem_id='t2i_prompt', value='Cute Chinese Dragon, (Best quality: 1.1), (Realistic: 1.1), (Photography: 1.1), (highly details: 1.1) with the words ', visible=False)
110
+ with gr.Row(variant='compact'):
111
+ img_count = gr.Slider(label="image number", minimum=1, maximum=4, value=4, step=1)
112
+ ddim_steps = gr.Slider(label="steps", minimum=1, maximum=100, value=20, step=1, visible=False)
113
+ with gr.Row(variant='compact'):
114
+ image_width = gr.Slider(label="width", minimum=256, maximum=768, value=512, step=64)
115
+ image_height = gr.Slider(label="height", minimum=256, maximum=768, value=512, step=64)
116
+ strength = gr.Slider(label="Strength", minimum=0.0, maximum=2.0, value=1.0, step=0.01, visible=False)
117
+ cfg_scale = gr.Slider(label="CFG scale", minimum=0.1, maximum=30.0, value=9.0, step=0.1, visible=False)
118
+ seed = gr.Slider(label="seed", minimum=-1, maximum=99999999, step=1, randomize=False, value=-1, visible=False)
119
+ eta = gr.Number(label="eta (DDIM)", value=0.0, visible=False)
120
+ show_debug = gr.Checkbox(label='debug', value=False, visible=False)
121
+ a_prompt = gr.Textbox(label="Added Prompt", value='best quality, extremely detailed,4k, HD, supper legible text, clear text edges, clear strokes, neat writing, no watermarks', visible=False)
122
+ n_prompt = gr.Textbox(label="Negative Prompt", value='low-res, bad anatomy, extra digit, fewer digits, cropped, worst quality, low quality, watermark, unreadable text, messy words, distorted text, disorganized writing, advertising picture', visible=False)
123
+ base_model_path = gr.Textbox(label='Base Model Path', visible=False, value='./')
124
+ lora_path_ratio = gr.Textbox(label='LoRA Path and Ratio', visible=False, value='9 0.5')
125
+
126
+ with gr.Column():
127
+ with gr.Row(variant='compact'):
128
+ style_radio = gr.Radio(["Q版3D小龙(3D dragon)", "红火财神爷(Red wealthgod)", "2D手绘小龙(2D dragon)","黄金财神爷(Gold wealthgod)","喜庆灯笼(Lantern)","可爱贴纸(Sticker)","可爱喷绘(Splash)","卡通门神(Doorgod)","可爱盲盒(Blindbox)","蜡笔女孩(Crayon)","肥龙在天(Fat dragon)"], value='Q版3D小龙(3D dragon)', label="Meme Style", visible=True)
129
+ example_style1 = gr.Image(value='example_images/example_style/3dcute_dragon.jpg',visible=True, label="Q版3D小龙(3D dragon)", info="效果预览", height=320, width=320, elem_id="example_style1")
130
+ example_style2 = gr.Image(value='example_images/example_style/caishenye1.jpg',visible=False, label="红火财神爷(Red wealthgod)", info="效果预览", height=320, width=320, elem_id="example_style2")
131
+ example_style3 = gr.Image(value='example_images/example_style/2dcartoon_dragon.jpg',visible=False, label="2D手绘小龙(2D dragon)", info="效果预览", height=320, width=320, elem_id="example_style3")
132
+ example_style4 = gr.Image(value='example_images/example_style/caishenye2.jpg',visible=False, label="黄金财神爷(Gold wealthgod)", info="效果预览", height=320, width=320, elem_id="example_style4")
133
+ example_style5 = gr.Image(value='example_images/example_style/cute_lantern_girl.jpg',visible=False, label="喜庆灯笼(Lantern)", info="效果预览", height=320, width=320, elem_id="example_style5")
134
+ example_style6 = gr.Image(value='example_images/example_style/cute_baby_girl.jpg',visible=False, label="可爱贴纸(Sticker)", info="效果预览", height=320, width=320, elem_id="example_style6")
135
+ example_style7 = gr.Image(value='example_images/example_style/cutegirl1.jpg',visible=False, label="可爱喷绘(Splash)", info="效果预览", height=320, width=320, elem_id="example_style7")
136
+ example_style8 = gr.Image(value='example_images/example_style/cartoon_doorgod.jpg',visible=False, label="卡通门神(Doorgod)", info="效果预览", height=320, width=320, elem_id="example_style8")
137
+ example_style9 = gr.Image(value='example_images/example_style/blindbox.jpg',visible=False, label="可爱盲盒(Blindbox)", info="效果预览", height=320, width=320, elem_id="example_style9")
138
+ example_style10 = gr.Image(value='example_images/example_style/crayon.jpg',visible=False, label="蜡笔女孩(Crayon)", info="效果预览", height=320, width=320, elem_id="example_style10")
139
+ example_style11 = gr.Image(value='example_images/example_style/fatdragon.jpg',visible=False, label="肥龙在天(Fat dragon)", info="效果预览", height=320, width=320, elem_id="example_style11")
140
+
141
+
142
+ def change_options2(selected_option):
143
+ if selected_option == 'Q版3D小龙(3D dragon)':
144
+ _text = 'Cute Chinese Dragon, (Best quality: 1.1), (Realistic: 1.1), (Photography: 1.1), (highly details: 1.1), with a sign written '
145
+ _lora = '9 0.5'
146
+ elif selected_option == '红火财神爷(Red wealthgod)':
147
+ _text = '1boy,chinese clothes,facial hair,solo,full body,red_background,chibi, with a sign written '
148
+ _lora = '13 1.0'
149
+ elif selected_option == '2D手绘小龙(2D dragon)':
150
+ _text = 'Cute Chinese Dragon, no humans,white background,solo,full body,looking at viewer,blush stickers,claws, (Best quality: 1.1), (Realistic: 1.1), (Photography: 1.1), (highly details: 1.1), written, with a sign written '
151
+ _lora = '9 0.5'
152
+ elif selected_option == '黄金财神爷(Gold wealthgod)':
153
+ _text = 'dafengcaishen,solo,blush,simple background,long sleeves,1boy,hat,white background,standing,full body,Smiling eyes,male focus,wide sleeves,chibi,facial hair,chinese clothes,crown,facing viewer,mustache, on the sign reads, with a sign written '
154
+ _lora = '10 0.8'
155
+ elif selected_option == '可爱贴纸(Sticker)':
156
+ _text = 'masterpiece,cartoon, best quality,high quality, sticker, 1girl, chinese new year, happy, smiling, with a sign written '
157
+ _lora = '1 0.8'
158
+ elif selected_option == '喜庆灯笼(Lantern)':
159
+ _text = "children's animation, masterpiece,best quality,chinese new year, cartoon drawing, 1girl, cute face, fish, red Chinese dress, half-body, lantern, fireworks, cartoon style, 2d-drawing, with a sign written "
160
+ _lora = '3 0.65'
161
+ elif selected_option == '可爱喷绘(Splash)':
162
+ _text = 'masterpiece,best quality,chinese new year,1girl,close-up portrait, solo, joyful festive expression, cute face, looking at viewer, golden chinese dragon,short hair,blue hair,red background,dress,chinese clothes,red dress,china dress,simple background,cnd style,pose, cndstyle, on the wall that reads, with a sign written '
163
+ _lora = '15 0.8'
164
+ elif selected_option == '卡通门神(Doorgod)':
165
+ _text = 'chinese door gods, a painting of god with a sword and armor, full body, 1boy, male focus, solo, drawing, with a sign written '
166
+ _lora = '2 0.5'
167
+ elif selected_option == '可爱盲盒(Blindbox)':
168
+ _text = 'chinese new year, (masterpiece),(best quality),(ultra-detailed), (full body:1.2),1girl,chibi,cute, smile, open mouth,flower, outdoors, beret, jacket, blush, tree, :3, shirt, short hair, cherry blossoms, red headwear, blurry, brown hair, blush stickers, long sleeves, bangs, headphones, black hair, pink flower,(beautiful detailed face), (beautiful detailed eyes), with a sign written '
169
+ _lora = '6 0.8'
170
+ elif selected_option == '蜡笔女孩(Crayon)':
171
+ _text = 'masterpiece,cartoon, best quality,high quality, 1girl, chinese new year, happy, smiling, with a sign written '
172
+ _lora = '8 0.8'
173
+ elif selected_option == '肥龙在天(Fat dragon)':
174
+ _text = 'Cute yellow fat Dragon, flying in the cloud, simple background, 2D cartoon, 2D sticker, with a sign written '
175
+ _lora = '9 0.5'
176
+
177
+ return [
178
+ gr.Textbox(value=_text),
179
+ gr.Textbox(value=_lora),
180
+ gr.Image(visible=selected_option == 'Q版3D小龙(3D dragon)'),
181
+ gr.Image(visible=selected_option == '红火财神爷(Red wealthgod)'),
182
+ gr.Image(visible=selected_option == '2D手绘小龙(2D dragon)'),
183
+ gr.Image(visible=selected_option == '黄金财神爷(Gold wealthgod)'),
184
+ gr.Image(visible=selected_option == '喜庆灯笼(Lantern)'),
185
+ gr.Image(visible=selected_option == '可爱贴纸(Sticker)'),
186
+ gr.Image(visible=selected_option == '可爱喷绘(Splash)'),
187
+ gr.Image(visible=selected_option == '卡通门神(Doorgod)'),
188
+ gr.Image(visible=selected_option == '可爱盲盒(Blindbox)'),
189
+ gr.Image(visible=selected_option == '蜡笔女孩(Crayon)'),
190
+ gr.Image(visible=selected_option == '肥龙在天(Fat dragon)'),
191
+ ]
192
+ style_radio.change(change_options2, style_radio, [prompt, lora_path_ratio, example_style1, example_style2, example_style3,example_style4,example_style5,example_style6,example_style7,example_style8,example_style9, example_style10, example_style11], show_progress=False, queue=False)
193
+
194
+
195
+
196
+
197
+ def change_buttons(selected_option):
198
+ if selected_option == 'Add a line':
199
+ return [gr.Button(value="Delete a line", scale=0.3, elem_classes='add_row'),
200
+ gr.Textbox(value='恭喜发财', visible=True),
201
+ gr.Radio(["top two","down two","left and right","top and down"], value='left right')]
202
+ elif selected_option == 'Delete a line':
203
+ return [gr.Button(value="Add a line", scale=0.3, elem_classes='add_row'),
204
+ gr.Textbox(value="", visible=False),
205
+ gr.Radio(["top","down","left","right"], value='down')]
206
+
207
+
208
+
209
+
210
+ texts = gr.Textbox(label="Input Texts(first line)", value='新春快乐')
211
+ texts2 = gr.Textbox(label="Input Texts(second line)", value='', visible=False)
212
+ layout_radio = gr.Radio(["top","down","left","right"], value='down', label="text layout", visible=True)
213
+
214
+ def text_change(in_texts):
215
+ if len(in_texts)> 10:
216
+ gr.Warning("The text length is too long, please input a shorter text for better quality.")
217
+
218
+ return
219
+
220
+
221
+ texts.change(fn=text_change, inputs=texts, outputs=None)
222
+ texts2.change(fn=text_change, inputs=texts2, outputs=None)
223
+
224
+ with gr.Row():
225
+ gr.Markdown("")
226
+ add_row_bt = gr.Button(value="Add a line", scale=0.3, elem_classes='add_row')
227
+ gr.Markdown("")
228
+
229
+ add_row_bt.click(change_buttons, add_row_bt, [add_row_bt,texts2,layout_radio], show_progress=False, queue=False)
230
+
231
+ layout_radio.change(fn=None, inputs=layout_radio, outputs=layout_radio, show_progress=False, queue=False)
232
+
233
+
234
+ def exp_gen_click():
235
+ return [gr.Slider(value=512), gr.Slider(value=512)] # all examples are 512x512, refresh draw_img
236
+ with gr.Tab("Examples"):
237
+ with gr.Row(variant='compact'):
238
+ exp_gen_en = gr.Examples(
239
+ [
240
+ ['新年快乐'],
241
+ ['Happy New Year'],
242
+ ['恭贺新年'],
243
+ ['新春快乐'],
244
+ ['龙年吉祥'],
245
+ ['万事如意'],
246
+ ['大吉大利'],
247
+ ['恭贺新禧'],
248
+ ['初五迎财神'],
249
+ ['恭喜发财']
250
+ ],
251
+ [texts],
252
+ examples_per_page=15,
253
+ label=''
254
+ )
255
+ exp_gen_en.dataset.click(exp_gen_click, None, [image_width, image_height])
256
+
257
+
258
+ with gr.Row():
259
+ sort_radio = gr.Radio(["↕", "↔"], value='↕', label="Sort Position", info="position sorting priority", visible=False)
260
+ revise_pos = gr.Checkbox(label='Revise Position', value=False, visible=False)
261
+
262
+ with gr.Row():
263
+ gr.Markdown("")
264
+ run_gen = gr.Button(value="Generate meme!", scale=0.3, elem_classes='run')
265
+ gr.Markdown("")
266
+
267
+
268
+
269
+
270
+ ips = [prompt, texts, texts2, layout_radio, sort_radio, revise_pos, base_model_path, lora_path_ratio, show_debug,img_count, ddim_steps, image_width, image_height, strength, cfg_scale, seed, eta, a_prompt, n_prompt]
271
+ run_gen.click(fn=process, inputs=[gr.State('gen')] + ips, outputs=[result_gallery])
272
+
273
+ block.launch(server_name='0.0.0.0',share=False, server_port=7687)
css/style.css ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #banner {
2
+ max-width: 400px;
3
+ margin: auto;
4
+ box-shadow: 0 2px 20px rgba(0, 0, 0, 0.5) !important;
5
+ border-radius: 20px;
6
+ }
7
+
8
+ .run {
9
+ background-color: #624AFF !important;
10
+ color: #FFFFFF !important;
11
+ border-radius: 2px !important;
12
+ box-shadow: 0 3px 5px rgba(0, 0, 0, 0.5) !important;
13
+ }
14
+ .run:active {
15
+ background-color: #d96565 !important;
16
+ }
17
+ .run:hover {
18
+ background-color: #a079f5 !important;
19
+ }
20
+ /* tab button style */
21
+ button.svelte-kqij2n {
22
+ margin-bottom: -1px;
23
+ border: 1px solid transparent;
24
+ border-color: transparent;
25
+ border-bottom: none;
26
+ color: #9CA3AF !important;
27
+ font-size: 16px;
28
+ }
29
+ button.selected.svelte-kqij2n {
30
+ background: #ddd8f9 !important;
31
+ color: rgb(62, 7, 240) !important;
32
+ }
css/style2.css ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .baselayout {
3
+ background: url('https://img.alicdn.com/imgextra/i1/O1CN016hd0V91ilWY5Xr24B_!!6000000004453-2-tps-2882-256.png') no-repeat;
4
+ }
5
+
6
+ #btn {
7
+ background-color: #336699;
8
+ color: white;
9
+ }
10
+
11
+ #recBut {
12
+ background-color: #bb5252;
13
+ color: white;
14
+ width: 30%;
15
+ margin: auto;
16
+ }
17
+
18
+ #btnSEG {
19
+ background-color: #D5F3F4;
20
+ color: black;
21
+ }
22
+
23
+ #btnCHAT {
24
+ background-color: #B6DBF2;
25
+ color: black;
26
+ }
27
+
28
+ #accordion {
29
+ background-color: transparent;
30
+ }
31
+
32
+ #accordion1 {
33
+ background-color: #ecedee;
34
+ }
35
+
36
+ .feedback button.selected {
37
+ background-color: #6699CC;
38
+ color: white !important;
39
+ }
40
+
41
+ .feedback1 button.selected {
42
+ background-color: #839ab2;
43
+ color: white !important;
44
+ }
45
+
46
+ .Tab button.selected {
47
+ color: red;
48
+ font-weight: bold;
49
+ }
50
+
51
+ #Image {
52
+ width: 80%;
53
+ margin: auto;
54
+ }
55
+
56
+ #ShowCase {
57
+ width: 30%;
58
+ flex: none !important;
59
+ }
60
+
61
+ #Input {
62
+ border-style: solid;
63
+ border-width: 1px;
64
+ border-color: #000000
65
+ }
66
+
67
+ #Seg {
68
+ min-width: min(100px, 100%) !important;
69
+ width: 100%;
70
+ margin: auto;
71
+ }
example_images/banner.png ADDED

Git LFS Details

  • SHA256: 4ceafd52f8cf85913731c943c1cfb21d51d651689daa90b9a4781ec0b58e5308
  • Pointer size: 131 Bytes
  • Size of remote file: 399 kB
example_images/banner2.png ADDED

Git LFS Details

  • SHA256: 6de7efb96696718eb26da9e3437e22421aa245fc1743b1e622eb74bd139cde4e
  • Pointer size: 131 Bytes
  • Size of remote file: 578 kB
example_images/example_style/2dcartoon_dragon.jpg ADDED
example_images/example_style/3dcute_dragon.jpg ADDED
example_images/example_style/blindbox.jpg ADDED
example_images/example_style/caishenye1.jpg ADDED
example_images/example_style/caishenye2.jpg ADDED
example_images/example_style/cartoon_doorgod.jpg ADDED
example_images/example_style/crayon.jpg ADDED
example_images/example_style/cute_baby_girl.jpg ADDED
example_images/example_style/cute_lantern_girl.jpg ADDED
example_images/example_style/cutegirl1.jpg ADDED
example_images/example_style/fatdragon.jpg ADDED
example_images/gallery/2dcartoon_dragon.jpg ADDED
example_images/gallery/3dcute_dragon.jpg ADDED
example_images/gallery/blindbox.jpg ADDED
example_images/gallery/caishenye1.jpg ADDED
example_images/gallery/caishenye2.jpg ADDED
example_images/gallery/cartoon_doorgod.jpg ADDED
example_images/gallery/crayon.jpg ADDED
example_images/gallery/cute_baby_girl.jpg ADDED
example_images/gallery/cute_lantern_girl.jpg ADDED
example_images/gallery/cutegirl1.jpg ADDED
example_images/gallery/fatdragon.jpg ADDED
example_images/gallery/kaimenhong.png ADDED

Git LFS Details

  • SHA256: 3d741f2c0221befaa14e362a5299351cea0592c9509e5aac9cc336492a1d4a71
  • Pointer size: 131 Bytes
  • Size of remote file: 429 kB
example_images/templates/bottom2_512_512.png ADDED

Git LFS Details

  • SHA256: b10fa5ca8f8f4dba3a298cb0ecec327356f7ee2e5e60262bf61b2eb52f472bc6
  • Pointer size: 130 Bytes
  • Size of remote file: 11.8 kB
example_images/templates/bottom_512_512.png ADDED

Git LFS Details

  • SHA256: ecab19675624499a32c16a709007c8d17376f40a39f4f9c5db685a6e41d34eb2
  • Pointer size: 130 Bytes
  • Size of remote file: 11.5 kB
example_images/templates/left_512_512.png ADDED

Git LFS Details

  • SHA256: 2a1d8e64d3206962c178599823ac8752622e03ca898dfe3ee8aaa450cbf7b11e
  • Pointer size: 129 Bytes
  • Size of remote file: 8.81 kB
example_images/templates/left_right_512_512.png ADDED

Git LFS Details

  • SHA256: 3abc7971d2cf8a554f01b8c1f53ef67d0afd226b287d36fab764da7e89bf489d
  • Pointer size: 130 Bytes
  • Size of remote file: 12.1 kB
example_images/templates/right_512_512.png ADDED

Git LFS Details

  • SHA256: 039e68997859c7677f19f143839b6bac321b0714b095a17ed58b19fe940c41a7
  • Pointer size: 130 Bytes
  • Size of remote file: 12 kB
example_images/templates/top2_512_512.png ADDED

Git LFS Details

  • SHA256: f29a732ad8dc2c063e1de3f9abba1c05baee097632e69c358e92f8fbb5986203
  • Pointer size: 130 Bytes
  • Size of remote file: 12.1 kB
example_images/templates/top_512_512.png ADDED

Git LFS Details

  • SHA256: a48997547b47f55541841465ee78d25d57d5457b49b58ec61ef53cdc70336d4f
  • Pointer size: 130 Bytes
  • Size of remote file: 12.1 kB
example_images/templates/top_bottom_512_512.png ADDED

Git LFS Details

  • SHA256: 818ec428500f06521139490ecad7bf9acf85347287f40d34ac9293badb4beb64
  • Pointer size: 130 Bytes
  • Size of remote file: 12.2 kB
javascript/bboxHint.js ADDED
@@ -0,0 +1,554 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Part of the implementation is borrowed and modified from multidiffusion-upscaler-for-automatic1111,
3
+ publicly available at https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111
4
+ */
5
+
6
+ const BBOX_MAX_NUM = 16;
7
+ const BBOX_WARNING_SIZE = 1280;
8
+ const DEFAULT_X = 0.4;
9
+ const DEFAULT_Y = 0.4;
10
+ const DEFAULT_H = 0.2;
11
+ const DEFAULT_W = 0.2;
12
+
13
+ // ref: https://html-color.codes/
14
+ const COLOR_MAP = [
15
+ ['#ff0000', 'rgba(255, 0, 0, 0.3)'], // red
16
+ ['#ff9900', 'rgba(255, 153, 0, 0.3)'], // orange
17
+ ['#ffff00', 'rgba(255, 255, 0, 0.3)'], // yellow
18
+ ['#33cc33', 'rgba(51, 204, 51, 0.3)'], // green
19
+ ['#33cccc', 'rgba(51, 204, 204, 0.3)'], // indigo
20
+ ['#0066ff', 'rgba(0, 102, 255, 0.3)'], // blue
21
+ ['#6600ff', 'rgba(102, 0, 255, 0.3)'], // purple
22
+ ['#cc00cc', 'rgba(204, 0, 204, 0.3)'], // dark pink
23
+ ['#ff6666', 'rgba(255, 102, 102, 0.3)'], // light red
24
+ ['#ffcc66', 'rgba(255, 204, 102, 0.3)'], // light orange
25
+ ['#99cc00', 'rgba(153, 204, 0, 0.3)'], // lime green
26
+ ['#00cc99', 'rgba(0, 204, 153, 0.3)'], // teal
27
+ ['#0099cc', 'rgba(0, 153, 204, 0.3)'], // steel blue
28
+ ['#9933cc', 'rgba(153, 51, 204, 0.3)'], // lavender
29
+ ['#ff3399', 'rgba(255, 51, 153, 0.3)'], // hot pink
30
+ ['#996633', 'rgba(153, 102, 51, 0.3)'], // brown
31
+ ];
32
+
33
+ const RESIZE_BORDER = 5;
34
+ const MOVE_BORDER = 5;
35
+
36
+ const t2i_bboxes = new Array(BBOX_MAX_NUM).fill(null);
37
+ const i2i_bboxes = new Array(BBOX_MAX_NUM).fill(null);
38
+
39
+ function gradioApp() {
40
+ const elems = document.getElementsByTagName('gradio-app')
41
+ const gradioShadowRoot = elems.length == 0 ? null : elems[0].shadowRoot
42
+ return !!gradioShadowRoot ? gradioShadowRoot : document;
43
+ }
44
+
45
+ // ↓↓↓ called from gradio ↓↓↓
46
+
47
+ function onCreateT2IRefClick(overwrite) {
48
+ let width, height;
49
+ if (overwrite) {
50
+ const overwriteInputs = gradioApp().querySelectorAll('#MD-overwrite-width-t2i input, #MD-overwrite-height-t2i input');
51
+ width = parseInt(overwriteInputs[0].value);
52
+ height = parseInt(overwriteInputs[2].value);
53
+ } else {
54
+ const sizeInputs = gradioApp().querySelectorAll('#txt2img_width input, #txt2img_height input');
55
+ width = parseInt(sizeInputs[0].value);
56
+ height = parseInt(sizeInputs[2].value);
57
+ }
58
+
59
+ if (isNaN(width)) width = 512;
60
+ if (isNaN(height)) height = 512;
61
+
62
+ // Concat it to string to bypass the gradio bug
63
+ // 向黑恶势力低头
64
+ return width.toString() + 'x' + height.toString();
65
+ }
66
+
67
+ function onCreateI2IRefClick() {
68
+ const canvas = gradioApp().querySelector('#img2img_image img');
69
+ return canvas.src;
70
+ }
71
+
72
+ function onBoxEnableClick(is_t2i, idx, enable) {
73
+ let canvas = null;
74
+ let bboxes = null;
75
+ let locator = null;
76
+ if (is_t2i) {
77
+ // locator = () => gradioApp().querySelector('#MD-bbox-ref-t2i');
78
+ locator = () => gradioApp().querySelector('#MD-bbox-rect-t2i');
79
+ bboxes = t2i_bboxes;
80
+
81
+ } else {
82
+ locator = () => gradioApp().querySelector('#MD-bbox-ref-i2i');
83
+ bboxes = i2i_bboxes;
84
+ }
85
+ ref_div = locator();
86
+ canvas = ref_div.querySelector('img');
87
+ if (!canvas) { return false; }
88
+
89
+ if (enable) {
90
+ // Check if the bounding box already exists
91
+ if (!bboxes[idx]) {
92
+ // Initialize bounding box
93
+ const bbox = [DEFAULT_X, DEFAULT_Y, DEFAULT_W, DEFAULT_H];
94
+ const colorMap = COLOR_MAP[idx % COLOR_MAP.length];
95
+ const div = document.createElement('div');
96
+ div.id = 'MD-bbox-' + (is_t2i ? 't2i-' : 'i2i-') + idx;
97
+ div.style.left = '0px';
98
+ div.style.top = '0px';
99
+ div.style.width = '0px';
100
+ div.style.height = '0px';
101
+ div.style.position = 'absolute';
102
+ div.style.border = '2px solid ' + colorMap[0];
103
+ div.style.background = colorMap[1];
104
+ div.style.zIndex = '900';
105
+ div.style.display = 'none';
106
+ // A text tip to warn the user if bbox is too large
107
+ const tip = document.createElement('span');
108
+ tip.id = 'MD-tip-' + (is_t2i ? 't2i-' : 'i2i-') + idx;
109
+ tip.style.left = '50%';
110
+ tip.style.top = '50%';
111
+ tip.style.position = 'absolute';
112
+ tip.style.transform = 'translate(-50%, -50%)';
113
+ tip.style.fontSize = '12px';
114
+ tip.style.fontWeight = 'bold';
115
+ tip.style.textAlign = 'center';
116
+ tip.style.color = colorMap[0];
117
+ tip.style.zIndex = '901';
118
+ tip.style.display = 'none';
119
+ tip.innerHTML = 'Warning: Region very large!<br>Take care of VRAM usage!';
120
+ div.appendChild(tip);
121
+ div.addEventListener('mousedown', function (e) {
122
+ if (e.button === 0) { onBoxMouseDown(e, is_t2i, idx); }
123
+ });
124
+ div.addEventListener('mousemove', function (e) {
125
+ updateCursorStyle(e, is_t2i, idx);
126
+ });
127
+
128
+ const shower = function() { // insert to DOM if necessary
129
+ if (!gradioApp().querySelector('#' + div.id)) {
130
+ locator().appendChild(div);
131
+ }
132
+ }
133
+ bboxes[idx] = [div, bbox, shower];
134
+ }
135
+
136
+ // Show the bounding box
137
+ displayBox(canvas, is_t2i, bboxes[idx]);
138
+ return true;
139
+ } else {
140
+ if (!bboxes[idx]) { return false; }
141
+ const [div, bbox, shower] = bboxes[idx];
142
+ div.style.display = 'none';
143
+ }
144
+ return false;
145
+ }
146
+
147
+ function onBoxChange(is_t2i, idx, what, v) {
148
+ // This function handles all the changes of the bounding box
149
+ // Including the rendering and python slider update
150
+ let bboxes = null;
151
+ let canvas = null;
152
+ if (is_t2i) {
153
+ bboxes = t2i_bboxes;
154
+ canvas = gradioApp().querySelector('#MD-bbox-rect-t2i img');
155
+ } else {
156
+ bboxes = i2i_bboxes;
157
+ canvas = gradioApp().querySelector('#MD-bbox-ref-i2i img');
158
+ }
159
+ if (!bboxes[idx] || !canvas) {
160
+ switch (what) {
161
+ case 'x': return DEFAULT_X;
162
+ case 'y': return DEFAULT_Y;
163
+ case 'w': return DEFAULT_W;
164
+ case 'h': return DEFAULT_H;
165
+ }
166
+ }
167
+ const [div, bbox, shower] = bboxes[idx];
168
+ if (div.style.display === 'none') { return v; }
169
+
170
+ // parse trigger
171
+ switch (what) {
172
+ case 'x': bbox[0] = v; break;
173
+ case 'y': bbox[1] = v; break;
174
+ case 'w': bbox[2] = v; break;
175
+ case 'h': bbox[3] = v; break;
176
+ }
177
+ displayBox(canvas, is_t2i, bboxes[idx]);
178
+ return v;
179
+ }
180
+
181
+ // ↓↓↓ called from js ↓↓↓
182
+
183
+ function getSeedInfo(is_t2i, id, current_seed) {
184
+ const info_id = is_t2i ? '#html_info_txt2img' : '#html_info_img2img';
185
+ const info_div = gradioApp().querySelector(info_id);
186
+ try{
187
+ current_seed = parseInt(current_seed);
188
+ } catch(e) {
189
+ current_seed = -1;
190
+ }
191
+ if (!info_div) return current_seed;
192
+ let info = info_div.innerHTML;
193
+ if (!info) return current_seed;
194
+ // remove all html tags
195
+ info = info.replace(/<[^>]*>/g, '');
196
+ // Find a json string 'region control:' in the info
197
+ // get its index
198
+ idx = info.indexOf('Region control');
199
+ if (idx == -1) return current_seed;
200
+ // get the json string (detect the bracket)
201
+ // find the first '{'
202
+ let start_idx = info.indexOf('{', idx);
203
+ let bracket = 1;
204
+ let end_idx = start_idx + 1;
205
+ while (bracket > 0 && end_idx < info.length) {
206
+ if (info[end_idx] == '{') bracket++;
207
+ if (info[end_idx] == '}') bracket--;
208
+ end_idx++;
209
+ }
210
+ if (bracket > 0) {
211
+ return current_seed;
212
+ }
213
+ // get the json string
214
+ let json_str = info.substring(start_idx, end_idx);
215
+ // replace the single quote to double quote
216
+ json_str = json_str.replace(/'/g, '"');
217
+ // replace python True to javascript true, False to false
218
+ json_str = json_str.replace(/True/g, 'true');
219
+ // parse the json string
220
+ let json = JSON.parse(json_str);
221
+ // get the seed if the region id is in the json
222
+ const region_id = 'Region ' + id.toString();
223
+ if (!(region_id in json)) return current_seed;
224
+ const region = json[region_id];
225
+ if (!('seed' in region)) return current_seed;
226
+ let seed = region['seed'];
227
+ try{
228
+ seed = parseInt(seed);
229
+ } catch(e) {
230
+ return current_seed;
231
+ }
232
+ return seed;
233
+ }
234
+
235
+ function displayBox(canvas, is_t2i, bbox_info) {
236
+ // check null input
237
+ const [div, bbox, shower] = bbox_info;
238
+ const [x, y, w, h] = bbox;
239
+ if (!canvas || !div || x == null || y == null || w == null || h == null) { return; }
240
+
241
+ // client: canvas widget display size
242
+ // natural: content image real size
243
+ let vpScale = Math.min(canvas.clientWidth / canvas.naturalWidth, canvas.clientHeight / canvas.naturalHeight);
244
+ let canvasCenterX = canvas.clientWidth / 2;
245
+ let canvasCenterY = canvas.clientHeight / 2;
246
+ let scaledX = canvas.naturalWidth * vpScale;
247
+ let scaledY = canvas.naturalHeight * vpScale;
248
+ let viewRectLeft = canvasCenterX - scaledX / 2;
249
+ let viewRectRight = canvasCenterX + scaledX / 2;
250
+ let viewRectTop = canvasCenterY - scaledY / 2;
251
+ let viewRectDown = canvasCenterY + scaledY / 2;
252
+
253
+ let xDiv = viewRectLeft + scaledX * x;
254
+ let yDiv = viewRectTop + scaledY * y;
255
+ let wDiv = Math.min(scaledX * w, viewRectRight - xDiv);
256
+ let hDiv = Math.min(scaledY * h, viewRectDown - yDiv);
257
+
258
+ // Calculate warning bbox size
259
+ let upscalerFactor = 1.0;
260
+ if (!is_t2i) {
261
+ const upscalerInput = parseFloat(gradioApp().querySelector('#MD-i2i-upscaler-factor input').value);
262
+ if (!isNaN(upscalerInput)) upscalerFactor = upscalerInput;
263
+ }
264
+ let maxSize = BBOX_WARNING_SIZE / upscalerFactor * vpScale;
265
+ let maxW = maxSize / scaledX;
266
+ let maxH = maxSize / scaledY;
267
+ if (w > maxW || h > maxH) {
268
+ div.querySelector('span').style.display = 'block';
269
+ } else {
270
+ div.querySelector('span').style.display = 'none';
271
+ }
272
+
273
+ // update <div> when not equal
274
+ div.style.left = xDiv + 'px';
275
+ div.style.top = yDiv + 'px';
276
+ div.style.width = wDiv + 'px';
277
+ div.style.height = hDiv + 'px';
278
+ div.style.display = 'block';
279
+
280
+ // insert it to DOM if not appear
281
+ shower();
282
+ }
283
+
284
+ function onBoxMouseDown(e, is_t2i, idx) {
285
+ let bboxes = null;
286
+ let canvas = null;
287
+ if (is_t2i) {
288
+ bboxes = t2i_bboxes;
289
+ canvas = gradioApp().querySelector('#MD-bbox-rect-t2i img');
290
+ } else {
291
+ bboxes = i2i_bboxes;
292
+ canvas = gradioApp().querySelector('#MD-bbox-ref-i2i img');
293
+ }
294
+ // Get the bounding box
295
+ if (!canvas || !bboxes[idx]) { return; }
296
+ const [div, bbox, shower] = bboxes[idx];
297
+
298
+ // Check if the click is inside the bounding box
299
+ const boxRect = div.getBoundingClientRect();
300
+ let mouseX = e.clientX;
301
+ let mouseY = e.clientY;
302
+
303
+ const resizeLeft = mouseX >= boxRect.left && mouseX <= boxRect.left + RESIZE_BORDER;
304
+ const resizeRight = mouseX >= boxRect.right - RESIZE_BORDER && mouseX <= boxRect.right;
305
+ const resizeTop = mouseY >= boxRect.top && mouseY <= boxRect.top + RESIZE_BORDER;
306
+ const resizeBottom = mouseY >= boxRect.bottom - RESIZE_BORDER && mouseY <= boxRect.bottom;
307
+
308
+ const moveHorizontal = mouseX >= boxRect.left + MOVE_BORDER && mouseX <= boxRect.right - MOVE_BORDER;
309
+ const moveVertical = mouseY >= boxRect.top + MOVE_BORDER && mouseY <= boxRect.bottom - MOVE_BORDER;
310
+
311
+ if (!resizeLeft && !resizeRight && !resizeTop && !resizeBottom && !moveHorizontal && !moveVertical) { return; }
312
+
313
+ const horizontalPivot = resizeLeft ? bbox[0] + bbox[2] : bbox[0];
314
+ const verticalPivot = resizeTop ? bbox[1] + bbox[3] : bbox[1];
315
+
316
+ // Canvas can be regarded as invariant during the drag operation
317
+ // Calculate in advance to reduce overhead
318
+
319
+ // Calculate viewport scale based on the current canvas size and the natural image size
320
+ let vpScale = Math.min(canvas.clientWidth / canvas.naturalWidth, canvas.clientHeight / canvas.naturalHeight);
321
+ let vpOffset = canvas.getBoundingClientRect();
322
+
323
+ // Calculate scaled dimensions of the canvas
324
+ let scaledX = canvas.naturalWidth * vpScale;
325
+ let scaledY = canvas.naturalHeight * vpScale;
326
+
327
+ // Calculate the canvas center and view rectangle coordinates
328
+ let canvasCenterX = (vpOffset.left + window.scrollX) + canvas.clientWidth / 2;
329
+ let canvasCenterY = (vpOffset.top + window.scrollY) + canvas.clientHeight / 2;
330
+ let viewRectLeft = canvasCenterX - scaledX / 2 - window.scrollX;
331
+ let viewRectRight = canvasCenterX + scaledX / 2 - window.scrollX;
332
+ let viewRectTop = canvasCenterY - scaledY / 2 - window.scrollY;
333
+ let viewRectDown = canvasCenterY + scaledY / 2 - window.scrollY;
334
+
335
+ mouseX = Math.min(Math.max(mouseX, viewRectLeft), viewRectRight);
336
+ mouseY = Math.min(Math.max(mouseY, viewRectTop), viewRectDown);
337
+
338
+ //const accordion = gradioApp().querySelector(`#MD-accordion-${is_t2i ? 't2i' : 'i2i'}-${idx}`);
339
+ const accordion = gradioApp().querySelector('#MD-tab-t2i');
340
+
341
+ // Move or resize the bounding box on mousemove
342
+ function onMouseMove(e) {
343
+ // Prevent selecting anything irrelevant
344
+ e.preventDefault();
345
+
346
+ // Get the new mouse position
347
+ let newMouseX = e.clientX;
348
+ let newMouseY = e.clientY;
349
+
350
+ // clamp the mouse position to the view rectangle
351
+ newMouseX = Math.min(Math.max(newMouseX, viewRectLeft), viewRectRight);
352
+ newMouseY = Math.min(Math.max(newMouseY, viewRectTop), viewRectDown);
353
+
354
+ // Calculate the mouse movement delta
355
+ const dx = (newMouseX - mouseX) / scaledX;
356
+ const dy = (newMouseY - mouseY) / scaledY;
357
+
358
+ // Update the mouse position
359
+ mouseX = newMouseX;
360
+ mouseY = newMouseY;
361
+
362
+ // if no move just return
363
+ if (dx === 0 && dy === 0) { return; }
364
+
365
+ // Update the mouse position
366
+ let [x, y, w, h] = bbox;
367
+ if (moveHorizontal && moveVertical) {
368
+ // If moving the bounding box
369
+ x = Math.min(Math.max(x + dx, 0), 1 - w);
370
+ y = Math.min(Math.max(y + dy, 0), 1 - h);
371
+ } else {
372
+ // If resizing the bounding box
373
+ if (resizeLeft || resizeRight) {
374
+ if (x < horizontalPivot) {
375
+ if (dx <= w) {
376
+ // If still within the left side of the pivot
377
+ x = x + dx;
378
+ w = w - dx;
379
+ } else {
380
+ // If crossing the pivot
381
+ w = dx - w;
382
+ x = horizontalPivot;
383
+ }
384
+ } else {
385
+ if (w + dx < 0) {
386
+ // If still within the right side of the pivot
387
+ x = horizontalPivot + w + dx;
388
+ w = - dx - w;
389
+ } else {
390
+ // If crossing the pivot
391
+ x = horizontalPivot;
392
+ w = w + dx;
393
+ }
394
+ }
395
+
396
+ // Clamp the bounding box to the image
397
+ if (x < 0) {
398
+ w = w + x;
399
+ x = 0;
400
+ } else if (x + w > 1) {
401
+ w = 1 - x;
402
+ }
403
+ }
404
+ // Same as above, but for the vertical axis
405
+ if (resizeTop || resizeBottom) {
406
+ if (y < verticalPivot) {
407
+ if (dy <= h) {
408
+ y = y + dy;
409
+ h = h - dy;
410
+ } else {
411
+ h = dy - h;
412
+ y = verticalPivot;
413
+ }
414
+ } else {
415
+ if (h + dy < 0) {
416
+ y = verticalPivot + h + dy;
417
+ h = - dy - h;
418
+ } else {
419
+ y = verticalPivot;
420
+ h = h + dy;
421
+ }
422
+ }
423
+ if (y < 0) {
424
+ h = h + y;
425
+ y = 0;
426
+ } else if (y + h > 1) {
427
+ h = 1 - y;
428
+ }
429
+ }
430
+ }
431
+ const [div, old_bbox, _] = bboxes[idx];
432
+
433
+ // If all the values are the same, just return
434
+ if (old_bbox[0] === x && old_bbox[1] === y && old_bbox[2] === w && old_bbox[3] === h) { return; }
435
+ // else update the bbox
436
+ const event = new Event('input');
437
+ const coords = [x, y, w, h];
438
+ // <del>The querySelector is not very efficient, so we query it once and reuse it</del>
439
+ // caching will result gradio bugs that stucks bbox and cannot move & drag
440
+ const sliderIds = ['x', 'y', 'w', 'h'];
441
+ // We try to select the input sliders
442
+ const sliderSelectors = sliderIds.map(id => `#MD-${is_t2i ? 't2i' : 'i2i'}-${idx}-${id} input`).join(', ');
443
+ let sliderInputs = accordion.querySelectorAll(sliderSelectors);
444
+ // alert(sliderInputs.length)
445
+ if (sliderInputs.length == 0) {
446
+ // If we failed, the accordion is probably closed and sliders are removed in the dom, so we open it
447
+ accordion.querySelector('.label-wrap').click();
448
+ // and try again
449
+ sliderInputs = accordion.querySelectorAll(sliderSelectors);
450
+ // If we still failed, we just return
451
+ if (sliderInputs.length == 0) { return; }
452
+ }
453
+ for (let i = 0; i < 4; i++) {
454
+ if (old_bbox[i] !== coords[i]) {
455
+ sliderInputs[2*i].value = coords[i];
456
+ sliderInputs[2*i].dispatchEvent(event);
457
+ }
458
+ }
459
+ }
460
+
461
+ // Remove the mousemove and mouseup event listeners
462
+ function onMouseUp() {
463
+ document.removeEventListener('mousemove', onMouseMove);
464
+ document.removeEventListener('mouseup', onMouseUp);
465
+ }
466
+
467
+ // Add the event listeners
468
+ document.addEventListener('mousemove', onMouseMove);
469
+ document.addEventListener('mouseup', onMouseUp);
470
+ }
471
+
472
+ function updateCursorStyle(e, is_t2i, idx) {
473
+ // This function changes the cursor style when hovering over the bounding box
474
+ const bboxes = is_t2i ? t2i_bboxes : i2i_bboxes;
475
+ if (!bboxes[idx]) return;
476
+
477
+ const div = bboxes[idx][0];
478
+ const boxRect = div.getBoundingClientRect();
479
+ const mouseX = e.clientX;
480
+ const mouseY = e.clientY;
481
+
482
+ const resizeLeft = mouseX >= boxRect.left && mouseX <= boxRect.left + RESIZE_BORDER;
483
+ const resizeRight = mouseX >= boxRect.right - RESIZE_BORDER && mouseX <= boxRect.right;
484
+ const resizeTop = mouseY >= boxRect.top && mouseY <= boxRect.top + RESIZE_BORDER;
485
+ const resizeBottom = mouseY >= boxRect.bottom - RESIZE_BORDER && mouseY <= boxRect.bottom;
486
+
487
+ if ((resizeLeft && resizeTop) || (resizeRight && resizeBottom)) {
488
+ div.style.cursor = 'nwse-resize';
489
+ } else if ((resizeLeft && resizeBottom) || (resizeRight && resizeTop)) {
490
+ div.style.cursor = 'nesw-resize';
491
+ } else if (resizeLeft || resizeRight) {
492
+ div.style.cursor = 'ew-resize';
493
+ } else if (resizeTop || resizeBottom) {
494
+ div.style.cursor = 'ns-resize';
495
+ } else {
496
+ div.style.cursor = 'move';
497
+ }
498
+ }
499
+
500
+ // ↓↓↓ auto called event listeners ↓↓↓
501
+
502
+ function updateBoxes(is_t2i) {
503
+ // This function redraw all bounding boxes
504
+ let bboxes = null;
505
+ let canvas = null;
506
+ if (is_t2i) {
507
+ bboxes = t2i_bboxes;
508
+ canvas = gradioApp().querySelector('#MD-bbox-rect-t2i img');
509
+ } else {
510
+ bboxes = i2i_bboxes;
511
+ canvas = gradioApp().querySelector('#MD-bbox-ref-i2i img');
512
+ }
513
+ if (!canvas) return;
514
+
515
+ for (let idx = 0; idx < bboxes.length; idx++) {
516
+ if (!bboxes[idx]) continue;
517
+ const [div, bbox, shower] = bboxes[idx];
518
+ if (div.style.display === 'none') { return; }
519
+
520
+ displayBox(canvas, is_t2i, bboxes[idx]);
521
+ }
522
+ }
523
+
524
+ window.addEventListener('resize', _ => {
525
+ updateBoxes(true);
526
+ updateBoxes(false);
527
+ });
528
+
529
+ // ======== Gradio Bug Fix ========
530
+ // For Gradio versions > 3.16.0 and < 3.29.0, the accordion DOM will be deleted when it is closed.
531
+ // We need to judge the versions and listen to the accordion open event, rerender the bbox at that time.
532
+ // This silly bug fix is only for compatibility, we recommend to update the gradio version to 3.29.0 or higher.
533
+ try {
534
+ const GRADIO_VERSIONS = window.gradio_config["version"].split(".");
535
+ const gradio_major_version = parseInt(GRADIO_VERSIONS[0]);
536
+ const gradio_minor_version = parseInt(GRADIO_VERSIONS[1]);
537
+ if (gradio_major_version == 3 && gradio_minor_version > 16 && gradio_minor_version < 29) {
538
+ let listener = e => {
539
+ if (!e) { return; }
540
+ if (!e.target) { return; }
541
+ if (!e.target.classList) { return; }
542
+ if (!e.target.classList.contains('label-wrap')) { return; }
543
+ for (let tab of ['t2i', 'i2i']) {
544
+ const div = gradioApp().querySelector('#MD-bbox-control-' + tab +' div.label-wrap');
545
+ if (!div) { continue; }
546
+ updateBoxes(tab === 't2i');
547
+ }
548
+ };
549
+ window.addEventListener('DOMNodeInserted', listener);
550
+ }
551
+ } catch (ignored) {
552
+ // If the above code failed, the gradio version shouldn't be in the range of 3.16.0 to 3.29.0, so we just return.
553
+ }
554
+ // ======== Gradio Bug Fix ========
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ dashscope
2
+ modelscope[cv] -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html
3
+ tensorflow-gpu==2.11.0
src/__init__.py ADDED
File without changes
src/generation.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import time
4
+
5
+ import gradio as gr
6
+ import requests
7
+
8
+ from src.log import logger
9
+ from src.util import download_images
10
+
11
+
12
+ def call_generation(prompt, mask_image_url,lora_path_ratio="0 1.0", image_width=512, image_height=512, BATCH_SIZE=1):
13
+ API_KEY = os.getenv("API_KEY_GENERATION")
14
+ headers = {
15
+ "Content-Type": "application/json",
16
+ "Accept": "application/json",
17
+ "Authorization": f"Bearer {API_KEY}",
18
+ "X-DashScope-Async": "enable",
19
+ }
20
+ data = {
21
+ "model": "jinshu-emoji",
22
+ "input": {
23
+ "prompt": prompt,
24
+ "mask_image_url": mask_image_url,
25
+ "lora_path_ratio": lora_path_ratio,
26
+ "base_model_path": 0,
27
+
28
+ },
29
+ "parameters": {
30
+ "n": BATCH_SIZE,
31
+ "image_width": image_width,
32
+ "image_height": image_height,
33
+ "text_position_revise": True,
34
+ }
35
+ }
36
+ url_create_task = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/anytext/generation'
37
+
38
+ all_res_ = []
39
+ REPEAT = 1
40
+ for _ in range(REPEAT):
41
+ res_ = requests.post(url_create_task, data=json.dumps(data), headers=headers)
42
+ all_res_.append(res_)
43
+
44
+ all_image_data = []
45
+ for res_ in all_res_:
46
+ respose_code = res_.status_code
47
+ if 200 == respose_code:
48
+ res = json.loads(res_.content.decode())
49
+ request_id = res['request_id']
50
+ task_id = res['output']['task_id']
51
+ logger.info(f"task_id: {task_id}: Create Poster Imitation request success. Params: {data}")
52
+
53
+ # 异步查询
54
+ is_running = True
55
+ while is_running:
56
+ url_query = f'https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}'
57
+ res_ = requests.post(url_query, headers=headers)
58
+ respose_code = res_.status_code
59
+ if 200 == respose_code:
60
+ res = json.loads(res_.content.decode())
61
+ if "SUCCEEDED" == res['output']['task_status']:
62
+ logger.info(f"task_id: {task_id}: Generation task query success.")
63
+ results = res['output']
64
+ img_urls = results['result_url']
65
+ logger.info(f"task_id: {task_id}: {res}")
66
+ break
67
+ elif "FAILED" != res['output']['task_status']:
68
+ logger.debug(f"task_id: {task_id}: query result...")
69
+ time.sleep(1)
70
+ else:
71
+ raise gr.Error('Fail to get results from Generation task.')
72
+
73
+ else:
74
+ logger.error(f'task_id: {task_id}: Fail to query task result: {res_.content}')
75
+ raise gr.Error("Fail to query task result.")
76
+
77
+ logger.info(f"task_id: {task_id}: download generated images.")
78
+ img_data = download_images(img_urls, BATCH_SIZE)
79
+ logger.info(f"task_id: {task_id}: Generate done.")
80
+ all_image_data += img_data
81
+ else:
82
+ logger.error(f'Fail to create Generation task: {res_.content}')
83
+ raise gr.Error("Fail to create Generation task.")
84
+
85
+ if len(all_image_data) != REPEAT * BATCH_SIZE:
86
+ raise gr.Error("Fail to Generation.")
87
+ return all_image_data
88
+
89
+
90
+ if __name__ == "__main__":
91
+ call_generation()
src/log.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ from logging.handlers import RotatingFileHandler
4
+
5
+ log_file_name = "workdir/log_mememaster.log"
6
+ os.makedirs(os.path.dirname(log_file_name), exist_ok=True)
7
+
8
+ format = '[%(levelname)s] %(asctime)s "%(filename)s", line %(lineno)d, %(message)s'
9
+ logging.basicConfig(
10
+ format=format,
11
+ datefmt="%Y-%m-%d %H:%M:%S",
12
+ level=logging.INFO)
13
+ logger = logging.getLogger(name="WordArt_Studio")
14
+
15
+ fh = RotatingFileHandler(log_file_name, maxBytes=20000000, backupCount=3)
16
+ formatter = logging.Formatter(format, datefmt="%Y-%m-%d %H:%M:%S")
17
+ fh.setFormatter(formatter)
18
+ logger.addHandler(fh)
src/util.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import concurrent.futures
2
+ import io
3
+ import os
4
+
5
+ import numpy as np
6
+ import oss2
7
+ import requests
8
+ from PIL import Image, ImageDraw, ImageFont
9
+
10
+ from .log import logger
11
+
12
+ # oss
13
+ access_key_id = os.getenv("ACCESS_KEY_ID")
14
+ access_key_secret = os.getenv("ACCESS_KEY_SECRET")
15
+ bucket_name = os.getenv("BUCKET_NAME")
16
+ endpoint = os.getenv("ENDPOINT")
17
+
18
+ oss_path = "wangmeng.xwm/MemeMaster"
19
+ oss_path_img_gallery = "wangmeng.xwm/MemeMaster_img_gallery"
20
+
21
+ bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)
22
+
23
+ def download_img_pil(index, img_url):
24
+ # print(img_url)
25
+ r = requests.get(img_url, stream=True)
26
+ if r.status_code == 200:
27
+ img = Image.open(io.BytesIO(r.content))
28
+ return (index, img)
29
+ else:
30
+ logger.error(f"Fail to download: {img_url}")
31
+
32
+
33
+ def download_images(img_urls, batch_size):
34
+ imgs_pil = [None] * batch_size
35
+ # worker_results = []
36
+ with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
37
+ to_do = []
38
+ for i, url in enumerate(img_urls):
39
+ future = executor.submit(download_img_pil, i, url)
40
+ to_do.append(future)
41
+
42
+ for future in concurrent.futures.as_completed(to_do):
43
+ ret = future.result()
44
+ # worker_results.append(ret)
45
+ index, img_pil = ret
46
+ imgs_pil[index] = img_pil # 按顺序排列url,后续下载关联的图片或者svg需要使用
47
+
48
+ return imgs_pil
49
+
50
+
51
+ def upload_np_2_oss(input_image, name="cache.png", gallery=False):
52
+ imgByteArr = io.BytesIO()
53
+ Image.fromarray(input_image).save(imgByteArr, format="PNG")
54
+ imgByteArr = imgByteArr.getvalue()
55
+
56
+ if gallery:
57
+ path = oss_path_img_gallery
58
+ else:
59
+ path = oss_path
60
+
61
+ bucket.put_object(path + "/" + name, imgByteArr) # data为数据,可以是图片
62
+ ret = bucket.sign_url('GET', path + "/" + name, 60 * 60 * 24) # 返回值为链接,参数依次为,方法/oss上文件路径/过期时间(s)
63
+ del imgByteArr
64
+ return ret