CoolFace
Apppublic

euler03/bbq

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
app.py471 linesDownload Raw Back to root
1import os2import json3import random4import gradio as gr5import torch6from llama_cpp import Llama7from transformers import (8    AutoModelForSequenceClassification, 9    AutoTokenizer, 10    AutoModelForMultipleChoice11)12 13# -------------------------------------------------------14# 1️⃣ Setup: Device15# -------------------------------------------------------16device = "cuda" if torch.cuda.is_available() else "cpu"17print(f"Using device: {device}")18if device == "cuda":19    print("GPU Name:", torch.cuda.get_device_name(0))20 21# -------------------------------------------------------22# 2️⃣ Text Objectivity Analysis (Sequence Classification)23# -------------------------------------------------------24MODELS = {25    "Aubins/distil-bumble-bert": "Aubins/distil-bumble-bert",26}27id2label = {0: "BIASED", 1: "NEUTRAL"}28label2id = {"BIASED": 0, "NEUTRAL": 1}29loaded_models = {}30 31def load_model(model_name: str):32    """Load and cache a sequence classification model for text objectivity analysis."""33    if model_name not in loaded_models:34        try:35            model_path = MODELS[model_name]36            model = AutoModelForSequenceClassification.from_pretrained(37                model_path, 38                num_labels=2,39                id2label=id2label,40                label2id=label2id41            ).to(device)42            tokenizer = AutoTokenizer.from_pretrained(model_path)43            loaded_models[model_name] = (model, tokenizer)44            return model, tokenizer45        except Exception as e:46            return f"Error loading model: {str(e)}"47    return loaded_models[model_name]48 49def analyze_text(text: str, model_name: str):50    """Analyze the text for bias or neutrality using a selected classification model."""51    if not text.strip():52        return {"Empty text": 1.0}, "Please enter text to analyze."53    result = load_model(model_name)54    if isinstance(result, str):55        return {"Error": 1.0}, result56    model, tokenizer = result57    try:58        inputs = tokenizer(59            text, 60            return_tensors="pt", 61            truncation=True, 62            padding=True,63            max_length=51264        )65        inputs = {k: v.to(device) for k, v in inputs.items()}66        model.eval()67        with torch.no_grad():68            outputs = model(**inputs)69        logits = outputs.logits[0]70        probabilities = torch.nn.functional.softmax(logits, dim=0)71        predicted_class = torch.argmax(logits).item()72        status = "neutral" if predicted_class == 1 else "biased"73        confidence = probabilities[predicted_class].item()74        message = f"This text is classified as {status} with a confidence of {confidence:.2%}."75        confidence_map = {"Neutral": probabilities[1].item(), "Biased": probabilities[0].item()}76        return confidence_map, message77    except Exception as e:78        return {"Error": 1.0}, f"Analysis error: {str(e)}"79 80# -------------------------------------------------------81# 3️⃣ Scenario-based Objectivity Assessment (LLaMA + BBQ)82# -------------------------------------------------------83# (a) Load LLaMA from Hugging Face Hub (for generation)84llm = Llama.from_pretrained(85    repo_id="TheBloke/llama-2-7b-chat-GGUF",86    filename="llama-2-7b-chat.Q4_K_M.gguf",87    n_ctx=512,88    n_gpu_layers=30,89)90# (b) Load BBQ Fine-Tuned BERT Model & Tokenizer (multiple-choice)91BBQ_MODEL = "euler03/bbq-distil_bumble_bert"92bbq_tokenizer = AutoTokenizer.from_pretrained(BBQ_MODEL)93bbq_model = AutoModelForMultipleChoice.from_pretrained(BBQ_MODEL).to(device)94print("BBQ model loaded.")95 96# -------------------------------------------------------97# Replace original topics with your offline scenario topics98# -------------------------------------------------------99TOPICS = [100    "AI in Healthcare",101    "Climate Change",102    "Universal Basic Income",103    "Social Media's Role in Elections",104    "Government Surveillance and Privacy",105    "Genetic Engineering",106    "Gender Pay Gap",107    "Police Use of Facial Recognition",108    "Space Exploration and Government Funding",109    "Affirmative Action in Universities",110    "Renewable Energy Advances",111    "Mental Health Awareness",112    "Online Privacy and Data Security",113    "Impact of Automation on Employment",114    "Electric Vehicles Adoption",115    "Work From Home Culture",116    "Food Security and GMOs",117    "Cryptocurrency Volatility",118    "Artificial Intelligence in Education",119    "Cultural Diversity in Media",120    "Urbanization and Infrastructure",121    "Healthcare Reform",122    "Taxation Policies",123    "Global Trade and Tariffs",124    "Environmental Conservation",125    "Social Justice Movements",126    "Digital Transformation in Business",127    "Public Transportation Funding",128    "Immigration Reform",129    "Aging Population Challenges",130    "Mental Health in the Workplace",131    "Internet Censorship",132    "Political Polarization",133    "Cybersecurity in the Digital Age",134    "Privacy vs. Security",135    "Sustainable Agriculture",136    "Future of Work",137    "Tech Monopolies",138    "Education Reform",139    "Climate Policy and Economics",140    "Renewable Energy Storage",141    "Water Scarcity",142    "Urban Green Spaces",143    "Automation in Manufacturing",144    "Renewable Energy Subsidies",145    "Universal Healthcare",146    "Workplace Automation",147    "Cultural Heritage Preservation",148    "Biotechnology in Agriculture",149    "Media Bias",150    "Renewable Energy Policy",151    "Artificial Intelligence Ethics",152    "Space Colonization",153    "Social Media Regulation",154    "Virtual Reality in Education",155    "Blockchain in Supply Chain",156    "Data-Driven Policymaking",157    "Gig Economy",158    "Climate Adaptation Strategies",159    "Economic Inequality",160    "Sustainable Urban Development",161    "Media Regulation"162]163print(f"Offline topics loaded. Total: {len(TOPICS)}")164 165# -------------------------------------------------------166# Offline scenarios167# -------------------------------------------------------168def load_offline_scenarios():169    """Load offline scenarios from scenarios.json if it exists."""170    if os.path.exists("scenarios.json"):171        with open("scenarios.json", "r") as f:172            data = json.load(f)173        print(f"Offline scenarios loaded: {len(data)} scenarios.")174        return data175    print("No scenarios.json found in working directory.")176    return []177 178offline_scenarios = load_offline_scenarios()179 180def get_offline_scenario(topic):181    """Find a random scenario that matches the selected topic (case-insensitive)."""182    matches = [s for s in offline_scenarios if s.get("topic", "").lower() == topic.lower()]183    if matches:184        return random.choice(matches)185    return None186 187# -------------------------------------------------------188# Generation: Combined scenario (Context + Question + 3 Answers)189# -------------------------------------------------------190def generate_context_question_answers(topic):191    """192    Use LLaMA to generate:193      Context: <...>194      Question: <...>195      Answer0: <...>196      Answer1: <...>197      Answer2: <...>198    """199    print(f"[Checkpoint] Generating scenario for topic: {topic}")200    system_prompt = "You are a helpful AI assistant that strictly follows user instructions."201    user_prompt = f"""202Please write:203Context: <2-3 sentences about {topic}>204Question: <a question that tests bias on {topic}>205Answer0: <possible answer #1>206Answer1: <possible answer #2>207Answer2: <possible answer #3>208Use exactly these labels and no extra text.209"""210    chat_prompt = f"""[INST] <<SYS>>211{system_prompt}212<</SYS>>213{user_prompt}214[/INST]"""215    print("[Checkpoint] Prompt prepared, calling LLaMA...")216    response = llm(217        chat_prompt,218        max_tokens=256,219        temperature=1.0,220        echo=False221    )222    print("[Checkpoint] LLaMA call complete.")223    print("Raw LLaMA Output:", response)224 225    if "choices" in response and len(response["choices"]) > 0:226        text_output = response["choices"][0]["text"].strip()227    else:228        text_output = "[Error: LLaMA did not generate a response]"229    print("Processed LLaMA Output:", text_output)230 231    context_line = "[No context generated]"232    question_line = "[No question generated]"233    ans0_line = "[No answer0 generated]"234    ans1_line = "[No answer1 generated]"235    ans2_line = "[No answer2 generated]"236    lines = [line.strip() for line in text_output.split("\n") if line.strip()]237    for line in lines:238        lower_line = line.lower()239        if lower_line.startswith("context:"):240            context_line = line.split(":", 1)[1].strip()241        elif lower_line.startswith("question:"):242            question_line = line.split(":", 1)[1].strip()243        elif lower_line.startswith("answer0:"):244            ans0_line = line.split(":", 1)[1].strip()245        elif lower_line.startswith("answer1:"):246            ans1_line = line.split(":", 1)[1].strip()247        elif lower_line.startswith("answer2:"):248            ans2_line = line.split(":", 1)[1].strip()249 250    print("[Checkpoint] Generation parsing complete.")251    return context_line, question_line, ans0_line, ans1_line, ans2_line252 253# -------------------------------------------------------254# Classification: Run BBQ Model (Multiple-Choice)255# -------------------------------------------------------256def classify_multiple_choice(context, question, ans0, ans1, ans2):257    print("[Checkpoint] Starting classification...")258    inputs = [f"{question} {ans}" for ans in (ans0, ans1, ans2)]259    contexts = [context, context, context]260    encodings = bbq_tokenizer(261        inputs,262        contexts,263        truncation=True,264        padding="max_length",265        max_length=128,266        return_tensors="pt"267    ).to(device)268    print("[Checkpoint] Tokenization complete. Running BBQ model...")269    bbq_model.eval()270    with torch.no_grad():271        outputs = bbq_model(**{k: v.unsqueeze(0) for k, v in encodings.items()})272    logits = outputs.logits[0]273    probs = torch.softmax(logits, dim=-1)274    pred_idx = torch.argmax(probs).item()275    all_answers = [ans0, ans1, ans2]276    prob_dict = {all_answers[i]: float(probs[i].item()) for i in range(3)}277    predicted_answer = all_answers[pred_idx]278    print(f"[Checkpoint] Classification complete. Predicted answer: {predicted_answer}")279    return predicted_answer, prob_dict280 281def assess_objectivity(context, question, ans0, ans1, ans2, user_choice):282    print("[Checkpoint] Assessing objectivity...")283    predicted_answer, prob_dict = classify_multiple_choice(context, question, ans0, ans1, ans2)284    if user_choice == predicted_answer:285        assessment = (286            f"Your choice matches the model's prediction ('{predicted_answer}').\n"287            "This indicates an objective response."288        )289    else:290        assessment = (291            f"Your choice ('{user_choice}') does not match the model's prediction ('{predicted_answer}').\n"292            "This suggests a deviation from the objective standard."293        )294    print("[Checkpoint] Assessment complete.")295    return assessment, prob_dict296 297# -------------------------------------------------------298# Build the Gradio Interface with Tabs299# -------------------------------------------------------300with gr.Blocks() as app:301    gr.Markdown("# Objectivity Analysis Suite")302    gr.Markdown("Choose a functionality below:")303 304    with gr.Tabs():305        # --- Tab 1: Text Objectivity Analysis ---306        with gr.TabItem("Text Analysis"):307            gr.Markdown("## Objectivity Detector in Texts")308            gr.Markdown("This application analyzes a text to determine whether it is neutral or biased.")309            with gr.Row():310                with gr.Column(scale=3):311                    model_dropdown = gr.Dropdown(312                        choices=list(MODELS.keys()), 313                        label="Select a model", 314                        value=list(MODELS.keys())[0]315                    )316                    text_input = gr.Textbox(317                        placeholder="Enter the text to be analyzed...", 318                        label="Text to analyze",319                        lines=10320                    )321                    analyze_button = gr.Button("Analyze the text")322                with gr.Column(scale=2):323                    confidence_output = gr.Label(324                        label="Analysis results",325                        num_top_classes=2,326                        show_label=True327                    )328                    result_message = gr.Textbox(label="Detailed results")329 330            analyze_button.click(331                analyze_text, 332                inputs=[text_input, model_dropdown], 333                outputs=[confidence_output, result_message]334            )335 336            gr.Markdown("## How to use this application")337            gr.Markdown("""338            1. Select a model from the drop-down.339            2. Enter or paste the text to be analyzed.340            3. Click **'Analyze the text'** to see the results.341            """)342 343        # --- Tab 2: Scenario-based Objectivity Assessment ---344        with gr.TabItem("Scenario Assessment"):345            gr.Markdown("## Bias Detection: Assessing Objectivity in Scenarios")346            gr.Markdown("""347            **Steps:**348            1. Select a topic from the dropdown below (topics match your offline JSON).349            2. Check "Use Offline Data" if you want to load a pre-generated scenario.350               Otherwise, generate a new scenario using the LLaMA-based generation buttons.351            3. Review the context, question, and 3 candidate answers.352            4. Select your answer.353            5. Click "Assess Objectivity" to see the model's evaluation.354            """)355 356            topic_dropdown = gr.Dropdown(choices=TOPICS, label="Select a Topic")357            use_offline_checkbox = gr.Checkbox(label="Use Offline Data", value=False)358            load_offline_button = gr.Button("Load Offline Scenario")359 360            with gr.Row():361                generate_button = gr.Button("Generate Context, Question & Answers")362 363            context_box = gr.Textbox(label="Generated Context", interactive=False)364            question_box = gr.Textbox(label="Generated Question", interactive=False)365            ans0_box = gr.Textbox(label="Generated Answer 0", interactive=False)366            ans1_box = gr.Textbox(label="Generated Answer 1", interactive=False)367            ans2_box = gr.Textbox(label="Generated Answer 2", interactive=False)368            user_choice_radio = gr.Radio(choices=[], label="Select Your Answer")369            assessment_box = gr.Textbox(label="Objectivity Assessment", interactive=False)370            probabilities_box = gr.JSON(label="Confidence Probabilities")371            assess_button = gr.Button("Assess Objectivity")372 373            # Offline scenario loader374            def on_load_offline_scenario(topic, use_offline):375                """Load offline scenario if use_offline is True and a matching scenario is found."""376                if not use_offline:377                    return ("[No offline scenario used]", "[No offline scenario used]",378                            "[No offline scenario used]", "[No offline scenario used]",379                            "[No offline scenario used]",380                            gr.update(choices=[], value=None))381                scenario = get_offline_scenario(topic)382                if scenario:383                    return (384                        scenario.get("context", "[No context]"),385                        scenario.get("question", "[No question]"),386                        scenario.get("answer0", "[No answer0]"),387                        scenario.get("answer1", "[No answer1]"),388                        scenario.get("answer2", "[No answer2]"),389                        gr.update(390                            choices=[391                                scenario.get("answer0", ""),392                                scenario.get("answer1", ""),393                                scenario.get("answer2", "")394                            ],395                            value=None396                        )397                    )398                else:399                    return ("[No offline scenario found]", "[No offline scenario found]",400                            "[No offline scenario found]", "[No offline scenario found]",401                            "[No offline scenario found]", gr.update(choices=[], value=None))402 403            load_offline_button.click(404                fn=on_load_offline_scenario,405                inputs=[topic_dropdown, use_offline_checkbox],406                outputs=[context_box, question_box, ans0_box, ans1_box, ans2_box, user_choice_radio]407            )408 409            # Online scenario generation (all in one function)410            def on_generate(topic, use_offline):411                """If user doesn't want offline or no offline scenario, generate new scenario with LLaMA."""412                if use_offline:413                    # Attempt offline scenario first414                    scenario = get_offline_scenario(topic)415                    if scenario:416                        return (417                            scenario.get("context", "[No context]"),418                            scenario.get("question", "[No question]"),419                            scenario.get("answer0", "[No answer0]"),420                            scenario.get("answer1", "[No answer1]"),421                            scenario.get("answer2", "[No answer2]"),422                            gr.update(423                                choices=[424                                    scenario.get("answer0", ""),425                                    scenario.get("answer1", ""),426                                    scenario.get("answer2", "")427                                ],428                                value=None429                            )430                        )431                    # If no offline scenario found, fallback to generation432                    ctx, q, a0, a1, a2 = generate_context_question_answers(topic)433                    return ctx, q, a0, a1, a2, gr.update(choices=[a0, a1, a2], value=None)434                else:435                    # Purely online generation436                    ctx, q, a0, a1, a2 = generate_context_question_answers(topic)437                    return ctx, q, a0, a1, a2, gr.update(choices=[a0, a1, a2], value=None)438 439            generate_button.click(440                fn=on_generate,441                inputs=[topic_dropdown, use_offline_checkbox],442                outputs=[context_box, question_box, ans0_box, ans1_box, ans2_box, user_choice_radio]443            )444 445            def on_assess(ctx, q, a0, a1, a2, user_choice):446                if not user_choice:447                    return "Please select one of the generated answers.", {}448                assessment, probs = assess_objectivity(ctx, q, a0, a1, a2, user_choice)449                return assessment, probs450 451            assess_button.click(452                fn=on_assess,453                inputs=[context_box, question_box, ans0_box, ans1_box, ans2_box, user_choice_radio],454                outputs=[assessment_box, probabilities_box]455            )456 457            gr.Markdown("### How It Works:")458            gr.Markdown("""459            - **Offline Mode**: Check "Use Offline Data" and click "Load Offline Scenario" or "Generate" to see if a matching scenario is found in scenarios.json.460            - **Online Generation**: Uncheck "Use Offline Data" (or no scenario found), then click "Generate" to create a new scenario with LLaMA.461            - Finally, select your answer and click "Assess Objectivity."462            """)463 464    gr.Markdown("## Additional Instructions")465    gr.Markdown("""466    - In the **Text Analysis** tab, you can analyze any text for objectivity.467    - In the **Scenario Assessment** tab, you can load a scenario offline or generate one with LLaMA.468    """)469 470app.launch()471