tchung1970 Claude Opus 4.5 commited on
Commit
ea70609
·
1 Parent(s): d146910

Update UI to match Qwen-Image styling

Browse files

- Add gr.themes.Soft() theme with Apple-style design
- Two-column horizontal layout with dark mode support
- Custom CSS for panel styling, borders, and shadows
- JavaScript for enforcing horizontal layout
- Blue accent colors (#0071e3) and Inter font

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +625 -85
app.py CHANGED
@@ -73,9 +73,515 @@ ovis_encoder = OvisEmbedder(
73
  ).to(device=device, dtype=_dtype)
74
 
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  @spaces.GPU(duration=75)
77
- def generate(prompt, img_height=1024, img_width=1024, seed=42, steps=50, guidance_scale=5.0):
78
- print(f'inference with prompt : {prompt}, size: {img_height}x{img_width}, seed : {seed}, step : {steps}, cfg : {guidance_scale}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  image = generate_image(
80
  device=next(ovis_image.parameters()).device,
81
  dtype=_dtype,
@@ -84,9 +590,9 @@ def generate(prompt, img_height=1024, img_width=1024, seed=42, steps=50, guidanc
84
  autoencoder=autoencoder,
85
  ovis_tokenizer=ovis_tokenizer,
86
  ovis_encoder=ovis_encoder,
87
- img_height=img_height,
88
- img_width=img_width,
89
- denoising_steps=steps,
90
  cfg_scale=guidance_scale,
91
  seed=seed,
92
  )
@@ -94,101 +600,135 @@ def generate(prompt, img_height=1024, img_width=1024, seed=42, steps=50, guidanc
94
  image = image.clamp(-1, 1)
95
  image = image.cpu().permute(0, 2, 3, 1).float().numpy()
96
  image = (image * 255).round().astype("uint8")
97
-
98
- return image[0]
99
 
100
- examples = [
101
- "Solar punk vehicle in a bustling city",
102
- "An anthropomorphic cat riding a Harley Davidson in Arizona with sunglasses and a leather jacket",
103
- "An elderly woman poses for a high fashion photoshoot in colorful, patterned clothes with a cyberpunk 2077 vibe",
104
- ]
105
 
106
- css="""
107
- #col-container {
108
- margin: 0 auto;
109
- max-width: 520px;
110
- }
111
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
- with gr.Blocks(css=css) as demo:
114
-
115
- with gr.Column(elem_id="col-container"):
116
- gr.Markdown(f"""# Ovis-Image
117
- [[code](https://github.com/AIDC-AI/Ovis-Image)] [[model](https://huggingface.co/AIDC-AI/Ovis-Image-7B)]
118
- """)
119
-
120
- with gr.Row():
121
-
122
- prompt = gr.Text(
123
  label="Prompt",
124
- show_label=False,
125
- max_lines=1,
126
- placeholder="Enter your prompt here",
127
- container=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  )
129
-
130
- run_button = gr.Button("Run", scale=0)
131
-
132
- result = gr.Image(label="Result", show_label=False)
133
-
134
- with gr.Accordion("Advanced Settings", open=False):
135
- with gr.Row():
136
-
137
- img_height = gr.Slider(
138
- label="Image Height",
139
- minimum=256,
140
- maximum=2048,
141
- step=32,
142
- value=1024,
143
- )
144
-
145
- img_width = gr.Slider(
146
- label="Image Width",
147
- minimum=256,
148
- maximum=2048,
149
- step=32,
150
- value=1024,
151
- )
152
-
153
- with gr.Row():
154
-
155
- guidance_scale = gr.Slider(
156
- label="Guidance Scale",
157
- minimum=1,
158
- maximum=14,
159
- step=0.1,
160
- value=5.0,
161
- )
162
-
163
- num_inference_steps = gr.Slider(
164
- label="Number of inference steps",
165
- minimum=1,
166
- maximum=100,
167
- step=1,
168
- value=50,
169
- )
170
 
 
 
 
 
 
 
 
 
171
  seed = gr.Slider(
172
  label="Seed",
173
  minimum=0,
174
  maximum=MAX_SEED,
175
  step=1,
176
- value=42,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  )
178
-
179
- gr.Examples(
180
- examples = examples,
181
- fn = generate,
182
- inputs = [prompt],
183
- outputs = [result],
184
- cache_examples="lazy"
185
- )
186
 
 
187
  gr.on(
188
  triggers=[run_button.click, prompt.submit],
189
- fn = generate,
190
- inputs = [prompt, img_height, img_width, seed, num_inference_steps, guidance_scale],
191
- outputs = [result]
 
 
 
 
 
 
 
192
  )
193
 
194
  if __name__ == '__main__':
 
73
  ).to(device=device, dtype=_dtype)
74
 
75
 
76
+ examples = [
77
+ "Five shimmering goldfish weave through crevices between stones; four are red-and-white, while one is silver-white. By the pond's edge, a golden shaded British Shorthair cat watches them intently, counting on blind luck. Watercolor style.",
78
+ "Solar punk vehicle in a bustling city",
79
+ "An anthropomorphic cat riding a Harley Davidson in Arizona with sunglasses and a leather jacket",
80
+ "An elderly woman poses for a high fashion photoshoot in colorful, patterned clothes with a cyberpunk 2077 vibe",
81
+ ]
82
+
83
+ def get_image_size(aspect_ratio):
84
+ """Converts aspect ratio string to width, height tuple."""
85
+ if "(" in aspect_ratio and "x" in aspect_ratio:
86
+ try:
87
+ res_part = aspect_ratio.split("(")[1].split(")")[0]
88
+ width, height = res_part.split("x")
89
+ return int(width), int(height)
90
+ except:
91
+ pass
92
+ return 1024, 1024
93
+
94
+ apple_css = """
95
+ /* Global Styles */
96
+ .gradio-container {
97
+ max-width: 85vw !important;
98
+ margin: 0 auto !important;
99
+ padding: 48px 20px !important;
100
+ font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', 'Roboto', sans-serif !important;
101
+ }
102
+
103
+ /* Disable all transitions globally to prevent layout shifts */
104
+ * {
105
+ transition: none !important;
106
+ animation: none !important;
107
+ }
108
+
109
+ /* Header */
110
+ .header-container {
111
+ text-align: left;
112
+ margin-bottom: 24px;
113
+ }
114
+
115
+ .main-title {
116
+ font-size: 32px !important;
117
+ font-weight: 600 !important;
118
+ letter-spacing: -0.02em !important;
119
+ line-height: 1.07 !important;
120
+ color: #1d1d1f !important;
121
+ margin: 0 0 16px 0 !important;
122
+ }
123
+
124
+ .subtitle {
125
+ font-size: 21px !important;
126
+ font-weight: 400 !important;
127
+ line-height: 1.38 !important;
128
+ color: #6e6e73 !important;
129
+ margin: 0 0 24px 0 !important;
130
+ }
131
+
132
+ .attribution-link {
133
+ display: inline-block;
134
+ font-size: 14px !important;
135
+ color: #0071e3 !important;
136
+ text-decoration: none !important;
137
+ font-weight: 400 !important;
138
+ transition: color 0.2s ease !important;
139
+ }
140
+
141
+ .attribution-link:hover {
142
+ color: #0077ed !important;
143
+ text-decoration: underline !important;
144
+ }
145
+
146
+ /* Input Section */
147
+ .input-section {
148
+ background: #ffffff;
149
+ border-radius: 18px;
150
+ padding: 32px;
151
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
152
+ }
153
+
154
+ /* Textbox */
155
+ textarea {
156
+ font-size: 17px !important;
157
+ line-height: 1.47 !important;
158
+ border-radius: 12px !important;
159
+ border: 1px solid #d2d2d7 !important;
160
+ padding: 12px 16px !important;
161
+ background: #ffffff !important;
162
+ font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif !important;
163
+ min-height: 200px !important;
164
+ max-height: 400px !important;
165
+ height: 200px !important;
166
+ resize: vertical !important;
167
+ overflow-y: auto !important;
168
+ margin-bottom: 16px !important;
169
+ }
170
+
171
+ textarea:focus {
172
+ border-color: #0071e3 !important;
173
+ box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.15) !important;
174
+ outline: none !important;
175
+ }
176
+
177
+ textarea::placeholder {
178
+ color: #86868b !important;
179
+ }
180
+
181
+ /* Button */
182
+ button.primary {
183
+ font-size: 17px !important;
184
+ font-weight: 400 !important;
185
+ padding: 12px 32px !important;
186
+ border-radius: 980px !important;
187
+ background: #0071e3 !important;
188
+ border: none !important;
189
+ color: #ffffff !important;
190
+ min-height: 44px !important;
191
+ letter-spacing: -0.01em !important;
192
+ cursor: pointer !important;
193
+ }
194
+
195
+ button.primary:hover {
196
+ background: #0077ed !important;
197
+ }
198
+
199
+ button.primary:active {
200
+ opacity: 0.9 !important;
201
+ }
202
+
203
+ /* Output Section */
204
+ div.output-section {
205
+ background: #ffffff;
206
+ border-radius: 18px;
207
+ padding: 32px;
208
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
209
+ overflow: hidden;
210
+ display: flex;
211
+ align-items: center;
212
+ justify-content: center;
213
+ min-height: 80vh;
214
+ max-height: 90vh;
215
+ will-change: auto;
216
+ position: relative;
217
+ }
218
+
219
+ .output-section * {
220
+ transform: none !important;
221
+ transition: none !important;
222
+ animation: none !important;
223
+ }
224
+
225
+ .output-section img {
226
+ border-radius: 12px !important;
227
+ max-width: 100% !important;
228
+ max-height: 85vh !important;
229
+ width: auto !important;
230
+ height: auto !important;
231
+ object-fit: contain !important;
232
+ transform: none !important;
233
+ transition: none !important;
234
+ animation: none !important;
235
+ backface-visibility: hidden;
236
+ -webkit-backface-visibility: hidden;
237
+ }
238
+
239
+ /* Make progress/generation area fill more space */
240
+ .output-section > div {
241
+ width: 100% !important;
242
+ min-height: 75vh !important;
243
+ max-height: 85vh !important;
244
+ display: flex !important;
245
+ align-items: center !important;
246
+ justify-content: center !important;
247
+ }
248
+
249
+ .output-section > div > div {
250
+ min-height: 75vh !important;
251
+ max-height: 85vh !important;
252
+ width: 100% !important;
253
+ display: flex !important;
254
+ align-items: center !important;
255
+ justify-content: center !important;
256
+ }
257
+
258
+ .output-section * {
259
+ max-width: 100% !important;
260
+ }
261
+
262
+ /* Footer */
263
+ .footer-text {
264
+ text-align: center;
265
+ margin-top: 48px;
266
+ font-size: 14px !important;
267
+ color: #86868b !important;
268
+ line-height: 1.43 !important;
269
+ }
270
+
271
+ /* Progress */
272
+ .progress-bar {
273
+ background: #0071e3 !important;
274
+ border-radius: 4px !important;
275
+ }
276
+
277
+ /* Dark Mode */
278
+ .dark .main-title {
279
+ color: #ffffff !important;
280
+ }
281
+
282
+ .dark .subtitle {
283
+ color: #a1a1a6 !important;
284
+ }
285
+
286
+ .input-section .main-title {
287
+ color: #ffffff !important;
288
+ }
289
+
290
+ .dark .input-section .main-title {
291
+ color: #f5f5f7 !important;
292
+ }
293
+
294
+ .dark .input-section,
295
+ .dark .output-section {
296
+ background: #1d1d1f;
297
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
298
+ }
299
+
300
+ .dark textarea {
301
+ background: #1d1d1f !important;
302
+ border-color: #424245 !important;
303
+ color: #f5f5f7 !important;
304
+ }
305
+
306
+ .dark textarea::placeholder {
307
+ color: #86868b !important;
308
+ }
309
+
310
+ /* Inline labels */
311
+ label.inline-label {
312
+ display: flex !important;
313
+ align-items: center !important;
314
+ min-width: 120px !important;
315
+ margin: 0 !important;
316
+ padding: 0 12px 0 0 !important;
317
+ font-weight: 400 !important;
318
+ font-size: 14px !important;
319
+ color: #1d1d1f !important;
320
+ }
321
+
322
+ /* Fix column width to prevent shrinking - target Gradio's generated structure */
323
+ .input-section {
324
+ min-width: 550px !important;
325
+ max-width: 550px !important;
326
+ width: 550px !important;
327
+ flex-shrink: 0 !important;
328
+ flex-grow: 0 !important;
329
+ }
330
+
331
+ /* Lock the output section to fill remaining space */
332
+ .output-section {
333
+ flex-grow: 1 !important;
334
+ flex-shrink: 0 !important;
335
+ flex-basis: auto !important;
336
+ }
337
+
338
+ /* Prevent Gradio columns from flexing */
339
+ .gradio-column {
340
+ flex-shrink: 0 !important;
341
+ }
342
+
343
+ /* Stabilize row layout - force horizontal layout with maximum specificity */
344
+ .gradio-row,
345
+ div.gradio-row,
346
+ .gradio-container .gradio-row,
347
+ .gradio-container > .gradio-row,
348
+ .gradio-container div.gradio-row {
349
+ align-items: flex-start !important;
350
+ flex-direction: row !important;
351
+ display: flex !important;
352
+ flex-wrap: nowrap !important;
353
+ width: 100% !important;
354
+ }
355
+
356
+ /* Force columns to stay inline */
357
+ .gradio-row > .gradio-column,
358
+ .gradio-row > div {
359
+ display: inline-flex !important;
360
+ vertical-align: top !important;
361
+ }
362
+
363
+ /* First column - input section */
364
+ .gradio-row > .gradio-column:first-child,
365
+ .gradio-row > div:first-child {
366
+ width: 550px !important;
367
+ min-width: 550px !important;
368
+ max-width: 550px !important;
369
+ flex: 0 0 550px !important;
370
+ }
371
+
372
+ /* Second column - output section */
373
+ .gradio-row > .gradio-column:last-child,
374
+ .gradio-row > div:last-child {
375
+ flex: 1 1 auto !important;
376
+ min-width: 0 !important;
377
+ }
378
+
379
+ /* Lock textbox container size */
380
+ .input-section .gr-textbox,
381
+ .input-section label[for] {
382
+ width: 100% !important;
383
+ }
384
+
385
+ /* Prevent form from expanding */
386
+ .input-section form {
387
+ width: 100% !important;
388
+ max-width: 100% !important;
389
+ }
390
+
391
+ /* Ensure seed input always visible */
392
+ .input-section input[type="number"] {
393
+ display: block !important;
394
+ visibility: visible !important;
395
+ }
396
+
397
+ /* Hide progress indicator in input section - target specific progress elements */
398
+ .input-section .progress-container,
399
+ .input-section [class*="progress-bar"],
400
+ .input-section [class*="progress-text"],
401
+ .input-section [class*="progress-level"],
402
+ .input-section .progress,
403
+ .input-section .eta-bar {
404
+ display: none !important;
405
+ visibility: hidden !important;
406
+ height: 0 !important;
407
+ overflow: hidden !important;
408
+ }
409
+
410
+ /* Override ALL responsive behavior - force horizontal layout at ALL viewport sizes */
411
+ @media (max-width: 2000px) {
412
+ .gradio-row,
413
+ div.gradio-row,
414
+ .gradio-container .gradio-row,
415
+ .gradio-container > .gradio-row {
416
+ flex-direction: row !important;
417
+ flex-wrap: nowrap !important;
418
+ display: flex !important;
419
+ }
420
+
421
+ .gradio-row > .gradio-column,
422
+ .gradio-row > div {
423
+ display: inline-flex !important;
424
+ }
425
+
426
+ .gradio-row > .gradio-column:first-child,
427
+ .gradio-row > div:first-child {
428
+ width: 550px !important;
429
+ min-width: 550px !important;
430
+ max-width: 550px !important;
431
+ flex: 0 0 550px !important;
432
+ }
433
+
434
+ .gradio-row > .gradio-column:last-child,
435
+ .gradio-row > div:last-child {
436
+ flex: 1 1 auto !important;
437
+ min-width: 0 !important;
438
+ }
439
+ }
440
+
441
+ /* Responsive text sizing only */
442
+ @media (max-width: 734px) {
443
+ .main-title {
444
+ font-size: 40px !important;
445
+ }
446
+
447
+ .subtitle {
448
+ font-size: 19px !important;
449
+ }
450
+
451
+ .gradio-container {
452
+ padding: 32px 16px !important;
453
+ }
454
+
455
+ .input-section,
456
+ .output-section {
457
+ padding: 24px !important;
458
+ }
459
+
460
+ /* FORCE horizontal layout even on mobile */
461
+ .gradio-row,
462
+ div.gradio-row {
463
+ flex-direction: row !important;
464
+ flex-wrap: nowrap !important;
465
+ }
466
+ }
467
+
468
+ /* Remove default Gradio styling */
469
+ .contain {
470
+ padding: 0 !important;
471
+ }
472
+
473
+ /* Hide Gradio footer */
474
+ footer {
475
+ display: none !important;
476
+ }
477
+
478
+ .footer {
479
+ display: none !important;
480
+ }
481
+
482
+ /* Target main app container */
483
+ #root, #app {
484
+ width: 100% !important;
485
+ max-width: none !important;
486
+ }
487
+ """
488
+
489
+ # JavaScript to force horizontal layout
490
+ js_code = """
491
+ function() {
492
+ function forceHorizontalLayout() {
493
+ // Set container width
494
+ const container = document.querySelector('.gradio-container');
495
+ if (container) {
496
+ container.style.maxWidth = '85vw';
497
+ container.style.width = '85vw';
498
+ }
499
+
500
+ // Target the main row specifically
501
+ const mainRow = document.getElementById('main-row');
502
+ if (mainRow) {
503
+ mainRow.style.flexDirection = 'row';
504
+ mainRow.style.flexWrap = 'nowrap';
505
+ mainRow.style.display = 'flex';
506
+ mainRow.style.width = '100%';
507
+ }
508
+
509
+ // Force ALL rows to stay horizontal
510
+ const rows = document.querySelectorAll('.gradio-row');
511
+ rows.forEach(row => {
512
+ row.style.flexDirection = 'row';
513
+ row.style.flexWrap = 'nowrap';
514
+ row.style.display = 'flex';
515
+ });
516
+
517
+ // Target specific columns
518
+ const inputCol = document.getElementById('input-column');
519
+ if (inputCol) {
520
+ inputCol.style.width = '550px';
521
+ inputCol.style.minWidth = '550px';
522
+ inputCol.style.maxWidth = '550px';
523
+ inputCol.style.flex = '0 0 550px';
524
+ inputCol.style.display = 'inline-flex';
525
+ inputCol.style.flexDirection = 'column';
526
+ }
527
+
528
+ const outputCol = document.getElementById('output-column');
529
+ if (outputCol) {
530
+ outputCol.style.flex = '1 1 auto';
531
+ outputCol.style.minWidth = '0';
532
+ outputCol.style.display = 'inline-flex';
533
+ outputCol.style.flexDirection = 'column';
534
+ }
535
+
536
+ // Fallback: force all column children of rows
537
+ const columns = document.querySelectorAll('.gradio-row > .gradio-column, .gradio-row > div');
538
+ columns.forEach((col, index) => {
539
+ if (index === 0) {
540
+ col.style.width = '550px';
541
+ col.style.minWidth = '550px';
542
+ col.style.maxWidth = '550px';
543
+ col.style.flex = '0 0 550px';
544
+ } else if (index === 1) {
545
+ col.style.flex = '1 1 auto';
546
+ col.style.minWidth = '0';
547
+ }
548
+ col.style.display = 'inline-flex';
549
+ });
550
+ }
551
+
552
+ // Run immediately
553
+ forceHorizontalLayout();
554
+
555
+ // Run again after delays to override Gradio's dynamic changes
556
+ setTimeout(forceHorizontalLayout, 100);
557
+ setTimeout(forceHorizontalLayout, 500);
558
+ setTimeout(forceHorizontalLayout, 1000);
559
+ setTimeout(forceHorizontalLayout, 2000);
560
+
561
+ // Set up mutation observer to reapply on DOM changes
562
+ const observer = new MutationObserver(forceHorizontalLayout);
563
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
564
+ }
565
+ """
566
+
567
  @spaces.GPU(duration=75)
568
+ def infer(
569
+ prompt,
570
+ seed=42,
571
+ randomize_seed=False,
572
+ aspect_ratio="1:1 (1024x1024)",
573
+ guidance_scale=5.0,
574
+ num_inference_steps=50,
575
+ progress=gr.Progress(track_tqdm=True),
576
+ ):
577
+ """Generates an image using the Ovis-Image pipeline."""
578
+ if randomize_seed:
579
+ seed = random.randint(0, MAX_SEED)
580
+
581
+ width, height = get_image_size(aspect_ratio)
582
+
583
+ print(f'inference with prompt: {prompt}, size: {height}x{width}, seed: {seed}, steps: {num_inference_steps}, cfg: {guidance_scale}')
584
+
585
  image = generate_image(
586
  device=next(ovis_image.parameters()).device,
587
  dtype=_dtype,
 
590
  autoencoder=autoencoder,
591
  ovis_tokenizer=ovis_tokenizer,
592
  ovis_encoder=ovis_encoder,
593
+ img_height=height,
594
+ img_width=width,
595
+ denoising_steps=num_inference_steps,
596
  cfg_scale=guidance_scale,
597
  seed=seed,
598
  )
 
600
  image = image.clamp(-1, 1)
601
  image = image.cpu().permute(0, 2, 3, 1).float().numpy()
602
  image = (image * 255).round().astype("uint8")
 
 
603
 
604
+ return image[0], seed
 
 
 
 
605
 
606
+ with gr.Blocks(
607
+ title="Ovis-Image",
608
+ fill_height=False,
609
+ theme=gr.themes.Soft(
610
+ primary_hue=gr.themes.colors.blue,
611
+ secondary_hue=gr.themes.colors.slate,
612
+ neutral_hue=gr.themes.colors.gray,
613
+ spacing_size=gr.themes.sizes.spacing_lg,
614
+ radius_size=gr.themes.sizes.radius_lg,
615
+ text_size=gr.themes.sizes.text_md,
616
+ font=[gr.themes.GoogleFont("Inter"), "SF Pro Display", "-apple-system", "BlinkMacSystemFont", "system-ui", "sans-serif"],
617
+ font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "SF Mono", "ui-monospace", "monospace"],
618
+ ).set(
619
+ body_background_fill='#f5f5f7',
620
+ body_background_fill_dark='#000000',
621
+ button_primary_background_fill='#0071e3',
622
+ button_primary_background_fill_hover='#0077ed',
623
+ button_primary_text_color='#ffffff',
624
+ block_background_fill='#ffffff',
625
+ block_background_fill_dark='#1d1d1f',
626
+ block_border_width='0px',
627
+ block_shadow='0 2px 12px rgba(0, 0, 0, 0.08)',
628
+ block_shadow_dark='0 2px 12px rgba(0, 0, 0, 0.4)',
629
+ input_background_fill='#ffffff',
630
+ input_background_fill_dark='#1d1d1f',
631
+ input_border_width='1px',
632
+ input_border_color='#d2d2d7',
633
+ input_border_color_dark='#424245',
634
+ input_shadow='none',
635
+ input_shadow_focus='0 0 0 4px rgba(0, 113, 227, 0.15)',
636
+ ),
637
+ css=apple_css,
638
+ js=js_code,
639
+ ) as demo:
640
+ # Two-column layout - variant='panel' prevents responsive stacking
641
+ with gr.Row(equal_height=False, variant="panel", elem_id="main-row"):
642
+ # Left column - Input controls (fixed width)
643
+ with gr.Column(scale=0, min_width=550, elem_classes="input-section", elem_id="input-column"):
644
+ # Title above prompt box
645
+ gr.HTML("""
646
+ <div class="header-container">
647
+ <h1 class="main-title">Ovis-Image</h1>
648
+ </div>
649
+ """)
650
 
651
+ prompt = gr.Textbox(
652
+ placeholder="Describe the image you want to create...",
653
+ value=examples[0],
654
+ lines=7,
655
+ max_lines=7,
 
 
 
 
 
656
  label="Prompt",
657
+ show_label=True,
658
+ container=True,
659
+ autoscroll=False,
660
+ )
661
+
662
+ aspect_ratio = gr.Dropdown(
663
+ choices=[
664
+ "1:1 (1024x1024)",
665
+ "4:3 (1024x768)",
666
+ "3:4 (768x1024)",
667
+ "16:9 (1024x576)",
668
+ "9:16 (576x1024)",
669
+ ],
670
+ value="1:1 (1024x1024)",
671
+ label="Aspect Ratio",
672
+ show_label=True,
673
+ container=True,
674
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
675
 
676
+ run_button = gr.Button(
677
+ "Generate",
678
+ variant="primary",
679
+ size="lg",
680
+ elem_classes="primary"
681
+ )
682
+
683
+ # Hidden advanced settings (still functional but not visible)
684
  seed = gr.Slider(
685
  label="Seed",
686
  minimum=0,
687
  maximum=MAX_SEED,
688
  step=1,
689
+ value=0,
690
+ visible=False
691
+ )
692
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True, visible=False)
693
+ guidance_scale = gr.Slider(
694
+ label="Guidance scale",
695
+ minimum=0.0,
696
+ maximum=14.0,
697
+ step=0.1,
698
+ value=5.0,
699
+ visible=False
700
+ )
701
+ num_inference_steps = gr.Slider(
702
+ label="Number of inference steps",
703
+ minimum=1,
704
+ maximum=100,
705
+ step=1,
706
+ value=50,
707
+ visible=False
708
+ )
709
+
710
+ # Right column - Image output
711
+ with gr.Column(scale=2, elem_classes="output-section", elem_id="output-column"):
712
+ result = gr.Image(
713
+ label="Result",
714
+ show_label=False,
715
+ type="numpy",
716
+ format="png",
717
  )
 
 
 
 
 
 
 
 
718
 
719
+ # Event handlers - using gr.on() like original Qwen-Image
720
  gr.on(
721
  triggers=[run_button.click, prompt.submit],
722
+ fn=infer,
723
+ inputs=[
724
+ prompt,
725
+ seed,
726
+ randomize_seed,
727
+ aspect_ratio,
728
+ guidance_scale,
729
+ num_inference_steps,
730
+ ],
731
+ outputs=[result, seed],
732
  )
733
 
734
  if __name__ == '__main__':