prithivMLmods commited on
Commit
450c73f
·
verified ·
1 Parent(s): ab90afa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +329 -249
app.py CHANGED
@@ -5,12 +5,9 @@ import os
5
  import tempfile
6
  from PIL import Image, ImageOps
7
  from transformers import AutoProcessor, AutoModelForImageTextToText
8
- from io import BytesIO
9
- import base64
10
 
11
  MODEL_PATH = "zai-org/GLM-OCR"
12
 
13
- # Load model and processor
14
  processor = AutoProcessor.from_pretrained(MODEL_PATH, trust_remote_code=True)
15
  model = AutoModelForImageTextToText.from_pretrained(
16
  pretrained_model_name_or_path=MODEL_PATH,
@@ -78,16 +75,12 @@ css = """
78
  --bg-card: #ff66a3;
79
  --bg-header: #ffffff;
80
  --bg-result: #ffffff;
81
- --bg-dropdown-active: #ff66a3;
82
- --bg-advanced: rgba(255, 255, 255, 0.3);
83
- --bg-uploader: rgba(255, 255, 255, 0.4);
84
  --bg-button-primary: #4ade80;
85
  --bg-button-primary-hover: #1ac2ff;
86
  --bg-button-secondary: #fde047;
87
- --bg-button-secondary-hover: #f97316;
88
  --color-border: #000000;
89
  --color-text: #000000;
90
- --color-text-button: #000000;
91
  --color-text-muted: #444444;
92
  }
93
 
@@ -96,42 +89,50 @@ css = """
96
  --bg-card: #592659;
97
  --bg-header: #1a1a1a;
98
  --bg-result: #2a2a2a;
99
- --bg-dropdown-active: #7f397f;
100
- --bg-advanced: rgba(0, 0, 0, 0.3);
101
  --bg-uploader: rgba(0, 0, 0, 0.4);
102
  --bg-button-primary: #22c55e;
103
  --bg-button-primary-hover: #0ea5e9;
104
  --bg-button-secondary: #eab308;
105
- --bg-button-secondary-hover: #ea580c;
106
  --color-border: #e0e0e0;
107
  --color-text: #f0f0f0;
108
- --color-text-button: #000000;
109
  --color-text-muted: #b0b0b0;
110
  }
111
 
112
  * {
113
  font-family: 'Montserrat', sans-serif !important;
 
114
  }
115
 
116
  body, .gradio-container {
117
  background: var(--bg-main) !important;
118
  min-height: 100vh;
119
- margin: 0;
120
- padding: 0;
121
  }
122
 
123
  .gradio-container {
124
  max-width: 100% !important;
125
  }
126
 
127
- /* Header Styles */
128
- .app-header {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  background: var(--bg-header);
130
- padding: 1.5rem 2rem;
131
  border-bottom: 3px solid var(--color-border);
132
- display: flex;
133
- justify-content: space-between;
134
- align-items: center;
135
  margin-bottom: 2rem;
136
  }
137
 
@@ -139,203 +140,297 @@ body, .gradio-container {
139
  font-size: 2.2rem;
140
  font-weight: 900;
141
  color: var(--color-text);
142
- margin: 0;
143
- letter-spacing: -1px;
144
  }
145
 
146
  .header-subtitle {
147
  font-size: 0.95rem;
148
  font-weight: 600;
149
  color: var(--color-text-muted);
150
- margin-top: 0.25rem;
151
  }
152
 
153
- /* Card Styles */
154
- .card-container {
155
- translate: -6px -6px;
 
 
 
 
 
 
156
  background: var(--bg-card);
157
  border: 3px solid var(--color-border);
158
- box-shadow: 12px 12px 0 var(--color-border);
159
  transition: all 0.2s ease;
160
- margin-bottom: 1rem;
161
  }
162
 
163
- .card-container:hover {
164
- translate: -3px -3px;
165
- box-shadow: 9px 9px 0 var(--color-border);
166
  }
167
 
168
  .card-head {
169
- font-size: 14px;
170
  font-weight: 900;
171
- width: 100%;
172
  background: var(--bg-header);
173
- padding: 10px 14px;
174
  color: var(--color-text);
175
  border-bottom: 3px solid var(--color-border);
176
  text-transform: uppercase;
177
- letter-spacing: 1px;
178
  }
179
 
180
- .card-content {
181
  padding: 1.5rem;
182
- font-size: 14px;
183
- font-weight: 600;
184
- color: var(--color-text);
185
  }
186
 
187
  /* Section Labels */
188
  .section-label {
189
  font-weight: 900;
190
- font-size: 13px;
191
  color: var(--color-text);
192
- margin-bottom: 8px;
193
  text-transform: uppercase;
194
- letter-spacing: 0.5px;
195
  }
196
 
197
- /* Upload Box */
198
- .upload-box {
199
  border: 3px dashed var(--color-border) !important;
200
  background: var(--bg-uploader) !important;
201
- min-height: 220px !important;
202
- transition: all 0.2s ease;
203
- cursor: pointer;
204
  }
205
 
206
- .upload-box:hover {
207
- background: rgba(255, 255, 255, 0.5) !important;
208
  }
209
 
210
- .dark .upload-box:hover {
211
  background: rgba(0, 0, 0, 0.5) !important;
212
  }
213
 
214
- .upload-box span, .upload-box p, .upload-box label, .upload-box svg {
215
  color: var(--color-text) !important;
216
  }
217
 
218
- /* Task Buttons */
219
- .task-radio {
220
- background: var(--bg-uploader);
221
- border: 3px solid var(--color-border);
222
- padding: 0.75rem;
223
  }
224
 
225
- .task-radio label {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  font-weight: 700 !important;
 
227
  color: var(--color-text) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  }
229
 
230
- .task-radio input[type="radio"]:checked + label {
 
231
  background: var(--bg-button-secondary) !important;
232
- color: var(--color-text-button) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  }
234
 
235
  /* Primary Button */
236
- .go-button {
237
  width: 100%;
238
- height: 55px;
239
  border: 3px solid var(--color-border) !important;
240
  background: var(--bg-button-primary) !important;
241
  box-shadow: 6px 6px 0 var(--color-border) !important;
242
- font-size: 1rem !important;
243
  font-weight: 900 !important;
244
- color: var(--color-text-button) !important;
245
  cursor: pointer;
246
  transition: all 0.15s ease;
247
  border-radius: 0 !important;
248
  text-transform: uppercase;
249
- letter-spacing: 1px;
 
250
  }
251
 
252
- .go-button:hover {
253
  background: var(--bg-button-primary-hover) !important;
254
- translate: 2px 2px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  box-shadow: 4px 4px 0 var(--color-border) !important;
 
 
 
 
256
  }
257
 
258
- .go-button:active {
259
- translate: 4px 4px;
 
 
 
 
 
 
 
 
 
260
  box-shadow: 2px 2px 0 var(--color-border) !important;
261
  }
262
 
263
- /* Output Area */
264
- .output-area {
 
 
 
 
 
 
 
 
265
  background: var(--bg-result) !important;
266
  border: 3px solid var(--color-border) !important;
267
  box-shadow: 6px 6px 0 var(--color-border) !important;
268
- font-family: 'IBM Plex Mono', monospace !important;
269
- min-height: 350px !important;
270
- padding: 1rem !important;
271
  border-radius: 0 !important;
 
272
  }
273
 
274
- .output-area textarea {
275
  font-family: 'IBM Plex Mono', monospace !important;
276
- background: transparent !important;
277
  border: none !important;
278
  box-shadow: none !important;
279
  color: var(--color-text) !important;
280
  font-weight: 500 !important;
281
  font-size: 14px !important;
282
- line-height: 1.6 !important;
 
 
283
  }
284
 
285
- /* Markdown Preview */
286
- .md-preview {
 
 
 
 
287
  background: var(--bg-result) !important;
288
  border: 3px solid var(--color-border) !important;
289
  box-shadow: 6px 6px 0 var(--color-border) !important;
290
- padding: 1.5rem !important;
291
- min-height: 350px;
292
  border-radius: 0 !important;
 
293
  }
294
 
295
- .md-preview p, .md-preview h1, .md-preview h2, .md-preview h3,
296
- .md-preview h4, .md-preview h5, .md-preview h6, .md-preview li,
297
- .md-preview span, .md-preview code, .md-preview pre, .md-preview td,
298
- .md-preview th, .md-preview table {
299
  color: var(--color-text) !important;
300
  }
301
 
302
- .md-preview code {
303
- background: var(--bg-advanced) !important;
304
- padding: 2px 6px;
305
  font-family: 'IBM Plex Mono', monospace !important;
 
306
  }
307
 
308
- /* Tabs */
309
- .tabs-container {
310
- margin-top: 0.5rem;
311
- }
312
-
313
- .tabs-container button {
314
- border: 3px solid var(--color-border) !important;
315
  background: var(--bg-uploader) !important;
316
- font-weight: 700 !important;
317
- border-radius: 0 !important;
318
- margin-right: 0 !important;
319
- padding: 10px 20px !important;
320
- color: var(--color-text) !important;
321
- box-shadow: 4px 4px 0 var(--color-border) !important;
322
- transition: all 0.15s ease;
323
- }
324
-
325
- .tabs-container button:hover {
326
- background: var(--bg-button-secondary) !important;
327
- color: var(--color-text-button) !important;
328
- }
329
-
330
- .tabs-container button.selected {
331
- background: var(--bg-button-secondary) !important;
332
- color: var(--color-text-button) !important;
333
- translate: 2px 2px;
334
- box-shadow: 2px 2px 0 var(--color-border) !important;
335
  }
336
 
337
  /* Footer */
338
- .footer-card {
339
  background: var(--bg-header);
340
  border: 3px solid var(--color-border);
341
  box-shadow: 6px 6px 0 var(--color-border);
@@ -344,108 +439,110 @@ body, .gradio-container {
344
  font-size: 0.9rem;
345
  color: var(--color-text-muted);
346
  font-weight: 600;
347
- margin-top: 1.5rem;
348
  }
349
 
350
- .footer-card strong {
351
  color: var(--color-text);
352
  font-weight: 900;
353
  }
354
 
355
- /* Hide default footer */
356
- footer {
357
- display: none !important;
358
  }
359
 
360
- /* Form elements reset */
361
- .gr-box, .gr-form, .gr-panel {
362
- border: none !important;
363
- background: transparent !important;
364
- box-shadow: none !important;
365
- border-radius: 0 !important;
366
- }
367
-
368
- label {
369
- font-weight: 900 !important;
370
- font-size: 13px !important;
371
- color: var(--color-text) !important;
372
- text-transform: uppercase !important;
373
- letter-spacing: 0.5px !important;
374
  }
375
 
376
- /* Copy button */
377
- button[title="Copy"] {
378
- border: 2px solid var(--color-border) !important;
379
- background: var(--bg-button-secondary) !important;
380
- box-shadow: 3px 3px 0 var(--color-border) !important;
381
  border-radius: 0 !important;
382
  transition: all 0.15s ease;
 
 
 
383
  }
384
 
385
- button[title="Copy"]:hover {
386
- translate: 1px 1px;
387
- box-shadow: 2px 2px 0 var(--color-border) !important;
388
- }
389
-
390
- button[title="Copy"]:active {
391
- translate: 2px 2px;
392
- box-shadow: 1px 1px 0 var(--color-border) !important;
393
  }
394
 
395
- /* Radio buttons styling */
396
- .gr-radio, .gr-checkbox {
397
- accent-color: var(--bg-button-primary);
398
  }
399
 
400
- /* Dropdown and select */
401
- select, .gr-dropdown {
402
- border: 3px solid var(--color-border) !important;
403
- background: var(--bg-result) !important;
404
- color: var(--color-text) !important;
405
- font-weight: 600 !important;
406
- border-radius: 0 !important;
407
- padding: 8px 12px !important;
408
  }
409
 
410
- /* Input fields */
411
- input[type="text"], input[type="password"], textarea {
412
- border: 3px solid var(--color-border) !important;
413
- background: var(--bg-result) !important;
414
- color: var(--color-text) !important;
415
- font-weight: 600 !important;
416
  border-radius: 0 !important;
 
 
417
  }
418
 
419
- /* Examples section */
420
- .examples-section {
421
- margin-top: 1rem;
422
  }
423
 
424
- .examples-section img {
425
- border: 3px solid var(--color-border) !important;
426
- box-shadow: 4px 4px 0 var(--color-border) !important;
427
- transition: all 0.15s ease;
428
  }
429
 
430
- .examples-section img:hover {
431
- translate: -2px -2px;
432
- box-shadow: 6px 6px 0 var(--color-border) !important;
433
  }
434
 
435
- /* Animations */
436
- @keyframes fadeIn {
437
- from { opacity: 0; transform: translateY(10px); }
438
- to { opacity: 1; transform: translateY(0); }
439
  }
440
 
441
- .card-container {
442
- animation: fadeIn 0.3s ease-out;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  }
444
 
445
- /* Scrollbar styling */
446
  ::-webkit-scrollbar {
447
- width: 12px;
448
- height: 12px;
449
  }
450
 
451
  ::-webkit-scrollbar-track {
@@ -458,56 +555,39 @@ input[type="text"], input[type="password"], textarea {
458
  border: 2px solid var(--color-border);
459
  }
460
 
461
- ::-webkit-scrollbar-thumb:hover {
462
- background: var(--bg-button-secondary-hover);
 
 
463
  }
464
 
465
- /* Loading state */
466
- .generating {
467
- animation: pulse 1.5s infinite;
468
  }
469
 
470
- @keyframes pulse {
471
- 0%, 100% { opacity: 1; }
472
- 50% { opacity: 0.6; }
473
  }
474
 
475
- /* Responsive adjustments */
476
- @media (max-width: 768px) {
477
- .header-title {
478
- font-size: 1.6rem;
479
- }
480
-
481
- .header-subtitle {
482
- font-size: 0.85rem;
483
- }
484
-
485
- .card-container {
486
- translate: -4px -4px;
487
- box-shadow: 8px 8px 0 var(--color-border);
488
- }
489
-
490
- .go-button {
491
- height: 50px;
492
- font-size: 0.9rem !important;
493
- }
494
  }
495
 
496
- /* Main content wrapper */
497
- .main-content {
498
- padding: 0 2rem 2rem 2rem;
499
- max-width: 1200px;
500
- margin: 0 auto;
501
  }
502
 
503
- /* Row styling */
504
- .main-row {
505
- gap: 2rem;
506
  }
507
 
508
- /* Column styling */
509
- .input-column, .output-column {
510
- min-width: 0;
 
 
 
511
  }
512
  """
513
 
@@ -515,87 +595,87 @@ with gr.Blocks(title="GLM-OCR") as demo:
515
 
516
  # Header
517
  gr.HTML("""
518
- <div class="app-header">
519
- <div>
520
- <h1 class="header-title">GLM-OCR</h1>
521
- <p class="header-subtitle">Document parsing and text recognition powered by AI</p>
522
- </div>
523
  </div>
524
  """)
525
 
526
  # Main Content
527
- with gr.Row(elem_classes=["main-content", "main-row"]):
 
 
528
 
529
  # Input Column
530
- with gr.Column(scale=1, elem_classes=["input-column"]):
531
- gr.HTML('<div class="card-container"><div class="card-head">Input</div><div class="card-content">')
532
 
533
  gr.HTML('<div class="section-label">Upload Image</div>')
534
  image_input = gr.Image(
535
  type="pil",
536
  label="",
537
  sources=["upload", "clipboard"],
538
- elem_classes=["upload-box"],
539
- height=250
 
540
  )
541
 
542
- gr.HTML('<div class="section-label" style="margin-top: 1.25rem;">Recognition Type</div>')
543
  task = gr.Radio(
544
  choices=list(TASK_PROMPTS.keys()),
545
  value="Text",
546
  label="",
547
- elem_classes=["task-radio"]
548
  )
549
 
550
  btn = gr.Button(
551
  "Recognize",
552
  variant="primary",
553
- elem_classes=["go-button"]
554
  )
555
 
556
- gr.HTML('<div class="section-label" style="margin-top: 1.25rem;">Examples</div>')
 
557
  examples = gr.Examples(
558
- examples=[
559
- "examples/1.jpg",
560
- "examples/2.jpg",
561
- "examples/3.jpg"
562
- ],
563
  inputs=image_input,
564
  label=""
565
  )
 
566
 
567
  gr.HTML('</div></div>')
568
 
569
  # Output Column
570
- with gr.Column(scale=1, elem_classes=["output-column"]):
571
- gr.HTML('<div class="card-container"><div class="card-head">Result</div><div class="card-content">')
572
 
573
- with gr.Tabs(elem_classes=["tabs-container"]):
574
  with gr.Tab("Text"):
575
  output_text = gr.Textbox(
576
  label="",
577
- lines=18,
578
- elem_classes=["output-area"],
 
579
  # show_copy_button=True
580
  )
581
 
582
  with gr.Tab("Markdown"):
583
  output_md = gr.Markdown(
584
  value="",
585
- elem_classes=["md-preview"]
586
  )
587
 
588
  gr.HTML('</div></div>')
589
 
590
  # Footer
591
  gr.HTML("""
592
- <div class="main-content">
593
- <div class="footer-card">
594
- Powered by <strong>zai-org/GLM-OCR</strong> | Supports text, formula, and table recognition
595
- </div>
596
  </div>
597
  """)
598
 
 
 
599
  # Event handlers
600
  def run_ocr(image, task):
601
  result = process_image(image, task)
 
5
  import tempfile
6
  from PIL import Image, ImageOps
7
  from transformers import AutoProcessor, AutoModelForImageTextToText
 
 
8
 
9
  MODEL_PATH = "zai-org/GLM-OCR"
10
 
 
11
  processor = AutoProcessor.from_pretrained(MODEL_PATH, trust_remote_code=True)
12
  model = AutoModelForImageTextToText.from_pretrained(
13
  pretrained_model_name_or_path=MODEL_PATH,
 
75
  --bg-card: #ff66a3;
76
  --bg-header: #ffffff;
77
  --bg-result: #ffffff;
78
+ --bg-uploader: rgba(255, 255, 255, 0.5);
 
 
79
  --bg-button-primary: #4ade80;
80
  --bg-button-primary-hover: #1ac2ff;
81
  --bg-button-secondary: #fde047;
 
82
  --color-border: #000000;
83
  --color-text: #000000;
 
84
  --color-text-muted: #444444;
85
  }
86
 
 
89
  --bg-card: #592659;
90
  --bg-header: #1a1a1a;
91
  --bg-result: #2a2a2a;
 
 
92
  --bg-uploader: rgba(0, 0, 0, 0.4);
93
  --bg-button-primary: #22c55e;
94
  --bg-button-primary-hover: #0ea5e9;
95
  --bg-button-secondary: #eab308;
 
96
  --color-border: #e0e0e0;
97
  --color-text: #f0f0f0;
 
98
  --color-text-muted: #b0b0b0;
99
  }
100
 
101
  * {
102
  font-family: 'Montserrat', sans-serif !important;
103
+ box-sizing: border-box;
104
  }
105
 
106
  body, .gradio-container {
107
  background: var(--bg-main) !important;
108
  min-height: 100vh;
109
+ margin: 0 !important;
110
+ padding: 0 !important;
111
  }
112
 
113
  .gradio-container {
114
  max-width: 100% !important;
115
  }
116
 
117
+ /* Remove all default Gradio styling */
118
+ .gr-group, .gr-box, .gr-form, .gr-panel, .gr-block, .contain {
119
+ border: none !important;
120
+ background: transparent !important;
121
+ box-shadow: none !important;
122
+ border-radius: 0 !important;
123
+ padding: 0 !important;
124
+ gap: 0 !important;
125
+ }
126
+
127
+ .gr-padded {
128
+ padding: 0 !important;
129
+ }
130
+
131
+ /* Header */
132
+ .header-wrapper {
133
  background: var(--bg-header);
 
134
  border-bottom: 3px solid var(--color-border);
135
+ padding: 1.5rem 3rem;
 
 
136
  margin-bottom: 2rem;
137
  }
138
 
 
140
  font-size: 2.2rem;
141
  font-weight: 900;
142
  color: var(--color-text);
143
+ margin: 0 0 0.25rem 0;
 
144
  }
145
 
146
  .header-subtitle {
147
  font-size: 0.95rem;
148
  font-weight: 600;
149
  color: var(--color-text-muted);
150
+ margin: 0;
151
  }
152
 
153
+ /* Main Layout */
154
+ .main-wrapper {
155
+ padding: 0 3rem 3rem 3rem;
156
+ max-width: 1400px;
157
+ margin: 0 auto;
158
+ }
159
+
160
+ /* Cards */
161
+ .card {
162
  background: var(--bg-card);
163
  border: 3px solid var(--color-border);
164
+ box-shadow: 10px 10px 0 var(--color-border);
165
  transition: all 0.2s ease;
166
+ overflow: hidden;
167
  }
168
 
169
+ .card:hover {
170
+ transform: translate(2px, 2px);
171
+ box-shadow: 8px 8px 0 var(--color-border);
172
  }
173
 
174
  .card-head {
175
+ font-size: 13px;
176
  font-weight: 900;
 
177
  background: var(--bg-header);
178
+ padding: 12px 16px;
179
  color: var(--color-text);
180
  border-bottom: 3px solid var(--color-border);
181
  text-transform: uppercase;
182
+ letter-spacing: 1.5px;
183
  }
184
 
185
+ .card-body {
186
  padding: 1.5rem;
 
 
 
187
  }
188
 
189
  /* Section Labels */
190
  .section-label {
191
  font-weight: 900;
192
+ font-size: 12px;
193
  color: var(--color-text);
194
+ margin-bottom: 10px;
195
  text-transform: uppercase;
196
+ letter-spacing: 1px;
197
  }
198
 
199
+ /* Image Upload */
200
+ .image-upload-container {
201
  border: 3px dashed var(--color-border) !important;
202
  background: var(--bg-uploader) !important;
203
+ min-height: 200px !important;
204
+ border-radius: 0 !important;
205
+ overflow: hidden;
206
  }
207
 
208
+ .image-upload-container:hover {
209
+ background: rgba(255, 255, 255, 0.6) !important;
210
  }
211
 
212
+ .dark .image-upload-container:hover {
213
  background: rgba(0, 0, 0, 0.5) !important;
214
  }
215
 
216
+ .image-upload-container * {
217
  color: var(--color-text) !important;
218
  }
219
 
220
+ .image-upload-container img {
221
+ border-radius: 0 !important;
 
 
 
222
  }
223
 
224
+ /* Hide image upload extras */
225
+ .image-upload-container .upload-container,
226
+ .image-upload-container [data-testid="image"] {
227
+ border: none !important;
228
+ background: transparent !important;
229
+ }
230
+
231
+ /* Radio Buttons */
232
+ .radio-container {
233
+ display: flex;
234
+ gap: 0;
235
+ }
236
+
237
+ .radio-container label {
238
+ flex: 1;
239
+ padding: 12px 16px !important;
240
+ border: 3px solid var(--color-border) !important;
241
+ background: var(--bg-uploader) !important;
242
  font-weight: 700 !important;
243
+ font-size: 13px !important;
244
  color: var(--color-text) !important;
245
+ text-align: center;
246
+ cursor: pointer;
247
+ transition: all 0.15s ease;
248
+ margin: 0 !important;
249
+ border-radius: 0 !important;
250
+ }
251
+
252
+ .radio-container label:not(:last-child) {
253
+ border-right: none !important;
254
+ }
255
+
256
+ .radio-container input[type="radio"] {
257
+ display: none !important;
258
  }
259
 
260
+ .radio-container input[type="radio"]:checked + label,
261
+ .radio-container label.selected {
262
  background: var(--bg-button-secondary) !important;
263
+ color: #000 !important;
264
+ }
265
+
266
+ /* Hide default radio styling */
267
+ .gr-radio {
268
+ border: none !important;
269
+ background: transparent !important;
270
+ padding: 0 !important;
271
+ }
272
+
273
+ .gr-radio > div {
274
+ display: flex !important;
275
+ gap: 0 !important;
276
+ }
277
+
278
+ .gr-radio label {
279
+ flex: 1;
280
+ padding: 12px 16px !important;
281
+ border: 3px solid var(--color-border) !important;
282
+ background: var(--bg-uploader) !important;
283
+ font-weight: 700 !important;
284
+ font-size: 13px !important;
285
+ color: var(--color-text) !important;
286
+ text-align: center;
287
+ cursor: pointer;
288
+ transition: all 0.15s ease;
289
+ margin: 0 !important;
290
+ border-radius: 0 !important;
291
+ }
292
+
293
+ .gr-radio label:not(:last-child) {
294
+ border-right: none !important;
295
+ }
296
+
297
+ .gr-radio label.selected {
298
+ background: var(--bg-button-secondary) !important;
299
+ color: #000 !important;
300
+ }
301
+
302
+ .gr-radio input[type="radio"] {
303
+ display: none !important;
304
+ }
305
+
306
+ .gr-radio span.text-lg {
307
+ display: none !important;
308
  }
309
 
310
  /* Primary Button */
311
+ .primary-btn {
312
  width: 100%;
313
+ height: 52px;
314
  border: 3px solid var(--color-border) !important;
315
  background: var(--bg-button-primary) !important;
316
  box-shadow: 6px 6px 0 var(--color-border) !important;
317
+ font-size: 14px !important;
318
  font-weight: 900 !important;
319
+ color: #000 !important;
320
  cursor: pointer;
321
  transition: all 0.15s ease;
322
  border-radius: 0 !important;
323
  text-transform: uppercase;
324
+ letter-spacing: 1.5px;
325
+ margin-top: 1.25rem;
326
  }
327
 
328
+ .primary-btn:hover {
329
  background: var(--bg-button-primary-hover) !important;
330
+ transform: translate(2px, 2px);
331
+ box-shadow: 4px 4px 0 var(--color-border) !important;
332
+ }
333
+
334
+ .primary-btn:active {
335
+ transform: translate(4px, 4px);
336
+ box-shadow: 2px 2px 0 var(--color-border) !important;
337
+ }
338
+
339
+ /* Tabs */
340
+ .tabs-wrapper button {
341
+ border: 3px solid var(--color-border) !important;
342
+ background: var(--bg-uploader) !important;
343
+ font-weight: 700 !important;
344
+ font-size: 12px !important;
345
+ border-radius: 0 !important;
346
+ padding: 10px 20px !important;
347
+ color: var(--color-text) !important;
348
  box-shadow: 4px 4px 0 var(--color-border) !important;
349
+ transition: all 0.15s ease;
350
+ text-transform: uppercase;
351
+ letter-spacing: 1px;
352
+ margin-right: 8px !important;
353
  }
354
 
355
+ .tabs-wrapper button:hover {
356
+ background: var(--bg-button-secondary) !important;
357
+ color: #000 !important;
358
+ transform: translate(1px, 1px);
359
+ box-shadow: 3px 3px 0 var(--color-border) !important;
360
+ }
361
+
362
+ .tabs-wrapper button.selected {
363
+ background: var(--bg-button-secondary) !important;
364
+ color: #000 !important;
365
+ transform: translate(2px, 2px);
366
  box-shadow: 2px 2px 0 var(--color-border) !important;
367
  }
368
 
369
+ /* Tab content panel */
370
+ .tabitem {
371
+ border: none !important;
372
+ background: transparent !important;
373
+ padding: 0 !important;
374
+ margin-top: 1rem !important;
375
+ }
376
+
377
+ /* Output Textbox */
378
+ .output-textbox {
379
  background: var(--bg-result) !important;
380
  border: 3px solid var(--color-border) !important;
381
  box-shadow: 6px 6px 0 var(--color-border) !important;
 
 
 
382
  border-radius: 0 !important;
383
+ overflow: hidden;
384
  }
385
 
386
+ .output-textbox textarea {
387
  font-family: 'IBM Plex Mono', monospace !important;
388
+ background: var(--bg-result) !important;
389
  border: none !important;
390
  box-shadow: none !important;
391
  color: var(--color-text) !important;
392
  font-weight: 500 !important;
393
  font-size: 14px !important;
394
+ line-height: 1.7 !important;
395
+ padding: 1rem !important;
396
+ min-height: 380px !important;
397
  }
398
 
399
+ .output-textbox .scroll-hide {
400
+ background: var(--bg-result) !important;
401
+ }
402
+
403
+ /* Markdown Output */
404
+ .md-output {
405
  background: var(--bg-result) !important;
406
  border: 3px solid var(--color-border) !important;
407
  box-shadow: 6px 6px 0 var(--color-border) !important;
408
+ padding: 1.25rem !important;
409
+ min-height: 380px;
410
  border-radius: 0 !important;
411
+ color: var(--color-text) !important;
412
  }
413
 
414
+ .md-output * {
 
 
 
415
  color: var(--color-text) !important;
416
  }
417
 
418
+ .md-output code {
419
+ background: var(--bg-uploader) !important;
420
+ padding: 3px 8px;
421
  font-family: 'IBM Plex Mono', monospace !important;
422
+ border: 1px solid var(--color-border);
423
  }
424
 
425
+ .md-output pre {
 
 
 
 
 
 
426
  background: var(--bg-uploader) !important;
427
+ padding: 1rem;
428
+ border: 2px solid var(--color-border);
429
+ overflow-x: auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430
  }
431
 
432
  /* Footer */
433
+ .footer-wrapper {
434
  background: var(--bg-header);
435
  border: 3px solid var(--color-border);
436
  box-shadow: 6px 6px 0 var(--color-border);
 
439
  font-size: 0.9rem;
440
  color: var(--color-text-muted);
441
  font-weight: 600;
442
+ margin-top: 2rem;
443
  }
444
 
445
+ .footer-wrapper strong {
446
  color: var(--color-text);
447
  font-weight: 900;
448
  }
449
 
450
+ /* Examples */
451
+ .examples-wrapper {
452
+ margin-top: 1.25rem;
453
  }
454
 
455
+ .examples-wrapper .gallery {
456
+ display: flex;
457
+ gap: 0.75rem;
458
+ flex-wrap: wrap;
 
 
 
 
 
 
 
 
 
 
459
  }
460
 
461
+ .examples-wrapper img {
462
+ border: 3px solid var(--color-border) !important;
463
+ box-shadow: 4px 4px 0 var(--color-border) !important;
 
 
464
  border-radius: 0 !important;
465
  transition: all 0.15s ease;
466
+ width: 80px !important;
467
+ height: 80px !important;
468
+ object-fit: cover;
469
  }
470
 
471
+ .examples-wrapper img:hover {
472
+ transform: translate(-2px, -2px);
473
+ box-shadow: 6px 6px 0 var(--color-border) !important;
 
 
 
 
 
474
  }
475
 
476
+ /* Hide Gradio footer and extra elements */
477
+ footer, .footer {
478
+ display: none !important;
479
  }
480
 
481
+ /* Hide labels */
482
+ .gr-block.gr-box > label,
483
+ .block > label:first-child,
484
+ label.float {
485
+ display: none !important;
 
 
 
486
  }
487
 
488
+ /* Copy Button */
489
+ button[title="Copy"] {
490
+ border: 2px solid var(--color-border) !important;
491
+ background: var(--bg-button-secondary) !important;
492
+ box-shadow: 3px 3px 0 var(--color-border) !important;
 
493
  border-radius: 0 !important;
494
+ padding: 6px !important;
495
+ transition: all 0.15s ease;
496
  }
497
 
498
+ button[title="Copy"]:hover {
499
+ transform: translate(1px, 1px);
500
+ box-shadow: 2px 2px 0 var(--color-border) !important;
501
  }
502
 
503
+ /* Remove container padding */
504
+ .contain > .gap {
505
+ gap: 0 !important;
 
506
  }
507
 
508
+ /* Row gap */
509
+ .main-row {
510
+ gap: 2.5rem !important;
511
  }
512
 
513
+ .main-row > .gr-column {
514
+ min-width: 0;
 
 
515
  }
516
 
517
+ /* Responsive */
518
+ @media (max-width: 768px) {
519
+ .header-wrapper, .main-wrapper {
520
+ padding-left: 1.5rem;
521
+ padding-right: 1.5rem;
522
+ }
523
+
524
+ .header-title {
525
+ font-size: 1.6rem;
526
+ }
527
+
528
+ .card {
529
+ box-shadow: 6px 6px 0 var(--color-border);
530
+ }
531
+
532
+ .main-row {
533
+ gap: 1.5rem !important;
534
+ }
535
+
536
+ .gr-radio label {
537
+ padding: 10px 12px !important;
538
+ font-size: 12px !important;
539
+ }
540
  }
541
 
542
+ /* Scrollbar */
543
  ::-webkit-scrollbar {
544
+ width: 10px;
545
+ height: 10px;
546
  }
547
 
548
  ::-webkit-scrollbar-track {
 
555
  border: 2px solid var(--color-border);
556
  }
557
 
558
+ /* Animation */
559
+ @keyframes fadeIn {
560
+ from { opacity: 0; transform: translateY(8px); }
561
+ to { opacity: 1; transform: translateY(0); }
562
  }
563
 
564
+ .card {
565
+ animation: fadeIn 0.25s ease-out;
 
566
  }
567
 
568
+ /* Fix spacing issues */
569
+ .block {
570
+ padding: 0 !important;
571
  }
572
 
573
+ .wrap {
574
+ gap: 0 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
575
  }
576
 
577
+ .gr-compact {
578
+ gap: 0 !important;
 
 
 
579
  }
580
 
581
+ div[data-testid="block-label"] {
582
+ display: none !important;
 
583
  }
584
 
585
+ .label-wrap {
586
+ display: none !important;
587
+ }
588
+
589
+ .gr-input-label {
590
+ display: none !important;
591
  }
592
  """
593
 
 
595
 
596
  # Header
597
  gr.HTML("""
598
+ <div class="header-wrapper">
599
+ <h1 class="header-title">GLM-OCR</h1>
600
+ <p class="header-subtitle">Document parsing and text recognition powered by AI</p>
 
 
601
  </div>
602
  """)
603
 
604
  # Main Content
605
+ gr.HTML('<div class="main-wrapper">')
606
+
607
+ with gr.Row(elem_classes=["main-row"]):
608
 
609
  # Input Column
610
+ with gr.Column(scale=1):
611
+ gr.HTML('<div class="card"><div class="card-head">Input</div><div class="card-body">')
612
 
613
  gr.HTML('<div class="section-label">Upload Image</div>')
614
  image_input = gr.Image(
615
  type="pil",
616
  label="",
617
  sources=["upload", "clipboard"],
618
+ elem_classes=["image-upload-container"],
619
+ height=220,
620
+ show_label=False
621
  )
622
 
623
+ gr.HTML('<div class="section-label" style="margin-top: 1.5rem;">Recognition Type</div>')
624
  task = gr.Radio(
625
  choices=list(TASK_PROMPTS.keys()),
626
  value="Text",
627
  label="",
628
+ show_label=False
629
  )
630
 
631
  btn = gr.Button(
632
  "Recognize",
633
  variant="primary",
634
+ elem_classes=["primary-btn"]
635
  )
636
 
637
+ gr.HTML('<div class="section-label" style="margin-top: 1.5rem;">Examples</div>')
638
+ gr.HTML('<div class="examples-wrapper">')
639
  examples = gr.Examples(
640
+ examples=["examples/1.jpg", "examples/2.jpg", "examples/3.jpg"],
 
 
 
 
641
  inputs=image_input,
642
  label=""
643
  )
644
+ gr.HTML('</div>')
645
 
646
  gr.HTML('</div></div>')
647
 
648
  # Output Column
649
+ with gr.Column(scale=1):
650
+ gr.HTML('<div class="card"><div class="card-head">Result</div><div class="card-body">')
651
 
652
+ with gr.Tabs(elem_classes=["tabs-wrapper"]):
653
  with gr.Tab("Text"):
654
  output_text = gr.Textbox(
655
  label="",
656
+ lines=16,
657
+ elem_classes=["output-textbox"],
658
+ show_label=False,
659
  # show_copy_button=True
660
  )
661
 
662
  with gr.Tab("Markdown"):
663
  output_md = gr.Markdown(
664
  value="",
665
+ elem_classes=["md-output"]
666
  )
667
 
668
  gr.HTML('</div></div>')
669
 
670
  # Footer
671
  gr.HTML("""
672
+ <div class="footer-wrapper">
673
+ Powered by <strong>zai-org/GLM-OCR</strong> | Supports text, formula, and table recognition
 
 
674
  </div>
675
  """)
676
 
677
+ gr.HTML('</div>')
678
+
679
  # Event handlers
680
  def run_ocr(image, task):
681
  result = process_image(image, task)