| 14 | |
| 15 | |
| 16 | class LineProcessor: |
| 17 | def __init__(self, tokenizer): |
| 18 | self.tokenizer = tokenizer |
| 19 | self.lock = threading.Lock() |
| 20 | |
| 21 | def process_line(self, line_pair: Tuple[str, str]) -> Optional[Dict]: |
| 22 | line1, line2 = line_pair |
| 23 | |
| 24 | line1, line2 = line1.strip(), line2.strip() |
| 25 | if not line1 or not line2: |
| 26 | return None |
| 27 | |
| 28 | parts1, parts2 = line1.split(maxsplit=1), line2.split(maxsplit=1) |
| 29 | if len(parts1) != 2 or len(parts2) != 2: |
| 30 | return None |
| 31 | |
| 32 | utt1, utt2 = parts1[0], parts2[0] |
| 33 | wav_path, text = parts1[1], parts2[1] |
| 34 | |
| 35 | if utt1 != utt2: |
| 36 | return {"error": f"UTT mismatch: {utt1} vs {utt2}"} |
| 37 | |
| 38 | try: |
| 39 | if wav_path.startswith("http"): |
| 40 | response = urlopen(wav_path) |
| 41 | if response.status != 200: |
| 42 | return {"error": f"WAV not found: {wav_path}"} |
| 43 | audio_file = BytesIO(response.read()) |
| 44 | duration = sf.info(audio_file).duration |
| 45 | else: |
| 46 | if not os.path.exists(wav_path): |
| 47 | return {"error": f"WAV not found: {wav_path}"} |
| 48 | duration = sf.info(wav_path).duration |
| 49 | |
| 50 | data = { |
| 51 | "messages": [ |
| 52 | {"role": "system", "content": "You are a helpful assistant."}, |
| 53 | { |
| 54 | "role": "user", |
| 55 | "content": f"语音转写:<|startofspeech|>!{wav_path}<|endofspeech|>", |
| 56 | }, |
| 57 | {"role": "assistant", "content": text}, |
| 58 | ], |
| 59 | "speech_length": int((duration * 1000 - 25) // 10 + 1), |
| 60 | "text_length": len(self.tokenizer.tokenize(text)), |
| 61 | } |
| 62 | return {"success": data, "utt": utt1} |
| 63 | |
| 64 | except Exception as e: |
| 65 | return {"error": f"Error processing {wav_path}: {str(e)}"} |
| 66 | |
| 67 | |
| 68 | @hydra.main(config_name=None, version_base=None) |