Friday, April 17, 2026

Using a VPN with Raspberry Pi

For an index to all my stories click this text.

In a previous story I explained what a VPN is and how to install that service when your computer runs Kubuntu (Linux)

This story explains what a VPN is and how to install it on Your Raspberry Pi.
The VPN I am going to discuss here is a different one from the previous story. However this one runs on Raspberry Pi as well on a PC with Kubuntu.

What is a VPN

For those that have no idea what a VPN is and why you could use one I'll give a brief explanation.

Normally when you visit a website with your browser you have a direct connection to that website.

A VPN is a bridge in between. So you send the request for the website to the server of the VPN provider. The connection between your browser and the VPN server is encrypted and their server is a secure server. The VPN then contacts the website, gets the information and sends it encrypted back to you.
That way you do not have direct contact with the website you want to visit. This keeps you safe in countries where free speech is at stake. But it also makes it impossible for the website you are visiting to track you down.

Another advantage is that you can access sites that are geo-restricted. This means that the website you are contacting believes that you are in a different country then where you really are.
For a long time this was popular by people in Europe that wanted to watch certain US restricted TV-shows. Without a VPN the US media server saw that you were in Europe and blocked viewing. If you contacted these media through a VPN you could trick them in thinking you were in the US.

A VPN is secure for both UDP and TCP communication. Therefore you can also mask your IOT communication this way.

Free or paid VPN's

There are free and paid VPN services.
The restriction of a free VPN service is that you have less VPN servers to chose from, the service might not always be available and it may be slower.

I have been using the free VPN service from RiseUp for a while, on my Raspberry, and they were always available and I did not notice any significant speed limitations. RiseUp has no paid services and runs on donations. So if you need to use their serices on a frequent base consider making a donation. That can be done at their webpage: 

https://riseup.net/en/vpn

RiseUp has a no-log policy. That means that they do not keep a log of your activities. That is an extra safety measure that makes sure that no one can see what sites or services you have been using.

Next to the VPN service they also supply a safe email service, and an email-list service.

Install RiseUp VPN

To use a VPN you'll need to install a small software package. This package intercepts all your network communication and sends it to the VPN server.

Installing the RiseUp VPN software on your Raspberry is easy.


Just open Discover from your Application Launcher and search for VPN.

This may look awkward to (maybe) most of you. But I am using the KDE desktop on my Raspberry Pi with Trixie as it is far more convenient then the Raspberry Desktop. And it is fully compatible. 

I really urge you to install the KDE desktop on your Raspberry PI as it is so much better as the Raspberry standard desktop. Installing is easy. You can read my story where I explain the installation here: 
https://lucstechblog.blogspot.com/2025/10/raspberry-trixie-with-kde-plasma.html


Click Install and you're done.
No need to make an account or fill in your email address. Just click and install.

Using the RiseUp VPN


After downloading and installing RiseUp VPN you will find the software in the internet section of the Application Launcher.


Starting the program opens a window that immediately shows that it already has made a secured connection.
The bottom of the window shows to what server you are connected. In this example you can see I was connected to a server in Amsterdam.


If you click on that connection name you'll get a list of available servers. You can chose another server from the list if that makes you more comfortable.

Next to the server there is a small graph that shows if the server is available. A green graph (like in this example) shows that the server is available.

Click on the server of your choice. Then click on the left arrow at the top of the screen. This brings you back to the start-screen.


Click on the Turn ON button ad a new connection is made.
Be aware that switching from VPN server to another server might take some time.


After a short while you will see that the new connection has been made.

That is all.

You can now open your browser and visit any website you want without anybody being able to trace your internet tracks.

Connection status.


At the bottom of your desktop on the right side there are some icons. Like said before: this is the Raspberry Pi running the KDE desktop.
This example shows a small green shield which means that your VPN connection is up and running.

This shield can have several colours.


Well this explains all.

Does it work.

Here is a quick and simple test to see if the VPN works.

Start with disconnecting the VPN server in the RiseUp VPN software by simply pressing the Turn Off button.
Then open your internet browser and visit the following site:

https://www.whatsmyip.org/


The website shows your normal IP address.

Now activate the RiseUp server and choose any server anywhere in the world to your liking. Then again visit https://www.whatsmyip.org/


And look at that: a totally different IP address.

And here is a different prove.


If you open your web browser and visit the Google search or Youtube or whatever Google service, you are greeted in a different language. Here I was greeted in French. Meaning that Google thinks my location is somewhere in France !!

Extra safety

Those of you who have worked with a TOR browser know that a TOR browser connects to a TOR server, that connects to another TOR server and that again connects to yet another TOR server. And that last server connects to the website you wanted to have a look at. For safety all these connections are encrypted.

This way you can not easily be traced.

For extra safety you can use your TOR browser with the VPN.

Just make sure to start the VPN connection first and then start your TOR browser. That way your TOR browser connects to a TOR server through your VPN connection which gives you an encrypted communication line upon an encrypted line. So a double encrypted and untraceable connection.

So if you, for example, want to see a tv show or series that is only available for US citizens within the US connect to a VPN server in the US. And if you connect through a TOR browser make sure the last server in the range is also a US TOR server.

Safe surfing
till next time
have fun


Luc Volders

Friday, April 10, 2026

To MIP or not to MIP : installing libraries in MicroPython

For an index to all my stories click this text.

The world changes, and so does the MicroPython language.
In the latest versions of MicroPython a new method to install libraries was introduced : MIP And it is supposed to make life less complicated.

How I use(d) to install libraries.

When I need a display in a MicroPython project I often use a TM1637 quad 7 segment display. To be able to use this display you'll need a library.

THE place to find libraries for MicroPython is Mike Causers repo at Github:
https://github.com/mcauser/awesome-micropython


Scrolling through this huge list of libraries the TM1637 library is in the LED Segment section (about half way down the page).

Clicking micropython-tm1637 brings you to the github page that contains the driver.


At that page I click on the drivers entry being tm1637.py


This is the MicroPython driver for the TM1637. As you can see it is actually just a MicroPython program.


I copy the complete code and paste it into Thonny.


Then I save this in the lib folder using the exact name the library has. In this case tm1637.py


And there it is, in the Pico's memory, in the lib folder, ready to use.

Using MIP

Now let's see how the new method works. MIP is supposed to make this all less complicated. Well let's have a look.

First step is to know where the library is located.
So we need to look at the same library list mentioned above.
Then we need to scroll downwards to the LED Segment section.
Like above described we need to click on the drivers entry in the list.
And then click on the actual driver.

So until now everything is the same.
But we now have the exact URL where the driver is located:
https://github.com/mcauser/micropython-tm1637/tm1637.py

We can use that with MIP.
MIP knows Github so we can leave https://github.com/ out and just use github: like this:

mip.install("github:mcauser/micropython-tm1637/tm1637.py")

But first we need to install MIP.


So these are the lines that are needed:

import mip

mip.install("github:mcauser/micropython-tm1637/tm1637.py")



And this is the output I got.
It did not work.

Of course it did not work !!!  MIP gets the driver from the internet, so you have to activate Wifi first.........

import network
import time

ssid = "Ziggo2903181"
pw = "ptzbB2ohKbgs7agp"

print("Connecting to wifi...")

# wifi connection
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.connect(ssid, pw)
print('Waiting for connection.',end="")
while wifi.isconnected() == False:
    time.sleep(1)
    print('', end='.')
print("")

ip = wifi.ifconfig()[0]

print("Connected with IP adress : "+ip)

import mip

mip.install("github:mcauser/micropython-tm1637/tm1637.py")



And now it works.


The library is automatically downloaded and placed in the /lib folder.

Conclusion:

Actually it is a lot of hassle.
The first steps are the same as in my original method. Then you have to make sure you got the URL right and then write a small program in MicroPython that activates the Wifi.
To be frank: by that time I have already copied and pasted and saved the library by hand.

Mip comes from the land of Python. And Python runs mostly on desktop computers and notebooks. These machines have an internet connection standard activated and then it is a lot less hassle.
On our microcontrollers Wifi is not standard activated.

Looking at the start of this story:
The world changes and MicroPython changes to.
But not all changes are for the better. Luckily the old method still works.

Till next time
have fun

Luc Volders

Friday, April 3, 2026

Trolling google with a Pico

For an index to all my stories click this text.

In some previous stories on this weblog I showed how the Raspberry Pi Pico could produce audio. And not just plain audio but really decent audio.

And then when I was goofing around I had this weird idea.
How about the Raspberry Pi Pico activating my Google Home mini..........

If you want to try this and Troll your own Google you need the following setup:

- A raspberry Pi Pico with audio like described in this story:
https://lucstechblog.blogspot.com/2024/10/pico-audio-part-3.html
- A small active speaker (like a computer speaker)
- Preferably an SD card attached to the Raspberry Pi Pico like this story showed:
https://lucstechblog.blogspot.com/2025/01/pico-sdcard-part-1-hardware.html
And this story for the software:
https://lucstechblog.blogspot.com/2025/01/pico-sd-card-part-2-software.html

Next to that you will need the Audacity software to record your own voice saying ok google ...... and converting it into an 8K wav file. Audacity is free and available on Linux and Windows. I wrote a story on how to use audacity especially for this purpose which you can read here:
https://lucstechblog.blogspot.com/2024/10/audacity-pico-audio-part-1.html

The breadboard setup

I used my audio setup from the previous stories. This includes 3 buttons and an SD-card.



For the example presented here you only need the two buttons attached to GP18 and GP19. And you do not need the oled screen.
You could even do without the SD-card as both files together take less than 200k. However working with an SD card is so easy and convenient that I highly recommend it for many projects, but certainly for audio projects.

For all the details on this setup read this story:
https://lucstechblog.blogspot.com/2025/02/raspberry-pi-pico-audio-player.html

Record the "Ok-Google" sentence.

First thing you need to do is to record some sentences that you want your Google Home (or nest) to react on. I used Audacity to record two sentences and convert them to an 8K WAV file. The sentences I used are:

- OK Google, is it going to rain in Amsterdam today
- OK Google, what is the time.

Make sure you pause for a second or so after OK Google and before speaking the rest. Your Google home needs some time to wake up.

If you are not sure how to record the sentences and convert them to an 8K wav file please read this story:
https://lucstechblog.blogspot.com/2024/10/audacity-pico-audio-part-1.html

Transfer the recorded sentences to the SD card.

Next step is of course to transfer the recorded sentences to your SD card. You can do that physically by attaching the SD card to your computer with an SD-card reader.
Another option is to use Thonny to transfer the recorded sounds to the SD=card if that is still attached to your Pico.

I put the sounds in "/sd/Sounds2" and named them okgoogletime.wav and okgooglerain.wav.
You can of course put these in any directory you want and name them as you like. Just make sure to adjust the upocoming program to your own settings.

The program

The program is easy to follow. It just constantly tests whether one of the buttons is pressed and if so it speaks out the recorded sentences.

import os
from machine import SPI, Pin
import sdcard

spi = SPI(1,sck=Pin(14), mosi=Pin(15), miso=Pin(12))
cs = Pin(13)
sd = sdcard.SDCard(spi, cs)

os.mount(sd, '/sd')

but01=machine.Pin(18, machine.Pin.IN)
but02=machine.Pin(19, machine.Pin.IN)

from wavePlayer import wavePlayer
import time

player = wavePlayer()

while True:
    if (but01.value()==0) :
        player.play('sd/Sounds2/okgooglerain.wav')
          
    if (but02.value()==0) :
        player.play('sd/Sounds2/okgoogletime.wav')

        
That is all. The program is based on my previous stories about playing audio and attaching an SD-card to the Pico. In these stories you will also find the links to the required libraries.

That's all.

Now just press one of the buttons and hear your voice speaking the sentences. And then just wait a moment and your Google Home will react.

The video that demonstrates it



The only thing now to do is to find a practical purpose for this. But for now it is fun to troll your google assistant a bit.

Till next time
have fun

Luc Volders




Friday, March 20, 2026

A stupid MicroPython quirk

For an index to all my stories click this text

Here is a small and stupid MicroPython / Python quirk.
I blundered into this when I made an error in one of my programs.

Both MicroPython and Python have this stupid quirk: they see _ (underscore) as a normal variable.

for _ in range(10):
       print("This is stupid :")
       print(_)


Just look at this example.
You would not expect this to work. But look at the output in Thonny's shell:


So be careful with your variables. A typo can have strange results.

Till next time,
have fun

Luc Volders

Friday, March 6, 2026

Make Gemini speak

For an index to all my stories click this text.

In the previous story I showed how to build a webpage on which you could type a question. The question was then send to a simple AI system and then spoken out.
You can read that story here: https://lucstechblog.blogspot.com/2026/02/2a-speaking-ai.html

It works but has some flaws. It uses a special service to avoid a CORS error. And that service sometimes is so busy, that you need to retry sending your question a few times. Which is annoying.

I had better luck with Google's Gemini AI.
I know that there are people out there that hate Google. But I actually like them. And their AI has a great free tier, and it works great.
So I am going to rebuild the webpage with Gemini.

To use the following program you will need to obtain an API key from VoiceRSS. Read this story that tells you how to get it: https://lucstechblog.blogspot.com/2026/02/text-to-speech-with-voicerss.html

And you'll need an API key for using Google's Gemini. Read this story that tells how to get it: https://lucstechblog.blogspot.com/2026/02/build-webpage-with-gemini-ai-as-your.html


Sidenote.

Javascript is a fun language which is not very difficult to learn. And you get instant results in your webbrowser. The language is useful for all kinds of projects, including IOT projects of which you find several on this weblog.
To make programming in Javascript easier I collected over 500 tips and tricks and bundled them in a book. The book is distributed world-wide by amazon.com


Click here to learn more about this book or to order it.

So what we are going to do is to build a webpage on which you can type a question. That question is send to Gemini and the answer is spoken out aloud. So turn up the volume of your computers speakers and let's go.

And here is the complete program.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Gemini Web Chat Demo</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      background: #f7f7f7;
      padding: 2rem;
    }
    #container {
      background: #fff;
      padding: 1.5rem;
      border-radius: 8px;
      box-shadow: 0 0 10px rgba(0,0,0,0.1);
      max-width: 600px;
      margin: auto;
    }
    textarea {
      width: 100%;
      font-family: inherit;
      font-size: 1rem;
      padding: 0.6rem;
      border: 1px solid #ccc;
      border-radius: 6px;
      resize: none;           /* user can’t drag resize */
      overflow: hidden;       /* hide scrollbar */
      min-height: 2.5rem;
    }
    button {
      margin-top: 0.5rem;
      padding: 0.4rem 1rem;
    }
    #response {
      margin-top: 1rem;
      white-space: pre-wrap;
      background: #f0f0f0;
      padding: 1rem;
      border-radius: 6px;
      min-height: 100px;
    }
  </style>
</head>
<body>
  <div id="container">
    <h2>Ask Gemini</h2>
    <textarea id="userInput" placeholder="Type your question..."></textarea>
    <br>
    <button id="sendBtn">Send</button>

    <h3>Response:</h3>
    <div id="response" contenteditable="true"></div>

    <div id="output"></div>
    <audio id="audioPlayer" controls></audio>

  </div>

  <script>
    const Google_API_KEY = "PUT-YOUR-GEMINI-API-KEY-HERE"; // Replace with your key
    const MODEL = "gemini-2.5-flash";//works
    const textarea = document.getElementById("userInput");
    const sendBtn = document.getElementById("sendBtn");

    // Auto-resize textarea
    textarea.addEventListener("input", () => {
      textarea.style.height = "auto";
      textarea.style.height = textarea.scrollHeight + "px";
    });

    sendBtn.addEventListener("click", async () => {
      const input = textarea.value.trim();
      if (!input) return alert("Please enter a question.");
      const responseDiv = document.getElementById("response");
      responseDiv.textContent = "Loading...";

      try {
        const res = await fetch(
  `https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent?key=${Google_API_KEY}`,
          {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
            contents: [{ parts: [{ text: input }] }] // ✅ send user input
            })
          }
    );


        const data = await res.json();
        const text = data?.candidates?.[0]?.content?.parts?.[0]?.text || "(No response)";
        responseDiv.textContent = text;


        let rec_ans = text || "";
        rec_ans = rec_ans.replace(/[^A-Za-z0-9 \n.,!?\\*+\-%@$&:<>()[\]{}"`]/g, "").trim();

        //document.getElementById("output").textContent = rec_ans;
        //console.log("Received Answer:", rec_ans);

        const VoiceRSS_API_KEY = 'PUT=VOICERSS-API-KEY-HERE';
        const url = 'https://api.voicerss.org/';

        const params = new URLSearchParams({
          key: VoiceRSS_API_KEY,
          hl: 'en-us',
          v: 'Amy',
          f: '8khz_16bit_mono',
          src: rec_ans
        });

        const ttsResponse = await fetch(url, {
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          body: params
        });

        if (!ttsResponse.ok) {
          console.error('❌ TTS request failed:', ttsResponse.status);
          return;
        }

        const audioBlob = await ttsResponse.blob();
        const audioUrl = URL.createObjectURL(audioBlob);

        const audioPlayer = document.getElementById("audioPlayer");
        audioPlayer.src = audioUrl;

        audioPlayer.play().catch(err => console.error("🎧 Playback error:", err));

        console.log("🎵 Playing audio...");


      // ✅ Automatically trigger audio file download (no visible button)
      const downloadLink = document.createElement('a');
      downloadLink.href = audioUrl;
      downloadLink.download = `response_${Date.now()}.mp3`;
      document.body.appendChild(downloadLink);
      downloadLink.click();
      downloadLink.remove(); // clean up the temporary link

      } // end of try part

      catch (err) {
        responseDiv.textContent = "Error: " + err.message;
      }
    });
  </script>
</body>
</html>

I do think there are no real pitfalls here and the code is derived from the code from the previous stories. So I will not go into details here. Please check those previous stories for clarification of the code.
You can also send me a message if you want an explanation about a certain part of the code.

How to use this.

Copy the complete code and paste it in your favorite editor. Then save it as gemini.html Change that name in anything you want as long as it ends on .html
Then open the directory where you saved the program and click on it's icon.
Your default web browser will open with the webpage.


You can now type your question. Then press the Send button
The answer will be written as text in the output field and also spoken.
The audio file is also saved to your download folder, so you can use it for different projects.
Pressing the play button at the bottom of the screen will replay that audio file. So if you misheard the answer you can play it again without sending the question anew to Gemini.

You can restrict the answer from Gemini by putting in your question: "answer in x lines without giving an explanation". Where x can be any number of your choice.

Have fun playing with this. I sure am !!!

Till next time

Luc Volders



Friday, February 27, 2026

Speaking AI

For an index to all my stories click this text.

Let's do something fun.
This story shows how you can send a question to an AI chatbot and have the answer spoken out !! This story falls back on two previous stories.

The first one is building a webpage with JavaScript that accesses a simple AI system.
You can read that story here : https://lucstechblog.blogspot.com/2026/02/easy-ai-with-javascript.html

The second story shows how to use the VoiceRSS service to make your webpage generate spoken text.
You can read that story here: https://lucstechblog.blogspot.com/2026/02/text-to-speech-with-voicerss.html

How about typing a text on a webpage, send that text to an AI system and then send the answer to VoiceRSS. Our webpage then speaks out the audio received from VoiceRSS.

Actually this is quite simple to achieve. The only thing we need to do is to combine the programs of the two previous (above mentioned) stories.

First thing to do.

The first thing to do is to get your own API key from VoiceRSS. This was discussed in the following story:
https://lucstechblog.blogspot.com/2026/02/text-to-speech-with-voicerss.html
So make sure to carefully read that story and get your own API Key.

When you got the Key you can fill it in the next program.

The basic program.

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta charset='utf-8' />
    <script src='voicerss-tts.min.js'></script>
</head>
<body>
    <script>
        VoiceRSS.speech({
            key: 'PUT-YOUR-API-KEY-HERE',
            src: 'Hello, world!',
            hl: 'en-us',
            v: 'Linda',
            r: 0,
            c: 'mp3',
            f: '44khz_16bit_stereo',
            ssml: false
        });
    </script>
</body>
</html>


Actually this program works and speaks out the words "Hello World"
So copy this and paste it in your favorite editor and then save it as an HTML file.
Do not forget to paste n your own API key where it says: PUT-YOUR-API-KEY-HERE

Click on the icon and your web browser will open and after a few seconds the text will be spoken. So make sure to turn the volume of your speakers up.

Sidenote.

The script (program) inside the webpage is Javascript. Javascript is actually not very complicated to use. And best part is that you can get immediate results on a simple webpage. However, Javascript is very versatile and can be used for all kinds of projects. To make programming with Javascript a lot easier I collected more then 500 programming tips and tricks and put them in a book. You can buy this book at Amazon and they ship worldwide.


Click here to learn more or buy this book.

The program looks and is very simple but that is because it imports a library from the internet.
The point is that I actually do not want to import a library.
Why ???
Well because it is totally unnecessary. You can use VoiceRSS with a simple fetch command.

So I wrote a complete program that is a webpage which has an input field in which you can type your question.

When you then press the send button the question is send to a simple AI system. The answer that the AI system sends back is then send to VoiceRSS. The answer is also saved in your downloads directory, as a wav file. This way you can use that audio file in other programs or projects.
The answer is then spoken out.

And there is an audio player at the bottom of the page that can replay the text that was spoken, it just gets the saved audio file and plays that again.

Here is the complete program:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Simple AI Fetch</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 20px;
    }

    textarea {
      width: 100%;
      min-height: 100px;
      resize: vertical;
      box-sizing: border-box;
      padding: 10px;
      font-size: 16px;
      border: 1px solid #ccc;
      border-radius: 5px;
      overflow-y: auto;
    }

    button {
      margin-top: 10px;
      padding: 10px 20px;
      font-size: 16px;
      cursor: pointer;
    }

    pre {
      background: #f9f9f9;
      border: 1px solid #ddd;
      padding: 10px;
      white-space: pre-wrap;
      word-wrap: break-word;
    }

    audio {
      margin-top: 10px;
      width: 100%;
    }
  </style>
</head>
<body>
  <h2>Ask a Question</h2>

  <!-- Replaced input with textarea -->
  <textarea id="userInput" placeholder="Type your question..."></textarea>
  <br>
  <button onclick="sendRequest()">Send</button>

  <h3>Response:</h3>
  <pre id="output"></pre>

  <audio id="audioPlayer" controls></audio>

  <script>
    async function sendRequest() {
      const userText = document.getElementById("userInput").value.trim();
      if (!userText) return alert("Please enter a question!");

      const targetUrl = "http://nimaartman.ir/science/L1.php?text=" +
                        encodeURIComponent("answerinenglishnoutf8anywhere.:" + userText);

      const proxyUrl = "https://api.allorigins.win/raw?url=" + encodeURIComponent(targetUrl);

      try {
        const response = await fetch(proxyUrl);
        const text = await response.text();

        let data;
        try {
          data = JSON.parse(text);
        } catch {
          data = { data: text };
        }

        let rec_ans = data.data || "";
        rec_ans = rec_ans.replace(/[^A-Za-z0-9 \n.,!?\\*+\-%@$&:<>()[\]{}"`]/g, "").trim();

        document.getElementById("output").textContent = rec_ans;
        console.log("Received Answer:", rec_ans);

        const API_KEY = 'YOUR-OWN-API-KEY-HERE';
        const url = 'https://api.voicerss.org/';

        const params = new URLSearchParams({
          key: API_KEY,
          hl: 'en-us',
          v: 'Amy',
          f: '8khz_16bit_mono',
          src: rec_ans || "I have turned the lights off"
        });

        const ttsResponse = await fetch(url, {
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          body: params
        });

        if (!ttsResponse.ok) {
          console.error('❌ TTS request failed:', ttsResponse.status);
          return;
        }

        const audioBlob = await ttsResponse.blob();
        const audioUrl = URL.createObjectURL(audioBlob);

        const audioPlayer = document.getElementById("audioPlayer");
        audioPlayer.src = audioUrl;

        audioPlayer.play().catch(err => console.error("🎧 Playback error:", err));

        console.log("🎵 Playing audio...");


      //  Automatically trigger audio file download (no visible button)
      const downloadLink = document.createElement('a');
      downloadLink.href = audioUrl;
      downloadLink.download = `response_${Date.now()}.mp3`;
      document.body.appendChild(downloadLink);
      downloadLink.click();
      downloadLink.remove(); // clean up the temporary link


      } catch (error) {
        console.error('⚠️ Request failed:', error);
      }
    }
  </script>
</body>
</html>

Nothing dramatically complicated here.
I will just hi-lite a few sections.

      const targetUrl = "http://nimaartman.ir/science/L1.php?text=" +
                        encodeURIComponent("answerinenglishnoutf8anywhere.:" + userText);

This is the URL for the AI we are going to use for asking our questions.
But using this in a fetch command will throw a CORS error.
I have written about that in this story : https://lucstechblog.blogspot.com/2026/01/solving-cors-error-with-javascript.html

      const proxyUrl = "https://api.allorigins.win/raw?url=" + encodeURIComponent(targetUrl);

To avoid the CORS error we are going to use an external service called AllOrigins.
So we are going to wrap our fetch command into an AllOrigins fetch. Please read the story about this like stated above.

The AI system does not need you to log in or make an account. So you also do not need an API key for that.

But VoiceRSS does need an API key.
I wrote how to get that key in this story:
https://lucstechblog.blogspot.com/2026/02/text-to-speech-with-voicerss.html
So follow that to get your own key.

        const API_KEY = 'YOUR-OWN-API-KEY-HERE';

This is where you fill in your own API key for VoiceRSS.

        const params = new URLSearchParams({
          key: API_KEY,
          hl: 'en-us',
          v: 'Amy',
          f: '8khz_16bit_mono',
          src: rec_ans || "I have turned the lights off"
        });

This is where you set the language and voice. You can find all supported languages and voices on https://www.voicerss.org/api/

The rest is just the fetch command and the code for playing the audio.

How to use this.

Just copy the above code and paste it in your favorite editor. Then save it as spoken-ai.html or give it any name you like. Then open the directory where you saved it and click on the icon. Your default browser will open and show the webpage.




Put your question in the input field and press the send button. After a second or two the answer to your question will be spoken out. So turn up the volume of your speakers.

The audio file with the spoken text is saved to your download directory. And pressing the play button replays the audio (speaking the text) without the need to press the send button again.

Things to consider.

It takes a few seconds before the program starts speaking the answer to your question. Sometimes it takes just a second and sometimes it takes a few seconds.
This is because the program first has to access the AllOrigins API, then the AI and then access VoiceRSS. And sometimes (especially Allorigins) can get a bit busy.

And just sometimes it will not work at all.
Then you can see that AllOrigins is not working cause you'll get a CORS error.
You can see that if you open the console window in your browser (in more tools -  developer tools).
The only thing that rests then is to retry sending your question several times.

You could solve this by building your own local AllOrigins server: their Github page tells you how. But that is maybe asking too much.

So maybe we should stick to the Gemini version..........
I am going to show you how to add voice to that next time.
Till that time you really can play and have fun with this.

Till next time then.
Have fun

Luc Volders