Konsole unterdrücken

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
raorao
User
Beiträge: 24
Registriert: Mittwoch 30. Dezember 2009, 15:35

Hoi mitenand!

Bin kurz vor der Fertigstellung einer Lernsoftware und wollte nun noch eine Sprachausgabe der Abfragen einbauen. Über die üblichen Microsoft Stimmen führt dies wie gewünscht zum Erfolg, allerdings sind diese recht unverständlich, deshalb habe ich mir eSpeak installiert, funktioniert deutlich verständlicher. Beim Versuch, eine Ausgabe via

Code: Alles auswählen

os.system("C:\\Programme\\eSpeak\\command_line\\espeak 'hello'")
zu erreichen, entsteht aber die Unschönheit, dass für kurze Zeit (nämlich während der gesamten Sprechzeit) ein schwarzes Konsolenfenster im Vordergrund sichtbar wird. Gibt es eine Möglichkeit, dieses zu unterdrücken oder aber einen ganz anderen Ansatz eSpeak zum sprechen zu zwingen?

Herzlichen Dank für eure Mithilfe!
raorao
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Vergiss, dass es os.system() gibt und nutze das subprocess-Modul. Beispiele gibt es in der Doku (gaaanz unten) und auch zu Hauf hier im Forum ;-)

Vermutlich liegt das Konsolenfenster an diesem "espeak"-Tool. Ich denke nicht, dass man das unterdrücken kann.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Das Konsolenfenster sollte sich mit dem startupinfo-Schlüsselwortargument unterdrücken lassen.

Code: Alles auswählen

import subprocess

startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE

subprocess.call(["C:\\Programme\\eSpeak\\command_line\\espeak", "hello"], startupinfo=startupinfo)
raorao
User
Beiträge: 24
Registriert: Mittwoch 30. Dezember 2009, 15:35

Suuuuuuper, herzlichen Dank! Funktioniert super, habe folgendes Modul geschrieben, welches bei Ausführung als __main__ die bessere der beiden installierten Varianten ausgibt. Der Pfad in der Klasse TTS_eSpeak muss natürlich je nach Speicherort und Betriebssystem angepasst werden.

Code: Alles auswählen

import sys, subprocess
sys.path.append(r"C:\Python26\Lib\site-packages\win32\lib")
sys.path.append(r"C:\Python26\Lib\site-packages\win32")
import win32com.client

class TTS_Sapi(object):
    def __init__(self, text):
        self.text = text
        self.sprechen()
        
    def sprechen(self):
        speaker = win32com.client.Dispatch("SAPI.SpVoice")
        speaker.Speak(self.text)

class TTS_eSpeak(object):
    def __init__(self, text):
        self.text = text
        self.sprechen()

    def sprechen(self):
        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
        startupinfo.wShowWindow = subprocess.SW_HIDE
        subprocess.call(["C:\\Programme\\eSpeak\\command_line\\espeak",\
                         "%s" % self.text], startupinfo=startupinfo)

if __name__ == "__main__":
    try:
        TTS_eSpeak("Speaking espeak")
    except:
        TTS_Sapi("Speaking Microsoft")
BlackJack

@raorao: Das ist aber heftiger Missbrauch von Klassen. Das wären doch einfach nur zwei einfache Funktionen, warum machst Du das so unnötig kompliziert!?
raorao
User
Beiträge: 24
Registriert: Mittwoch 30. Dezember 2009, 15:35

Na weil da jemand wohl deutlich zu wenig Ahnung von objektorientierter Programmierung hat... :?
Habs nun daher nochmals überarbeitet, danke:

Code: Alles auswählen

import sys, subprocess
sys.path.append(r"C:\Python26\Lib\site-packages\win32\lib")
sys.path.append(r"C:\Python26\Lib\site-packages\win32")
import win32com.client

def sapi(text):
    speaker = win32com.client.Dispatch("SAPI.SpVoice")
    speaker.Speak(text)

def espeak(text):
    startupinfo = subprocess.STARTUPINFO()
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    startupinfo.wShowWindow = subprocess.SW_HIDE
    subprocess.call(["C:\\Programme\\eSpeak\\command_line\\espeak",\
                     "%s" % text], startupinfo=startupinfo)

if __name__ == "__main__":
    try:
        espeak("Speaking espeak")
    except:
        sapi("Speaking Microsoft")
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Das blanke `except` solltest du mir der tatsaechlichen Exception erweitern, bei der du `sapi` noch nutzen kannst. Momentan wird das auch ausgefuehrt, wenn jemand `Ctrl-C` waehrend `espeak` drueckt oder wenn waehrend dessen bspw ein `MemoryError` passiert. Schlechte Idee.
micnic
User
Beiträge: 3
Registriert: Mittwoch 22. April 2009, 14:49

Statt den Pfad zum Programm hart reinzuschreiben, könnte man auch versuchen, ihn aus der Registry auszulesen:

Code: Alles auswählen

import _winreg
...
root = _winreg.HKEY_LOCAL_MACHINE
hKey = _winreg.OpenKey (root, 'SOFTWARE\Microsoft\Speech\Voices\Tokens\eSpeak', 0, _winreg.KEY_READ)
program_path, _ = _winreg.QueryValueEx (hKey, 'Path')
Grüße,
micnic
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

fhoech hat geschrieben:Das Konsolenfenster sollte sich mit dem startupinfo-Schlüsselwortargument unterdrücken lassen.
Cool - war mir noch nicht bekannt. Wieder was gelernt :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
raorao
User
Beiträge: 24
Registriert: Mittwoch 30. Dezember 2009, 15:35

@micnic: Sehr interessante Lösung, funktioniert natürlich hervorragend. Soweit ich der Doku entnehmen konnte, funktioniert _winreg jedoch nur für Windows. Gibts dassselbe vielleicht sogar noch Plattformunabhängig?

@cofi: Danke, hab ich vergessen mittlerweile aber brav durch if os.path.isfile(pfad):... else: ersetzt, so gehts gleich ganz ohne try and error bzw. try and except...
BlackJack

@raorao: Ausnahmebehandlung wird einem Test in Python aber oft vorgezogen. Also Ausnahmen "brav" durch Tests ersetzen ist vielleicht gar nicht so brav. :-)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

raorao hat geschrieben:@micnic: Sehr interessante Lösung, funktioniert natürlich hervorragend. Soweit ich der Doku entnehmen konnte, funktioniert _winreg jedoch nur für Windows. Gibts dassselbe vielleicht sogar noch Plattformunabhängig?
Ähm, die anderen Platformen haben keine solche Registry, also nein, da es sowas eigentlich nur auf Windows gibt. Das was am nächsten da rankommt ist gconf unter GNOME, aber dort stehen keine Pfade zu Binaries drin, weil Binaries sinnigerweise direkt im $PATH auffindbar sind. Somit reicht es auf Unices einfach den Namen des Programms zu kennen um es aufzurufen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

raorao hat geschrieben:@cofi: Danke, hab ich vergessen mittlerweile aber brav durch if os.path.isfile(pfad):... else: ersetzt, so gehts gleich ganz ohne try and error bzw. try and except...
Nein so geht es nicht ohne try und except. Nach dem os.path.isfile aufruf und bevor du die Datei aufrufst kann sie immer noch verschwinden oder du bekommst einfach keinen Zugriff darauf.
Antworten