vietnamese_hate_speech_detection / utils /convert_vihsd_gemini.py
jesse-tong's picture
Update datasets
30ae36c
Raw
History Blame
6.64 kB
import os
import glob
import pandas as pd
import argparse
from google import genai
from tqdm import tqdm
import time
import re
from word_segmentation_vi import word_segmentation_vi
def setup_genai(api_key):
"""Configure the Google Generative AI client with your API key"""
return genai.Client(api_key=api_key)
def classify_text(model, text):
"""Classify Vietnamese text into hate speech categories using Google's Generative AI"""
prompt = f"""
Analyze the following Vietnamese text for hate speech (each sentence is separated by a newline):
"{text}"
Rate it on these categories (0=NORMAL, 1=CLEAN, 2=OFFENSIVE, 3=HATE):
- individual (targeting specific individuals)
- groups (targeting groups or organizations)
- religion/creed (targeting religious groups or beliefs)
- race/ethnicity (racial/ethnic hate speech)
- politics (political hate speech)
If the text doesn't specify a person or group in a category, return 0 for that category.
Else, return 1 for CLEAN, 2 for OFFENSIVE, or 3 for HATE.
For each sentence in the text, return only 5 numbers separated by commas (corresponding to the label of individual, groups, religion/creed, race/ethnicity, politics) and numbers for each sentence seperated by newlines, like (with no other text):
0,1,0,0,0
1,0,0,0,2
"""
try:
response = model.models.generate_content(model="gemini-2.0-flash", contents=prompt)
values = response.text.strip().split('\n')
values = [line.split(',') for line in values]
return values
except Exception as e:
print(f"Error classifying text: {e}")
return None
def process_file(input_file, output_file, model, rate_limit_pause=4):
"""Process a single CSV file to match the test.csv format"""
print(f"Processing {input_file}...")
# Read the input file
try:
df = pd.read_csv(input_file)
except Exception as e:
print(f"Error reading {input_file}: {e}")
return
# Rename column free_text to content
if 'free_text' in df.columns:
df.rename(columns={'free_text': 'content'}, inplace=True)
elif 'content' not in df.columns:
print(f"Error: 'content' column not found in {input_file}")
return
# Ensure all required columns exist
category_columns = ['individual', 'groups', 'religion/creed', 'race/ethnicity', 'politics']
for col in category_columns:
if col not in df.columns:
# Change column type to int if it doesn't exist
df[col] = 0
# Process each batch (100 rows at a time)
batch_size = 100
for start in tqdm(range(0, len(df), batch_size), desc="Processing batches"):
end = min(start + batch_size, len(df))
batch_df = df.iloc[start:end]
# Skip if all categories already have values
if all(batch_df[cat].all() != 0 for cat in category_columns):
continue
# Join 50 rows by newlines, and classify all at once
text_to_classify = "\n".join([str(sentence) for sentence in batch_df['content'].tolist()])
classifications = classify_text(model, text_to_classify)
# Try 2 more times, else skip
if classifications is None:
for _ in range(2):
classifications = classify_text(model, text_to_classify)
if classifications is not None:
break
time.sleep(rate_limit_pause)
else:
print(f"Error classifying batch starting at index {start}. Skipping...")
continue
try:
# Update the DataFrame with the classifications
for i, row in enumerate(classifications):
for j, col in enumerate(category_columns):
df.at[start + i, col] = int(row[j])
except Exception as e:
for _ in range(2):
classifications = classify_text(model, text_to_classify)
if classifications is not None:
break
time.sleep(rate_limit_pause)
else:
print(f"Error classifying batch starting at index {start}. Skipping...")
continue
try:
for i, row in enumerate(classifications):
for j, col in enumerate(category_columns):
df.at[start + i, col] = int(row[j])
except Exception as e:
print(f"Error updating DataFrame: {e}")
continue
time.sleep(rate_limit_pause)
# Apply word segmentation to the content column
df['content'] = df['content'].apply(lambda x: word_segmentation_vi(str(x)))
# Save processed file, export columns of category_columns is int
for col in category_columns:
df[col] = df[col].astype(int)
# Drop label_id column if it exists
if 'label_id' in df.columns:
df.drop(columns=['label_id'], inplace=True)
df.to_csv(output_file, index=False)
print(f"Saved processed file to {output_file}")
def main():
parser = argparse.ArgumentParser(description="Process ViHSD CSV files with Google Generative AI")
parser.add_argument("--input_dir", required=True, help="Directory containing input CSV files")
parser.add_argument("--output_dir", required=True, help="Directory to save processed files")
parser.add_argument("--api_key", required=True, help="Google Generative AI API key")
parser.add_argument("--pause", type=float, default=4.0, help="Pause between API calls (seconds)")
args = parser.parse_args()
# Ensure output directory exists
os.makedirs(args.output_dir, exist_ok=True)
# Setup Google Generative AI
model = setup_genai(args.api_key)
# Get all CSV files in the input directory
csv_files = glob.glob(os.path.join(args.input_dir, "*.csv"))
if not csv_files:
print(f"No CSV files found in {args.input_dir}")
return
print(f"Found {len(csv_files)} CSV files to process")
# Process each file
for input_file in csv_files:
output_file = os.path.join(args.output_dir, os.path.basename(input_file))
if os.path.exists(output_file):
print(f"Output file {output_file} already exists. Skipping...")
continue
process_file(input_file, output_file, model, args.pause)
if __name__ == "__main__":
# This script is used to process ViHSD CSV files with Google Generative AI
# First, git clone from https://huggingface.co/datasets/sonlam1102/vihsd
main()