codelion commited on
Commit
b3dddf7
·
verified ·
1 Parent(s): 37d457e

Add share link + result card to text tab, download image button for mobile, hide Gradio toolbar via CSS

Browse files
Files changed (2) hide show
  1. __pycache__/app.cpython-313.pyc +0 -0
  2. app.py +130 -20
__pycache__/app.cpython-313.pyc CHANGED
Binary files a/__pycache__/app.cpython-313.pyc and b/__pycache__/app.cpython-313.pyc differ
 
app.py CHANGED
@@ -284,6 +284,16 @@ label span {
284
  text-decoration: none !important;
285
  border-bottom: 1px dotted var(--text-muted);
286
  }
 
 
 
 
 
 
 
 
 
 
287
  """
288
 
289
  HUMAN_EXAMPLE = (
@@ -361,13 +371,28 @@ def _error_label(msg: str) -> dict:
361
 
362
 
363
  def detect_text(text: str) -> dict:
364
- """Classify text as human-written or AI-generated."""
365
  if not text or len(text.strip().split()) < 10:
366
  return _error_label("Please enter at least a few sentences (~50 words)")
367
  predictions = classifier.predict(text, k=2)
368
  return {label: round(score, 4) for label, score in predictions}
369
 
370
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  SPACE_URL = "https://adaptive-classifier-ai-detector.hf.space"
372
 
373
 
@@ -419,10 +444,12 @@ def make_result_card(url: str, label: str, confidence: float) -> Image.Image:
419
  if fill_w > 0:
420
  draw.rounded_rectangle([bar_x, bar_y, bar_x + fill_w, bar_y + bar_h], radius=12, fill=result_color)
421
 
422
- # URL
423
- display_url = url[:80] + "..." if len(url) > 80 else url
424
- draw.text((60, 285), "URL analyzed:", fill=muted_color, font=font_small)
425
- draw.text((60, 308), display_url, fill=text_color, font=font_mono)
 
 
426
 
427
  # Footer
428
  draw.text((60, H - 60), "adaptive-classifier-ai-detector.hf.space", fill=muted_color, font=font_small)
@@ -487,8 +514,62 @@ with gr.Blocks(css=CSS, title="AI Text Detector", theme=gr.themes.Base()) as dem
487
 
488
  with gr.Group(elem_classes="result-card"):
489
  text_output = gr.Label(num_top_classes=2, label="Result")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
 
491
- text_btn.click(fn=detect_text, inputs=text_input, outputs=text_output, api_name="detect")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
492
 
493
  gr.HTML('<div class="examples-heading">Try an example</div>')
494
  gr.Examples(
@@ -513,14 +594,12 @@ with gr.Blocks(css=CSS, title="AI Text Detector", theme=gr.themes.Base()) as dem
513
  with gr.Row(visible=False) as share_row:
514
  copy_link_btn = gr.Button("Copy Link", size="sm", elem_classes="detect-btn")
515
  copy_img_btn = gr.Button("Copy Image", size="sm", elem_classes="detect-btn")
 
516
  share_card = gr.Image(
517
  label="Result card",
518
  visible=False,
519
  type="pil",
520
  elem_id="share-card",
521
- show_download_button=False,
522
- show_share_button=False,
523
- show_fullscreen_button=False,
524
  )
525
 
526
  with gr.Group(elem_classes="input-card"):
@@ -576,6 +655,18 @@ with gr.Blocks(css=CSS, title="AI Text Detector", theme=gr.themes.Base()) as dem
576
  }""",
577
  )
578
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  gr.HTML('<div class="examples-heading">Try an example</div>')
580
  gr.Examples(
581
  examples=[
@@ -600,25 +691,44 @@ with gr.Blocks(css=CSS, title="AI Text Detector", theme=gr.themes.Base()) as dem
600
  """)
601
 
602
  def _on_load(request: gr.Request):
603
- url = request.query_params.get("url", "")
604
- if url:
605
- result, preview, link, card = detect_url(url)
606
- has_result = bool(link)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  return (
608
  gr.update(selected="url-tab"),
609
- url,
610
- result,
611
- gr.update(value=link, visible=has_result),
612
- gr.update(visible=has_result),
613
- gr.update(value=card, visible=has_result),
614
  preview,
615
  )
616
- return gr.update(), "", {}, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), ""
617
 
618
  demo.load(
619
  fn=_on_load,
620
  inputs=None,
621
- outputs=[tabs, url_input, url_output, share_link, share_row, share_card, url_preview],
 
 
 
 
 
 
622
  )
623
 
624
  if __name__ == "__main__":
 
284
  text-decoration: none !important;
285
  border-bottom: 1px dotted var(--text-muted);
286
  }
287
+
288
+ /* Hide Gradio image toolbar (download/share/fullscreen) on result cards */
289
+ #share-card .image-toolbar,
290
+ #text-share-card .image-toolbar,
291
+ #share-card .icon-buttons,
292
+ #text-share-card .icon-buttons,
293
+ #share-card button[aria-label],
294
+ #text-share-card button[aria-label] {
295
+ display: none !important;
296
+ }
297
  """
298
 
299
  HUMAN_EXAMPLE = (
 
371
 
372
 
373
  def detect_text(text: str) -> dict:
374
+ """Classify text as human-written or AI-generated (label only)."""
375
  if not text or len(text.strip().split()) < 10:
376
  return _error_label("Please enter at least a few sentences (~50 words)")
377
  predictions = classifier.predict(text, k=2)
378
  return {label: round(score, 4) for label, score in predictions}
379
 
380
 
381
+ def detect_text_full(text: str) -> tuple[dict, str, Image.Image | None]:
382
+ """Classify text and generate share link + card."""
383
+ result = detect_text(text)
384
+ if len(result) != 2 or any(k.startswith("Please") for k in result):
385
+ return result, "", None
386
+ # Share link with text snippet as param
387
+ snippet = text.strip()[:200]
388
+ share_link = f"{SPACE_URL}/?text={urllib.parse.quote(snippet, safe='')}"
389
+ # Card image
390
+ top_label = max(result, key=result.get)
391
+ preview = text.strip()[:80] + ("..." if len(text.strip()) > 80 else "")
392
+ card = make_result_card(preview, top_label, result[top_label])
393
+ return result, share_link, card
394
+
395
+
396
  SPACE_URL = "https://adaptive-classifier-ai-detector.hf.space"
397
 
398
 
 
444
  if fill_w > 0:
445
  draw.rounded_rectangle([bar_x, bar_y, bar_x + fill_w, bar_y + bar_h], radius=12, fill=result_color)
446
 
447
+ # Source text/URL
448
+ display_src = url[:80] + "..." if len(url) > 80 else url
449
+ is_url = url.startswith("http") or url.startswith("www")
450
+ src_label = "URL analyzed:" if is_url else "Text analyzed:"
451
+ draw.text((60, 285), src_label, fill=muted_color, font=font_small)
452
+ draw.text((60, 308), display_src, fill=text_color, font=font_mono)
453
 
454
  # Footer
455
  draw.text((60, H - 60), "adaptive-classifier-ai-detector.hf.space", fill=muted_color, font=font_small)
 
514
 
515
  with gr.Group(elem_classes="result-card"):
516
  text_output = gr.Label(num_top_classes=2, label="Result")
517
+ text_share_link = gr.Textbox(visible=False, elem_id="text-share-url")
518
+ with gr.Row(visible=False) as text_share_row:
519
+ text_copy_link_btn = gr.Button("Copy Link", size="sm", elem_classes="detect-btn")
520
+ text_copy_img_btn = gr.Button("Copy Image", size="sm", elem_classes="detect-btn")
521
+ text_dl_img_btn = gr.Button("Download Image", size="sm", elem_classes="detect-btn")
522
+ text_share_card = gr.Image(
523
+ label="Result card",
524
+ visible=False,
525
+ type="pil",
526
+ elem_id="text-share-card",
527
+ )
528
+
529
+ def run_text_detection(text):
530
+ result, link, card = detect_text_full(text)
531
+ has_result = bool(link)
532
+ return (
533
+ result,
534
+ gr.update(value=link, visible=has_result),
535
+ gr.update(visible=has_result),
536
+ gr.update(value=card, visible=has_result),
537
+ )
538
+
539
+ text_btn.click(
540
+ fn=run_text_detection,
541
+ inputs=text_input,
542
+ outputs=[text_output, text_share_link, text_share_row, text_share_card],
543
+ api_name="detect",
544
+ )
545
 
546
+ text_copy_link_btn.click(
547
+ fn=None, inputs=text_share_link, outputs=None,
548
+ js="(url) => { navigator.clipboard.writeText(url); }",
549
+ )
550
+ text_copy_img_btn.click(
551
+ fn=None, inputs=None, outputs=None,
552
+ js="""() => {
553
+ const img = document.querySelector('#text-share-card img');
554
+ if (img) {
555
+ const c = document.createElement('canvas');
556
+ c.width = img.naturalWidth; c.height = img.naturalHeight;
557
+ c.getContext('2d').drawImage(img, 0, 0);
558
+ c.toBlob(b => navigator.clipboard.write([new ClipboardItem({'image/png': b})]), 'image/png');
559
+ }
560
+ }""",
561
+ )
562
+ text_dl_img_btn.click(
563
+ fn=None, inputs=None, outputs=None,
564
+ js="""() => {
565
+ const img = document.querySelector('#text-share-card img');
566
+ if (img) {
567
+ const a = document.createElement('a');
568
+ a.href = img.src; a.download = 'ai-detector-result.png';
569
+ a.click();
570
+ }
571
+ }""",
572
+ )
573
 
574
  gr.HTML('<div class="examples-heading">Try an example</div>')
575
  gr.Examples(
 
594
  with gr.Row(visible=False) as share_row:
595
  copy_link_btn = gr.Button("Copy Link", size="sm", elem_classes="detect-btn")
596
  copy_img_btn = gr.Button("Copy Image", size="sm", elem_classes="detect-btn")
597
+ dl_img_btn = gr.Button("Download Image", size="sm", elem_classes="detect-btn")
598
  share_card = gr.Image(
599
  label="Result card",
600
  visible=False,
601
  type="pil",
602
  elem_id="share-card",
 
 
 
603
  )
604
 
605
  with gr.Group(elem_classes="input-card"):
 
655
  }""",
656
  )
657
 
658
+ dl_img_btn.click(
659
+ fn=None, inputs=None, outputs=None,
660
+ js="""() => {
661
+ const img = document.querySelector('#share-card img');
662
+ if (img) {
663
+ const a = document.createElement('a');
664
+ a.href = img.src; a.download = 'ai-detector-result.png';
665
+ a.click();
666
+ }
667
+ }""",
668
+ )
669
+
670
  gr.HTML('<div class="examples-heading">Try an example</div>')
671
  gr.Examples(
672
  examples=[
 
691
  """)
692
 
693
  def _on_load(request: gr.Request):
694
+ text_param = request.query_params.get("text", "")
695
+ url_param = request.query_params.get("url", "")
696
+ # Default: no changes
697
+ no_change = (
698
+ gr.update(), "", {}, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
699
+ "", {}, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), "",
700
+ )
701
+ if text_param:
702
+ result, link, card = detect_text_full(text_param)
703
+ has = bool(link)
704
+ return (
705
+ gr.update(selected="text-tab"),
706
+ text_param, result,
707
+ gr.update(value=link, visible=has), gr.update(visible=has), gr.update(value=card, visible=has),
708
+ "", {}, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), "",
709
+ )
710
+ if url_param:
711
+ result, preview, link, card = detect_url(url_param)
712
+ has = bool(link)
713
  return (
714
  gr.update(selected="url-tab"),
715
+ "", {}, gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
716
+ url_param, result,
717
+ gr.update(value=link, visible=has), gr.update(visible=has), gr.update(value=card, visible=has),
 
 
718
  preview,
719
  )
720
+ return no_change
721
 
722
  demo.load(
723
  fn=_on_load,
724
  inputs=None,
725
+ outputs=[
726
+ tabs,
727
+ # text tab outputs
728
+ text_input, text_output, text_share_link, text_share_row, text_share_card,
729
+ # url tab outputs
730
+ url_input, url_output, share_link, share_row, share_card, url_preview,
731
+ ],
732
  )
733
 
734
  if __name__ == "__main__":