Seite 1 von 1

Worterkennung für Sprachassistent

Verfasst: Mittwoch 8. April 2020, 20:15
von Life4Gaming
Hallo,
ich bin seit Ende letzter Woche dabei mir einen kleinen Sprachassistenten in Python zu basteln.
Momentan benutze ich zur Spracherkennung Speech Recognition.
Jetzt zu meiner Frage beziehungsweise meinem Problem.
Ich benutze momentan einfach nur viele if-Abfragen um zu überprüfen ob ein bestimmtes Schlüsselwort im Text enthalten ist.
Wenn dieses Wort enthalten ist dann wird ein bestimmter Teil des Codes abgespielt.
Da ich jedoch noch einige Features im Kopf habe welche ich gerne noch einbauen möchte denke ich, dass da noch einiges an Abfragen mit dazu kommen.
Gibt es irgendeinen Weg wie ich die Schlüsselwörter kompakter abfragen kann?
Also so, dass nicht immer alles einzeln Abgefragt werden muss?
Oder ist das schon die "ideale" Lösung?

Vielen Dank für eure Hilfe :)

Code: Alles auswählen

while True:
	print("Listening")
	text = get_audio()

	if wake in text:

		if text == wake:
			say("Wie kann ich helfen?")
			text = get_audio()

		noteActivation = ["schreib", "notiz"]
		for word in noteActivation:
			if word in text:
				say("Was soll ich aufschreiben?")
				note_text = get_audio()
				note(note_text)
		
		programActivation = ["start", "öffne"]
		for word in programActivation:
			if word in text:
				startProgram(text)
		
		if "suche" in text:
			search(text)

		elif "spiele" and "von" in text:
			track = text.split("spiele")[1]
			track = track.split("von")[0]
			artist = text.split()
			artist = artist[-1]
			spotify.playSongFromArtist(track, artist)

		elif "spiele" in text:
			spotify.playSong(text.split("spiele")[1])

		elif "stop" in text:
			spotify.stopSong()

		elif "vorheriges" in text:
			spotify.previousSong()

		elif "neustart" in text:
			config.read(settings_path)

		elif "screenshot" in text:
			myScreenshot = pyautogui.screenshot()
			myScreenshot.save(r'C:\Users\Pictures\Screenshots\{}.png'.format(dateNow()))
			say("Der Screenshot wurde gespeichert. Soll ich den Ordner öffnen?")
			text = get_audio()
			if text == "ja":
				os.startfile(r'C:\Users\Pictures\Screenshots')

		elif "einstellungen" in text:
			os.startfile(settings_path)

		elif ("e-mail" in text) or ("email" in text):
			webbrowser.open("https://mail.google.com/mail/u/0/#inbox", new=2)
			
		elif "speedtest" in text:
			os.system("start cmd /k speedtest-cli")
			

Re: Worterkennung für Sprachassistent

Verfasst: Samstag 23. Mai 2020, 09:42
von PythonProgrammer2.0
Ich baue auch gerade einen Sprachassistenten in Python und habe mal über eine Datenbank nachgedacht, welche Phrasen und Synonyme abspeichert. Wäre das was für dich?

Re: Worterkennung für Sprachassistent

Verfasst: Samstag 23. Mai 2020, 10:24
von NPC
Hallo,

Ich persönlich würde das in mehr Funktionen aufteilen ggf. bieten sich hier auch verschiedene Scripte an die du dann importierst.
Jedes dieser Scripte könnte z.B. über eine Liste PHRASES sowie eine funktion handler(order) (wobei order der ganze string ist) verfügen.

Für jedes importierte Script speicherst du dir nun die PHRASES sowie die handler funktion in einer Liste:

Code: Alles auswählen

phrase2func = [(module.PHRASES, module.handler), ...]


Anschließend gehst du die Liste durch und überprüfst auf die Phrase. Wenn ja Funktion aufrufen, wenn nicht, dann nicht.

Code: Alles auswählen

# der erhaltene String ist order
for phrases, func in phrase2func:
	if any([phrase in order for phrase in phrases]):
		func(order)

Re: Worterkennung für Sprachassistent

Verfasst: Samstag 23. Mai 2020, 12:35
von __blackjack__
@Life4Gaming: Das sieht so aus als wenn die ``while``-Schleife auf Modulebene steht. Da gehört aber nur Code hin der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Ich weiss nicht ob `wake` so ein günstiger Name ist. Schau mal in ein Wörterbuch als was man das so auf deutsch übersetzen würde.

Die beiden ``for``-Schleifen brechen bei einem Treffer die weitere Verarbeiting nicht ab, so dass dort mehr als eine Aktion mit dem selben Text ausgelöst werden kann. Das liesse sich beispielsweise verhindern in dem man da keine ``for``-Schleife schreibt, sondern ein ``if`` beziehungsweise ``elif`` mit `any()` und einem Generatorausdruck.

Die Bedingung ``elif "spiele" and "von" in text:`` macht nicht was Du denkst was sie tut. "spiele" ist eine nicht-leere Zeichenkette und damit immer wahr, also ist dass das gleiche wie ``elif "von" in text:``. Auf der rechten Seite vom ``and``-Operator sollte wohl besser ``spiele in text`` stehen.

Der Künstler darf in dem Programmteil nur aus einem Wort bestehen‽ Würde es da nicht mehr Sinn machen alles nach dem "von" als Künstlernamen zu verwenden? Ähnliches Problem bei nur "spiele" wo dann nur das erste Wort des Liedtitel verwendet wird.

`my` als Vorsilbe von Namen ist in aller Regel unsinnig. Wenn es nicht auch ein `our` oder `their` oder etwas in der Art als Vorsilbe für den gleichen Namen gibt, hat `my` genau Null Informationswert.

Daten und Code sollten nicht mehrfach im Code stehen. Das macht das schreiben und warten vom Programm nur unnötig umständlich und fehleranfällig. Der Pfad für die Bildschirmfotos sollte nur einmal im Quelltext stehen. Üblicherweise als Konstante.

Die Klammern beim Test auf "e-mail"/"email" sind überflüssig.

`os.system()` sollte schon lange nicht mehr verwendet werden. Für das ausführen von externen Programmen gibt es das `subprocess`-Modul.

`os.startfile()` funktioniert nur unter Windows. Man könnte hier `webbrowser.open()` verwenden oder das `desktop3`-Package aus dem Python Package Index.

Da wo `webbrowser.open()` verwendet wird, würde ein `webbrowser.open_new_tab()` versändlicher sein als die ”magische” 2 für das `new`-Argument bei `webbrowser.open()`.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import os
import subprocess
import webbrowser
from datetime import datetime as DateTime
from pathlib import Path

import pyautogui
import spotify

import config

WAKE_UP_PHRASE = "Hallo Computer"
SETTINGS_PATH = Path("...")
SCREENSHOT_PATH = Path(r"C:\Users\Pictures\Screenshots")

...

def main():
    while True:
        print("Listening")
        text = get_audio()
        if WAKE_UP_PHRASE in text:
            if text == WAKE_UP_PHRASE:
                say("Wie kann ich helfen?")
                text = get_audio()

            if any(word in text for word in ["schreib", "notiz"]):
                say("Was soll ich aufschreiben?")
                note(get_audio())

            elif any(word in text for word in ["start", "öffne"]):
                start_program(text)

            elif "suche" in text:
                search(text)

            elif "spiele" in text and "von" in text:
                track, _, artist = text.split("spiele", 1)[1].partition("von")
                spotify.playSongFromArtist(track.strip(), artist.strip())

            elif "spiele" in text:
                spotify.playSong(text.split("spiele", 1)[1].strip())

            elif "stop" in text:
                spotify.stopSong()

            elif "vorheriges" in text:
                spotify.previousSong()

            elif "neustart" in text:
                config.read(SETTINGS_PATH)

            elif "screenshot" in text:
                pyautogui.screenshot().save(
                    SCREENSHOT_PATH / f"{DateTime.now():%Y-%m-%d_%H:%M:%S}.png"
                )
                say(
                    "Der Screenshot wurde gespeichert."
                    " Soll ich den Ordner öffnen?"
                )
                if get_audio() == "ja":
                    os.startfile(SCREENSHOT_PATH)

            elif "einstellungen" in text:
                os.startfile(SETTINGS_PATH)

            elif "e-mail" in text or "email" in text:
                webbrowser.open_new_tab(
                    "https://mail.google.com/mail/u/0/#inbox"
                )

            elif "speedtest" in text:
                subprocess.run(
                    ["start", "cmd", "/k", "speedtest-cli"], check=True
                )
            else:
                say("Hä? Ich verstehe nicht!")


if __name__ == "__main__":
    main()
NPCs Vorschlag ist sinnvoll, nur das ich aus den `PHRASES` ein aufrufbares Objekt machen würde das den Text bekommt und entscheidet ob der die Aktion auslöst oder nicht und ich würde eine Registrierungsfunktion bereit stellen, damit Module flexibler entscheiden können ob, welche, und wie viele Tests+Aktionen sie bereitstellen.

Re: Worterkennung für Sprachassistent

Verfasst: Mittwoch 3. Juni 2020, 20:42
von Life4Gaming
Vielen Dank für die Antworten!
Ich habe irgendwie keine Benachrichtigung bekommen für die Antworten, daher sorry für die späte Rückmeldung!

@__blackjack__: Was genau meinst du mit einer Registrierungsfunktion? Ich kann mir da gerade nichts darunter vorstellen.

Ich werde mir die Lösungsvorschläge gleich nochmal anschauen und meinen Code verbessern.
Danke nochmal!

Re: Worterkennung für Sprachassistent

Verfasst: Donnerstag 4. Juni 2020, 09:48
von __blackjack__
@Life4Gaming: Eine Funktion die das Programm zur Verfügung stellt, die Plugin-Module aufrufen können um Paare von Test-/Aktionsfunktionen zu registrieren.

Also das ein Plugin beispielsweise eine `init_plugin()`-Funktion haben muss, die nach dem importieren des Moduls aufgerufen wird und die eine Funktion übergeben bekommt, mit der sie dann Funktionalität registrieren kann.

Code: Alles auswählen

# Modul/Plugin, das die Suche implementiert.
def search(text):
    ...

def init_plugin(register):
    register(lambda text: "suche" in text, search)
Das Plugin für Spotify würde dann mehrere `register()`-Aufrufe machen.

Man könnte auch etwas noch ein bisschen flexibleres und fertiges wie `pluggy` verwenden.

Re: Worterkennung für Sprachassistent

Verfasst: Dienstag 24. November 2020, 10:23
von Python567
Hallo,
Ich bin auch gerade dabei, einen Sprachassistenten zu basteln. Welches Programm wurde hier verwendet um die Stimme zu erkennen?