Project: Super Simple ChatUI

I’ve been playing around a lot with Ollama, an open source project that allows one to run LLMs locally on their machine. It’s been fun to mess around with. Some benefits: no rate-limits, private (e.g., trying to create a pseudo therapy bot, trying to simulate a foul mouthed smarmy sailor, or trying to generate ridiculous fake news articles about a Florida Man losing a fight to a wheel of cheese), and access to all sorts of models that get released.

I decided to try my hand at creating a simplified interface for interacting with it. The result: Super Simple ChatUI.

As if I need more side projects. So it goes!

Ever changing communication

There was a time (really, the past 15 years or so) where responding to things with an animated GIF was so perfect and encapsulated so much (e.g., if a picture is worth 1,000 words, what is a series of pixelated images moving a 8 frames per second worth?).

For example. see the rise of services like Giphy. I even have a random 10 year old project myself that involves animated GIFs!

Now though, it’s becoming generative AI all the way down.

For example, I just received a meeting invite that increases the frequency of meetings I’m having related to a certain project to… every single day.

Me: Hey, robot! Please create a meme image of a programmer jumping up on a desk and excitedly cheering “MOAR MEETINGS!”

Robot:

Now to figure out a way to send it in my place…

Upgrading Mr. RossBot’s image model and prompt template

My Mastodon landscape painting bot, Mr. RossBot keeps kicking along, generating some fun landscape art. It’s been powered by the AI Horde (the open source project behind ArtBot) and has tried to utilize whatever image models provided by the API to the best of its abilities.

For the most part, the code behind it is a bunch of spaghetti that looks like this:

An update to the AI Horde late last year added support for SDXL. However, the SDXL model on the Horde did not use a refiner. Because of this, images tended to come out a bit soft and lacked texture.

You can see examples of this in my announcement post about Mr. RossBot being back, here. See also:

More recently, the Horde added support for a new image model: AlbedoBaseXL. It’s an SDXL model that has a refiner baked in. Now images will come out a lot sharper looking.

Coincidentally, I was also playing around with various prompts and discovered I could get much better image results that look more painterly (rather than simple digital renderings) by utilizing the following prompt:

A beautiful oil painting of [LITERALLY_ANYTHING], with thick messy brush strokes.

And that is it! No more messy appending various junk to the end of the prompt to attempt to get what I want. The results speak for themselves and are pretty awesome, I think!

Implementing and testing a “poor man’s prompt expansion” model for Stable Diffusion

Various Stable Diffusion models massively benefit from verbose prompt descriptions that contain a variety of additional descriptors. Much recent research has gone into training text generation models for expanding existing Stable Diffusion prompts with relevant and context appropriate descriptors.

Since it isn’t feasible to run LLMs and text generation models inside most users’ web browsers at this time, I present my “Poor Man’s Prompt Expansion Model“. It uses a number of examples I’ve acquired from Fooocus and Hugging Face to generate completely random (and absolutely not context appropriate) prompt expansions.

(For those interested in following along at home, you can checkout the gist for this script on GitHub).

How does it work?

We iterate through a list of an absolute crap ton of prompt descriptors that I’ve sourced from other (smarter) systems that tokenize user prompts and attempt to come up with context appropriate responses. We’re not going to do that, because we’re going to go into full chaos mode:

  1. Iterate through a list of source material and split up everything separated by a comma.
  2. Add the resulting list to a new 1-dimensional array.
  3. Now, build a new descriptive prompt by looping through the list until we get a random string of descriptors that are between 175 and 220 characters long.
  4. Once that’s done, return the result to the user.
  5. Create a new prompt.

For our experiment, we’re going to lock all image generation parameters and seed, so we theoretically get the same image given the exact same parameters.

Ready?

Here is our base prompt and the result:

Happy penguins having a beer

Not bad! Now, let’s go full chaos mode with a new prompt using the above rules and check out the result:

Happy penguins having a beer, silent, 4K UHD image, 8k, professional photography, clouds, gold, dramatic light, cinematic lighting, creative, pretty, artstation, award winning, pure, trending on artstation, airbrush, cgsociety, glowing

That’s fun! (I’m not sure what the “silent” descriptor means, but hey!) Let’s try another:

Happy penguins having a beer, 8k, redshift, illuminated, clear, elegant, creative, black and white, masterpiece, great power, pinterest, photorealistic, award winning, vray, enchanted, complex, excellent composition, beautiful composition

I think we just created an advertisement for a new type of beverage! It nailed the “black and white”, though I’m not sure how that penguin turned into a bottle. What else can we make?

Happy penguins having a beer, volumetric lighting, Digital, intricate, awesome, futuristic, cartoon artstyle, vector, solid, detailed, dramatic light, realistic photograph, wonderful colors, dramatic atmosphere

The dude in the middle is planning on having a good night. Definitely some “wonderful colors”. Not so much realistic photo or vector, but fun! One last try:

Happy penguins having a beer, 35mm, surreal, amazing, Trending on Artstation HQ, matte painting hyperrealistic, full focus, very inspirational, pixta.jp, aesthetic, 8k, black and white, reflected on the matrix studio background, awesome

As you can see, you can get a wide variety of image styles by simply mixing a bunch of descriptive elements to an image prompt.

I’ve wanted to implement a feature like this on ArtBot for a long time. (Essentially, if the user allows it, automatically append these descriptions behind the scenes when an image is requested). Perhaps this will come soon.

Mr. RossBot is back!

Alrighty, I updated the logic this weekend and have Mr. RossBot operating on the hairy elephant website (Mastodon). (It’s also posting on Threads, if you’re into that sort of thing.)

I also updated the image model to use Stability.ai’s swanky new SDXL model. I’m pretty impressed with the results.

ArtBot mentioned again in PC World!

ArtBot got another callout in PC World in the article: “The best AI art generators: Bring your wildest dreams to life.”

Though a bit of (fair) criticism at the end of the blurb though:

Why use Artbot? The vast number of AI models, and the variance in style those images produce. Otherwise, generating images via Artbot can be a bit of a crapshoot, and you may expend a great number of kudos simply exploring all the options. Since there’s no real setup besides figuring out the API key, Stable Horde (Artbot) can be worth a try.

Hey, I’ll take it!

ArtBot written up in PC World!

Hah! This is pretty awesome. My nifty side project, ArtBot, has been written up in PC World as part of a larger article about Stable Horde (the open source backend that powers my web app):

Stable Horde has a few front-end interfaces to use to create AI art, but my preferred choice is ArtBot, which taps into the Horde. (There’s also a separate client interface, with either a Web version or downloadable software.)

Interestingly enough, ArtBot just passed 2,000,000 images generated!

New side project: ArtBot, a way to create images using Stable Diffusion

Thanks to Reddit, I recently stumbled upon a cool project called Stable Horde. It essentially lets you generate images using a distributed cluster of GPUs donated by community members.

I had been creating my own web interface to remotely interact with a Stable Diffusion instance running on my own machine. I decided to quickly repurpose the web app and connect to the Stable Horde API. The result?

ArtBot, a Stable Diffusion demonstration that allows you to generate images using the power of the Stable Horde. It is awesome!

Quickly bootstrapping a new Node.js project

A problem that often happens to me: I get the inspiration to whip up something in Node.js  (for fun, for experimentation, for a side project, etc) but then I realize that I need to go through the process of actually setting things up before I can even start writing some code.

Usually, I have to dig through previous projects and copy over my eslint and prettier config files, read through some documentation and remember how to setup TypeScript again, install the correct dependencies for running tests. Before I know it, I’m bored and tired and no longer interested in doing whatever I was going to do.

I decided to experiment with some command line tools and created a Node.js script that can help me quickly bootstrap a new project with common configuration parameters that I use. It’s available on GitHub: Bootstrap Node Project.

The GIF above shows this tool in action. I’m able to get the scaffolding for a new project up and running within about 20 seconds! After running, the project structure looks like this (with associated npm start and test scripts, all ready to go). That is pretty awesome.

my-cool-project/
├─ .husky/
├─ node_modules/
├─ src/
│ ├─ index.js (.ts)
│ ├─ index.test.js (.ts)
├─ .eslintrc.json
├─ .gitignore
├─ .prettierrc
├─ package-lock.json
├─ package.json
├─ README.md
├─ tsconfig.json (optional)

Obviously, it’s highly opinionated and caters to configuration options that I personally like to use. But I figure it’s a great resource for anyone who wishes to roll their own utility to quickly bootstrap projects as well.

 

Creating an automated Twitter bot about gun violence

The school shooting in Uvalde last week was horrible. As a parent, I feel so powerless to protect my kids from something like that. Taking them to school the next day was extremely emotional.

It’s clear that we, as a country, are going to continue to do nothing about guns and gun violence. I channeled some of my emotion into building an automated bot for Twitter. I call it SABSStochastic Analysis for Ballistics Superfans (alternative title is “Second Amendment Bullshit”).

If you’re so technically inclined, you can download and run it yourself. Powered by Node and a fun little experiment into Twitter’s API.

It automatically replies to any congressional member who tweets.

Which of course includes unhinged Republicans.

3 weeks of GOES-17 imagery: hurricanes, wildfires and more

I recently built a side project recently that automatically downloads GOES-17 imagery every 10 minutes and then compiles it into a video.

The result is pretty darn awesome! Here is 3 weeks of GOES-17 imagery sourced from NOAA / CIRA / RAMMB. The video begins the night of August 15th, 2020 as lightning storms rolled through Northern California and runs until the afternoon of September 10th, 2020.

Almost immediately, you begin to see smoke plumes from fires created due to lightning strikes.

Note: The blue and yellow blocks that you see periodically flash on screen are the result of corrupted image data downlinked from GOES-17. I’m not sure exactly what causes this, but these errors are present within the original images files hosted on NOAA’s CDN.

(Be sure to bump up the video quality — YouTube’s default compression really ruins the image)

A simple dark-mode hook for React

I recently wrote a simple hook for React to automatically detect a device’s dark mode preference (as well as any changes to it) and style your web app accordingly, using something like ThemeProvider from styled-components.

It was developed as part of a side project I was hacking around on using my personal React Starter Kit, which is my own React project for quickly getting prototypes and side projects up and running.

I’ve released this as a standard GitHub repo instead of an NPM module due to the simplicity of this hook, especially in light of one-line packages breaking the Internet. To use it, just copy it into your project where needed.

I’ve released this under an MIT license. Feel free to use as-is, fork, copy, tear apart, profit, and share as you wish.

You can check out the code on Github.

Emoji Say What?

Here’s a random little side project that I’ve been working on: Emoji Say What?

It’s like a game of telephone, but using the latest in human communication technologies, hieroglyphics, emoji!

Basically, you visit the site and get a completely out of context sentence or set of emoji and it’s your job to decipher it. And so on and so on. It evolves over time and eventually you get something like this.

nodeEbot: A bot for Twitter that generates tweets from pseudo Markov chains

Current Version: 0.1.4

Say hello to NodeEBot (pronounced as “nodey bot” or even “naughty bot”, if you prefer). It stands for Node E-books Bot.

It’s a Nodejs package for creating Twitter bots which can write their own tweets and interact with other users (by favoriting, replying, and following). This project draws heavy inspiration from the twitter_ebooks gem for Ruby.

You can see two examples of this bot in action at @daveleeeeee and @roboderp.

Installation and Usage

This project requires Nodejs v0.10.35+. If you’re looking for a place to host Nodejs projects, I’ve had success setting up a free Ubuntu virtual server through Amazon’s Web Services dashboard and installing nodejs on it.

To run, copy the project into your preferred directory and then install the required dependencies using:

npm install

You can edit various configuration settings in the bot.js file. Before you can begin you’ll need to have Twitter API credentials which can be setup right here. Once you have your consumer API key and secret as well as your access token and secret, add them to the top of the bot.js file:

// Twitter API configuration
var client = new Twitter({
  consumer_key: ‘xxxx’,
  consumer_secret: ‘xxxx’,
  access_token_key: ‘xxxx’,
  access_token_secret: ‘xxxx’
});

You’ll also need to add the Twitter username of your bot (without the @ symbol) to the config file. (This is for tracking mentions as well as making sure the bot ignores actions from itself so it doesn’t get caught in a loop).

// Your robot’s Twitter username (without the @ symbol)
// We use this to search for mentions of the robot and to prevent it from replying to itself
robotName = “xxxx”;

Once that’s done, the bot is almost ready to go. You can modify a few other settings that influence how chatty the bot is, how often it will interact with other users or use random hashtags and emojis.

In order to run the bot, I use the forever npm package. This allows us to automatically restart the server in case of a crash, as well as force restart the server in order to reload the Twitter stream (added in v 0.1.2).

Source material

The one last thing that you’ll need to do is give it some source material to generate text from. I use source material my own Twitter archive.

Right now, I haven’t implemented a way to parse the Twitter’s csv data that’s generated when you request your history. In the meantime, I’ve simply opened up the tweets.csv in a spreadsheet app, copied the contents of the ‘text’ column into a new file and used that as the source material. This script will treat each line as a separate and unique sentence.

I’ve added some basic ability to strip our Twitter usernames and URLs from the archive. That means it will treat something like:

@davely That’s great. I’ve seen something like that before. 
http://flickr.com/…

as

That’s great. I’ve seen something like that before.

Running multiple bots

If you want to run multiple bots for different Twitter accounts, copy this project into separate folders (e.g., ~/MyBot1, ~/MyBot2, ~/MyBot3, etc) and make sure you input the proper Twitter API credentials at the top of each bot.js file. Then spool up separate node instances and load up the relevant bot files.

Future things to do.

  • Better modularization of our script. Right now it’s in one ginormous .js file.
  • Turn it into a proper npm module.
  • Better regex handling to clean up source material (e.g., links, usernames, etc
  • Send direct messages back to users who DM our robot.
  • Keyword ranking of our source material. (Sort of implemented but disabled right now since performance is SLOW.)
  • Allow robot to reply with some content (e.g., if someone asks what it thinks about ‘baseball,’ it tries to compose a reply that mentions ‘baseball.’
  • Retweet various tweets that it finds interesting based on keywords and interests.
  • Let it potentially upload images or GIFs.

Changelog

v 0.1.4 (2015/05/07)

  • Simple change to load and require underscore. This is going to help simplify some of my functions in future development.

v 0.1.3 (2015/04/28)

  • Fixed bug that would cause bot to think that all users replying to it were found in our otherBots array and kept applying a temporary time out on replies, even if not needed.

v 0.1.2 (2015/04/27)

  • Implemented a hacky fix for an issue I’m having with the Twitter Streaming API randomly dying without an error. If we’re running this with the npm package forever, let’s kill the server and restart if ever few hours.

v 0.1.1 (2015/04/19)

  • Initial public release!

Other stuff

If you end up using this script in your own Twitter bots, let me know! I’d love to know how it works out for you and please let me know about any improvements or suggestions you might have.

Thanks for checking it out!

You can download the source code for nodeEbot on Github.