multimodalart HF Staff commited on
Commit
3ec4c8b
ยท
verified ยท
1 Parent(s): 8e6b5bc

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. README.md +23 -6
  2. app.py +190 -0
  3. requirements.txt +3 -0
README.md CHANGED
@@ -1,13 +1,30 @@
1
  ---
2
- title: Korean Toxicity Deobfuscation Kotox
3
- emoji: ๐Ÿ†
4
- colorFrom: red
5
  colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 6.22.0
8
- python_version: '3.12'
9
  app_file: app.py
10
- pinned: false
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Korean Toxicity Deobfuscation KOTOX
3
+ emoji: ๐Ÿงผ
4
+ colorFrom: purple
5
  colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 6.22.0
 
8
  app_file: app.py
9
+ short_description: Deobfuscate and detoxify Korean text with KOTOX
10
+ python_version: "3.12"
11
+ startup_duration_timeout: 1h
12
  ---
13
 
14
+ # Korean Toxicity Deobfuscation (KOTOX)
15
+
16
+ This Space demonstrates the KOTOX model โ€” a fine-tuned Llama-3-Korean-Bllossom-8B (LoRA adapter)
17
+ for Korean text deobfuscation and sanitization, from the paper
18
+ [Obfuscation Rules for Detecting and Detoxifying Korean Toxicity](https://arxiv.org/abs/2510.10961).
19
+
20
+ ## Two modes
21
+
22
+ - **Deobfuscation** โ€” restores obfuscated *neutral* text to clean, standard Korean.
23
+ - **Sanitization** โ€” rewrites obfuscated *toxic* text into deobfuscated, non-toxic Korean
24
+ while preserving the intended meaning.
25
+
26
+ ## Model
27
+
28
+ - Base: [MLP-KTLim/llama-3-Korean-Bllossom-8B](https://huggingface.co/MLP-KTLim/llama-3-Korean-Bllossom-8B)
29
+ - LoRA adapter: [ssgyejin/llama-3-Korean-Bllossom-8B-deobfuscation-KOTOX](https://huggingface.co/ssgyejin/llama-3-Korean-Bllossom-8B-deobfuscation-KOTOX)
30
+ - Dataset: [ssgyejin/KOTOX](https://huggingface.co/datasets/ssgyejin/KOTOX)
app.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces # MUST come before any CUDA-touching import
2
+ import torch
3
+ import gradio as gr
4
+ from transformers import AutoModelForCausalLM, AutoTokenizer
5
+ from peft import PeftModel
6
+ from string import Template
7
+
8
+ BASE_MODEL = "MLP-KTLim/llama-3-Korean-Bllossom-8B"
9
+ ADAPTER = "ssgyejin/llama-3-Korean-Bllossom-8B-deobfuscation-KOTOX"
10
+
11
+ # Prompts from the paper's official code (evaluation/PROMPTS.py)
12
+ DEOBFUSCATION_PROMPT = Template("""You are an expert in Korean language correction.
13
+ The sentence I provide may be non-standard, use internet slang, phonetic spelling, intentional misspellings, or be obfuscated in other ways.
14
+ Your task is to translate and normalize the sentence into natural, standard Korean.
15
+
16
+ Rules:
17
+ 1. Preserve the original meaning.
18
+ 2. If the tone is conversational, keep it conversational but in standard Korean.
19
+ 3. Remove unnecessary emoticons or special characters.
20
+ 4. Make the sentence grammatically smooth and natural.
21
+
22
+ Translate:
23
+ Input sentence: $input
24
+ Output sentence: """)
25
+
26
+ SANITIZATION_PROMPT = Template("""You are an expert in Korean language correction and detoxification.
27
+ The sentence I provide may be non-standard, use internet slang, phonetic spelling, intentional misspellings, be obfuscated, or even contain toxic/abusive expressions.
28
+ Your task is to translate and normalize the sentence into natural, standard Korean, while also detoxifying it to make it polite, safe, and non-toxic.
29
+
30
+ Rules:
31
+ 1. Preserve the intended meaning as much as possible, but remove or soften toxic, offensive, or abusive language.
32
+ 2. If the tone is conversational, keep it conversational but in standard Korean.
33
+ 3. Remove unnecessary emoticons or special characters.
34
+ 4. Make the sentence grammatically smooth and natural.
35
+ 5. Ensure the output is non-toxic, respectful, and safe.
36
+
37
+ Translate:
38
+ Input sentence: $input
39
+ Output sentence: """)
40
+
41
+ # Load tokenizer from the adapter repo (includes chat template)
42
+ tokenizer = AutoTokenizer.from_pretrained(ADAPTER, trust_remote_code=True)
43
+ tokenizer.padding_side = "left"
44
+
45
+ # Load base model and apply LoRA adapter at module scope
46
+ base_model = AutoModelForCausalLM.from_pretrained(
47
+ BASE_MODEL,
48
+ torch_dtype=torch.bfloat16,
49
+ trust_remote_code=True,
50
+ )
51
+ model = PeftModel.from_pretrained(base_model, ADAPTER)
52
+ model = model.merge_and_unload()
53
+ model.eval()
54
+ model.to("cuda")
55
+
56
+
57
+ @spaces.GPU(duration=120)
58
+ def process(
59
+ text: str,
60
+ task: str = "Deobfuscation",
61
+ max_new_tokens: int = 256,
62
+ temperature: float = 0.0,
63
+ top_p: float = 1.0,
64
+ ) -> str:
65
+ """Process Korean text by deobfuscating or sanitizing it.
66
+
67
+ Args:
68
+ text: The obfuscated Korean text to process.
69
+ task: Either "Deobfuscation" (restore obfuscated neutral text to standard Korean)
70
+ or "Sanitization" (rewrite obfuscated toxic text into clean, non-toxic Korean).
71
+ max_new_tokens: Maximum number of new tokens to generate.
72
+ temperature: Sampling temperature (0 = greedy decoding).
73
+ top_p: Nucleus sampling probability (1.0 = full range).
74
+
75
+ Returns:
76
+ The processed Korean text.
77
+ """
78
+ if not text.strip():
79
+ return "Please enter some text to process."
80
+
81
+ if task == "Sanitization":
82
+ prompt = SANITIZATION_PROMPT.substitute(input=text)
83
+ else:
84
+ prompt = DEOBFUSCATION_PROMPT.substitute(input=text)
85
+
86
+ messages = [{"role": "user", "content": prompt}]
87
+ input_text = tokenizer.apply_chat_template(
88
+ messages, add_generation_prompt=True, tokenize=False
89
+ )
90
+ inputs = tokenizer(input_text, add_special_tokens=False, return_tensors="pt").to("cuda")
91
+
92
+ do_sample = temperature > 0.0
93
+ gen_kwargs = {
94
+ "max_new_tokens": max_new_tokens,
95
+ "do_sample": do_sample,
96
+ "pad_token_id": tokenizer.pad_token_id,
97
+ "eos_token_id": tokenizer.eos_token_id,
98
+ }
99
+ if do_sample:
100
+ gen_kwargs["temperature"] = temperature
101
+ gen_kwargs["top_p"] = top_p
102
+
103
+ with torch.no_grad():
104
+ output_ids = model.generate(**inputs, **gen_kwargs)
105
+
106
+ answer_length = len(output_ids[0]) - len(inputs["input_ids"][0])
107
+ result = tokenizer.decode(output_ids[0][-answer_length:], skip_special_tokens=True)
108
+ return result.strip()
109
+
110
+
111
+ CSS = """
112
+ #col-container { max-width: 900px; margin: 0 auto; }
113
+ .dark .gradio-container { color: var(--body-text-color); }
114
+ """
115
+
116
+ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
117
+ with gr.Column(elem_id="col-container"):
118
+ gr.Markdown(
119
+ """
120
+ # Korean Toxicity Deobfuscation (KOTOX)
121
+ Restore obfuscated Korean text to standard Korean using a fine-tuned
122
+ Llama-3-Korean-Bllossom-8B model with LoRA.
123
+
124
+ **Two modes:**
125
+ - **Deobfuscation** โ€” restores obfuscated *neutral* text to clean, standard Korean.
126
+ - **Sanitization** โ€” rewrites obfuscated *toxic* text into deobfuscated, non-toxic Korean.
127
+
128
+ Paper: [Obfuscation Rules for Detecting and Detoxifying Korean Toxicity](https://arxiv.org/abs/2510.10961)
129
+ """
130
+ )
131
+
132
+ with gr.Row():
133
+ text_input = gr.Textbox(
134
+ label="Input text (obfuscated Korean)",
135
+ placeholder="์—ฌ๊ธฐ์— ๋‚œ๋…ํ™”๋œ ํ•œ๊ตญ์–ด ๋ฌธ์žฅ์„ ์ž…๋ ฅํ•˜์„ธ์š”",
136
+ lines=5,
137
+ scale=4,
138
+ )
139
+
140
+ with gr.Row():
141
+ task_radio = gr.Radio(
142
+ choices=["Deobfuscation", "Sanitization"],
143
+ value="Deobfuscation",
144
+ label="Task",
145
+ )
146
+ run_btn = gr.Button("Process", variant="primary")
147
+
148
+ output_text = gr.Textbox(
149
+ label="Output (clean Korean)",
150
+ lines=5,
151
+ interactive=False,
152
+ )
153
+
154
+ with gr.Accordion("Advanced settings", open=False):
155
+ max_tokens = gr.Slider(
156
+ minimum=64, maximum=512, value=256, step=32,
157
+ label="Max new tokens",
158
+ )
159
+ temp_slider = gr.Slider(
160
+ minimum=0.0, maximum=2.0, value=0.0, step=0.1,
161
+ label="Temperature (0 = greedy)",
162
+ )
163
+ top_p_slider = gr.Slider(
164
+ minimum=0.1, maximum=1.0, value=1.0, step=0.05,
165
+ label="Top-p",
166
+ )
167
+
168
+ run_btn.click(
169
+ fn=process,
170
+ inputs=[text_input, task_radio, max_tokens, temp_slider, top_p_slider],
171
+ outputs=output_text,
172
+ api_name="process",
173
+ )
174
+
175
+ gr.Examples(
176
+ examples=[
177
+ ["๋จ–์•ผ, ๊ทธ๋ž˜์„œ ๋ƒ๋Šฐ ์ˆ˜๋Šฅ๋๋‚˜๋ฉด ใ‰ณ๋กœ ๋‹ค๋…€๋ณด๋ ค๊ณ .", "Deobfuscation"],
178
+ ["๋‚ด ๋งไบŒ ๋‚˜๋Š” ๋‚ด ๋ฐ”๋””ๅฎถ ์„ธ์ƒ ํ—ฌ์”จํ•œ ์ค„ ์•Œ์•˜์ง€", "Deobfuscation"],
179
+ ["์šฐ๋ฆฌ ๋‹ค ๊ฐ™์ด ์ž์ „๊ฑฐ ๋จธ์žฅ์ •์„ ๋”ฐ๋‚˜ ๋ณผ?๊นŒ", "Deobfuscation"],
180
+ ["์•ผ ์”น๋•๋“คใ‰ต, ์šฐ๋ฆฌ ๋‹ค ๊ฐ™์ด ์ž๊ฑฐ์ „๋กœ ๅผ“ํ† ์ข…์ฃผใ‰ฏ ํ•ด๊นŒ๋ณผ?", "Sanitization"],
181
+ ["๋ฏธ์ฟก ๊ฐœ๋ผ์ง€๋“ค์€ ๋š€ ๋†˜๋†จ๋คผ๋ƒ ๋ณด๋„ค ใ…‰ใ…‰", "Sanitization"],
182
+ ],
183
+ inputs=[text_input, task_radio],
184
+ outputs=output_text,
185
+ fn=process,
186
+ cache_examples=True,
187
+ cache_mode="lazy",
188
+ )
189
+
190
+ demo.launch(mcp_server=True)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ peft
2
+ accelerate
3
+ sentencepiece