Андрей commited on
Commit
9738dda
·
verified ·
1 Parent(s): b77a344

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +5 -3
  2. index.html +341 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Censor Text
3
- emoji: 🏢
4
  colorFrom: green
5
  colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: censor-text
3
+ emoji: 🐳
4
  colorFrom: green
5
  colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,341 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Text Censorship App</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .file-input-label {
11
+ display: inline-block;
12
+ padding: 0.5rem 1rem;
13
+ border-radius: 0.375rem;
14
+ background-color: #3b82f6;
15
+ color: white;
16
+ cursor: pointer;
17
+ transition: background-color 0.2s;
18
+ }
19
+ .file-input-label:hover {
20
+ background-color: #2563eb;
21
+ }
22
+ #fileInput {
23
+ display: none;
24
+ }
25
+ .textarea-container {
26
+ position: relative;
27
+ }
28
+ .word-count {
29
+ position: absolute;
30
+ bottom: 0.5rem;
31
+ right: 0.5rem;
32
+ background-color: rgba(255, 255, 255, 0.8);
33
+ padding: 0.2rem 0.5rem;
34
+ border-radius: 0.25rem;
35
+ font-size: 0.75rem;
36
+ color: #6b7280;
37
+ }
38
+ .censored {
39
+ background-color: #fecaca;
40
+ color: transparent;
41
+ text-shadow: 0 0 8px #ef4444;
42
+ border-radius: 0.25rem;
43
+ }
44
+ </style>
45
+ </head>
46
+ <body class="bg-gray-100 min-h-screen">
47
+ <div class="container mx-auto px-4 py-8 max-w-4xl">
48
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden">
49
+ <!-- Header -->
50
+ <div class="bg-blue-600 px-6 py-4">
51
+ <div class="flex items-center justify-between">
52
+ <h1 class="text-2xl font-bold text-white">
53
+ <i class="fas fa-shield-alt mr-2"></i> Text Censorship Tool
54
+ </h1>
55
+ <div class="flex items-center space-x-2">
56
+ <span id="statusBadge" class="px-3 py-1 rounded-full text-xs font-semibold bg-blue-500 text-white">
57
+ <i class="fas fa-circle-notch fa-spin mr-1"></i> Loading word list
58
+ </span>
59
+ </div>
60
+ </div>
61
+ </div>
62
+
63
+ <!-- Main Content -->
64
+ <div class="p-6">
65
+ <!-- File Input Section -->
66
+ <div class="mb-6 bg-blue-50 p-4 rounded-lg">
67
+ <h2 class="text-lg font-semibold text-blue-800 mb-3">
68
+ <i class="fas fa-file-import mr-2"></i> Bad Words Dictionary
69
+ </h2>
70
+ <div class="flex flex-col sm:flex-row items-start sm:items-center gap-4">
71
+ <div>
72
+ <label for="fileInput" class="file-input-label">
73
+ <i class="fas fa-upload mr-2"></i> Choose Word List File
74
+ </label>
75
+ <input type="file" id="fileInput" accept=".txt">
76
+ </div>
77
+ <div class="text-sm text-gray-600">
78
+ <p>Or use our <button id="defaultWordsBtn" class="text-blue-600 hover:underline">default word list</button></p>
79
+ </div>
80
+ </div>
81
+ <div id="fileInfo" class="mt-3 text-sm text-gray-600 hidden">
82
+ <i class="fas fa-file-alt mr-1"></i> <span id="fileName">No file selected</span>
83
+ <span id="wordCount" class="ml-3"></span>
84
+ </div>
85
+ </div>
86
+
87
+ <!-- Text Input Section -->
88
+ <div class="mb-6">
89
+ <label for="inputText" class="block text-sm font-medium text-gray-700 mb-2">
90
+ <i class="fas fa-pencil-alt mr-2"></i> Enter your text:
91
+ </label>
92
+ <div class="textarea-container">
93
+ <textarea id="inputText" rows="8" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500" placeholder="Type or paste your text here..."></textarea>
94
+ <div class="word-count">
95
+ <span id="inputWordCount">0</span> words
96
+ </div>
97
+ </div>
98
+ </div>
99
+
100
+ <!-- Options Section -->
101
+ <div class="mb-6 bg-gray-50 p-4 rounded-lg">
102
+ <h2 class="text-lg font-semibold text-gray-800 mb-3">
103
+ <i class="fas fa-cog mr-2"></i> Censorship Options
104
+ </h2>
105
+ <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
106
+ <div>
107
+ <label class="inline-flex items-center">
108
+ <input type="checkbox" id="matchCase" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
109
+ <span class="ml-2 text-sm text-gray-700">Match case</span>
110
+ </label>
111
+ </div>
112
+ <div>
113
+ <label class="inline-flex items-center">
114
+ <input type="checkbox" id="matchPartial" checked class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
115
+ <span class="ml-2 text-sm text-gray-700">Match partial words</span>
116
+ </label>
117
+ </div>
118
+ <div>
119
+ <label class="inline-flex items-center">
120
+ <input type="checkbox" id="highlightWords" checked class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
121
+ <span class="ml-2 text-sm text-gray-700">Highlight censored words</span>
122
+ </label>
123
+ </div>
124
+ <div>
125
+ <label class="inline-flex items-center">
126
+ <input type="checkbox" id="replaceWithStars" checked class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
127
+ <span class="ml-2 text-sm text-gray-700">Replace with asterisks</span>
128
+ </label>
129
+ </div>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Action Button -->
134
+ <div class="flex justify-center mb-6">
135
+ <button id="censorBtn" class="px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
136
+ <i class="fas fa-filter mr-2"></i> Censor Text
137
+ </button>
138
+ </div>
139
+
140
+ <!-- Output Section -->
141
+ <div>
142
+ <label for="outputText" class="block text-sm font-medium text-gray-700 mb-2">
143
+ <i class="fas fa-shield-virus mr-2"></i> Censored text:
144
+ </label>
145
+ <div class="textarea-container">
146
+ <textarea id="outputText" rows="8" readonly class="w-full px-3 py-2 border border-gray-300 rounded-lg bg-gray-50" placeholder="Your censored text will appear here..."></textarea>
147
+ <div class="word-count">
148
+ <span id="outputWordCount">0</span> words | <span id="censoredCount">0</span> censored
149
+ </div>
150
+ </div>
151
+ </div>
152
+ </div>
153
+
154
+ <!-- Footer -->
155
+ <div class="bg-gray-100 px-6 py-3 text-center text-sm text-gray-600">
156
+ <p><i class="fas fa-info-circle mr-1"></i> This tool helps maintain respectful communication by filtering inappropriate language.</p>
157
+ </div>
158
+ </div>
159
+ </div>
160
+
161
+ <script>
162
+ // Default word list (Russian swear words)
163
+ const defaultWordList = [
164
+ "блядь", "бля", "блять", "блядина", "блядский", "блядство", "блядун", "блядюга",
165
+ "ебанутый", "ебать", "ебал", "ебало", "ебанько", "ебаный", "ебарь", "ебатория",
166
+ "ебашит", "ебись", "ебливый", "ебля", "ебнуть", "ебнутый", "ебун", "ебучий",
167
+ "говно", "говнюк", "говняный", "говнецо", "говнище", "говнарь",
168
+ "дерьмо", "дерьмовый", "дерьмище", "дерьмак",
169
+ "дрочить", "дрочила", "дрочун", "дрочка", "дроченый",
170
+ "залупа", "залупиться", "залупляться", "залупень", "залупский",
171
+ "мудак", "мудила", "мудозвон", "мудоеб", "мудацкий", "муде", "мудень",
172
+ "пизда", "пиздец", "пиздатый", "пиздеть", "пиздёж", "пиздища", "пиздобол",
173
+ "пиздолиз", "пиздорванный", "пиздюк", "пиздюлина", "пиздюли", "пиздюля",
174
+ "пиздятина", "пиздячий", "пиздят", "пиздящий",
175
+ "срать", "срака", "сраный", "срань", "срач", "срачка", "срачник",
176
+ "хуй", "хуев", "хуёвый", "хуёвина", "хуета", "хуила", "хуило", "хуище",
177
+ "хуйло", "хуйня", "хуйрик", "хуита", "хуище", "хуяк", "хуярить", "хуякнуть",
178
+ "шлюха", "шлюшка", "шлюшиный", "шлюшонок",
179
+ "выебон", "выебываться", "взъебанный", "взъебать", "взъебка",
180
+ "выебанный", "выебать", "выебениваться", "выебистика", "выебон",
181
+ "доебаться", "доебываться", "долбоеб", "долбоёб", "долбоёбище",
182
+ "заебал", "заебанец", "заебатый", "заебать", "заебенить", "заебись",
183
+ "изъебнуться", "изъебать", "изъебанный", "изъебениться",
184
+ "наебал", "наебалово", "наебать", "наебенить", "наебка", "наебнутый",
185
+ "недоебень", "недоебыш", "недоёб", "недоёбище",
186
+ "объебал", "объебать", "объебос", "объебанный", "объебать",
187
+ "отъебался", "отъебать", "отъебись", "отъебон", "отъебанный",
188
+ "переебанный", "переебать", "переёб", "переёбывать", "переёбочный",
189
+ "поебень", "поеботина", "поебуха", "поебывать", "подъеб", "подъебать",
190
+ "подъебка", "подъёбывать", "подъёбщик",
191
+ "приебать", "приебаться", "приёб", "приёбывать", "приёбочный",
192
+ "проебать", "проебал", "проебанный", "проёб", "проёбывать",
193
+ "разъебай", "разъебать", "разъебанный", "разъёб", "разъёбывать",
194
+ "съебать", "съебался", "съебанный", "съёбывать", "съёбочный",
195
+ "уебать", "уебал", "уебанец", "уебанка", "уебанский", "уебище",
196
+ "выебон", "выебываться", "взъебанный", "взъебать", "взъебка",
197
+ "выебанный", "выебать", "выебениваться", "выебистика", "выебон",
198
+ "доебаться", "доебываться", "долбоеб", "долбоёб", "долбоёбище",
199
+ "заебал", "заебанец", "заебатый", "заебать", "заебенить", "заебись",
200
+ "изъебнуться", "изъебать", "изъебанный", "изъебениться",
201
+ "наебал", "наебалово", "наебать", "наебенить", "наебка", "наебнутый",
202
+ "недоебень", "недоебыш", "недоёб", "недоёбище",
203
+ "объебал", "объебать", "объебос", "объебанный", "объебать",
204
+ "отъебался", "отъебать", "отъебись", "отъебон", "отъебанный",
205
+ "переебанный", "переебать", "переёб", "переёбывать", "переёбочный",
206
+ "поебень", "поеботина", "поебуха", "поебывать", "подъеб", "подъебать",
207
+ "подъебка", "подъёбывать", "подъёбщик",
208
+ "приебать", "приебаться", "приёб", "приёбывать", "приёбочный",
209
+ "проебать", "проебал", "проебанный", "проёб", "проёбывать",
210
+ "разъебай", "разъебать", "разъебанный", "разъёб", "разъёбывать",
211
+ "съебать", "съебался", "съебанный", "съёбывать", "съёбочный",
212
+ "уебать", "уебал", "уебанец", "уебанка", "уебанский", "уебище"
213
+ ];
214
+
215
+ // Initialize variables
216
+ let badWords = [];
217
+ let statusBadge = document.getElementById('statusBadge');
218
+ let fileInput = document.getElementById('fileInput');
219
+ let fileName = document.getElementById('fileName');
220
+ let wordCount = document.getElementById('wordCount');
221
+ let fileInfo = document.getElementById('fileInfo');
222
+ let inputText = document.getElementById('inputText');
223
+ let outputText = document.getElementById('outputText');
224
+ let inputWordCount = document.getElementById('inputWordCount');
225
+ let outputWordCount = document.getElementById('outputWordCount');
226
+ let censoredCount = document.getElementById('censoredCount');
227
+ let censorBtn = document.getElementById('censorBtn');
228
+ let defaultWordsBtn = document.getElementById('defaultWordsBtn');
229
+ let matchCase = document.getElementById('matchCase');
230
+ let matchPartial = document.getElementById('matchPartial');
231
+ let highlightWords = document.getElementById('highlightWords');
232
+ let replaceWithStars = document.getElementById('replaceWithStars');
233
+
234
+ // Load default word list initially
235
+ loadWordListFromArray(defaultWordList);
236
+ statusBadge.innerHTML = '<i class="fas fa-check-circle mr-1"></i> Default word list loaded';
237
+
238
+ // Event listeners
239
+ fileInput.addEventListener('change', handleFileSelect);
240
+ defaultWordsBtn.addEventListener('click', loadDefaultWords);
241
+ inputText.addEventListener('input', updateWordCount);
242
+ censorBtn.addEventListener('click', censorText);
243
+
244
+ // Functions
245
+ function handleFileSelect(event) {
246
+ const file = event.target.files[0];
247
+ if (!file) return;
248
+
249
+ fileName.textContent = file.name;
250
+ fileInfo.classList.remove('hidden');
251
+
252
+ const reader = new FileReader();
253
+ reader.onload = function(e) {
254
+ const content = e.target.result;
255
+ const words = content.split('\n')
256
+ .map(word => word.trim())
257
+ .filter(word => word.length > 0);
258
+
259
+ loadWordListFromArray(words);
260
+ statusBadge.innerHTML = `<i class="fas fa-check-circle mr-1"></i> ${words.length} words loaded`;
261
+ wordCount.textContent = `${words.length} words`;
262
+ };
263
+ reader.readAsText(file);
264
+ }
265
+
266
+ function loadDefaultWords() {
267
+ loadWordListFromArray(defaultWordList);
268
+ statusBadge.innerHTML = '<i class="fas fa-check-circle mr-1"></i> Default word list loaded';
269
+ wordCount.textContent = `${defaultWordList.length} words`;
270
+ fileInfo.classList.remove('hidden');
271
+ fileName.textContent = 'Default Russian word list';
272
+ fileInput.value = ''; // Clear file input
273
+ }
274
+
275
+ function loadWordListFromArray(words) {
276
+ badWords = words;
277
+ // Create regex patterns for all word forms
278
+ badWords = badWords.map(word => {
279
+ // Create pattern that matches all forms of the word (with different endings)
280
+ return word.replace(/[а-я]/g, (char) => {
281
+ return `[${char}${char.toUpperCase()}]`;
282
+ });
283
+ });
284
+ }
285
+
286
+ function updateWordCount() {
287
+ const text = inputText.value;
288
+ const count = text.trim() === '' ? 0 : text.split(/\s+/).length;
289
+ inputWordCount.textContent = count;
290
+ }
291
+
292
+ function censorText() {
293
+ const text = inputText.value;
294
+ if (!text.trim()) {
295
+ outputText.value = '';
296
+ outputWordCount.textContent = '0';
297
+ censoredCount.textContent = '0';
298
+ return;
299
+ }
300
+
301
+ let censoredText = text;
302
+ let censoredWords = 0;
303
+ const caseSensitive = matchCase.checked;
304
+ const partialMatch = matchPartial.checked;
305
+ const highlight = highlightWords.checked;
306
+ const useStars = replaceWithStars.checked;
307
+
308
+ // Create a single regex pattern for all bad words
309
+ const pattern = new RegExp(
310
+ badWords.map(word =>
311
+ partialMatch ? `(${word}[а-яa-z]*)` : `(\\b${word}\\b)`
312
+ ).join('|'),
313
+ caseSensitive ? 'g' : 'gi'
314
+ );
315
+
316
+ censoredText = censoredText.replace(pattern, (match) => {
317
+ censoredWords++;
318
+
319
+ if (useStars) {
320
+ const stars = '*'.repeat(match.length);
321
+ if (highlight) {
322
+ return `<span class="censored" title="Censored word">${stars}</span>`;
323
+ }
324
+ return stars;
325
+ } else {
326
+ if (highlight) {
327
+ return `<span class="censored" title="Censored word">${match}</span>`;
328
+ }
329
+ return match;
330
+ }
331
+ });
332
+
333
+ // Update output
334
+ outputText.innerHTML = censoredText;
335
+ const outputCount = censoredText.trim() === '' ? 0 : censoredText.split(/\s+/).length;
336
+ outputWordCount.textContent = outputCount;
337
+ censoredCount.textContent = censoredWords;
338
+ }
339
+ </script>
340
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=l0ngAF/censor-text" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
341
+ </html>