Weiter zum Inhalt
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. ioBroker Allgemein
  4. Lösung für: Alexa Anfragen nach Chat-GPT umleiten

NEWS

  • Der neue Monatsrückblick für Mai und Juni 2026 ist online!
    BluefoxB
    Bluefox
    8
    1
    1.1k

  • wichtiges UPDATE für controller 7.2.2 im stable
    HomoranH
    Homoran
    10
    1
    3.6k

  • Neues YouTube-Video: Visualisierung im Devices-Adapter
    BluefoxB
    Bluefox
    16
    1
    6.3k

Lösung für: Alexa Anfragen nach Chat-GPT umleiten

Geplant Angeheftet Gesperrt Verschoben ioBroker Allgemein
10 Beiträge 4 Kommentatoren 353 Aufrufe 4 Beobachtet
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • D Offline
    D Offline
    derrapf
    schrieb am zuletzt editiert von derrapf
    #1

    Hallo alle
    Ich wollte Euch mein Projekt von heute nicht vorenthalten. Mir ging das ständige "Das weiss ich nicht" von Alexa auf den Keks und dann habe ich mit Claude zusammen ein Script gebaut, dass bei einer ich-habe-keine-Ahnung Antwort von Alexa einfach die Frage an Chat-GPT schickt, die Antwort abholt und dann von Alexa sprechen lässt.
    Das funktioniert ganz gut, mit Einschränkungen: Die "ich weiss nicht" Antwort von Alexa kommt leider immer, aber wenige Sekunden später kommt dann die Antwort von Chat-GPT. Ich habe versucht im Systempromt Chat-GPT daran zu hindern eine Rückfrage zu stellen, weil das wäre ja eine Sackgasse.
    Man kann auch direkt die KI addressieren in dem man sowas sagt wie "Alexa frag die KI was ist ein Neutrino"
    Triggerwörter könnt ihr im Script ergänzen.
    Die Datenpunkte müsst ihr ev. noch anpassen.

    Hier das Script

    /************************************************************
     * OpenAI – ChatGPT Abfrage für ioBroker (STABLE DEBUG VERSION)
     ************************************************************/
    
    /* ===================== Namespace ===================== */
    
    const ns = {
        MODEL_ID: 'gpt-4.1-mini',
    
        QUESTION_DP_ID:  '0_userdata.0.Manuelle_Datenpunkte.OpenAI.OpenAIQuestion',
        ANSWER_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.OpenAI.OpenAIAnswer',
        APIKEY_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.OpenAI.ApiKey',
    
        ALEXA_SUMMARY_DP_ID:    'alexa2.0.History.summary',
        ALEXA_ANSWERTEXT_DP_ID: 'alexa2.0.History.answerText',
        ALEXA_SPEAK_DP_ID:      'alexa2.0.Echo-Devices.G090U509848221KE.Commands.speak'
    };
    
    ns.https = require('https');
    
    console.log("### SCRIPT START V8 ###");
    
    /* ===================== Zwischenspeicher für die letzte Frage ===================== */
    
    // Wird bei JEDER Änderung von "summary" sofort synchron aktualisiert.
    // Grund: Bei mehreren Echo-Geräten im Haus (Device Arbitration) wird "summary"
    // kurz nach der eigentlichen Frage von den "Verlierer"-Geräten wieder auf ""
    // zurückgesetzt. Ein späteres getState() im answerText-Trigger kommt dann oft
    // zu spät und liest bereits einen leeren Wert. Deshalb hier zwischenspeichern.
    let letzteFrage = '';
    
    /* ===================== Generische OpenAI Anfrage ===================== */
    
    function callOpenAI(inputText, callback) {
    
        const apiKey = getState(ns.APIKEY_DP_ID).val;
    
        if (!apiKey || String(apiKey).trim().length < 10) {
            console.error("API-Key fehlt oder ist ungültig! Bitte in " + ns.APIKEY_DP_ID + " eintragen.");
            callback(null, "Fehler: API-Key nicht konfiguriert");
            return;
        }
    
        const payloadObj = {
            model: ns.MODEL_ID,
            input: inputText
        };
    
        const payload = JSON.stringify(payloadObj);
    
        const options = {
            hostname: 'api.openai.com',
            path: '/v1/responses',
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${apiKey}`
            }
        };
    
        const req = ns.https.request(options, res => {
    
            let data = '';
    
            res.on('data', chunk => {
                data += chunk;
            });
    
            res.on('end', () => {
    
                console.log("STATUS: " + res.statusCode);
                console.log("RESPONSE RAW: " + data);
    
                try {
                    const json = JSON.parse(data);
    
                    if (json.error) {
                        callback(null, "OpenAI Fehler: " + json.error.message);
                        return;
                    }
    
                    let answer = "Keine Antwort";
    
                    try {
                        answer = json.output[0].content
                            .map(c => c.text || '')
                            .join('')
                            .trim();
                    } catch (e) {
                        console.log("Parsing Fehler:", e);
                    }
    
                    callback(answer, null);
    
                } catch (e) {
                    console.log("JSON Fehler:", e);
                    callback(null, "Fehler beim Parsen");
                }
            });
        });
    
        req.on('error', err => {
            console.error("HTTP Fehler:", err);
            callback(null, "Verbindungsfehler");
        });
    
        req.write(payload);
        req.end();
    }
    
    /* ===================== ChatGPT fragen (normale Anfrage) ===================== */
    
    function askChatGPT(question, callback) {
    
        const prompt =
            'Du bist die Sprachausgabe eines Smart-Speakers. Der Nutzer kann NICHT antworten oder nachfragen – ' +
            'deine Antwort wird einmalig vorgelesen und die Interaktion ist danach beendet. ' +
            'Beantworte die folgende Frage deshalb IMMER mit einer konkreten Aussage in maximal 1-2 Sätzen. ' +
            'Stelle unter keinen Umständen eine Rückfrage und bitte nicht um weitere Details – ' +
            'das ist technisch nicht möglich und würde den Nutzer nur verwirren. ' +
            'Falls die Frage mehrdeutig oder unterspezifiziert ist, sag das kurz UND gib trotzdem direkt ' +
            'die naheliegendste Antwort oder ein plausibles Beispiel, statt nach mehr Informationen zu fragen. ' +
            'Frage: ' + question;
    
        callOpenAI(prompt, (answer, error) => {
            if (error) {
                callback(error);
                return;
            }
            callback(answer);
        });
    }
    
    /* ===================== Klassifikation: "weiß nicht"-Antwort? ===================== */
    
    function istWeissNichtAntwort(answerText, callback) {
    
        const prompt =
            'Antworte NUR mit "ja" oder "nein", ohne weiteren Text. ' +
            'Ist folgende Antwort eines Sprachassistenten eine Aussage, dass er die Frage NICHT beantworten konnte ' +
            '(z.B. "weiß ich nicht", "kann ich nicht helfen", "habe ich nicht verstanden" o.ä.), ' +
            'im Gegensatz zu einer inhaltlichen, echten Antwort? ' +
            'Antwort des Sprachassistenten: "' + answerText + '"';
    
        callOpenAI(prompt, (result, error) => {
    
            if (error) {
                console.log("Klassifikation fehlgeschlagen: " + error);
                // Im Zweifel: kein Fallback auslösen, um Endlosschleifen/unnötige Kosten zu vermeiden
                callback(false);
                return;
            }
    
            const normalized = String(result || '').trim().toLowerCase();
            console.log("KLASSIFIKATION ERGEBNIS: " + normalized);
    
            callback(normalized.startsWith('ja'));
        });
    }
    
    /* ===================== Trigger: manuelle Frage ===================== */
    
    on({ id: ns.QUESTION_DP_ID, change: 'ne' }, obj => {
    
        const question = String(obj.state.val || '').trim();
    
        console.log("FRAGE: " + question);
    
        if (!question || question.length < 2) {
            console.log("Frage ungültig");
            return;
        }
    
        setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
    
        askChatGPT(question, answer => {
            console.log("ANTWORT: " + answer);
            setState(ns.ANSWER_DP_ID, answer, true);
        });
    });
    
    /* ===================== Trigger: summary geändert -> Frage merken + Direkt-KI prüfen ===================== */
    
    // Wenn die Frage mit einer dieser Phrasen beginnt, sofort an ChatGPT weiterleiten,
    // ohne auf Alexas eigene Antwort zu warten.
    const KI_TRIGGER_PHRASES = [
        'frag gpt',
        'frage gpt',
        'frag chatgpt',
        'frage chatgpt',
        'frag chat',
        'frage chat',
        'frag die ki',
        'frage die ki',
        'frag ki',
        'frage ki',
        'frag jarvis',
        'frage jarvis'
    ];
    
    on({ id: ns.ALEXA_SUMMARY_DP_ID, change: 'ne' }, obj => {
    
        const summaryRaw = String(obj.state.val || '').trim();
    
        if (!summaryRaw) return;
    
        // Frage sofort synchron zwischenspeichern (siehe Erklärung oben)
        letzteFrage = summaryRaw;
        console.log("Frage zwischengespeichert: " + letzteFrage);
    
        const summary = summaryRaw.toLowerCase();
    
        // Längste Phrase zuerst prüfen, damit z.B. "frag die ki" vor "frag ki" greift
        const sortedPhrases = [...KI_TRIGGER_PHRASES].sort((a, b) => b.length - a.length);
        const treffer = sortedPhrases.find(p => summary.startsWith(p + ' ') || summary === p);
    
        if (!treffer) return; // keine Trigger-Phrase -> normaler Ablauf über answerText
    
        // Phrase aus der Frage entfernen
        let question = summary.slice(treffer.length).trim();
        question = question.replace(/^,\s*/, ''); // führendes Komma entfernen, falls vorhanden
    
        if (!question || question.length < 2) {
            console.log("Direkte KI-Anfrage: Frage nach Trigger-Phrase ungültig.");
            return;
        }
    
        console.log("Direkte KI-Anfrage erkannt, leite sofort weiter: " + question);
    
        setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
    
        askChatGPT(question, answer => {
            console.log("ANTWORT (Direkt-KI): " + answer);
    
            setState(ns.ANSWER_DP_ID, answer, true);
            setState(ns.ALEXA_SPEAK_DP_ID, answer, true);
        });
    });
    
    /* ===================== Trigger: Alexa konnte nicht antworten (Fallback) ===================== */
    
    on({ id: ns.ALEXA_ANSWERTEXT_DP_ID, change: 'ne' }, obj => {
    
        const answerText = String(obj.state.val || '').trim();
        console.log("ALEXA ANSWERTEXT: " + answerText);
    
        if (!answerText) return;
    
        istWeissNichtAntwort(answerText, konnteNichtAntworten => {
    
            if (!konnteNichtAntworten) {
                console.log("Alexa konnte antworten – keine Weiterleitung an ChatGPT.");
                return;
            }
    
            const question = letzteFrage;
    
            if (!question || question.length < 2) {
                console.log("Keine gültige zwischengespeicherte Frage vorhanden.");
                return;
            }
    
            console.log("Alexa wusste keine Antwort – leite Frage an ChatGPT weiter: " + question);
    
            setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
    
            askChatGPT(question, answer => {
                console.log("ANTWORT (Alexa-Fallback): " + answer);
    
                const speakText = "Aber ich hab mal nachgefragt: " + answer;
    
                setState(ns.ANSWER_DP_ID, answer, true);
                setState(ns.ALEXA_SPEAK_DP_ID, speakText, true);
            });
        });
    });
    

    Ich denke damit solltet ihr klar kommen. Die Datenpunkte sind ganz oben definiert.

    Euren API KEy müsst ihr euch von Open-Ai besorgen und dann im entsprechenden Datenpunkt (Konstante QUESTION_DP_ID) eintragen.

    Gruss Ralf

    OliverIOO 1 Antwort Letzte Antwort
    1
    • Dr. BakteriusD Offline
      Dr. BakteriusD Offline
      Dr. Bakterius
      Most Active
      schrieb am zuletzt editiert von
      #2

      Danke! Sehe ich das richtig, dass jede Antwort von Alexa an ChatGPT gesendet wird? Also auch jedes 'Okay'?

      1 Antwort Letzte Antwort
      0
      • D Offline
        D Offline
        derrapf
        schrieb am zuletzt editiert von derrapf
        #3

        Nein. Nur wenn Alexa meint, dass sie keine Antwort hat. Um das aber rauszufinden (sie sagt ja auf unterschiedliche Weise, dass sie nichts blickt) schicke ich die Antwort auch an die KI um rauszufinden ob es eine negative Antwort ist. Wenn ja wird die Frage an ChatGPT weiter gereicht. Inzwischen mache ich es so, dass diese erste Prüfung mit einem ganz einfachen und billigen Modell gemacht wird. Kann ich noch posten
        Gruss Ralf

        Dr. BakteriusD 1 Antwort Letzte Antwort
        0
        • D derrapf

          Hallo alle
          Ich wollte Euch mein Projekt von heute nicht vorenthalten. Mir ging das ständige "Das weiss ich nicht" von Alexa auf den Keks und dann habe ich mit Claude zusammen ein Script gebaut, dass bei einer ich-habe-keine-Ahnung Antwort von Alexa einfach die Frage an Chat-GPT schickt, die Antwort abholt und dann von Alexa sprechen lässt.
          Das funktioniert ganz gut, mit Einschränkungen: Die "ich weiss nicht" Antwort von Alexa kommt leider immer, aber wenige Sekunden später kommt dann die Antwort von Chat-GPT. Ich habe versucht im Systempromt Chat-GPT daran zu hindern eine Rückfrage zu stellen, weil das wäre ja eine Sackgasse.
          Man kann auch direkt die KI addressieren in dem man sowas sagt wie "Alexa frag die KI was ist ein Neutrino"
          Triggerwörter könnt ihr im Script ergänzen.
          Die Datenpunkte müsst ihr ev. noch anpassen.

          Hier das Script

          /************************************************************
           * OpenAI – ChatGPT Abfrage für ioBroker (STABLE DEBUG VERSION)
           ************************************************************/
          
          /* ===================== Namespace ===================== */
          
          const ns = {
              MODEL_ID: 'gpt-4.1-mini',
          
              QUESTION_DP_ID:  '0_userdata.0.Manuelle_Datenpunkte.OpenAI.OpenAIQuestion',
              ANSWER_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.OpenAI.OpenAIAnswer',
              APIKEY_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.OpenAI.ApiKey',
          
              ALEXA_SUMMARY_DP_ID:    'alexa2.0.History.summary',
              ALEXA_ANSWERTEXT_DP_ID: 'alexa2.0.History.answerText',
              ALEXA_SPEAK_DP_ID:      'alexa2.0.Echo-Devices.G090U509848221KE.Commands.speak'
          };
          
          ns.https = require('https');
          
          console.log("### SCRIPT START V8 ###");
          
          /* ===================== Zwischenspeicher für die letzte Frage ===================== */
          
          // Wird bei JEDER Änderung von "summary" sofort synchron aktualisiert.
          // Grund: Bei mehreren Echo-Geräten im Haus (Device Arbitration) wird "summary"
          // kurz nach der eigentlichen Frage von den "Verlierer"-Geräten wieder auf ""
          // zurückgesetzt. Ein späteres getState() im answerText-Trigger kommt dann oft
          // zu spät und liest bereits einen leeren Wert. Deshalb hier zwischenspeichern.
          let letzteFrage = '';
          
          /* ===================== Generische OpenAI Anfrage ===================== */
          
          function callOpenAI(inputText, callback) {
          
              const apiKey = getState(ns.APIKEY_DP_ID).val;
          
              if (!apiKey || String(apiKey).trim().length < 10) {
                  console.error("API-Key fehlt oder ist ungültig! Bitte in " + ns.APIKEY_DP_ID + " eintragen.");
                  callback(null, "Fehler: API-Key nicht konfiguriert");
                  return;
              }
          
              const payloadObj = {
                  model: ns.MODEL_ID,
                  input: inputText
              };
          
              const payload = JSON.stringify(payloadObj);
          
              const options = {
                  hostname: 'api.openai.com',
                  path: '/v1/responses',
                  method: 'POST',
                  headers: {
                      'Content-Type': 'application/json',
                      'Authorization': `Bearer ${apiKey}`
                  }
              };
          
              const req = ns.https.request(options, res => {
          
                  let data = '';
          
                  res.on('data', chunk => {
                      data += chunk;
                  });
          
                  res.on('end', () => {
          
                      console.log("STATUS: " + res.statusCode);
                      console.log("RESPONSE RAW: " + data);
          
                      try {
                          const json = JSON.parse(data);
          
                          if (json.error) {
                              callback(null, "OpenAI Fehler: " + json.error.message);
                              return;
                          }
          
                          let answer = "Keine Antwort";
          
                          try {
                              answer = json.output[0].content
                                  .map(c => c.text || '')
                                  .join('')
                                  .trim();
                          } catch (e) {
                              console.log("Parsing Fehler:", e);
                          }
          
                          callback(answer, null);
          
                      } catch (e) {
                          console.log("JSON Fehler:", e);
                          callback(null, "Fehler beim Parsen");
                      }
                  });
              });
          
              req.on('error', err => {
                  console.error("HTTP Fehler:", err);
                  callback(null, "Verbindungsfehler");
              });
          
              req.write(payload);
              req.end();
          }
          
          /* ===================== ChatGPT fragen (normale Anfrage) ===================== */
          
          function askChatGPT(question, callback) {
          
              const prompt =
                  'Du bist die Sprachausgabe eines Smart-Speakers. Der Nutzer kann NICHT antworten oder nachfragen – ' +
                  'deine Antwort wird einmalig vorgelesen und die Interaktion ist danach beendet. ' +
                  'Beantworte die folgende Frage deshalb IMMER mit einer konkreten Aussage in maximal 1-2 Sätzen. ' +
                  'Stelle unter keinen Umständen eine Rückfrage und bitte nicht um weitere Details – ' +
                  'das ist technisch nicht möglich und würde den Nutzer nur verwirren. ' +
                  'Falls die Frage mehrdeutig oder unterspezifiziert ist, sag das kurz UND gib trotzdem direkt ' +
                  'die naheliegendste Antwort oder ein plausibles Beispiel, statt nach mehr Informationen zu fragen. ' +
                  'Frage: ' + question;
          
              callOpenAI(prompt, (answer, error) => {
                  if (error) {
                      callback(error);
                      return;
                  }
                  callback(answer);
              });
          }
          
          /* ===================== Klassifikation: "weiß nicht"-Antwort? ===================== */
          
          function istWeissNichtAntwort(answerText, callback) {
          
              const prompt =
                  'Antworte NUR mit "ja" oder "nein", ohne weiteren Text. ' +
                  'Ist folgende Antwort eines Sprachassistenten eine Aussage, dass er die Frage NICHT beantworten konnte ' +
                  '(z.B. "weiß ich nicht", "kann ich nicht helfen", "habe ich nicht verstanden" o.ä.), ' +
                  'im Gegensatz zu einer inhaltlichen, echten Antwort? ' +
                  'Antwort des Sprachassistenten: "' + answerText + '"';
          
              callOpenAI(prompt, (result, error) => {
          
                  if (error) {
                      console.log("Klassifikation fehlgeschlagen: " + error);
                      // Im Zweifel: kein Fallback auslösen, um Endlosschleifen/unnötige Kosten zu vermeiden
                      callback(false);
                      return;
                  }
          
                  const normalized = String(result || '').trim().toLowerCase();
                  console.log("KLASSIFIKATION ERGEBNIS: " + normalized);
          
                  callback(normalized.startsWith('ja'));
              });
          }
          
          /* ===================== Trigger: manuelle Frage ===================== */
          
          on({ id: ns.QUESTION_DP_ID, change: 'ne' }, obj => {
          
              const question = String(obj.state.val || '').trim();
          
              console.log("FRAGE: " + question);
          
              if (!question || question.length < 2) {
                  console.log("Frage ungültig");
                  return;
              }
          
              setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
          
              askChatGPT(question, answer => {
                  console.log("ANTWORT: " + answer);
                  setState(ns.ANSWER_DP_ID, answer, true);
              });
          });
          
          /* ===================== Trigger: summary geändert -> Frage merken + Direkt-KI prüfen ===================== */
          
          // Wenn die Frage mit einer dieser Phrasen beginnt, sofort an ChatGPT weiterleiten,
          // ohne auf Alexas eigene Antwort zu warten.
          const KI_TRIGGER_PHRASES = [
              'frag gpt',
              'frage gpt',
              'frag chatgpt',
              'frage chatgpt',
              'frag chat',
              'frage chat',
              'frag die ki',
              'frage die ki',
              'frag ki',
              'frage ki',
              'frag jarvis',
              'frage jarvis'
          ];
          
          on({ id: ns.ALEXA_SUMMARY_DP_ID, change: 'ne' }, obj => {
          
              const summaryRaw = String(obj.state.val || '').trim();
          
              if (!summaryRaw) return;
          
              // Frage sofort synchron zwischenspeichern (siehe Erklärung oben)
              letzteFrage = summaryRaw;
              console.log("Frage zwischengespeichert: " + letzteFrage);
          
              const summary = summaryRaw.toLowerCase();
          
              // Längste Phrase zuerst prüfen, damit z.B. "frag die ki" vor "frag ki" greift
              const sortedPhrases = [...KI_TRIGGER_PHRASES].sort((a, b) => b.length - a.length);
              const treffer = sortedPhrases.find(p => summary.startsWith(p + ' ') || summary === p);
          
              if (!treffer) return; // keine Trigger-Phrase -> normaler Ablauf über answerText
          
              // Phrase aus der Frage entfernen
              let question = summary.slice(treffer.length).trim();
              question = question.replace(/^,\s*/, ''); // führendes Komma entfernen, falls vorhanden
          
              if (!question || question.length < 2) {
                  console.log("Direkte KI-Anfrage: Frage nach Trigger-Phrase ungültig.");
                  return;
              }
          
              console.log("Direkte KI-Anfrage erkannt, leite sofort weiter: " + question);
          
              setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
          
              askChatGPT(question, answer => {
                  console.log("ANTWORT (Direkt-KI): " + answer);
          
                  setState(ns.ANSWER_DP_ID, answer, true);
                  setState(ns.ALEXA_SPEAK_DP_ID, answer, true);
              });
          });
          
          /* ===================== Trigger: Alexa konnte nicht antworten (Fallback) ===================== */
          
          on({ id: ns.ALEXA_ANSWERTEXT_DP_ID, change: 'ne' }, obj => {
          
              const answerText = String(obj.state.val || '').trim();
              console.log("ALEXA ANSWERTEXT: " + answerText);
          
              if (!answerText) return;
          
              istWeissNichtAntwort(answerText, konnteNichtAntworten => {
          
                  if (!konnteNichtAntworten) {
                      console.log("Alexa konnte antworten – keine Weiterleitung an ChatGPT.");
                      return;
                  }
          
                  const question = letzteFrage;
          
                  if (!question || question.length < 2) {
                      console.log("Keine gültige zwischengespeicherte Frage vorhanden.");
                      return;
                  }
          
                  console.log("Alexa wusste keine Antwort – leite Frage an ChatGPT weiter: " + question);
          
                  setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
          
                  askChatGPT(question, answer => {
                      console.log("ANTWORT (Alexa-Fallback): " + answer);
          
                      const speakText = "Aber ich hab mal nachgefragt: " + answer;
          
                      setState(ns.ANSWER_DP_ID, answer, true);
                      setState(ns.ALEXA_SPEAK_DP_ID, speakText, true);
                  });
              });
          });
          

          Ich denke damit solltet ihr klar kommen. Die Datenpunkte sind ganz oben definiert.

          Euren API KEy müsst ihr euch von Open-Ai besorgen und dann im entsprechenden Datenpunkt (Konstante QUESTION_DP_ID) eintragen.

          Gruss Ralf

          OliverIOO Offline
          OliverIOO Offline
          OliverIO
          schrieb am zuletzt editiert von OliverIO
          #4

          @derrapf

          Wie ist da die Latenz?

          Was kommt da so an api kosten zusammen?
          Reicht das 4.1 mini Modell aus?

          Optimieren könnte man das noch in dem das als custom Gpt nutzt, indem man als systemprompt den Standard prompt und als User Message die eigentliche Frage mitgibt. Da gibt es entsprechende Message Rollen. Diese werden als cached tokens abgerechnet, die etwas günstiger sind, als wenn das immer im prompt mitkommt, was als Input Token abgerechnet wird.

          So war es zumindest letztes Jahr noch, als wir für einen Kunden was gemacht haben (hatte aber nix mit iobroker zu tun)

          760a3480-4e7a-43f5-95b7-a72800e21004-image.jpeg

          Erwähnenswert ist auch das das nicht über das Standard Abo Modell geht, sondern man extra Geld einzahlen muss.

          Aber für so Abfragen hält sich der Tokenverbrauch in Grenzen. Alle Preise sind immer pro eine Million Token.

          Ich wäre auch auf 5.6 Luna umstellen, da es im vergleich intelligenter und günstiger ist

          249ee89c-1165-4447-a0e7-b39a4d172931-image.jpeg

          Da sich dort allerdings die api geändert hat, geht das nicht durch einfachen Tausch des Modell Namens

          Meine Adapter und Widgets
          TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
          Links im Profil

          1 Antwort Letzte Antwort
          0
          • D derrapf

            Nein. Nur wenn Alexa meint, dass sie keine Antwort hat. Um das aber rauszufinden (sie sagt ja auf unterschiedliche Weise, dass sie nichts blickt) schicke ich die Antwort auch an die KI um rauszufinden ob es eine negative Antwort ist. Wenn ja wird die Frage an ChatGPT weiter gereicht. Inzwischen mache ich es so, dass diese erste Prüfung mit einem ganz einfachen und billigen Modell gemacht wird. Kann ich noch posten
            Gruss Ralf

            Dr. BakteriusD Offline
            Dr. BakteriusD Offline
            Dr. Bakterius
            Most Active
            schrieb am zuletzt editiert von
            #5

            @derrapf sagte:

            schicke ich die Antwort auch an die KI um rauszufinden ob es eine negative Antwort ist

            Und das meinte ich mit "dass jede Antwort von Alexa an ChatGPT gesendet wird". Oder wo wird festgestellt, dass Alexa die Antwort nicht weiß?

            1 Antwort Letzte Antwort
            0
            • D Offline
              D Offline
              derrapf
              schrieb am zuletzt editiert von derrapf
              #6

              So, hier nochmal das aktuelle Script:

              /************************************************************
               * OpenAI – ChatGPT Abfrage für ioBroker (STABLE DEBUG VERSION)
               ************************************************************/
              
              /* ===================== Namespace ===================== */
              
              const ns = {
                  MODEL_ID:          'gpt-4.1-mini', // für die eigentlichen Antworten (bessere Qualität)
                  CLASSIFY_MODEL_ID: 'gpt-4.1-nano', // für die simple ja/nein-Klassifikation (günstiger & schneller)
              
                  QUESTION_DP_ID:  '0_userdata.0.Manuelle_Datenpunkte.OpenAI.OpenAIQuestion',
                  ANSWER_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.OpenAI.OpenAIAnswer',
                  APIKEY_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.OpenAI.ApiKey',
              
                  ALEXA_SUMMARY_DP_ID:    'alexa2.0.History.summary',
                  ALEXA_ANSWERTEXT_DP_ID: 'alexa2.0.History.answerText',
                  ALEXA_SPEAK_DP_ID:      'alexa2.0.Echo-Devices.G090U509848221KE.Commands.speak'
              };
              
              ns.https = require('https');
              
              console.log("### SCRIPT START V8 ###");
              
              /* ===================== Zwischenspeicher für die letzte Frage ===================== */
              
              // Wird bei JEDER Änderung von "summary" sofort synchron aktualisiert.
              // Grund: Bei mehreren Echo-Geräten im Haus (Device Arbitration) wird "summary"
              // kurz nach der eigentlichen Frage von den "Verlierer"-Geräten wieder auf ""
              // zurückgesetzt. Ein späteres getState() im answerText-Trigger kommt dann oft
              // zu spät und liest bereits einen leeren Wert. Deshalb hier zwischenspeichern.
              let letzteFrage = '';
              
              /* ===================== Generische OpenAI Anfrage ===================== */
              
              function callOpenAI(inputText, model, callback) {
              
                  const apiKey = getState(ns.APIKEY_DP_ID).val;
              
                  if (!apiKey || String(apiKey).trim().length < 10) {
                      console.error("API-Key fehlt oder ist ungültig! Bitte in " + ns.APIKEY_DP_ID + " eintragen.");
                      callback(null, "Fehler: API-Key nicht konfiguriert");
                      return;
                  }
              
                  const payloadObj = {
                      model: model,
                      input: inputText
                  };
              
                  const payload = JSON.stringify(payloadObj);
              
                  const options = {
                      hostname: 'api.openai.com',
                      path: '/v1/responses',
                      method: 'POST',
                      headers: {
                          'Content-Type': 'application/json',
                          'Authorization': `Bearer ${apiKey}`
                      }
                  };
              
                  const req = ns.https.request(options, res => {
              
                      let data = '';
              
                      res.on('data', chunk => {
                          data += chunk;
                      });
              
                      res.on('end', () => {
              
                          console.log("STATUS: " + res.statusCode);
                          console.log("RESPONSE RAW: " + data);
              
                          try {
                              const json = JSON.parse(data);
              
                              if (json.error) {
                                  callback(null, "OpenAI Fehler: " + json.error.message);
                                  return;
                              }
              
                              let answer = "Keine Antwort";
              
                              try {
                                  answer = json.output[0].content
                                      .map(c => c.text || '')
                                      .join('')
                                      .trim();
                              } catch (e) {
                                  console.log("Parsing Fehler:", e);
                              }
              
                              callback(answer, null);
              
                          } catch (e) {
                              console.log("JSON Fehler:", e);
                              callback(null, "Fehler beim Parsen");
                          }
                      });
                  });
              
                  req.on('error', err => {
                      console.error("HTTP Fehler:", err);
                      callback(null, "Verbindungsfehler");
                  });
              
                  req.write(payload);
                  req.end();
              }
              
              /* ===================== ChatGPT fragen (normale Anfrage) ===================== */
              
              function askChatGPT(question, callback) {
              
                  const prompt =
                      'Du bist die Sprachausgabe eines Smart-Speakers. Der Nutzer kann NICHT antworten oder nachfragen – ' +
                      'deine Antwort wird einmalig vorgelesen und die Interaktion ist danach beendet. ' +
                      'Beantworte die folgende Frage deshalb IMMER mit einer konkreten Aussage in maximal 1-2 Sätzen. ' +
                      'Stelle unter keinen Umständen eine Rückfrage und bitte nicht um weitere Details – ' +
                      'das ist technisch nicht möglich und würde den Nutzer nur verwirren. ' +
                      'Falls die Frage mehrdeutig oder unterspezifiziert ist, sag das kurz UND gib trotzdem direkt ' +
                      'die naheliegendste Antwort oder ein plausibles Beispiel, statt nach mehr Informationen zu fragen. ' +
                      'Frage: ' + question;
              
                  callOpenAI(prompt, ns.MODEL_ID, (answer, error) => {
                      if (error) {
                          callback(error);
                          return;
                      }
                      callback(answer);
                  });
              }
              
              /* ===================== Klassifikation: "weiß nicht"-Antwort? ===================== */
              
              function istWeissNichtAntwort(answerText, callback) {
              
                  const prompt =
                      'Antworte NUR mit "ja" oder "nein", ohne weiteren Text. ' +
                      'Ist folgende Antwort eines Sprachassistenten eine Aussage, dass er die Frage NICHT beantworten konnte ' +
                      '(z.B. "weiß ich nicht", "kann ich nicht helfen", "habe ich nicht verstanden" o.ä.), ' +
                      'im Gegensatz zu einer inhaltlichen, echten Antwort? ' +
                      'Antwort des Sprachassistenten: "' + answerText + '"';
              
                  callOpenAI(prompt, ns.CLASSIFY_MODEL_ID, (result, error) => {
              
                      if (error) {
                          console.log("Klassifikation fehlgeschlagen: " + error);
                          // Im Zweifel: kein Fallback auslösen, um Endlosschleifen/unnötige Kosten zu vermeiden
                          callback(false);
                          return;
                      }
              
                      const normalized = String(result || '').trim().toLowerCase();
                      console.log("KLASSIFIKATION ERGEBNIS: " + normalized);
              
                      callback(normalized.startsWith('ja'));
                  });
              }
              
              /* ===================== Trigger: manuelle Frage ===================== */
              
              on({ id: ns.QUESTION_DP_ID, change: 'ne' }, obj => {
              
                  const question = String(obj.state.val || '').trim();
              
                  console.log("FRAGE: " + question);
              
                  if (!question || question.length < 2) {
                      console.log("Frage ungültig");
                      return;
                  }
              
                  setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
              
                  askChatGPT(question, answer => {
                      console.log("ANTWORT: " + answer);
                      setState(ns.ANSWER_DP_ID, answer, true);
                  });
              });
              
              /* ===================== Trigger: summary geändert -> Frage merken + Direkt-KI prüfen ===================== */
              
              // Wenn die Frage mit einer dieser Phrasen beginnt, sofort an ChatGPT weiterleiten,
              // ohne auf Alexas eigene Antwort zu warten.
              const KI_TRIGGER_PHRASES = [
                  'frag gpt',
                  'frage gpt',
                  'frag chatgpt',
                  'frage chatgpt',
                  'frag chat',
                  'frage chat',
                  'frag die ki',
                  'frage die ki',
                  'frag ki',
                  'frage ki',
                  'frag jarvis',
                  'frage jarvis'
              ];
              
              on({ id: ns.ALEXA_SUMMARY_DP_ID, change: 'ne' }, obj => {
              
                  const summaryRaw = String(obj.state.val || '').trim();
              
                  if (!summaryRaw) return;
              
                  // Frage sofort synchron zwischenspeichern (siehe Erklärung oben)
                  letzteFrage = summaryRaw;
                  console.log("Frage zwischengespeichert: " + letzteFrage);
              
                  const summary = summaryRaw.toLowerCase();
              
                  // Längste Phrase zuerst prüfen, damit z.B. "frag die ki" vor "frag ki" greift
                  const sortedPhrases = [...KI_TRIGGER_PHRASES].sort((a, b) => b.length - a.length);
                  const treffer = sortedPhrases.find(p => summary.startsWith(p + ' ') || summary === p);
              
                  if (!treffer) return; // keine Trigger-Phrase -> normaler Ablauf über answerText
              
                  // Phrase aus der Frage entfernen
                  let question = summary.slice(treffer.length).trim();
                  question = question.replace(/^,\s*/, ''); // führendes Komma entfernen, falls vorhanden
              
                  if (!question || question.length < 2) {
                      console.log("Direkte KI-Anfrage: Frage nach Trigger-Phrase ungültig.");
                      return;
                  }
              
                  console.log("Direkte KI-Anfrage erkannt, leite sofort weiter: " + question);
              
                  setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
              
                  askChatGPT(question, answer => {
                      console.log("ANTWORT (Direkt-KI): " + answer);
              
                      setState(ns.ANSWER_DP_ID, answer, true);
                      setState(ns.ALEXA_SPEAK_DP_ID, answer, true);
                  });
              });
              
              /* ===================== Trigger: Alexa konnte nicht antworten (Fallback) ===================== */
              
              on({ id: ns.ALEXA_ANSWERTEXT_DP_ID, change: 'ne' }, obj => {
              
                  const answerText = String(obj.state.val || '').trim();
                  console.log("ALEXA ANSWERTEXT: " + answerText);
              
                  if (!answerText) return;
              
                  istWeissNichtAntwort(answerText, konnteNichtAntworten => {
              
                      if (!konnteNichtAntworten) {
                          console.log("Alexa konnte antworten – keine Weiterleitung an ChatGPT.");
                          return;
                      }
              
                      const question = letzteFrage;
              
                      if (!question || question.length < 2) {
                          console.log("Keine gültige zwischengespeicherte Frage vorhanden.");
                          return;
                      }
              
                      console.log("Alexa wusste keine Antwort – leite Frage an ChatGPT weiter: " + question);
              
                      setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
              
                      askChatGPT(question, answer => {
                          console.log("ANTWORT (Alexa-Fallback): " + answer);
              
                          const speakText = "Aber ich hab mal nachgefragt: " + answer;
              
                          setState(ns.ANSWER_DP_ID, answer, true);
                          setState(ns.ALEXA_SPEAK_DP_ID, speakText, true);
                      });
                  });
              });
              
              

              Die "billige" Anfrage ob es ein "ich weiss nicht" war geht mit dem "gpt-4.1-nano" Modell.
              Das bekommt das Script in der Funktion
              istWeissNichtAntwort raus.
              Der Rest dann mit dem "gpt-4.1-mini"
              Andere Modelle hab ich nicht ausprobiert. Wie sich das mit den Kosten entwickelt, kann ich dann irgendwann in ein paar Wochen / Monaten sagen. Ihr könnt aber gerne andere Modelle verwenden und dann Feedback geben.
              Zur Latenz: Nicht soo geil:
              Nach dem Alexa "Ich weiss nicht" gesagt hat, dauert es ein zwei Sekunden bis die Antwort von Chat-GPT kommt. Aber dass! eine kommt ist mir wichtiger als wann! sie kommt.

              Reicht das 4.1 mini Modell aus?

              Bis jetzt ja. Kommt halt drauf an was Du wissen willst. Wenn Du Fragen zu niedrigdimensionalen Topologien z.B. speziell für 4-Manigfaltigkeiten und Knotentheorie hast... dann eher nicht...

              Optimieren könnte man das noch

              Feel free. Ich werde dann gerne die optimierte Version übernehmen.
              Wie gesagt: Das sollte nur eine Anregung sein. Ihr dürft da gerne weiter dran optimieren. Ev. kann das auch mal Jemand in ein Addon giessen. Oder man erweitert das Alexa Addon damit...
              Gruss Ralf

              1 Antwort Letzte Antwort
              0
              • Andreas HochstögerA Online
                Andreas HochstögerA Online
                Andreas Hochstöger
                schrieb am zuletzt editiert von Andreas Hochstöger
                #7

                /************************************************************

                • Groq (Llama 3.3) – Alexa Fallback (MULTI-DEVICE VERSION)
                  ************************************************************/
                1 Antwort Letzte Antwort
                0
                • Andreas HochstögerA Online
                  Andreas HochstögerA Online
                  Andreas Hochstöger
                  schrieb am zuletzt editiert von Andreas Hochstöger
                  #8

                  [Groq (Llama 3.3) – Alexa Fallback (MULTI-DEVICE VERSION)

                  1 Antwort Letzte Antwort
                  0
                  • Andreas HochstögerA Online
                    Andreas HochstögerA Online
                    Andreas Hochstöger
                    schrieb am zuletzt editiert von
                    #9

                    Wer eine Gratis Version braucht kann das hier testen. Es werden 3 Datenpunkte in Manuelle Datenpunkte erstellt bitte hier den ApiKey eingeben.

                    1 Antwort Letzte Antwort
                    0
                    • Andreas HochstögerA Online
                      Andreas HochstögerA Online
                      Andreas Hochstöger
                      schrieb am zuletzt editiert von Andreas Hochstöger
                      #10
                      /************************************************************
                       * Groq (Llama 3.3) – Alexa Fallback (SMART-HOME-FIX VERSION)
                       ************************************************************/
                      
                      const ns = {
                          MODEL_ID: 'llama-3.3-70b-versatile',
                      
                          QUESTION_DP_ID:  '0_userdata.0.Manuelle_Datenpunkte.KI.Question',
                          ANSWER_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.KI.Answer',
                          APIKEY_DP_ID:    '0_userdata.0.Manuelle_Datenpunkte.KI.ApiKey',
                      
                          ALEXA_HISTORY_TRIGGER:   'alexa2.0.History.#trigger',
                          ALEXA_SUMMARY_DP_ID:     'alexa2.0.History.summary',
                          ALEXA_ANSWERTEXT_DP_ID:  'alexa2.0.History.answerText',
                          ALEXA_CREATIONTIME_DP_ID:'alexa2.0.History.creationTime',
                          ALEXA_SERIAL_DP_ID:      'alexa2.0.History.serialNumber',
                      
                          DEFAULT_SERIAL: 'Hier die Serialnummer von der Alexa eingeben',
                      
                          POLL_INTERVAL_MS: 15000,
                          MAX_AGE_MS:       120000
                      };
                      
                      ns.https = require('https');
                      
                      let lastProcessedQuestion = '';
                      let lastProcessedTime = 0;
                      
                      /* ===================== Auto-Setup ===================== */
                      async function setupDataPoints() {
                          const statesToSetup = [
                              { id: ns.QUESTION_DP_ID, name: 'KI Frage (Input)', def: '' },
                              { id: ns.ANSWER_DP_ID,   name: 'KI Antwort (Output)', def: '' },
                              { id: ns.APIKEY_DP_ID,   name: 'Groq API Key', def: '' }
                          ];
                          for (const state of statesToSetup) {
                              const obj = await getObjectAsync(state.id);
                              if (!obj) {
                                  await createStateAsync(state.id, state.def, false, {
                                      name: state.name, type: 'string', role: 'text', read: true, write: true
                                  });
                                  console.log('✅ Datenpunkt erstellt: ' + state.id);
                              }
                          }
                      }
                      
                      /* ===================== Sprachausgabe ===================== */
                      function speak(text, serial) {
                          let targetSerial = String(serial || '').trim();
                          if (!targetSerial || !getObject('alexa2.0.Echo-Devices.' + targetSerial)) {
                              console.log('⚠️ Seriennummer ungültig (' + targetSerial + '). Nutze Standard-Gerät.');
                              targetSerial = ns.DEFAULT_SERIAL;
                          }
                          const speakId = 'alexa2.0.Echo-Devices.' + targetSerial + '.Commands.speak';
                          console.log('🔊 AUSGABE ÜBER: ' + speakId);
                          setState(speakId, text, false);
                      }
                      
                      /* ===================== Groq API Call ===================== */
                      function callGroq(inputText, callback) {
                          const apiKey = getState(ns.APIKEY_DP_ID).val;
                          if (!apiKey || String(apiKey).trim().length < 10) {
                              callback(null, 'Fehler: API-Key fehlt');
                              return;
                          }
                      
                          const payload = JSON.stringify({
                              model: ns.MODEL_ID,
                              messages: [{ role: 'user', content: inputText }],
                              temperature: 0.5,
                              max_tokens: 150
                          });
                      
                          const options = {
                              hostname: 'api.groq.com',
                              path: '/openai/v1/chat/completions',
                              method: 'POST',
                              headers: {
                                  'Content-Type': 'application/json',
                                  'Authorization': 'Bearer ' + apiKey
                              }
                          };
                      
                          const req = ns.https.request(options, res => {
                              let data = '';
                              res.on('data', chunk => { data += chunk; });
                              res.on('end', () => {
                                  try {
                                      const json = JSON.parse(data);
                                      if (json.error) { callback(null, 'Groq Fehler: ' + json.error.message); return; }
                      
                                      let answer = 'Keine Antwort';
                                      if (json.choices && json.choices.length > 0) {
                                          answer = json.choices[0].message.content.trim();
                                      }
                                      callback(answer, null);
                                  } catch (e) {
                                      callback(null, 'JSON Parse Error');
                                  }
                              });
                          });
                          req.on('error', () => callback(null, 'HTTP Error'));
                          req.write(payload);
                          req.end();
                      }
                      
                      /* ===================== Prompts ===================== */
                      function askKI(question, callback) {
                          const prompt =
                              'Du bist die Sprachausgabe eines Smart-Speakers. Der Nutzer kann NICHT antworten oder nachfragen – ' +
                              'deine Antwort wird einmalig vorgelesen und die Interaktion ist danach beendet. ' +
                              'Beantworte die folgende Frage deshalb IMMER mit einer konkreten Aussage in maximal 1-2 Sätzen (unter 40 Wörtern). ' +
                              'Stelle unter keinen Umständen eine Rückfrage und bitte nicht um weitere Details. ' +
                              'WICHTIGER KONTEXT: Wenn der Nutzer nach "io broker", "i. o. broker" oder "iobroker" fragt, meint er die bekannte Open-Source Smart-Home-Plattform ioBroker, NICHT einen Finanzmakler oder "in Ordnung". ' +
                              'Frage: ' + question;
                          callGroq(prompt, callback);
                      }
                      
                      /* ===================== Klassifikation ===================== */
                      function istWeissNichtAntwort(answerText, callback) {
                          const prompt =
                              'Analysiere die Antwort eines Sprachassistenten. ' +
                              'Konnte der Assistent die Frage NICHT beantworten oder hat er unsinnigen Standard-Text ausgegeben (z.B. "weiß ich nicht", "kann ich nicht helfen", ' +
                              '"wie ich dir dabei helfen kann", "habe ich nicht verstanden", "Es konnte keine Zeit erkannt werden", "probiere es mit")? ' +
                              'Antworte AUSSCHLIESSLICH mit diesem JSON-Objekt: {"failed": true} oder {"failed": false}. ' +
                              'Kein Markdown, keine Erklärungen! ' +
                              'Antwort des Assistenten: "' + answerText + '"';
                      
                          callGroq(prompt, (result, error) => {
                              if (error) {
                                  console.log('🔴 Klassifikation API Fehler: ' + error);
                                  callback(false);
                                  return;
                              }
                              console.log('🟣 KI RAW ANTWORT: ' + result);
                              let failed = false;
                              try {
                                  const match = String(result).match(/\{[\s\S]*\}/);
                                  if (match) {
                                      failed = JSON.parse(match[0]).failed === true;
                                  }
                              } catch (e) {
                                  console.log('🔴 JSON Parsing Fehler: ' + e);
                              }
                              callback(failed);
                          });
                      }
                      
                      /* ===================== Smart-Home-Erkennung ===================== */
                      function istSmartHomeBefehl(question, answerText) {
                          const lowerQuestion = question.toLowerCase();
                          const lowerAnswer = String(answerText || '').toLowerCase();
                          
                          // Smart-Home-Trigger-Wörter
                          const smartHomeKeywords = [
                              'schalte', 'schalt', 'mache', 'mach', 'stelle', 'stell', 'setze', 'setz',
                              'licht', 'lampe', 'lampen', 'leuchte', 'leuchten',
                              'ein', 'aus', 'an', 'hell', 'dunkel', 'dimme', 'dimmen',
                              'temperatur', 'heizung', 'thermostat', 'klima',
                              'steckdose', 'steckdosen', 'schalter',
                              'szene', 'szenen', 'modus',
                              'öffne', 'schließe', 'tor', 'tür', 'garage', 'rollo', 'rollladen', 'vorhang',
                              'starte', 'stoppe', 'pause', 'musik', 'radio', 'playlist',
                              'timer', 'wecker', 'erinnere', 'erinnerung'
                          ];
                          
                          // Prüfe, ob die Frage Smart-Home-Wörter enthält
                          const hatSmartHomeKeyword = smartHomeKeywords.some(keyword => 
                              lowerQuestion.includes(keyword)
                          );
                          
                          // Prüfe, ob die Antwort eine Bestätigung ist (oder leer = Aktion ausgeführt)
                          const istBestaetigung = 
                              !answerText || answerText.trim() === '' ||
                              lowerAnswer.includes('eingeschaltet') ||
                              lowerAnswer.includes('ausgeschaltet') ||
                              lowerAnswer.includes('ok') ||
                              lowerAnswer.includes('fertig') ||
                              lowerAnswer.includes('erledigt') ||
                              lowerAnswer.includes('wird') ||
                              lowerAnswer.includes('habe ich') ||
                              lowerAnswer.length < 10; // Sehr kurze Antworten sind oft Bestätigungen
                          
                          const istSmartHome = hatSmartHomeKeyword && istBestaetigung;
                          
                          if (istSmartHome) {
                              console.log('🏠 SMART-HOME-BEFEHL ERKANNT – kein KI-Fallback nötig.');
                          }
                          
                          return istSmartHome;
                      }
                      
                      /* ===================== Direkt-KI-Phrasen ===================== */
                      const KI_TRIGGER_PHRASES = [
                          'frag gpt', 'frage gpt', 'frag chatgpt', 'frage chatgpt',
                          'frag chat', 'frage chat', 'frag die ki', 'frage die ki',
                          'frag ki', 'frage ki', 'frag jarvis', 'frage jarvis',
                          'frag google', 'frage google', 'frag gemini', 'frage gemini',
                          'frag llama', 'frage llama'
                      ];
                      
                      /* ===================== History-Eintrag verarbeiten ===================== */
                      function processHistoryEntry(summary, answerText, serial) {
                      
                          const now = Date.now();
                          if (summary === lastProcessedQuestion && (now - lastProcessedTime) < 10000) {
                              console.log('⏳ DEBOUNCE: Frage wurde gerade erst bearbeitet. Ignoriere doppelten Trigger.');
                              return;
                          }
                      
                          const lower = summary.toLowerCase();
                          const sorted = [...KI_TRIGGER_PHRASES].sort((a, b) => b.length - a.length);
                          const treffer = sorted.find(p => lower.startsWith(p + ' ') || lower === p);
                      
                          // 1) Direkte KI-Anfrage (z.B. "Alexa, frag Jarvis ...")
                          if (treffer) {
                              const question = summary.slice(treffer.length).trim().replace(/^,\s*/, '');
                              if (question.length >= 2) {
                                  console.log('🎯 Direkte KI-Anfrage erkannt: ' + question);
                                  lastProcessedQuestion = summary;
                                  lastProcessedTime = now;
                      
                                  setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
                                  askKI(question, (answer, err) => {
                                      const text = err || answer;
                                      console.log('🏆 KI ANTWORT: ' + text);
                                      setState(ns.ANSWER_DP_ID, text, true);
                                      speak(text, serial);
                                  });
                                  return;
                              }
                          }
                      
                          // 2) WICHTIG: Ist es ein Smart-Home-Befehl? Dann KEIN Fallback!
                          if (istSmartHomeBefehl(summary, answerText)) {
                              lastProcessedQuestion = summary;
                              lastProcessedTime = now;
                              return; // Abbruch – Alexa hat die Aktion erfolgreich ausgeführt
                          }
                      
                          // 3) Fallback: Alexa-Antwort war komplett leer (bei Wissensfragen)
                          if (!answerText || answerText.trim() === '') {
                              console.log('⚠️ Keine Alexa-Antwort in der History (leer). Leite sicherheitshalber an KI weiter.');
                              lastProcessedQuestion = summary;
                              lastProcessedTime = now;
                      
                              setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
                              askKI(summary, (answer, err) => {
                                  if (err) { setState(ns.ANSWER_DP_ID, err, true); return; }
                                  console.log('🏆 KI ANTWORT (bei leerem Alexa-Text): ' + answer);
                                  setState(ns.ANSWER_DP_ID, answer, true);
                                  speak('Aber ich hab mal nachgefragt: ' + answer, serial);
                              });
                              return;
                          }
                      
                          // 4) Normaler Fallback: Hat Alexa eine Ausrede gegeben?
                          istWeissNichtAntwort(answerText, failed => {
                              console.log('🟣 PRÜFUNG ERGEBNIS (Alexa versagt?): ' + failed);
                              if (!failed) { console.log('✅ Alexa wusste Rat – kein Fallback nötig.'); return; }
                      
                              lastProcessedQuestion = summary;
                              lastProcessedTime = now;
                      
                              console.log('🚨 ALEXA WUSSTE ES NICHT! Frage an KI: ' + summary);
                              setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
                              askKI(summary, (answer, err) => {
                                  if (err) { setState(ns.ANSWER_DP_ID, err, true); return; }
                                  console.log('🏆 KI ANTWORT: ' + answer);
                                  setState(ns.ANSWER_DP_ID, answer, true);
                                  speak('Aber ich hab mal nachgefragt: ' + answer, serial);
                              });
                          });
                      }
                      
                      /* ===================== Init ===================== */
                      async function init() {
                          console.log('### 🚀 SCRIPT START (SMART-HOME-FIX VERSION) ###');
                          await setupDataPoints();
                      
                          on({ id: ns.QUESTION_DP_ID, change: 'any' }, obj => {
                              const question = String(obj.state.val || '').trim();
                              if (!question || question.length < 2) return;
                              console.log('🟢 MANUELLE FRAGE: ' + question);
                              setState(ns.ANSWER_DP_ID, 'Bitte warten …', true);
                              askKI(question, (answer, err) => {
                                  setState(ns.ANSWER_DP_ID, err || answer, true);
                              });
                          });
                      
                          setState(ns.ALEXA_HISTORY_TRIGGER, true);
                          setInterval(() => {
                              setState(ns.ALEXA_HISTORY_TRIGGER, true);
                          }, ns.POLL_INTERVAL_MS);
                          console.log('🔄 History-Polling aktiv (alle ' + (ns.POLL_INTERVAL_MS / 1000) + ' Sekunden)');
                      
                          on({ id: ns.ALEXA_CREATIONTIME_DP_ID, change: 'ne' }, obj => {
                              const creationTime = obj.state.val;
                              console.log('📥 Neuer History-Eintrag: ' + creationTime);
                      
                              const t = new Date(creationTime).getTime();
                              if (!isNaN(t) && (Date.now() - t) > ns.MAX_AGE_MS) {
                                  console.log('⚠️ Eintrag ist zu alt – wird ignoriert.');
                                  return;
                              }
                      
                              setTimeout(() => {
                                  const summary    = String(getState(ns.ALEXA_SUMMARY_DP_ID).val || '').trim();
                                  const answerText = String(getState(ns.ALEXA_ANSWERTEXT_DP_ID).val || '').trim();
                                  const serial     = String(getState(ns.ALEXA_SERIAL_DP_ID).val || '').trim();
                      
                                  console.log('🟡 DEINE FRAGE: ' + summary);
                                  console.log('🔵 ALEXAS ANTWORT: ' + answerText);
                                  console.log('📱 FRAGENDES GERÄT: ' + serial);
                      
                                  if (!summary || summary.length < 2) return;
                                  processHistoryEntry(summary, answerText, serial);
                              }, 700);
                          });
                      
                          console.log('### 🟢 ALLES AKTIV – TESTE JETZT! ###');
                      }
                      
                      init();
                      
                      1 Antwort Letzte Antwort
                      0

                      Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.

                      Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.

                      Mit deinem Input könnte dieser Beitrag noch besser werden 💗

                      Registrieren Anmelden
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

                      ioBroker
                      Community Adapters
                      Donate
                      FAQ Cloud / IOT
                      HowTo: Node.js-Update
                      HowTo: Backup/Restore
                      Downloads
                      BLOG

                      461

                      Online

                      33.0k

                      Benutzer

                      83.6k

                      Themen

                      1.3m

                      Beiträge
                      Community
                      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                      ioBroker Community 2014-2026
                      logo
                      • Anmelden

                      • Du hast noch kein Konto? Registrieren

                      • Anmelden oder registrieren, um zu suchen
                      • Erster Beitrag
                        Letzter Beitrag
                      0
                      • Home
                      • Aktuell
                      • Tags
                      • Ungelesen 0
                      • Kategorien
                      • Unreplied
                      • Beliebt
                      • GitHub
                      • Docu
                      • Hilfe