Compare commits
17 Commits
drone-ci
...
pi-nas-mus
Author | SHA1 | Date |
---|---|---|
ktyl | bb633a93c8 | |
ktyl | 34988c272e | |
ktyl | f0eb8bc2a2 | |
ktyl | 4a3adcd46a | |
ktyl | e3d3ac2df4 | |
ktyl | 6d0715f5b5 | |
ktyl | 2d9b6b689a | |
ktyl | 1f6c9649a5 | |
ktyl | 5f8a0cefe5 | |
ktyl | 89f56103f3 | |
ktyl | b7c2193ba5 | |
ktyl | 9ca4dd6b62 | |
ktyl | d42897624f | |
ktyl | c306093453 | |
ktyl | 40fbdd93c0 | |
ktyl | ef586f654d | |
ktyl | f31ebc88f4 |
|
@ -0,0 +1 @@
|
|||
*.png filter=lfs diff=lfs merge=lfs -text
|
|
@ -6,7 +6,7 @@ However, I have some gripes: I mostly only use it for the CI, but it comes with
|
|||
Because it's such a complete solution, GitLab is a bit of a resource hog, and can often run frustratingly slowly.
|
||||
|
||||
Recently I've been playing with a friend's self-hosted instance of [Drone CI](https://drone.io/) as a lightweight alternative, and I much prefer it.
|
||||
I didn't set up the instance, so that part is out of scope for this post, but in case it's relevant, we're using a self-hosted [Gitea](gitea.io) instance to host the source.
|
||||
I didn't set up the instance, so that part is out of scope for this post, but in case it's relevant, we're using a self-hosted [Gitea](https://gitea.io/) instance to host the source.
|
||||
You can find out about configuring Drone with Gitea [here](https://docs.drone.io/server/provider/gitea/).
|
||||
|
||||
|
||||
|
@ -114,3 +114,8 @@ I also want to try building some more complex projects, such as those using game
|
|||
Those are adventures for another day, though.
|
||||
|
||||
That's all for now, thanks for reading and see you next time!
|
||||
|
||||
## References
|
||||
|
||||
* [GitLab CI config to deploy via SSH](https://medium.com/@hfally/a-gitlab-ci-config-to-deploy-to-your-server-via-ssh-43bf3cf93775)
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# The Prince of Milk
|
||||
|
||||
The Prince of Milk is a science fiction novel by Exurb1a of YouTube fame.
|
||||
|
||||
It follows the story of a fictional village in southern England named Wilthail, which ends up the unwilling venue for the settling of an ancient grudge.
|
||||
Deities ("Etherics") exist alongside the mundanity of 21st century Wilthail, and engage in absurdity, sodomy and violence with its quaint population.
|
||||
The books makes reference to a number of popular philosophical debates, and takes inspiration from a number of classical sci-fi authors.
|
||||
|
||||
A common theme is the idea that power is relative.
|
||||
The Etherics are immortal - their grudge has played out across hundreds of 'Corporic' incarnations - and have power and abilities far beyond the comprehension of their human counterparts.
|
||||
However, they do not necessarily view themselves as gods.
|
||||
This is particularly true of the character Beomus, who frequently plays down their immortality and returns fire with questions about modern humans' relationship to their primitive ancestors, or with ants.
|
||||
This relativity of power recurs plenty, and is reminiscient of Arthur C. Clarke's assertion that sufficiently advanced technology is indistinguishable from magic.
|
||||
As characters in a book, the Etherics are understandably cagey about how any of their abilities work - but broadly refuse to classify them as either magic or technology.
|
||||
|
||||
Reincarnation is viewed as a fundamental way of the world - Chalmers' panpsychism, or the Hard Problem of Philosophy.
|
||||
This goes further than to suggest that people are simply reincarnated as others when they die, rather suggesting that consciousness is a fundamental force of the universe, in just the way electromagnetism is.
|
||||
It's a recursive thing, from the lowliest atom up through rocks, mice, snakes, cats, people, stars and gods.
|
||||
It's a neat and satisfying view, and one that has yet to be disproven by neuroscience.
|
||||
|
||||
The human characters are invariably damaged - mental health issues, broken relationships, toxic parentage, drug use, suicide, difficult histories.
|
||||
This paints PoM's world as realistic, and grounds it through the fantastical happenings in the middle act.
|
||||
It grips the reader with its variety of characters, and follows them all as they confront not only their own personal hells, but the one they now find themselves sharing, in a twisted take on country bumpkinism.
|
||||
|
||||
Overall, I thoroughly enjoyed this book, and am looking forward to reading more of Exurb1a's writing.
|
||||
I am a little biased, as I have already enjoyed the YouTube channel for a number of years.
|
||||
|
||||
There is a short glossary at the end naming and exploring some of the particular concepts explored in the novel, which prompt the reader to explore further.
|
||||
Top marks!
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Un Cafe Dans l'Espace
|
||||
|
||||
J'ai acheté ce livre quand j'ai visité la Cité de l'Espace à Toulouse. C'est écrit par Michel Tognini, un astronaute français qui été dans l'espace deux fois. Il a travillé sur la station spatiale de Mir, et sur la navette spatiale pour décoller CHANDRA, une observatoir dans le bas orbite. Depuis, il a selectionné et entrainé de nouveaux astronautes européens.
|
||||
|
||||
Ce livre parle de plusiers subjets en relation à l'espace: de l'entrainement de l'auteur à la Cité des Étoiles en Russie, de les échecs et défis dans l'espace, aux réalisations des sociétés privés comme SpaceX, Blue Origin et Virgin Galactic. Comme d'autres astronautes, Tognini a étudié comme pilote de chasse, et puis comme pilote d'essai. Il a rejoint l'agence spatiale française CNES avant la formation de l'ESA, qui existe encore aujourd'hui.
|
||||
|
||||
J'ai trouvé que je connaissais déjà beaucoup des histoires dans ce livre, parce que j'ai toujours eu une adoration pour l'espace, et c'est écrit pour une audience générale. Ma première raison de lire ce livre est que c'était mon premier français! Cela m'a pris quelques mois, mais c'etait une experience agréable. Au début, j'avais besoin de rechercer plusiers mots à chaque page, mais à la fin j'ai trouvé que je pouvais lire beaucoup d'aisance.
|
||||
|
||||
Je recommende ce livre aux francophones qui sont interessés par l'espace, mais qui sont peut-être moins familiers avec le jargon comme moi.
|
||||
|
||||
Encore, merci à mon cher Ethel pour m'aider avec mon français ! <3
|
|
@ -0,0 +1,92 @@
|
|||
# Automounting network drives with NFS
|
||||
|
||||
I have a NAS which supports NFS, which I use to store all of my photos, music and other media on my local network.
|
||||
This gives me OS-independent to all of these files, and frees up drive space on my laptops and desktop - most of which are dual-booted.
|
||||
On Windows it's fairly straightforward to establish a network drive, but on Linux-based systems - at least on the Debian- and Arch- based distros I find myself using - the process is a little more involved.
|
||||
|
||||
Here I'll use `systemd` to automatically mount a shared folder when they're accessed by a client machine.
|
||||
There are other ways to do this, but as my machines predimonantly run Debian- or Arch-derived Linux distributions, `systemd` is a choice that works for both.
|
||||
This post is largely based on the description on the [ArchWiki](https://wiki.archlinux.org/title/NFS#As_systemd_unit).
|
||||
My NAS' hostname is `sleeper-service`, and I'll be mounting the `Music` shared folder.
|
||||
|
||||
You'll need the appropriate package to mount NFS filesytems.
|
||||
On Arch Linux, `nfs-utils` is what you'll be after.
|
||||
On Debian, the client pckage is `nfs-common`, which may already be installed.
|
||||
You may also need to configure security on your NAS to allow NFS connections from your local machine's IP.
|
||||
|
||||
## Initial mount
|
||||
|
||||
Before doing anything automatically, we first need to create a `systemd` unit to mount the remote filesystem at a path in our local filesystem.
|
||||
I'll mount the remote folder onto the local path `/sleeper-service/Music`.
|
||||
When creating this file, pay attention to its name, as it's important for it to correspond to the path of the mountpoint.
|
||||
The correct name can be determined using `systemd-escape` - pay attention to escape characters in the output, this caught me out several times.
|
||||
|
||||
```
|
||||
$ systemd-escape /sleeper-service/Music
|
||||
-sleeper\x2dservice-Music
|
||||
$ sudo touch /etc/systemd/system/sleeper\\x2dservice-Music.mount
|
||||
```
|
||||
|
||||
Don't ask me why `systemd` is like this - I think it's silly too.
|
||||
After creating the unit file, we then need to edit it and fill out some information, specifying where the remote filesystem is and also when we need to initialise it.
|
||||
|
||||
Here I used a name instead of an address for the `What=` part - I have an entry for `sleeper-service` configured in `/etc/hosts`, but you can equally use an IP address just as well.
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Mount music at boot
|
||||
|
||||
[Mount]
|
||||
What=sleeper-service:/volume1/Music
|
||||
Where=/sleeper-service/Music
|
||||
Options=vers=3
|
||||
Type=nfs
|
||||
TimeoutSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Once we've created this, we can try to manually mount the shared folder by starting the unit:
|
||||
|
||||
```
|
||||
$ sudo systemctl start sleeper\\x2dservice-Music.mount
|
||||
$ ls /sleeper-service/Music
|
||||
```
|
||||
|
||||
At this stage you ought to see the contents of your shared folder.
|
||||
Next, we want to set up the automount, so that this remote folder is mounted automatically when we try to access it.
|
||||
To do that, we need to first stop/disable the unit we just created:
|
||||
|
||||
```
|
||||
$ sudo systemctl disable sleeper\\x2dservice-Music.mount
|
||||
```
|
||||
|
||||
Then, let's create an `.automount` unit with the same name as the `.mount` file we already have.
|
||||
The automount unit expects the mount unit to exist alongside it - it doesn't replace it.
|
||||
|
||||
```
|
||||
$ sudo touch /etc/systemd/system/sleeper\\x2dservice-Music.automount
|
||||
```
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Automount NAS music
|
||||
|
||||
[Automount]
|
||||
Where=/sleeper-service/Music
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Then, enable the new `.automount` unit to have it run automatically:
|
||||
|
||||
```
|
||||
$ sudo systemctl enable sleeper\\x2dservice-Music.automount
|
||||
```
|
||||
|
||||
The folder should now be automatically mounted at the target location when trying to access it.
|
||||
|
||||
As always, thanks for reading and I hope this was helpful.
|
||||
If I got something wrong, or there's an easier way to do it, or you just want to say hi, please don't hesitate to [get in touch!](mailto:me@ktyl.dev)
|
Binary file not shown.
After Width: | Height: | Size: 214 KiB |
Binary file not shown.
|
@ -0,0 +1,128 @@
|
|||
# Local Stable Diffusion
|
||||
|
||||
![astronaut rides horse](astronaut_rides_horse.jpg)
|
||||
|
||||
Stable diffusion (SD) is an AI technique for generating images from text prompts.
|
||||
Similar to DALL-E, which drives the popular [craiyon](https://www.craiyon.com/), SD is available as an [online tool](https://huggingface.co/spaces/stabilityai/stable-diffusion).
|
||||
These web tools are amazing, and easy to use, but can be frustrating - they're often under high load, and impose long waiting times.
|
||||
They use a good chunk of computational resources, specifically GPUs and so have generally been out of reach for even people with powerful personal machines.
|
||||
|
||||
Now, however, SD has reached the point it can be run using (admittedly, high-end) consumer video cards.
|
||||
Stability AI - the model's developers - recently [published a blog post](https://stability.ai/blog/stable-diffusion-v2-release) open-sourcing SD 2.
|
||||
There's a README for getting started [here](https://huggingface.co/stabilityai/stable-diffusion-2/blob/main/README.md), but it has a couple of gotchas and assumptions which plenty of people (like myself) won't have known if they're not already familiar with the technologies in use, such as Python and CUDA.
|
||||
|
||||
This post is descibes my experience setting up SD 2 on my local workstation.
|
||||
For hardware, I have an i7-6700k, RTX 2080 Super and 48GB of RAM.
|
||||
If you have an AMD video card, you won't be able to use CUDA, but you may be able to use GPU acceleration regardless using something ROCm.
|
||||
In this post I'm using Arch Linux, but I have successfully set it up on Windows too.
|
||||
Python is an exceedingly portable language, so it should work wherever you're able to get a Python installation.
|
||||
|
||||
This post assumes that you already have a working Python installation.
|
||||
|
||||
## Install CUDA
|
||||
|
||||
CUDA needs to be installed separately from Python dependencies.
|
||||
It is quite large, and as with all NVIDIA driver installations, can be a bit confusing.
|
||||
On Linux, it's straightforward to install it from your distribution's package manager.
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu
|
||||
sudo pacman -S cuda
|
||||
```
|
||||
|
||||
On Windows, you will need to go to NVIDIA's site to download the correct version of CUDA.
|
||||
At time of writing, the SD 2 script expects CUDA 11.7, and will not work if you install the latest 12.0 version.
|
||||
To get older versions, go to their [download archive](https://developer.nvidia.com/cuda-toolkit-archive) and select the appropriate one.
|
||||
|
||||
## Set up a virtual environment an PyTorch
|
||||
|
||||
Python can be installed at a system level, but it's usually a good idea to set up a virtual environment for your project.
|
||||
This isolates the project dependencies from the wider system, and makes your setup reproducible.
|
||||
I will use [`pipenv`](https://pipenv.pypa.io/en/latest/index.html) as it's what I'm familiar with.
|
||||
|
||||
PyTorch is a deep-learning framework, used to put together machine learning pipelines.
|
||||
|
||||
To get a command to install the relevant dependencies, go to [PyTorch's site](https://pytorch.org/get-started/locally/) and choose the options for your setup.
|
||||
In my case, I replaced `pip3` with `pipenv` as I want to install dependencies to a new virtual environment instead of to the system.
|
||||
|
||||
```bash
|
||||
mkdir stable-diffusion && cd stable-diffusion
|
||||
pipenv install torch torchvision torchaudio
|
||||
```
|
||||
|
||||
## Install Stable Diffusion
|
||||
|
||||
SD 2 is provided by the `diffusers` package.
|
||||
We can install it in our virtual environment as follows:
|
||||
|
||||
```bash
|
||||
pipenv shell
|
||||
pip3 install git+https://github.com/huggingface/diffusers.git transformers accelerate scipy
|
||||
exit
|
||||
```
|
||||
|
||||
We use `pipenv shell` to enter a shell using the virtual environment, before using the `pip3` command described on their README.
|
||||
After installing dependencies, we can leave the virtual environment shell and return to our original one.
|
||||
`transformers` and `accelerate` are optional, but used to reduce memory usage and so are recommended.
|
||||
|
||||
## Create a Python script
|
||||
|
||||
Python does have an interactive envronment, but so save our fingers let's use a `stable-diffusion.py` script to contain and run our Python code.
|
||||
Here I'll mostly copy the Python included in their README:
|
||||
|
||||
```python
|
||||
import torch
|
||||
from diffusers import StableDiffusionPipeline, EulerDiscreteScheduler
|
||||
|
||||
model_id = "stabilityai/stable-diffusion-2"
|
||||
|
||||
# Use the Euler scheduler here instead
|
||||
scheduler = EulerDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler")
|
||||
pipe = StableDiffusionPipeline.from_pretrained(model_id, scheduler=scheduler, revision="fp16", torch_dtype=torch.float16)
|
||||
pipe = pipe.to("cuda")
|
||||
pipe.enable_attention_slicing()
|
||||
|
||||
prompt = "a photo of an astronaut riding a horse on mars"
|
||||
image = pipe(prompt, height=768, width=768).images[0]
|
||||
|
||||
image.save("astronaut_rides_horse.png")
|
||||
```
|
||||
|
||||
I've made two additions here.
|
||||
First, I've added `import torch` at the top - I'm not sure why the code in the README omits this, but it's needed to work.
|
||||
|
||||
I've also added `pipe.enable_attention_slicing()` - this is a more memory-efficient running mode, which is less intensive at the cost of taking longer.
|
||||
If you have a monster video card, this may not be necessary.
|
||||
|
||||
At this point, we're done - after running the script successfully, you should have a new picture of an astronaut riding a horse on mars.
|
||||
|
||||
## Some nice-to-haves
|
||||
|
||||
In this basic script we only have the one, hardcoded prompt.
|
||||
To change it, we need to update the file itself.
|
||||
Instead, we can change how `prompt` is set, and have it read from command-line parameters instead.
|
||||
|
||||
```python
|
||||
# at the top of the file
|
||||
import sys
|
||||
|
||||
...
|
||||
|
||||
prompt = " ".join(sys.argv[1:])
|
||||
```
|
||||
|
||||
While we're at it, we can also base the filename on the input prompt:
|
||||
|
||||
```python
|
||||
image.save(f'{prompt.replace(" ", "_")}.png')
|
||||
```
|
||||
|
||||
## Wrapping up
|
||||
|
||||
And that's it!
|
||||
Enjoy making some generative art.
|
||||
My favourites so far have been prefixing "psychedelic" to things.
|
||||
I've also been enjoying generating descriptions with [ChatGPT](https://chat.openai.com/chat) and plugging them into SD, for some zero-effort creativity.
|
||||
As always, if anything's out of place of if you'd like to get in touch, please [send me an email!](mailto:me@ktyl.dev).
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Game dialogue with ChatGPT
|
||||
|
||||
[ChatGPT](https://chat.openai.com/chat) has become the latest AI application to enjoy viral popularity.
|
||||
At time of writing it's a closed-source research tool developed by OpenAI, with the only access being via their web portal.
|
||||
Users have to create an account to interact with the bot, and have no API access, though they no doubt have one internally.
|
||||
I think given its capabilities, this is probably a good idea for now, but I'd like to outline the impact it can already have in game development, even in its fairly limited form.
|
||||
|
||||
However, it can already be made immensely useful for content generation, without any kind of API access.
|
||||
Generally, characters come in two flavours: main characters, whose motivations and actions shape the story; and generic NPCs, who exist to fill out the world for the player.
|
||||
|
||||
For the story to carry the author's intent (which they might not necessarily care about), it would probably be best not to leave ChatGPT to generate a plotline on its own.
|
||||
Its susceptibilty to bias is a problem - try generating men or women and count how often they're describing as petite, as having chiseled jaws or as wearing form-fitting dresses.
|
||||
It can be coaxed out of this with enough description, but lots of manual intervention defeats any content generation technique.
|
||||
|
||||
The other group of characters, though, I think represents ripe pickings.
|
||||
Often in a game world, background dialogue quickly becomes stale, as lines are reused.
|
||||
ChatGPT can already easily be used as a supporting writer to generate a huge amount of less-than-critical dialogue.
|
||||
Take, for example, a merchant.
|
||||
|
||||
![generating merchant dialogue](merchant_prompt.png)
|
||||
|
||||
This psuedo-format is instantly combatible with a simple templating system.
|
||||
It would be trivial to generate variations using perfectly traditional programming techniques.
|
||||
This prompt took a minute to write, and includes specific about the character's context, as well as a slightly more than default personality.
|
||||
|
||||
We've instantly generated 8 perfectly workable dialogue options for our character, from some basic and mostly templated information about their context.
|
||||
However, we notice that our item choices weren't included in the output, though we described them.
|
||||
So we ask:
|
||||
|
||||
![merchant items](merchant_items.png)
|
||||
|
||||
And, instantly, another 8 lines.
|
||||
We now have, after a modicum of input, 16 possible lines for a background merchant character to respond with when interacted with.
|
||||
With some templated prompt generation, this could be made even faster than the description given here.
|
||||
|
||||
It's also capable of going beyond just lines dialogue.
|
||||
[Ibralogue](https://github.com/Ibralogue/Ibralogue)'s developer taught it the syntax, had it generate an example and then taught it a new feature:
|
||||
|
||||
![sprite prompt](sprite_prompt.png)
|
||||
|
||||
![sprite response](sprite_response.png)
|
||||
|
||||
All that's left is to copy the output and paste it into a text file for a game to use.
|
||||
|
||||
---
|
||||
|
||||
This is barely even a scratch on what ChatGPT or systems like it are already capable of.
|
||||
At present, the website gets overloaded, you can't save and reload conversations, and its content filtering is very much evolving problem.
|
||||
However, even with those limitations it's an extraordinarily powerful tool, and this is just one very minor example of an application.
|
||||
|
||||
That's it from me, but I'd love to read more discussion about use cases and the ethical issues at play.
|
||||
If you have anything interesting, please [get in touch](mailto:me@ktyl.dev)!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
For the communal music player, means of access is also something to consider.
|
||||
I'm personally quite comfortable with the minimal MPD client, [ncmpcpp](https://github.com/ncmpcpp/ncmpcpp), but the aim of a _communal_ music system is to entice others, potentially houseguests to use it too.
|
||||
To ask them to use a TUI system whose name doesn't even contain vowels would be an exercise in the obtuse.
|
||||
Therefore, I also want a means to interact with this music player which is ideally as straightforward as Spotify.
|
|
@ -0,0 +1,26 @@
|
|||
# Setting up a network media drive with an NFS-enabled NAS and a Raspberry Pi
|
||||
|
||||
I have a large digitised collection of music, and have been experimenting with ways to set up a communal music player in my living room without defaulting to Spotify, or any other such streaming platform.
|
||||
Thus far I have used an old laptop with as much music as it will fit loaded onto it, running [MPD](https://www.musicpd.org/) and plugged into some speakers.
|
||||
This is an OK solution, but has a few drawbacks: I'm limited to the disk of the laptop, the laptop uses more power than it needs to, and I kind of want that laptop back as a laptop!
|
||||
|
||||
I also have a desktop machine from which I often work from home, and would like my music collection available there too.
|
||||
Ideally, these should be stored in the same place, to save having to manage duplicate files and manually synchronising locations, since I am likely to add to my collection from a variety of locations.
|
||||
I have spent enough time `rsync`ing albums between machines, life is too short even on a gigabit local network.
|
||||
|
||||
I've recently had the good fortune to acquire a Synology NAS, so I'm going to use that to host my music collection.
|
||||
Nothing I'm doing should be specific to Synology's hardware or software, as we'll be using [NFS](https://wiki.archlinux.org/title/NFS) to mount remote drives - but exposing an NFS shared folder to the network is therefore out of scope for this post.
|
||||
I also had the luck to grab a Raspberry Pi from a pop-up store a few weeks ago, and felt that would make a perfect, low-power, unintrusive box to attach to the speakers.
|
||||
Ostensibly, the Pi is overkill for just playing music, but it's better than a whole laptop and I'm sure I'll find other jobs for it to do as time goes on.
|
||||
|
||||
## Set up a shared folder
|
||||
|
||||
The first step is to centralise my music storage.
|
||||
To do this, I created a shared folder from my NAS' web interface, and exposed it to the network.
|
||||
|
||||
In my case, I had to specifically add permission for other devices to access the folder via NFS - such as the Pi, my desktop and my laptop.
|
||||
It was therefore prudent to assign each of these machines a static IP on my network, so that the NAS can continue to recognise them.
|
||||
I also had to set it to map all users to admin, but this is almost certainly a misconfiguration on my part - don't follow me for security advice, I am just tinkering!
|
||||
|
||||
## Setting up the Pi
|
||||
|
Loading…
Reference in New Issue