| import os |
| import glob |
| import json |
| import logging |
| import subprocess |
| from concurrent.futures import ProcessPoolExecutor, as_completed |
| import pandas as pd |
| from tqdm import tqdm |
|
|
| logging.basicConfig(level=logging.INFO) |
|
|
| BAK_JSONL = r"D:/dataset/audio/New folder/thaiserextract/metadata.jsonl.bak" |
| PARQUET_DIR = r"D:/dataset/audio/New folder/thaiser/data" |
| OUTPUT_AUDIO_DIR = r"D:/dataset/audio/New folder/thaiserextract/audio" |
| OUTPUT_JSONL = r"D:/dataset/audio/New folder/thaiserextract/metadata_clean.jsonl" |
|
|
| os.makedirs(OUTPUT_AUDIO_DIR, exist_ok=True) |
|
|
| def extract_base_id(audio_id): |
| return audio_id.replace("_con_", "_").replace("_clip_", "_").replace("_middle_", "_") |
|
|
| def safe_json_loads(line): |
| |
| |
| try: |
| return json.loads(line) |
| except: |
| return None |
|
|
| def load_bak_mapping(): |
| mapping = {} |
| if os.path.exists(BAK_JSONL): |
| with open(BAK_JSONL, "r", encoding="utf-8", errors="ignore") as f: |
| for line in f: |
| data = safe_json_loads(line) |
| if data and "audio_id" in data and "text" in data: |
| base_id = extract_base_id(data["audio_id"]) |
| mapping[base_id] = { |
| "text": data["text"], |
| "speaker_id": data.get("speaker_id", "Unknown") |
| } |
| return mapping |
|
|
| def convert_bytes_to_mp3(audio_bytes, out_mp3): |
| if os.path.exists(out_mp3): |
| return True |
| try: |
| cmd = ['ffmpeg', '-y', '-f', 'flac', '-i', 'pipe:0', '-c:a', 'libmp3lame', '-q:a', '2', out_mp3] |
| subprocess.run(cmd, input=audio_bytes, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
| return True |
| except Exception as e: |
| return False |
|
|
| def process_parquet(parquet_file, mapping): |
| results = [] |
| try: |
| df = pd.read_parquet(parquet_file) |
| |
| df = df[df['assigned_emo'].notna() & (df['assigned_emo'].astype(str).str.lower() != 'none')] |
| |
| for _, row in df.iterrows(): |
| audio_id_con = row['audio_id'] |
| base_id = extract_base_id(audio_id_con) |
| |
| text = None |
| speaker_id = str(row.get('actor_id', 'Unknown')) |
| emo = row['assigned_emo'] |
|
|
| if base_id in mapping: |
| text = mapping[base_id]["text"] |
| speaker_id = mapping[base_id]["speaker_id"] |
| elif pd.notna(row.get('script_sent')): |
| text = str(row['script_sent']) |
| |
| if not text or len(text.strip()) == 0: |
| continue |
|
|
| mics = [("mic_con", "_con_"), ("mic_clip", "_clip_"), ("mic_middle", "_middle_")] |
| |
| |
| |
| |
| for col, infix in mics: |
| if col in row and pd.notna(row[col]) and isinstance(row[col], dict) and 'bytes' in row[col]: |
| first_underscore = base_id.find('_') |
| if first_underscore != -1: |
| new_audio_id = base_id[:first_underscore] + infix + base_id[first_underscore+1:] |
| else: |
| new_audio_id = infix.strip('_') + "_" + base_id |
| |
| out_mp3_name = new_audio_id + ".mp3" |
| out_mp3_path = os.path.join(OUTPUT_AUDIO_DIR, out_mp3_name) |
| |
| success = convert_bytes_to_mp3(row[col]['bytes'], out_mp3_path) |
| if success: |
| results.append({ |
| "audio_id": new_audio_id, |
| "file_path": out_mp3_path.replace("\\", "/"), |
| "text": text, |
| "speaker_id": speaker_id, |
| "emotion": emo, |
| "path": out_mp3_path.replace("\\", "/") |
| }) |
| except Exception as e: |
| print(f"Error processing {parquet_file}: {e}") |
| return results |
|
|
| def main(): |
| print("Loading mapping from metadata.jsonl.bak...") |
| mapping = load_bak_mapping() |
| print(f"Loaded {len(mapping)} verified texts.") |
| |
| parquet_files = glob.glob(os.path.join(PARQUET_DIR, "*.parquet")) |
| print(f"Found {len(parquet_files)} parquet files to process.") |
| |
| all_results = [] |
| |
| |
| |
| with ProcessPoolExecutor(max_workers=4) as executor: |
| futures = {executor.submit(process_parquet, pf, mapping): pf for pf in parquet_files} |
| |
| for future in tqdm(as_completed(futures), total=len(futures), desc="Extracting Audio"): |
| res = future.result() |
| all_results.extend(res) |
| |
| print(f"Extraction complete! Total multi-mic segments: {len(all_results)}") |
| |
| print("Writing metadata_clean.jsonl...") |
| with open(OUTPUT_JSONL, "w", encoding="utf-8") as f: |
| for r in all_results: |
| f.write(json.dumps(r, ensure_ascii=False) + "\n") |
| print("Done!") |
|
|
| if __name__ == "__main__": |
| main() |
|
|