Einstieg in Python und eine Fehlermeldung, mit der ich nicht wirklich was anfangen kann.

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
Benutzeravatar
Cancriformis
User
Beiträge: 3
Registriert: Sonntag 18. August 2024, 18:12

Nach dem ich unter Zuhilfenahme eines Buches über Python3 einige Beispiele und Standards durchgearbeitet hatte, habe ich mich auch dabei ein wenig an die Syntax gewöhnen müssen. Ich habe danach nach einem kleinen Projekt gesucht welches z.B. Chat GPT-4o mit Hilfe von akustischen Befehlen durchführen kann. Es gibt div. Beispiele im Internet dazu (div. bei GitHub), allerdings scheint bei mir auf dem System wohl das ein oder andere trotz Vollinstallation (Microsoft Visual Code v1.92.2 unter Windows + Erweiterung "Python3") zu fehlen... Microphone sowie Lautsprecher sind vorhanden und funktioneren auch. Ich kann aber nicht wirklich was mit der Fehlermeldung anfangen.

Der aktuell komplette Code (Hello_World.py):

Code: Alles auswählen

#!/usr/bin/env python3
#
import os
import sys
import openai 
import pyaudio
import pygame
import speech_recognition as sr
import pyttsx3
import datetime

#Initializing pyttsx3
listening = True
engine = pyttsx3.init()

#Set your openai api key and customizing the chatgpt role
openai.api_key = "sk-..."
messages = [{"role": "system", "content": "Your name is Jarvis and give answers in 2 lines"}]

#Customizing The output voice
voices = engine.getProperty('voices')
rate = engine.getProperty('rate')
volume = engine.getProperty('volume')

def speak(audio):
    engine.say(audio)
    engine.runAndWait()

def wishMe():
    hour = int(datetime.datetime.now().hour)
    if hour >= 0 and hour < 12:
        speak("Guten Morgen!")
    elif hour >= 12 and hour < 18:
        speak("Guten Tag!")
    else:
        speak("Guten Abend!")
    speak("Ich bin Jarvis... Wie kann ich Dir helfen?")

def get_response(user_input):
    messages.append({"role": "user", "content": user_input})
    response = openai.ChatCompletion.create(
        model = "gpt-4o",
        messages = messages
    )
    ChatGPT_reply = response["choices"][0]["message"]["content"]
    messages.append({"role": "assistant", "content": ChatGPT_reply})
    return ChatGPT_reply

while listening:
    wishMe()  
    with sr.Microphone() as source:
        recognizer = sr.Recognizer()
        recognizer.adjust_for_ambient_noise(source)
        recognizer.dynamic_energy_threshold = 3000

        try:
            print("Listening...")
            audio = recognizer.listen(source, timeout=5.0)
            response = recognizer.recognize_google(audio)
            print(response)
           
            if "jarvis" in response.lower():         
                response_from_openai = get_response(response)
                engine.setProperty('rate', 120)
                engine.setProperty('volume', volume)
                engine.setProperty('voice', 'greek')
                engine.say(response_from_openai)
                engine.runAndWait()             
            else:
                print("Didn't recognize 'jarvis'.")
           
        except sr.UnknownValueError:
            print("Didn't recognize anything.")
Die komplette Ausgabe zur Fehlermeldungsanalyse:

Code: Alles auswählen

PS D:\Python\Hello-World> & C:/Users/rvogt/AppData/Local/Microsoft/WindowsApps/python3.11.exe d:/Python/Hello-World/Hello_World.py
pygame 2.6.0 (SDL 2.28.4, Python 3.11.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "d:\Python\Hello-World\Hello_World.py", line 53, in <module>
    recognizer.adjust_for_ambient_noise(source)
  File "C:\Users\[user]\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\speech_recognition\__init__.py", line 383, in adjust_for_ambient_noise
    assert source.stream is not None, "Audio source must be entered before adjusting, see documentation for ``AudioSource``; are you using ``source`` 
outside of a ``with`` statement?"
           ^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: Audio source must be entered before adjusting, see documentation for ``AudioSource``; are you using ``source`` outside of a ``with`` statement?

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "d:\Python\Hello-World\Hello_World.py", line 51, in <module>
    with sr.Microphone() as source:
  File "C:\Users\[user]\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\speech_recognition\__init__.py", line 189, in __exit__
    self.stream.close()
    ^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'close'
Könnte mir da jemand behilflich sein, hat jemand von euch eine Idee, da ich nicht verstehe was er von mir noch haben will oder was er wo vermisst?
Grüße,
Cancriformis.
Sven_TKLOOP
User
Beiträge: 12
Registriert: Freitag 16. August 2024, 14:10

Code: Alles auswählen

assert source.stream is not None, "Audio source must be entered before adjusting, see documentation for ``AudioSource``; are you using ``source`` outside of a ``with`` statement?"
Der Fehler tritt auf, weil die Methode adjust_for_ambient_noise versucht, auf den Mikrofon-Stream (source.stream) zuzugreifen, bevor dieser richtig initialisiert wurde.
Die speech_recognition-Bibliothek will, dass der Mikrofon-Stream innerhalb eines with-Blocks geöffnet wird. Wenn dies nicht der Fall ist, wird source.stream als None betrachtet, daher der Fehler.

Code: Alles auswählen

AttributeError: 'NoneType' object has no attribute 'close'
Dies passiert, weil versucht wird, die Methode close() auf einem NoneType-Objekt auszuführen. Da source.stream auf None gesetzt ist (wegen der fehlerhaften Initialisierung), schlägt der Versuch fehl, den Stream zu schließen, da None keine Methode close() hat.

Du solltest auf source nicht zugreifen von außerhalb des with Blocks


Um zu schauen, ob dein Mikrofon in Python generell richtig funktioniert könntest du nen kleinen Testcode wie hier nutzen:

Code: Alles auswählen

import speech_recognition as sr

recognizer = sr.Recognizer()
with sr.Microphone() as source:
    print("Bitte sprechen Sie etwas...")
    audio = recognizer.listen(source)
    print("Audio aufgenommen.")
Dein Mikrofon sollte auch als Standardaufnahmegerät eingestellt sein.
Benutzeravatar
__blackjack__
User
Beiträge: 14000
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cancriformis: Anmerkungen zum Quelltext: `os`, `sys`, `pyaudio`, und `pygame` werdejn importiert, aber nirgends verwendet.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben und greifen da nicht auf magische Weise auf globale Variablen zu. Spätestens wenn da Datenstrukturen verändert werden, wird es sehr unübersichtlich und fehleranfällig.

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Inhaltlich falsche Kommentare sind sehr schlecht, weil Kommentare ja eigentlich Fragen klären sollen, die der Code beim Leser hinterlässt, und nicht neue Fragen aufwerfen sollten. Beispielsweise der Kommentar das die Ausgabestimme angepasst wird, dann aber Code folgt der das gar nicht tut. Fehlt da jetzt was im Code oder ist der Kommentar falsch?

`listening` wird nirgends verändert, also kann man an der Stelle auch gleich `True` einsetzen.

`voices`, `rate`, und `volume` werden nicht verwendet. Also `volume` formal schon, aber da immer der gleiche Wert verwendet wird, der ausgelesen wurde, macht das keinen Sinn, denn es ändert am Programmverhalten nichts.

Das setzen der Eigenschaften der TTS-Engine wird in der Schleife immer mit den gleichen Werten gemacht — das kann man also *einmal* vor der Schleife machen.

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

`wishMe()` ist zu umständlich. `hour` ist bereits eine ganze Zahl, der `int()`-Aufruf macht keinen Sinn. Die Stunde ist auch nie negativ, das muss man also nicht testen. Und man muss auch nicht die Untergrenze testen, wenn das durch die vorhergehende ``if``-Bedingung schon ausgeschlossen ist, dass der Wert darunter liegen kann.

Der Parametername `audio` bei `speak()` ist irreführend, denn das ist ja *Text* der da übergeben wird, und kein Ton.

Das was im Hauptprogramm `response` heisst, ist ja im Kontext des Programms eigentlich genau das Gegenteil, nämlich die Anfrage, die der Benutzer an das Programm stellt. Es sieht auch sehr komisch aus einer `get_response()`-Funktion einen Wert zu übergeben der `response` heisst.

Man muss auch nicht jeden Zwischenwert an einen Namen binden.

Im Hauptrogramm steht beim Antworten Code der schon in `speak()` steht.

Der Name "Jarvis" kommt mehrfach im Code vor. Wenn man das mal ändern möchte, ist das umständlicher und fehleranfälliger als wenn man den als Konstante definiert.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import datetime

import openai
import pyttsx3
import speech_recognition as sr

ASSISTANT_NAME = "Jarvis"


def say(engine, text):
    engine.say(text)
    engine.runAndWait()


def say_prompt(engine):
    hour = datetime.datetime.now().hour
    if hour < 12:
        say(engine, "Guten Morgen!")
    elif hour < 18:
        say(engine, "Guten Tag!")
    else:
        say(engine, "Guten Abend!")

    say(engine, f"Ich bin {ASSISTANT_NAME}... Wie kann ich Dir helfen?")


def get_response(messages, user_input):
    messages.append({"role": "user", "content": user_input})
    reply_text = openai.ChatCompletion.create(
        model="gpt-4o", messages=messages
    )["choices"][0]["message"]["content"]
    messages.append({"role": "assistant", "content": reply_text})
    return reply_text


def main():
    engine = pyttsx3.init()
    engine.setProperty("rate", 120)
    engine.setProperty("voice", "greek")

    openai.api_key = "sk-..."
    messages = [
        {
            "role": "system",
            "content": (
                f"Your name is {ASSISTANT_NAME} and give answers in 2 lines"
            ),
        }
    ]
    while True:
        say_prompt(engine)
        with sr.Microphone() as source:
            recognizer = sr.Recognizer()
            recognizer.adjust_for_ambient_noise(source)
            recognizer.dynamic_energy_threshold = 3000

            try:
                print("Listening...")
                request = recognizer.recognize_google(
                    recognizer.listen(source, timeout=5)
                )
                print(request)

                if ASSISTANT_NAME.lower() in request.lower():
                    say(engine, get_response(messages, request))
                else:
                    print(f"Didn't recognize {ASSISTANT_NAME!r}.")

            except sr.UnknownValueError:
                print("Didn't recognize anything.")


if __name__ == "__main__":
    main()
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
Cancriformis
User
Beiträge: 3
Registriert: Sonntag 18. August 2024, 18:12

Hallo zusammen,

vielen Dank für die Vorschläge, Berichtigungen und Optimierungen. Werde in den kommenden Tagen
eure Vorschläge verifizieren/umsetzen und auch die ganze Sache auf einem 2. Rechner prüfen.

Vielen Dank an die jenigen, die sich die Mühe gemacht haben, mir zu helfen bzw. Dinge zu klären!
Grüße,
Cancriformis.
Benutzeravatar
Cancriformis
User
Beiträge: 3
Registriert: Sonntag 18. August 2024, 18:12

Hallo zusammen,

nach mehreren Stunden verteilt auf 3 Werktage war ich nun glücklicherweise in der Lage, die vorhandenen Fehler
auszumerzen und das Script korrekt ans Laufen zu bekommen. Ich muss dazu allerdings sagen, dass hat die
Erfahrung nun gezeigt, wenn man unter Windows etwas als "Standard-Eingabegerät" wie ein USB-Microfon
installiert, das dies nicht unbedingt so bleibt wie eingestellt. Auch wenn zwischenzeitig Updates durch MS
eingespielt werden, können diese ggf. für einen "Reset" dieser Einstellungen sorge tragen.

Warum div. Fehler beim ausführen des zuvor zusammengestellten Scripts angezeigt wurden, hing
einerseits mit nachfolgenden Tatsachen zusammen:

1. Das wie zuvor schon erwähnte Standard-Device "Mikrofon" für die Spracheingabe war nicht mehr vorhanden.
2. Div. Aufrufe in den Routinen von OpenAI sind ab der Version "1.0.0.0" mittlerweile untersagt.
3. Danach konnte ich die Optimierungen an den Routinen vornehmen, was die Funktionalität angeht.

Code: Alles auswählen

import speech_recognition as sr
import pyttsx3
from openai import OpenAI
import os

# gets API Key from environment variable OPENAI_API_KEY
#
os.environ['OPENAI_API_KEY'] = "sk-pro..."
client = OpenAI()

# Initialize the recognizer
r = sr.Recognizer()

# Function to convert text to speech
def SpeakText(command):
    # Initialize the engine
    engine = pyttsx3.init()
    engine.say(command)
    engine.runAndWait()

# Function to record and recognize speech
def record_text():
    try:
        # use the microphone as source for input.
        with sr.Microphone() as source:
            # wait for a second to let the recognizer
            # adjust the energy threshold based on
            # the surrounding noise level
            r.adjust_for_ambient_noise(source, duration=0.2)
            print("Ich lausche...!")

            # listens for the user's input
            audio = r.listen(source, 5)

            # Using google to recognize audio
            my_text = r.recognize_google( audio, language="de-DE")
            my_text = my_text.lower()

            return my_text

    except sr.RequestError as e:
        print("Could not request results; {0}".format(e))
        return None

    except sr.UnknownValueError:
        # print("Unknown error occurred")
        return None
    
def send_to_chatGPT(messages, model="gpt-4"):
    completion = client.chat.completions.create(
        model=model,
        messages=messages,
        n=1,
        stop=None,
        temperature=0.5,
    )

    message = completion.choices[0].message.content
    return message

def main():
    SpeakText(f"Hallo, ich bin Lisa! Wie kann ich Dir behilflich sein?")
    while(True):
        messages = []
        text = record_text()
        if text is None or text == "":
            print("")
        else:
            print("Du fragtest: " + text)
            SpeakText("Du fragtest: " + text)
            messages.append({"role":"user","content":text})
            response = send_to_chatGPT(messages)
            print(response)
            SpeakText(response)

if __name__ == "__main__":
    main()

Ich stelle den Quellcode in der letzten Version hiermit auch anderen Members zur Verfügung für den Fall, dass falls jemand
auch auf der Suche nach einer funktionierenden Lösung ist - einen Sprachassisenten für OpenAI sucht und/oder einsetzen möchte,
nicht wieder ganz neu das Rad erfinden muss. Viele Beispiel aus dem Internet funktionieren (nicht) mehr.

Zu Optimieren wird es aber immer einen Grund geben. :-)
Auf jeden Fall ist dieser Code unter Windows getestet und läuft ohne Abstürze, wenn die Voraussetzungen alle vorhanden sind.

Benutzt und erstellt mit Hilfe von:
- MS Visual Code v1.92.2
- Python3 v3.11
- Audio: USB Mikrofon und USB Lautsprecher (JBL)
Grüße,
Cancriformis.
Benutzeravatar
__blackjack__
User
Beiträge: 14000
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cancriformis: Da sind jetzt wieder globale Variablen. Und überflüssige und inhaltlich falsche Kommentare sind auch wieder da.

Was Funktionen machen würde man besser als Docstring schreiben und nicht als Kommentar. Da gehört auch nicht rein, dass es eine Funktion ist. Das sieht man auch ohne den Kommentar, dass es eine Funktion ist.

Die Namenskonventionen wurden auch komplett ignoriert. `SpeakText` wäre ein Klassenname, ist aber eine Funktion.

Warum heisst das Argument dort `command`?

Der erste Aufruf bekommt eine f-Zeichenkette übergeben in der gar kein Wert formatiert wird‽

`messages` als Liste zu definieren und da mit `append()` genau *ein* Element rein zu stecken ist ein bisschen sinnlos und der Name ist ja auch falsch wenn in `messages` — Mehrzahl — immer genau *eine* Nachricht drin steckt. Und so über die Schleife verteilt ist das auch ein bisschen irreführend.

Ausnahmebehandlung dazu zu benutzen um aus einer Ausnahme einen Fehlerrückgabewert zu machen ist in der Regel nicht gut. Ausnahmen gibt es ja unter anderem deswegen um besondere Fehlerrückgabewerte loszuwerden.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import logging
import os

import pyttsx3
import speech_recognition as sr
from openai import OpenAI


def say(text, also_print=True):
    if also_print:
        print(text)
    engine = pyttsx3.init()
    engine.say(text)
    engine.runAndWait()


def record_text(recognizer):
    with sr.Microphone() as source:
        recognizer.adjust_for_ambient_noise(source, duration=0.2)
        print("Ich lausche...!")
        return recognizer.recognize_google(
            recognizer.listen(source, 5), language="de-DE"
        ).lower()


def send_to_chat_gpt(client, text, model="gpt-4"):
    return (
        client.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": text}],
            n=1,
            stop=None,
            temperature=0.5,
        )
        .choices[0]
        .message.content
    )


def main():
    os.environ["OPENAI_API_KEY"] = "sk-pro..."
    client = OpenAI()

    recognizer = sr.Recognizer()

    say("Hallo, ich bin Lisa! Wie kann ich Dir behilflich sein?", False)
    while True:
        try:
            text = record_text(recognizer)
            if not text:
                print()
            else:
                say(f"Du fragtest: {text}")
                say(send_to_chat_gpt(client, text))

        except sr.RequestError:
            logging.exception("Could not request results.")
        except sr.UnknownValueError:
            logging.exception("Unknown value.")


if __name__ == "__main__":
    main()
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Antworten