File size: 28,073 Bytes
7676e0a
 
 
 
7ffbba4
7676e0a
4ff8b83
 
f462bd2
 
 
 
 
 
7676e0a
 
7ffbba4
 
f462bd2
7676e0a
 
7ffbba4
 
7676e0a
 
 
 
 
 
 
 
7ffbba4
7676e0a
 
 
 
 
 
 
 
86f6efe
b213fb9
7ffbba4
4ff8b83
7ffbba4
7676e0a
 
 
 
 
 
 
 
 
 
 
e941c48
 
7676e0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e941c48
7676e0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7ffbba4
7676e0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7ffbba4
7676e0a
6df811c
7ffbba4
e3e69c0
 
 
6df811c
7ffbba4
 
7676e0a
f462bd2
 
 
 
 
 
7676e0a
f462bd2
 
7ffbba4
7676e0a
7ffbba4
7676e0a
 
 
 
7ffbba4
7676e0a
6df811c
f462bd2
 
 
7676e0a
5107ea7
f462bd2
e941c48
7ffbba4
 
 
 
e941c48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7ffbba4
e3e69c0
 
 
7ffbba4
 
4ff8b83
7ffbba4
f462bd2
e941c48
f462bd2
 
 
 
 
e941c48
 
f462bd2
 
7ffbba4
 
 
 
 
e941c48
 
f462bd2
 
e8d0176
 
f462bd2
e8d0176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e3e69c0
 
 
 
e8d0176
 
4ff8b83
e8d0176
f462bd2
 
 
 
 
e8d0176
 
 
f462bd2
e8d0176
f462bd2
e8d0176
 
 
 
 
f462bd2
 
e8d0176
f462bd2
e8d0176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e3e69c0
 
 
e8d0176
 
4ff8b83
f462bd2
 
 
 
e8d0176
 
 
 
f462bd2
e8d0176
f462bd2
e8d0176
 
 
 
 
f462bd2
 
ed5fd92
f462bd2
ed5fd92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a7b12ed
 
ed5fd92
 
 
 
 
 
 
 
 
 
 
 
 
 
4ff8b83
f462bd2
ed5fd92
e3e69c0
 
 
 
f462bd2
 
 
ed5fd92
f462bd2
ed5fd92
 
 
 
 
f462bd2
ed5fd92
 
 
 
 
f462bd2
 
a7b12ed
 
f462bd2
a7b12ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa274a5
 
f462bd2
fa274a5
a7b12ed
4ff8b83
f462bd2
a7b12ed
e3e69c0
 
 
 
f462bd2
 
 
a7b12ed
f462bd2
a7b12ed
 
 
 
 
f462bd2
a7b12ed
 
 
f462bd2
 
a7b12ed
7b19804
f462bd2
7b19804
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ff8b83
f462bd2
7b19804
 
 
 
 
f462bd2
 
 
7b19804
f462bd2
 
7b19804
 
 
 
 
 
 
 
f462bd2
 
6191d4c
b213fb9
f462bd2
b213fb9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ff8b83
f462bd2
b213fb9
 
 
 
 
f462bd2
 
 
b213fb9
f462bd2
 
b213fb9
 
 
 
 
f462bd2
 
b213fb9
f462bd2
b213fb9
 
 
 
 
 
 
 
 
 
4ff8b83
f462bd2
b213fb9
 
 
 
 
 
 
 
 
f462bd2
 
 
b213fb9
 
 
f462bd2
 
b213fb9
 
 
 
f462bd2
 
b213fb9
 
 
f462bd2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
import pandas as pd
import numpy as np

import random
import math

import fomula

##SER: Tỷ lệ lỗi đã thêm (mong muốn: < 15% - tối đa <= 30%)
SER_want = 0.15
SER_max = 0.3
k_sigmoid = fomula.get_k_sigmoid(x=SER_max - SER_want)
print("k_sigmoid", k_sigmoid)
def character_replacement(text, SER, error_rate=0.03):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất thay thế ký tự
    :SER: Tỷ lệ lỗi đã sửa / tổng lỗi
    :return: Gồm 1 câu sai chính tả

    Kết hợp phương pháp error_rate và augmentation_probability để tạo lỗi chính tả.

    Bàn phím QWERTY tiếng Việt:

    Tạo một từ điển (keyboard) chứa các ký tự và các ký tự gần đó trên bàn phím. Ví dụ, ký tự 'a' có thể được thay thế bằng 'â', 'ă', 'á',...
    Chuyển đổi văn bản thành danh sách ký tự:

    Sử dụng list(text) để chuyển chuỗi văn bản thành danh sách các ký tự riêng lẻ. Điều này giúp dễ dàng thay thế từng ký tự.
    Chọn ngẫu nhiên các vị trí để thay thế ký tự:

    Sử dụng random.sample để chọn ngẫu nhiên các vị trí dựa trên tỷ lệ lỗi. Điều này giúp tạo ra các lỗi chính tả ngẫu nhiên và đa dạng.
    Thực hiện thay thế ký tự:

    Với mỗi vị trí đã chọn, kiểm tra nếu ký tự đó có trong từ điển keyboard. Nếu có, chọn ngẫu nhiên một ký tự từ các ký tự gần đó trên bàn phím.
    Giữ nguyên kiểu chữ hoa hoặc chữ thường của ký tự gốc.
    Ghép lại thành chuỗi văn bản:

    Sử dụng ''.join(text) để ghép danh sách các ký tự lại thành chuỗi văn bản hoàn chỉnh.
    '''


    # Tính toán xác suất thay thế ký tự dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)

    # Bàn phím QWERTY tiếng Việt
    keyboard = {
        'a': 'âăáàạảãấầậẩẫắằặẳẵ',
        'â': 'aăáàạảãấầậẩẫắằặẳẵ',
        'ă': 'aâáàạảãấầậẩẫắằặẳẵ',
        'á': 'aâăàạảãấầậẩẫắằặẳẵ',
        'à': 'aâăáạảãấầậẩẫắằặẳẵ',
        'ạ': 'aâăáàảãấầậẩẫắằặẳẵ',
        'ả': 'aâăáàạãấầậẩẫắằặẳẵ',
        'ã': 'aâăáàạảấầậẩẫắằặẳẵ',
        'â': 'aăáàạảãấầậẩẫắằặẳẵ',
        'b': 'vn',
        'c': 'xv',
        'd': 'đ',
        'đ': 'd',
        'e': 'êéèẹẻẽếềệểễ',
        'ê': 'eéèẹẻẽếềệểễ',
        'é': 'eêèẹẻẽếềệểễ',
        'è': 'eêéẹẻẽếềệểễ',
        'ẹ': 'eêéèẻẽếềệểễ',
        'ẻ': 'eêéèẹẽếềệểễ',
        'ẽ': 'eêéèẹẻếềệểễ',
        'ế': 'eêéèẹẻẽềệểễ',
        'ề': 'eêéèẹẻẽếệểễ',
        'ệ': 'eêéèẹẻẽếềểễ',
        'ể': 'eêéèẹẻẽếềệễ',
        'ễ': 'eêéèẹẻẽếềệ',
        'f': 'r',
        'g': 'hf',
        'h': 'g',
        'i': 'ìíỉĩị',
        'í': 'iìỉĩị',
        'ì': 'iíỉĩị',
        'ỉ': 'iíìĩị',
        'ĩ': 'iíìỉị',
        'ị': 'iíìỉĩ',
        'k': 'l',
        'l': 'k;',
        'm': 'n',
        'n': 'm',
        'o': 'ôơóòọỏõốồộổỗớờợởỡ',
        'ô': 'oơóòọỏõốồộổỗớờợởỡ',
        'ơ': 'oôóòọỏõốồộổỗớờợởỡ',
        'ó': 'oôơòọỏõốồộổỗớờợởỡ',
        'ò': 'oôơóọỏõốồộổỗớờợởỡ',
        'ọ': 'oôơóòỏõốồộổỗớờợởỡ',
        'ỏ': 'oôơóòọõốồộổỗớờợởỡ',
        'õ': 'oôơóòọỏốồộổỗớờợởỡ',
        'ố': 'oôơóòọỏõồộổỗớờợởỡ',
        'ồ': 'oôơóòọỏõốộổỗớờợởỡ',
        'ộ': 'oôơóòọỏõốồổỗớờợởỡ',
        'ổ': 'oôơóòọỏõốồộỗớờợởỡ',
        'ỗ': 'oôơóòọỏõốồộổỗớờợởỡ',
        'ớ': 'oôơóòọỏõốồộổỗờợởỡ',
        'ờ': 'oôơóòọỏõốồộổỗớờợởỡ',
        'ợ': 'oôơóòọỏõốồộổỗớờợởỡ',
        'ở': 'oôơóòọỏõốồộổỗớờợỡ',
        'ỡ': 'oôơóòọỏõốồộổỗớờợở',
        'p': 'q',
        'q': 'p',
        'r': 'f',
        's': 'd',
        't': 'y',
        'u': 'ưúùụủũứừựửữ',
        'ư': 'uúùụủũứừựửữ',
        'ú': 'uưùụủũứừựửữ',
        'ù': 'uưúụủũứừựửữ',
        'ụ': 'uưúùủũứừựửữ',
        'ủ': 'uưúùụũứừựửữ',
        'ũ': 'uưúùụủứừựửữ',
        'ứ': 'uưúùụủũừựửữ',
        'ừ': 'uưúùụủũứựửữ',
        'ự': 'uưúùụủũứừửữ',
        'ử': 'uưúùụủũứừựữ',
        'ữ': 'uưúùụủũứừựử',
        'v': 'b',
        'x': 'c',
        'y': 't',
        'z': 's'
    }

    # Chuyển đổi văn bản thành danh sách ký tự
    text = list(text)

    # Xác định số lượng ký tự cần thay thế dựa trên tỷ lệ lỗi
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    # Chọn ngẫu nhiên các vị trí để thay thế ký tự
    indices = random.sample(range(len(text)), num_errors)

    num_of_change = 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, - (SER - SER_want) * k_sigmoid))))
    print(sigmoid)


    for index in indices:
        if text[index].lower() in keyboard and random.random() <= augmentation_probability * sigmoid:
            num_of_change += 1
            # Lấy ngẫu nhiên một ký tự từ các ký tự gần trên bàn phím
            replacement_char = random.choice(keyboard[text[index].lower()])
            # Giữ nguyên kiểu chữ hoa hoặc chữ thường
            if text[index].isupper():
                replacement_char = replacement_char.upper()
            text[index] = replacement_char

    # Ghép các ký tự lại thành chuỗi văn bản hoàn chỉnh
    final_text = ''.join(text)

    print("character_replacement: ", num_of_change)

    return final_text, num_of_change


def character_insertion(text, SER, error_rate=0.03):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất chèn ký tự
    :return: Gồm 1 câu sai chính tả

    Bàn phím QWERTY tiếng Việt:

    Một chuỗi ký tự bao gồm tất cả các ký tự chữ cái tiếng Việt và các ký tự dấu (â, ă, ê, ô, ơ, ư, đ).
    Chuyển đổi văn bản thành danh sách ký tự:

    Sử dụng list(text) để chuyển chuỗi văn bản thành danh sách các ký tự riêng lẻ. Điều này giúp dễ dàng thêm ký tự vào bất kỳ vị trí nào trong văn bản.
    Thực hiện thêm ký tự:

    Sử dụng vòng lặp for _ in range(num_errors) để thêm một số lượng ký tự ngẫu nhiên xác định (num_errors).
    Mỗi lần trong vòng lặp:
    Sử dụng random.randint(0, len(text)) để chọn ngẫu nhiên một vị trí trong văn bản nơi ký tự sẽ được thêm vào. Vị trí này có thể nằm ở bất kỳ đâu trong văn bản, bao gồm cả đầu và cuối văn bản.
    Sử dụng random.choice(keyboard) để chọn ngẫu nhiên một ký tự từ chuỗi keyboard.
    Sử dụng text.insert(index, char_to_insert) để thêm ký tự đã chọn vào vị trí đã chọn trong danh sách ký tự.
    Ghép lại thành chuỗi văn bản:

    Sử dụng ''.join(text) để ghép danh sách các ký tự lại thành chuỗi văn bản hoàn chỉnh.
    '''

    # Bàn phím QWERTY tiếng Việt với các ký tự gần nhau
    keyboard = 'abcdefghijklmnopqrstuvwxyzâăáàạảãấầậẩẫắằặẳẵêéèẹẻẽếềệểễìíỉĩịôơóòọỏõốồộổỗớờợởỡưúùụủũứừựửữđ'

    # Chuyển đổi văn bản thành danh sách ký tự để có thể thêm ký tự
    text = list(text)

    # Xác định số lượng ký tự cần thêm dựa trên tỷ lệ lỗi
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    # Tính toán xác suất chèn ký tự dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)

    num_of_change = 0
    # Thực hiện thêm ký tự tại các vị trí ngẫu nhiên

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)


    for _ in range(num_errors):
        # Chọn ngẫu nhiên một vị trí trong văn bản để thêm ký tự
        if random.random() <= augmentation_probability * sigmoid:
            num_of_change += 1
            index = random.randint(0, len(text))
            # Chọn ngẫu nhiên một ký tự từ bàn phím
            char_to_insert = random.choice(keyboard)
            # Thêm ký tự vào vị trí đã chọn
            text.insert(index, char_to_insert)

    # Ghép các ký tự lại thành chuỗi văn bản
    print("character_insertion: ", num_of_change)
    return ''.join(text), num_of_change


def character_deletion(text, SER, error_rate=0.03):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất xóa ký tự
    :return: Gồm 1 câu sai chính tả

    Thực hiện xóa ký tự:
    Sử dụng vòng lặp for _ in range(num_errors) để xóa một số lượng ký tự ngẫu nhiên xác định (num_errors).
    Mỗi lần trong vòng lặp:
    Sử dụng random.randint(0, len(text)-1) để chọn ngẫu nhiên một vị trí trong văn bản nơi ký tự sẽ bị xóa.
    Sử dụng text.pop(index) để xóa ký tự tại vị trí đã chọn.
    Ghép lại thành chuỗi văn bản:
    Sử dụng ''.join(text) để ghép danh sách các ký tự lại thành chuỗi văn bản hoàn chỉnh.
    '''

    # Chuyển đổi văn bản thành danh sách ký tự để có thể xóa ký tự
    text = list(text)

    # Xác định số lượng ký tự cần xóa dựa trên tỷ lệ lỗi
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0


    # Tính toán xác suất xóa ký tự dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)

    num_of_change = 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    # Thực hiện xóa ký tự tại các vị trí ngẫu nhiên
    for _ in range(num_errors):
        # Chọn ngẫu nhiên một vị trí trong văn bản để xóa ký tự
        if random.random() <= augmentation_probability * sigmoid:
            if len(text) > 0:  # Đảm bảo rằng danh sách không trống
                num_of_change += 1
                index = random.randint(0, len(text) - 1)
                # Xóa ký tự tại vị trí đã chọn
                text.pop(index)

    # Ghép các ký tự lại thành chuỗi văn bản
    print("character_deletion: ", num_of_change)
    return ''.join(text), num_of_change

def character_transposition(text, SER, error_rate=0.03):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất hoán đổi ký tự
    :return: Gồm 1 câu sai chính tả

    Thực hiện hoán đổi ký tự:
    Sử dụng vòng lặp for _ in range(num_errors) để hoán đổi một số lượng ký tự ngẫu nhiên xác định (num_errors).
    Mỗi lần trong vòng lặp:
    Sử dụng random.randint(0, len(text)-2) để chọn ngẫu nhiên một vị trí trong văn bản nơi ký tự sẽ bị hoán đổi.
    Hoán đổi hai ký tự liên tiếp tại vị trí đã chọn.
    Ghép lại thành chuỗi văn bản:
    Sử dụng ''.join(text) để ghép danh sách các ký tự lại thành chuỗi văn bản hoàn chỉnh.
    '''

    # Chuyển đổi văn bản thành danh sách ký tự để có thể hoán đổi ký tự
    text = list(text)

    # Xác định số lượng lần hoán đổi cần thực hiện dựa trên tỷ lệ lỗi
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    # Tính toán xác suất hoán đổi ký tự dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)
    num_of_change = 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    # Thực hiện hoán đổi ký tự tại các vị trí ngẫu nhiên
    for _ in range(num_errors):
        # Chọn ngẫu nhiên một vị trí trong văn bản để hoán đổi ký tự
        if random.random() <= augmentation_probability * sigmoid:
            if len(text) > 1:  # Đảm bảo rằng danh sách có ít nhất 2 ký tự để hoán đổi
                num_of_change += 2
                index = random.randint(0, len(text) - 2)
                # Hoán đổi hai ký tự liên tiếp tại vị trí đã chọn
                text[index], text[index + 1] = text[index + 1], text[index]

    # Ghép các ký tự lại thành chuỗi văn bản
    print("character_transposition: ", num_of_change)
    return ''.join(text), num_of_change

def homophone_replacement(text, SER, error_rate=0.03):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất thay thế từ đồng âm
    :return: Gồm 1 câu sai chính tả

    Thực hiện thay thế từ đồng âm:
    - Tìm các từ chứa homophones trước
    - Sử dụng augmentation_probability để xác định liệu từ đó có bị thay thế hay không
    Sử dụng ' '.join(words) để ghép danh sách các từ lại thành chuỗi văn bản hoàn chỉnh.
    '''

    homophones = {
        'gi': 'd',
        'd': 'gi',
        's': 'x',
        'x': 's',
        'tr': 'ch',
        'ch': 'tr',
        'r': 'd',
        'd': 'r',
        'l': 'n',
        'n': 'l',
        'c': 't',
        't': 'c',
        'v': 'b',
        'b': 'v',
        'ng': 'ngh',
        'ngh': 'ng',
        'v': 'z'
    }

    # Chuyển đổi văn bản thành danh sách từ để có thể thay thế từ
    words = text.split()

    # Xác định các từ có chứa homophones
    candidate_indices = []
    for i, word in enumerate(words):
        for key in homophones.keys():
            if key in word:
                candidate_indices.append(i)
                break

    # Tính toán xác suất thay thế từ dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)
    num_of_change = 0
    # Thực hiện thay thế từ tại các vị trí ngẫu nhiên
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    for _ in range(num_errors):
        if len(candidate_indices) > 0 and random.random() <= augmentation_probability * sigmoid:
            index = random.choice(candidate_indices)
            word = words[index]
            for key in homophones.keys():
                if key in word:
                    word = word.replace(key, homophones[key])
                    num_of_change += np.abs(len(key) - len(homophones[key]))
                    break  # Dừng lại sau khi thay thế lần đầu tiên để tránh thay thế nhiều lần
            words[index] = word
            candidate_indices.remove(index)  # Đảm bảo từ này không bị thay thế nhiều lần

    # Ghép các từ lại thành chuỗi văn bản
    print("homophone_replacement: ", num_of_change)
    return ' '.join(words), num_of_change


def common_misspelling_replacement(text, SER, error_rate=0.12):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất thay thế từ sai chính tả phổ biến
    :return: Gồm 1 câu sai chính tả

    Thực hiện thay thế từ bằng các phiên bản sai chính tả phổ biến.
    - Tìm các từ có thể thay thế trước
    - Sử dụng augmentation_probability để xác định liệu từ đó có bị thay thế hay không
    '''

    # Từ điển các từ đúng chính tả và các phiên bản sai chính tả phổ biến của chúng, teen code
    common_misspellings = {
        'những': ['nhửng', 'nhừng'],
        'của': ['cuả', 'cũa'],
        'cái': ['cái', 'cã'],
        'giải': ['giãi', 'giải'],
        'pháp': ['pháp', 'fáp'],
        'đúng': ['dúng', 'đúng'],
        'rất': ['rất', 'rậc'],
        'sáng': ['sán', 'sáng'],
        'tạo': ['tạo', 'tạu']
    }

    # Chuyển đổi văn bản thành danh sách từ để có thể thay thế từ
    words = text.split()

    # Tìm các từ có thể thay thế
    candidate_indices = [i for i, word in enumerate(words) if word in common_misspellings]

    #Kiểm tra xem có thể thay không
    if len(candidate_indices) == 0:
        return ' '.join(words), 0

    # Tính toán xác suất thay thế từ dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)
    num_of_change = 0
    # Thực hiện thay thế từ tại các vị trí ngẫu nhiên
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    for _ in range(num_errors):
        if len(candidate_indices) > 0 and random.random() <= augmentation_probability * sigmoid:
            index = random.choice(candidate_indices)
            word = words[index]
            # Chọn ngẫu nhiên một phiên bản sai chính tả từ từ điển
            misspelled_word = random.choice(common_misspellings[word])
            words[index] = misspelled_word
            num_of_change += np.abs(len(misspelled_word) - len(word))
            candidate_indices.remove(index)  # Đảm bảo từ này không bị thay thế nhiều lần

    # Ghép các từ lại thành chuỗi văn bản
    print("common_misspelling_replacement: ", num_of_change)
    return ' '.join(words), num_of_change


def similar_character_replacement(text, SER, error_rate=0.03):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất thay thế ký tự tương tự
    :return: Gồm 1 câu sai chính tả

    Thực hiện thay thế ký tự bằng ký tự tương tự trong bộ mã Unicode.
    - Tìm các ký tự có thể thay thế trước
    - Sử dụng augmentation_probability để xác định liệu ký tự đó có bị thay thế hay không
    '''

    # Từ điển các ký tự và các ký tự tương tự của chúng trong bộ mã Unicode
    similar_characters = {
        'a': ['á', 'à', 'ả', 'ã', 'ạ', 'â', 'ă'],
        'e': ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê'],
        'i': ['í', 'ì', 'ỉ', 'ĩ', 'ị'],
        'o': ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ơ'],
        'u': ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư'],
        'y': ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ'],
        'd': ['đ'],
        'A': ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Â', 'Ă'],
        'E': ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê'],
        'I': ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị'],
        'O': ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ơ'],
        'U': ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư'],
        'Y': ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ'],
        'D': ['Đ']
    }

    # Chuyển đổi văn bản thành danh sách ký tự để có thể thay thế ký tự
    characters = list(text)

    # Xác định các ký tự có thể thay thế
    candidate_indices = [i for i, char in enumerate(characters) if char in similar_characters]

    # Tính toán xác suất thay thế ký tự dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)
    num_of_change = 0
    # Thực hiện thay thế ký tự tại các vị trí ngẫu nhiên
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    for _ in range(num_errors):
        if len(candidate_indices) > 0 and random.random() <= augmentation_probability * sigmoid:
            num_of_change += 1
            index = random.choice(candidate_indices)
            char = characters[index]
            # Chọn ngẫu nhiên một ký tự tương tự từ từ điển
            similar_char = random.choice(similar_characters[char])
            characters[index] = similar_char
            candidate_indices.remove(index)  # Đảm bảo ký tự này không bị thay thế nhiều lần

    # Ghép các ký tự lại thành chuỗi văn bản
    print("similar_character_replacement: ", num_of_change)
    return ''.join(characters), num_of_change


def random_space_insertion(text, SER, error_rate=0.025):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất chèn khoảng trắng ngẫu nhiên
    :return: Gồm 1 câu sai chính tả

    Thực hiện chèn khoảng trắng ngẫu nhiên vào giữa từ.
    '''

    # Chuyển đổi văn bản thành danh sách ký tự để có thể chèn khoảng trắng
    characters = list(text)

    # Tìm các vị trí có thể chèn khoảng trắng
    candidate_indices = [i for i in range(1, len(characters))]

    # Tính toán xác suất chèn khoảng trắng dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)
    num_of_change = 0
    # Thực hiện chèn khoảng trắng tại các vị trí ngẫu nhiên
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    for _ in range(num_errors):
        if len(candidate_indices) > 0 and random.random() <= augmentation_probability * sigmoid:
            num_of_change += 1
            index = random.choice(candidate_indices)
            characters.insert(index, ' ')
            candidate_indices.remove(index)  # Đảm bảo không chèn khoảng trắng nhiều lần tại cùng một vị trí

    # Ghép các ký tự lại thành chuỗi văn bản
    print("random_space_insertion: ", num_of_change)
    return ''.join(characters), num_of_change

def random_space_removal(text, SER, error_rate=0.01):
    '''
    :param text: Gồm 1 câu đúng chính tả
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất bỏ dấu cách
    :return: Gồm 1 câu bị thiếu dấu cách

    Thực hiện bỏ ngẫu nhiên một vài dấu cách giữa các từ.
    '''

    # Tính toán xác suất bỏ dấu cách dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)
    num_of_change = 0
    # Tìm các vị trí có thể bỏ dấu cách (giữa các từ)
    words = text.split()
    candidate_indices = [i for i in range(len(words) - 1)]

    # Nếu num_errors không được cung cấp, tính toán số lượng dấu cách cần bỏ dựa trên error_rate
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    # Thực hiện bỏ dấu cách tại các vị trí ngẫu nhiên
    selected_indices = random.sample(candidate_indices, min(num_errors, len(candidate_indices)))
    for index in selected_indices:
        if random.random() <= augmentation_probability * sigmoid:
            num_of_change += 1
            words[index] = words[index] + words[index + 1]
            words[index + 1] = ''  # Xóa từ đã ghép để tránh lặp lại

    # Ghép các từ lại thành chuỗi văn bản, bỏ qua các từ trống
    print("random_space_removal: ", num_of_change)
    return ' '.join([word for word in words if word]), num_of_change



import unidecode

def remove_vietnamese_accents(text, SER, error_rate=0.05):
    '''
    :param text: Gồm 1 câu có dấu tiếng Việt
    :param error_rate: tỷ lệ lỗi sai muốn thêm
    :param C: hằng số để tính toán xác suất chuyển đổi ký tự
    :param num_errors: số lượng lỗi sai muốn thêm (tuỳ chọn)
    :return: Gồm 1 câu không dấu tiếng Việt với một tỷ lệ lỗi nhất định

    Thực hiện chuyển đổi các ký tự có dấu thành các ký tự không dấu tương ứng với xác suất nhất định.
    '''

    # Tính toán xác suất chuyển đổi ký tự dựa trên error_rate sử dụng hàm logarit
    augmentation_probability = fomula.AP_fomula(error_rate=error_rate)

    # Chuyển đổi văn bản thành danh sách ký tự để có thể chuyển đổi ký tự
    characters = list(text)

    num_of_change = 0
    num_errors = int(len(text) * error_rate)
    if num_errors < 1:
        num_errors = 1 if random.random() > 0.5 else 0

    # Xác định các ký tự có thể chuyển đổi
    candidate_indices = [i for i, char in enumerate(characters) if unidecode.unidecode(char) != char]

    sigmoid = 1 if SER <= SER_want else (1 - (1 / (1 + pow(math.e, -(SER - SER_want) * k_sigmoid))))
    print(sigmoid)

    # Thực hiện chuyển đổi ký tự tại các vị trí ngẫu nhiên
    selected_indices = random.sample(candidate_indices, min(num_errors, len(candidate_indices)))
    for index in selected_indices:
        if random.random() <= augmentation_probability * sigmoid:
            num_of_change += 1
            characters[index] = unidecode.unidecode(characters[index])

    print("remove_vietnamese_accents: ", num_of_change)
    # Ghép các ký tự lại thành chuỗi văn bản
    return ''.join(characters), num_of_change