various updates
This commit is contained in:
@@ -42,6 +42,7 @@ or give me access to your servers.
|
|||||||
- [bash](#bash)
|
- [bash](#bash)
|
||||||
- [Bulk File/Folder Renaming](#bulk-filefolder-renaming)
|
- [Bulk File/Folder Renaming](#bulk-filefolder-renaming)
|
||||||
- [Escaping a Stuck SSH Terminal](#escaping-a-stuck-ssh-terminal)
|
- [Escaping a Stuck SSH Terminal](#escaping-a-stuck-ssh-terminal)
|
||||||
|
- [Curl output hidden by bash prompt](#curl-output-hidden-by-bash-prompt)
|
||||||
- [SSH Setup](#ssh-setup)
|
- [SSH Setup](#ssh-setup)
|
||||||
- [Git GPG Commit Signing](#git-gpg-commit-signing)
|
- [Git GPG Commit Signing](#git-gpg-commit-signing)
|
||||||
- [Important Dates and Times](#important-dates-and-times)
|
- [Important Dates and Times](#important-dates-and-times)
|
||||||
@@ -133,6 +134,14 @@ done
|
|||||||
|
|
||||||
Press the following keys: enter + ~ + .
|
Press the following keys: enter + ~ + .
|
||||||
|
|
||||||
|
### Curl output hidden by bash prompt
|
||||||
|
|
||||||
|
Add this to your ~/.curlrc
|
||||||
|
|
||||||
|
```conf
|
||||||
|
-w "\n"
|
||||||
|
```
|
||||||
|
|
||||||
## SSH Setup
|
## SSH Setup
|
||||||
|
|
||||||
Generate a key (password protect it!)
|
Generate a key (password protect it!)
|
||||||
@@ -212,15 +221,16 @@ signed you'll see an output. If not, nothing will show.
|
|||||||
|
|
||||||
## Important Dates and Times
|
## Important Dates and Times
|
||||||
|
|
||||||
| Time | Day | Description |
|
| Time | Day | Description |
|
||||||
| ----- | --- | ---------------------------------- |
|
| ----- | --- | ------------------------------ |
|
||||||
| 00:00 | All | Automated builds |
|
| 00:00 | All | Automated builds |
|
||||||
| 00:00 | All | NAS Snapshots |
|
| 00:00 | All | NAS Snapshots |
|
||||||
| 02:00 | All | Backups |
|
| 01:00 | All | Backups |
|
||||||
| 04:00 | All | Bare Metal Server Security Updates |
|
| 03:00 | All | App Updates |
|
||||||
| 05:00 | All | VM Server Security Updates |
|
| 04:00 | All | Bare Metal Server Updates |
|
||||||
| 05:00 | All | Unifi Protect Firmware Updates |
|
| 05:00 | All | VM Server Updates |
|
||||||
| 06:00 | All | Unifi Network Firmware Updates |
|
| 05:00 | All | Unifi Protect Firmware Updates |
|
||||||
|
| 06:00 | All | Unifi Network Firmware Updates |
|
||||||
|
|
||||||
## Project Lifecycle
|
## Project Lifecycle
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# AWS Bedrock
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
Completions endpoint: <https://bedrock-mantle.us-east-1.api.aws/v1>
|
||||||
|
|
||||||
|
## Model Analysis
|
||||||
|
|
||||||
|
| Model ID | Input Price (Mil) | Output Price (Mil) | Doodle Jump Notes |
|
||||||
|
| ----------------------- | ----------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| minimax.minimax-m2.5 | $ 0.30 | $ 1.20 | Way too fast and player moves too slow. Identified issue and fixed after second attempt |
|
||||||
|
| zai.glm-5 | $ 1.00 | $ 3.20 | Perfect game with great graphics. |
|
||||||
|
| mistral.devstral-2-123b | $ 0.40 | $ 2.00 | Broken game with very basic graphics. Second attempt broken as well. |
|
||||||
|
| deepseek.v3.2 | $1.35 | $5.40 | Way too fast, platform generation erratic, mobile controls were a nice touch. Fixed speed issue on second attempt but platform generation still bad |
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
services:
|
|
||||||
gitea:
|
|
||||||
image: docker.gitea.com/gitea:1.25-rootless
|
|
||||||
container_name: gitea
|
|
||||||
environment:
|
|
||||||
- GITEA__database__DB_TYPE=postgres
|
|
||||||
- GITEA__database__HOST=postgres:5432
|
|
||||||
- GITEA__database__NAME=gitea
|
|
||||||
- GITEA__database__USER=gitea
|
|
||||||
- GITEA__database__PASSWD=gitea
|
|
||||||
security_opt:
|
|
||||||
- "label=disable"
|
|
||||||
restart: always
|
|
||||||
networks:
|
|
||||||
- gitea
|
|
||||||
volumes:
|
|
||||||
- /home/gitea/gitea_data:/data:Z
|
|
||||||
- /home/gitea/gitea_etc:/etc/gitea:Z
|
|
||||||
- /home/gitea/gitea_custom:/var/lib/gitea/custom:Z
|
|
||||||
- /etc/localtime:/etc/localtime:ro
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
- "2222:2222"
|
|
||||||
depends_on:
|
|
||||||
- postgres
|
|
||||||
labels:
|
|
||||||
- "io.containers.autoupdate=registry"
|
|
||||||
|
|
||||||
postgres:
|
|
||||||
image: docker.io/library/postgres:15
|
|
||||||
container_name: postgres
|
|
||||||
security_opt:
|
|
||||||
- "label=disable"
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
- POSTGRES_USER=gitea
|
|
||||||
- POSTGRES_PASSWORD=gitea
|
|
||||||
- POSTGRES_DB=gitea
|
|
||||||
networks:
|
|
||||||
- gitea
|
|
||||||
volumes:
|
|
||||||
- /home/gitea/gitea_postgres:/var/lib/postgresql/data:Z
|
|
||||||
labels:
|
|
||||||
- "io.containers.autoupdate=registry"
|
|
||||||
|
|
||||||
networks:
|
|
||||||
gitea:
|
|
||||||
enable_ipv6: true
|
|
||||||
@@ -4,7 +4,7 @@ networks:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
server:
|
server:
|
||||||
image: docker.gitea.com/gitea:1.25.3
|
image: docker.gitea.com/gitea:1.26.1
|
||||||
container_name: gitea
|
container_name: gitea
|
||||||
environment:
|
environment:
|
||||||
- USER_UID=1001
|
- USER_UID=1001
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Requires=postgres.service
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
AutoUpdate=registry
|
|
||||||
ContainerName=gitea
|
|
||||||
Environment=GITEA__database__DB_TYPE=postgres GITEA__database__HOST=postgres:5432 GITEA__database__NAME=gitea GITEA__database__USER=gitea GITEA__database__PASSWD=gitea
|
|
||||||
Image=docker.gitea.com/gitea:1.25-rootless
|
|
||||||
Network=gitea.network
|
|
||||||
PublishPort=3000:3000
|
|
||||||
PublishPort=2222:2222
|
|
||||||
SecurityLabelDisable=true
|
|
||||||
Volume=/home/gitea/gitea_data:/data:Z
|
|
||||||
Volume=/home/gitea/gitea_etc:/etc/gitea:Z
|
|
||||||
Volume=/home/gitea/gitea_custom:/var/lib/gitea/custom:Z
|
|
||||||
Volume=/etc/localtime:/etc/localtime:ro
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=default.target
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[Container]
|
|
||||||
AutoUpdate=registry
|
|
||||||
ContainerName=postgres
|
|
||||||
Environment=POSTGRES_USER=gitea POSTGRES_PASSWORD=gitea POSTGRES_DB=gitea
|
|
||||||
Image=docker.io/library/postgres:15
|
|
||||||
Network=gitea.network
|
|
||||||
SecurityLabelDisable=true
|
|
||||||
Volume=/home/gitea/gitea_postgres:/var/lib/postgresql/data:Z
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=default.target
|
|
||||||
@@ -10,7 +10,7 @@ DB_DATA_LOCATION=/srv/immich-db/postgres
|
|||||||
# TZ=Etc/UTC
|
# TZ=Etc/UTC
|
||||||
|
|
||||||
# The Immich version to use. You can pin this to a specific version like "v2.1.0"
|
# The Immich version to use. You can pin this to a specific version like "v2.1.0"
|
||||||
IMMICH_VERSION=v2
|
IMMICH_VERSION=v3
|
||||||
|
|
||||||
# Connection secret for postgres. You should change it to a random password
|
# Connection secret for postgres. You should change it to a random password
|
||||||
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
|
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
services:
|
|
||||||
keycloak:
|
|
||||||
container_name: keycloak
|
|
||||||
restart: always
|
|
||||||
image: quay.io/keycloak/keycloak:26.4.5
|
|
||||||
ports:
|
|
||||||
- "9443:443"
|
|
||||||
- "8443:8443"
|
|
||||||
volumes:
|
|
||||||
- /home/foobar/data:/var/app/data
|
|
||||||
security_opt:
|
|
||||||
- label=disable
|
|
||||||
userns_mode: keep-id
|
|
||||||
command:
|
|
||||||
- "start"
|
|
||||||
- "--hostname"
|
|
||||||
- "https://keycloak.reeseapps.com"
|
|
||||||
- "--hostname-admin"
|
|
||||||
- "https://keycloak.reeselink.com:8443"
|
|
||||||
@@ -1,186 +1,10 @@
|
|||||||
# Podman keycloak
|
# Podman keycloak
|
||||||
|
|
||||||
- [Podman keycloak](#podman-keycloak)
|
- [Podman keycloak](#podman-keycloak)
|
||||||
- [Setup keycloak Project](#setup-keycloak-project)
|
- [Adding a Client](#adding-a-client)
|
||||||
- [Install Keycloak with Docker](#install-keycloak-with-docker)
|
|
||||||
- [Install Keycloak with Podman](#install-keycloak-with-podman)
|
|
||||||
- [Create the keycloak user](#create-the-keycloak-user)
|
|
||||||
- [Write the keycloak compose spec](#write-the-keycloak-compose-spec)
|
|
||||||
- [A Note on Volumes](#a-note-on-volumes)
|
|
||||||
- [Convert keycloak compose spec to quadlets](#convert-keycloak-compose-spec-to-quadlets)
|
|
||||||
- [Create any container-mounted directories](#create-any-container-mounted-directories)
|
|
||||||
- [Start and enable your systemd quadlet](#start-and-enable-your-systemd-quadlet)
|
|
||||||
- [Expose keycloak](#expose-keycloak)
|
|
||||||
- [firewalld](#firewalld)
|
|
||||||
- [Backup keycloak](#backup-keycloak)
|
|
||||||
- [Upgrade keycloak](#upgrade-keycloak)
|
|
||||||
- [Upgrade Quadlets](#upgrade-quadlets)
|
|
||||||
- [Uninstall](#uninstall)
|
|
||||||
- [Notes](#notes)
|
|
||||||
- [SELinux](#selinux)
|
|
||||||
|
|
||||||
## Setup keycloak Project
|
## Adding a Client
|
||||||
|
|
||||||
- [ ] Copy and rename this folder to active/container_keycloak
|
1. Create a new client
|
||||||
- [ ] Find and replace keycloak with the name of the service.
|
2. Clients -> click on client -> Client scopes -> client-frontend-dedicated -> Scope -> turn off Full Scope Allowed
|
||||||
- [ ] Create the rootless user to run the podman containers
|
3.
|
||||||
- [ ] Write the compose.yaml spec for your service
|
|
||||||
- [ ] Convert the compose.yaml spec to a quadlet
|
|
||||||
- [ ] Install the quadlet on the podman server
|
|
||||||
- [ ] Expose the quadlet service
|
|
||||||
- [ ] Install a backup service and timer
|
|
||||||
|
|
||||||
## Install Keycloak with Docker
|
|
||||||
|
|
||||||
<https://www.keycloak.org/getting-started/getting-started-docker>
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Test in dev mode
|
|
||||||
docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.4.7 start-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Install Keycloak with Podman
|
|
||||||
|
|
||||||
### Create the keycloak user
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# SSH into your podman server as root
|
|
||||||
useradd keycloak
|
|
||||||
loginctl enable-linger $(id -u keycloak)
|
|
||||||
systemctl --user --machine=keycloak@.host enable podman-restart
|
|
||||||
systemctl --user --machine=keycloak@.host enable --now podman.socket
|
|
||||||
mkdir -p /home/keycloak/.config/containers/systemd
|
|
||||||
```
|
|
||||||
|
|
||||||
### Write the keycloak compose spec
|
|
||||||
|
|
||||||
<https://www.keycloak.org/getting-started/getting-started-podman>
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Based on the example
|
|
||||||
podman run \
|
|
||||||
-p 127.0.0.1:8080:8080 \
|
|
||||||
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
|
|
||||||
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
|
|
||||||
quay.io/keycloak/keycloak:26.4.5 start-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
#### A Note on Volumes
|
|
||||||
|
|
||||||
Named volumes are stored at `/home/keycloak/.local/share/containers/storage/volumes/`.
|
|
||||||
|
|
||||||
### Convert keycloak compose spec to quadlets
|
|
||||||
|
|
||||||
Run the following to convert a compose.yaml into the various `.container` files for systemd:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Generate the systemd service
|
|
||||||
podman run \
|
|
||||||
--security-opt label=disable \
|
|
||||||
--rm \
|
|
||||||
-v $(pwd)/active/container_keycloak/:/compose \
|
|
||||||
-v $(pwd)/active/container_keycloak/quadlets:/quadlets \
|
|
||||||
quay.io/k9withabone/podlet \
|
|
||||||
-f /quadlets \
|
|
||||||
-i \
|
|
||||||
--overwrite \
|
|
||||||
compose /compose/compose.yaml
|
|
||||||
|
|
||||||
# Copy the files to the server
|
|
||||||
export PODMAN_SERVER=
|
|
||||||
scp -r active/container_keycloak/quadlets/. $PODMAN_SERVER:/home/keycloak/.config/containers/systemd/
|
|
||||||
ssh $PODMAN_SERVER chown -R keycloak:keycloak /home/keycloak/.config/containers/systemd/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create any container-mounted directories
|
|
||||||
|
|
||||||
SSH into your podman server as root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
machinectl shell keycloak@
|
|
||||||
podman unshare
|
|
||||||
mkdir some_volume
|
|
||||||
# Chown to the namespaced user with UID 1000
|
|
||||||
# This will be some really obscure UID outside the namespace
|
|
||||||
# This will also solve most permission denied errors
|
|
||||||
chown -R 1000:1000 some_volume
|
|
||||||
```
|
|
||||||
|
|
||||||
### Start and enable your systemd quadlet
|
|
||||||
|
|
||||||
SSH into your podman server as root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
machinectl shell keycloak@
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user restart keycloak
|
|
||||||
# Enable auto-update service which will pull new container images automatically every day
|
|
||||||
systemctl --user enable --now podman-auto-update.timer
|
|
||||||
```
|
|
||||||
|
|
||||||
### Expose keycloak
|
|
||||||
|
|
||||||
1. If you need a domain, follow the [DDNS instructions](/active/container_ddns/ddns.md#install-a-new-ddns-service)
|
|
||||||
2. For a web service, follow the [Caddy instructions](/active/container_caddy/caddy.md#adding-a-new-caddy-record)
|
|
||||||
3. Finally, follow your OS's guide for opening ports via its firewall service.
|
|
||||||
|
|
||||||
#### firewalld
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# command to get current active zone and default zone
|
|
||||||
firewall-cmd --get-active-zones
|
|
||||||
firewall-cmd --get-default-zone
|
|
||||||
|
|
||||||
# command to open 443 on tcp
|
|
||||||
firewall-cmd --permanent --zone=<zone> --add-port=443/tcp
|
|
||||||
|
|
||||||
# command to open 80 and 443 on tcp and udp
|
|
||||||
firewall-cmd --permanent --zone=<zone> --add-port={80,443}/{tcp,udp}
|
|
||||||
|
|
||||||
# command to list available services and then open http and https
|
|
||||||
firewall-cmd --get-services
|
|
||||||
firewall-cmd --permanent --zone=<zone> --add-service={http,https}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Backup keycloak
|
|
||||||
|
|
||||||
Follow the [Borg Backup instructions](/active/systemd_borg/borg.md#set-up-a-client-for-backup)
|
|
||||||
|
|
||||||
## Upgrade keycloak
|
|
||||||
|
|
||||||
### Upgrade Quadlets
|
|
||||||
|
|
||||||
Upgrades should be a repeat of [writing the compose spec](#convert-keycloak-compose-spec-to-quadlets) and [installing the quadlets](#start-and-enable-your-systemd-quadlet)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export PODMAN_SERVER=
|
|
||||||
scp -r quadlets/. $PODMAN_SERVER$:/home/keycloak/.config/containers/systemd/
|
|
||||||
ssh keycloak systemctl --user daemon-reload
|
|
||||||
ssh keycloak systemctl --user restart keycloak
|
|
||||||
```
|
|
||||||
|
|
||||||
## Uninstall
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Stop the user's services
|
|
||||||
systemctl --user disable podman-restart
|
|
||||||
podman container stop --all
|
|
||||||
systemctl --user disable --now podman.socket
|
|
||||||
systemctl --user disable --now podman-auto-update.timer
|
|
||||||
|
|
||||||
# Delete the user (this won't delete their home directory)
|
|
||||||
# userdel might spit out an error like:
|
|
||||||
# userdel: user keycloak is currently used by process 591255
|
|
||||||
# kill those processes and try again
|
|
||||||
userdel keycloak
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
### SELinux
|
|
||||||
|
|
||||||
<https://blog.christophersmart.com/2021/01/31/podman-volumes-and-selinux/>
|
|
||||||
|
|
||||||
:z allows a container to share a mounted volume with all other containers.
|
|
||||||
|
|
||||||
:Z allows a container to reserve a mounted volume and prevents any other container from accessing.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Quadlets
|
|
||||||
|
|
||||||
Put your quadlets here.
|
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
# Make sure to update the credential placeholders with your own secrets.
|
||||||
|
# We mark them with # CHANGEME in the file below.
|
||||||
|
# In addition, we recommend to restrict inbound traffic on the host to langfuse-web (port 3000) and minio (port 9090) only.
|
||||||
|
# All other components are bound to localhost (127.0.0.1) to only accept connections from the local machine.
|
||||||
|
# External connections from other machines will not be able to reach these services directly.
|
||||||
|
services:
|
||||||
|
langfuse-worker:
|
||||||
|
image: docker.io/langfuse/langfuse-worker:3
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:3030:3030
|
||||||
|
environment: &langfuse-worker-env
|
||||||
|
NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000}
|
||||||
|
DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/postgres} # CHANGEME
|
||||||
|
SALT: ${SALT:-mysalt} # CHANGEME
|
||||||
|
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # CHANGEME: generate via `openssl rand -hex 32`
|
||||||
|
TELEMETRY_ENABLED: ${TELEMETRY_ENABLED:-true}
|
||||||
|
LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES: ${LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES:-false}
|
||||||
|
CLICKHOUSE_MIGRATION_URL: ${CLICKHOUSE_MIGRATION_URL:-clickhouse://clickhouse:9000}
|
||||||
|
CLICKHOUSE_URL: ${CLICKHOUSE_URL:-http://clickhouse:8123}
|
||||||
|
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||||
|
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME
|
||||||
|
CLICKHOUSE_CLUSTER_ENABLED: ${CLICKHOUSE_CLUSTER_ENABLED:-false}
|
||||||
|
LANGFUSE_USE_AZURE_BLOB: ${LANGFUSE_USE_AZURE_BLOB:-false}
|
||||||
|
LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE: ${LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE:-false}
|
||||||
|
LANGFUSE_OCI_AUTH_TYPE: ${LANGFUSE_OCI_AUTH_TYPE:-workload_identity}
|
||||||
|
LANGFUSE_S3_EVENT_UPLOAD_BUCKET: ${LANGFUSE_S3_EVENT_UPLOAD_BUCKET:-langfuse}
|
||||||
|
LANGFUSE_S3_EVENT_UPLOAD_REGION: ${LANGFUSE_S3_EVENT_UPLOAD_REGION:-auto}
|
||||||
|
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||||
|
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||||
|
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: ${LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT:-http://minio:9000}
|
||||||
|
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||||
|
LANGFUSE_S3_EVENT_UPLOAD_PREFIX: ${LANGFUSE_S3_EVENT_UPLOAD_PREFIX:-events/}
|
||||||
|
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: ${LANGFUSE_S3_MEDIA_UPLOAD_BUCKET:-langfuse}
|
||||||
|
LANGFUSE_S3_MEDIA_UPLOAD_REGION: ${LANGFUSE_S3_MEDIA_UPLOAD_REGION:-auto}
|
||||||
|
LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio}
|
||||||
|
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||||
|
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: ${LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT:-http://localhost:9090}
|
||||||
|
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true}
|
||||||
|
LANGFUSE_S3_MEDIA_UPLOAD_PREFIX: ${LANGFUSE_S3_MEDIA_UPLOAD_PREFIX:-media/}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_ENABLED: ${LANGFUSE_S3_BATCH_EXPORT_ENABLED:-false}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_BUCKET: ${LANGFUSE_S3_BATCH_EXPORT_BUCKET:-langfuse}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_PREFIX: ${LANGFUSE_S3_BATCH_EXPORT_PREFIX:-exports/}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_REGION: ${LANGFUSE_S3_BATCH_EXPORT_REGION:-auto}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_ENDPOINT: ${LANGFUSE_S3_BATCH_EXPORT_ENDPOINT:-http://minio:9000}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT: ${LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT:-http://localhost:9090}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID: ${LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID:-minio}
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY: ${LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME
|
||||||
|
LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE: ${LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE:-true}
|
||||||
|
LANGFUSE_INGESTION_QUEUE_DELAY_MS: ${LANGFUSE_INGESTION_QUEUE_DELAY_MS:-}
|
||||||
|
LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS: ${LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS:-}
|
||||||
|
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||||
|
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||||
|
REDIS_AUTH: ${REDIS_AUTH:-myredissecret} # CHANGEME
|
||||||
|
REDIS_TLS_ENABLED: ${REDIS_TLS_ENABLED:-false}
|
||||||
|
REDIS_TLS_CA: ${REDIS_TLS_CA:-/certs/ca.crt}
|
||||||
|
REDIS_TLS_CERT: ${REDIS_TLS_CERT:-/certs/redis.crt}
|
||||||
|
REDIS_TLS_KEY: ${REDIS_TLS_KEY:-/certs/redis.key}
|
||||||
|
EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-}
|
||||||
|
SMTP_CONNECTION_URL: ${SMTP_CONNECTION_URL:-}
|
||||||
|
|
||||||
|
langfuse-web:
|
||||||
|
image: docker.io/langfuse/langfuse:3
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
environment:
|
||||||
|
<<: *langfuse-worker-env
|
||||||
|
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:-mysecret} # CHANGEME
|
||||||
|
LANGFUSE_INIT_ORG_ID: ${LANGFUSE_INIT_ORG_ID:-}
|
||||||
|
LANGFUSE_INIT_ORG_NAME: ${LANGFUSE_INIT_ORG_NAME:-}
|
||||||
|
LANGFUSE_INIT_PROJECT_ID: ${LANGFUSE_INIT_PROJECT_ID:-}
|
||||||
|
LANGFUSE_INIT_PROJECT_NAME: ${LANGFUSE_INIT_PROJECT_NAME:-}
|
||||||
|
LANGFUSE_INIT_PROJECT_PUBLIC_KEY: ${LANGFUSE_INIT_PROJECT_PUBLIC_KEY:-}
|
||||||
|
LANGFUSE_INIT_PROJECT_SECRET_KEY: ${LANGFUSE_INIT_PROJECT_SECRET_KEY:-}
|
||||||
|
LANGFUSE_INIT_USER_EMAIL: ${LANGFUSE_INIT_USER_EMAIL:-admin@ducoterra.net}
|
||||||
|
LANGFUSE_INIT_USER_NAME: ${LANGFUSE_INIT_USER_NAME:-admin}
|
||||||
|
LANGFUSE_INIT_USER_PASSWORD: ${LANGFUSE_INIT_USER_PASSWORD:-testpass}
|
||||||
|
|
||||||
|
clickhouse:
|
||||||
|
image: docker.io/clickhouse/clickhouse-server
|
||||||
|
restart: always
|
||||||
|
user: "101:101"
|
||||||
|
environment:
|
||||||
|
CLICKHOUSE_DB: default
|
||||||
|
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-clickhouse}
|
||||||
|
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME
|
||||||
|
volumes:
|
||||||
|
- langfuse_clickhouse_data:/var/lib/clickhouse
|
||||||
|
- langfuse_clickhouse_logs:/var/log/clickhouse-server
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:8123:8123
|
||||||
|
- 127.0.0.1:9000:9000
|
||||||
|
healthcheck:
|
||||||
|
test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 1s
|
||||||
|
|
||||||
|
minio:
|
||||||
|
image: cgr.dev/chainguard/minio
|
||||||
|
restart: always
|
||||||
|
entrypoint: sh
|
||||||
|
# create the 'langfuse' bucket before starting the service
|
||||||
|
command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
|
||||||
|
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniosecret} # CHANGEME
|
||||||
|
ports:
|
||||||
|
- 9090:9000
|
||||||
|
- 127.0.0.1:9091:9001
|
||||||
|
volumes:
|
||||||
|
- langfuse_minio_data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mc", "ready", "local"]
|
||||||
|
interval: 1s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 1s
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: docker.io/redis:7
|
||||||
|
restart: always
|
||||||
|
# CHANGEME: row below to secure redis password
|
||||||
|
command: >
|
||||||
|
--requirepass ${REDIS_AUTH:-myredissecret}
|
||||||
|
--maxmemory-policy noeviction
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:6379:6379
|
||||||
|
volumes:
|
||||||
|
- langfuse_redis_data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 3s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: docker.io/postgres:${POSTGRES_VERSION:-17}
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||||
|
interval: 3s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 10
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} # CHANGEME
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||||
|
TZ: UTC
|
||||||
|
PGTZ: UTC
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:5432:5432
|
||||||
|
volumes:
|
||||||
|
- langfuse_postgres_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
langfuse_postgres_data:
|
||||||
|
driver: local
|
||||||
|
langfuse_clickhouse_data:
|
||||||
|
driver: local
|
||||||
|
langfuse_clickhouse_logs:
|
||||||
|
driver: local
|
||||||
|
langfuse_minio_data:
|
||||||
|
driver: local
|
||||||
|
langfuse_redis_data:
|
||||||
|
driver: local
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
# Podman langfuse
|
||||||
|
|
||||||
|
- [Podman langfuse](#podman-langfuse)
|
||||||
|
- [Setup langfuse Project](#setup-langfuse-project)
|
||||||
|
- [Install langfuse](#install-langfuse)
|
||||||
|
- [Create the langfuse user](#create-the-langfuse-user)
|
||||||
|
- [Write the langfuse compose spec](#write-the-langfuse-compose-spec)
|
||||||
|
- [A Note on Volumes](#a-note-on-volumes)
|
||||||
|
- [Convert langfuse compose spec to quadlets](#convert-langfuse-compose-spec-to-quadlets)
|
||||||
|
- [Create any container-mounted directories](#create-any-container-mounted-directories)
|
||||||
|
- [Start and enable your systemd quadlet](#start-and-enable-your-systemd-quadlet)
|
||||||
|
- [Expose langfuse](#expose-langfuse)
|
||||||
|
- [firewalld](#firewalld)
|
||||||
|
- [Backup langfuse](#backup-langfuse)
|
||||||
|
- [Upgrade langfuse](#upgrade-langfuse)
|
||||||
|
- [Upgrade Quadlets](#upgrade-quadlets)
|
||||||
|
- [Uninstall](#uninstall)
|
||||||
|
- [Notes](#notes)
|
||||||
|
- [SELinux](#selinux)
|
||||||
|
|
||||||
|
## Setup langfuse Project
|
||||||
|
|
||||||
|
- [ ] Copy and rename this folder to active/container_langfuse
|
||||||
|
- [ ] Find and replace langfuse with the name of the service.
|
||||||
|
- [ ] Create the rootless user to run the podman containers
|
||||||
|
- [ ] Write the compose.yaml spec for your service
|
||||||
|
- [ ] Convert the compose.yaml spec to a quadlet
|
||||||
|
- [ ] Install the quadlet on the podman server
|
||||||
|
- [ ] Expose the quadlet service
|
||||||
|
- [ ] Install a backup service and timer
|
||||||
|
|
||||||
|
## Install langfuse
|
||||||
|
|
||||||
|
### Create the langfuse user
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH into your podman server as root
|
||||||
|
useradd langfuse
|
||||||
|
loginctl enable-linger $(id -u langfuse)
|
||||||
|
systemctl --user --machine=langfuse@.host enable podman-restart
|
||||||
|
systemctl --user --machine=langfuse@.host enable --now podman.socket
|
||||||
|
mkdir -p /home/langfuse/.config/containers/systemd
|
||||||
|
```
|
||||||
|
|
||||||
|
### Write the langfuse compose spec
|
||||||
|
|
||||||
|
Edit the compose.yaml at active/container_langfuse/compose/compose.yaml
|
||||||
|
|
||||||
|
#### A Note on Volumes
|
||||||
|
|
||||||
|
Named volumes are stored at `/home/langfuse/.local/share/containers/storage/volumes/`.
|
||||||
|
|
||||||
|
### Convert langfuse compose spec to quadlets
|
||||||
|
|
||||||
|
Run the following to convert a compose.yaml into the various `.container` files for systemd:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate the systemd service
|
||||||
|
podman run \
|
||||||
|
--security-opt label=disable \
|
||||||
|
--rm \
|
||||||
|
-v $(pwd)/active/container_langfuse/compose:/compose \
|
||||||
|
-v $(pwd)/active/container_langfuse/quadlets:/quadlets \
|
||||||
|
quay.io/k9withabone/podlet \
|
||||||
|
-f /quadlets \
|
||||||
|
-i \
|
||||||
|
--overwrite \
|
||||||
|
compose /compose/compose.yaml
|
||||||
|
|
||||||
|
# Copy the files to the server
|
||||||
|
export PODMAN_SERVER=
|
||||||
|
scp -r active/container_langfuse/quadlets/. $PODMAN_SERVER:/home/langfuse/.config/containers/systemd/
|
||||||
|
ssh $PODMAN_SERVER chown -R langfuse:langfuse /home/langfuse/.config/containers/systemd/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create any container-mounted directories
|
||||||
|
|
||||||
|
SSH into your podman server as root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
machinectl shell langfuse@
|
||||||
|
podman unshare
|
||||||
|
mkdir some_volume
|
||||||
|
# Chown to the namespaced user with UID 1000
|
||||||
|
# This will be some really obscure UID outside the namespace
|
||||||
|
# This will also solve most permission denied errors
|
||||||
|
chown -R 1000:1000 some_volume
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start and enable your systemd quadlet
|
||||||
|
|
||||||
|
SSH into your podman server as root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
machinectl shell langfuse@
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user restart langfuse
|
||||||
|
# Enable auto-update service which will pull new container images automatically every day
|
||||||
|
systemctl --user enable --now podman-auto-update.timer
|
||||||
|
```
|
||||||
|
|
||||||
|
### Expose langfuse
|
||||||
|
|
||||||
|
1. If you need a domain, follow the [DDNS instructions](/active/container_ddns/ddns.md#install-a-new-ddns-service)
|
||||||
|
2. For a web service, follow the [Caddy instructions](/active/container_caddy/caddy.md#adding-a-new-caddy-record)
|
||||||
|
3. Finally, follow your OS's guide for opening ports via its firewall service.
|
||||||
|
|
||||||
|
#### firewalld
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# command to get current active zone and default zone
|
||||||
|
firewall-cmd --get-active-zones
|
||||||
|
firewall-cmd --get-default-zone
|
||||||
|
|
||||||
|
# command to open 443 on tcp
|
||||||
|
firewall-cmd --permanent --zone=<zone> --add-port=443/tcp
|
||||||
|
|
||||||
|
# command to open 80 and 443 on tcp and udp
|
||||||
|
firewall-cmd --permanent --zone=<zone> --add-port={80,443}/{tcp,udp}
|
||||||
|
|
||||||
|
# command to list available services and then open http and https
|
||||||
|
firewall-cmd --get-services
|
||||||
|
firewall-cmd --permanent --zone=<zone> --add-service={http,https}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backup langfuse
|
||||||
|
|
||||||
|
Follow the [Borg Backup instructions](/active/systemd_borg/borg.md#set-up-a-client-for-backup)
|
||||||
|
|
||||||
|
## Upgrade langfuse
|
||||||
|
|
||||||
|
### Upgrade Quadlets
|
||||||
|
|
||||||
|
Upgrades should be a repeat of [writing the compose spec](#convert-langfuse-compose-spec-to-quadlets) and [installing the quadlets](#start-and-enable-your-systemd-quadlet)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export PODMAN_SERVER=
|
||||||
|
scp -r quadlets/. $PODMAN_SERVER$:/home/langfuse/.config/containers/systemd/
|
||||||
|
ssh langfuse systemctl --user daemon-reload
|
||||||
|
ssh langfuse systemctl --user restart langfuse
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stop the user's services
|
||||||
|
systemctl --user disable podman-restart
|
||||||
|
podman container stop --all
|
||||||
|
systemctl --user disable --now podman.socket
|
||||||
|
systemctl --user disable --now podman-auto-update.timer
|
||||||
|
|
||||||
|
# Delete the user (this won't delete their home directory)
|
||||||
|
# userdel might spit out an error like:
|
||||||
|
# userdel: user langfuse is currently used by process 591255
|
||||||
|
# kill those processes and try again
|
||||||
|
userdel langfuse
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
### SELinux
|
||||||
|
|
||||||
|
<https://blog.christophersmart.com/2021/01/31/podman-volumes-and-selinux/>
|
||||||
|
|
||||||
|
:z allows a container to share a mounted volume with all other containers.
|
||||||
|
|
||||||
|
:Z allows a container to reserve a mounted volume and prevents any other container from accessing.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
[Container]
|
||||||
|
Pod=langfuse.pod
|
||||||
|
ContainerName=langfuse-clickhouse
|
||||||
|
Environment=CLICKHOUSE_DB=default
|
||||||
|
Environment=CLICKHOUSE_USER=clickhouse
|
||||||
|
Environment=CLICKHOUSE_PASSWORD=clickhouse
|
||||||
|
User=101:101
|
||||||
|
Image=docker.io/clickhouse/clickhouse-server
|
||||||
|
Volume=langfuse-clickhouse_data.volume:/var/lib/clickhouse
|
||||||
|
Volume=langfuse-clickhouse_logs.volume:/var/log/clickhouse-server
|
||||||
|
HealthCmd=wget --no-verbose --tries=1 --spider http://localhost:8123/ping
|
||||||
|
HealthInterval=5s
|
||||||
|
HealthTimeout=5s
|
||||||
|
HealthRetries=10
|
||||||
|
HealthStartPeriod=1s
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[Volume]
|
||||||
|
VolumeName=langfuse_clickhouse_data
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[Volume]
|
||||||
|
VolumeName=langfuse_clickhouse_logs
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[Container]
|
||||||
|
Pod=langfuse.pod
|
||||||
|
ContainerName=langfuse-minio
|
||||||
|
Environment=MINIO_ROOT_USER=minio
|
||||||
|
Environment=MINIO_ROOT_PASSWORD=miniosecret
|
||||||
|
Image=cgr.dev/chainguard/minio
|
||||||
|
Volume=langfuse-minio_data.volume:/data
|
||||||
|
Entrypoint=sh
|
||||||
|
Exec=-c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data'
|
||||||
|
HealthCmd=mc ready local
|
||||||
|
HealthInterval=1s
|
||||||
|
HealthTimeout=5s
|
||||||
|
HealthRetries=5
|
||||||
|
HealthStartPeriod=1s
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[Volume]
|
||||||
|
VolumeName=langfuse_minio_data
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[Container]
|
||||||
|
Pod=langfuse.pod
|
||||||
|
ContainerName=langfuse-postgres
|
||||||
|
Environment=POSTGRES_USER=postgres
|
||||||
|
Environment=POSTGRES_PASSWORD=postgres
|
||||||
|
Environment=POSTGRES_DB=postgres
|
||||||
|
Environment=TZ=UTC
|
||||||
|
Environment=PGTZ=UTC
|
||||||
|
Image=docker.io/postgres:17
|
||||||
|
Volume=langfuse-postgres_data.volume:/var/lib/postgresql/data
|
||||||
|
HealthCmd=pg_isready -U postgres
|
||||||
|
HealthInterval=3s
|
||||||
|
HealthTimeout=3s
|
||||||
|
HealthRetries=10
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[Volume]
|
||||||
|
VolumeName=langfuse_postgres_data
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[Container]
|
||||||
|
Pod=langfuse.pod
|
||||||
|
ContainerName=langfuse-redis
|
||||||
|
Environment=REDIS_AUTH=myredissecret
|
||||||
|
Image=docker.io/redis:7
|
||||||
|
Volume=langfuse-redis_data.volume:/data
|
||||||
|
Exec=--requirepass myredissecret --maxmemory-policy noeviction
|
||||||
|
HealthCmd=redis-cli ping
|
||||||
|
HealthInterval=3s
|
||||||
|
HealthTimeout=10s
|
||||||
|
HealthRetries=10
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[Volume]
|
||||||
|
VolumeName=langfuse_redis_data
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
[Unit]
|
||||||
|
Requires=langfuse-postgres.service langfuse-clickhouse.service langfuse-redis.service langfuse-minio.service
|
||||||
|
|
||||||
|
[Container]
|
||||||
|
Pod=langfuse.pod
|
||||||
|
ContainerName=langfuse-web
|
||||||
|
Environment=NEXTAUTH_URL=http://localhost:3000
|
||||||
|
Environment=DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
|
||||||
|
Environment=SALT=mysalt
|
||||||
|
Environment=ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
Environment=TELEMETRY_ENABLED=true
|
||||||
|
Environment=LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES=false
|
||||||
|
Environment=CLICKHOUSE_MIGRATION_URL=clickhouse://localhost:9000
|
||||||
|
Environment=CLICKHOUSE_URL=http://localhost:8123
|
||||||
|
Environment=CLICKHOUSE_USER=clickhouse
|
||||||
|
Environment=CLICKHOUSE_PASSWORD=clickhouse
|
||||||
|
Environment=CLICKHOUSE_CLUSTER_ENABLED=false
|
||||||
|
Environment=LANGFUSE_USE_AZURE_BLOB=false
|
||||||
|
Environment=LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE=false
|
||||||
|
Environment=LANGFUSE_OCI_AUTH_TYPE=workload_identity
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_BUCKET=langfuse
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_REGION=auto
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=minio
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=http://localhost:9000
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_PREFIX=events/
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_BUCKET=langfuse
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_REGION=auto
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID=minio
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_PREFIX=media/
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_ENABLED=false
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_BUCKET=langfuse
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_PREFIX=exports/
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_REGION=auto
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_ENDPOINT=http://localhost:9000
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT=http://localhost:9090
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID=minio
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=miniosecret
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||||
|
Environment=LANGFUSE_INGESTION_QUEUE_DELAY_MS=
|
||||||
|
Environment=LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=
|
||||||
|
Environment=REDIS_HOST=localhost
|
||||||
|
Environment=REDIS_PORT=6379
|
||||||
|
Environment=REDIS_AUTH=myredissecret
|
||||||
|
Environment=REDIS_TLS_ENABLED=false
|
||||||
|
Environment=REDIS_TLS_CA=/certs/ca.crt
|
||||||
|
Environment=REDIS_TLS_CERT=/certs/redis.crt
|
||||||
|
Environment=REDIS_TLS_KEY=/certs/redis.key
|
||||||
|
Environment=EMAIL_FROM_ADDRESS=
|
||||||
|
Environment=SMTP_CONNECTION_URL=
|
||||||
|
Environment=NEXTAUTH_SECRET=mysecret
|
||||||
|
Environment=LANGFUSE_INIT_ORG_ID=
|
||||||
|
Environment=LANGFUSE_INIT_ORG_NAME=
|
||||||
|
Environment=LANGFUSE_INIT_PROJECT_ID=
|
||||||
|
Environment=LANGFUSE_INIT_PROJECT_NAME=
|
||||||
|
Environment=LANGFUSE_INIT_PROJECT_PUBLIC_KEY=
|
||||||
|
Environment=LANGFUSE_INIT_PROJECT_SECRET_KEY=
|
||||||
|
Environment=LANGFUSE_INIT_USER_EMAIL=admin@ducoterra.net
|
||||||
|
Environment=LANGFUSE_INIT_USER_NAME=admin
|
||||||
|
Environment=LANGFUSE_INIT_USER_PASSWORD=testpass
|
||||||
|
Image=docker.io/langfuse/langfuse:3
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
[Unit]
|
||||||
|
Requires=langfuse-postgres.service langfuse-clickhouse.service langfuse-redis.service langfuse-minio.service
|
||||||
|
|
||||||
|
[Container]
|
||||||
|
Pod=langfuse.pod
|
||||||
|
ContainerName=langfuse-worker
|
||||||
|
Environment=NEXTAUTH_URL=http://localhost:3000
|
||||||
|
Environment=DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
|
||||||
|
Environment=SALT=mysalt
|
||||||
|
Environment=ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
Environment=TELEMETRY_ENABLED=true
|
||||||
|
Environment=LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES=false
|
||||||
|
Environment=CLICKHOUSE_MIGRATION_URL=clickhouse://localhost:9000
|
||||||
|
Environment=CLICKHOUSE_URL=http://localhost:8123
|
||||||
|
Environment=CLICKHOUSE_USER=clickhouse
|
||||||
|
Environment=CLICKHOUSE_PASSWORD=clickhouse
|
||||||
|
Environment=CLICKHOUSE_CLUSTER_ENABLED=false
|
||||||
|
Environment=LANGFUSE_USE_AZURE_BLOB=false
|
||||||
|
Environment=LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE=false
|
||||||
|
Environment=LANGFUSE_OCI_AUTH_TYPE=workload_identity
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_BUCKET=langfuse
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_REGION=auto
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID=minio
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT=http://localhost:9000
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE=true
|
||||||
|
Environment=LANGFUSE_S3_EVENT_UPLOAD_PREFIX=events/
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_BUCKET=langfuse
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_REGION=auto
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID=minio
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=miniosecret
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE=true
|
||||||
|
Environment=LANGFUSE_S3_MEDIA_UPLOAD_PREFIX=media/
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_ENABLED=false
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_BUCKET=langfuse
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_PREFIX=exports/
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_REGION=auto
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_ENDPOINT=http://localhost:9000
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT=http://localhost:9090
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID=minio
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=miniosecret
|
||||||
|
Environment=LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE=true
|
||||||
|
Environment=LANGFUSE_INGESTION_QUEUE_DELAY_MS=
|
||||||
|
Environment=LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=
|
||||||
|
Environment=REDIS_HOST=localhost
|
||||||
|
Environment=REDIS_PORT=6379
|
||||||
|
Environment=REDIS_AUTH=myredissecret
|
||||||
|
Environment=REDIS_TLS_ENABLED=false
|
||||||
|
Environment=REDIS_TLS_CA=/certs/ca.crt
|
||||||
|
Environment=REDIS_TLS_CERT=/certs/redis.crt
|
||||||
|
Environment=REDIS_TLS_KEY=/certs/redis.key
|
||||||
|
Environment=EMAIL_FROM_ADDRESS=
|
||||||
|
Environment=SMTP_CONNECTION_URL=
|
||||||
|
Image=docker.io/langfuse/langfuse-worker:3
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[Pod]
|
||||||
|
PublishPort=3000:3000/tcp
|
||||||
|
PublishPort=127.0.0.1:3030:3030/tcp
|
||||||
|
PublishPort=127.0.0.1:8123:8123/tcp
|
||||||
|
PublishPort=127.0.0.1:9000:9000/tcp
|
||||||
|
PublishPort=9090:9000/tcp
|
||||||
|
PublishPort=127.0.0.1:9091:9001/tcp
|
||||||
|
PublishPort=127.0.0.1:6379:6379/tcp
|
||||||
|
PublishPort=127.0.0.1:5432:5432/tcp
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -11,7 +11,7 @@ HealthInterval=30s
|
|||||||
HealthRetries=3
|
HealthRetries=3
|
||||||
HealthStartPeriod=40s
|
HealthStartPeriod=40s
|
||||||
HealthTimeout=10s
|
HealthTimeout=10s
|
||||||
Image=ghcr.io/berriai/litellm-database:v1.83.14-stable.patch.3
|
Image=ghcr.io/berriai/litellm-database:main-stable
|
||||||
Volume=/home/ai/litellm-config.yaml:/app/config.yaml:z
|
Volume=/home/ai/litellm-config.yaml:/app/config.yaml:z
|
||||||
Exec=--config=/app/config.yaml
|
Exec=--config=/app/config.yaml
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# NTFY
|
||||||
|
|
||||||
|
## Running ntfy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
podman run \
|
||||||
|
-v ntfy:/var/cache/ntfy \
|
||||||
|
-v ./active/container_ntfy/server.yml:/etc/ntfy/server.yml:z \
|
||||||
|
-p 8001:80 \
|
||||||
|
-it \
|
||||||
|
docker.io/binwiederhier/ntfy:latest \
|
||||||
|
serve \
|
||||||
|
--cache-file /var/cache/ntfy/cache.db
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing with Curl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Publish a topic
|
||||||
|
curl -d "Backup successful" localhost:8001/mytopic
|
||||||
|
|
||||||
|
# Listen on a topic
|
||||||
|
curl -s localhost:8001/mytopic
|
||||||
|
```
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# base-url:
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"type": "micro",
|
||||||
|
"wake_word": "Alexa",
|
||||||
|
"author": "Kevin Ahrendt",
|
||||||
|
"website": "https://www.kevinahrendt.com/",
|
||||||
|
"model": "alexa.tflite",
|
||||||
|
"trained_languages": ["en"],
|
||||||
|
"version": 2,
|
||||||
|
"micro": {
|
||||||
|
"probability_cutoff": 0.9,
|
||||||
|
"sliding_window_size": 5,
|
||||||
|
"feature_step_size": 10,
|
||||||
|
"tensor_arena_size": 22348,
|
||||||
|
"minimum_esphome_version": "2024.7.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1,9 +1,12 @@
|
|||||||
esphome:
|
esphome:
|
||||||
name: tab2
|
name: dickhead
|
||||||
friendly_name: M5Stack Tab5 2
|
friendly_name: Dickhead
|
||||||
on_boot:
|
on_boot:
|
||||||
# Set the charing icon to the correct state on boot
|
# Set the charging icon to the correct state on boot
|
||||||
- then:
|
- then:
|
||||||
|
- logger.log: "Delaying backlight initialization"
|
||||||
|
- delay: 2s
|
||||||
|
- logger.log: "End delay"
|
||||||
- if:
|
- if:
|
||||||
condition:
|
condition:
|
||||||
lambda: return id(charging).state;
|
lambda: return id(charging).state;
|
||||||
@@ -17,6 +20,7 @@ esphome:
|
|||||||
esp32:
|
esp32:
|
||||||
board: esp32-p4-evboard
|
board: esp32-p4-evboard
|
||||||
flash_size: 16MB
|
flash_size: 16MB
|
||||||
|
cpu_frequency: 360MHz
|
||||||
framework:
|
framework:
|
||||||
type: esp-idf
|
type: esp-idf
|
||||||
advanced:
|
advanced:
|
||||||
@@ -36,6 +40,7 @@ esp32_hosted:
|
|||||||
|
|
||||||
logger:
|
logger:
|
||||||
hardware_uart: USB_SERIAL_JTAG
|
hardware_uart: USB_SERIAL_JTAG
|
||||||
|
level: DEBUG
|
||||||
|
|
||||||
psram:
|
psram:
|
||||||
mode: hex
|
mode: hex
|
||||||
@@ -53,8 +58,8 @@ ota:
|
|||||||
platform: esphome
|
platform: esphome
|
||||||
|
|
||||||
wifi:
|
wifi:
|
||||||
ssid: !secret wifi_ssid
|
ssid: !secret mobile_wifi_ssid
|
||||||
password: !secret wifi_password
|
password: !secret mobile_wifi_pass
|
||||||
fast_connect: true
|
fast_connect: true
|
||||||
on_connect:
|
on_connect:
|
||||||
- lvgl.label.update:
|
- lvgl.label.update:
|
||||||
@@ -63,15 +68,50 @@ wifi:
|
|||||||
- select.set:
|
- select.set:
|
||||||
id: dac_output
|
id: dac_output
|
||||||
option: "LINE1"
|
option: "LINE1"
|
||||||
|
- lvgl.label.update:
|
||||||
|
id: lbl_ip
|
||||||
|
text: !lambda return id(ip_addr).state;
|
||||||
|
- lvgl.label.update:
|
||||||
|
id: lbl_ap
|
||||||
|
text: !lambda return id(ssid).state;
|
||||||
on_disconnect:
|
on_disconnect:
|
||||||
- lvgl.label.update:
|
- lvgl.label.update:
|
||||||
id: lbl_status
|
id: lbl_status
|
||||||
text: "DISCONNECTED"
|
text: "DISCONNECTED"
|
||||||
# ap:
|
ap:
|
||||||
# password: !secret hotspot_password
|
password: !secret hotspot_password
|
||||||
# ap_timeout: 90s
|
ap_timeout: 30s
|
||||||
|
|
||||||
# captive_portal:
|
captive_portal:
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: wifi_info
|
||||||
|
ip_address:
|
||||||
|
id: ip_addr
|
||||||
|
name: Device IP Address
|
||||||
|
address_0:
|
||||||
|
name: Device IP Address 0
|
||||||
|
address_1:
|
||||||
|
name: Device IP Address 1
|
||||||
|
address_2:
|
||||||
|
name: Device IP Address 2
|
||||||
|
address_3:
|
||||||
|
name: Device IP Address 3
|
||||||
|
address_4:
|
||||||
|
name: Device IP Address 4
|
||||||
|
ssid:
|
||||||
|
id: ssid
|
||||||
|
name: Device Connected SSID
|
||||||
|
bssid:
|
||||||
|
name: Device Connected BSSID
|
||||||
|
mac_address:
|
||||||
|
name: Device Mac Wifi Address
|
||||||
|
scan_results:
|
||||||
|
name: Device Latest Scan Results
|
||||||
|
dns_address:
|
||||||
|
name: Device DNS Address
|
||||||
|
power_save_mode:
|
||||||
|
name: Device Wifi Power Save Mode
|
||||||
|
|
||||||
time:
|
time:
|
||||||
- platform: sntp
|
- platform: sntp
|
||||||
@@ -82,14 +122,13 @@ time:
|
|||||||
- 1.pool.ntp.org
|
- 1.pool.ntp.org
|
||||||
- 2.pool.ntp.org
|
- 2.pool.ntp.org
|
||||||
|
|
||||||
# wireguard:
|
wireguard:
|
||||||
# address: !secret tab1_wg_ip
|
address: !secret tab1_wg_ip
|
||||||
# private_key: !secret tab1_wg_pk
|
private_key: !secret tab1_wg_pk
|
||||||
# peer_endpoint: !secret wg_host
|
peer_endpoint: !secret wg_host
|
||||||
# peer_public_key: !secret wg_pubkey
|
peer_public_key: !secret wg_pubkey
|
||||||
|
netmask: 0.0.0.0
|
||||||
# # Optional keepalive (disabled by default)
|
peer_persistent_keepalive: 25s
|
||||||
# peer_persistent_keepalive: 25s
|
|
||||||
|
|
||||||
i2c:
|
i2c:
|
||||||
- id: bsp_bus
|
- id: bsp_bus
|
||||||
@@ -196,6 +235,39 @@ binary_sensor:
|
|||||||
pin:
|
pin:
|
||||||
pi4ioe5v6408: pi4ioe1
|
pi4ioe5v6408: pi4ioe1
|
||||||
number: 7
|
number: 7
|
||||||
|
- platform: lvgl
|
||||||
|
widget: volume_up_widget
|
||||||
|
name: Volume Up Button
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- logger.log: "Button pressed"
|
||||||
|
- media_player.volume_up:
|
||||||
|
id: tab5_media_player
|
||||||
|
- delay: 100ms
|
||||||
|
- lvgl.label.update:
|
||||||
|
id: lbl_volume
|
||||||
|
text: !lambda return to_string(int(id(tab5_media_player).volume * 100));
|
||||||
|
- light.turn_on:
|
||||||
|
id: backlight
|
||||||
|
brightness: !lambda |-
|
||||||
|
float current_value = id(backlight).current_values.get_brightness();
|
||||||
|
return current_value < 0.6 ? 0.6 : current_value + 0.2;
|
||||||
|
- platform: lvgl
|
||||||
|
widget: volume_down_widget
|
||||||
|
name: Volume Down Button
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- logger.log: "Button pressed"
|
||||||
|
- media_player.volume_down:
|
||||||
|
id: tab5_media_player
|
||||||
|
- lvgl.label.update:
|
||||||
|
id: lbl_volume
|
||||||
|
text: !lambda return to_string(int(id(tab5_media_player).volume * 100));
|
||||||
|
- light.turn_on:
|
||||||
|
id: backlight
|
||||||
|
brightness: !lambda |-
|
||||||
|
float current_value = id(backlight).current_values.get_brightness();
|
||||||
|
return current_value < 0.6 ? 0.6 : current_value - 0.2;
|
||||||
|
|
||||||
sensor:
|
sensor:
|
||||||
- platform: ina226
|
- platform: ina226
|
||||||
@@ -255,8 +327,8 @@ touchscreen:
|
|||||||
- logger.log: "LVGL resuming"
|
- logger.log: "LVGL resuming"
|
||||||
- lvgl.resume:
|
- lvgl.resume:
|
||||||
- light.turn_on: backlight
|
- light.turn_on: backlight
|
||||||
on_release:
|
# on_release:
|
||||||
- media_player.stop:
|
# - media_player.stop:
|
||||||
|
|
||||||
esp_ldo:
|
esp_ldo:
|
||||||
- voltage: 2.5V
|
- voltage: 2.5V
|
||||||
@@ -287,7 +359,7 @@ light:
|
|||||||
restore_mode: ALWAYS_ON
|
restore_mode: ALWAYS_ON
|
||||||
default_transition_length: 250ms
|
default_transition_length: 250ms
|
||||||
initial_state:
|
initial_state:
|
||||||
brightness: "100%"
|
brightness: "50%"
|
||||||
|
|
||||||
image:
|
image:
|
||||||
defaults:
|
defaults:
|
||||||
@@ -318,20 +390,41 @@ lvgl:
|
|||||||
transition_length: 15s
|
transition_length: 15s
|
||||||
- lvgl.pause:
|
- lvgl.pause:
|
||||||
widgets:
|
widgets:
|
||||||
|
- obj:
|
||||||
|
align: TOP_MID
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
layout:
|
||||||
|
type: flex
|
||||||
|
flex_flow: column
|
||||||
|
flex_align_main: START
|
||||||
|
flex_align_track: center
|
||||||
|
flex_align_cross: center
|
||||||
|
widgets:
|
||||||
|
- label:
|
||||||
|
align: TOP_MID
|
||||||
|
id: lbl_status
|
||||||
|
text_font: montserrat_48
|
||||||
|
text: "CONNECTING..."
|
||||||
|
- label:
|
||||||
|
align: TOP_MID
|
||||||
|
id: lbl_ap
|
||||||
|
text_font: montserrat_22
|
||||||
|
text: "CONNECTING..."
|
||||||
|
- label:
|
||||||
|
align: TOP_MID
|
||||||
|
id: lbl_ip
|
||||||
|
text_font: montserrat_22
|
||||||
|
text: "CONNECTING..."
|
||||||
- image:
|
- image:
|
||||||
id: listen_icon_widget
|
id: listen_icon_widget
|
||||||
src: va_idle
|
src: va_idle
|
||||||
align: CENTER
|
align: CENTER
|
||||||
- label:
|
|
||||||
align: TOP_MID
|
|
||||||
id: lbl_status
|
|
||||||
text_font: montserrat_48
|
|
||||||
text: "CONNECTING..."
|
|
||||||
- label:
|
- label:
|
||||||
align: BOTTOM_LEFT
|
align: BOTTOM_LEFT
|
||||||
id: lbl_version
|
id: lbl_version
|
||||||
text_font: montserrat_12
|
text_font: montserrat_12
|
||||||
text: "v0.5"
|
text: "v0.6"
|
||||||
- label:
|
- label:
|
||||||
align: BOTTOM_RIGHT
|
align: BOTTOM_RIGHT
|
||||||
id: lbl_battery
|
id: lbl_battery
|
||||||
@@ -341,21 +434,38 @@ lvgl:
|
|||||||
id: charging_icon_widget
|
id: charging_icon_widget
|
||||||
src: charging_icon
|
src: charging_icon
|
||||||
align: TOP_RIGHT
|
align: TOP_RIGHT
|
||||||
- slider:
|
- button:
|
||||||
id: backlight_slider
|
id: volume_up_widget
|
||||||
|
widgets:
|
||||||
|
- label:
|
||||||
|
text: "\uF028"
|
||||||
|
text_font: montserrat_48
|
||||||
|
text_align: CENTER
|
||||||
|
align: CENTER
|
||||||
x: 20
|
x: 20
|
||||||
y: 50
|
y: 20
|
||||||
width: 30
|
width: 100
|
||||||
height: 220
|
height: 100
|
||||||
pad_all: 8
|
pad_all: 8
|
||||||
min_value: 0
|
- button:
|
||||||
max_value: 255
|
id: volume_down_widget
|
||||||
on_release:
|
widgets:
|
||||||
- homeassistant.action:
|
- label:
|
||||||
action: light.turn_on
|
text: "\uF027"
|
||||||
data:
|
text_font: montserrat_48
|
||||||
entity_id: light.backlight
|
text_align: CENTER
|
||||||
brightness: !lambda return int(x);
|
align: CENTER
|
||||||
|
x: 20
|
||||||
|
y: 140
|
||||||
|
width: 100
|
||||||
|
height: 100
|
||||||
|
pad_all: 8
|
||||||
|
- label:
|
||||||
|
x: 20
|
||||||
|
y: 260
|
||||||
|
id: lbl_volume
|
||||||
|
text_font: montserrat_28
|
||||||
|
text: !lambda return "%.1f",to_string(id(tab5_media_player).volume);
|
||||||
|
|
||||||
# The DAC Output select needs to be manually (or with an automation) changed to `LINE1` for the onboard speaker
|
# The DAC Output select needs to be manually (or with an automation) changed to `LINE1` for the onboard speaker
|
||||||
select:
|
select:
|
||||||
@@ -414,7 +524,7 @@ speaker:
|
|||||||
audio_dac: es8388_dac
|
audio_dac: es8388_dac
|
||||||
dac_type: external
|
dac_type: external
|
||||||
channel: mono
|
channel: mono
|
||||||
buffer_duration: 100ms
|
buffer_duration: 60000ms
|
||||||
bits_per_sample: 16bit
|
bits_per_sample: 16bit
|
||||||
sample_rate: 48000
|
sample_rate: 48000
|
||||||
|
|
||||||
@@ -429,9 +539,12 @@ media_player:
|
|||||||
micro_wake_word:
|
micro_wake_word:
|
||||||
id: mww
|
id: mww
|
||||||
models:
|
models:
|
||||||
- okay_nabu
|
- model:
|
||||||
- hey_mycroft
|
type: local
|
||||||
- hey_jarvis
|
path: alexa.json
|
||||||
|
id: alexa
|
||||||
|
probability_cutoff: 0.97
|
||||||
|
sliding_window_size: 5
|
||||||
on_wake_word_detected:
|
on_wake_word_detected:
|
||||||
- voice_assistant.start:
|
- voice_assistant.start:
|
||||||
wake_word: !lambda return wake_word;
|
wake_word: !lambda return wake_word;
|
||||||
@@ -56,6 +56,13 @@ Make sure your permissions are set correctly
|
|||||||
sudo usermod -a -G dialout ducoterra
|
sudo usermod -a -G dialout ducoterra
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or on Kinoite
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -E '^dialout:' /usr/lib/group | sudo tee -a /etc/group
|
||||||
|
sudo usermod -aG dialout $USER
|
||||||
|
```
|
||||||
|
|
||||||
Then "run" your config file
|
Then "run" your config file
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"type": "micro",
|
||||||
|
"wake_word": "hey dick head",
|
||||||
|
"author": "peenfart",
|
||||||
|
"website": "https://www.kevinahrendt.com/",
|
||||||
|
"model": "./hey_dick_head.tflite",
|
||||||
|
"trained_languages": ["en"],
|
||||||
|
"version": 2,
|
||||||
|
"micro": {
|
||||||
|
"probability_cutoff": 0.97,
|
||||||
|
"sliding_window_size": 5,
|
||||||
|
"feature_step_size": 10,
|
||||||
|
"tensor_arena_size": 22860,
|
||||||
|
"minimum_esphome_version": "2024.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Submodule
+1
Submodule active/device_home_assistant/config added at 5a3ce1da52
@@ -0,0 +1,48 @@
|
|||||||
|
# Reese's Workstation
|
||||||
|
|
||||||
|
- [Reese's Workstation](#reeses-workstation)
|
||||||
|
- [Virtual Machines](#virtual-machines)
|
||||||
|
|
||||||
|
## Virtual Machines
|
||||||
|
|
||||||
|
1. Blueprints are stored in active/software_osbuild
|
||||||
|
2. Builds are stored in ${HOME}/Images/builds
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# These are saved in ~/.bashrc.d/osbuild.sh
|
||||||
|
export OSBUILD_BLUEPRINT_DIR=active/software_osbuild
|
||||||
|
export OSBUILD_CLOUD_DIR=${HOME}/Images/cloud
|
||||||
|
export OSBUILD_BUILD_DIR=${HOME}/Images/builds
|
||||||
|
export OSBUILD_IMAGE_DIR=${HOME}/Images/disks
|
||||||
|
|
||||||
|
# Push a blueprint
|
||||||
|
composer-cli blueprints push ${OSBUILD_BLUEPRINT_DIR}/fedora43-base.toml
|
||||||
|
|
||||||
|
# Start a build
|
||||||
|
composer-cli compose start fedora43-base qcow2
|
||||||
|
|
||||||
|
# Watch the build
|
||||||
|
watch composer-cli compose list running
|
||||||
|
|
||||||
|
# Extract the build
|
||||||
|
composer-cli compose image \
|
||||||
|
--filename ${OSBUILD_BUILD_DIR}/fedora-43-base.qcow2 \
|
||||||
|
92a2f1dd-9238-4d50-ab1d-cd7c8e355cac
|
||||||
|
|
||||||
|
# Convert the build to raw
|
||||||
|
qemu-img convert -f qcow2 -O raw \
|
||||||
|
${OSBUILD_BUILD_DIR}/fedora-43-base.qcow2 \
|
||||||
|
${OSBUILD_IMAGE_DIR}/fedora-boot.raw
|
||||||
|
|
||||||
|
# Install (Change password for default user ducoterra!)
|
||||||
|
virt-install \
|
||||||
|
--boot uefi,firmware.feature0.name=secure-boot,firmware.feature0.enabled=no \
|
||||||
|
--cpu host-passthrough --vcpus sockets=1,cores=8,threads=2 \
|
||||||
|
--ram=8192 \
|
||||||
|
--os-variant=fedora43 \
|
||||||
|
--network default \
|
||||||
|
--graphics none \
|
||||||
|
--console pty,target.type=virtio \
|
||||||
|
--name "fedora" \
|
||||||
|
--import --disk "path=${OSBUILD_IMAGE_DIR}/fedora-boot.raw,bus=virtio"
|
||||||
|
```
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# KDE Notes
|
||||||
|
|
||||||
|
## Fixing alt tab or taskbar icons
|
||||||
|
|
||||||
|
1. System Settings - Window Management - Window Rules - Add New...
|
||||||
|
2. Bring the buggy app window side-by-side with system settings.
|
||||||
|
3. Click "Detect Window Properties..." in the bottom.
|
||||||
|
4. Move the crosshair to the buggy window and click.
|
||||||
|
5. Click "Window class (application)".
|
||||||
|
6. Click "Add Property..." in the bottm left.
|
||||||
|
7. Click "Desktop file name".
|
||||||
|
8. Enter the base name of the desktop file
|
||||||
|
|
||||||
|
For flatpak, check `/var/lib/flatpak/exports/share/applications/`
|
||||||
|
|
||||||
|
For system apps, check `/usr/share/applications/`
|
||||||
|
|
||||||
|
For user apps, check `~/.local/share/applications/`
|
||||||
|
|
||||||
|
9. Click "Apply".
|
||||||
|
10. The icon should be fixed immediately.
|
||||||
|
|
||||||
|
## KDE Connect
|
||||||
|
|
||||||
|
Allow KDE Connect via 1714-1764 tcp/udp
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set source address to allow connections
|
||||||
|
sudo firewall-cmd \
|
||||||
|
--zone=drop \
|
||||||
|
--permanent \
|
||||||
|
--add-port=1714-1764/udp \
|
||||||
|
--add-port=1714-1764/tcp
|
||||||
|
|
||||||
|
sudo firewall-cmd --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatic Display Switching
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List displays
|
||||||
|
# Builtin: eDP-2
|
||||||
|
# Roku: DP-13
|
||||||
|
# Lenovo: DP-11
|
||||||
|
kscreen-doctor -o
|
||||||
|
|
||||||
|
# Put the builtin display back to normal
|
||||||
|
kscreen-doctor \
|
||||||
|
output.eDP-2.enable \
|
||||||
|
output.eDP-2.position.0,0 \
|
||||||
|
output.eDP-2.primary \
|
||||||
|
output.eDP-2.mode.2560x1600@165 \
|
||||||
|
output.eDP-2.scale.1.25
|
||||||
|
|
||||||
|
# Show on Roku TV and Monitor
|
||||||
|
kscreen-doctor \
|
||||||
|
output.DP-11.enable \
|
||||||
|
output.DP-11.position.0,0 \
|
||||||
|
output.DP-11.mode.2560x1440@60 \
|
||||||
|
output.DP-11.scale.1 \
|
||||||
|
output.DP-13.enable \
|
||||||
|
output.DP-13.position.0,0 \
|
||||||
|
output.DP-13.mode.2560x1440@100 \
|
||||||
|
output.DP-13.scale.1 \
|
||||||
|
output.DP-13.primary \
|
||||||
|
output.eDP-2.disable
|
||||||
|
|
||||||
|
# Show only on the roku TV
|
||||||
|
kscreen-doctor \
|
||||||
|
output.DP-11.enable \
|
||||||
|
output.DP-11.position.0,0 \
|
||||||
|
output.DP-11.primary \
|
||||||
|
output.DP-11.mode.3840x2160@60 \
|
||||||
|
output.DP-11.scale.2 \
|
||||||
|
output.DP-13.disable \
|
||||||
|
output.eDP-2.disable
|
||||||
|
|
||||||
|
# Mirror the builtin display to the roku tv
|
||||||
|
kscreen-doctor \
|
||||||
|
output.DP-11.enable \
|
||||||
|
output.DP-11.position.0,0 \
|
||||||
|
output.DP-11.primary \
|
||||||
|
output.DP-11.mode.3840x2160@60 \
|
||||||
|
output.DP-11.scale.2 \
|
||||||
|
output.eDP-2.enable \
|
||||||
|
output.eDP-2.mode.1920x1080@60 \
|
||||||
|
output.eDP-2.scale.1 \
|
||||||
|
output.eDP-2.position.0,0
|
||||||
|
```
|
||||||
+178
-251
@@ -1,114 +1,204 @@
|
|||||||
# Fedora Kinoite
|
# Fedora Kinoite
|
||||||
|
|
||||||
- [Fedora Kinoite](#fedora-kinoite)
|
- [Fedora Kinoite](#fedora-kinoite)
|
||||||
- [TPM2 Luks Decryption](#tpm2-luks-decryption)
|
- [Adding users to groups (usermod replacement)](#adding-users-to-groups-usermod-replacement)
|
||||||
- [Podman](#podman)
|
- [System Prereqs](#system-prereqs)
|
||||||
- [Docker Compose and Docker Buildkit with Rootless Podman](#docker-compose-and-docker-buildkit-with-rootless-podman)
|
- [Toolbox](#toolbox)
|
||||||
- [rpm-ostree](#rpm-ostree)
|
- [Clipboard Sharing](#clipboard-sharing)
|
||||||
- [Git, Vim, etc](#git-vim-etc)
|
- [Running Host Commands](#running-host-commands)
|
||||||
- [Libvirt, Qemu, KVM](#libvirt-qemu-kvm)
|
- [Saving a Toolbox](#saving-a-toolbox)
|
||||||
- [ROCM](#rocm)
|
- [Apps](#apps)
|
||||||
- [Ollama](#ollama)
|
- [Gear Lever](#gear-lever)
|
||||||
- [Network](#network)
|
- [VSCodium](#vscodium)
|
||||||
- [Hostname](#hostname)
|
- [Ansible](#ansible)
|
||||||
- [VLAN Setup with nmcli](#vlan-setup-with-nmcli)
|
- [OpenCode](#opencode)
|
||||||
- [GPU Support in Distrobox](#gpu-support-in-distrobox)
|
- [Nextcloud](#nextcloud)
|
||||||
- [Automatic Display Switching](#automatic-display-switching)
|
- [UV](#uv)
|
||||||
|
- [NVM](#nvm)
|
||||||
|
- [Set Hostname](#set-hostname)
|
||||||
|
- [rpm-ostree Notes](#rpm-ostree-notes)
|
||||||
|
- [Accent keys when holding a key](#accent-keys-when-holding-a-key)
|
||||||
|
|
||||||
## TPM2 Luks Decryption
|
## Adding users to groups (usermod replacement)
|
||||||
|
|
||||||
Mostly taken from here:
|
|
||||||
<https://gist.github.com/jdoss/777e8b52c8d88eb87467935769c98a95>
|
|
||||||
|
|
||||||
PCR reference for `--tpm2-pcrs` args
|
|
||||||
|
|
||||||
```text
|
|
||||||
0: System firmware executable
|
|
||||||
2: Kernel
|
|
||||||
4: Bootloader
|
|
||||||
7: Secure boot state
|
|
||||||
8: Cmdline
|
|
||||||
9: Initrd
|
|
||||||
```
|
|
||||||
|
|
||||||
Basic commands:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Show tpm2 devices
|
grep -E '^weldr:' /usr/lib/group | sudo tee -a /etc/group
|
||||||
systemd-cryptenroll --tpm2-device=list
|
sudo usermod -aG weldr $USER
|
||||||
# Show crypto luks block devices
|
|
||||||
blkid -t TYPE=crypto_LUKS
|
|
||||||
|
|
||||||
# Enroll the tpm2 device with systemd-cryptenroll
|
|
||||||
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0,2,4,7,8,9 /dev/nvme0n1p3
|
|
||||||
|
|
||||||
# Reenroll
|
|
||||||
systemd-cryptenroll /dev/nvme0n1p3 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=0,2,4,7,8,9
|
|
||||||
|
|
||||||
# Append to command line args
|
|
||||||
rpm-ostree kargs --append=rd.luks.options=tpm2-device=auto
|
|
||||||
```
|
```
|
||||||
|
|
||||||
When you update you'll need to reenroll. Add this to your ~/.bashrc
|
## System Prereqs
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# LUKS TPM2 commands
|
# Appimage support
|
||||||
alias tpm2-reenroll='sudo systemd-cryptenroll /dev/nvme0n1p3 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=0,2,4,7,8,9'
|
rpm-ostree install fuse fuse-libs
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
rpm-ostree install vim
|
||||||
|
|
||||||
|
# Qemu/KVM
|
||||||
|
rpm-ostree install virt-manager libvirt virt-install
|
||||||
|
|
||||||
|
# OSBuild
|
||||||
|
rpm-ostree install -y osbuild-composer composer-cli openscap-scanner scap-security-guide
|
||||||
|
|
||||||
|
# Distrobox
|
||||||
|
rpm-ostree install -y distrobox
|
||||||
|
|
||||||
|
# BTRFS Snapshots
|
||||||
|
rpm-ostree install -y snapper
|
||||||
|
|
||||||
|
# Kitty Terminal
|
||||||
|
# terminfo prevents the "WARNING: terminal is not fully functional" error
|
||||||
|
rpm-ostree install -y kitty kitty-terminfo
|
||||||
```
|
```
|
||||||
|
|
||||||
## Podman
|
## Toolbox
|
||||||
|
|
||||||
Since you'll be using podman for most container-based services, you'll want to set the
|
### Clipboard Sharing
|
||||||
the podman auth file to somewhere persistent, otherwise it'll get deleted every time you
|
|
||||||
reboot.
|
|
||||||
|
|
||||||
Add this to your `.bashrc`:
|
Inside the toolbox run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Podman auth file
|
sudo dnf install -y wl-clipboard
|
||||||
export REGISTRY_AUTH_FILE=$HOME/.podman-auth.json
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Source that and then run `podman login` to create the file.
|
### Running Host Commands
|
||||||
|
|
||||||
### Docker Compose and Docker Buildkit with Rootless Podman
|
You'll want to use toolbox for development. Unfortunately, toolbox doesn't
|
||||||
|
integrate well with host system operations.
|
||||||
|
|
||||||
Allows you to use podman with full docker-compose compatibility.
|
I create a `toolbox.sh` in `~/.bashrc.d` with functions that map to host
|
||||||
|
commands like so:
|
||||||
<https://emersion.fr/blog/2025/using-podman-compose-and-buildkit/>
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rpm-ostree install docker-compose docker-buildx
|
# Use flatpak-spawn --host podman inside toolbox, regular podman outside
|
||||||
reboot
|
podman() {
|
||||||
systemctl --user enable --now podman.socket
|
if [ -f /run/.containerenv ]; then
|
||||||
docker context create podman --docker host=unix://$XDG_RUNTIME_DIR/podman/podman.sock
|
flatpak-spawn --host podman "$@"
|
||||||
docker context use podman
|
else
|
||||||
|
command podman "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
### Autostarting services with quadlets
|
# Notify the user if they're trying to run a command that doesn't work in a toolbox
|
||||||
|
rpm-ostree() {
|
||||||
If you want to run something as your user at boot (like a systemd process, think ollama) you can
|
if [ -f /run/.containerenv ]; then
|
||||||
create a user quadlets like so:
|
echo "Command must be run outside toolbox."
|
||||||
|
else
|
||||||
```bash
|
command rpm-ostree "$@"
|
||||||
# Generate the .container file
|
fi
|
||||||
podman run --rm ghcr.io/containers/podlet --install --description "Local AI" \
|
}
|
||||||
podman run \
|
|
||||||
-d \
|
|
||||||
-v ollama:/root/.ollama \
|
|
||||||
-p 11434:11434 \
|
|
||||||
--name ollama \
|
|
||||||
--restart always \
|
|
||||||
docker.io/ollama/ollama > ~/.config/containers/systemd/ollama.container
|
|
||||||
|
|
||||||
# Verify the service (Note the filename:service, this is required! You will get "Failed to prepare filename" without it)
|
|
||||||
systemd-analyze verify ~/.config/containers/systemd/ollama.container:ollama.service
|
|
||||||
|
|
||||||
# Start the service
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user start ollama
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## rpm-ostree
|
I have the following functions mapped:
|
||||||
|
|
||||||
|
1. podman
|
||||||
|
2. rpm-ostree
|
||||||
|
3. flatpak
|
||||||
|
4. firewall-cmd
|
||||||
|
|
||||||
|
### Saving a Toolbox
|
||||||
|
|
||||||
|
After setting up a base toolbox you'll want to save it for future use. This is easy with podman commit.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Commit the running container to a new image
|
||||||
|
podman commit fedora-toolbox-44 my-toolbox-snapshot
|
||||||
|
|
||||||
|
# 2. Save the image to a tar file for later use
|
||||||
|
podman save -o ~/my-toolbox-snapshot.tar my-toolbox-snapshot
|
||||||
|
|
||||||
|
# Load the image
|
||||||
|
podman load -i ~/my-toolbox-snapshot.tar
|
||||||
|
|
||||||
|
# Create a new toolbox from it
|
||||||
|
toolbox create --image my-toolbox-snapshot
|
||||||
|
```
|
||||||
|
|
||||||
|
## Apps
|
||||||
|
|
||||||
|
Anything not mentioned here is installed via flatpak from flathub.
|
||||||
|
|
||||||
|
### Gear Lever
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak install it.mijorus.gearlever
|
||||||
|
```
|
||||||
|
|
||||||
|
### VSCodium
|
||||||
|
|
||||||
|
Install in toolbox.
|
||||||
|
|
||||||
|
<https://vscodium.com/#install-on-fedora-rhel-centos-rockylinux-opensuse-rpm-package>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo tee -a /etc/yum.repos.d/vscodium.repo << 'EOF'
|
||||||
|
[gitlab.com_paulcarroty_vscodium_repo]
|
||||||
|
name=gitlab.com_paulcarroty_vscodium_repo
|
||||||
|
baseurl=https://paulcarroty.gitlab.io/vscodium-deb-rpm-repo/rpms/
|
||||||
|
enabled=1
|
||||||
|
gpgcheck=1
|
||||||
|
repo_gpgcheck=1
|
||||||
|
gpgkey=https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg
|
||||||
|
metadata_expire=1h
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo dnf install codium
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ansible
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install pipx
|
||||||
|
python3 -m ensurepip --user
|
||||||
|
python3 -m pip install --user pipx
|
||||||
|
pipx ensurepath
|
||||||
|
|
||||||
|
# Install ansible
|
||||||
|
pipx install --include-deps ansible
|
||||||
|
```
|
||||||
|
|
||||||
|
### OpenCode
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://opencode.ai/install | bash
|
||||||
|
|
||||||
|
# Install pyright LSP
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
python -m pip install --user pyright
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
|
||||||
|
Download the AppImage. Install via Gear Lever.
|
||||||
|
|
||||||
|
<https://github.com/nextcloud-releases/desktop/releases>
|
||||||
|
|
||||||
|
| Source | Repo | Release file name |
|
||||||
|
| ------ | -------------------------- | ----------------- |
|
||||||
|
| Github | nextcloud-releases/desktop | *x86_64.AppImage |
|
||||||
|
|
||||||
|
### UV
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### NVM
|
||||||
|
|
||||||
|
<https://www.nvmnode.com/guide/installation.html#nvm-install-for-linux-macos>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set Hostname
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo hostnamectl hostname reesework16
|
||||||
|
```
|
||||||
|
|
||||||
|
## rpm-ostree Notes
|
||||||
|
|
||||||
Note: if you don't need them, remove extra repos
|
Note: if you don't need them, remove extra repos
|
||||||
|
|
||||||
@@ -133,169 +223,6 @@ rpm-ostree apply-live
|
|||||||
rpm-ostree status
|
rpm-ostree status
|
||||||
```
|
```
|
||||||
|
|
||||||
### Git, Vim, etc
|
## Accent keys when holding a key
|
||||||
|
|
||||||
Some packages are nice to have at the system level.
|
Settings -> keyboard -> virtual keyboard -> disable virtual keyboard
|
||||||
|
|
||||||
```bash
|
|
||||||
rpm-ostree install git vim
|
|
||||||
```
|
|
||||||
|
|
||||||
### Libvirt, Qemu, KVM
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rpm-ostree install virt-manager libvirt
|
|
||||||
systemctl enable --now libvirtd
|
|
||||||
```
|
|
||||||
|
|
||||||
### ROCM
|
|
||||||
|
|
||||||
Credit to:
|
|
||||||
<https://medium.com/@seancheo/running-generative-ai-on-amd-in-fedora-40-28aa3bebb187>
|
|
||||||
|
|
||||||
Here are most of the ROCM packages that you'll need.
|
|
||||||
|
|
||||||
Fedora is currently working on a ROCM meta package here:
|
|
||||||
<https://packages.fedoraproject.org/pkgs/rocm/rocm/>
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rpm-ostree install \
|
|
||||||
hipblas-devel \
|
|
||||||
hipblaslt-devel \
|
|
||||||
hipcc \
|
|
||||||
hipcc-libomp-devel \
|
|
||||||
hipcub-devel \
|
|
||||||
hipfft-devel \
|
|
||||||
hipfort-devel \
|
|
||||||
hiprand-devel \
|
|
||||||
hiprt-devel \
|
|
||||||
hipsolver-devel \
|
|
||||||
hipsparse-devel \
|
|
||||||
rocalution-devel \
|
|
||||||
rocblas-devel \
|
|
||||||
rocfft-devel \
|
|
||||||
rocm-clang-devel \
|
|
||||||
rocm-clang-tools-extra-devel \
|
|
||||||
rocm-cmake \
|
|
||||||
rocm-comgr-devel \
|
|
||||||
rocm-core-devel \
|
|
||||||
rocm-hip-devel \
|
|
||||||
rocm-libc++-devel \
|
|
||||||
rocm-libc++-static \
|
|
||||||
rocm-llvm-devel \
|
|
||||||
rocm-omp-devel \
|
|
||||||
rocm-runtime-devel \
|
|
||||||
rocm-rpp-devel \
|
|
||||||
rocm-smi-devel \
|
|
||||||
rocminfo \
|
|
||||||
rocdecode-devel \
|
|
||||||
rocjpeg-devel \
|
|
||||||
rocprim-devel \
|
|
||||||
rocrand-devel \
|
|
||||||
rocsolver-devel \
|
|
||||||
rocsparse-devel \
|
|
||||||
rocthrust-devel \
|
|
||||||
roctracer-devel \
|
|
||||||
miopen
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ollama
|
|
||||||
|
|
||||||
<https://ollama.com/download>
|
|
||||||
|
|
||||||
Run the installation script as normal. Make sure you have the [ROCM](#rocm) drivers installed
|
|
||||||
for GPU acceleration. The script *should* automatically pull the ROCM drivers after installing
|
|
||||||
the base packages. If not, you should install them manually.
|
|
||||||
|
|
||||||
For starting ollama as a service, follow the link below with one exception.
|
|
||||||
|
|
||||||
<https://github.com/ollama/ollama/blob/main/docs/linux.md#adding-ollama-as-a-startup-service-recommended>
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Change the recommended home dir to /var/home/ollama
|
|
||||||
sudo useradd -r -s /bin/false -U -m -d /var/home/ollama ollama
|
|
||||||
```
|
|
||||||
|
|
||||||
## Network
|
|
||||||
|
|
||||||
### Hostname
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo hostnamectl hostname reesework16
|
|
||||||
```
|
|
||||||
|
|
||||||
### VLAN Setup with nmcli
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# VLAN 2
|
|
||||||
nmcli conn
|
|
||||||
export NMCLI_DEVICE=enp195s0f4u1u3
|
|
||||||
nmcli connection add type VLAN con-name $NMCLI_DEVICE.2 dev $NMCLI_DEVICE id 2
|
|
||||||
```
|
|
||||||
|
|
||||||
## GPU Support in Distrobox
|
|
||||||
|
|
||||||
Fix for `error="failed to check permission on /dev/kfd: open /dev/kfd: invalid argument"`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# You have to create the video and render group to /etc/group before you can use it
|
|
||||||
sudo grep -E '^video:' /usr/lib/group | sudo tee -a /etc/group
|
|
||||||
sudo grep -E '^render:' /usr/lib/group | sudo tee -a /etc/group
|
|
||||||
sudo usermod -aG video $USER
|
|
||||||
sudo usermod -aG render $USER
|
|
||||||
```
|
|
||||||
|
|
||||||
Logout and log back in to adopt new groups.
|
|
||||||
|
|
||||||
## Automatic Display Switching
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# List displays
|
|
||||||
# Builtin: eDP-2
|
|
||||||
# Roku: DP-13
|
|
||||||
# Lenovo: DP-11
|
|
||||||
kscreen-doctor -o
|
|
||||||
|
|
||||||
# Put the builtin display back to normal
|
|
||||||
kscreen-doctor \
|
|
||||||
output.eDP-2.enable \
|
|
||||||
output.eDP-2.position.0,0 \
|
|
||||||
output.eDP-2.primary \
|
|
||||||
output.eDP-2.mode.2560x1600@165 \
|
|
||||||
output.eDP-2.scale.1.25
|
|
||||||
|
|
||||||
# Show on Roku TV and Monitor
|
|
||||||
kscreen-doctor \
|
|
||||||
output.DP-11.enable \
|
|
||||||
output.DP-11.position.0,0 \
|
|
||||||
output.DP-11.mode.2560x1440@60 \
|
|
||||||
output.DP-11.scale.1 \
|
|
||||||
output.DP-13.enable \
|
|
||||||
output.DP-13.position.0,0 \
|
|
||||||
output.DP-13.mode.2560x1440@100 \
|
|
||||||
output.DP-13.scale.1 \
|
|
||||||
output.DP-13.primary \
|
|
||||||
output.eDP-2.disable
|
|
||||||
|
|
||||||
# Show only on the roku TV
|
|
||||||
kscreen-doctor \
|
|
||||||
output.DP-11.enable \
|
|
||||||
output.DP-11.position.0,0 \
|
|
||||||
output.DP-11.primary \
|
|
||||||
output.DP-11.mode.3840x2160@60 \
|
|
||||||
output.DP-11.scale.2 \
|
|
||||||
output.DP-13.disable \
|
|
||||||
output.eDP-2.disable
|
|
||||||
|
|
||||||
# Mirror the builtin display to the roku tv
|
|
||||||
kscreen-doctor \
|
|
||||||
output.DP-11.enable \
|
|
||||||
output.DP-11.position.0,0 \
|
|
||||||
output.DP-11.primary \
|
|
||||||
output.DP-11.mode.3840x2160@60 \
|
|
||||||
output.DP-11.scale.2 \
|
|
||||||
output.eDP-2.enable \
|
|
||||||
output.eDP-2.mode.1920x1080@60 \
|
|
||||||
output.eDP-2.scale.1 \
|
|
||||||
output.eDP-2.position.0,0
|
|
||||||
```
|
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Setup SSH](#setup-ssh)
|
- [Setup SSH](#setup-ssh)
|
||||||
- [DNF](#dnf)
|
- [DNF](#dnf)
|
||||||
|
- [Version lock](#version-lock)
|
||||||
- [Power Profiles with Tuned](#power-profiles-with-tuned)
|
- [Power Profiles with Tuned](#power-profiles-with-tuned)
|
||||||
- [Fail2Ban](#fail2ban)
|
- [Fail2Ban](#fail2ban)
|
||||||
- [BTRFS Parent Volumes](#btrfs-parent-volumes)
|
- [BTRFS Parent Volumes](#btrfs-parent-volumes)
|
||||||
@@ -84,6 +85,7 @@
|
|||||||
- [Sound Devices](#sound-devices)
|
- [Sound Devices](#sound-devices)
|
||||||
- [Install ffmpegthumbnailer, remove totem](#install-ffmpegthumbnailer-remove-totem)
|
- [Install ffmpegthumbnailer, remove totem](#install-ffmpegthumbnailer-remove-totem)
|
||||||
- [Add compatibility for HEIC to mogrify](#add-compatibility-for-heic-to-mogrify)
|
- [Add compatibility for HEIC to mogrify](#add-compatibility-for-heic-to-mogrify)
|
||||||
|
- [Redirecting ports for rootless services](#redirecting-ports-for-rootless-services)
|
||||||
|
|
||||||
<https://docs.fedoraproject.org/en-US/fedora-server/installation/postinstallation-tasks/#_manage_system_updates>
|
<https://docs.fedoraproject.org/en-US/fedora-server/installation/postinstallation-tasks/#_manage_system_updates>
|
||||||
|
|
||||||
@@ -127,6 +129,16 @@ dnf update --refresh -y
|
|||||||
dnf install -y git glances tmux vim python3-libdnf5 borgbackup tpm2-tools
|
dnf install -y git glances tmux vim python3-libdnf5 borgbackup tpm2-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Version lock
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install dnf-plugin-versionlock
|
||||||
|
sudo dnf list <package> --showduplicates
|
||||||
|
sudo dnf versionlock add <package_name>-<version>.x86_64
|
||||||
|
sudo dnf versionlock list
|
||||||
|
sudo dnf versionlock delete <package_name>
|
||||||
|
```
|
||||||
|
|
||||||
## Power Profiles with Tuned
|
## Power Profiles with Tuned
|
||||||
|
|
||||||
1. `dnf install tuned`
|
1. `dnf install tuned`
|
||||||
@@ -1486,3 +1498,29 @@ sudo dnf install ffmpegthumbnailer
|
|||||||
```bash
|
```bash
|
||||||
sudo dnf install libheic-freeworld
|
sudo dnf install libheic-freeworld
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Redirecting ports for rootless services
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ipv4
|
||||||
|
sudo firewall-cmd \
|
||||||
|
--permanent \
|
||||||
|
--add-forward-port=port=80:proto=tcp:toport=8080
|
||||||
|
|
||||||
|
sudo firewall-cmd --add-rich-rule='forward-port port=80 protocol=tcp to-port=8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Or in ansible
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Forward ports
|
||||||
|
ansible.posix.firewalld:
|
||||||
|
port_forward:
|
||||||
|
- port: "{{ item.from }}"
|
||||||
|
proto: tcp
|
||||||
|
toport: "{{ item.to }}"
|
||||||
|
permanent: true
|
||||||
|
state: enabled
|
||||||
|
immediate: true
|
||||||
|
loop: "{{ forward_ports }}"
|
||||||
|
```
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
[Network]
|
|
||||||
Internal=true
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[Pod]
|
|
||||||
Network=ai-internal.network
|
|
||||||
# llama.cpp server
|
|
||||||
PublishPort=8000:8000/tcp
|
|
||||||
# llama.cpp embed
|
|
||||||
PublishPort=8001:8001/tcp
|
|
||||||
# llama.cpp instruct
|
|
||||||
PublishPort=8002:8002/tcp
|
|
||||||
# llama.cpp tool
|
|
||||||
PublishPort=8003:8003/tcp
|
|
||||||
# stable-diffusion.cpp gen
|
|
||||||
PublishPort=1234:1234/tcp
|
|
||||||
# stable-diffusion.cpp edit
|
|
||||||
PublishPort=1235:1235/tcp
|
|
||||||
@@ -3,10 +3,6 @@
|
|||||||
- [Self Hosted AI Stack](#self-hosted-ai-stack)
|
- [Self Hosted AI Stack](#self-hosted-ai-stack)
|
||||||
- [Notes](#notes)
|
- [Notes](#notes)
|
||||||
- [Podman Volume Locations](#podman-volume-locations)
|
- [Podman Volume Locations](#podman-volume-locations)
|
||||||
- [List of Internal Links](#list-of-internal-links)
|
|
||||||
- [Quick Install](#quick-install)
|
|
||||||
- [Text Stack](#text-stack)
|
|
||||||
- [Image Stack](#image-stack)
|
|
||||||
- [Setup](#setup)
|
- [Setup](#setup)
|
||||||
- [Create the AI user](#create-the-ai-user)
|
- [Create the AI user](#create-the-ai-user)
|
||||||
- [Helper aliases](#helper-aliases)
|
- [Helper aliases](#helper-aliases)
|
||||||
@@ -36,16 +32,7 @@
|
|||||||
- [open-webui](#open-webui)
|
- [open-webui](#open-webui)
|
||||||
- [Upgrade Open Webui](#upgrade-open-webui)
|
- [Upgrade Open Webui](#upgrade-open-webui)
|
||||||
- [lite-llm](#lite-llm)
|
- [lite-llm](#lite-llm)
|
||||||
- [Install Services with Quadlets](#install-services-with-quadlets)
|
- [Install the update script](#install-the-update-script)
|
||||||
- [API Keys](#api-keys)
|
|
||||||
- [Internal and External Pods](#internal-and-external-pods)
|
|
||||||
- [Llama CPP Server (Port 8000)](#llama-cpp-server-port-8000)
|
|
||||||
- [Llama CPP Embedding Server (Port 8001)](#llama-cpp-embedding-server-port-8001)
|
|
||||||
- [Llama CPP Instruct Server (Port 8002)](#llama-cpp-instruct-server-port-8002)
|
|
||||||
- [Stable Diffusion CPP (Port 1234 and 1235)](#stable-diffusion-cpp-port-1234-and-1235)
|
|
||||||
- [Open Webui (Port 8080)](#open-webui-port-8080)
|
|
||||||
- [Install the update script](#install-the-update-script)
|
|
||||||
- [Install Guest Open Webui with Start/Stop Services](#install-guest-open-webui-with-startstop-services)
|
|
||||||
- [Benchmark Results](#benchmark-results)
|
- [Benchmark Results](#benchmark-results)
|
||||||
- [Testing with Curl](#testing-with-curl)
|
- [Testing with Curl](#testing-with-curl)
|
||||||
- [OpenAI API](#openai-api)
|
- [OpenAI API](#openai-api)
|
||||||
@@ -77,33 +64,6 @@ hf-download ()
|
|||||||
|
|
||||||
`~/.local/share/containers/storage/volumes/`
|
`~/.local/share/containers/storage/volumes/`
|
||||||
|
|
||||||
### List of Internal Links
|
|
||||||
|
|
||||||
- llama-cpp
|
|
||||||
- llama-embed
|
|
||||||
- llama-instruct
|
|
||||||
- image-gen
|
|
||||||
- image-edit
|
|
||||||
- openwebui
|
|
||||||
|
|
||||||
## Quick Install
|
|
||||||
|
|
||||||
### Text Stack
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook \
|
|
||||||
-i ansible/inventory.yaml \
|
|
||||||
active/software_ai_stack/install_ai_text_stack.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Image Stack
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook \
|
|
||||||
-i ansible/inventory.yaml \
|
|
||||||
active/software_ai_stack/install_ai_image_stack.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
### Create the AI user
|
### Create the AI user
|
||||||
@@ -186,8 +146,7 @@ rsync -av --progress /home/ai/models/ /srv/models/
|
|||||||
In my completely subjective opinion: 5 bit quant is usually the sweet spot for
|
In my completely subjective opinion: 5 bit quant is usually the sweet spot for
|
||||||
unsloth models. Q5_K_S is usually just fine.
|
unsloth models. Q5_K_S is usually just fine.
|
||||||
|
|
||||||
I usually download the F16 mmproj files. This is also completely subjective.
|
I usually download the BF16 mmproj files. This is also completely subjective.
|
||||||
BF16 is fine. F32 is overkill.
|
|
||||||
|
|
||||||
#### Text models
|
#### Text models
|
||||||
|
|
||||||
@@ -391,20 +350,43 @@ podman run \
|
|||||||
--name llama-server-demo \
|
--name llama-server-demo \
|
||||||
--device=/dev/kfd \
|
--device=/dev/kfd \
|
||||||
--device=/dev/dri \
|
--device=/dev/dri \
|
||||||
-v /home/ai/models/text:/models:z \
|
-v $(pwd):/models:z \
|
||||||
-p 8010:8000 \
|
-p 8010:8000 \
|
||||||
--ipc host \
|
--ipc host \
|
||||||
localhost/llama-cpp-vulkan:latest \
|
localhost/llama-cpp-vulkan:latest \
|
||||||
--host 0.0.0.0 \
|
--host 0.0.0.0 \
|
||||||
--port 8000 \
|
--port 8000 \
|
||||||
-c 128000 \
|
|
||||||
--perf \
|
--perf \
|
||||||
--n-gpu-layers all \
|
--n-gpu-layers all \
|
||||||
--jinja \
|
--jinja \
|
||||||
--models-max 1 \
|
--model /models/gemma-4-E4B-it-qat-UD-Q4_K_XL.gguf \
|
||||||
--models-dir /models \
|
--mmproj /models/mmproj-F16.gguf \
|
||||||
--chat-template-kwargs '{"enable_thinking": false}' \
|
--temp 1.0 \
|
||||||
-m /models/qwen3.5-35b-a3b
|
--top-p 0.95 \
|
||||||
|
--top-k 64 \
|
||||||
|
--chat-template-kwargs '{"enable_thinking":true}'
|
||||||
|
|
||||||
|
podman run \
|
||||||
|
--rm \
|
||||||
|
--name llama-server-demo \
|
||||||
|
--device=/dev/kfd \
|
||||||
|
--device=/dev/dri \
|
||||||
|
-v $(pwd):/models:z \
|
||||||
|
-p 8010:8000 \
|
||||||
|
--ipc host \
|
||||||
|
localhost/llama-cpp-vulkan:latest \
|
||||||
|
--host 0.0.0.0 \
|
||||||
|
--port 8000 \
|
||||||
|
--perf \
|
||||||
|
--n-gpu-layers all \
|
||||||
|
--jinja \
|
||||||
|
--model /models/Qwen3.5-9B-UD-Q4_K_XL.gguf \
|
||||||
|
--mmproj /models/mmproj-BF16.gguf \
|
||||||
|
--temp 0.6 \
|
||||||
|
--top-p 0.95 \
|
||||||
|
--top-k 20 \
|
||||||
|
--min-p 0.00 \
|
||||||
|
--chat-template-kwargs '{"enable_thinking":true}'
|
||||||
```
|
```
|
||||||
|
|
||||||
Embedding models
|
Embedding models
|
||||||
@@ -595,96 +577,7 @@ podman run \
|
|||||||
-p 4000:4000
|
-p 4000:4000
|
||||||
```
|
```
|
||||||
|
|
||||||
## Install Services with Quadlets
|
## Install the update script
|
||||||
|
|
||||||
### API Keys
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p /home/ai/.llama-api
|
|
||||||
touch /home/ai/.llama-api/keys.env
|
|
||||||
chmod 600 /home/ai/.llama-api/keys.env
|
|
||||||
vim /home/ai/.llama-api/keys.env
|
|
||||||
|
|
||||||
LLAMA_API_KEY=
|
|
||||||
|
|
||||||
# Generate keys and append to file, then comma separate the keys
|
|
||||||
openssl rand -base64 48 >> keys.env
|
|
||||||
openssl rand -base64 48 >> keys.env
|
|
||||||
openssl rand -base64 48 >> keys.env
|
|
||||||
```
|
|
||||||
|
|
||||||
### Internal and External Pods
|
|
||||||
|
|
||||||
These will be used to restrict internet access to our llama.cpp and
|
|
||||||
stable-diffusion.cpp services while allowing the frontend services to
|
|
||||||
communicate with those containers.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scp -r active/software_ai_stack/ai-internal.* deskwork-ai:.config/containers/systemd/
|
|
||||||
ssh deskwork-ai
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user start ai-internal-pod.service
|
|
||||||
```
|
|
||||||
|
|
||||||
### Llama CPP Server (Port 8000)
|
|
||||||
|
|
||||||
Installs the llama.cpp server to run our text models.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scp -r active/software_ai_stack/llama-think.container deskwork-ai:.config/containers/systemd/
|
|
||||||
ssh deskwork-ai
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user restart ai-internal-pod.service
|
|
||||||
```
|
|
||||||
|
|
||||||
### Llama CPP Embedding Server (Port 8001)
|
|
||||||
|
|
||||||
Installs the llama.cpp server to run our embedding models
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scp -r active/software_ai_stack/llama-embed.container deskwork-ai:.config/containers/systemd/
|
|
||||||
ssh deskwork-ai
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user restart ai-internal-pod.service
|
|
||||||
```
|
|
||||||
|
|
||||||
### Llama CPP Instruct Server (Port 8002)
|
|
||||||
|
|
||||||
Installs the llama.cpp server to run a constant instruct (no thinking) model for quick replies
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scp -r active/software_ai_stack/llama-instruct.container deskwork-ai:.config/containers/systemd/
|
|
||||||
ssh deskwork-ai
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user restart ai-internal-pod.service
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stable Diffusion CPP (Port 1234 and 1235)
|
|
||||||
|
|
||||||
Installs the stable-diffusion.cpp server to run our image models.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scp -r active/software_ai_stack/quadlets_stable_diffusion/* deskwork-ai:.config/containers/systemd/
|
|
||||||
ssh deskwork-ai
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user restart ai-internal-pod.service
|
|
||||||
```
|
|
||||||
|
|
||||||
### Open Webui (Port 8080)
|
|
||||||
|
|
||||||
Installs the open webui frontend.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scp -r active/software_ai_stack/quadlets_openwebui/* deskwork-ai:.config/containers/systemd/
|
|
||||||
ssh deskwork-ai
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user restart ai-external-pod.service
|
|
||||||
```
|
|
||||||
|
|
||||||
Note, all services will be available at `host.containers.internal`. So llama.cpp
|
|
||||||
will be up at `http://host.containers.internal:8000`.
|
|
||||||
|
|
||||||
### Install the update script
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Builds the latest llama.cpp and stable-diffusion.cpp
|
# 1. Builds the latest llama.cpp and stable-diffusion.cpp
|
||||||
@@ -696,18 +589,6 @@ chmod +x update-script.sh
|
|||||||
./update-script.sh
|
./update-script.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install Guest Open Webui with Start/Stop Services
|
|
||||||
|
|
||||||
Optionally install a guest openwebui service.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scp -r active/software_ai_stack/systemd/. deskwork-ai:.config/systemd/user/
|
|
||||||
ssh deskwork-ai
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user enable open-webui-guest-start.timer
|
|
||||||
systemctl --user enable open-webui-guest-stop.timer
|
|
||||||
```
|
|
||||||
|
|
||||||
## Benchmark Results
|
## Benchmark Results
|
||||||
|
|
||||||
Benchmarks are run with [unsloth gpt-oss-20b Q8_0](https://huggingface.co/unsloth/gpt-oss-20b-GGUF/blob/main/gpt-oss-20b-Q8_0.gguf)
|
Benchmarks are run with [unsloth gpt-oss-20b Q8_0](https://huggingface.co/unsloth/gpt-oss-20b-GGUF/blob/main/gpt-oss-20b-Q8_0.gguf)
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
- name: Create Deskwork AI Stack
|
|
||||||
hosts: deskwork-ai
|
|
||||||
tasks:
|
|
||||||
- name: Create /home/ai/.config/containers/systemd
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /home/ai/.config/containers/systemd
|
|
||||||
state: directory
|
|
||||||
mode: "0755"
|
|
||||||
- name: Copy Quadlets
|
|
||||||
template:
|
|
||||||
src: "{{ item }}"
|
|
||||||
dest: "/home/ai/.config/containers/systemd/{{ item }}"
|
|
||||||
loop:
|
|
||||||
- ai-internal.network
|
|
||||||
- ai-internal.pod
|
|
||||||
- stable-diffusion-gen-server.container
|
|
||||||
- stable-diffusion-edit-server.container
|
|
||||||
- name: Reload and start the ai-internal-pod service
|
|
||||||
ansible.builtin.systemd_service:
|
|
||||||
state: restarted
|
|
||||||
name: ai-internal-pod.service
|
|
||||||
daemon_reload: true
|
|
||||||
scope: user
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
- name: Create Deskwork AI Stack
|
|
||||||
hosts: deskwork-ai
|
|
||||||
tasks:
|
|
||||||
- name: Create /home/ai/.config/containers/systemd
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /home/ai/.config/containers/systemd
|
|
||||||
state: directory
|
|
||||||
mode: "0755"
|
|
||||||
- name: Copy Quadlets
|
|
||||||
template:
|
|
||||||
src: "{{ item }}"
|
|
||||||
dest: "/home/ai/.config/containers/systemd/{{ item }}"
|
|
||||||
loop:
|
|
||||||
- ai-internal.network
|
|
||||||
- ai-internal.pod
|
|
||||||
- llama-embed.container
|
|
||||||
- llama-instruct.container
|
|
||||||
- llama-tool.container
|
|
||||||
- name: Reload and start the ai-internal-pod service
|
|
||||||
ansible.builtin.systemd_service:
|
|
||||||
state: restarted
|
|
||||||
name: ai-internal-pod.service
|
|
||||||
daemon_reload: true
|
|
||||||
scope: user
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
- name: Create Deskwork AI Stack
|
|
||||||
hosts: driveripper-ai
|
|
||||||
tasks:
|
|
||||||
- name: Create /home/ai/.config/containers/systemd
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /home/ai/.config/containers/systemd
|
|
||||||
state: directory
|
|
||||||
mode: "0755"
|
|
||||||
- name: Copy Quadlets
|
|
||||||
template:
|
|
||||||
src: "{{ item }}"
|
|
||||||
dest: "/home/ai/.config/containers/systemd/{{ item }}"
|
|
||||||
loop:
|
|
||||||
- ai-internal.network
|
|
||||||
- ai-internal.pod
|
|
||||||
- llama-turbo.container
|
|
||||||
- name: Reload and start the ai-internal-pod service
|
|
||||||
ansible.builtin.systemd_service:
|
|
||||||
state: restarted
|
|
||||||
name: ai-internal-pod.service
|
|
||||||
daemon_reload: true
|
|
||||||
scope: user
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=A Llama CPP Server For Embedding Models
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
# Shared AI internal pod without internet access
|
|
||||||
Pod=ai-internal.pod
|
|
||||||
|
|
||||||
# Image is built locally via podman build
|
|
||||||
Image=localhost/llama-cpp-vulkan:latest
|
|
||||||
|
|
||||||
# Downloaded models volume
|
|
||||||
Volume=/home/ai/models/embedding:/models:z
|
|
||||||
|
|
||||||
# GPU Device
|
|
||||||
AddDevice=/dev/kfd
|
|
||||||
AddDevice=/dev/dri
|
|
||||||
|
|
||||||
# Server command
|
|
||||||
Exec=--port 8001 \
|
|
||||||
-c 0 \
|
|
||||||
-b 1024 \
|
|
||||||
-ub 1024 \
|
|
||||||
--perf \
|
|
||||||
--n-gpu-layers all \
|
|
||||||
--embedding \
|
|
||||||
-m /models/emebeddinggemma-300m/embeddinggemma-300M-BF16.gguf \
|
|
||||||
--alias embed
|
|
||||||
|
|
||||||
# Health Check
|
|
||||||
HealthCmd=CMD-SHELL curl --fail http://127.0.0.1:8001/health || exit 1
|
|
||||||
HealthInterval=10s
|
|
||||||
HealthRetries=3
|
|
||||||
HealthStartPeriod=10s
|
|
||||||
HealthTimeout=30s
|
|
||||||
HealthOnFailure=kill
|
|
||||||
|
|
||||||
# EnvironmentFile=/home/ai/.llama-api/keys.env
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
# Extend Timeout to allow time to pull the image
|
|
||||||
TimeoutStartSec=900
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
# Start by default on boot
|
|
||||||
WantedBy=multi-user.target default.target
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=A Llama CPP Server Running a Non-Reasoning Model
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
# Shared AI internal pod without internet access
|
|
||||||
Pod=ai-internal.pod
|
|
||||||
|
|
||||||
# Image is built locally via podman build
|
|
||||||
Image=localhost/llama-cpp-vulkan:latest
|
|
||||||
|
|
||||||
# Downloaded models volume
|
|
||||||
Volume=/home/ai/models/text:/models:z
|
|
||||||
|
|
||||||
# GPU Device
|
|
||||||
AddDevice=/dev/kfd
|
|
||||||
AddDevice=/dev/dri
|
|
||||||
|
|
||||||
# Server command
|
|
||||||
Exec=--port 8002 \
|
|
||||||
-c 262144 \
|
|
||||||
-n 32768 \
|
|
||||||
--temp 0.7 \
|
|
||||||
--top-p 0.8 \
|
|
||||||
--top-k 20 \
|
|
||||||
--presence-penalty 1.5 \
|
|
||||||
--min-p 0.00 \
|
|
||||||
--perf \
|
|
||||||
--n-gpu-layers all \
|
|
||||||
-fa on \
|
|
||||||
--spec-type draft-mtp --spec-draft-n-max 2 \
|
|
||||||
--jinja \
|
|
||||||
--chat-template-kwargs '{"preserve_thinking": false, "enable_thinking": false}' \
|
|
||||||
-m /models/qwen3.6-35b-a3b-mtp/Qwen3.6-35B-A3B-UD-Q5_K_M.gguf \
|
|
||||||
--mmproj /models/qwen3.6-35b-a3b-mtp/mmproj-F16.gguf \
|
|
||||||
--alias instruct
|
|
||||||
|
|
||||||
# Health Check
|
|
||||||
HealthCmd=CMD-SHELL curl --fail http://127.0.0.1:8002/health || exit 1
|
|
||||||
HealthInterval=10s
|
|
||||||
HealthRetries=3
|
|
||||||
HealthStartPeriod=10s
|
|
||||||
HealthTimeout=30s
|
|
||||||
HealthOnFailure=kill
|
|
||||||
|
|
||||||
# EnvironmentFile=/home/ai/.llama-api/keys.env
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
# Extend Timeout to allow time to pull the image
|
|
||||||
TimeoutStartSec=900
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
# Start by default on boot
|
|
||||||
WantedBy=multi-user.target default.target
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=A Llama CPP Server Running a Reasoning Model
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
# Shared AI internal pod without internet access
|
|
||||||
Pod=ai-internal.pod
|
|
||||||
|
|
||||||
# Image is built locally via podman build
|
|
||||||
# latest-mtp is for mtp testing
|
|
||||||
# latest is main branch
|
|
||||||
Image=localhost/llama-cpp-vulkan:latest
|
|
||||||
|
|
||||||
# Downloaded models volume
|
|
||||||
Volume=/home/ai/models/text:/models:z
|
|
||||||
|
|
||||||
# GPU Device
|
|
||||||
AddDevice=/dev/kfd
|
|
||||||
AddDevice=/dev/dri
|
|
||||||
|
|
||||||
# Server command
|
|
||||||
Exec=--port 8003 \
|
|
||||||
-c 262144 \
|
|
||||||
-n 32768 \
|
|
||||||
--temp 0.6 \
|
|
||||||
--top-p 0.95 \
|
|
||||||
--top-k 20 \
|
|
||||||
--min-p 0.0 \
|
|
||||||
--presence-penalty 0.0 \
|
|
||||||
--repeat-penalty 1.0 \
|
|
||||||
--reasoning-budget 4096 \
|
|
||||||
--perf \
|
|
||||||
--n-gpu-layers all \
|
|
||||||
-fa on \
|
|
||||||
--spec-type draft-mtp --spec-draft-n-max 2 \
|
|
||||||
--jinja \
|
|
||||||
--chat-template-kwargs '{"preserve_thinking": false}' \
|
|
||||||
--chat-template-file /models/qwen3.6-35b-a3b-mtp/chat_template.jinja \
|
|
||||||
-m /models/qwen3.6-35b-a3b-mtp/Qwen3.6-35B-A3B-UD-Q5_K_M.gguf \
|
|
||||||
--mmproj /models/qwen3.6-35b-a3b-mtp/mmproj-F16.gguf \
|
|
||||||
--alias tool
|
|
||||||
|
|
||||||
# Health Check
|
|
||||||
HealthCmd=CMD-SHELL curl --fail http://127.0.0.1:8003/health || exit 1
|
|
||||||
HealthInterval=10s
|
|
||||||
HealthRetries=3
|
|
||||||
HealthStartPeriod=10s
|
|
||||||
HealthTimeout=30s
|
|
||||||
HealthOnFailure=kill
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
# Extend Timeout to allow time to pull the image
|
|
||||||
TimeoutStartSec=900
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
# Start by default on boot
|
|
||||||
WantedBy=multi-user.target default.target
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=A Llama CPP Server Running a Reasoning Model
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
# Shared AI internal pod without internet access
|
|
||||||
Pod=ai-internal.pod
|
|
||||||
|
|
||||||
# Image is built locally via podman build
|
|
||||||
# latest-mtp is for mtp testing
|
|
||||||
# latest is main branch
|
|
||||||
Image=localhost/llama-cpp-vulkan:latest
|
|
||||||
|
|
||||||
# Downloaded models volume
|
|
||||||
Volume=/home/ai/models/text:/models:z
|
|
||||||
|
|
||||||
# GPU Device
|
|
||||||
AddDevice=/dev/kfd
|
|
||||||
AddDevice=/dev/dri
|
|
||||||
|
|
||||||
# Server command
|
|
||||||
Exec=--port 8000 \
|
|
||||||
-c 262144 \
|
|
||||||
-n 32768 \
|
|
||||||
--temp 0.6 \
|
|
||||||
--top-p 0.95 \
|
|
||||||
--top-k 20 \
|
|
||||||
--min-p 0.0 \
|
|
||||||
--presence-penalty 0.0 \
|
|
||||||
--repeat-penalty 1.0 \
|
|
||||||
--reasoning-budget 4096 \
|
|
||||||
--perf \
|
|
||||||
--n-gpu-layers all \
|
|
||||||
-fa on \
|
|
||||||
--spec-type draft-mtp --spec-draft-n-max 2 \
|
|
||||||
--jinja \
|
|
||||||
--chat-template-kwargs '{"preserve_thinking": true}' \
|
|
||||||
--chat-template-file /models/qwen3.6-35b-a3b-mtp/chat_template.jinja \
|
|
||||||
-m /models/qwen3.6-35b-a3b-mtp/Qwen3.6-35B-A3B-UD-Q5_K_M.gguf \
|
|
||||||
--mmproj /models/qwen3.6-35b-a3b-mtp/mmproj-F16.gguf \
|
|
||||||
--alias turbo
|
|
||||||
|
|
||||||
# Health Check
|
|
||||||
HealthCmd=CMD-SHELL curl --fail http://127.0.0.1:8000/health || exit 1
|
|
||||||
HealthInterval=10s
|
|
||||||
HealthRetries=3
|
|
||||||
HealthStartPeriod=10s
|
|
||||||
HealthTimeout=30s
|
|
||||||
HealthOnFailure=kill
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
# Extend Timeout to allow time to pull the image
|
|
||||||
TimeoutStartSec=900
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
# Start by default on boot
|
|
||||||
WantedBy=multi-user.target default.target
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=An Open Webui Frontend for Local AI Services
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
# Shared AI external pod
|
|
||||||
PublishPort=8080:8080
|
|
||||||
|
|
||||||
# Open Webui base image
|
|
||||||
Image=ghcr.io/open-webui/open-webui:main
|
|
||||||
|
|
||||||
# Nothing too complicated here. Open Webui will basically configure itself.
|
|
||||||
Volume=open-webui-data:/app/backend/data
|
|
||||||
|
|
||||||
# WEBUI_SECRET_KEY is required to prevent logout on Restart
|
|
||||||
EnvironmentFile=/home/ai/.env/open-webui-env
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
# Extend Timeout to allow time to pull the image
|
|
||||||
TimeoutStartSec=900
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
# Start by default on boot
|
|
||||||
WantedBy=multi-user.target default.target
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=A Stable Diffusion CPP Server for Editing Images
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
# Shared AI internal pod without internet access
|
|
||||||
Pod=ai-internal.pod
|
|
||||||
|
|
||||||
# Vulkan image for AMD GPU
|
|
||||||
Image=localhost/stable-diffusion-cpp:latest
|
|
||||||
|
|
||||||
# Shared models directory
|
|
||||||
Volume=/home/ai/models:/models:z
|
|
||||||
|
|
||||||
# GPU Device
|
|
||||||
AddDevice=/dev/kfd
|
|
||||||
AddDevice=/dev/dri
|
|
||||||
|
|
||||||
# Override entrypoint to use server
|
|
||||||
Entrypoint=/sd-server
|
|
||||||
|
|
||||||
# Server args
|
|
||||||
Exec=-l 0.0.0.0 \
|
|
||||||
--listen-port 1235 \
|
|
||||||
--diffusion-model /models/image/flux2-klein/flux-2-klein-9b-Q8_0.gguf \
|
|
||||||
--vae /models/image/flux2-klein/ae.safetensors \
|
|
||||||
--llm /models/image/flux2-klein/Qwen3-8B-Q4_K_M.gguf \
|
|
||||||
-v \
|
|
||||||
--sampling-method euler \
|
|
||||||
--cfg-scale 1.0 \
|
|
||||||
--vae-conv-direct \
|
|
||||||
--diffusion-conv-direct \
|
|
||||||
--fa \
|
|
||||||
--mmap \
|
|
||||||
--seed -1 \
|
|
||||||
--steps 5
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
# Extend Timeout to allow time to pull the image
|
|
||||||
TimeoutStartSec=900
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
# Start by default on boot
|
|
||||||
WantedBy=multi-user.target default.target
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=A Stable Diffusion CPP Server for Generating Images
|
|
||||||
|
|
||||||
[Container]
|
|
||||||
# Shared AI internal pod without internet access
|
|
||||||
Pod=ai-internal.pod
|
|
||||||
|
|
||||||
# Vulkan image for AMD GPU
|
|
||||||
Image=localhost/stable-diffusion-cpp:latest
|
|
||||||
|
|
||||||
# Shared models directory
|
|
||||||
Volume=/home/ai/models:/models:z
|
|
||||||
|
|
||||||
# GPU Device
|
|
||||||
AddDevice=/dev/kfd
|
|
||||||
AddDevice=/dev/dri
|
|
||||||
|
|
||||||
# Override entrypoint to use server
|
|
||||||
Entrypoint=/sd-server
|
|
||||||
|
|
||||||
# Server args
|
|
||||||
Exec=-l 0.0.0.0 \
|
|
||||||
--listen-port 1234 \
|
|
||||||
--diffusion-model /models/image/z-turbo/z_image_turbo-Q8_0.gguf \
|
|
||||||
--vae /models/image/z-turbo/ae.safetensors \
|
|
||||||
--llm /models/image/z-turbo/Qwen3-4B-Instruct-2507-Q4_K_M.gguf \
|
|
||||||
-v \
|
|
||||||
--cfg-scale 1.0 \
|
|
||||||
--vae-conv-direct \
|
|
||||||
--diffusion-conv-direct \
|
|
||||||
--fa \
|
|
||||||
--mmap \
|
|
||||||
--seed -1 \
|
|
||||||
--steps 8
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Restart=always
|
|
||||||
# Extend Timeout to allow time to pull the image
|
|
||||||
TimeoutStartSec=900
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
# Start by default on boot
|
|
||||||
WantedBy=multi-user.target default.target
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Start open-webui-guest on schedule
|
|
||||||
Wants=open-webui-guest.service
|
|
||||||
After=open-webui-guest.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
ExecStart=/bin/systemctl --user start open-webui-guest.service
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Timer to start open-webui-guest at 08:00 Mon‑Fri
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnCalendar=Mon..Fri *-*-* 08:00:00
|
|
||||||
Persistent=true
|
|
||||||
Unit=open-webui-guest-start.service
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=timers.target
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Stop open-webui-guest on schedule
|
|
||||||
After=open-webui-guest.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
ExecStart=/bin/systemctl --user stop open-webui-guest.service
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Timer to stop open-webui-guest at 18:00 Mon‑Fri
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnCalendar=Mon..Fri *-*-* 18:00:00
|
|
||||||
Persistent=true
|
|
||||||
Unit=open-webui-guest-stop.service
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=timers.target
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Konsole
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
- To open new tabs with the same profile as the current tab, assign the "clone tab" keyboard shortcut to <ctrl>+<shift>+<T>.
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
name = "fedora44-base"
|
||||||
|
description = "Fedora Base Installation"
|
||||||
|
version = "0.2.3"
|
||||||
|
distro = "fedora-44"
|
||||||
|
modules = []
|
||||||
|
groups = []
|
||||||
|
|
||||||
|
[customizations]
|
||||||
|
hostname = "fedora44-base"
|
||||||
|
|
||||||
|
[customizations.timezone]
|
||||||
|
timezone = "America/New_York"
|
||||||
|
|
||||||
|
[[customizations.disk.partitions]]
|
||||||
|
type = "plain"
|
||||||
|
label = "root"
|
||||||
|
mountpoint = "/"
|
||||||
|
fs_type = "ext4"
|
||||||
|
minsize = "128 GiB"
|
||||||
|
|
||||||
|
[customizations.firewall.services]
|
||||||
|
enabled = ["ssh", "cockpit"]
|
||||||
|
|
||||||
|
[customizations.services]
|
||||||
|
enabled = ["sshd", "cockpit.socket"]
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "bash-completion"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "tmux"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "openssh-server"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "vim"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "git"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "cockpit"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "borgbackup"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "policycoreutils-python-utils"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[packages]]
|
||||||
|
name = "systemd-container"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[customizations.files]]
|
||||||
|
path = "/root/.inputrc"
|
||||||
|
mode = "0644"
|
||||||
|
user = "root"
|
||||||
|
group = "root"
|
||||||
|
data = """
|
||||||
|
"\\C-h": backward-kill-word
|
||||||
|
"""
|
||||||
|
|
||||||
|
[[customizations.files]]
|
||||||
|
path = "/root/.ssh/authorized_keys"
|
||||||
|
mode = "0600"
|
||||||
|
user = "root"
|
||||||
|
group = "root"
|
||||||
|
data = """
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQa781Qj8mNlUdRquFFqg0O2ornG9SBHe705y4+1vPI ssh@ducoterra.net
|
||||||
|
"""
|
||||||
@@ -29,6 +29,8 @@ dnf install -y osbuild-composer composer-cli
|
|||||||
systemctl enable --now osbuild-composer.socket
|
systemctl enable --now osbuild-composer.socket
|
||||||
|
|
||||||
# Optional: add your user to the weldr group
|
# Optional: add your user to the weldr group
|
||||||
|
# On fedora kinoite (atomic) you'll need to add the group manually for now
|
||||||
|
grep -E '^weldr:' /usr/lib/group | sudo tee -a /etc/group
|
||||||
sudo usermod -aG weldr $USER
|
sudo usermod -aG weldr $USER
|
||||||
|
|
||||||
# Optional: cockpit dependency
|
# Optional: cockpit dependency
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Podman
|
||||||
|
|
||||||
|
## Networks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a podman network to group shared containers
|
||||||
|
podman network create test1
|
||||||
|
# Create an iperf3 container running on that network
|
||||||
|
podman run -d --name iperf3 --network test1 docker.io/networkstatic/iperf3 -s
|
||||||
|
# A container running in the same network can reference another pod by its name
|
||||||
|
podman run --rm -it --network test1 docker.io/networkstatic/iperf3 -c iperf3
|
||||||
|
# A container outside the created network can't talk to other containers
|
||||||
|
# This will fail
|
||||||
|
podman run --rm -it docker.io/networkstatic/iperf3 -c iperf3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Healthchecks
|
||||||
|
|
||||||
|
TCP Healthchecks can be accomplished with netcat (netcat-openbsd)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
podman run -d --name iperf3 \
|
||||||
|
--health-cmd='CMD-SHELL iperf3 -n 1 -c localhost' \
|
||||||
|
--health-interval=10s --health-timeout=5s --health-retries=3 \
|
||||||
|
docker.io/networkstatic/iperf3 iperf3 -s
|
||||||
|
```
|
||||||
|
|
||||||
|
HTTP Healthchecks can be accomplished with curl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
podman run -d --name nginx \
|
||||||
|
--health-cmd='CMD-SHELL curl --fail http://127.0.0.1:80 || exit 1' \
|
||||||
|
--health-interval=10s --health-timeout=5s --health-retries=3 \
|
||||||
|
docker.io/nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
Check healthchecks with
|
||||||
|
|
||||||
|
```bash
|
||||||
|
podman --log-level debug healthcheck run <container>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Volume Import and Export
|
||||||
|
|
||||||
|
```bash
|
||||||
|
podman volume export myvol --output myvol.tar
|
||||||
|
podman volume import myvol test.tar
|
||||||
|
```
|
||||||
@@ -30,11 +30,17 @@ sudo smbpasswd -a sambauser
|
|||||||
## Create a SMB Share
|
## Create a SMB Share
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Add the share user
|
||||||
|
sudo useradd -r -M -s /usr/sbin/nologin sambauser
|
||||||
|
sudo smbpasswd -a sambauser
|
||||||
|
|
||||||
# Create share
|
# Create share
|
||||||
mkdir /srv/smb/sambauser
|
sudo mkdir /srv/smb/sambauser
|
||||||
|
sudo chown -R sambauser:sambauser /srv/smb/sambauser
|
||||||
|
sudo chmod -R 2770 /srv/samba/sambauser
|
||||||
|
|
||||||
# Set proper selinux labels for samba
|
# Set proper selinux labels for samba
|
||||||
sudo semanage fcontext --add --type "samba_share_t" "/srv/smb(/.*)?"
|
sudo semanage fcontext --add --type "samba_share_t" "/srv/smb/sambauser"
|
||||||
|
|
||||||
# Run restorecon at the root of the btrfs subvolume
|
# Run restorecon at the root of the btrfs subvolume
|
||||||
sudo restorecon -FRv /srv
|
sudo restorecon -FRv /srv
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
FROM registry.fedoraproject.org/fedora-toolbox:44
|
||||||
|
|
||||||
|
COPY vscodium.repo /etc/yum.repos.d/vscodium.repo
|
||||||
|
|
||||||
|
RUN dnf install -y \
|
||||||
|
vim git btop \
|
||||||
|
virt-manager virt-install \
|
||||||
|
podman podman-compose \
|
||||||
|
wl-clipboard \
|
||||||
|
jq yq rg \
|
||||||
|
kubectl helm \
|
||||||
|
pinentry \
|
||||||
|
pandoc \
|
||||||
|
iperf3 \
|
||||||
|
nethogs \
|
||||||
|
ansible \
|
||||||
|
tmux \
|
||||||
|
wine \
|
||||||
|
unzip \
|
||||||
|
ImageMagick \
|
||||||
|
go \
|
||||||
|
rust rustup \
|
||||||
|
git git-lfs \
|
||||||
|
net-tools \
|
||||||
|
texlive-latex texlive-scheme-full \
|
||||||
|
pwgen \
|
||||||
|
reptyr \
|
||||||
|
netcat \
|
||||||
|
p7zip \
|
||||||
|
make \
|
||||||
|
gcc \
|
||||||
|
codium \
|
||||||
|
pass
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Toolbox
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
```bash
|
||||||
|
podman build -t localhost/fedora-toolbox:44 active/software_toolbx
|
||||||
|
```
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[gitlab.com_paulcarroty_vscodium_repo]
|
||||||
|
name=gitlab.com_paulcarroty_vscodium_repo
|
||||||
|
baseurl=https://paulcarroty.gitlab.io/vscodium-deb-rpm-repo/rpms/
|
||||||
|
enabled=1
|
||||||
|
gpgcheck=1
|
||||||
|
repo_gpgcheck=1
|
||||||
|
gpgkey=https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg
|
||||||
|
metadata_expire=1h
|
||||||
|
|
||||||
@@ -40,7 +40,6 @@ Virtual Machine Management
|
|||||||
<https://libvirt.org/uri.html#ssh-transport>
|
<https://libvirt.org/uri.html#ssh-transport>
|
||||||
|
|
||||||
### Configuring Aliases
|
### Configuring Aliases
|
||||||
|
|
||||||
1. Edit `~/.config/libvirt/libvirt.conf`
|
1. Edit `~/.config/libvirt/libvirt.conf`
|
||||||
2. Add your aliases
|
2. Add your aliases
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import smtplib
|
import smtplib
|
||||||
import ssl
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable, TypedDict, cast
|
from typing import Iterable, TypedDict, cast
|
||||||
|
|
||||||
|
import requests
|
||||||
from dotenv import dotenv_values, load_dotenv
|
from dotenv import dotenv_values, load_dotenv
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from openai.types.chat import ChatCompletionMessageParam, ChatCompletionToolUnionParam
|
from openai.types.chat import ChatCompletionMessageParam, ChatCompletionToolUnionParam
|
||||||
|
|
||||||
|
|
||||||
class AWS_SES_DOTENV(TypedDict):
|
class NTFY_DOTENV(TypedDict):
|
||||||
USER: str
|
TOKEN: str
|
||||||
PASSWORD: str
|
|
||||||
ENDPOINT: str
|
|
||||||
TLS_PORT: str
|
|
||||||
SENDER: str
|
|
||||||
RECEIVER: str
|
|
||||||
|
|
||||||
|
|
||||||
class ToolCallController:
|
class ToolCallController:
|
||||||
@@ -209,39 +204,30 @@ def smartctl(device_path: str) -> str:
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def load_ses_creds() -> AWS_SES_DOTENV:
|
def load_ntfy_creds() -> NTFY_DOTENV:
|
||||||
ses_dotenv_location = Path(os.getenv("HOME", "/root"), ".env/aws_ses")
|
ses_dotenv_location = Path(os.getenv("HOME", "/root"), ".env/aws_ses")
|
||||||
print(f"Loading env from {ses_dotenv_location}")
|
print(f"Loading env from {ses_dotenv_location}")
|
||||||
raw_values = dotenv_values(ses_dotenv_location)
|
raw_values = dotenv_values(ses_dotenv_location)
|
||||||
if raw_values:
|
if raw_values:
|
||||||
aws_ses_config = cast(AWS_SES_DOTENV, raw_values)
|
ntfy_config = cast(NTFY_DOTENV, raw_values)
|
||||||
# print(f"AWS SES Credentials loaded: {aws_ses_config}")
|
# print(f"AWS SES Credentials loaded: {aws_ses_config}")
|
||||||
return aws_ses_config
|
return ntfy_config
|
||||||
print("No email credentials supplied. Exiting.")
|
print("No ntfy credentials supplied. Exiting.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
def alert_user(message: str) -> str:
|
def alert_user(message: str) -> str:
|
||||||
ses_config = load_ses_creds()
|
ntfy_creds = load_ntfy_creds()
|
||||||
port = int(ses_config["TLS_PORT"])
|
|
||||||
user = ses_config["USER"]
|
|
||||||
password = ses_config["PASSWORD"]
|
|
||||||
sender = ses_config["SENDER"]
|
|
||||||
receiver = ses_config["RECEIVER"]
|
|
||||||
|
|
||||||
# Create a secure SSL context
|
requests.post(
|
||||||
context = ssl.create_default_context()
|
"https://ntfy.reeseapps.com/servers",
|
||||||
|
data=message,
|
||||||
msg = EmailMessage()
|
headers={
|
||||||
msg["Subject"] = "Agent Disk Report"
|
"Authorization": f"Bearer {ntfy_creds['TOKEN']}",
|
||||||
msg["From"] = sender
|
"Title": "Agent Disk Report",
|
||||||
msg["To"] = receiver
|
"Priority": "default",
|
||||||
msg.set_content(message)
|
},
|
||||||
|
)
|
||||||
with smtplib.SMTP_SSL(ses_config["ENDPOINT"], port, context=context) as server:
|
|
||||||
server.login(user, password)
|
|
||||||
result = server.send_message(msg)
|
|
||||||
print(result)
|
|
||||||
|
|
||||||
return "Sent."
|
return "Sent."
|
||||||
|
|
||||||
@@ -322,13 +308,14 @@ def run_conversation(user_message: str, max_tool_calls=10):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
api_key = os.getenv("OPENAI_API_KEY", "")
|
api_key = os.getenv("OPENAI_API_KEY", "")
|
||||||
client = OpenAI(base_url="https://llama-think.reeselink.com", api_key=api_key)
|
client = OpenAI(base_url="https://aipi.reeseapps.com", api_key=api_key)
|
||||||
# Example usage
|
# Example usage
|
||||||
print(
|
print(
|
||||||
run_conversation(
|
run_conversation(
|
||||||
"Check the btrfs pools on this system. Take the appropriate action if any pools aren't "
|
"Check the btrfs pools on this system. Take the appropriate action if any pools aren't "
|
||||||
"healthy. Don't run scrubs unless necessary. Also check the btrfs pool space and report "
|
"healthy. Don't run scrubs unless necessary. Also check the btrfs pool space and report "
|
||||||
"if any are getting full. At the very end of performing your checks send a single, "
|
"if any are getting full. At the very end of performing your checks send a single, "
|
||||||
"concise message to the user explaining what you did and what concerns you might have."
|
"concise message to the user via the alert_user tool explaining what you did and "
|
||||||
|
"what concerns you might have."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
# Proxy Automation
|
|
||||||
|
|
||||||
1. Create or update the reeselink.com address in Unifi
|
|
||||||
2. Create or update the entry in the ddns values
|
|
||||||
3. Create or update the entry in the caddy values
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
3.13
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# Update
|
|
||||||
|
|
||||||
Updates every server in the fleet
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
uv run automations/updates/main.py
|
|
||||||
```
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
import time
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
print("Retrieving hosts")
|
|
||||||
with open("ansible/inventory.yaml", "r") as f:
|
|
||||||
all_hosts = yaml.load(f, yaml.SafeLoader)
|
|
||||||
fedora_hosts = all_hosts["fedora"]["hosts"].keys()
|
|
||||||
|
|
||||||
with open("update.log", "w") as log_file:
|
|
||||||
for _, host in enumerate(tqdm(fedora_hosts, desc="Running system updates")):
|
|
||||||
log_file.write(f"Updating {host}\n")
|
|
||||||
log_file.flush()
|
|
||||||
try:
|
|
||||||
subprocess.run(
|
|
||||||
["ssh", host, "dnf", "upgrade", "-y"],
|
|
||||||
stdout=log_file,
|
|
||||||
stderr=log_file,
|
|
||||||
check=True,
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
log_file.write(f"Couldn't connect to {host}. Skipping...\n")
|
|
||||||
continue
|
|
||||||
log_file.flush()
|
|
||||||
log_file.write(f"Rebooting {host}\n")
|
|
||||||
log_file.flush()
|
|
||||||
subprocess.run(
|
|
||||||
["ssh", host, "reboot"],
|
|
||||||
stdout=log_file,
|
|
||||||
stderr=log_file,
|
|
||||||
check=True,
|
|
||||||
)
|
|
||||||
time.sleep(5) # wait for reboot to take effect
|
|
||||||
booted = False
|
|
||||||
max_attempts = 10
|
|
||||||
cur_attempts = 0
|
|
||||||
while max_attempts > cur_attempts and not booted:
|
|
||||||
try:
|
|
||||||
subprocess.run(
|
|
||||||
["ssh", host, "echo"],
|
|
||||||
stdout=log_file,
|
|
||||||
stderr=log_file,
|
|
||||||
check=True,
|
|
||||||
timeout=2,
|
|
||||||
)
|
|
||||||
log_file.write(f"{host} booted!\n")
|
|
||||||
log_file.flush()
|
|
||||||
booted = True
|
|
||||||
except Exception as e:
|
|
||||||
cur_attempts += 1
|
|
||||||
log_file.write(f"Waiting for {host} to reboot\n")
|
|
||||||
log_file.flush()
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
if cur_attempts >= max_attempts:
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "updates"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Update servers based on ansible inventory"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.13"
|
|
||||||
dependencies = [
|
|
||||||
"pyyaml>=6.0.3",
|
|
||||||
"tqdm>=4.67.3",
|
|
||||||
"types-pyyaml>=6.0.12.20250915",
|
|
||||||
"types-tqdm>=4.67.3.20260205",
|
|
||||||
]
|
|
||||||
Generated
-121
@@ -1,121 +0,0 @@
|
|||||||
version = 1
|
|
||||||
revision = 3
|
|
||||||
requires-python = ">=3.13"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "colorama"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyyaml"
|
|
||||||
version = "6.0.3"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tqdm"
|
|
||||||
version = "4.67.3"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "types-pyyaml"
|
|
||||||
version = "6.0.12.20250915"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "types-requests"
|
|
||||||
version = "2.32.4.20260107"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "urllib3" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d", size = 20676, upload-time = "2026-01-07T03:20:52.929Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "types-tqdm"
|
|
||||||
version = "4.67.3.20260205"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "types-requests" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/53/46/790b9872523a48163bdda87d47849b4466017640e5259d06eed539340afd/types_tqdm-4.67.3.20260205.tar.gz", hash = "sha256:f3023682d4aa3bbbf908c8c6bb35f35692d319460d9bbd3e646e8852f3dd9f85", size = 17597, upload-time = "2026-02-05T04:03:19.721Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/cc/da/7f761868dbaa328392356fab30c18ab90d14cce86b269e7e63328f29d4a3/types_tqdm-4.67.3.20260205-py3-none-any.whl", hash = "sha256:85c31731e81dc3c5cecc34c6c8b2e5166fafa722468f58840c2b5ac6a8c5c173", size = 23894, upload-time = "2026-02-05T04:03:18.48Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "updates"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = { virtual = "." }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "pyyaml" },
|
|
||||||
{ name = "tqdm" },
|
|
||||||
{ name = "types-pyyaml" },
|
|
||||||
{ name = "types-tqdm" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.metadata]
|
|
||||||
requires-dist = [
|
|
||||||
{ name = "pyyaml", specifier = ">=6.0.3" },
|
|
||||||
{ name = "tqdm", specifier = ">=4.67.3" },
|
|
||||||
{ name = "types-pyyaml", specifier = ">=6.0.12.20250915" },
|
|
||||||
{ name = "types-tqdm", specifier = ">=4.67.3.20260205" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "urllib3"
|
|
||||||
version = "2.6.3"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
|
||||||
]
|
|
||||||
@@ -16,6 +16,7 @@ dependencies = [
|
|||||||
"pytest>=9.0.2",
|
"pytest>=9.0.2",
|
||||||
"pyyaml>=6.0.3",
|
"pyyaml>=6.0.3",
|
||||||
"requests>=2.32.5",
|
"requests>=2.32.5",
|
||||||
|
"rich>=15.0.0",
|
||||||
"sse-starlette>=3.3.4",
|
"sse-starlette>=3.3.4",
|
||||||
"tqdm>=4.67.3",
|
"tqdm>=4.67.3",
|
||||||
"types-pyyaml>=6.0.12.20250915",
|
"types-pyyaml>=6.0.12.20250915",
|
||||||
|
|||||||
Submodule
+1
Submodule retired/kubernetes_userspace added at 18f62b5fb0
@@ -285,6 +285,7 @@ dependencies = [
|
|||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pyyaml" },
|
{ name = "pyyaml" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
|
{ name = "rich" },
|
||||||
{ name = "sse-starlette" },
|
{ name = "sse-starlette" },
|
||||||
{ name = "tqdm" },
|
{ name = "tqdm" },
|
||||||
{ name = "types-pyyaml" },
|
{ name = "types-pyyaml" },
|
||||||
@@ -307,6 +308,7 @@ requires-dist = [
|
|||||||
{ name = "pytest", specifier = ">=9.0.2" },
|
{ name = "pytest", specifier = ">=9.0.2" },
|
||||||
{ name = "pyyaml", specifier = ">=6.0.3" },
|
{ name = "pyyaml", specifier = ">=6.0.3" },
|
||||||
{ name = "requests", specifier = ">=2.32.5" },
|
{ name = "requests", specifier = ">=2.32.5" },
|
||||||
|
{ name = "rich", specifier = ">=15.0.0" },
|
||||||
{ name = "sse-starlette", specifier = ">=3.3.4" },
|
{ name = "sse-starlette", specifier = ">=3.3.4" },
|
||||||
{ name = "tqdm", specifier = ">=4.67.3" },
|
{ name = "tqdm", specifier = ">=4.67.3" },
|
||||||
{ name = "types-pyyaml", specifier = ">=6.0.12.20250915" },
|
{ name = "types-pyyaml", specifier = ">=6.0.12.20250915" },
|
||||||
@@ -612,6 +614,18 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" },
|
{ url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown-it-py"
|
||||||
|
version = "4.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mdurl" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markupsafe"
|
name = "markupsafe"
|
||||||
version = "3.0.3"
|
version = "3.0.3"
|
||||||
@@ -689,6 +703,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl", hash = "sha256:5ce1fa81614958e267b21fb2aa34e0aea8e2c6ede60d52aba45fd47246b4d741", size = 215967, upload-time = "2026-04-02T14:48:07.24Z" },
|
{ url = "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl", hash = "sha256:5ce1fa81614958e267b21fb2aa34e0aea8e2c6ede60d52aba45fd47246b4d741", size = 215967, upload-time = "2026-04-02T14:48:07.24Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdurl"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mergedeep"
|
name = "mergedeep"
|
||||||
version = "1.3.4"
|
version = "1.3.4"
|
||||||
@@ -1259,6 +1282,19 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
|
{ url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rich"
|
||||||
|
version = "15.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "markdown-it-py" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rpds-py"
|
name = "rpds-py"
|
||||||
version = "0.30.0"
|
version = "0.30.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user