File size: 5,593 Bytes
960b1a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import json
import random
import pandas as pd
import re
from datetime import timedelta
from pathlib import Path

# === Загрузка шаблонов ===
def load_templates_json(templates_dir, emotion):
    path = Path(templates_dir) / f"{emotion}.json"
    if not path.exists():
        raise FileNotFoundError(f"Шаблон для эмоции '{emotion}' не найден: {path}")
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)

# === Генерация текстов с учётом seed и антидубликатов ===
def generate_emotion_batch(n, template_data, seed=None):
    if seed is not None:
        random.seed(seed)

    subjects       = template_data["subjects"]
    verbs          = template_data["verbs"]
    contexts       = template_data["contexts"]
    interjections  = template_data.get("interjections", [""])
    templates      = template_data["templates"]

    # Допустимые звуковые метки DIA‑TTS
    dia_tags = {
        "(laughs)", "(clears throat)", "(sighs)", "(gasps)", "(coughs)",
        "(singing)", "(sings)", "(mumbles)", "(beep)", "(groans)", "(sniffs)",
        "(claps)", "(screams)", "(inhales)", "(exhales)", "(applause)",
        "(burps)", "(humming)", "(sneezes)", "(chuckle)", "(whistles)"
    }

    def has_tag(text):      return any(tag in text for tag in dia_tags)
    def remove_tags(text):
        for tag in dia_tags:
            text = text.replace(tag, "")
        return text.strip()

    phrases, attempts = set(), 0
    max_attempts = n * 50

    while len(phrases) < n and attempts < max_attempts:
        s, v = random.choice(subjects), random.choice(verbs)
        c, i = random.choice(contexts), random.choice(interjections)
        t     = random.choice(templates)

        # ▸ Разрешаем максимум одну звуковую метку на фразу
        if has_tag(i) and has_tag(c):
            if random.random() < .5:
                c = remove_tags(c)
            else:
                i = remove_tags(i)

        phrase = t.format(s=s, v=v, c=c, i=i)

        # --- Очистка без разрушения многоточий ---------------------------
        # 1) убрать пробелы перед знаками пунктуации
        phrase = re.sub(r"\s+([,.!?])", r"\1", phrase)
        # 2) превратить двойную точку, КОТОРАЯ не часть троеточия, в одну
        phrase = re.sub(r"(?<!\.)\.\.(?!\.)", ".", phrase)
        # 3) вставить пробел, если после метки сразу идёт слово
        phrase = re.sub(r"\)(?=\w)", ") ", phrase)
        # 4) схлопнуть множественные пробелы и обрезать края
        phrase = re.sub(r"\s{2,}", " ", phrase).strip()
        # ------------------------------------------------------------------

        if phrase not in phrases:
            phrases.add(phrase)
        attempts += 1

    if len(phrases) < n:
        print(f"⚠️ Только {len(phrases)} уникальных фраз из {n} запрошенных — возможно, исчерпан пул шаблонов.")

    return list(phrases)

# === Генерация временных меток ===
def generate_dummy_timestamps(n):
    base_time, result = timedelta(), []
    for idx in range(n):
        start = base_time + timedelta(seconds=idx * 6)
        end   = start + timedelta(seconds=5)
        result.append((
            str(start).split(".")[0] + ",000",
            str(end).split(".")[0]   + ",000"
        ))
    return result

# === Финальная сборка и сохранение CSV ===
def create_emotion_csv(template_path, emotion_label, out_file, n=1000, seed=None):
    data     = load_templates_json(template_path, emotion_label)
    phrases  = generate_emotion_batch(n, data, seed)
    timeline = generate_dummy_timestamps(n)

    emotions   = ["neutral", "happy", "sad", "anger", "surprise", "disgust", "fear"]
    label_mask = {e: float(e == emotion_label) for e in emotions}

    df = pd.DataFrame({
        "video_name": [f"dia_{emotion_label}_utt{i}_synt" for i in range(n)],
        "start_time": [s for s, _ in timeline],
        "end_time"  : [e for _, e in timeline],
        "sentiment" : [0] * n,
        **{e: [label_mask[e]] * n for e in emotions},
        "text"      : phrases
    })

    df.to_csv(out_file, index=False)
    print(f"✅ Сохранено {len(df)} строк → {out_file}")

    # --- Проверка дубликатов ---
    dupes = df[df.duplicated("text", keep=False)]
    if not dupes.empty:
        dupe_file = Path(out_file).with_name(f"duplicates_{emotion_label}.csv")
        dupes.to_csv(dupe_file, index=False)
        print(f"⚠️ Найдено {len(dupes)} повторов → {dupe_file}")
    else:
        print("✅ Дубликатов нет.")

# === Точка входа ===
if __name__ == "__main__":
    emotion_config = {
        "anger":    3600,
        "disgust":  4438,
        "fear":     4441,
        "happy":    2966,
        "sad":      4026,
        "surprise": 3504
    }

    seed, template_path, out_dir = 42, "emotion_templates", "synthetic_data"
    Path(out_dir).mkdir(parents=True, exist_ok=True)

    for emotion, n in emotion_config.items():
        out_csv = Path(out_dir) / f"meld_synthetic_{emotion}_{n}.csv"
        print(f"\n🔄 Генерация: {emotion} ({n} фраз)")
        create_emotion_csv(template_path, emotion, str(out_csv), n, seed)