nubiasv2 / app.py
Ano woy
Upload 2 files
d2efd18 verified
Raw
History Blame Contribute Delete
7.16 kB
# ============================================
# app.py β€” Gradio interface for HuggingFace Spaces
# Provides both a web UI and automatic API endpoints
# ============================================
import gradio as gr
from bias_detector import BiasDetector
# Load models once at startup
bd = BiasDetector()
# Session-level sustainability log (accumulated across all requests in one session)
_session_log: list[dict] = []
def _format_sustainability(s: dict) -> str:
"""Format a sustainability dict into a human-readable string."""
return (
f"⚑ Energy: {s['energy_kwh']:.6f} kWh\n"
f"πŸ’¨ COβ‚‚eq: {s['co2_grams']:.4f} gCOβ‚‚e\n"
f"πŸ’§ Water: {s['water_liters']:.6f} L"
)
def _session_totals() -> dict:
"""Sum all sustainability metrics recorded so far this session."""
return {
"energy_kwh": sum(r["energy_kwh"] for r in _session_log),
"co2_grams": sum(r["co2_grams"] for r in _session_log),
"water_liters": sum(r["water_liters"] for r in _session_log),
}
def _build_history_table() -> str:
"""Return a plain-text table of all requests so far."""
if not _session_log:
return "No requests yet this session."
lines = [
f"{'#':<4} {'Type':<20} {'Energy (kWh)':<16} {'COβ‚‚ (gCOβ‚‚e)':<16} {'Water (L)':<12}",
"-" * 72,
]
for i, r in enumerate(_session_log, 1):
lines.append(
f"{i:<4} {r['type']:<20} "
f"{r['energy_kwh']:<16.6f} "
f"{r['co2_grams']:<16.4f} "
f"{r['water_liters']:<12.6f}"
)
totals = _session_totals()
lines.append("-" * 72)
lines.append(
f"{'TOTAL':<24} "
f"{totals['energy_kwh']:<16.6f} "
f"{totals['co2_grams']:<16.4f} "
f"{totals['water_liters']:<12.6f}"
)
return "\n".join(lines)
# ---- Endpoint functions ----
def bias_detection(text):
"""Endpoint: analyze + rewrite a job posting."""
rewrite = bd.rewrite_job_posting(text)
result = rewrite["analysis"]
summary = (
f"Overall: {result['overall_label']}\n"
f"Bias Score: {result['bias_score']}\n"
f"ML Model: {result['ml_model_result']['label']} "
f"({round(result['ml_model_result']['score'], 3)})\n"
f"Masculine-coded words: {result['masculine_count']}\n"
f"Feminine-coded words: {result['feminine_count']}"
)
flagged_summary = ""
for f in result["flagged_words"]:
flagged_summary += f"β€’ \"{f['word']}\" β†’ {f['category']}\n"
if not flagged_summary:
flagged_summary = "No gendered words detected by lexicon."
# Log sustainability
s = rewrite["sustainability"]
_session_log.append({"type": "Job posting rewrite", **s})
totals = _session_totals()
return (
summary,
flagged_summary,
rewrite["fully_rewritten"],
_format_sustainability(s),
_build_history_table(),
_format_sustainability(totals),
)
def anonymize(text):
"""Endpoint: anonymize a CV/letter."""
result = bd.anonymize_document(text)
# Log sustainability
s = result["sustainability"]
_session_log.append({"type": "CV anonymization", **s})
totals = _session_totals()
return (
result["surface_anonymized"],
result["fully_anonymized"],
_format_sustainability(s),
_build_history_table(),
_format_sustainability(totals),
)
def refresh_sustainability():
"""Refresh the sustainability tab manually."""
totals = _session_totals()
return _build_history_table(), _format_sustainability(totals)
# ---- Build Gradio UI ----
with gr.Blocks(title="Nubias: Gender Bias Detector & CV Anonymizer") as demo:
gr.Markdown("# 🌍 Nubias: Gender Bias Detector & CV Anonymizer")
gr.Markdown(
"Detecting gender bias in job postings and anonymizing CVs/letters "
"to promote fair hiring practices β€” aligned with **SDG 5: Gender Equality**."
)
# Shared sustainability components (declared here, rendered inside the tab below)
history_box = gr.Textbox(label="Request History", lines=12, interactive=False, visible=False)
totals_box = gr.Textbox(label="Session Totals", lines=4, interactive=False, visible=False)
with gr.Tab("Job Posting Analyzer"):
gr.Markdown("### Analyze and rewrite a job posting for gendered language")
input_posting = gr.Textbox(
label="Paste job posting here",
lines=8,
placeholder="e.g. We are looking for an aggressive self-starter who can dominate the market...",
)
btn_analyze = gr.Button("Analyze & Rewrite", variant="primary")
output_summary = gr.Textbox(label="Bias Analysis", lines=5)
output_flagged = gr.Textbox(label="Flagged Words", lines=5)
output_rewrite = gr.Textbox(label="Gender-Neutral Rewrite", lines=8)
output_sustain_j = gr.Textbox(label="♻️ This Request β€” Sustainability", lines=4)
with gr.Tab("CV / Letter Anonymizer"):
gr.Markdown("### Anonymize a CV, cover letter, or recommendation letter")
input_cv = gr.Textbox(
label="Paste document text here",
lines=8,
placeholder="e.g. Sarah Johnson (sarah@email.com) is an exceptionally warm leader...",
)
btn_anonymize = gr.Button("Anonymize", variant="primary")
output_surface = gr.Textbox(
label="Surface Anonymized (names, emails, pronouns, titles removed)", lines=6
)
output_full = gr.Textbox(
label="Fully Anonymized (gendered style words neutralized)", lines=6
)
output_sustain_c = gr.Textbox(label="♻️ This Request β€” Sustainability", lines=4)
with gr.Tab("♻️ Sustainability"):
gr.Markdown(
"### Environmental impact of Nubias this session\n"
"Estimates are based on measured CPU energy draw (via **CodeCarbon**) "
"and a data-centre Water Usage Effectiveness (WUE) of **1.6 L / kWh**.\n\n"
"Carbon intensity uses CodeCarbon's location-aware grid data. "
"All figures are per-request and cumulative for the current session."
)
tab_history = gr.Textbox(label="Request History", lines=12, interactive=False)
tab_totals = gr.Textbox(label="Session Totals", lines=4, interactive=False)
btn_refresh = gr.Button("πŸ”„ Refresh", variant="secondary")
btn_refresh.click(
refresh_sustainability,
inputs=[],
outputs=[tab_history, tab_totals],
)
# Wire action buttons β€” both update the sustainability tab directly
btn_analyze.click(
bias_detection,
inputs=input_posting,
outputs=[output_summary, output_flagged, output_rewrite,
output_sustain_j, tab_history, tab_totals],
)
btn_anonymize.click(
anonymize,
inputs=input_cv,
outputs=[output_surface, output_full, output_sustain_c,
tab_history, tab_totals],
)
demo.launch(server_name="0.0.0.0", server_port=7860)