ketav commited on
Commit
1a635c0
·
verified ·
1 Parent(s): c139219

Chatterbox Turbo finetuned for Hindi/Hinglish TTS (romanized text)

Browse files
Files changed (7) hide show
  1. .gitattributes +1 -0
  2. README.md +147 -0
  3. TRAINING_NOTES.md +135 -0
  4. config.py +42 -0
  5. inference.py +107 -0
  6. reference.wav +3 -0
  7. t3_turbo_finetuned.safetensors +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ reference.wav filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - hi
4
+ - en
5
+ license: mit
6
+ tags:
7
+ - tts
8
+ - text-to-speech
9
+ - voice-cloning
10
+ - hindi
11
+ - hinglish
12
+ - chatterbox
13
+ base_model: ResembleAI/chatterbox-turbo
14
+ pipeline_tag: text-to-speech
15
+ ---
16
+
17
+ # Chatterbox Turbo — Hindi/Hinglish Finetuned
18
+
19
+ Finetuned [Chatterbox Turbo](https://huggingface.co/ResembleAI/chatterbox-turbo) (350M, GPT-2 backbone) for **Hindi (romanized) and English** text-to-speech with voice cloning.
20
+
21
+ ## Key Features
22
+ - **Bilingual**: Speaks both Hindi (romanized Latin script) and English
23
+ - **Hinglish**: Handles code-mixed Hindi-English seamlessly
24
+ - **Voice Cloning**: Provide any 5-10s reference audio to clone the voice
25
+ - **Fast**: Single-step decoder, ~6x faster than real-time on GPU
26
+
27
+ ## How It Works
28
+ Hindi text is written in **romanized form** (Latin script), not Devanagari. This allows the GPT-2 BPE tokenizer to handle it natively without any vocabulary extension.
29
+
30
+ Example: `"bharat ke kisan bahut mehnat karte hai"` instead of `"भारत के किसान बहुत मेहनत करते हैं"`
31
+
32
+ ## Usage
33
+
34
+ ### Prerequisites
35
+ ```bash
36
+ pip install chatterbox-tts safetensors torch torchaudio soundfile
37
+ ```
38
+
39
+ ### Quick Inference
40
+ ```python
41
+ import torch
42
+ import soundfile as sf
43
+ from safetensors.torch import load_file
44
+ from chatterbox.tts_turbo import ChatterboxTurboTTS
45
+ from chatterbox.models.t3.t3 import T3
46
+
47
+ # Load base Chatterbox Turbo
48
+ engine = ChatterboxTurboTTS.from_pretrained(device="cuda")
49
+
50
+ # Load finetuned T3 weights
51
+ t3_config = engine.t3.hp
52
+ t3_config.text_tokens_dict_size = 50276
53
+ new_t3 = T3(hp=t3_config)
54
+ if hasattr(new_t3.tfmr, "wte"):
55
+ del new_t3.tfmr.wte
56
+
57
+ state_dict = load_file("t3_turbo_finetuned.safetensors", device="cpu")
58
+ new_t3.load_state_dict(state_dict, strict=True)
59
+
60
+ engine.t3 = new_t3
61
+ engine.t3.to("cuda").eval()
62
+
63
+ # Generate speech
64
+ wav = engine.generate(
65
+ text="yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai.",
66
+ audio_prompt_path="reference.wav", # 5-10s reference clip of target voice
67
+ temperature=0.5,
68
+ )
69
+ sf.write("output.wav", wav.squeeze().cpu().numpy(), 24000)
70
+ ```
71
+
72
+ ### Text Format
73
+ - **Hindi**: Use romanized text (Latin script). Example: `"namaste, mera naam Ketav hai"`
74
+ - **English**: Use as-is. Example: `"Hello, my name is Ketav"`
75
+ - **Hinglish**: Mix freely. Example: `"mujhe lagta hai ki yeh project bahut successful hoga"`
76
+
77
+ ### Romanization Guide
78
+ Common Hindi romanization patterns used in training:
79
+
80
+ | Hindi | Romanized |
81
+ |-------|-----------|
82
+ | है | hai |
83
+ | में | mein |
84
+ | यह | yeh |
85
+ | वो | voh |
86
+ | नहीं | nahi |
87
+ | बहुत | bahut |
88
+ | क्योंकि | kyonki |
89
+
90
+ ### Inference Tips
91
+ - **Temperature 0.5** recommended (lower = more precise pronunciation)
92
+ - Reference audio must be **>5 seconds**
93
+ - Clean reference audio with minimal background noise works best
94
+
95
+ ## Training Details
96
+
97
+ ### Data
98
+ - **14,085 samples** (~20.4 hours) from a single male Hindi/English speaker
99
+ - 7,320 Hindi samples (romanized via IndicXlit + loanword dictionary)
100
+ - 6,765 English samples (original text)
101
+ - Duration filtered to 1-15 seconds per clip
102
+
103
+ ### Text Processing Pipeline
104
+ 1. Indic Normalize (DevanagariNormalizer)
105
+ 2. English loanword replacement (23,019 entry dictionary)
106
+ 3. IndicXlit transliteration cache (235,973 entries)
107
+ 4. Lowercase + standardize romanization (62 rules)
108
+
109
+ ### Hyperparameters
110
+ - Base model: `ResembleAI/chatterbox-turbo`
111
+ - Vocab size: 50,276 (original GPT-2, no extension)
112
+ - Batch size: 16, gradient accumulation: 2 (effective 32)
113
+ - Learning rate: 5e-5
114
+ - Epochs: 100
115
+ - Best checkpoint: step 38,000, loss 0.6685
116
+ - GPU: NVIDIA RTX 3090 (24GB)
117
+ - Training time: ~14 hours
118
+
119
+ ### Loss Curve
120
+ | Epoch | Loss |
121
+ |-------|------|
122
+ | 1 | 7.204 |
123
+ | 10 | 3.672 |
124
+ | 20 | 2.162 |
125
+ | 30 | 1.519 |
126
+ | 50 | 0.938 |
127
+ | 80 | 0.669 |
128
+
129
+ ## Files
130
+ | File | Description |
131
+ |------|-------------|
132
+ | `t3_turbo_finetuned.safetensors` | Finetuned T3 model weights (1.6 GB) |
133
+ | `inference.py` | Inference script with test sentences |
134
+ | `reference.wav` | Sample reference audio for voice cloning |
135
+ | `config.py` | Training configuration used |
136
+ | `TRAINING_NOTES.md` | Detailed training documentation |
137
+
138
+ ## Limitations
139
+ - Only handles **romanized** Hindi text, not Devanagari script
140
+ - Voice quality depends on reference audio quality
141
+ - May merge words at high temperature (use 0.5)
142
+ - Trained on single male speaker — works for voice cloning of any voice, but Hindi pronunciation patterns are from one speaker
143
+
144
+ ## Acknowledgments
145
+ - [Resemble AI](https://www.resemble.ai/) for Chatterbox Turbo
146
+ - [gokhaneraslan/chatterbox-finetuning](https://github.com/gokhaneraslan/chatterbox-finetuning) for the finetuning toolkit
147
+ - [AI4Bharat IndicXlit](https://github.com/AI4Bharat/IndicXlit) for transliteration
TRAINING_NOTES.md ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Chatterbox Turbo Hinglish Finetuning — Training Notes
2
+
3
+ ## Overview
4
+ Finetuning Chatterbox Turbo (350M, GPT-2 backbone) for **Hindi (romanized) + English** TTS using a single male speaker.
5
+
6
+ ## Data Pipeline
7
+
8
+ ### Source Data
9
+ - **Hindi male**: 7,320 files from `/workspace/data/bilingual/hindi/wav_22k/` (train_hindimale_*.wav)
10
+ - **English male**: 6,765 files from `/workspace/data/bilingual/english/wav_22k/` (train_hindifullmale_*.wav)
11
+ - **Total**: 14,085 files, ~21.3 hours → filtered to 13,941 (1-15s duration), ~20.4 hours
12
+ - **Audio format**: 22kHz mono WAV (auto-resampled to 16kHz by Chatterbox)
13
+ - **Speaker**: Single male speaker (speaker ID 1)
14
+
15
+ ### Text Processing Pipeline (Hindi only, English left intact)
16
+ 1. **Indic Normalize** — DevanagariNormalizer from IndicNLP (nukta decomposition, visarga fixes)
17
+ 2. **Loanword Replacement** — 23,019 entry Devanagari→English dictionary (`scripts/utils/english_loanwords.py` from asr-main repo)
18
+ 3. **Transliteration** — xlit_cache_merged.json (235,973 entries) maps remaining Devanagari words to romanized Latin
19
+ 4. **Lowercase** — all Hindi text lowercased
20
+ 5. **Standardize Romanization** — 62 rules for common variations (hain→hai, vo→voh, bahot→bahut, etc.)
21
+ 6. **English text** — left completely untouched from source manifests
22
+
23
+ ### Coverage
24
+ - xlit cache: 91,323 tokens (96.9%)
25
+ - Loanword dict: 2,857 tokens (3.0%)
26
+ - Missing: 1 token (junk `__वें`)
27
+ - **Total: 100% coverage**
28
+
29
+ ### Dataset Format
30
+ - **LJSpeech format**: `metadata.csv` (filename|text|text) + `wavs/` directory (symlinks)
31
+ - Sorted by duration (ascending) to minimize padding waste
32
+ - Uploaded to HuggingFace: `ketav/hinglish-tts-data/romanized_transcripts_hindimale.zip`
33
+
34
+ ## Model Configuration
35
+
36
+ ### No Vocab Extension Needed
37
+ - All text is Latin characters (romanized Hindi + English)
38
+ - GPT-2 BPE tokenizer handles this natively
39
+ - `new_vocab_size = 50276` (matches pretrained T3 turbo exactly)
40
+ - Skipped the `setup.py` vocab merging step entirely
41
+
42
+ ### Training Config
43
+ ```python
44
+ is_turbo = True
45
+ new_vocab_size = 50276
46
+ batch_size = 16
47
+ grad_accum = 2 # effective batch = 32
48
+ learning_rate = 5e-5
49
+ num_epochs = 100
50
+ save_steps = 1000
51
+ max_speech_len = 850
52
+ max_text_len = 256
53
+ prompt_duration = 3.0 # seconds
54
+ ```
55
+
56
+ ### Speed Optimizations Applied
57
+ - `torch.backends.cuda.matmul.allow_tf32 = True` (~15% faster)
58
+ - `torch.set_float32_matmul_precision('high')`
59
+ - `bf16 = True` (mixed precision)
60
+ - `gradient_checkpointing = True` (VRAM savings)
61
+ - Duration-sorted data (less padding waste)
62
+ - Filtered clips to 1-15s (removed 144 extreme outliers)
63
+ - `torch.compile` — tried but incompatible with T3 model (CUDAGraphs conflict)
64
+
65
+ ### GPU
66
+ - NVIDIA RTX 3090 (24GB)
67
+ - VRAM usage: ~13.8 GB peak (with batch_size=16)
68
+ - GPU utilization: 96-100%
69
+ - Training speed: ~1.17-1.23 s/step
70
+
71
+ ## Training Progress
72
+
73
+ ### Loss Curve
74
+ | Epoch | Loss |
75
+ |-------|--------|
76
+ | 1 | 7.204 |
77
+ | 5 | 5.042 |
78
+ | 10 | 3.672 |
79
+ | 20 | 2.162 |
80
+ | 30 | 1.519 |
81
+ | 40 | 1.127 |
82
+ | 50 | 0.938 |
83
+ | 60 | 0.822 |
84
+
85
+ ### Checkpoints
86
+ Best checkpoints saved to `best_models/` by automated checkpoint_saver.py script.
87
+ Backup copy at `/workspace/best_models_backup/`.
88
+
89
+ ## Inference
90
+
91
+ ### Reference Audio
92
+ - Must be >5 seconds (Chatterbox Turbo requirement)
93
+ - Using `train_hindimale_04569.wav` (6.28s Hindi male clip)
94
+
95
+ ### Best Settings
96
+ ```python
97
+ temperature = 0.5 # lower = more precise, less word-merging artifacts
98
+ # exaggeration and repetition_penalty are ignored by Turbo mode
99
+ ```
100
+
101
+ ### Known Issues
102
+ - **Word merging**: At temperature 0.8, words can blend together (e.g., "company ka growth" → "compgrowth")
103
+ - **Fix**: Lower temperature to 0.5 resolves this
104
+ - Turbo mode ignores `exaggeration`, `cfg_weight`, and `min_p` parameters
105
+
106
+ ### Test Sentences Used
107
+ ```
108
+ Hindi: "yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai."
109
+ Hindi: "bharat ke kisan bahut mehnat karte hai lekin unhe sahi daam nahi milta."
110
+ English: "The weather today is beautiful and I feel very happy about it."
111
+ English: "Technology has changed our lives in ways we never imagined before."
112
+ Hinglish: "mujhe lagta hai ki yeh project bahut successful hoga because humne bahut hard work kiya hai."
113
+ Hinglish: "aaj meeting mein boss ne kaha ki next quarter mein company ka growth double hoga."
114
+ ```
115
+
116
+ ## Monitoring
117
+ - **Telegram bot**: Sends training updates every 30 min (loss, LR, epoch, progress)
118
+ - **Checkpoint saver**: Keeps best 3 checkpoints by loss, detects overfitting (3 consecutive loss increases)
119
+ - **TensorBoard**: `tensorboard --logdir chatterbox_output --port 6006`
120
+
121
+ ## Files Created
122
+ | File | Purpose |
123
+ |------|---------|
124
+ | `src/config.py` | Training configuration |
125
+ | `train.py` | Modified with resume support, tf32, torch.load patch |
126
+ | `test_inference.py` | Mid-training inference from best checkpoint |
127
+ | `telegram_monitor.py` | Telegram training status updates |
128
+ | `checkpoint_saver.py` | Best checkpoint tracking + overfitting detection |
129
+ | `TRAINING_NOTES.md` | This file |
130
+
131
+ ## Key Repos & Data
132
+ - **Finetuning repo**: gokhaneraslan/chatterbox-finetuning
133
+ - **ASR pipeline (text processing)**: `/workspace/asr-main/asr-main/`
134
+ - **HF dataset**: `ketav/hinglish-tts-data` (private)
135
+ - **HF parakeet data**: `ketav/hinglish-parakeet-tarred`, `ketav/hinglish-v2-sorted-tarred`
config.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class TrainConfig:
5
+ # --- Paths ---
6
+ model_dir: str = "./pretrained_models"
7
+ csv_path: str = "/workspace/chatterbox_dataset/metadata.csv"
8
+ metadata_path: str = "./metadata.json"
9
+ wav_dir: str = "/workspace/chatterbox_dataset/wavs"
10
+ preprocessed_dir = "/workspace/chatterbox_dataset/preprocess"
11
+ output_dir: str = "./chatterbox_output"
12
+
13
+ is_inference = False
14
+ inference_prompt_path: str = "./speaker_reference/reference.wav"
15
+ inference_test_text: str = "yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai."
16
+
17
+ ljspeech = True
18
+ json_format = False
19
+ preprocess = False
20
+
21
+ is_turbo: bool = True
22
+
23
+ # --- Vocabulary ---
24
+ # Match pretrained T3 turbo vocab size exactly (GPT-2 50257 + 19 special tokens)
25
+ new_vocab_size: int = 50276
26
+
27
+ # --- Hyperparameters ---
28
+ batch_size: int = 16 # RTX 3090 24GB — plenty of headroom
29
+ grad_accum: int = 2 # Effective batch = 32
30
+ learning_rate: float = 5e-5
31
+ num_epochs: int = 100
32
+
33
+ save_steps: int = 1000
34
+ save_total_limit: int = 20
35
+ dataloader_num_workers: int = 8
36
+
37
+ # --- Constraints ---
38
+ start_text_token = 255
39
+ stop_text_token = 0
40
+ max_text_len: int = 256
41
+ max_speech_len: int = 850
42
+ prompt_duration: float = 3.0
inference.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Quick inference test using best checkpoint. Runs separately from training."""
3
+
4
+ import os
5
+ import glob
6
+ import torch
7
+ import numpy as np
8
+ import soundfile as sf
9
+ from safetensors.torch import load_file
10
+
11
+ from src.config import TrainConfig
12
+ from src.chatterbox_.tts_turbo import ChatterboxTurboTTS
13
+ from src.chatterbox_.models.t3.t3 import T3
14
+ from src.utils import trim_silence_with_vad
15
+
16
+ # Patch torch.load for compatibility
17
+ _original_torch_load = torch.load
18
+ torch.load = lambda *args, **kwargs: _original_torch_load(*args, **{**kwargs, "weights_only": kwargs.get("weights_only", False)})
19
+
20
+ cfg = TrainConfig()
21
+ DEVICE = "cuda"
22
+ REFERENCE_AUDIO = "./speaker_reference/reference.wav"
23
+ OUTPUT_DIR = "/workspace/inference_test_v3"
24
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
25
+
26
+ # Test sentences
27
+ TEST_SENTENCES = {
28
+ "hindi_1": "yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai.",
29
+ "hindi_2": "bharat ke kisan bahut mehnat karte hai lekin unhe sahi daam nahi milta.",
30
+ "english_1": "The weather today is beautiful and I feel very happy about it.",
31
+ "english_2": "Technology has changed our lives in ways we never imagined before.",
32
+ "hinglish_1": "mujhe lagta hai ki yeh project bahut successful hoga because humne bahut hard work kiya hai.",
33
+ "hinglish_2": "aaj meeting mein boss ne kaha ki next quarter mein company ka growth double hoga.",
34
+ }
35
+
36
+ def find_best_checkpoint():
37
+ """Find the best checkpoint from best_models/ or latest from training."""
38
+ best_dir = "/workspace/chatterbox-finetuning/best_models"
39
+ if os.path.exists(best_dir):
40
+ ckpts = sorted(glob.glob(f"{best_dir}/best_loss*"), key=lambda x: float(x.split("loss")[1].split("_")[0]))
41
+ if ckpts:
42
+ # Find the safetensors file inside
43
+ for f in os.listdir(ckpts[0]):
44
+ if f.endswith(".safetensors") and "model" in f:
45
+ return os.path.join(ckpts[0], f)
46
+ # Try trainer format
47
+ model_path = os.path.join(ckpts[0], "model.safetensors")
48
+ if os.path.exists(model_path):
49
+ return model_path
50
+ return None
51
+
52
+ def load_engine(checkpoint_path):
53
+ print(f"Loading base model...")
54
+ engine = ChatterboxTurboTTS.from_local(cfg.model_dir, device="cpu")
55
+
56
+ print(f"Creating T3 with vocab size: {cfg.new_vocab_size}")
57
+ t3_config = engine.t3.hp
58
+ t3_config.text_tokens_dict_size = cfg.new_vocab_size
59
+ new_t3 = T3(hp=t3_config)
60
+
61
+ if hasattr(new_t3.tfmr, "wte"):
62
+ del new_t3.tfmr.wte
63
+
64
+ print(f"Loading checkpoint: {checkpoint_path}")
65
+ state_dict = load_file(checkpoint_path, device="cpu")
66
+ # Strip "t3." prefix if saved by HF Trainer wrapper
67
+ if any(k.startswith("t3.") for k in state_dict):
68
+ state_dict = {k.replace("t3.", "", 1): v for k, v in state_dict.items()}
69
+ new_t3.load_state_dict(state_dict, strict=True)
70
+
71
+ engine.t3 = new_t3
72
+ engine.t3.to(DEVICE).eval()
73
+ engine.s3gen.to(DEVICE).eval()
74
+ engine.ve.to(DEVICE).eval()
75
+ engine.device = DEVICE
76
+
77
+ return engine
78
+
79
+ def generate(engine, text, output_path):
80
+ with torch.no_grad():
81
+ wav = engine.generate(
82
+ text=text,
83
+ audio_prompt_path=REFERENCE_AUDIO,
84
+ temperature=0.5,
85
+ )
86
+ wav_np = wav.squeeze().cpu().numpy()
87
+ wav_np = trim_silence_with_vad(wav_np, engine.sr)
88
+ sf.write(output_path, wav_np, engine.sr)
89
+ return len(wav_np) / engine.sr
90
+
91
+ if __name__ == "__main__":
92
+ ckpt = find_best_checkpoint()
93
+ if not ckpt:
94
+ print("No checkpoint found!")
95
+ exit(1)
96
+
97
+ print(f"Best checkpoint: {ckpt}")
98
+ engine = load_engine(ckpt)
99
+
100
+ print(f"\nGenerating {len(TEST_SENTENCES)} test sentences...\n")
101
+ for name, text in TEST_SENTENCES.items():
102
+ out_path = os.path.join(OUTPUT_DIR, f"{name}.wav")
103
+ dur = generate(engine, text, out_path)
104
+ print(f" {name}: {dur:.1f}s -> {out_path}")
105
+ print(f" Text: {text}")
106
+
107
+ print(f"\nDone! Audio files in {OUTPUT_DIR}/")
reference.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ad65adc16d23ab41aa6e2f32ec19e51400acdb862e1055a724a776bd02997f71
3
+ size 277188
t3_turbo_finetuned.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a0ce1dd72db44baa59f4aa1996a64ca4ac5f69113117927f93b4236021f6c87f
3
+ size 1709549468