Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- hate_speech_demo.py +90 -189
hate_speech_demo.py
CHANGED
@@ -15,7 +15,27 @@ from pathlib import Path
|
|
15 |
# Load environment variables (for local development)
|
16 |
load_dotenv()
|
17 |
|
18 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
def process_retrieval_text(retrieval_text, user_input):
|
20 |
"""
|
21 |
Process the retrieval text by identifying proper document boundaries
|
@@ -389,6 +409,55 @@ h1, h2, h3, h4, h5, h6, p, span, div, button, input, textarea, label {
|
|
389 |
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
390 |
transform: translateY(-2px);
|
391 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
392 |
"""
|
393 |
|
394 |
# Contextual API class - UPDATED WITH NEW MODEL ID
|
@@ -517,7 +586,6 @@ def get_openai_moderation(openai_client, user_input):
|
|
517 |
return f"Safety Status: Error\nError: {str(e)}", "unsafe"
|
518 |
|
519 |
# Perspective API
|
520 |
-
|
521 |
def get_perspective_rating(api_key, user_input):
|
522 |
url = 'https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze'
|
523 |
params = {'key': api_key}
|
@@ -553,7 +621,6 @@ def get_perspective_rating(api_key, user_input):
|
|
553 |
except Exception as e:
|
554 |
return f"Safety Status: Error\nError: {str(e)}", "unsafe"
|
555 |
|
556 |
-
|
557 |
# Updated to only require one input
|
558 |
def rate_user_input(user_input):
|
559 |
# Initialize APIs with hardcoded keys
|
@@ -567,7 +634,6 @@ def rate_user_input(user_input):
|
|
567 |
openai_rating, openai_safety = get_openai_moderation(openai_client, user_input)
|
568 |
perspective_rating, perspective_safety = get_perspective_rating(PERSPECTIVE_API_KEY, user_input)
|
569 |
|
570 |
-
|
571 |
# Format responses carefully to avoid random line breaks
|
572 |
llama_rating = re.sub(r'\.(?=\s+[A-Z])', '.\n', llama_rating)
|
573 |
# Don't add line breaks to contextual rating
|
@@ -652,180 +718,15 @@ def create_gradio_app():
|
|
652 |
border_color_primary="#E0E0E0"
|
653 |
)
|
654 |
|
655 |
-
#
|
656 |
-
custom_css = CUSTOM_CSS
|
657 |
-
/* Policy preview popup styles */
|
658 |
-
.policy-popup {
|
659 |
-
display: none;
|
660 |
-
position: fixed;
|
661 |
-
top: 0;
|
662 |
-
left: 0;
|
663 |
-
width: 100%;
|
664 |
-
height: 100%;
|
665 |
-
background-color: rgba(0,0,0,0.7);
|
666 |
-
z-index: 1000;
|
667 |
-
justify-content: center;
|
668 |
-
align-items: center;
|
669 |
-
}
|
670 |
-
|
671 |
-
.policy-popup-content {
|
672 |
-
background-color: white;
|
673 |
-
width: 80%;
|
674 |
-
height: 80%;
|
675 |
-
border-radius: 8px;
|
676 |
-
padding: 20px;
|
677 |
-
position: relative;
|
678 |
-
box-shadow: 0 5px 20px rgba(0,0,0,0.3);
|
679 |
-
display: flex;
|
680 |
-
flex-direction: column;
|
681 |
-
}
|
682 |
-
|
683 |
-
.policy-popup-header {
|
684 |
-
display: flex;
|
685 |
-
justify-content: space-between;
|
686 |
-
align-items: center;
|
687 |
-
margin-bottom: 15px;
|
688 |
-
border-bottom: 1px solid #eee;
|
689 |
-
padding-bottom: 10px;
|
690 |
-
}
|
691 |
-
|
692 |
-
.policy-popup-title {
|
693 |
-
font-weight: bold;
|
694 |
-
font-size: 18px;
|
695 |
-
}
|
696 |
-
|
697 |
-
.policy-popup-close {
|
698 |
-
background-color: #222222;
|
699 |
-
color: white;
|
700 |
-
border: none;
|
701 |
-
border-radius: 4px;
|
702 |
-
padding: 5px 10px;
|
703 |
-
cursor: pointer;
|
704 |
-
}
|
705 |
-
|
706 |
-
.policy-popup-close:hover {
|
707 |
-
background-color: #000000;
|
708 |
-
}
|
709 |
-
|
710 |
-
.policy-iframe-container {
|
711 |
-
flex: 1;
|
712 |
-
overflow: hidden;
|
713 |
-
}
|
714 |
-
|
715 |
-
.policy-iframe {
|
716 |
-
width: 100%;
|
717 |
-
height: 100%;
|
718 |
-
border: 1px solid #eee;
|
719 |
-
}
|
720 |
-
|
721 |
-
/* Fallback for when PDF can't be displayed in iframe */
|
722 |
-
.policy-fallback {
|
723 |
-
padding: 20px;
|
724 |
-
text-align: center;
|
725 |
-
}
|
726 |
-
|
727 |
-
.policy-fallback a {
|
728 |
-
display: inline-block;
|
729 |
-
margin-top: 15px;
|
730 |
-
padding: 10px 15px;
|
731 |
-
background-color: #FCA539;
|
732 |
-
color: #000000;
|
733 |
-
text-decoration: none;
|
734 |
-
border-radius: 4px;
|
735 |
-
font-weight: bold;
|
736 |
-
}
|
737 |
-
|
738 |
-
|
739 |
-
"""
|
740 |
|
741 |
with gr.Blocks(title="Hate Speech Rating Oracle", theme=theme, css=custom_css) as app:
|
742 |
# Add loading spinner
|
743 |
loading_spinner = gr.HTML('<div id="loading-spinner"></div>')
|
744 |
|
745 |
-
#
|
746 |
-
|
747 |
-
# Convert Path object to string explicitly
|
748 |
-
pdf_file = gr.File(str("Hate Speech Policy.pdf"), visible=False, label="Policy PDF")
|
749 |
-
except Exception as e:
|
750 |
-
print(f"Error creating PDF file component: {e}")
|
751 |
-
# Fallback if PDF doesn't exist or other error occurs
|
752 |
-
pdf_file = gr.File(None, visible=False, label="Policy PDF")
|
753 |
-
|
754 |
-
# Add policy popup HTML with reliable PDF loading that works on first click
|
755 |
-
policy_popup_html = """
|
756 |
-
<div id="policy-popup" class="policy-popup">
|
757 |
-
<div class="policy-popup-content">
|
758 |
-
<div class="policy-popup-header">
|
759 |
-
<div class="policy-popup-title">Hate Speech Policy</div>
|
760 |
-
<button class="policy-popup-close" onclick="document.getElementById('policy-popup').style.display='none';">Close</button>
|
761 |
-
</div>
|
762 |
-
<div class="policy-iframe-container">
|
763 |
-
<!-- PDF viewer iframe with PDF.js as fallback -->
|
764 |
-
<iframe class="policy-iframe" id="policy-iframe"
|
765 |
-
src="https://docs.google.com/viewer?url=${pdf_url}&embedded=true"
|
766 |
-
style="width:100%; height:100%; border:none;"></iframe>
|
767 |
-
|
768 |
-
<!-- Loading indicator -->
|
769 |
-
<div id="pdf-loading" style="display: flex; justify-content: center; align-items: center; height: 100%;">
|
770 |
-
<div style="text-align: center;">
|
771 |
-
<div style="width: 50px; height: 50px; border: 5px solid #f3f3f3;
|
772 |
-
border-top: 5px solid #FCA539; border-radius: 50%;
|
773 |
-
margin: 0 auto 15px auto; animation: spin 1s linear infinite;"></div>
|
774 |
-
<p>Loading policy document...</p>
|
775 |
-
</div>
|
776 |
-
</div>
|
777 |
-
|
778 |
-
<!-- Fallback content -->
|
779 |
-
<div class="policy-fallback" id="policy-fallback" style="display:none;">
|
780 |
-
<p>The policy document couldn't be displayed in the preview.</p>
|
781 |
-
<a href="#" id="policy-download-link" target="_blank">Download Policy PDF</a>
|
782 |
-
</div>
|
783 |
-
</div>
|
784 |
-
</div>
|
785 |
-
</div>
|
786 |
-
|
787 |
-
<script>
|
788 |
-
// Function to open the policy popup
|
789 |
-
function openPolicyPopup() {
|
790 |
-
const popup = document.getElementById('policy-popup');
|
791 |
-
popup.style.display = 'flex';
|
792 |
-
|
793 |
-
// Find the PDF URL from Gradio's file component
|
794 |
-
const fileComponents = document.querySelectorAll("div.file-component");
|
795 |
-
let pdfUrl = null;
|
796 |
-
|
797 |
-
for (const comp of fileComponents) {
|
798 |
-
const downloadBtn = comp.querySelector("a[download]");
|
799 |
-
if (downloadBtn && downloadBtn.href) {
|
800 |
-
pdfUrl = downloadBtn.href;
|
801 |
-
break;
|
802 |
-
}
|
803 |
-
}
|
804 |
-
|
805 |
-
if (pdfUrl) {
|
806 |
-
// Encode the URL for Google Viewer
|
807 |
-
const encodedUrl = encodeURIComponent(pdfUrl);
|
808 |
-
const iframe = document.getElementById('policy-iframe');
|
809 |
-
iframe.src = `https://docs.google.com/viewer?url=${encodedUrl}&embedded=true`;
|
810 |
-
|
811 |
-
// Set up the download link
|
812 |
-
document.getElementById('policy-download-link').href = pdfUrl;
|
813 |
-
|
814 |
-
// Hide loading after some time (or when loaded)
|
815 |
-
setTimeout(() => {
|
816 |
-
document.getElementById('pdf-loading').style.display = 'none';
|
817 |
-
}, 3000);
|
818 |
-
} else {
|
819 |
-
// Show fallback if no PDF found
|
820 |
-
document.getElementById('pdf-loading').style.display = 'none';
|
821 |
-
document.getElementById('policy-fallback').style.display = 'block';
|
822 |
-
document.getElementById('policy-iframe').style.display = 'none';
|
823 |
-
}
|
824 |
-
}
|
825 |
-
</script>
|
826 |
-
"""
|
827 |
-
|
828 |
-
gr.HTML(policy_popup_html)
|
829 |
|
830 |
gr.Markdown("# Safety Oracle for Rating Hate Speech [BETA]")
|
831 |
gr.HTML("""
|
@@ -874,10 +775,10 @@ def create_gradio_app():
|
|
874 |
rate_btn = gr.Button("Rate Content", elem_classes=["gray-button"], scale=1)
|
875 |
|
876 |
user_input = gr.Textbox(
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
)
|
881 |
|
882 |
# 🌟 Contextual Safety Oracle
|
883 |
gr.HTML("""
|
@@ -949,18 +850,18 @@ def create_gradio_app():
|
|
949 |
|
950 |
# Bind rating button with loading indicator
|
951 |
rate_btn.click(
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
).then(
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
).then(
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
)
|
964 |
|
965 |
return app
|
966 |
|
|
|
15 |
# Load environment variables (for local development)
|
16 |
load_dotenv()
|
17 |
|
18 |
+
# Google Drive Embed URL for PDF
|
19 |
+
PDF_EMBED_URL = "https://drive.google.com/file/d/1WZCQpIWfelbxgBr8dNiW2rqVGaDyf-Gi/preview"
|
20 |
+
|
21 |
+
# Custom PDF Viewer Modal (injected HTML)
|
22 |
+
PDF_MODAL_HTML = f"""
|
23 |
+
<div id='policy-popup' class='pdf-modal' style='display:none;'>
|
24 |
+
<div class='pdf-modal-content'>
|
25 |
+
<button class='close-btn' onclick="document.getElementById('policy-popup').style.display='none'; document.body.style.overflow='auto';">×</button>
|
26 |
+
<div class='pdf-container'>
|
27 |
+
<iframe class='pdf-embed' src='{PDF_EMBED_URL}' allow="autoplay"></iframe>
|
28 |
+
</div>
|
29 |
+
</div>
|
30 |
+
</div>
|
31 |
+
<script>
|
32 |
+
function openPolicyPopup() {{
|
33 |
+
document.getElementById('policy-popup').style.display = 'flex';
|
34 |
+
document.body.style.overflow = 'hidden';
|
35 |
+
}}
|
36 |
+
</script>
|
37 |
+
"""
|
38 |
+
|
39 |
def process_retrieval_text(retrieval_text, user_input):
|
40 |
"""
|
41 |
Process the retrieval text by identifying proper document boundaries
|
|
|
409 |
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
410 |
transform: translateY(-2px);
|
411 |
}
|
412 |
+
|
413 |
+
/* PDF Modal Styling */
|
414 |
+
.pdf-modal {
|
415 |
+
display: none;
|
416 |
+
position: fixed;
|
417 |
+
top: 0;
|
418 |
+
left: 0;
|
419 |
+
width: 100%;
|
420 |
+
height: 100%;
|
421 |
+
background-color: rgba(0,0,0,0.7);
|
422 |
+
z-index: 1000;
|
423 |
+
justify-content: center;
|
424 |
+
align-items: center;
|
425 |
+
}
|
426 |
+
|
427 |
+
.pdf-modal-content {
|
428 |
+
background-color: white;
|
429 |
+
width: 80%;
|
430 |
+
height: 80%;
|
431 |
+
border-radius: 8px;
|
432 |
+
padding: 20px;
|
433 |
+
position: relative;
|
434 |
+
box-shadow: 0 5px 20px rgba(0,0,0,0.3);
|
435 |
+
}
|
436 |
+
|
437 |
+
.close-btn {
|
438 |
+
position: absolute;
|
439 |
+
right: 15px;
|
440 |
+
top: 15px;
|
441 |
+
font-size: 24px;
|
442 |
+
cursor: pointer;
|
443 |
+
background: #222;
|
444 |
+
color: white;
|
445 |
+
border: none;
|
446 |
+
border-radius: 4px;
|
447 |
+
padding: 5px 15px;
|
448 |
+
}
|
449 |
+
|
450 |
+
.pdf-container {
|
451 |
+
width: 100%;
|
452 |
+
height: calc(100% - 40px);
|
453 |
+
margin-top: 40px;
|
454 |
+
}
|
455 |
+
|
456 |
+
.pdf-embed {
|
457 |
+
width: 100%;
|
458 |
+
height: 100%;
|
459 |
+
border: 1px solid #eee;
|
460 |
+
}
|
461 |
"""
|
462 |
|
463 |
# Contextual API class - UPDATED WITH NEW MODEL ID
|
|
|
586 |
return f"Safety Status: Error\nError: {str(e)}", "unsafe"
|
587 |
|
588 |
# Perspective API
|
|
|
589 |
def get_perspective_rating(api_key, user_input):
|
590 |
url = 'https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze'
|
591 |
params = {'key': api_key}
|
|
|
621 |
except Exception as e:
|
622 |
return f"Safety Status: Error\nError: {str(e)}", "unsafe"
|
623 |
|
|
|
624 |
# Updated to only require one input
|
625 |
def rate_user_input(user_input):
|
626 |
# Initialize APIs with hardcoded keys
|
|
|
634 |
openai_rating, openai_safety = get_openai_moderation(openai_client, user_input)
|
635 |
perspective_rating, perspective_safety = get_perspective_rating(PERSPECTIVE_API_KEY, user_input)
|
636 |
|
|
|
637 |
# Format responses carefully to avoid random line breaks
|
638 |
llama_rating = re.sub(r'\.(?=\s+[A-Z])', '.\n', llama_rating)
|
639 |
# Don't add line breaks to contextual rating
|
|
|
718 |
border_color_primary="#E0E0E0"
|
719 |
)
|
720 |
|
721 |
+
# Use the custom CSS with PDF modal styling
|
722 |
+
custom_css = CUSTOM_CSS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
723 |
|
724 |
with gr.Blocks(title="Hate Speech Rating Oracle", theme=theme, css=custom_css) as app:
|
725 |
# Add loading spinner
|
726 |
loading_spinner = gr.HTML('<div id="loading-spinner"></div>')
|
727 |
|
728 |
+
# Add the PDF modal HTML directly (defined at the top of the file)
|
729 |
+
gr.HTML(PDF_MODAL_HTML)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
730 |
|
731 |
gr.Markdown("# Safety Oracle for Rating Hate Speech [BETA]")
|
732 |
gr.HTML("""
|
|
|
775 |
rate_btn = gr.Button("Rate Content", elem_classes=["gray-button"], scale=1)
|
776 |
|
777 |
user_input = gr.Textbox(
|
778 |
+
placeholder="Type content to evaluate here...",
|
779 |
+
lines=6,
|
780 |
+
label=""
|
781 |
+
)
|
782 |
|
783 |
# 🌟 Contextual Safety Oracle
|
784 |
gr.HTML("""
|
|
|
850 |
|
851 |
# Bind rating button with loading indicator
|
852 |
rate_btn.click(
|
853 |
+
show_loading,
|
854 |
+
inputs=None,
|
855 |
+
outputs=loading_spinner
|
856 |
+
).then(
|
857 |
+
rate_user_input,
|
858 |
+
inputs=[user_input],
|
859 |
+
outputs=[contextual_results, llama_results, openai_results, perspective_results]
|
860 |
+
).then(
|
861 |
+
hide_loading,
|
862 |
+
inputs=None,
|
863 |
+
outputs=loading_spinner
|
864 |
+
)
|
865 |
|
866 |
return app
|
867 |
|