Future-proof your skills with Linux, Python, vim & git as I share with you the most timeless and love-worthy tools in tech through my two great projects that work great together.

Adding WebDev to MyKoz.AI with uvicorn ASGI Python Webserver

I added webdev to MyKoz.AI with uvicorn ASGI Python webserver. Follow the steps I used to add another monitorable service running through GNU screen that opens new possibilities. This sets the stage for writing a sample HTMX app.

I Just Added WebDev to MyKoz.AI with uvicorn ASGI Python Webserver!

By Michael Levin

Friday, August 25, 2023

Okay, MyKoz.AI really needs webdev as a part of it. Even for projects that I want to start. There’s only one viable long-term user interface sort of development to take up, and that’s web development. However, the same can not be said about the JavaScript frameworks like ReactJS. They come and go too quickly and are the definition of what you want to stay away from to resist obsolescence. You know what’s not? HTML. And that makes HTMX the webdev approach to use.

With HTMX, you keep most everything on the server. Only leverage client-side JavaScript frameworks to ease the difficulty of HTML div-replacement and such. Just swap out rectangular regions of HTML code on events. Bammo whammo, it’s not really webdev. It’s timeless HTML. Oh yeah, the Web and JavaScript happens to be there, but it need not ruin your 10-years and 10,000 hours. And what is HTMX? Some library to download? No, not quite. You will need a lightweight JavaScript framework like AlpineJS to do the dirtywork. But besides that, it’s just the use of vanilla HTML and some coding discipline.

That’s the beauty of it. HTMX is just a way of working with HTML that assumes you have just enough JavaScript control to swap out DOM components. The rest is up to you.

Yup. That’s the kind of WebDev I want in MyKoz.AI.

Okay, so we need a lightweight Python webserver. Just to remind folks, this is at a lower level even than Python web frameworks like Flask or FastAPI. Either of those technologies can probably be used here too, but before you even talk about yet another framework, albeit Python server-side as Flask and FastAPI are, they’re not the beginning of this discussion. The beginning of the discussion is choosing your WSGI, or more modern ASGI, server you’re going to use.

Historically, the no-brainer was something called gunicorn. I guess you can think of it like ye old Apache, but respecting Python conventions. But since everything went to asynchronous mode, WSGI won’t cut it anymore and many gnuicorn users have moved to uvicorn. It’s really just a Python-friendly gnuicorn WSGI server updated to ASGI for faster performance.

Okay, so how do we install it? With a pip install uvicorn of course! But wait! There’s more. And I think I will need some of that more, because I’ll be running this under WSL and that means it has special considerations for that nifty source monitoring feature where you can just change files and have the webserver pick up the changes without having to stop and start it.

Okay, so we do a test install:

pip install 'uvicorn[standard]'

and then we make a file using their quickstart example:

async def app(scope, receive, send):
    assert scope['type'] == 'http'

    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [
            (b'content-type', b'text/plain'),
    await send({
        'type': 'http.response.body',
        'body': b'hello, world!',

and then we run it:

uvicorn example:app

Yup, Hello World is being served as promised. For those who are still wondering why no Flask or FastAPI at this point, it’s because the example they provide is so low-level that it’s writing out the http response codes explicitly. This is the kind of overhead that Flask and FastAPI do for you. But wow! What a great introduction to WebDev!

I need to build this into MyKoz.AI as fast as possible. Then move onto the other stuff you want to do today.

This should be a third service that’s visible to the MyKoz.AI user the same way the JuptyerLab and yourservice service are using the GNU screen -ls command. It should be fully visible and able to be poked around once you know gnu screen a bit.

Hmmm. Steps? 1, 2, 3… 1? Get it installed!

Okay, it’s odd but i can add this line to mykoz/requirements.txt that’s used with the pip install -r requirements.txt command.


Okay, and it’s tested. now let’s see if we can precision scalpel this in. i did it recently with the your.service daemon, so just shadow that. 1, 2, 3… 1?

Create the uvicorn.service file. done.

Add it to the giant curl command in install_wsl.sh. done.

Okay, make a github repo named webdev with the uvicorn example in it. done.

Don’t do too many steps (like starting the service) yet. commit, push and install MyKoz.AI again on this machine and make sure everything’s in place. delete the webdev repo ahead of time.

Okay, wow. I just re-ran the MyKoz.AI install procedure on this machine. I only had to make tiny adjustments to my workflow now to be re-settled onto this new-again hardware. It’s a laptop that’s been out of commission for months because of a catastrophic crash. It got me on Windows 11 for long enough to know that I hate it. The metal is hot! I could really push MyKoz.AI on the inevitable Windows 12 push.

But don’t get distracted. The whole install process worked getting the new webdev repo and all. So test-start uvicorn again without going though gnu sceen yet. Change directories into the webdev repo and run:

uvicorn example:app

Okay, confirmed! We want to model how this starts and stops on how the JupyterLab and yourservice both start and stop, and that’s with a bash script that goes into ~/pyenv/bin/ which is a brilliant way to beat the eternal path issues. virtualenv`, the Python tool for making virtual Python environments goes to considerable lengths to make sure you can issue Python commands as if they were built-in operating system commands. And we can piggyback off that same trick to run new bash scripts we need the same way. That’s what uvicorn itself is doing. So the above command could really be re-written as:

/home/ubuntu/pyenv/bin/uvicorn example:app

And so the new uvicorn.service file I’m creating contains this:

#! /usr/bin/env bash

source /home/ubuntu/pyenv/bin/activate

# Run through GNUY screen and prevent double-running
cd /home/ubuntu/repos/webdev
screen -wipe >/dev/null 2>&1
if ! screen -list | grep -q "uvicorn"; then
    screen -dmS uvicorn /home/ubuntu/pyenv/bin/uvicorn example:app

Alright so add startuvicorn to the mykoz repo and to the giant curl command. Okay, so now both the systemd file and the pyenv bin file are made and part of the repo. Now I just need to make sure the file permissions are correct and the service is enabled and started. Okay, done. Do a MyKoz.AI install and check if the Hello World website is running.