cocoat commited on
Commit
0ab55d1
·
verified ·
1 Parent(s): cb18e81

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -97
app.py CHANGED
@@ -46,24 +46,36 @@ def make_html_table(caption):
46
  if ": " in row:
47
  key, val = row.split(": ", 1)
48
  html += (
49
- f'<tr><th style="text-align:left;border:1px solid #ddd;padding:4px;">{key}</th>'
50
- f'<td style="border:1px solid #ddd;padding:4px;">{val}</td></tr>'
 
 
51
  )
52
  html += '</table>'
53
  return html
54
 
55
- def infer(prompt, neg, seed, rand, w, h, cfg, steps, scheduler_type, progress=gr.Progress(track_tqdm=True)):
 
 
 
 
56
  if rand:
57
  seed = random.randint(0, MAX_SEED)
58
  generator = torch.Generator(device=device).manual_seed(seed)
59
 
60
- pipe.scheduler = euler_scheduler if scheduler_type == "Euler Ancestral" else dpm_scheduler
 
 
 
 
61
  pipe.scheduler.set_timesteps(steps)
62
 
 
63
  def _callback(pipeline, step_idx, timestep, callback_kwargs):
64
  progress(step_idx / steps, desc=f"Step {step_idx}/{steps}")
65
  return callback_kwargs
66
 
 
67
  output = pipe(
68
  prompt=prompt,
69
  negative_prompt=neg or None,
@@ -76,6 +88,7 @@ def infer(prompt, neg, seed, rand, w, h, cfg, steps, scheduler_type, progress=gr
76
  )
77
  img = output.images[0]
78
 
 
79
  caption_text = (
80
  f"Prompt: {prompt}\n"
81
  f"Negative: {neg or 'None'}\n"
@@ -88,63 +101,70 @@ def infer(prompt, neg, seed, rand, w, h, cfg, steps, scheduler_type, progress=gr
88
  history.insert(0, (img, caption_text))
89
  progress(1.0, desc="Done!")
90
 
 
91
  gallery_items = [(item[0], make_html_table(item[1])) for item in history]
92
  return img, gallery_items
93
 
 
94
  css = """
95
- /* ──────────────────────────────── */
96
- /* 全体背景とカフェ風2色配色 */
97
- body,
98
- html.dark body,
99
- html.light body {
100
  background-color: #f4e1c1 !important;
 
 
101
  }
102
- .gradio-container,
103
- html.dark .gradio-container,
104
- html.light .gradio-container {
105
  background: #fffaf1 !important;
106
- position: relative;
107
  }
108
- /* ──────────────────────────────── */
109
-
110
- /* 標準スピナーを完全に非表示 */
111
- .gradio-container .gradio-spinner {
112
- display: none !important;
 
 
113
  }
114
-
115
- /* ──────────────────────────────── */
116
- /* スピナーカバー(予備) */
117
- #spinner-cover {
118
- position: absolute;
119
- top: 0; left: 0;
120
- width: 100%; height: 100%;
 
 
 
 
 
 
 
 
 
121
  background: #fffaf1;
122
- z-index: 9998;
123
- display: none;
124
  }
125
- body.gradio-running #spinner-cover {
126
- display: block;
 
 
127
  }
128
- /* ──────────────────────────────── */
129
 
130
- /* カスタムローダー */
131
  #custom-loader {
132
- position: absolute;
133
- top: 50%; left: 50%;
134
- transform: translate(-50%, -50%);
135
- z-index: 9999;
136
  display: none;
137
  align-items: center;
138
  justify-content: center;
139
- font-family: 'Georgia', serif;
140
- font-size: 1.2em;
141
- color: #5a3e27;
142
  }
 
 
143
  body.gradio-running #custom-loader {
144
  display: flex;
145
  }
146
 
147
- /* カスタムローダー文字アニメーション */
148
  @keyframes fadeLetter {
149
  0%,100% { opacity: 1; }
150
  50% { opacity: 0.2; }
@@ -152,28 +172,15 @@ body.gradio-running #custom-loader {
152
  #custom-loader .loading-text span {
153
  display: inline-block;
154
  animation: fadeLetter 1s ease-in-out infinite;
155
- animation-delay: calc(var(--i) * 0.1s);
156
  }
157
- """
158
 
159
- script = """
160
- <script>
161
- // ページ読み込み時:スピナー要素を完全に削除
162
- window.addEventListener('load', function() {
163
- document.querySelectorAll('.gradio-spinner').forEach(el => el.remove());
164
- });
165
-
166
- // 生成開始時:カスタムローダーを表示
167
- document.addEventListener('gradio:request', () => {
168
- document.getElementById('spinner-cover').style.display = 'block';
169
- document.getElementById('custom-loader').style.display = 'flex';
170
- });
171
- // 生成完了時:カスタムローダーを非表示
172
- document.addEventListener('gradio:response', () => {
173
- document.getElementById('spinner-cover').style.display = 'none';
174
- document.getElementById('custom-loader').style.display = 'none';
175
- });
176
- </script>
177
  """
178
 
179
  with gr.Blocks(css=css) as demo:
@@ -181,63 +188,72 @@ with gr.Blocks(css=css) as demo:
181
  gr.Markdown("## SDXL Base – cocoamixXL3 Demo")
182
  gr.Markdown("[Link: Civitai](https://civitai.com/models/1553716?modelVersionId=1855218)")
183
 
 
184
  with gr.Row():
185
- prompt = gr.Textbox(lines=1, placeholder="Prompt…", value="1girl, cocoart, masterpiece, anime,")
186
- neg = gr.Textbox(lines=1, placeholder="Negative prompt", value="low quality, worst quality, bad shadow, smoke")
187
-
 
 
 
 
 
 
 
188
  with gr.Row():
189
  seed_sl = gr.Slider(0, MAX_SEED, step=1, value=0, label="Seed")
190
  rand = gr.Checkbox(True, label="Randomize seed")
191
-
192
  with gr.Row():
193
  width = gr.Slider(256, MAX_SIZE, step=32, value=512, label="Width")
194
  height = gr.Slider(256, MAX_SIZE, step=32, value=512, label="Height")
195
-
196
  with gr.Row():
197
- cfg = gr.Slider(1.0, 30.0, step=0.1, value=7.5, label="CFG Scale")
198
- steps = gr.Slider(1, 50, step=1, value=12, label="Steps")
199
-
200
  with gr.Row():
201
- scheduler_type = gr.Radio(choices=["Euler Ancestral", "DPM++ 2M SDE"], value="Euler Ancestral", label="Scheduler")
 
 
 
 
202
  run = gr.Button("Generate")
203
 
204
- # カバーとローダー要素を埋め込む
205
- gr.HTML('<div id="spinner-cover"></div>')
206
- gr.HTML(
207
  '<div id="custom-loader">'
208
  ' <div class="loading-text">'
209
- ' <span style="--i:0">i</span>'
210
- ' <span style="--i:1">n</span>'
211
- ' <span style="--i:2"> </span>'
212
- ' <span style="--i:3">p</span>'
213
- ' <span style="--i:4">r</span>'
214
- ' <span style="--i:5">o</span>'
215
- ' <span style="--i:6">g</span>'
216
- ' <span style="--i:7">r</span>'
217
- ' <span style="--i:8">e</span>'
218
- ' <span style="--i:9">s</span>'
219
- ' <span style="--i:10">s</span>'
220
  ' </div>'
 
221
  '</div>'
222
  )
223
 
224
- img_out = gr.Image()
225
- history_gallery = gr.Gallery(label="生成履歴", columns=4, height=280, show_label=False, interactive=True, type="pil")
226
-
227
- prompt.submit(
228
- fn=infer,
229
- inputs=[prompt, neg, seed_sl, rand, width, height, cfg, steps, scheduler_type],
230
- outputs=[img_out, history_gallery],
231
- show_progress="hidden"
232
- )
233
- run.click(
234
- fn=infer,
235
- inputs=[prompt, neg, seed_sl, rand, width, height, cfg, steps, scheduler_type],
236
- outputs=[img_out, history_gallery]
237
  )
238
 
239
- # JavaScript を末尾で埋め込む
240
- gr.HTML(script)
 
 
 
 
241
 
242
  demo.queue()
243
  demo.launch()
 
46
  if ": " in row:
47
  key, val = row.split(": ", 1)
48
  html += (
49
+ f'<tr>'
50
+ f'<th style="text-align:left;border:1px solid #ddd;padding:4px;">{key}</th>'
51
+ f'<td style="border:1px solid #ddd;padding:4px;">{val}</td>'
52
+ f'</tr>'
53
  )
54
  html += '</table>'
55
  return html
56
 
57
+ def infer(
58
+ prompt, neg, seed, rand, w, h, cfg, steps, scheduler_type,
59
+ progress=gr.Progress(track_tqdm=True)
60
+ ):
61
+ # シード設定
62
  if rand:
63
  seed = random.randint(0, MAX_SEED)
64
  generator = torch.Generator(device=device).manual_seed(seed)
65
 
66
+ # スケジューラ切り替え&ステップ設定
67
+ pipe.scheduler = (
68
+ euler_scheduler if scheduler_type == "Euler Ancestral"
69
+ else dpm_scheduler
70
+ )
71
  pipe.scheduler.set_timesteps(steps)
72
 
73
+ # コールバックで進捗更新
74
  def _callback(pipeline, step_idx, timestep, callback_kwargs):
75
  progress(step_idx / steps, desc=f"Step {step_idx}/{steps}")
76
  return callback_kwargs
77
 
78
+ # 推論実行
79
  output = pipe(
80
  prompt=prompt,
81
  negative_prompt=neg or None,
 
88
  )
89
  img = output.images[0]
90
 
91
+ # キャプション生成&履歴登録
92
  caption_text = (
93
  f"Prompt: {prompt}\n"
94
  f"Negative: {neg or 'None'}\n"
 
101
  history.insert(0, (img, caption_text))
102
  progress(1.0, desc="Done!")
103
 
104
+ # ギャラリー用項目
105
  gallery_items = [(item[0], make_html_table(item[1])) for item in history]
106
  return img, gallery_items
107
 
108
+ # CSS 設定(ダークモード防止+カフェ風テーマ+カスタムローダー)
109
  css = """
110
+ body {
 
 
 
 
111
  background-color: #f4e1c1 !important;
112
+ font-family: 'Georgia', serif;
113
+ color: #000 !important;
114
  }
115
+ html, .gradio-container, .dark, .dark * {
 
 
116
  background: #fffaf1 !important;
117
+ color: #000 !important;
118
  }
119
+ #col-container {
120
+ background: #fffaf1;
121
+ padding: 20px;
122
+ border-radius: 16px;
123
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
124
+ margin: auto;
125
+ max-width: 780px;
126
  }
127
+ .gr-button {
128
+ background-color: #d4a373 !important;
129
+ color: white !important;
130
+ border-radius: 8px !important;
131
+ padding: 10px 24px !important;
132
+ font-weight: bold;
133
+ transition: background-color 0.3s;
134
+ }
135
+ .gr-button:hover {
136
+ background-color: #c48f61 !important;
137
+ }
138
+ .gr-textbox, .gr-slider, .gr-radio, .gr-checkbox, .gr-image {
139
+ background: #fff;
140
+ border-radius: 8px;
141
+ }
142
+ .gr-gallery {
143
  background: #fffaf1;
144
+ padding: 10px;
145
+ border-radius: 12px;
146
  }
147
+
148
+ /* 標準スピナー非表示 */
149
+ .gradio-spinner {
150
+ display: none !important;
151
  }
 
152
 
153
+ /* カスタムローダー初期状態 */
154
  #custom-loader {
 
 
 
 
155
  display: none;
156
  align-items: center;
157
  justify-content: center;
158
+ font-weight: bold;
159
+ margin: 12px 0;
 
160
  }
161
+
162
+ /* 実行中のみ表示 */
163
  body.gradio-running #custom-loader {
164
  display: flex;
165
  }
166
 
167
+ /* 文字ごとのフェードアニメ */
168
  @keyframes fadeLetter {
169
  0%,100% { opacity: 1; }
170
  50% { opacity: 0.2; }
 
172
  #custom-loader .loading-text span {
173
  display: inline-block;
174
  animation: fadeLetter 1s ease-in-out infinite;
 
175
  }
 
176
 
177
+ /* アイコン調整 */
178
+ #custom-loader img {
179
+ width: 32px;
180
+ height: 32px;
181
+ border-radius: 50%;
182
+ margin-left: 8px;
183
+ }
 
 
 
 
 
 
 
 
 
 
 
184
  """
185
 
186
  with gr.Blocks(css=css) as demo:
 
188
  gr.Markdown("## SDXL Base – cocoamixXL3 Demo")
189
  gr.Markdown("[Link: Civitai](https://civitai.com/models/1553716?modelVersionId=1855218)")
190
 
191
+ # 入力欄
192
  with gr.Row():
193
+ prompt = gr.Textbox(
194
+ lines=1,
195
+ placeholder="Prompt…",
196
+ value="1girl, cocoart, masterpiece, anime,"
197
+ )
198
+ neg = gr.Textbox(
199
+ lines=1,
200
+ placeholder="Negative prompt",
201
+ value="low quality, worst quality, bad shadow, lowres, error, miss stroke, sketch art, smoke, ugly, extra digits, creepy, imprecise, glowing blur,"
202
+ )
203
  with gr.Row():
204
  seed_sl = gr.Slider(0, MAX_SEED, step=1, value=0, label="Seed")
205
  rand = gr.Checkbox(True, label="Randomize seed")
 
206
  with gr.Row():
207
  width = gr.Slider(256, MAX_SIZE, step=32, value=512, label="Width")
208
  height = gr.Slider(256, MAX_SIZE, step=32, value=512, label="Height")
 
209
  with gr.Row():
210
+ cfg = gr.Slider(1.0, 30.0, step=0.1, value=7.5, label="CFG Scale")
211
+ steps = gr.Slider(1, 50, step=1, value=12, label="Steps")
 
212
  with gr.Row():
213
+ scheduler_type = gr.Radio(
214
+ choices=["Euler Ancestral", "DPM++ 2M SDE"],
215
+ value="Euler Ancestral",
216
+ label="Scheduler"
217
+ )
218
  run = gr.Button("Generate")
219
 
220
+ # カスタムローダー表示エリア
221
+ loader = gr.HTML(
 
222
  '<div id="custom-loader">'
223
  ' <div class="loading-text">'
224
+ ' <span style="animation-delay:0s">i</span>'
225
+ ' <span style="animation-delay:0.1s">n</span>'
226
+ ' <span style="animation-delay:0.2s"> </span>'
227
+ ' <span style="animation-delay:0.3s">p</span>'
228
+ ' <span style="animation-delay:0.4s">r</span>'
229
+ ' <span style="animation-delay:0.5s">o</span>'
230
+ ' <span style="animation-delay:0.6s">g</span>'
231
+ ' <span style="animation-delay:0.7s">r</span>'
232
+ ' <span style="animation-delay:0.8s">e</span>'
233
+ ' <span style="animation-delay:0.9s">s</span>'
234
+ ' <span style="animation-delay:1.0s">s</span>'
235
  ' </div>'
236
+ ' <img src="icon.png" alt="loading icon" />'
237
  '</div>'
238
  )
239
 
240
+ # 出力欄
241
+ img_out = gr.Image()
242
+ history_gallery = gr.Gallery(
243
+ label="生成履歴",
244
+ columns=4,
245
+ height=280,
246
+ show_label=False,
247
+ interactive=True,
248
+ type="pil"
 
 
 
 
249
  )
250
 
251
+ # ボタンクリック時の動作定義
252
+ run.click(
253
+ fn=infer,
254
+ inputs=[prompt, neg, seed_sl, rand, width, height, cfg, steps, scheduler_type],
255
+ outputs=[img_out, history_gallery]
256
+ )
257
 
258
  demo.queue()
259
  demo.launch()