Notify when ChatGPT is done answering.
// ==UserScript==
// @name ChatGTP answer alert
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Notify when ChatGPT is done answering.
// @author Jonathan Lepage
// @match https://chatgpt.com/c/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=chatgpt.com
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
console.log("Answer detection script")
let thinking = false
setInterval(() => {
//console.log("Checking for answer. hidden=", document.hidden, " hasFocus=", document.hasFocus())
if (document.querySelector('button[aria-label="Stop streaming"]')) {
if (!thinking) {
thinking = true
console.log("Thinking")
}
} else {
if (thinking) {
thinking = false
console.log("Answer is ready")
if (document.hidden || !document.hasFocus()) {
console.log("Tab is not focused: Showing notification")
const notif = new Notification("Answer is ready")
notif.onclick = () => {
window.focus();
notif.close();
};
chime()
} else {
console.log("Tab is focused: Skipping notification")
}
}
}
}, 100)
function chime() {
const context = new AudioContext()
const gainNode = context.createGain()
gainNode.connect(context.destination)
gainNode.gain.value = 0.2
const biquadFilter = context.createBiquadFilter()
biquadFilter.type = "lowpass"
biquadFilter.frequency.value = 2000
biquadFilter.connect(gainNode)
const notes = [0, 12, 24]
let startTime = context.currentTime
for (const [index, note] of notes.entries()) {
const freq = 440 * Math.pow(2, note / 12)
const duration = 0.06
const oscillator = context.createOscillator()
oscillator.connect(biquadFilter)
oscillator.type = "sawtooth"
oscillator.frequency.value = freq
oscillator.start(startTime)
oscillator.stop(startTime + duration)
startTime += duration
}
}
})();