I got banned from Ngrok after 10 requests!

Reverse Proxy

So in order to test a new payment provider for a site I was looking around for a quick and easy reverse proxy. I didn’t have to look far as Ngrok is clearly the market leader, with a free tier to boot. They also have a convenient Python library called pyngrok for integration with Flask.

Secure Payment

So the payment provider has an easy system where you generate a form and fill it with details (customer, order details, etc) which once posted redirects to their payment processing page – so your standard “Pay Now” procedure. My error in conception was I ignored the docs and thought that this could be handled through the back end (for “security”) so I sent the form from Flask and returned the “Pay Now” page to the front end – also through Flask.

What went wrong?

In hindsight it seems fairly obvious to me that this is exactly how a bad guy would behave – only changing the html along the way. Ngrok service, which my requests and responses was routing through – from my laptop to the payment provider and back – thought the same. They monitor for exactly this type of behaviour I found out.

What happened?

I was banned! The routing stopped working and an error message appeared instead of my self-hosted site. I did contact support and after explaining myself the free account was actually re-instated, but not before two days had passed.

Reverse proxy using WireGuard

So I learned something about what not to do when processing payments. I wanted to keep learning more (and hopefully get to the point where I can process payments for the service I’m working on) so I needed a reverse proxy to receive messages direct from the payment provider sandbox on my laptop. So I found this site (by ducking the term “alternatives to Ngrok”) here: https://github.com/anderspitman/awesome-tunneling and from there I got to this free, open source service built with WireGuard: https://tunnel.pyjam.as/

Now I can host my own reverse proxy (using DigitalOcean droplet) and get back to learning about payment providers, phew!

Shout out to ChatGPT for making code documentation easy

Just a quick shout out to ChatGPT for helping me with some drudgery in my job. I think this is the best use for it – basically summarising text.

I do have reservations about the skill of ChatGPT and others when it comes to actual coding, having tried ChatGPT, HuggingChat and Claude, as well as Bard and Bing.

That’s it really. Docstrings for Python, JSDoc for JavaScript, etc. Just type something like “Please add c++ documentation for the following function in a class”. Or just “Add documentation here” works fine. If you are in a hurry you can type “docs” and it will most likely get the idea. You follow this up by a paste of your code of course.

Here is a sample of some cool looking documentation I generated recently for a Python helper class – with help from my new coding buddy, ChatGPT.

Don’t forget, always check the output from ChatGPT – it is often horribly wrong, trust me!

The free ChatGPT course was a lot of fun

About a month ago I completed the free course – direct from OpenAI – called “ChatGPT Prompt Engineering for Developers”

This course uses the OpenAI api and helps you create interactive chatbots with a purpose. I promptly started working on a chatbot to take orders for my entertainment company – Big Top Entertainment.

The instructions I gave to the bot included a price list for services and motivation (“you are a customer service agent, make sure to get payment”) and just for fun I included the option to accept chickens as payment. Here is an example conversation with the bot I coded (in Python):

Welcome to Big Top Entertainment Chat Bot, how can I help you?
Enter text: I need some Balloons pls
Assistant: Hi there! Great to hear that you’re interested in our Balloon Twisting service. How many hours of Balloon Twisting would you like to order?
Enter text: 4 hours
Assistant: Awesome! We can definitely arrange that for you. Just to confirm, you’d like to order 4 hours of Balloon Twisting, correct? Also, when would you like to schedule this service?
Enter text: monday
Assistant: Sure thing! Just to clarify, would you like to schedule the Balloon Twisting service for this coming Monday? And what time would you like the service to start?
Enter text: 2pm
Assistant: Great! So, to confirm, you’d like to schedule 4 hours of Balloon Twisting starting at 2pm this coming Monday. Is that correct?
Enter text: yes
Assistant: Perfect! I have you down for 4 hours of Balloon Twisting starting at 2pm this coming Monday. Is there anything else you’d like to add to your order? Maybe some Face Painting or Stilt Walking?
Enter text: No thanks
Assistant: No problem at all. Just one last thing, could you please provide me with the address where you’d like the Balloon Twisting service to take place?
Enter text: 4 Bigtop Lane
Assistant: Thank you! We have your order for 4 hours of Balloon Twisting at 4 Bigtop Lane on Monday at 2pm. The total cost for this service will be R1600.00. We accept payment in cash or chickens, with each chicken valued at R100. How would you like to proceed with payment?
Enter text: chickens
Please try again in a second (rate limiting)chickens
Enter text: chickens
Assistant: Great! We accept chickens as payment. Please let us know how many chickens you would like to use to pay for the service.
Enter text: chickens
Assistant: I apologize for the confusion. Could you please let me know how many chickens you would like to use to pay for the service?
Enter text: how many does it cost?
Please try again in a second (rate limiting)
Enter text: how many chickens??
Assistant: I apologize for the confusion. The cost of the Balloon Twisting service is R1600.00. Since each chicken is valued at R100, you would need to provide 16 chickens to cover the cost of the service.
Enter text: OK great here you go 16 chickens
Assistant: Thank you for your payment of 16 chickens. We have received your order for 4 hours of Balloon Twisting at 4 Bigtop Lane on Monday at 2pm. We look forward to providing you with our service. If you have any further questions or concerns, please don’t hesitate to contact us. Have a great day!
Enter text: Thank you!
Assistant: You’re welcome! It was a pleasure doing business with you. Have a great day!
Enter text:


Chat bots are fun to code. Clearly I could have expanded on this with a full web interface, handing off to a payment gateway (chicken farm?) etc but it was enough to get the idea.

I don’t think I will be going further with the paid api after my $5 free trial expires though (actually it’s my second one so far – tip: duckduckgo email aliases are great if two factor isn’t enforced). In further testing I managed to make a booking of 4 months straight (7 days per week) for 20 face painters – which we would never do – and in addition the bot refused to send a truck to collect the chickens (“As an AI Language Model, I am unable to do that…”). It did, however, refuse to take bookings of more than 8 hours per day. I didn’t tell it that, but we wouldn’t take anything longer for sure.

I have already attempted to do the same using huggingchat api but they changed something halfway and I gave up on it for now. Next time I am bored I will have another look, since it’s actually open source and self-hostable.

Solving a simple problem with ML

ChatGPT has been helping me out

A fair amount if I am going to be honest here. The problem for me always comes down to syntax. Currently focused on Full Stack IOT development my day consists of switching between coding in Python (Flask api and web back-end), JavaScript (with JQuery for front-end) and C++ (embedded).

I find that one of the more interesting parts of any Full Stack IOT code base comes down to dealing with requests and responses. A website has a login page, sends a request to the server. An IOT device has a key to access the online api, sends a request to the server. The server needs to respond but first check the input is valid (sanitize it).

Python/JavaScript/C++ all have their own ways of working with text input. In JavaScript for example you need to trim() but in Python it’s strip() – and in C++ (embedded) it’s a bit more complicated operation involving char arrays. The point is that when switching around between languages I sometimes find myself going blank on the specifics of each approach. That’s when ChatGPT comes in handy for me – as a helper, faster than a google search.

I recently came across an issue which was helped by ML in a different way – namely parsing unstructured text input.

The Problem

I had a series of spreadsheets which I was extracting data from (using Pandas) but the date format was unfortunately unstructured. For example:

12th, 13th Dec 2022 and 5th-8th Jan 2023

In order to continue with the project I needed the date in Pandas date format


If you give it “12th December 2022” as an input, Pandas can do this for you, but it couldn’t cope with the format in the spreadsheets. Regular expressions weren’t going to do the job either, considering the range of formats. So I asked ChatGPT. The prompt:

Please can you parse the following dates as separate dates in list format, suitable for python pandas usage:
12th, 13th Dec 2022 and 5th-8th Jan 2023

The reply:

['2022-12-12', '2022-12-13', '2023-01-05', '2023-01-06', '2023-01-07', '2023-01-08']

As you can see, this is exactly what I was looking for! Unfortunately my ChatGPT free trial has ended – not that I am opposed to paying for software but that’s not the only issue stopping me from using the api for this. I have been burned in the past by proprietary software solutions which have arbitrarily changed and/or cancelled a product which I relied on. This is a simple use case but I can imagine myself taking advantage of it more and more, then OpenAI pulling the rug (or just raising prices) and leaving me with a whole bunch of useless code.

The Solution:

After looking around I found NLPCloud (no affiliation, just it looks cool and works for me*). They use Open Source Generative AI models which in theory I could replicate and host anywhere. I decided to give it a try.

It works! The free plan api key is now plugged into my program and when my program encounters a date format it can’t deal with, a query is sent.

response = client.chatbot(f"Please can you parse the following dates as separate dates in list format, suitable for python pandas usage: {dates_unformatted}", "Human asking AI for help with a text summarization task. ", [])  #text, context, history

The response is exactly the same quality as the ChatGPT one, using the “finetuned-gpt-neox-20b” model.

What simple things has ML been helping you out with?

*Update: A couple of months later, tried out NLPCloud again and it’s broken. Luckily the same code works fine using hugging-chat-api. I really need to get onto self-hosting, every api breaks sooner or later it seems.

Using maps and geocoding to follow the money

I do shows all over Durban and surrounds – but where exactly? And which areas are the most lucrative? To work that out I made an interactive Desktop app using Processing and the Modest Maps library. To get the points on the map I used Google Geocoding api.

Map details page

How it works

The process is quite simple, I create a csv file from our records, with the customer address and total invoice amount in columns (as well as blank latitude and longitude columns).

I created a start screen to choose which csv to use for the visualisation, with an option to fill in the locations using Google geocoding* api.

*geocoding is taking an address and turning it into location co-ordinates.

Menu page

Once the geocoding is done, there are two options, map or details. The details page is basically the same but the points are larger or smaller depending on the amount.

Google geocoding is not completely accurate, so there is a bit of csv editing still to be done – some addresses may appear in different countries for example. Luckily fixing this manually is quite straightforward, you just find the correct location on google maps and then copy the “lat” and “lon” parts of the url from the browser address bar (just after the @ symbol).

The “Modest Maps” library for Processing has many options for tiling – I switched to the satellite view for the screenshots above, to avoid giving away sensitive information. Usually I use a street map view of course.

Purpose and functionality

The purpose of this app is mainly to see where all of our customers are booking us. This information is useful for marketing. When the program is running, two boxes can be drawn around areas on the map, and the text at the bottom compares the total invoice amount within those boxes. The map can be zoomed and panned, and a total for the whole page (with percentage) is shown for reference.

Comparing two zones

More possibilities

Since the pandemic is effectively over and we are back to full strength in terms of bookings, these statistics are now valuable again for my entertainment business. I plan on extending this simple app with more statistical visualisations – perhaps a colour map of distance from my house, and also pairing it with a database and more fields, like dates and type of booking. I could also automate the data entry, although that is rather trivial with a bit of spreadsheet manipulation, and I only really look at this a few times per year.

Speech to Text is finally ready – Whisper review.

Many years ago I developed and published an Android app called “Made Up Stories” which I used to record the bedtime stories I told to my young son. Many of the stories were sanitized versions of movies and novels, but I also had a lot of fun creating my own characters and plots on the fly. Years later, I have a collection of over 300 stories saved, and I started to think that it would be nice to turn some of the original ones into illustrated children’s books – but the time it would take to transcribe these audio files was daunting. I am a reasonably fast typist, but not quite up to the speed of spoken word.

Transcription software

In 2019/2020 I decided to try out transcription software, so I fed a sample audio file into Mozilla Deep Speech and Google Speech to Text, among others. Unfortunately, due to my South African accent, none of the transcribers I tried had any accuracy, and I shelved the idea. Literally every second word was incorrect. Also, Deep Speech required a very specific audio sample rate, and Google Speech to text isn’t free (I had a free trial). *they may have improved by now, I didn’t check.

Discovering Whisper

Last week I saw an article on The Verge, which was singing the praises of “Whisper“, the new open source transcription engine. It was incredibly easy to set up, and best of all, ran entirely on my laptop, for free. After installation it is a simple one-liner on the command line to get your audio file into text format. Best of all, the thing is really accurate – I read in their paper that the model was trained on a more diverse range of speech, and uses a different approach to others. Well, for me at least, it works!

There is still a lot to do with the transcriptions, which come out as one long line of text – with barely any punctuation.. And don’t get me wrong, there are still some errors (admittedly I was using the “tiny” model – only 350mb, the “Large” model is apparently even more accurate but takes up 5-6GB of space.)

Finishing touches

Well, I have cleaned up the first story, “Pinky the Amazon river dolphin visits the Mesozoic”. My wife is an amazing artist, and has agreed to illustrate, but I wonder, could AI help with that as well?

Dinosaurs on an ancient river bank – Craiyon generator
Underwater cave – Stable Diffusion

Maybe not.. (The dolphin images that I have managed to generate so far have only succeeded in making me feel ill.) I have signed up for “Midjourney” (which is DOWN at the time of writing). Apparently it is the best of the bunch – so who knows, maybe I can automate some backgrounds to save time illustrating the stories.

*Update: I signed up for DALL-E 2.

DALL-E 2 “Dinosaurs on an ancient river bank”
DALL-E 2 “Underwater cave scene”

I’m definitely going to do a more in-depth comparison of all of these image generators in future!

Upgrading K8 IR RGB Clubs

I love K8. Their reasonably priced LED equipment is the basis for my favourite solo juggling act, the “Electric Glow Juggling Show”. I bought my K8 clubs over 7 years ago, and last month they finally died.


Since the pandemic finished (or at least since we all learned to live with it) I have never been busier. People want to book my shows. Luckily, a friend has some working K8’s I can borrow for now, but long term I need to sort this out. I’m not changing manufacturer so the choice is to either purchase a new set or fix the ones I have. The pandemic also had the effect of limiting my finances for the past two years, so new purchases are on hold for now – so I opened up my K8’s to see what can be done.

Inside the K8 clubs and balls

First impression: these things are well put together. It took me the better part of an hour to get the electronics out without destroying the club in the process. I found the problem: a really fat lithium battery, completely finished.

Then I found something really interesting. The actual circuit is pretty straightforward and is running on a replaceable Attiny chip. So a few years ago I made some code for Arduino which was an attempt to emulate the K8 IR RGB internal workings. With a few adjustments this old code actually works inside of my favourite clubs – it was as simple as matching the alignment and dropping in my own chip. Thank you K8 for not soldering your chips on, and using a header instead!

The plan

First priority is to get the replacement batteries – I ordered these ones on Amazon: the same size as the original but bigger (>2x) capacity. Should be great if they work!

In the meantime I am working on the code, with upgrades such as variable strobe (like Aerotech equipment), and timed record and playback of settings for my show*.

*I understand that K8 have implemented a method of record and playback functionality in their latest equipment, as well as more new settings – if you need LED equipment I highly recommend going there and getting some. Also, their customer service is brilliant. https://k8malabares.com/

Here is a sneak preview of a new setting running on the bare circuit – Red/Blue with variable strobe!

If anyone is interested, the code is up on Github here – most of it is from many years ago and not very good, but I am working on it, need to have everything working without bugs by the time I receive the batteries. After I upgrade I don’t want to have to open the clubs again! When I get everything working I will do an “instructables” style tutorial – even if you aren’t interested in the firmware upgrade, the battery replacement is worth doing to extend the life of this amazing equipment. By the way, one of my K8 balls stopped working ages ago – I just opened it up and the battery is replaceable too!!

K8 Virtual Juggling with working remote

K8 are my favourite type of LED juggling equipment. Recently I updated my virtual juggling web app to include a working remote control – just like the real thing.

The App

So the app consists of an animated juggler, a remote control and “Change your pattern” button.

While the juggler is juggling, you can press buttons on the remote to change the juggling ball colours (accurately emulating the actual K8 equipment settings)

The “Change your pattern” menu is a large list of different juggling patterns, which when selected will change the animation displayed.

How it works: back end

The back end is based on Flask. I am using the beautiful soup library to fetch the menu of juggling patterns from the awesome library of juggling website. Once selected, the gif of the pattern is fetched. It is then processed (a script inverts the colours and makes the juggling balls transparent) – if that hasn’t already been done for the particular pattern.

How it works: front end

The juggling animation and remote control are written with P5.js. The juggling ball colours are implemented as a background which shows through the transparent balls. The button co-ordinates are relative, so work on any size screen (looks best on Desktop)

Magic Poi 2022 update

Current state of Magic Poi – and some ideas for the future.

First of all, an announcement: Magic Poi is now available for ESP32, as well as ESP8266 architecture. This will bring improvements in performance. I plan on continuing support for both, and in the near future a combined code base will be provided.

I am going to list current features here, and improvements I plan to implement.

On-board images:

  • I have partnered with EnterAction, an awesome Sydney based fabrication company who are taking over the hardware development from now on. Improvements will include an SD card add-on for limitless on-board storage. This will require changes to the code, as currently the maximum is 52 images supported.

UDP streaming:

  • this is a defining feature of Magic Poi. The images are generated off-device, and “streamed” via UDP pixel by pixel. I plan to keep improving this functionality but change it to not be the default mode. Due to WiFi interference the UDP stream is sometimes interrupted, making the LED’s stutter, so work is being done to mitigate that.

“Timeline” – images changing in time to music:

  • currently there is a desktop app to generate the timeline (and associated images) and save as a zip file, which needs to be uploaded to the Android app in order to be “streamed” to the poi. I plan on changing this functionality to rather happen in the poi code, thus avoiding the WiFi interference problem. The timeline editor will be made into a web app, with the option to download directly to the poi.

Station mode:

  • poi connected to a router provides more stable WiFi than the current AP mode. I have made a start on providing a way to use this mode.

Online account:

  • like a PlayStation or Kindle, there is a benefit to having a cloud aspect to any product that consumes media. The Magic Poi website is going to be a place where you can upload and share images and timelines, as well as interact with other poi owners. All uploaded images will be private of course, unless shared. I have made a start on this cloud aspect, with an option in testing to download images directly from your cloud account to the poi. The ultimate goal is to be able to sync any two pairs of poi with two clicks!

Android app:

  • Still not working: text to image (stream words directly to the poi).
  • Once the online portal is finished, this will be added to the app, so shared images and timelines can be viewed without need for a web browser.

The above is a small part of the list – thanks to EnterAction taking over the hardware development side, I will have more time to devote to the software improvements. We also plan on adding a battery level indicator, and a higher power battery for more play time.

Thanks for reading!

Keep an eye on this blog, and sign up to the newsletter (if you haven’t already) for more updates as Magic Poi moves forward towards it’s inevitable crowd funder launch!


Sign up for our update alerts:

Unpacking an inverted index with Python

Lately I have been doing a lot of data processing in my job for UCL. I recently came across a problem which didn’t have a ready made solution, so here is my take on it.

Inverted Index

An inverted index is simply a list of all the unique words in a document, labeled by their position. Something like {‘Hello’: [1], ‘world.’: [2]}. Except that they are rarely in order and there can be multiple instances of any given word in a document.

I was given the task of ‘unpacking’ one of these (actually thousands, but if you can do one..). The inverted index came in the form of a dictionary of words and their positions, returned from an api call. Since I couldn’t find a ready made solution, here is my take on it, in Python 3.

The solution

You can try it out with the included example. I hope this helps someone with a similar problem to solve – do let me know in the comments if you have a different solution.