With the recent updates to the Fediseer, it is now possible to use it more efficiently for programmatically adjusing one’s blocklist using the built-in censures, so I wanted to add this capability to the Divisions by zero by updating my update_blacklist.py script to utilize this method.
While I could have done this by using simple http requests, I thought it was enough features there that creating a python SDK package around the fediseer API would be worthwhile. So I’m excited to announce the release of pythonseer!
It is built very similar to Pythörhead, so if you’re already using that in your scripts, it should be trivial to add support for the Fediseer via pythonseer as well.
I have already updated the provided script to automatically maintain your blocklists to allow it to make use of the fediseer censures as well. Simply censure the domains you would like to defederate from, and the script will automatically add them to your list along with the suspicious instances. If you have the script to run on a schedule, you can then simply add new censures on the fediseer API and your blocklist will be automatically kept up to date.
Likewise, if you don’t want to maintain all the blocklist yourself, find other like-minded instances and combine their censures with yours. This way whenever they censure someone, you also benefit.
Enterprising fediverse admins could also do other fancy things with the pythonseer, such as creating polls to democratically add instances to their endorsements or censures etc. So do let me know if you come up with new ideas!
Just one day ago I released my initial release of the Overseer and I was annoyed by the implementation almost immediately. The requirement to register on another Lemmy instance using a custom username and wait for manual approval (which could also lead to someone sniping that username, and forcing me to manually delete it), and THEN register your instance on the Overseer was just too clunky.
While a few people did register, I realized almost immediately it’s very likely this would never take off. So I started rethinking how I could streamline this process so that it would require far less steps.
My initial plan was to simply register all available instances on the fediverse by default, and allow admins to claim them later. That would require me somehow being able to contact those admins directly. This led me to try to figure out the best way to do that where I discovered I could theoretically talk to any fediverse instance directly, and not have to rely on the a specific lemmy instance with all its limitations.
So I spent many many hours figuring out how to do that. The documentation is frustratingly sparse and incomplete on this point, with my best guide was this blogpost, from half a decade ago for a different language than python. Fortunately this day and age, I had access to ChatGPT, so I could ask it to translate the code on that page to python and then with some trial and error and digging in the official documentation, I had a working DM system for mastodon!
Then I set out to do the same for lemmy which is where the big frustration was waiting, as the documentation is practically non-existent, the messages are cryptic and Rust and the way it’s coded was completely impenetrable to me. Lots and lots of digging in the code, trial and error and asking around in desperation, and I managed to figure out that the main blocking point was a “type” key in my activitypub instance, instead of a fault in my payload.
Unfortunately figuring out how to “speak activitypub” took me the better part of my day. But the good news is that once I had that down, the rest was just a matter of time. I just had to refactor everything. And hell, while I am doing that, why not change the name and domain as well
I have already updated my previous post with the new workflow, but the big difference is that it completely removes the need for an extra lemmy instance one has to manually register. Instead one just has to “claim” their instance and they will get a PM directly in their mailbox!
Likewise, you can guarantee for a different instance even if their admins haven’t claimed it first and they will get a helpful PM informing them about it. If the instance doesn’t exist yet, all you need to do is search for it in the whitelist and it will be automatically added, and then can be guaranteed. My next step is to automatically import all known instances by pulling them from the federation, which should avoid the manual step of searching for them first.
So let’s see how it goes. Now with the ability to talk to fediverse instances directly, it also opens up some really fascinating doors for automation! Stay tuned!
Recently my provider send me a nastygram about my Database VPS using too much bandwidth, 150Mbit/s or more, over 10 days, and how they have already throttled it to 100Mbit/s to avoid affecting other customers.
This caught me by surprise as I know that my Database is the central location where all my nodes converge to pull data, but the transfer between them should be just text. 150 Mbit/s would be insane quantities of text.
Fortunately my provider has also crashed my DB just a day before on the weekend, and their lack of response outside working hours forced me to urgently deploy a new VM with a new postgres DB until they recovered and I had switched all my nodes to use that already. Nevertheless, on checking the new DB, I discovered that it too was using the same incredible amount of bandwidth constantly. This meant that my new DB VM was also on a timer as Contabo throttles you, if your VM takes too much bandwidth for 10 days in a row. I had to resolve this fast.
First order of business was to swap the code so that all source images and source masks used for img2img are also stored in my cloudflare r2 CDN. The img2img requests are about 1/6 of the total stable horde traffic, but until now they were stored as base64 strings inside the database, which means that whenever those requests were retrieved, say for a worker to pick one, they transferred all that data back and forth.
This made a small dent in the traffic, but not nearly enough. I was still at 150Mbit/s outside rush hours and 200Mbit/s during peak demand.
I started getting a bit desperate as I expected that was a big part of this. At this point I decided to open a discord thread to ask my community for help in debugging this as I was getting out of my depth. The best suggestion came from someone who told me to enable pg_stat_statements.
That, along with the query to retrieve the most used queries, lead me to find a few areas where I could do some improvements through caching. One was the worker retrieving the models from the DB all the time for example, which I instead made it cache on redis.
Unfortunately none of my tweak seemed to do much difference in the bandwidth. I was starting to lose my mind. Fortunately someone mentioned the amount of rows retrieved so I decided to sort my postgres statements by amount of rows retrieved and that finally got me the thing I was looking for. There was one statement which retrieved a number of rows two whole orders of magnitude more than every other statement!
That statement was an innocent looking query to retrieve all the performance statistics for all workers, which I then created an average for. Given hundreds of workers and 20 rows per worker, and this statement being retrieved once per second per status check on a request, you can imagine the amount of traffic it generated!
My initial stop was to cache it on redis as well. That just shifted the problem because while there wasn’t a load on the DB, the amount of traffic stayed the same, just on a different VM. So the next step was to try and cache it locally. I initially turned to python cachetools and their TTL function caching. That seemed to work but it was a big mistake. The cachetools are absolutely not thread safe and my code relies on python waitress WSGI server, and that one spawns dozens of threads all over the place.
So one day later, I get reports of random 500 errors and other problems. I look in to find my logs spewing hundreds of logs about missing key errors on the cache. Whoops!
I did make an attempt to see how I can make cachetools thread safe, but that involved adding python locks which would delay everything too much, on ultimately something that is not needed. So instead I just created my own simple cache using global vars and built-in types which are thread-safe by default. That solved the crashing issue.
But then I remembered that I’m stupid and instead of pulling thousands of rows of integers so I can make an average using python, I can just ask PostgreSQL to calculate the average and simply return that final number to me. Duh! This is what happens when my head is not yet tuned into using Databases correctly.
So finally, I wiped my internal cache and switched to that approach. And fortunately that was it! My Mbit/s on my database server dropped from 150 average, to 15! a 10x reduction!
The Nataili ML backend powering the workers of the Stable Horde has for a while now supported models which can perform image interrogation (AKA img2text) operations. For example captioning images or verifying whether they are displaying NSFW content or not. For almost as long, I’ve wanted to allow the AI Horde to facilitate the widespread use of those models, the same way we do for Stable Diffusion.
A primary reason for wanting this is the fact that the requirements to run a worker on the horde are fairly heavy, needing at least a mid-range GPU on your PC and most people just don’t have the capacity to provide that. Yes there is always a chance to run generations on free cloud services like Google Colaboratory, but that replaces cost with time and attention.
So I felt that being able to use models which are fairly low-powered and can run even on CPUs would provide a way for almost everyone to join the horde and start gaining kudos for themselves. The final push I needed to do this was discovering that there was useful accessibility browser extension out there which had already ceased operations because they couldn’t find cheap compute. Which is effectively what the horde has been built to do!
I was planning to get this done 2 weeks ago, but unfortunately I got massively sick during the holidays so I couldn’t do much of anything. So I moved my vacation days to the new year and finally got cracking.
Unfortunately, while the implementation of those models is much simpler than stable diffusion, preparing the AI Horde to be able to serve these was not quite as straightforward. The problem being that until now I built the horde under two core assumptions:
The input is going to include a prompt of some sort on which to run inference
The prompt would always expect the same type of results. Whether that is image or text.
Image interrogations flip these lot of these on their head. The input has to be a simple image, with no prompt from the user (other than payload tweaks), and the end result can differ wildly from each other, for example one being text, the other boolean and yet another returning a dictionary.
To make things worse, I did not want to duplicate my worker code, something which required me to implement table polymorphism within SQLAlchemy, which is a tricky subject on its own. More importantly, it requires modifying existing tables, which meant I needed to set up a development instance of the stable horde so that I can actually test the changes before going live. That in turn meant a new server, new DB, new nodes etc. Happily I had most of it ready via my Ansible code, but I still needed to tweak things to run on a new domain etc.
All-in all, designing, building and testing image interrogations took me the best part of a whole week.
So I am proud to announce that the new feature is now live on the stable horde!
As always, you have to look at the api documentation for each endpoint you want to use. But very simply, you simply send an image URL you want to interrogate and specify which interrogation forms you want to use, like so:
It otherwise works similar top image generation from a client’s perspective, with the difference that you don’t need to use a check/ endpoint, and you can keep polling the interrogate/status/ endpoint directly. Once a form is completed, you will get a result from that form matching its type.
Currently we support three interrogation forms: caption, nsfw, and interrogation
Caption: Returns a string describing the image
NSFW: Returns a true/false boolean depending on whether the image is displaying NSFW imagery or not.
Interrogation: Returns a dictionary of key words best describing the image, with an accompanying confidence score. This takes the most time of all the interrogations and is rewarded accordingly in kudos.
As I mentioned before, the worker code had to be completely refactored. It now lives in a new repository as well as the nataili repo will soon turn into a pip package I can install externally, so this is in preparation of that.
To start an interrogation worker, you use the same code, but you start with a different bridge script.
As the models used by the interrogation worker are much more lightweight, it actually benefits more from high threads and high queue_sizes, so feel free to crank those up so that it’s best utilizing your worker. A lot of the new code changes I did to the horde also allow your worker to pick up many forms at the same time, which will cut down on the poll requests to the horde, further reducing idle time.
However be careful not to set these too high. because you’re picking up the requests in advance, nobody else will work on them until your worker gets to them. If your queue is high and your threads are low (or slow), then you’ll notice your horde performance is not going to be great.
However the result of each form will be sent back as soon as it’s done, so as it save as much time as possible.
One more thing to note is that an Interrogation worker is different from the Stable Diffusion worker. As such you cannot use the same name! However they DO use the same bridgeData.py. If you plan to run both types of workers, utilize the command line arguments to tweak the bridge settings accordingly instead of having to change your bridgeData.py all the time.
In the future I plan to further tweak the bridge so that it can run parallel with the stable diffusion worker to best utilize your space processing. I also want to tweak the model loading so that optionally you can offload the whole thing to CPU. But I need to test if the speeds for this make sense first.
Another cool possibility from this refactor is that it opens the doors for different worker types on the horde, which in turn gives me an opening I’ve been considering for a while now, which is the complete merge of the Stable and KoboldAI horde into one service. This will reduce the amount of code juggling I have to do, and hopefully simplify things for everyone with a common kudos system.
I am excited to see what use cases you all will come up with this new system!
For the past 2 weeks I’ve been trying to build the new feature of the horde which will allow even people with a low powered GPU, or just CPU to join the horde and provide a service to gather kudos.
It is called “Interrogation” as it will “interrogate” source images to discover aspects about them, such as an image caption, or whether they are displaying NSFW content etc. This feature can then be on-boarded into new or existing tools, such as perhaps automatically captioning images for micro-blogging services as an accessibility feature, or a browser plugin for parental controls etc.
However what I thought would be a bit tricky but doable soon keeps running into various snags. First, I lost one complete week of work from my vacation by getting the nastiest cold I’ve had for the past 10 years at least. Flattening me for almost 9 days. Then it was holiday period where I had to put more attention to family and friends.
Now that I’m finally able to concentrate more on it, I find it’s actually an order of magnitude more complex than I initially expected, requiring me to actually have to update my existing database tables (always a risky proposition) and also redesign my approach to use such things as “Polymorphic tables” so that I don’t end up duplicating hundreds of lines of code between similar classes.
And while I’m doing this, the horde ML backend has been receiving a surprisingly increased pace of improvements, recently implementing depth2img, adding diffusers to voodoo-ray, CodeFormers and a ton of urgent bug-fixes and other improvements.
To say my attention has been split is an understatement.
But I’m slowly but surely making more progress. I hope to have something out soon-ish. I do wonder if it will require a complete horde downtime this time for the DB upgrades. Never done that before. Kinda scary, not gonna lie…
It’s not much but it’s mine 😀 It took me a while to gather everything needed to create the steam page as Steam is way way more thorough than Itch.io. The benefits over itch of course are the automatic updates you’ll be able to receive. And for me, hopefully being on steam might attract a few more eyeball than might become collaborators 🙂
Hypnagonia has copied a lot of design paradigms from Slay the Spire, primarily because I needed a baseline to start working on content, instead of getting stuck in trying to figure out all the details of the design for every aspect. But you may be wondering why almost a year since I started it, it still looks like something to manage servers. To explain that, I need to give some background.
As someone with ADHD, it’s very easy for me to be overwhelmed by the frontloaded effort needed to be able to start something as large as developing a new game, and give up. Copying the design of something else is way more conductive to jump straight into doing something I already know how to do well (in this case, coding and card game design).
I am very lucky that my “autistic comfort zone” so-to-speak is programming (and general PC use), so that counteracts my executive dysfunction to a degree that allows me to start working on something, just for the joy of having a goal to program something. I kinda think of this “autistic drive” as a car battery ignition. It allows me to kickstart myself to do something which is one of the massive blocking points of ADHD.
However it’s not a trick that can always work, and it needs the right circumstances.
I got first interested in programming when I was 10 years old. I even pestered my mother enough to voluntarily go to 2 years of programming school back then – and sit through some of the worst lessons in programming one can have. Who the hell tries to teach 10-year olds Fortran by reading from the manual? Later on, I didn’t manage to get into university – due to just wanting to play computer games instead of studying for the exams. Instead, I went to a vocational school for programming for 2 more years.
When did I finally start programming for myself? When I was in my 30s. I literally learned programming and then didn’t do anything with it until I had the right circumstances. I tried multiple times to motivate myself to actually do something I knew I liked doing, but I couldn’t because I didn’t know what to do with it that was achievable for my skills. Things like making video games were out of the question as I had nowhere the skill needed to even begin. Yes, I know everyone starts like that, but try telling that to my stupid ADHD brain who does not get the concept of not getting the happiness chemical immediately.
What I truly needed was something I could start with very little programming needed and then built up my skills little by little, but having a clear but achievable improvement I could do.
In my case, my circumstances ended up being my interest in coding old card games in OCTGN, which requires very little code to start, but allows you to go bonkers with python if you want to (even if it doesn’t make it easy). The way it worked for me, is that I kept wanting to add more features, but each feature was just simple enough that I could see myself achieving it within a day or so. It kept me motivated enough to keep going.
The good news was that I had already picked up enough gamedev knowledge to give me some confidence. Once some of my burnout started to wear off 3 years later, I wanted to get back into card game design, but I didn’t want to touch OCTGN anymore. And then I discovered the Godot Engine (the way how is a post for another day) and after a few false starts, I got the idea to start on the Card Game Framework.
The reason why work on CGF is what worked, is because I had just enough knowledge of the things I needed to build (due to my experience with OCTGN), so that my autistic kickstart gave me enough momentum to overcome my ADHD executive dysfunction and head straight to Hyperfocus.
So, back to Hypnagonia, when I initially got the first concept for it, I knew it was way bigger than what I had done until now. Especially since I have no support network (I am not in a modding scene, and none of my contacts from my OCTGN, Android: Netrunner or Doomtown days seemed interested). So I knew I had to settle in the solodev role.
I also knew that if I tried to “reinvent the wheel” too much with my game, I will never get going as I will be stuck trying to think of how everything should work together until I give up due to complexity.
So early on, I decided to mostly copy Slay the Spire, as the granddaddy of the genre, while adding the few spins I wanted to use, which I knew were manageable for me. This means I settled to clone the UI look and core gameplay loop at least. The reason is, by now, I know how to program a GUI I can see in my head, and I know how to design card games, but I have no idea how to design good looking graphical interfaces, fancy animations, shader and effects or even any sort of art.
By using the StS layout, I could bypass my annoying brain trying to trick me out of doing something cool, by not having it get existential dread about trying to do something it doesn’t yet know how to do!
The main reason then why Hypnagonia still looks like so bad, is because I have no idea how to fix it, and any time I consider that I should do it, my brain goes: “Nope, you don’t know how to do it! Procrastinate a little instead. Reddit is just a button away!”
If I were to nevertheless stubbornly pressure myself to not do anything else except trying to improve the look of the game, I would procrastinate so much, I risk loosing my motivation for developing Hypnagonia completely. I had more than one close call with this.
For example, early on, I decided not to copy StS overworld mechanic (a map with encounters) because I wanted a more storyline-based experience. However I had no idea whatsoever what to replace it with. I got so demotivated that I couldn’t think what to do about it, I started distracting myself with other things. I was stuck and losing interest worryingly fast.
Fortunately, an experienced board game designer friend of mine agreed to brainstorm a little with me, and managed to throw an idea out that broke my “designer’s block” which eventually became the dream journal I have now.
So experience has taught me to know my limits. And at the current point, my limits are game UI/UX. Staying within the StS guidelines allows me to have a usable game. My plan is to make something playable end-to-end, even if not it’s not good looking and is full of placeholders. To salvage the rest, I just hope that I can attract specialist in the areas I cannot handle.
Every day I think about working on Hypnagonia, I need to kickstart my motivation and push through my urge to procrastinate “a bit” first. The way to do this, is to stay within my comfort zone, which is programming and game design.
So in the end, my autism helps me overcome my ADHD, but it has its limits. Therefore, the game look suffers.
I’ve been working on my Godot-based deckbuilder for a few months now and I still hadn’t managed to find something to call it. I’ve been calling it “Project Dreams” to signify that it’s a provisional name, but it’s been really bothering me that I couldn’t find something appropriate.
So in the past few days, I took the time to start brainstorming for names in the discord server, along with the other contributors. My requirements for a name was
It has to be catchy (in a poetic or mysterious sense)
It has to somehow refer to one of the main themes of the game (dreams, torments, psychology, surrealism, therapy), preferably more than one at the same time.
Bonus points if it includes alliteration or portmanteau.
After tons of back and forth, I was almost done with choosing one of the options, but one of the last things I did, was throw the word “surreal” through a thesaurus, just to see what I find, and it showed me a word I’ve never seen before: Hypnagogia.
Hypnagogia is the experience of the transitional state from wakefulness to sleep: the hypnagogic state of consciousness, during the onset of sleep. (The opposite transitional state from sleep into wakefulness is described as hypnopompic.) Mental phenomena that may occur during this “threshold consciousness” phase include hypnagogic hallucinations, lucid thought, lucid dreaming, and sleep paralysis. The latter two phenomena are themselves separate sleep conditions that are sometimes experienced during the hypnagogic state
I don’t know why it was shown as a relevant word to “surreal”, but it immediately clicked for me, because with only a single letter change, I could create an interesting portmanteau.
In case you don’t get it, this is a mix of the aforementioned Hypnagogia + Agony (or “Αγωνιά in greek) and It hits so many of my requirements at the same time:
It refers to sleep
It references agony (being tormented by your own psyche is a core theme of the game)
The original word is close enough to the concept of surreality that the thesaurus brings it up as a suggestion.
It’s a portmanteau
It sounds exotic. Kinda like a fantasy setting
It is unique. I don’t conflict with anything else out there (from what I can see)
I did try a few other variations of this, but I believe this one is the catchiest. And I’m also fed up looking for names, so I just went ahead and finally renamed everything!
In case you’re interested, here’s some other names I was considering:
After Fragment Forge reached its first milestone, I decided to take a break from game development for a bit to clear my head. I started playing a lot of the new interesting deckbuilders, such as Griftland and Accross the Obelisk, I started getting ideas on how to make an infinitely expandable single-player deckbuilder, that does not dilute its card base by constantly adding new cards. Those game’s power-creeping on behalf of the player also inspired me to think of a way to make a deckbuilder which had legacy elements which were not straight up making the game easier.
I just had to think of a theme to marry these concepts into the spire-like deckbuilder formula. The only requirement was that the theme was not vanilla-fucking-fantasy 🙂
Enter Hypnagonia. My first attempt at making a deckbulder using the card game framework work on a deckbuilder formula. Not wanting to reinvent the wheel from the start, I stuck close to the Slay the Spire formula, but added a few twists of my own.
The first one is that you don’t get a preconstructed starting deck. You also don’t do a pseudo-deck construction. Rather like Monster Train, you combine many decks together to select the archetypes of your run. In typical vanilla-fantasy terms, think of it like selecting a class, race, weapon and quest. Each of these comes with their own starting cards, and each archetype selected also can modify your character in many ways, such as modifying their starting health.
Then, on top of that, each archetype selected has its own pool of cards to choose from when drafting. The pool for each archetype is large enough that when you combine them all together, you end up with approximately the card-pool for a single character in other games of this type.
This allows me to add new archetypes, (for example, new “weapons”), without diluting the consistency of card types in any single run. Therefore making for an infinitely expandable game with no downsides. In fact, each new archetype added, increases the possibilities in a run exponentially.
As I said before, I absolutely wanted to stay away from classical fantasy tropes. I also wanted to make a game which is not all about the pure-violence if possible. Not because I have something against Violent games, but because it’s just such a common trope. Griftlands made a cool approach with that, allowing you to play the game almost completely peacefully if you so wish.
But in my case, I decided to move onto the surreal. Not only because it’s not a typical theme, but also because it allows for a lot more possibilities, as well as a lot of humor. Therefore this game will be played in dreams.
Making a game about dreams, allows me to make cards that are anything from typical fantasy, to sci-fi, to absolutely ridiculous. After all, our dreams don’t follow any particular logic and it would totally make dream-like sense for a magic sword, a plasma rifle and a rubber chicken to not only exist at the same time, but be just as effective as each other! In fact, this is why the Rubber Chicken is my very first item (i.e. archetype card pool) which I designed. I want to set the theme just right, you know?
This also gives me an opportunity to move away from the typical terms of violence and death that are typical in these games. I put a lot of effort into making the terminology of the game fit well into its theme. Therefore, you don’t “damage” your enemies, you “interpret” them. In turn, they do not “damage” you, the “stress” you out, and if you get stressed enough, you don’t die, you wake-up!
And this meant that I was making a game with a Thesaurus as my buddy :D. I think it gives the game archetype a nice coat of paint, and I am pretty proud with some of the terms I’ve come up with to signify typical aspects. It also means that I need to come up with different terms on behalf of the player and the enemies, for the same things, but hopefully it’s not too much to pick up. It also allows me to use creative terms which you don’t typically get to see a lot. For example, some Torments clutter your deck with useless cards. I call these, “Perturbations”.
Finally, the dream theme, allows me to create a legacy-aspect which makes thematic sense. But I’ll talk about this another day.
Oh and btw, I am in great need of collaborators for this project. While I can handle the coding, the design, art, sound aspects elude me and I could also use support in coming up with ideas for archetypes, cards and campaign concepts.
If you are interested in jumping in, let me know! As always, this game is Free Software under the AGPL3, so any work you contribute belong to you and the whole human commons.
With the milestone of 100 fully-scripted cards in Fragment Forge, I believe it’s time to switch the focus from prototyping, to playtesting. To this end, I’ve released v0.15 which contains all the latest cards, + 6 personas, over 3 different affiliations.
If you want to help, please download a client, or try it direct from the browser (executable application is way faster though). The application will also open a debug window when it runs. This is normal and you will be useful for any bug-reports.
You can use the single (for now) starting deck, or make your own.
At this point I’m particularly interested in the following:
Design Feedback: is the game fun? Is the deck-building interesting? What could be improved?
Balance: overpowered cards, broken combos etc
Fluff suggestions: Think a card’s name doesn’t fit? Lemme know! I am still looking for better names for the “Zippers” and “Champions” affiliations. Hit me with your best ideas.
The game GUI is obviously rough around the edges, and the card layout leaves a lot to be desired, but I wanted something playable more than I wanted something pretty. Especially since the design might change in case the rules are adjusted.
It’s been a long road to this point, starting from scratch. Game design + Programming + Playtesting + Story design/Worldbuilding by myself is hard!
At this point I think there’s an interesting core in the game, but I’m not convinced it’s interesting enough to play solo repeatedly. I would be really happy to get some ideas on how to make the solo play more engaging.