2025, Sep 23 17:32
pyttsx3 runAndWait पर दूसरी पंक्ति नहीं बजती: कारण व समाधान
Python के pyttsx3 में runAndWait बार‑बार कॉल पर दूसरी पंक्ति नहीं बजती. कारण समझें और दो समाधान अपनाएँ: इंजन हर बार री‑इनिट करें या सबको queue कर एक बार चलाएँ.
जब आप pyttsx3 से लगातार एक से अधिक पंक्तियाँ बोलवाते हैं, तो runAndWait को बार‑बार कॉल करने पर कई बार केवल पहला उच्चारण ही चल पाता है। यह समस्या आसान स्थितियों में भी दिखती है—जैसे स्पेलिंग गेम, जहाँ आप एक शब्द पढ़ते हैं, उपयोगकर्ता का इंतज़ार करते हैं, फिर अगला शब्द पढ़ते हैं। कोड चलता रहता है, फिर भी दूसरी पंक्ति बजती नहीं।
न्यूनतम पुनरुत्पादन
नीचे दिया गया स्निपेट अलग‑अलग runAndWait कॉल के साथ लगातार दो उच्चारण कतार में लगाता है और हर रन के बाद इंजन को रोक देता है। नतीजा: सिर्फ पहली पंक्ति सुनाई देती है।
import pyttsx3
vocal = pyttsx3.init()
vocal.say("Hello World")
vocal.runAndWait()
vocal.stop()
vocal.say("Hi")
vocal.runAndWait()
vocal.stop()
असल में हो क्या रहा है
कंट्रोल फ्लो सामान्य रूप से आगे बढ़ता है; समस्या प्रोग्राम के अटकने की नहीं है। print जोड़ने पर साफ दिखता है कि दोनों ब्लॉक चलते हैं:
import pyttsx3
speaker = pyttsx3.init()
speaker.say("Hello World")
speaker.runAndWait()
print("HELLO CALLED")
speaker.stop()
speaker.say("Hi")
speaker.runAndWait()
print("HI CALLED")
speaker.stop()
दोनों संकेत प्रिंट होते हैं, यानी समस्या आपके Python कंट्रोल फ्लो में नहीं, बल्कि इंजन की स्थिति में है। देखे गए व्यवहार से लगता है कि दूसरी बार पाठ अपेक्षित रूप से कतारबद्ध या प्रोसेस नहीं हो रहा। कुछ रिपोर्ट बताती हैं कि stop करने पर इवेंट कतार साफ हो जाती है, पूरा टियरडाउन नहीं होता; एक अपस्ट्रीम रिपोर्ट भी है जिसका शीर्षक है “Only the first two messages in the queue are played.” व्यवहार परिवेश के अनुसार बदल सकता है: कुछ सेटअप में सब सामान्य बजता है, कुछ में नहीं। संदर्भित Windows 11 सेटअप में डिफ़ॉल्ट इंजन के साथ दूसरी पंक्ति नहीं चलती।
व्यावहारिक समाधान
कुल मिलाकर प्रोग्राम लॉजिक बदले बिना आगे बढ़ने के दो भरोसेमंद तरीके हैं।
विधि 1: हर उच्चारण के लिए इंजन को फिर से इनिशियलाइज़ करें
जब भी बोलवाना हो, एक नया इंजन बनाएँ, उसे चलाएँ और फिर रिलीज़ कर दें। इससे हर कॉल का स्टेट अलग रहता है और गड़बड़ी पैदा करने वाले री‑यूज़ से बचा जाता है।
import pyttsx3
def speak_once(msg):
    tts = pyttsx3.init()
    tts.say(msg)
    tts.runAndWait()
    del tts
speak_once("Hello World")
print("SAYING HELLO WORLD")
speak_once("Hi")
print("SAYING HI")
यदि आप runAndWait को आगे के लिए टालना चाहते हैं और फिर भी हर enqueue से पहले इंजन रीसेट करना चाहते हैं, तो नई इंस्टेंस लौटाएँ और उसे बाहर से चलाएँ:
import pyttsx3
voice_ref = ""
def queue_with_reset(text):
    global voice_ref
    del voice_ref
    voice_ref = pyttsx3.init()
    voice_ref.say(text)
    return voice_ref
runner = queue_with_reset("Hello World")
runner.runAndWait()
print("SAYING HELLO WORLD")
runner = queue_with_reset("Hi")
runner.runAndWait()
print("SAYING HI")
कभी‑कभी यदि आपको एक ही बैच में कई पंक्तियाँ जोड़नी हों, तो सिर्फ ज़रूरत होने पर ही रीसेट करें और आइटम इकट्ठा करने के लिए वही इंस्टेंस री‑यूज़ करें:
import pyttsx3
engine_ref = None
def enqueue(text, reset=True):
    global engine_ref
    if reset:
        engine_ref = pyttsx3.init()
        engine_ref.say(text)
        return engine_ref
    engine_ref.say(text)
    return engine_ref
runner = enqueue("Hello World")
runner.runAndWait()
print("SAYING HELLO WORLD")
runner = enqueue("Hi")
runner.runAndWait()
print("SAYING HI")
runner = enqueue("Hi")
runner = enqueue("Hello", reset=False)
runner.runAndWait()
विधि 2: पहले सभी पंक्तियाँ कतार में लगाएँ, फिर एक बार चलाएँ
बीच‑बीच का runAndWait छोड़ दें। जो‑जो बोलना है, सब पहले कतार में लगाएँ, एक बार runAndWait चलाएँ और बाद में stop करें।
import pyttsx3
narrator = pyttsx3.init()
narrator.say("Hello World")
narrator.say("Hi")
narrator.runAndWait()
narrator.stop()
यह क्यों मायने रखता है
स्पेलिंग या लिसनिंग जैसे इंटरेक्टिव ऐप्स में आपको भरोसेमंद क्रम चाहिए—बोलो, इनपुट का इंतज़ार करो, फिर बोलो। यदि stop के बाद या अलग‑अलग रन के बीच दूसरा enqueue सही तरह से हैंडल नहीं होता, तो UX टूट जाता है। इंजन का स्टेट अलग रखना या उच्चारणों को बैच में चलाना समझ लेने से सेशनों में व्यवहार निर्धारक रहता है और उन चुपचाप होने वाली विफलताओं से बचाव होता है जिन्हें डिबग करना मुश्किल होता है।
मुख्य बातें
जब runAndWait कई बार चलाना हो, कुछ सेटअप पर एक ही इंजन इंस्टेंस का पुनः उपयोग आगे की पंक्तियाँ चलाने में विफल हो सकता है। समाधान दो हैं: हर उच्चारण के लिए इंजन फिर से इनिशियलाइज़ करें, या पंक्तियाँ पहले कतार में लगाकर एक ही बार चलाएँ। अगर आपका वर्कफ़्लो बार‑बार प्रॉम्प्ट पर निर्भर है, तो प्रति‑कॉल इनिशियलाइज़ेशन अपनाएँ; निरंतर भाषण के लिए, पहले enqueue करें और एक बार चलाएँ। अगर आपके परिवेश में व्यवहार अलग हो, याद रखें कि नतीजे OS और लाइब्रेरी वर्ज़न पर बदल सकते हैं और कतार हैंडलिंग पर ज्ञात रिपोर्ट मौजूद हैं। लक्षित प्लेटफ़ॉर्म पर टेस्ट करें और आश्चर्य से बचने के लिए इंजन का लाइफसाइकल सरल रखें।
यह लेख StackOverflow के प्रश्न (लेखक: atthegreatestworld) और Aadvik के उत्तर पर आधारित है।