parente.dev

Jupyter Tidbit: Run and say "done!"

August 27, 2018

This post originates from a gist that supports comments, forks, and execution in binder.


Summary

Many modern web browsers provide a speech synthesis API for JavaScript. You can write and invoke a function to have your notebook speak when it finishes executing certain cells, whether you're running it in JupyterLab (>=0.34) or classic Jupyter Notebook.

def speak(text):
    from IPython.display import Javascript as js, clear_output
    # Escape single quotes
    text = text.replace("'", r"\'")
    display(js('''
    if(window.speechSynthesis) {{
        var synth = window.speechSynthesis;
        synth.speak(new window.SpeechSynthesisUtterance('{text}'));
    }}
    '''.format(text=text)))
    # Clear the JS so that the notebook doesn't speak again when reopened/refreshed
    clear_output(False)

Example

When I open the demo.ipynb notebook below and Run All cells, I hear the notebook speak aloud when it finishes executing the first and second loops.

Why is this useful?

You can add notifications at select locations in your notebook to report execution progress even while you're not looking at the notebook

Alternatives

You can also use the %%javascript cell magic to achieve the same net effect in Jupyter Notebook.

%%javascript
if(window.speechSynthesis) {{
    var synth = window.speechSynthesis;
    synth.speak(new window.SpeechSynthesisUtterance('All done!'));
    setTimeout(this.clear_output.bind(this), 0);
}}

However, the same code doesn't properly clear the JS from the notebook document in JupyterLab, and the notebook speaks immediately when opened unless you clear the cell output manually.

The jupyter_contrib_nbextensions project includes a notify extension for Jupyter Notebook which can show desktop popups and play a sounds when unattended notebooks become idle.

demo.ipynb

In [1]:
def speak(text):
    from IPython.display import Javascript as js, clear_output
    # Escape single quotes
    text = text.replace("'", r"\'")
    display(js(f'''
    if(window.speechSynthesis) {{
        var synth = window.speechSynthesis;
        synth.speak(new window.SpeechSynthesisUtterance('{text}'));
    }}
    '''))
    # Clear the JS so that the notebook doesn't speak again when reopened/refreshed
    clear_output(False)
In [2]:
for i in range(int(1e8)): pass
speak("I'm done with the first loop.")
In [3]:
for i in range(int(1e8)): pass
In [4]:
speak("Now I'm really done!")

Another Read: Jupyter Tidbit: Kernels for text files in JupyterLab »

You can associate a Console panel and kernel with a text editor in JupyterLab, and use it to execute selected code, RStudio style.