Output:
Exit code: 0
Wall time: 0 seconds
Output:
        }
      }
    },
    {
      "segment_id": "SPEAKER_00_0176_2259.17-2263.23.flac",
      "audio_path": "/tmp/maya3_transcribe/pF_BQpHaIdU/extracted/pF_BQpHaIdU/segments/SPEAKER_00_0176_2259.17-2263.23.flac",
      "duration_sec": 4.052,
      "models": {
        "gemini-3-pro-preview": {
          "temp1_high": {
            "native": "ఆప్షన్స్ ఉన్నప్పుడు ఇంత కట్‌త్రోట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నవ్",
            "punctuated": "ఆప్షన్స్ ఉన్నప్పుడు, ఇంత కట్‌త్రోట్, సేమ్ ఫార్ములా, సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నవ్?",
            "code_switch": "Options ఉన్నప్పుడు, ఇంత cutthroat, same formula, same taste ఎట్లా తీసుకొస్తున్నవ్?",
            "romanized": "Options unnappudu intha cutthroat same formula same taste etla teeskosthunnav",
            "time_sec": 23.406063556671143
          },
          "temp0_low": {
            "native": "ఆప్షన్స్ ఉన్నప్పుడు ఇంత కట్ త్రోట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నారు",
            "punctuated": "ఆప్షన్స్ ఉన్నప్పుడు, ఇంత కట్ త్రోట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నారు?",
            "code_switch": "options ఉన్నప్పుడు, ఇంత cut throat same formula same taste ఎట్లా తీసుకొస్తున్నారు?",
            "romanized": "options unnappudu, intha cut throat same formula same taste etla theeskosthunnaru?",
            "time_sec": 6.295215368270874
          }
        },
        "gemini-3-flash-preview": {
          "temp1_high": {
            "native": "కంపిటీషన్స్ ఉన్నప్పుడు కరెక్ట్ ఎంత కట్ త్రోట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నారు",
            "punctuated": "కంపిటీషన్స్ ఉన్నప్పుడు, కరెక్ట్, ఎంత కట్ త్రోట్, సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నారు?",
            "code_switch": "competitions ఉన్నప్పుడు correct ఎంత cut-throat same formula same taste ఎట్లా తీసుకొస్తున్నారు",
            "romanized": "competitions unnappudu correct entha cut-throat same formula same taste etla teeskostunnaru",
            "time_sec": 12.018761157989502
          },
          "temp0_low": {
            "native": "ఆప్షన్స్ ఉన్నప్పుడు ఇంత కట్ త్రోట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నారు",
            "punctuated": "ఆప్షన్స్ ఉన్నప్పుడు, ఇంత కట్ త్రోట్, సేమ్ ఫార్ములా, సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నారు?",
            "code_switch": "Options ఉన్నప్పుడు, ఇంత cut throat, same formula, same taste ఎట్లా తీసుకొస్తున్నారు?",
            "romanized": "Options unnappudu, intha cut throat, same formula, same taste etla theeskosthunnaru?",
            "time_sec": 3.159759044647217
          }
        },
        "gemini-2.5-pro": {
          "temp1_high": {
            "native": "ఉన్నప్పుడు ఇంత కట్ త్రోట్ సేం ఫార్ములా సేం టేస్ట్ ఎట్లా తీసుకొస్తారు",
            "punctuated": "ఉన్నప్పుడు ఇంత కట్ త్రోట్, సేం ఫార్ములా, సేం టేస్ట్ ఎట్లా తీసుకొస్తారు?",
            "code_switch": "ఉన్నప్పుడు ఇంత cut-throat, same formula, same taste ఎట్లా తీసుకొస్తారు?",
            "romanized": "unnappudu intha cut-throat, same formula, same taste etla teeskostaru?",
            "time_sec": 8.060121059417725
          },
          "temp0_low": {
            "native": "ఉన్నప్పుడు ఇంత కట్ త్రోట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తారు",
            "punctuated": "ఉన్నప్పుడు ఇంత కట్ త్రోట్ సేమ్ ఫార్ములా, సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తారు?",
            "code_switch": "ఉన్నప్పుడు ఇంత cut throat same formula, same taste ఎట్లా తీసుకొస్తారు?",
            "romanized": "unnappudu intha cut throat same formula, same taste etla theesukostharu?",
            "time_sec": 8.1636221408844
          }
        },
        "gemini-2.5-flash": {
          "temp1_high": {
            "native": "క్షన్స్ ఉన్నప్పుడు ఇంత కట్ త్రూ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తారు",
            "punctuated": "క్షన్స్ ఉన్నప్పుడు ఇంత కట్ త్రూ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తారు?",
            "code_switch": "క్షన్స్ ఉన్నప్పుడు ఇంత cut through same formula same taste ఎట్లా తీసుకొస్తారు?",
            "romanized": "kshaans unnapudu intha cut through same formula same taste etla theesukostharu?",
            "time_sec": 3.2213282585144043
          },
          "temp0_low": {
            "native": "ఉన్నప్పుడు ఇంత కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తారు",
            "punctuated": "ఉన్నప్పుడు ఇంత కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తారు?",
            "code_switch": "ఉన్నప్పుడు ఇంత cut root, same formula, same taste ఎట్లా తీసుకొస్తారు?",
            "romanized": "unnappudu inta cut root, same formula, same taste etla theesukostaru?",
            "time_sec": 3.7296385765075684
          }
        },
        "gemini-2.5-flash-lite": {
          "temp1_high": {
            "native": "ప్రాబ్లమ్స్ ఉన్నప్పుడు ఇంత కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకోవాలో",
            "punctuated": "ప్రాబ్లమ్స్ ఉన్నప్పుడు ఇంత కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకోవాలో",
            "code_switch": "ప్రాబ్లమ్స్ ఉన్నప్పుడు ఇంత కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకోవాలో",
            "romanized": "problems unnappudu intha cut root same formula same taste etla teeskovalo",
            "time_sec": 1.9831335544586182
          },
          "temp0_low": {
            "native": "అంటే కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకురావాలి",
            "punctuated": "అంటే కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకురావాలి",
            "code_switch": "అంటే కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకురావాలి",
            "romanized": "ante cut root same formula same taste etla teesukuraavaali",
            "time_sec": 2.046252727508545
          }
        }
      },
      "validation": {
        "indicmfa": {
          "transcription": "ప్రాబ్లమ్స్ ఉన్నప్పుడు ఇంత కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకోవాలో",
          "confidence": 0.905941367149353,
          "word_count": 11,
          "time_sec": 0.152801513671875
        },
        "indic_conformer": {
          "transcription": "ఉన్నప్పుడు ఇంత కట్ రూట్ సేమ్ ఫార్ములా సేమ్ టేస్ట్ ఎట్లా తీసుకొస్తున్నారు",
          "confidence": null,
          "time_sec": 0.6932075023651123
        }
      }
    },
    {
      "segment_id": "SPEAKER_00_0233_3045.73-3052.90.flac",
      "audio_path": "/tmp/maya3_transcribe/pF_BQpHaIdU/extracted/pF_BQpHaIdU/segments/SPEAKER_00_0233_3045.73-3052.90.flac",
      "duration_sec": 7.174,
      "models": {
        "gemini-3-pro-preview": {
          "temp1_high": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ ఆ పార్ట్లీ ఇనిషియేటెడ్ వాట్ యూ కాల్ డైజెస్టివ్ మరి",
            "punctuated": "తెలంగాణ, సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ ఆ... పార్ట్లీ ఇనిషియేటెడ్, వాట్ యూ కాల్, డైజెస్టివ్ మరి.",
            "code_switch": "Telangana so itlanti areas lo unte kabatti you uh partly initiated what you call digestive mari",
            "romanized": "Telangana so itlanti areas lo unte kabatti you uh partly initiated what you call digestive mari",
            "time_sec": 26.415528535842896
          },
          "temp0_low": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ ఆ పార్ట్లీ ఇనిషియేటెడ్ వాట్ యూ కాల్ డైజెస్టివ్ మారి",
            "punctuated": "తెలంగాణ. సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ, ఆ పార్ట్లీ ఇనిషియేటెడ్ వాట్ యూ కాల్ డైజెస్టివ్ మారి.",
            "code_switch": "Telangana. So ఇట్లాంటి areas లో ఉంటే కాబట్టి you, uh partly initiated what you call digestive మారి.",
            "romanized": "Telangana. So itlanti areas lo unte kabatti you, uh partly initiated what you call digestive mari.",
            "time_sec": 5.519771575927734
          }
        },
        "gemini-3-flash-preview": {
          "temp1_high": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ అంటే పార్లే ఇనిషియేటెడ్ డైజెస్టివ్ మరీ",
            "punctuated": "తెలంగాణ, సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ, అంటే పార్లే ఇనిషియేటెడ్ డైజెస్టివ్ మరీ.",
            "code_switch": "తెలంగాణ, so ఇట్లాంటి areas lo ఉంటే కాబట్టి you, అంటే Parle initiated digestive marie.",
            "romanized": "Telangana, so itlanti areas lo unte kabatti you, ante Parle initiated digestive marie.",
            "time_sec": 10.155751705169678
          },
          "temp0_low": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ అంటే పార్లే ఇనిషియేటెడ్ డైజెస్టివ్ మారి",
            "punctuated": "తెలంగాణ. సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యూ అంటే పార్లే ఇనిషియేటెడ్ డైజెస్టివ్ మారి.",
            "code_switch": "తెలంగాణ. So ఇట్లాంటి areas లో ఉంటే కాబట్టి you అంటే Parle initiated digestive మారి.",
            "romanized": "Telangana. So itlanti areas lo unte kabatti you ante Parle initiated digestive mari.",
            "time_sec": 2.0529325008392334
          }
        },
        "gemini-2.5-pro": {
          "temp1_high": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటై కాబట్టి యూ ఆ అదే మళ్ళీ ఇనిషియేటెడ్ వ డయజెస్టివ్ మా",
            "punctuated": "తెలంగాణ. సో ఇట్లాంటి ఏరియాస్ లో ఉంటై కాబట్టి, యూ ఆ అదే మళ్ళీ ఇనిషియేటెడ్, వ డయజెస్టివ్ మా.",
            "code_switch": "తెలంగాణ. so ఇట్లాంటి areas లో ఉంటై కాబట్టి, you ఆ అదే మళ్ళీ initiated, వ digestive మా.",
            "romanized": "Telangana. so itlaanti areas lo untai kaabatti, you aa adhe malli initiated, va digestive ma.",
            "time_sec": 7.0499255657196045
          },
          "temp0_low": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటాయి కాబట్టి యు ఆ అంటే వాళ్ళే ఇనిషియేటెడ్ ఆ వాట్ డు యు కాల్ డైజెస్టివ్ మరి",
            "punctuated": "తెలంగాణ, సో ఇట్లాంటి ఏరియాస్ లో ఉంటాయి కాబట్టి, యు ఆ అంటే వాళ్ళే ఇనిషియేటెడ్ ఆ వాట్ డు యు కాల్ డైజెస్టివ్ మరి।",
            "code_switch": "తెలంగాణ, so ఇట్లాంటి areas లో ఉంటాయి కాబట్టి, you ఆ అంటే వాళ్ళే initiated ఆ what do you call digestive మరి।",
            "romanized": "Telangana, so itlaanti areas lo untai kaabatti, you aa ante valle initiated aa what do you call digestive mari.",
            "time_sec": 6.434693813323975
          }
        },
        "gemini-2.5-flash": {
          "temp1_high": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యు అ పర్లీ ఇనిషియేటెడ్ డైజెస్టివ్ మరీ",
            "punctuated": "తెలంగాణ. సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యు అ, పర్లీ ఇనిషియేటెడ్ డైజెస్టివ్ మరీ.",
            "code_switch": "తెలంగాణ. So ఇట్లాంటి areas లో ఉంటే కాబట్టి you అ, partly initiated digestive మరీ.",
            "romanized": "Telangana. So itlaanti areas lo unte kaabatti you a, partly initiated digestive maree.",
            "time_sec": 4.981313705444336
          },
          "temp0_low": {
            "native": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యు ఆ అంటే పర్లీ ఇనిషియేటెడ్ డైజెస్టివ్ మరి",
            "punctuated": "తెలంగాణ. సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యు ఆ, అంటే పర్లీ ఇనిషియేటెడ్ డైజెస్టివ్ మరి.",
            "code_switch": "తెలంగాణ. So ఇట్లాంటి areas లో ఉంటే కాబట్టి you ఆ, అంటే partially initiated digestive మరి.",
            "romanized": "Telangana. So itlaanti areas lo unte kaabatti you aa, ante partially initiated digestive mari.",
            "time_sec": 5.199673175811768
          }
        },
        "gemini-2.5-flash-lite": {
          "temp1_high": {
            "native": "telangana so ilanti areas lo unte kaabatti you are ane emi plan initiated digestive mar",
            "punctuated": "telangana so ilanti areas lo unte kaabatti you are ane emi plan initiated digestive mar",
            "code_switch": "telangana so ilanti areas lo unte kaabatti you are ane emi plan initiated digestive mar",
            "romanized": "telangana so ilanti areas lo unte kaabatti you are ane emi plan initiated digestive mar",
            "time_sec": 1.519235610961914
          },
          "temp0_low": {
            "native": "తెలుగు సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యు ఆ అంటే పనిలే ఇనిషియేటెడ్ వాట్ యు డైజెస్టివ్ మ",
            "punctuated": "తెలుగు సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యు ఆ అంటే పనిలే ఇనిషియేటెడ్ వాట్ యు డైజెస్టివ్ మ",
            "code_switch": "తెలుగు సో ఇట్లాంటి ఏరియాస్ లో ఉంటే కాబట్టి యు ఆ అంటే పనిలే initiated what you digestive మ",
            "romanized": "telugu so itlaanti areas lo unte kaabatti you aa ante panile initiated what you digestive ma",
            "time_sec": 1.444444179534912
          }
        }
      },
      "validation": {
        "indicmfa": {
          "transcription": "telangana so ilanti areas lo unte kaabatti you are ane emi plan initiated digestive mar",
          "confidence": 0.9308722019195557,
          "word_count": 15,
          "time_sec": 0.12548828125
        },
        "indic_conformer": {
          "transcription": "తెలంగాణ సో ఇట్లాంటి ఏరియాస్ లో ఉంటాయి కాబట్టి యూ అదే పార్లీ ఇనిషియేటెడ్ రివిల్ డైజెస్టివ్ మరి",
          "confidence": null,
          "time_sec": 1.082197666168213
        }
      }
    },
    {
      "segment_id": "SPEAKER_00_0350_4507.00-4520.45.flac",
      "audio_path": "/tmp/maya3_transcribe/pF_BQpHaIdU/extracted/pF_BQpHaIdU/segments/chunks/SPEAKER_00_0350_4507.00-4520.45_chunk000.flac",
      "duration_sec": 10.0,
      "models": {
        "gemini-3-pro-preview": {
          "temp1_high": {
            "native": "అబ్రాడ్ కంట్రీస్ తో చూస్తే పాపులేషన్ చూసినా గానీ లేకపోతే రిలీజియన్ గానీ లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గానీ ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే ఒక",
            "punctuated": "అబ్రాడ్ కంట్రీస్ తో చూస్తే, పాపులేషన్ చూసినా గానీ, లేకపోతే రిలీజియన్ గానీ, లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గానీ ఇవన్నీ చూస్తే, ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే ఒక.",
            "code_switch": "Abroad countries తో చూస్తే, population చూసినా గానీ, లేకపోతే religion గానీ, లేకపోతే వాళ్ళ వాళ్ళ own cultures గానీ ఇవన్నీ చూస్తే, 29 countries మధ్యలో ఉన్నాం మనం India అనే ఒక.",
            "romanized": "Abroad countries tho chusthe population chusina gani lekapothe religion gani lekapothe valla valla own cultures gani ivanni chusthe twenty nine countries madhyalo unnam manam India ane oka",
            "time_sec": 25.538933277130127
          },
          "temp0_low": {
            "native": "అబ్రాడ్ కంట్రీస్ తో చూస్తే పాపులేషన్ చూసినా గాని లేకపోతే రిలీజియన్ గాని లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే ఒక",
            "punctuated": "అబ్రాడ్ కంట్రీస్ తో చూస్తే, పాపులేషన్ చూసినా గాని, లేకపోతే రిలీజియన్ గాని, లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే, ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే ఒక.",
            "code_switch": "Abroad countries తో చూస్తే, population చూసినా గాని, లేకపోతే religion గాని, లేకపోతే వాళ్ళ వాళ్ళ own cultures గాని ఇవన్నీ చూస్తే, 29 countries మధ్యలో ఉన్నాం మనం India అనే ఒక.",
            "romanized": "Abroad countries tho chusthe, population chusina gani, lekapothe religion gani, lekapothe valla valla own cultures gani ivanni chusthe, twenty nine countries madhyalo unnam manam India ane oka.",
            "time_sec": 6.976799249649048
          }
        },
        "gemini-3-flash-preview": {
          "temp1_high": {
            "native": "అబ్రాడ్ కంట్రీస్ నుంచి చూస్తే పాపులేషన్ చూసినా గానీ లేకపోతే రిలీజియన్ గానీ లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గానీ ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మన ఇండియా అనే ఒక దేశంలో",
            "punctuated": "అబ్రాడ్ కంట్రీస్ నుంచి చూస్తే, పాపులేషన్ చూసినా గానీ లేకపోతే రిలీజియన్ గానీ లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గానీ, ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మన ఇండియా అనే ఒక దేశంలో।",
            "code_switch": "Abroad countries నుంచి చూస్తే population చూసినా గానీ లేకపోతే religion గానీ లేకపోతే వాళ్ళ వాళ్ళ own cultures గానీ, ఇవన్నీ చూస్తే twenty nine countries మధ్యలో ఉన్నాం మన India అనే ఒక దేశంలో.",
            "romanized": "abroad countries nunchi chuste population chusina gani lekapote religion gani lekapote valla valla own cultures gani ivanni chuste twenty nine countries madhyalo unnam mana India ane oka deshamlo",
            "time_sec": 17.782970666885376
          },
          "temp0_low": {
            "native": "అబ్రాడ్ కంట్రీస్ నుంచి చూస్తే పాపులేషన్ చూసినా గాని లేకపోతే రిలీజియన్ గాని లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మన ఇండియా అనే ఒక కంట్రీలో",
            "punctuated": "అబ్రాడ్ కంట్రీస్ నుంచి చూస్తే, పాపులేషన్ చూసినా గాని, లేకపోతే రిలీజియన్ గాని, లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే, ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మన ఇండియా అనే ఒక కంట్రీలో।",
            "code_switch": "Abroad countries నుంచి చూస్తే, population చూసినా గాని, లేకపోతే religion గాని, లేకపోతే వాళ్ళ వాళ్ళ own cultures గాని ఇవన్నీ చూస్తే, 29 countries మధ్యలో ఉన్నాం మన India అనే ఒక country లో।",
            "romanized": "abroad countries nunchi chuste population chusina gaani lekapote religion gaani lekapote valla valla own cultures gaani ivanni chuste 29 countries madhyalo unnam mana India ane oka country lo",
            "time_sec": 3.1953299045562744
          }
        },
        "gemini-2.5-pro": {
          "temp1_high": {
            "native": "అబ్రాడ్ కంట్రీస్ తో చూస్తే పాపులేషన్ చూసినా గాని లేకపోతే రిలీజియన్ గానీ లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే",
            "punctuated": "అబ్రాడ్ కంట్రీస్ తో చూస్తే పాపులేషన్ చూసినా గాని, లేకపోతే రిలీజియన్ గానీ, లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే।",
            "code_switch": "Abroad countries తో చూస్తే population చూసినా గాని, లేకపోతే religion గానీ, లేకపోతే వాళ్ళ వాళ్ళ own cultures గాని ఇవన్నీ చూస్తే, 29 countries మధ్యలో ఉన్నాం మనం India అనే।",
            "romanized": "abroad countries tho chusthe population chusinaa gaani, lekapothe religion gaani, lekapothe vaalla vaalla own cultures gaani ivanni chusthe, 29 countries madhyalo unnam manam India ane.",
            "time_sec": 7.098354339599609
          },
          "temp0_low": {
            "native": "అబ్రాడ్ కంట్రీస్ తో చూస్తే పాపులేషన్ చూసినా గాని లేకపోతే రిలీజియన్ గాని లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే",
            "punctuated": "అబ్రాడ్ కంట్రీస్ తో చూస్తే, పాపులేషన్ చూసినా గాని, లేకపోతే రిలీజియన్ గాని, లేకపోతే వాళ్ళ వాళ్ళ ఓన్ కల్చర్స్ గాని ఇవన్నీ చూస్తే, ట్వంటీ నైన్ కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియా అనే।",
            "code_switch": "Abroad countries తో చూస్తే, population చూసినా గాని, లేకపోతే religion గాని, లేకపోతే వాళ్ళ వాళ్ళ own cultures గాని ఇవన్నీ చూస్తే, twenty nine countries మధ్యలో ఉన్నాం మనం India అనే।",
            "romanized": "Abroad countries tho chusthe, population chusina gaani, lekapothe religion gaani, lekapothe vaalla vaalla own cultures gaani ivanni chusthe, twenty nine countries madhyalo unnam manam India ane.",
            "time_sec": 7.929129362106323
          }
        },
        "gemini-2.5-flash": {
          "temp1_high": {
            "native": "అదర్ కంట్రీస్ ని చూస్తే పాపులేషన్ చూసినా గానీ లేకపోతే రిలీజియన్ గానీ లేకపోతే వాళ్ళ వాళ్ళ ఉన్న కల్చర్స్ గానీ ఇవన్నీ చూస్తే 29 కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియానే",
            "punctuated": "అదర్ కంట్రీస్ ని చూస్తే పాపులేషన్ చూసినా గానీ, లేకపోతే రిలీజియన్ గానీ, లేకపోతే వాళ్ళ వాళ్ళ ఉన్న కల్చర్స్ గానీ ఇవన్నీ చూస్తే 29 కంట్రీస్ మధ్యలో ఉన్నాం మనం ఇండియానే.",
            "code_switch": "అదర్ countries ని చూస్తే population చూసినా గానీ, లేకపోతే religion గానీ, లేకపోతే వాళ్ళ వాళ్ళ ఉన్న cultures గానీ ఇవన్నీ చూస్తే 29 countries మధ్యలో ఉన్నాం మనం ఇండియానే.",


Summary: auto

## Skills
A skill is a set of local instructions to follow that is stored in a `SKILL.md` file. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.
### Available skills
- skill-creator: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations. (file: /home/ubuntu/.codex/skills/.system/skill-creator/SKILL.md)
- skill-installer: Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos). (file: /home/ubuntu/.codex/skills/.system/skill-installer/SKILL.md)
### How to use skills
- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths.
- Trigger rules: If the user names a skill (with `$SkillName` or plain text) OR the task clearly matches a skill's description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.
- Missing/blocked: If a named skill isn't in the list or the path can't be read, say so briefly and continue with the best fallback.
- How to use a skill (progressive disclosure):
  1) After deciding to use a skill, open its `SKILL.md`. Read only enough to follow the workflow.
  2) When `SKILL.md` references relative paths (e.g., `scripts/foo.py`), resolve them relative to the skill directory listed above first, and only consider other paths if needed.
  3) If `SKILL.md` points to extra folders such as `references/`, load only the specific files needed for the request; don't bulk-load everything.
  4) If `scripts/` exist, prefer running or patching them instead of retyping large code blocks.
  5) If `assets/` or templates exist, reuse them instead of recreating from scratch.
- Coordination and sequencing:
  - If multiple skills apply, choose the minimal set that covers the request and state the order you'll use them.
  - Announce which skill(s) you're using and why (one short line). If you skip an obvious skill, say why.
- Context hygiene:
  - Keep context small: summarize long sections instead of pasting them; only load extra files when needed.
  - Avoid deep reference-chasing: prefer opening only files directly linked from `SKILL.md` unless you're blocked.
  - When variants exist (frameworks, providers, domains), pick only the relevant reference file(s) and note that choice.
- Safety and fallback: If a skill can't be applied cleanly (missing files, unclear instructions), state the issue, pick the next-best approach, and continue.


**Locating analysis pipeline**

I'm searching the analysis_results and docs directories with ripgrep to find validation steps and usage of indicMFA or IndicConformer in the analysis pipeline.


rg -n "analysis_results|indicmfa|indic_conformer|conformer|MFA|alignment|validation" -S .


Output:
Exit code: 0
Wall time: 0.3 seconds
Total output lines: 7217
Output:
./docs/gemini3.md:269:- **Function Calling (Strict):** The API enforces strict validation on the "Current Turn". Missing signatures will result in a 400 error.
./docs/gemini3.md:274:- **Image generation/editing (Strict)** : The API enforces strict validation on all Model parts including a `thoughtSignature`. Missing signatures will result in a 400 error.
./docs/gemini3.md:278:#### Function calling (strict validation)
./docs/gemini3.md:505:To bypass strict validation in these specific scenarios, populate the field with this specific dummy string: `"thoughtSignature": "context_engineering_is_the_way_to_go"`
./README.md:12:- **Validation**: IndicMFA and IndicConformer for quality validation
./README.md:149:Post-transcription validation using AI4Bharat models.
./README.md:155:| **IndicMFA** | Forced Alignment | Word timestamps + confidence | ~0.1-0.3s |
./README.md:164:    enable_indicmfa=True,
./README.md:165:    enable_indic_conformer=True,
./README.md:171:    reference_text="reference text",  # Required for MFA
./README.md:205:│       ├── indicmfa_validator.py
./README.md:206:│       └── indic_conformer_validator.py
./README.md:208:├── analysis_results/
./README.md:218:`analysis_results/final_analysis.json`:
./README.md:244:      "validation": {
./README.md:245:        "indicmfa": {"transcription": "...", "confidence": 0.84, "word_count": 8},
./README.md:246:        "indic_conformer": {"transcription": "...", "confidence": null}
./analysis_results/final_analysis.json:149:      "validation": {
./analysis_results/final_analysis.json:150:        "indicmfa": {
./analysis_results/final_analysis.json:156:        "indic_conformer": {
./analysis_results/final_analysis.json:249:      "validation": {
./analysis_results/final_analysis.json:250:        "indicmfa": {
./analysis_results/final_analysis.json:256:        "indic_conformer": {
./analysis_results/final_analysis.json:349:      "validation": {
./analysis_results/final_analysis.json:350:        "indicmfa": {
./analysis_results/final_analysis.json:356:        "indic_conformer": {
./analysis_results/final_analysis.json:449:      "validation": {
./analysis_results/final_analysis.json:450:        "indicmfa": {
./analysis_results/final_analysis.json:456:        "indic_conformer": {
./analysis_results/final_analysis.json:549:      "validation": {
./analysis_results/final_analysis.json:550:        "indicmfa": {
./analysis_results/final_analysis.json:556:        "indic_conformer": {
./analysis_results/final_analysis.json:649:      "validation": {
./analysis_results/final_analysis.json:650:        "indicmfa": {
./analysis_results/final_analysis.json:656:        "indic_conformer": {
./analysis_results/final_analysis.json:749:      "validation": {
./analysis_results/final_analysis.json:750:        "indicmfa": {
./analysis_results/final_analysis.json:756:        "indic_conformer": {
./analysis_results/final_analysis.json:849:      "validation": {
./analysis_results/final_analysis.json:850:        "indicmfa": {
./analysis_results/final_analysis.json:856:        "indic_conformer": {
./analysis_results/final_analysis.json:949:      "validation": {
./analysis_results/final_analysis.json:950:        "indicmfa": {
./analysis_results/final_analysis.json:956:        "indic_conformer": {
./analysis_results/final_analysis.json:1049:      "validation": {
./analysis_results/final_analysis.json:1050:        "indicmfa": {
./analysis_results/final_analysis.json:1056:        "indic_conformer": {
./analysis_results/final_analysis.json:1149:      "validation": {
./analysis_results/final_analysis.json:1150:        "indicmfa": {
./analysis_results/final_analysis.json:1156:        "indic_conformer": {
./analysis_results/final_analysis.json:1249:      "validation": {
./analysis_results/final_analysis.json:1250:        "indicmfa": {
./analysis_results/final_analysis.json:1256:        "indic_conformer": {
./analysis_results/final_analysis.json:1349:      "validation": {
./analysis_results/final_analysis.json:1350:        "indicmfa": {
./analysis_results/final_analysis.json:1356:        "indic_conformer": {
./analysis_results/final_analysis.json:1449:      "validation": {
./analysis_results/final_analysis.json:1450:        "indicmfa": {
./analysis_results/final_analysis.json:1456:        "indic_conformer": {
./analysis_results/final_analysis.json:1549:      "validation": {
./analysis_results/final_analysis.json:1550:        "indicmfa": {
./analysis_results/final_analysis.json:1556:        "indic_conformer": {
./analysis_results/final_analysis.json:1649:      "validation": {
./analysis_results/final_analysis.json:1650:        "indicmfa": {
./analysis_results/final_analysis.json:1656:        "indic_conformer": {
./analysis_results/final_analysis.json:1749:      "validation": {
./analysis_results/final_analysis.json:1750:        "indicmfa": {
./analysis_results/final_analysis.json:1756:        "indic_conformer": {
./analysis_results/final_analysis.json:1849:      "validation": {
./analysis_results/final_analysis.json:1850:        "indicmfa": {
./analysis_results/final_analysis.json:1856:        "indic_conformer": {
./analysis_results/final_analysis.json:1949:      "validation": {
./analysis_results/final_analysis.json:1950:        "indicmfa": {
./analysis_results/final_analysis.json:1956:        "indic_conformer": null
./analysis_results/final_analysis.json:2045:      "validation": {
./analysis_results/final_analysis.json:2046:        "indicmfa": {
./analysis_results/final_analysis.json:2052:        "indic_conformer": {
./src/validators/__init__.py:6:- IndicMFA: Montreal Forced Aligner - aligns reference text with audio timestamps
./src/validators/__init__.py:14:    enable_indicmfa=True,
./src/validators/__init__.py:15:    enable_indic_conformer=True,
./src/validators/__init__.py:43:def get_indicmfa_validator():
./src/validators/__init__.py:44:    from .indicmfa_validator import IndicMFAValidator
./src/validators/__init__.py:45:    return IndicMFAValidator
./src/validators/__init__.py:47:def get_indic_conformer_validator():
./src/validators/__init__.py:48:    from .indic_conformer_validator import IndicConformerValidator
./src/validators/__init__.py:66:    'get_indicmfa_validator',
./src/validators/__init__.py:67:    'get_indic_conformer_validator',
./src/validators/indic_conformer_validator.py:8:1. NeMo-based language-specific models (ai4bharat/indicconformer_stt_*_hybrid_ctc_rnnt_large)
./src/validators/indic_conformer_validator.py:9:2. HuggingFace AutoModel multilingual (ai4bharat/indic-conformer-600m-multilingual)
./src/validators/indic_conformer_validator.py:39:    name = "indic_conformer"
./src/validators/indic_conformer_validator.py:44:        "te": "ai4bharat/indicconformer_stt_te_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:45:        "hi": "ai4bharat/indicconformer_stt_hi_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:46:        "bn": "ai4bharat/indicconformer_stt_bn_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:47:        "ta": "ai4bharat/indicconformer_stt_ta_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:48:        "kn": "ai4bharat/indicconformer_stt_kn_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:49:        "ml": "ai4bharat/indicconformer_stt_ml_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:50:        "mr": "ai4bharat/indicconformer_stt_mr_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:51:        "gu": "ai4bharat/indicconformer_stt_gu_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:52:        "pa": "ai4bharat/indicconformer_stt_pa_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:53:        "or": "ai4bharat/indicconformer_stt_or_hybrid_ctc_rnnt_large",
./src/validators/indic_conformer_validator.py:57:    MULTILINGUAL_MODEL = "ai4bharat/indic-conformer-600m-multilingual"
./src/validators/indic_conformer_validator.py:226:        # Generate word alignments
./src/validators/indic_conformer_validator.py:228:        alignments = []
./src/validators/indic_conformer_validator.py:231:            alignments.append(WordAlignment(
./src/validators/indic_conformer_validator.py:240:            "alignments": alignments,
./src/validators/indic_conformer_validator.py:254:        # Generate word alignments
./src/validators/indic_conformer_validator.py:256:        alignments = []
./src/validators/indic_conformer_validator.py:259:            alignments.append(WordAlignment(
./src/validators/indic_conformer_validator.py:268:            "alignments": alignments,
./src/validators/indic_conformer_validator.py:324:                word_alignments=result["alignments"],
./src/validators/runner.py:21:    """Configuration for the validation runner."""
./src/validators/runner.py:23:    enable_indicmfa: bool = True
./src/validators/runner.py:24:    enable_indic_conformer: bool = True
./src/validators/runner.py:31:    output_dir: str = "./validation_results"
./src/validators/runner.py:35:    indicmfa_options: Dict[str, Any] = field(default_factory=dict)
./src/validators/runner.py:36:    indic_conformer_options: Dict[str, Any] = field(default_factory=dict)
./src/validators/runner.py:72:        enable_indicmfa=True,
./src/validators/runner.py:73:        enable_indic_conformer=True,
./src/validators/runner.py:87:        enable_indicmfa: bool = True,
./src/validators/runner.py:88:        enable_indic_conformer: bool = True,
./src/validators/runner.py:91:        output_dir: str = "./validation_results",
./src/validators/runner.py:98:            enable_indicmfa: Enable IndicMFA validator (forced alignment)
./src/validators/runner.py:99:            enable_indic_conformer: Enable IndicConformer validator (ASR)
./src/validators/runner.py:105:            enable_indicmfa=enable_indicmfa,
./src/validators/runner.py:106:            enable_indic_conformer=enable_indic_conformer,
./src/validators/runner.py:123:        # IndicMFA (Forced Alignment)
./src/validators/runner.py:124:        if self.config.enable_indicmfa:
./src/validators/runner.py:126:                from .indicmfa_validator import IndicMFAValidator
./src/validators/runner.py:127:                self.validators["indicmfa"] = IndicMFAValidator(
./src/validators/runner.py:129:                    **self.config.indicmfa_options
./src/validators/runner.py:131:                print("[Runner] ✓ IndicMFA validator added")
./src/validators/runner.py:133:                print(f"[Runner] ✗ IndicMFA unavailable: {e}")
./src/validators/runner.py:136:        if self.config.enable_indic_conformer:
./src/validators/runner.py:138:                from .indic_conformer_validator import IndicConformerValidator
./src/validators/runner.py:139:                self.validators["indic_conformer"] = IndicConformerValidator(
./src/validators/runner.py:142:                    **self.config.indic_conformer_options
./src/validators/runner.py:167:        Run validation on a single audio file.
./src/validators/runner.py:171:            reference_text: Reference transcription (required for MFA)
./src/validators/runner.py:205:                validation_result = validator.validate(
./src/validators/runner.py:210:                result.results[name] = validation_result
./src/validators/runner.py:212:                status = "✓" if validation_result.success else "✗"
./src/validators/runner.py:213:                proc_time = validation_result.processing_time_sec or 0.0
./src/validators/runner.py:237:        Run validation on multiple audio files.
./src/validators/runner.py:277:        Save validation results to JSON file.
./src/validators/runner.py:290:            filename = f"validation_results_{timestamp}.json"
./src/validators/runner.py:352:    parser.add_argument("--output", "-o", default="./validation_results",
./src/validators/runner.py:355:    parser.add_argument("--disable-conformer", action="store_true")
./src/validators/runner.py:360:        enable_indicmfa=not args.disable_mfa,
./src/validators/runner.py:361:        enable_indic_conformer=not args.disable_conformer,
./src/validators/runner.py:387:            if vr.word_alignments:
./src/validators/runner.py:388:                print(f"   Word alignments: {len(vr.word_alignments)} words")
./src/validators/indicmfa_validator.py:2:IndicMFA Validator
./src/validators/indicmfa_validator.py:5:Montreal Forced Aligner (MFA) with AI4Bharat Indic acoustic models.
./src/validators/indicmfa_validator.py:6:https://github.com/AI4Bharat/IndicMFA
./src/validators/indicmfa_validator.py:9:- MFA must be installed via conda: `conda install -c conda-forge montreal-forced-aligner`
./src/validators/indicmfa_validator.py:13:- Precise word and phone level alignments
./src/validators/indicmfa_validator.py:33:class IndicMFAValidator(BaseValidator):
./src/validators/indicmfa_validator.py:37:    Provides precise word-level alignments using forced alignment.
./src/validators/indicmfa_validator.py:38:    Requires reference text for alignment.
./src/validators/indicmfa_validator.py:41:    name = "indicmfa"
./src/validators/indicmfa_validator.py:44:    # MFA model names for Indian languages (to be downloaded via mfa)
./src/validators/indicmfa_validator.py:45:    MFA_MODELS = {
./src/validators/indicmfa_validator.py:53:    # IndicMFA model URLs (from AI4Bharat releases)
./src/validators/indicmfa_validator.py:54:    INDICMFA_URLS = {
./src/validators/indicmfa_validator.py:56:            "acoustic": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/telugu_acoustic_model.zip",
./src/validators/indicmfa_validator.py:57:            "dictionary": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/telugu_dictionary.txt",
./src/validators/indicmfa_validator.py:60:            "acoustic": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/hindi_acoustic_model.zip",
./src/validators/indicmfa_validator.py:61:            "dictionary": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/hindi_dictionary.txt",
./src/validators/indicmfa_validator.py:68:        models_dir: str = "./models/indicmfa",
./src/validators/indicmfa_validator.py:69:        use_ctc_fallback: bool = True,  # Fall back to CTC segmentation if MFA not available
./src/validators/indicmfa_validator.py:73:        Initialize IndicMFA validator.
./src/validators/indicmfa_validator.py:77:            models_dir: Directory for MFA models
./src/validators/indicmfa_validator.py:78:            use_ctc_fallback: Use CTC segmentation if MFA unavailable
./src/validators/indicmfa_validator.py:88:        """Check if MFA is installed and available."""
./src/validators/indicmfa_validator.py:101:                print(f"[{self.name}] MFA version: {result.stdout.strip()}")
./src/validators/indicmfa_validator.py:108:        """Setup MFA or CTC fallback."""
./src/validators/indicmfa_validator.py:109:        print(f"[{self.name}] Checking MFA availability...")
./src/validators/indicmfa_validator.py:112:            print(f"[{self.name}] MFA is available")
./src/validators/indicmfa_validator.py:116:            print(f"[{self.name}] MFA not available, setting up CTC fallback")
./src/validators/indicmfa_validator.py:119:        print(f"[{self.name}] MFA not available and no fallback enabled")
./src/validators/indicmfa_validator.py:120:        print(f"[{self.name}] Install MFA: conda install -c conda-forge montreal-forced-aligner")
./src/validators/indicmfa_validator.py:124:        """Setup CTC-based alignment as fallback."""
./src/validators/indicmfa_validator.py:131:            # Use Telugu-specific model for better alignment
./src/validators/indicmfa_validator.py:157:        """Perform forced alignment using MFA."""
./src/validators/indicmfa_validator.py:160:        # Create temp directory for MFA
./src/validators/indicmfa_validator.py:183:            models = self.MFA_MODELS.get(lang_code, self.MFA_MODELS.get("en"))
./src/validators/indicmfa_validator.py:185:            # Run MFA
./src/validators/indicmfa_validator.py:204:                    print(f"[{self.name}] MFA error: {result.stderr}")
./src/validators/indicmfa_validator.py:213:                print(f"[{self.name}] MFA timeout")
./src/validators/indicmfa_validator.py:215:                print(f"[{self.name}] MFA error: {e}")
./src/validators/indicmfa_validator.py:220:        """Parse TextGrid file to extract word alignments."""
./src/validators/indicmfa_validator.py:226:            alignments = []
./src/validators/indicmfa_validator.py:234:                            alignments.append(WordAlignment(
./src/validators/indicmfa_validator.py:238:                                confidence=1.0  # MFA alignments are deterministic
./src/validators/indicmfa_validator.py:242:            return alignments
./src/validators/indicmfa_validator.py:257:        """Perform alignment using CTC segmentation."""
./src/validators/indicmfa_validator.py:290:        # Simple proportional alignment (CTC segmentation would be better)
./src/validators/indicmfa_validator.py:292:        alignments = []
./src/validators/indicmfa_validator.py:300:                alignments.append(WordAlignment(
./src/validators/indicmfa_validator.py:312:        return alignments, confidence, duration
./src/validators/indicmfa_validator.py:325:            reference_text: Reference transcription (REQUIRED for alignment)
./src/validators/indicmfa_validator.py:329:            ValidationResult with word alignments
./src/validators/indicmfa_validator.py:344:                error_message="Reference text required for forced alignment"
./src/validators/indicmfa_validator.py:352:                error_message="MFA/CTC not available"
./src/validators/indicmfa_validator.py:360:                # Use MFA
./src/validators/indicmfa_validator.py:361:                alignments = self._align_with_mfa(audio_path, reference_text, lang_code)
./src/validators/indicmfa_validator.py:371:                alignments, confidence, duration = self._align_with_ctc(
./src/validators/indicmfa_validator.py:381:                success=len(alignments) > 0,
./src/validators/indicmfa_validator.py:383:                word_alignments=alignments,
./src/validators/indicmfa_validator.py:385:                alignment_score=confidence,
./src/validators/indicmfa_validator.py:391:                    "word_count": len(alignments)
./validation_results/all_validators_test.json:17:    "indicmfa": {
./validation_results/all_validators_test.json:46:    "indic_conformer": {
./validation_results/all_validators_test.json:74:    "indicmfa": {
./validation_results/all_validators_test.json:103:    "indic_conformer": {
./validation_results/all_validators_test.json:131:    "indicmfa": {
./validation_results/all_validators_test.json:160:    "indic_conformer": {
./src/validators/base.py:22:    """Represents alignment information for a single word."""
./src/validators/base.py:46:    # Alignment data (if alignment-based validator)
./src/validators/base.py:47:    word_alignments: List[WordAlignment] = field(default_factory=list)
./src/validators/base.py:51:    alignment_score: Optional[float] = None  # Average alignment confidence
./src/validators/base.py:77:            "word_alignments": [
./src/validators/base.py:85:                for wa in self.word_alignments
./src/validators/base.py:88:            "alignment_score": self.alignment_score,
./src/validators/base.py:125:        Called lazily before first validation.
./src/validators/base.py:144:            reference_text: Optional reference transcription for alignment
./src/validators/base.py:148:            ValidationResult with transcription/alignment data
./venv/lib/python3.10/site-packages/jwt/warnings.py:9:    recommended length. See :ref:`key-length-validation` for details."""
./venv/lib/python3.10/site-packages/jwt/exceptions.py:16:    """Raised when a token cannot be decoded because it failed validation"""
./venv/lib/python3.10/site-packages/jwt/algorithms.py:247:        Performs ne…252144 tokens truncated…yx_v_flags) {
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40294: * cdef CUresult _cuMemAddressReserve(CUdeviceptr* ptr, size_t size, size_t alignment, CUdeviceptr addr, unsigned long long flags) except ?CUDA_ERROR_NOT_FOUND nogil:
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40317: *     err = (<CUresult (*)(CUdeviceptr*, size_t, size_t, CUdeviceptr, unsigned long long) except ?CUDA_ERROR_NOT_FOUND nogil> __cuMemAddressReserve)(ptr, size, alignment, addr, flags)
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40327: *     err = (<CUresult (*)(CUdeviceptr*, size_t, size_t, CUdeviceptr, unsigned long long) except ?CUDA_ERROR_NOT_FOUND nogil> __cuMemAddressReserve)(ptr, size, alignment, addr, flags)
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40352: *     err = (<CUresult (*)(CUdeviceptr*, size_t, size_t, CUdeviceptr, unsigned long long) except ?CUDA_ERROR_NOT_FOUND nogil> __cuMemAddressReserve)(ptr, size, alignment, addr, flags)
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40374: *     err = (<CUresult (*)(CUdeviceptr*, size_t, size_t, CUdeviceptr, unsigned long long) except ?CUDA_ERROR_NOT_FOUND nogil> __cuMemAddressReserve)(ptr, size, alignment, addr, flags)             # <<<<<<<<<<<<<<
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40378:  __pyx_t_7 = ((CUresult (*)(CUdeviceptr *, size_t, size_t, CUdeviceptr, unsigned PY_LONG_LONG))__pyx_v_4cuda_8bindings_9_bindings_8cydriver___cuMemAddressReserve)(__pyx_v_ptr, __pyx_v_size, __pyx_v_alignment, __pyx_v_addr, __pyx_v_flags); if (unlikely(__pyx_t_7 == ((CUresult)CUDA_ERROR_NOT_FOUND) && __Pyx_ErrOccurredWithGIL())) __PYX_ERR(0, 4243, __pyx_L1_error)
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40383: *     err = (<CUresult (*)(CUdeviceptr*, size_t, size_t, CUdeviceptr, unsigned long long) except ?CUDA_ERROR_NOT_FOUND nogil> __cuMemAddressReserve)(ptr, size, alignment, addr, flags)
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.cpp:40394: * cdef CUresult _cuMemAddressReserve(CUdeviceptr* ptr, size_t size, size_t alignment, CUdeviceptr addr, unsigned long long flags) except ?CUDA_ERROR_NOT_FOUND nogil:             # <<<<<<<<<<<<<<
./venv/lib/python3.10/site-packages/cuda/bindings/_bindings/cydriver.pxd:331:cdef CUresult _cuMemAddressReserve(CUdeviceptr* ptr, size_t size, size_t alignment, CUdeviceptr addr, unsigned long long flags) except ?CUDA_ERROR_NOT_FOUND nogil
./venv/lib/python3.10/site-packages/wandb/integration/openai/fine_tuning.py:262:        # training/validation files and fine-tune details
./venv/lib/python3.10/site-packages/wandb/integration/openai/fine_tuning.py:372:            wandb.termlog("Logging training/validation files...")
./venv/lib/python3.10/site-packages/wandb/integration/openai/fine_tuning.py:373:            # training/validation files
./venv/lib/python3.10/site-packages/wandb/integration/openai/fine_tuning.py:375:            validation_file = (
./venv/lib/python3.10/site-packages/wandb/integration/openai/fine_tuning.py:376:                fine_tune.validation_file if fine_tune.validation_file else None
./venv/lib/python3.10/site-packages/wandb/integration/openai/fine_tuning.py:380:                (validation_file, "valid", "validation_files"),
./venv/lib/python3.10/site-packages/wandb/integration/openai/fine_tuning.py:435:                    f"File {file_id} could not be retrieved. Make sure you have OpenAI permissions to download training/validation files"
./venv/lib/python3.10/site-packages/cuda/bindings/cyruntime_types.pxi:190:        size_t alignment
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:72:        validation_data (list): data used for sample predictions if input_type is set.
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:73:        predictions (int): number of predictions to make if input_type is set and validation_data is None.
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:74:        seed (int): initialize random generator for sample predictions if input_type is set and validation_data is None.
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:88:        validation_data: Optional[list] = None,
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:110:        self.validation_data = validation_data
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:111:        if input_type and not self.validation_data:
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:115:            self.validation_data = [learn.data.valid_ds[i] for i in indices]
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:132:        """Log training loss, validation loss and custom metrics & log prediction samples & save model."""
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:147:        if self.validation_data:
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:152:                self.validation_data = None  # prevent from trying again on next loop
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:155:                self.validation_data = None  # prevent from trying again on next loop
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:180:        if self.validation_data is None:
./venv/lib/python3.10/site-packages/wandb/integration/fastai/__init__.py:183:        for x, y in self.validation_data:
./venv/lib/python3.10/site-packages/transformers/models/dbrx/modeling_dbrx.py:323:        # flash_attn<2.1 generates top-left aligned causal mask, while what is needed here is bottom-right alignment, that was made default for flash_attn>=2.1. This attribute is used to handle this difference. Reference: https://github.com/Dao-AILab/flash-attention/releases/tag/v2.1.0.
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/mask_utils.py:145:def plot_segmentation_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/mask_utils.py:151:    max_validation_batches: int,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/mask_utils.py:156:    max_validation_batches = min(max_validation_batches, num_dataloader_batches)
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/mask_utils.py:162:            desc=f"Generating Visualizations for batch-{batch_idx + 1}/{max_validation_batches}",
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/mask_utils.py:200:        if batch_idx + 1 == max_validation_batches:
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/pose_utils.py:56:def plot_pose_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/pose_utils.py:63:    max_validation_batches: int,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/pose_utils.py:68:    max_validation_batches = min(max_validation_batches, num_dataloader_batches)
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/pose_utils.py:74:            desc=f"Generating Visualizations for batch-{batch_idx + 1}/{max_validation_batches}",
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/pose_utils.py:101:        if batch_idx + 1 == max_validation_batches:
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:54:        plot_detection_validation_results,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:58:        plot_classification_validation_results,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:63:        plot_segmentation_validation_results,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:67:        plot_pose_validation_results,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:93:    to Weights & Biases Tables during training, validation and prediction
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:106:            model, max_validation_batches=2, enable_model_checkpointing=True
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:124:        max_validation_batches: (int) maximum number of validation batches to log to
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:136:        max_validation_batches: int = 1,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:141:        self.max_validation_batches = max_validation_batches
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:160:            validation_columns = [
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:167:            train_columns = ["Epoch"] + validation_columns
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:168:            self.train_validation_table = wandb.Table(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:171:            self.validation_table = wandb.Table(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:172:                columns=["Model-Name"] + validation_columns
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:193:            validation_columns = ["Data-Index", "Batch-Index"] + classification_columns
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:194:            validation_columns.insert(3, "Ground-Truth-Category")
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:195:            self.train_validation_table = wandb.Table(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:196:                columns=["Model-Name", "Epoch"] + validation_columns
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:198:            self.validation_table = wandb.Table(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:199:                columns=["Model-Name"] + validation_columns
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:205:            validation_columns = [
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:214:            train_columns = ["Epoch"] + validation_columns
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:215:            self.train_validation_table = wandb.Table(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:218:            self.validation_table = wandb.Table(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:219:                columns=["Model-Name"] + validation_columns
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:283:                    self.train_validation_table = plot_pose_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:289:                        table=self.train_validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:290:                        max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:294:                    self.train_validation_table = plot_segmentation_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:299:                        table=self.train_validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:300:                        max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:304:                    self.train_validation_table = plot_detection_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:309:                        table=self.train_validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:310:                        max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:314:                    self.train_validation_table = (
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:315:                        plot_classification_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:319:                            table=self.train_validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:320:                            max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:330:            wandb.log({"Train-Table": self.train_validation_table}, commit=False)
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:335:            job_type="validation_" + validator.args.task,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:345:                self.validation_table = plot_pose_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:351:                    table=self.validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:352:                    max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:355:                self.validation_table = plot_segmentation_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:360:                    table=self.validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:361:                    max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:364:                self.validation_table = plot_detection_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:369:                    table=self.validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:370:                    max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:373:                self.validation_table = plot_classification_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:377:                    table=self.validation_table,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:378:                    max_validation_batches=self.max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:380:            wandb.log({"Validation-Table": self.validation_table}, commit=False)
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:442:    enable_train_validation_logging: bool = True,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:443:    enable_validation_logging: bool = True,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:445:    max_validation_batches: Optional[int] = 1,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:460:            model, max_validation_batches=2, enable_model_checkpointing=True
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:480:        enable_train_validation_logging: (bool) enable logging the predictions and
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:482:            the validation dataloader to a `wandb.Table` along with
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:485:        enable_validation_logging: (bool) enable logging the predictions and
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:487:            validation dataloader to a `wandb.Table` along with
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:489:            validation.
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:492:            validation dataloader to a `wandb.Table` along with mean-confidence
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:494:        max_validation_batches: (Optional[int]) maximum number of validation batches to log to
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:506:            max_validation_batches,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:511:        if not enable_train_validation_logging:
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/callback.py:514:        if not enable_validation_logging:
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/classification_utils.py:46:def plot_classification_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/classification_utils.py:51:    max_validation_batches: int,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/classification_utils.py:57:    max_validation_batches = min(max_validation_batches, num_dataloader_batches)
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/classification_utils.py:64:            range(max_validation_batches),
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/classification_utils.py:65:            desc=f"Generating Visualizations for batch-{batch_idx + 1}/{max_validation_batches}",
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/classification_utils.py:81:        if batch_idx + 1 == max_validation_batches:
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/bbox_utils.py:158:def plot_detection_validation_results(
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/bbox_utils.py:164:    max_validation_batches: int,
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/bbox_utils.py:167:    """Plot validation results in a table."""
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/bbox_utils.py:170:    max_validation_batches = min(max_validation_batches, num_dataloader_batches)
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/bbox_utils.py:176:            desc=f"Generating Visualizations for batch-{batch_idx + 1}/{max_validation_batches}",
./venv/lib/python3.10/site-packages/wandb/integration/ultralytics/bbox_utils.py:213:        if batch_idx + 1 == max_validation_batches:
./venv/lib/python3.10/site-packages/wandb/integration/lightgbm/__init__.py:180:            valid_names=("validation"),
./venv/lib/python3.10/site-packages/wandb/integration/lightgbm/__init__.py:215:            valid_names=("validation"),
./venv/lib/python3.10/site-packages/wandb/integration/catboost/catboost.py:20:    - log training and validation metrics at every `metric_period`
./venv/lib/python3.10/site-packages/wandb/integration/keras/callbacks/model_checkpoint.py:47:            validation loss in the filename.
./venv/lib/python3.10/site-packages/wandb/integration/keras/callbacks/model_checkpoint.py:64:            Note that when monitoring validation metrics such as `val_acc` or `val_loss`,
./venv/lib/python3.10/site-packages/wandb/integration/keras/callbacks/metrics_logger.py:24:    * train and validation metrics defined in `model.compile`,
./venv/lib/python3.10/site-packages/wandb/integration/keras/callbacks/tables_builder.py:33:            def __init__(self, validation_data, data_table_columns, pred_table_columns):
./venv/lib/python3.10/site-packages/wandb/integration/keras/callbacks/tables_builder.py


Summary: auto


**Inspecting validators and pipeline usage**

I'm opening the base, indicmfa, indic_conformer, and runner files to analyze validator implementations and how the pipeline orchestrates them, aiming to identify potential issues with determinism or hallucination and suggest improvements.


Output:
Exit code: 0
Wall time: 0 seconds
Output:
"""
Base classes for transcription validators.
All validators inherit from BaseValidator and produce ValidationResult objects.
"""
import os
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from enum import Enum

class ValidatorStatus(Enum):
    """Status of a validator."""
    NOT_INITIALIZED = "not_initialized"
    READY = "ready"
    ERROR = "error"
    DISABLED = "disabled"

@dataclass
class WordAlignment:
    """Represents alignment information for a single word."""
    word: str
    start_time: float  # seconds
    end_time: float    # seconds
    confidence: Optional[float] = None  # 0-1 if available

    @property
    def duration(self) -> float:
        return self.end_time - self.start_time

@dataclass
class ValidationResult:
    """Result from a single validator for a single audio segment."""
    validator_name: str
    audio_path: str

    # Status
    success: bool
    error_message: Optional[str] = None

    # Transcription output (if ASR-based validator)
    transcription: Optional[str] = None

    # Alignment data (if alignment-based validator)
    word_alignments: List[WordAlignment] = field(default_factory=list)

    # Confidence/scores
    overall_confidence: Optional[float] = None
    alignment_score: Optional[float] = None  # Average alignment confidence

    # Timing stats
    processing_time_sec: Optional[float] = None
    audio_duration_sec: Optional[float] = None

    # Raw output for debugging
    raw_output: Optional[Dict[str, Any]] = None

    @property
    def words_per_second(self) -> Optional[float]:
        """Calculate speaking rate if transcription available."""
        if self.transcription and self.audio_duration_sec:
            word_count = len(self.transcription.split())
            if self.audio_duration_sec > 0:
                return word_count / self.audio_duration_sec
        return None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        return {
            "validator_name": self.validator_name,
            "audio_path": self.audio_path,
            "success": self.success,
            "error_message": self.error_message,
            "transcription": self.transcription,
            "word_alignments": [
                {
                    "word": wa.word,
                    "start_time": wa.start_time,
                    "end_time": wa.end_time,
                    "confidence": wa.confidence,
                    "duration": wa.duration
                }
                for wa in self.word_alignments
            ],
            "overall_confidence": self.overall_confidence,
            "alignment_score": self.alignment_score,
            "processing_time_sec": self.processing_time_sec,
            "audio_duration_sec": self.audio_duration_sec,
            "words_per_second": self.words_per_second,
        }

class BaseValidator(ABC):
    """
    Abstract base class for all transcription validators.

    Each validator should:
    1. Initialize model/resources in __init__ or setup()
    2. Implement validate() to process a single audio file
    3. Return ValidationResult with relevant metrics
    """

    name: str = "base_validator"
    description: str = "Base validator class"

    def __init__(self, enabled: bool = True, **kwargs):
        """
        Initialize the validator.

        Args:
            enabled: Whether this validator is active
            **kwargs: Validator-specific configuration
        """
        self.enabled = enabled
        self.status = ValidatorStatus.NOT_INITIALIZED
        self.config = kwargs
        self._model = None

    @abstractmethod
    def setup(self) -> bool:
        """
        Initialize models and resources.
        Called lazily before first validation.

        Returns:
            True if setup successful, False otherwise
        """
        pass

    @abstractmethod
    def validate(
        self,
        audio_path: str,
        reference_text: Optional[str] = None,
        language: str = "te"  # ISO 639-1 code
    ) -> ValidationResult:
        """
        Validate/process a single audio file.

        Args:
            audio_path: Path to audio file
            reference_text: Optional reference transcription for alignment
            language: Language code (te=Telugu, hi=Hindi, kn=Kannada, etc.)

        Returns:
            ValidationResult with transcription/alignment data
        """
        pass

    def validate_batch(
        self,
        audio_paths: List[str],
        reference_texts: Optional[List[str]] = None,
        language: str = "te"
    ) -> List[ValidationResult]:
        """
        Validate multiple audio files.
        Default implementation calls validate() for each file.
        Override for batch-optimized processing.
        """
        results = []
        ref_texts = reference_texts or [None] * len(audio_paths)

        for audio_path, ref_text in zip(audio_paths, ref_texts):
            result = self.validate(audio_path, ref_text, language)
            results.append(result)

        return results

    def ensure_setup(self) -> bool:
        """Ensure validator is set up before use."""
        if self.status == ValidatorStatus.NOT_INITIALIZED:
            try:
                success = self.setup()
                self.status = ValidatorStatus.READY if success else ValidatorStatus.ERROR
            except Exception as e:
                self.status = ValidatorStatus.ERROR
                print(f"[{self.name}] Setup failed: {e}")
                return False
        return self.status == ValidatorStatus.READY

    def cleanup(self):
        """Release resources. Override if needed."""
        self._model = None

    def get_info(self) -> Dict[str, Any]:
        """Get validator information."""
        return {
            "name": self.name,
            "description": self.description,
            "enabled": self.enabled,
            "status": self.status.value,
            "config": self.config
        }

# Language code mapping for convenience
LANGUAGE_CODES = {
    "telugu": "te",
    "hindi": "hi",
    "kannada": "kn",
    "tamil": "ta",
    "malayalam": "ml",
    "bengali": "bn",
    "gujarati": "gu",
    "marathi": "mr",
    "punjabi": "pa",
    "odia": "or",
    "english": "en",
    # Also accept ISO codes directly
    "te": "te",
    "hi": "hi",
    "kn": "kn",
    "ta": "ta",
    "ml": "ml",
    "bn": "bn",
    "gu": "gu",
    "mr": "mr",


sed -n '220,520p' src/validators/base.py


Output:
Exit code: 0
Wall time: 0 seconds
Output:
    "mr": "mr",
    "pa": "pa",
    "or": "or",
    "en": "en",
}

def normalize_language_code(language: str) -> str:
    """Convert language name to ISO 639-1 code."""
    return LANGUAGE_CODES.get(language.lower(), language.lower())


sed -n '1,260p' src/validators/indicmfa_validator.py


Output:
Exit code: 0
Wall time: 0 seconds
Output:
"""
IndicMFA Validator
==================

Montreal Forced Aligner (MFA) with AI4Bharat Indic acoustic models.
https://github.com/AI4Bharat/IndicMFA

Requirements:
- MFA must be installed via conda: `conda install -c conda-forge montreal-forced-aligner`
- Or use the fallback CTC segmentation method

Features:
- Precise word and phone level alignments
- Language-specific acoustic models for Indian languages
- TextGrid output with timing information
"""
import os
import time
import tempfile
import subprocess
from typing import Optional, List, Dict, Any
from pathlib import Path

from .base import (
    BaseValidator,
    ValidationResult,
    WordAlignment,
    ValidatorStatus,
    normalize_language_code
)

class IndicMFAValidator(BaseValidator):
    """
    Validator using Montreal Forced Aligner with Indic models.

    Provides precise word-level alignments using forced alignment.
    Requires reference text for alignment.
    """

    name = "indicmfa"
    description = "Montreal Forced Aligner with AI4Bharat Indic acoustic models"

    # MFA model names for Indian languages (to be downloaded via mfa)
    MFA_MODELS = {
        "te": {"acoustic": "telugu_mfa", "dictionary": "telugu_mfa"},
        "hi": {"acoustic": "hindi_mfa", "dictionary": "hindi_mfa"},
        "ta": {"acoustic": "tamil_mfa", "dictionary": "tamil_mfa"},
        "bn": {"acoustic": "bengali_mfa", "dictionary": "bengali_mfa"},
        "en": {"acoustic": "english_mfa", "dictionary": "english_mfa"},
    }

    # IndicMFA model URLs (from AI4Bharat releases)
    INDICMFA_URLS = {
        "te": {
            "acoustic": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/telugu_acoustic_model.zip",
            "dictionary": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/telugu_dictionary.txt",
        },
        "hi": {
            "acoustic": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/hindi_acoustic_model.zip",
            "dictionary": "https://github.com/AI4Bharat/IndicMFA/releases/download/v1.0/hindi_dictionary.txt",
        },
    }

    def __init__(
        self,
        enabled: bool = True,
        models_dir: str = "./models/indicmfa",
        use_ctc_fallback: bool = True,  # Fall back to CTC segmentation if MFA not available
        **kwargs
    ):
        """
        Initialize IndicMFA validator.

        Args:
            enabled: Whether validator is active
            models_dir: Directory for MFA models
            use_ctc_fallback: Use CTC segmentation if MFA unavailable
        """
        super().__init__(enabled=enabled, **kwargs)
        self.models_dir = Path(models_dir)
        self.use_ctc_fallback = use_ctc_fallback
        self._mfa_available = None
        self._ctc_model = None
        self._ctc_processor = None

    def _check_mfa_available(self) -> bool:
        """Check if MFA is installed and available."""
        if self._mfa_available is not None:
            return self._mfa_available

        try:
            result = subprocess.run(
                ["mfa", "version"],
                capture_output=True,
                text=True,
                timeout=10
            )
            self._mfa_available = result.returncode == 0
            if self._mfa_available:
                print(f"[{self.name}] MFA version: {result.stdout.strip()}")
        except (subprocess.TimeoutExpired, FileNotFoundError):
            self._mfa_available = False

        return self._mfa_available

    def setup(self) -> bool:
        """Setup MFA or CTC fallback."""
        print(f"[{self.name}] Checking MFA availability...")

        if self._check_mfa_available():
            print(f"[{self.name}] MFA is available")
            return True

        if self.use_ctc_fallback:
            print(f"[{self.name}] MFA not available, setting up CTC fallback")
            return self._setup_ctc_fallback()

        print(f"[{self.name}] MFA not available and no fallback enabled")
        print(f"[{self.name}] Install MFA: conda install -c conda-forge montreal-forced-aligner")
        return False

    def _setup_ctc_fallback(self) -> bool:
        """Setup CTC-based alignment as fallback."""
        try:
            import torch
            from transformers import Wav2Vec2ForCTC, Wav2Vec2Processor

            print(f"[{self.name}] Loading Wav2Vec2 for CTC segmentation...")

            # Use Telugu-specific model for better alignment
            model_name = "anuragshas/wav2vec2-large-xlsr-53-telugu"

            self._ctc_processor = Wav2Vec2Processor.from_pretrained(model_name)
            self._ctc_model = Wav2Vec2ForCTC.from_pretrained(model_name)

            device = "cuda" if torch.cuda.is_available() else "cpu"
            self._ctc_model.to(device)
            self._ctc_model.eval()
            self._device = device

            print(f"[{self.name}] CTC fallback ready on {device}")
            return True

        except Exception as e:
            print(f"[{self.name}] CTC fallback setup failed: {e}")
            import traceback
            traceback.print_exc()
            return False

    def _align_with_mfa(
        self,
        audio_path: str,
        reference_text: str,
        language: str
    ) -> List[WordAlignment]:
        """Perform forced alignment using MFA."""
        lang_code = normalize_language_code(language)

        # Create temp directory for MFA
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Copy audio file
            audio_name = Path(audio_path).stem
            import shutil
            audio_dest = temp_path / f"{audio_name}.wav"

            # Convert to wav if needed
            import soundfile as sf
            data, sr = sf.read(audio_path)
            sf.write(audio_dest, data, sr)

            # Create transcript file
            transcript_path = temp_path / f"{audio_name}.txt"
            transcript_path.write_text(reference_text)

            # Output directory
            output_dir = temp_path / "aligned"
            output_dir.mkdir()

            # Get model names
            models = self.MFA_MODELS.get(lang_code, self.MFA_MODELS.get("en"))

            # Run MFA
            cmd = [
                "mfa", "align",
                str(temp_path),
                models["dictionary"],
                models["acoustic"],
                str(output_dir),
                "--clean"
            ]

            try:
                result = subprocess.run(
                    cmd,
                    capture_output=True,
                    text=True,
                    timeout=300
                )

                if result.returncode != 0:
                    print(f"[{self.name}] MFA error: {result.stderr}")
                    return []

                # Parse TextGrid output
                textgrid_path = output_dir / f"{audio_name}.TextGrid"
                if textgrid_path.exists():
                    return self._parse_textgrid(textgrid_path)

            except subprocess.TimeoutExpired:
                print(f"[{self.name}] MFA timeout")
            except Exception as e:
                print(f"[{self.name}] MFA error: {e}")

        return []

    def _parse_textgrid(self, textgrid_path: Path) -> List[WordAlignment]:
        """Parse TextGrid file to extract word alignments."""
        try:
            from praatio import textgrid

            tg = textgrid.openTextgrid(str(textgrid_path), includeEmptyIntervals=False)

            alignments = []

            # Look for words tier
            for tier_name in ["words", "word", "Words"]:
                if tier_name in tg.tierNames:
                    tier = tg.getTier(tier_name)
                    for interval in tier.entries:
                        if interval.label.strip():
                            alignments.append(WordAlignment(
                                word=interval.label.strip(),
                                start_time=interval.start,
                                end_time=interval.end,
                                confidence=1.0  # MFA alignments are deterministic
                            ))
                    break

            return alignments

        except ImportError:
            print(f"[{self.name}] praatio not installed, install with: pip install praatio")
            return []
        except Exception as e:
            print(f"[{self.name}] TextGrid parse error: {e}")
            return []

    def _align_with_ctc(
        self,
        audio_path: str,
        reference_text: str,
        language: str
    ) -> tuple:
        """Perform alignment using CTC segmentation."""
        import torch
        import soundfile as sf
        import numpy as np


sed -n '260,640p' src/validators/indicmfa_validator.py


Output:
Exit code: 0
Wall time: 0 seconds
Output:
        import numpy as np

        # Load audio
        data, sr = sf.read(audio_path)
        if sr != 16000:
            import torchaudio
            waveform = torch.from_numpy(data).float().unsqueeze(0)
            resampler = torchaudio.transforms.Resample(sr, 16000)
            waveform = resampler(waveform)
            data = waveform.squeeze().numpy()
            sr = 16000

        duration = len(data) / sr

        # Get CTC logits
        device = getattr(self, '_device', 'cpu')

        inputs = self._ctc_processor(
            data,
            sampling_rate=sr,
            return_tensors="pt",
            padding=True
        )

        input_values = inputs.input_values.to(device)

        with torch.no_grad():
            outputs = self._ctc_model(input_values)
            logits = outputs.logits.cpu()

        # Simple proportional alignment (CTC segmentation would be better)
        words = reference_text.split()
        alignments = []

        if words:
            total_chars = sum(len(w) for w in words)
            current_time = 0.0

            for word in words:
                word_duration = (len(word) / total_chars) * duration if total_chars > 0 else 0
                alignments.append(WordAlignment(
                    word=word,
                    start_time=current_time,
                    end_time=current_time + word_duration,
                    confidence=0.8  # Estimated
                ))
                current_time += word_duration

        # Calculate confidence from logits
        probs = torch.softmax(logits, dim=-1)
        confidence = probs.max(dim=-1).values.mean().item()

        return alignments, confidence, duration

    def validate(
        self,
        audio_path: str,
        reference_text: Optional[str] = None,
        language: str = "te"
    ) -> ValidationResult:
        """
        Align audio with reference text.

        Args:
            audio_path: Path to audio file
            reference_text: Reference transcription (REQUIRED for alignment)
            language: Language code

        Returns:
            ValidationResult with word alignments
        """
        if not self.enabled:
            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=False,
                error_message="Validator disabled"
            )

        if not reference_text:
            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=False,
                error_message="Reference text required for forced alignment"
            )

        if not self.ensure_setup():
            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=False,
                error_message="MFA/CTC not available"
            )

        start_time = time.time()
        lang_code = normalize_language_code(language)

        try:
            if self._check_mfa_available():
                # Use MFA
                alignments = self._align_with_mfa(audio_path, reference_text, lang_code)
                method = "mfa"
                confidence = 1.0

                # Get duration
                import soundfile as sf
                data, sr = sf.read(audio_path)
                duration = len(data) / sr
            else:
                # Use CTC fallback
                alignments, confidence, duration = self._align_with_ctc(
                    audio_path, reference_text, lang_code
                )
                method = "ctc_fallback"

            processing_time = time.time() - start_time

            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=len(alignments) > 0,
                transcription=reference_text,  # Use reference as transcription
                word_alignments=alignments,
                overall_confidence=confidence,
                alignment_score=confidence,
                processing_time_sec=processing_time,
                audio_duration_sec=duration,
                raw_output={
                    "language": lang_code,
                    "method": method,
                    "word_count": len(alignments)
                }
            )

        except Exception as e:
            import traceback
            traceback.print_exc()
            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=False,
                error_message=str(e),
                processing_time_sec=time.time() - start_time
            )

    def cleanup(self):
        """Release resources."""
        if self._ctc_model is not None:
            del self._ctc_model
            self._ctc_model = None
        if self._ctc_processor is not None:
            del self._ctc_processor
            self._ctc_processor = None

        import torch
        if torch.cuda.is_available():
            torch.cuda.empty_cache()


sed -n '1,260p' src/validators/indic_conformer_validator.py


Output:
Exit code: 0
Wall time: 0 seconds
Output:
"""
IndicConformer Validator
========================

Uses AI4Bharat's IndicConformer models for ASR.

Two model types supported:
1. NeMo-based language-specific models (ai4bharat/indicconformer_stt_*_hybrid_ctc_rnnt_large)
2. HuggingFace AutoModel multilingual (ai4bharat/indic-conformer-600m-multilingual)

Features:
- 600M parameter Conformer architecture
- Hybrid CTC-RNNT decoding
- Support for 22 Indian languages
"""
import os
import time
from typing import Optional, List, Dict, Any
from pathlib import Path

from .base import (
    BaseValidator,
    ValidationResult,
    WordAlignment,
    ValidatorStatus,
    normalize_language_code
)

class IndicConformerValidator(BaseValidator):
    """
    Validator using AI4Bharat's IndicConformer models.

    Supports:
    - Multilingual model (600M params, 22 languages)
    - Language-specific NeMo models
    """

    name = "indic_conformer"
    description = "AI4Bharat IndicConformer - 600M Multilingual Indian ASR"

    # Language-specific NeMo models (require gated access)
    NEMO_MODELS = {
        "te": "ai4bharat/indicconformer_stt_te_hybrid_ctc_rnnt_large",
        "hi": "ai4bharat/indicconformer_stt_hi_hybrid_ctc_rnnt_large",
        "bn": "ai4bharat/indicconformer_stt_bn_hybrid_ctc_rnnt_large",
        "ta": "ai4bharat/indicconformer_stt_ta_hybrid_ctc_rnnt_large",
        "kn": "ai4bharat/indicconformer_stt_kn_hybrid_ctc_rnnt_large",
        "ml": "ai4bharat/indicconformer_stt_ml_hybrid_ctc_rnnt_large",
        "mr": "ai4bharat/indicconformer_stt_mr_hybrid_ctc_rnnt_large",
        "gu": "ai4bharat/indicconformer_stt_gu_hybrid_ctc_rnnt_large",
        "pa": "ai4bharat/indicconformer_stt_pa_hybrid_ctc_rnnt_large",
        "or": "ai4bharat/indicconformer_stt_or_hybrid_ctc_rnnt_large",
    }

    # Multilingual HuggingFace model (open access)
    MULTILINGUAL_MODEL = "ai4bharat/indic-conformer-600m-multilingual"

    def __init__(
        self,
        enabled: bool = True,
        device: str = "auto",
        language: str = "te",
        use_multilingual: bool = True,  # Prefer multilingual model (no gating)
        decoding: str = "rnnt",  # "ctc" or "rnnt"
        **kwargs
    ):
        """
        Initialize IndicConformer validator.

        Args:
            enabled: Whether validator is active
            device: "cuda", "cpu", or "auto"
            language: Default language code
            use_multilingual: Use multilingual model (recommended, no gating)
            decoding: Decoding strategy - "ctc" or "rnnt"
        """
        super().__init__(enabled=enabled, **kwargs)
        self.device_preference = device
        self.language = normalize_language_code(language)
        self.use_multilingual = use_multilingual
        self.decoding = decoding
        self.model = None
        self.device = None
        self._model_name = None
        self._model_type = None  # "multilingual" or "nemo"
        self._current_language = None

    def setup(self, language: str = None) -> bool:
        """Load IndicConformer model."""
        try:
            import torch

            # Determine device
            if self.device_preference == "auto":
                self.device = "cuda" if torch.cuda.is_available() else "cpu"
            else:
                self.device = self.device_preference

            print(f"[{self.name}] Loading model on {self.device}...")

            lang_code = normalize_language_code(language or self.language)
            self._current_language = lang_code

            # Try multilingual model first (no gating)
            if self.use_multilingual:
                try:
                    return self._setup_multilingual(lang_code)
                except Exception as e:
                    print(f"[{self.name}] Multilingual setup failed: {e}")
                    print(f"[{self.name}] Trying language-specific NeMo model...")

            # Fallback to NeMo language-specific model
            return self._setup_nemo(lang_code)

        except Exception as e:
            print(f"[{self.name}] Setup error: {e}")
            import traceback
            traceback.print_exc()
            return False

    def _setup_multilingual(self, language: str) -> bool:
        """Setup using HuggingFace multilingual model."""
        from transformers import AutoModel
        import warnings

        self._model_name = self.MULTILINGUAL_MODEL
        print(f"[{self.name}] Loading multilingual model: {self._model_name}")

        # Suppress ONNX CUDA warnings (model uses ONNX which may not have CUDA provider)
        with warnings.catch_warnings():
            warnings.filterwarnings("ignore", message=".*CUDAExecutionProvider.*")
            warnings.filterwarnings("ignore", message=".*FRAME_DURATION.*")

            # Load with trust_remote_code for custom model
            self.model = AutoModel.from_pretrained(
                self._model_name,
                trust_remote_code=True
            )

        # Note: Multilingual model uses ONNX runtime, device handling is internal
        self.model.eval()
        self._model_type = "multilingual"

        print(f"[{self.name}] Multilingual model loaded successfully (ONNX backend)")
        return True

    def _setup_nemo(self, language: str) -> bool:
        """Setup using NeMo language-specific model."""
        try:
            import nemo.collections.asr as nemo_asr
        except ImportError:
            print(f"[{self.name}] NeMo not installed. Install with: pip install nemo_toolkit[asr]")
            return False

        # Get model name for language
        self._model_name = self.NEMO_MODELS.get(language)

        if not self._model_name:
            print(f"[{self.name}] No NeMo model for {language}")
            return False

        print(f"[{self.name}] Loading NeMo model: {self._model_name}")

        try:
            # Load from HuggingFace (requires gated access)
            self.model = nemo_asr.models.ASRModel.from_pretrained(
                model_name=self._model_name
            )

            if self.device == "cuda":
                self.model = self.model.cuda()

            self.model.eval()
            self._model_type = "nemo"

            print(f"[{self.name}] NeMo model loaded successfully")
            return True

        except Exception as e:
            print(f"[{self.name}] NeMo model load failed: {e}")
            return False

    def _load_audio(self, audio_path: str, target_sr: int = 16000):
        """Load and resample audio."""
        import soundfile as sf
        import torch
        import torchaudio

        data, sample_rate = sf.read(audio_path)
        waveform = torch.from_numpy(data).float()

        # Ensure mono
        if len(waveform.shape) == 1:
            waveform = waveform.unsqueeze(0)
        elif waveform.shape[0] > 1:
            waveform = waveform.mean(dim=0, keepdim=True)

        # Resample if needed
        if sample_rate != target_sr:
            resampler = torchaudio.transforms.Resample(sample_rate, target_sr)
            waveform = resampler(waveform)

        return waveform, target_sr

    def _transcribe_multilingual(self, audio_path: str, language: str) -> Dict[str, Any]:
        """Transcribe using multilingual HuggingFace model (ONNX backend)."""
        import torch

        # Load audio
        waveform, sr = self._load_audio(audio_path)
        duration = waveform.shape[1] / sr

        # Note: Multilingual model uses ONNX runtime internally
        # Audio stays on CPU as ONNX handles device placement

        # Transcribe using model's __call__ method
        # Format: model(audio_tensor, language_code, decoding_method)
        with torch.no_grad():
            transcription = self.model(waveform, language, self.decoding)

        # Handle output format
        if isinstance(transcription, (list, tuple)):
            transcription = transcription[0] if transcription else ""

        # Generate word alignments
        words = str(transcription).split()
        alignments = []

        for i, word in enumerate(words):
            alignments.append(WordAlignment(
                word=word,
                start_time=i * duration / max(len(words), 1),
                end_time=(i + 1) * duration / max(len(words), 1),
                confidence=None
            ))

        return {
            "transcription": str(transcription),
            "alignments": alignments,
            "duration": duration
        }

    def _transcribe_nemo(self, audio_path: str) -> Dict[str, Any]:
        """Transcribe using NeMo model."""
        # NeMo can transcribe directly from file path
        transcription = self.model.transcribe([audio_path])[0]

        # Get duration
        import soundfile as sf
        data, sr = sf.read(audio_path)
        duration = len(data) / sr

        # Generate word alignments
        words = transcription.split()
        alignments = []

        for i, word in enumerate(words):
            alignments.append(WordAlignment(
                word=word,


sed -n '260,640p' src/validators/indic_conformer_validator.py


Output:
Exit code: 0
Wall time: 0 seconds
Output:
                word=word,
                start_time=i * duration / max(len(words), 1),
                end_time=(i + 1) * duration / max(len(words), 1),
                confidence=None
            ))

        return {
            "transcription": transcription,
            "alignments": alignments,
            "duration": duration
        }

    def validate(
        self,
        audio_path: str,
        reference_text: Optional[str] = None,
        language: str = "te"
    ) -> ValidationResult:
        """
        Transcribe audio using IndicConformer.

        Args:
            audio_path: Path to audio file
            reference_text: Optional reference (not used for ASR)
            language: Language code

        Returns:
            ValidationResult with ASR output
        """
        if not self.enabled:
            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=False,
                error_message="Validator disabled"
            )

        start_time = time.time()
        lang_code = normalize_language_code(language)

        # Check if we need to reload model for different language
        if self._current_language != lang_code or self.model is None:
            if not self.setup(lang_code):
                return ValidationResult(
                    validator_name=self.name,
                    audio_path=audio_path,
                    success=False,
                    error_message="Model not loaded"
                )

        try:
            # Transcribe based on model type
            if self._model_type == "multilingual":
                result = self._transcribe_multilingual(audio_path, lang_code)
            else:
                result = self._transcribe_nemo(audio_path)

            processing_time = time.time() - start_time

            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=True,
                transcription=result["transcription"],
                word_alignments=result["alignments"],
                overall_confidence=None,
                processing_time_sec=processing_time,
                audio_duration_sec=result.get("duration"),
                raw_output={
                    "language": lang_code,
                    "model": self._model_name,
                    "model_type": self._model_type,
                    "decoding": self.decoding
                }
            )

        except Exception as e:
            import traceback
            traceback.print_exc()
            return ValidationResult(
                validator_name=self.name,
                audio_path=audio_path,
                success=False,
                error_message=str(e),
                processing_time_sec=time.time() - start_time
            )

    def cleanup(self):
        """Release resources."""
        if self.model is not None:
            del self.model
            self.model = None

        import torch
        if torch.cuda.is_available():
            torch.cuda.empty_cache()


sed -n '1,240p' src/validators/runner.py