From d9ff25e04ea6e0c3f92420e7d2e59c427d8dd791 Mon Sep 17 00:00:00 2001 From: Akiru Date: Thu, 25 Jan 2024 08:31:43 +0000 Subject: [PATCH 01/12] =?UTF-8?q?monitoring/Readme.md=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- monitoring/Readme.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 monitoring/Readme.md diff --git a/monitoring/Readme.md b/monitoring/Readme.md new file mode 100644 index 0000000..0d28450 --- /dev/null +++ b/monitoring/Readme.md @@ -0,0 +1 @@ +These scripts exist to automatically restart the bot in case of errors and connectivity issues. They should either be run as systemd services or cronjobs. \ No newline at end of file From ffff9c87ef6e0ccaebf27a63d123c2a78354ddf4 Mon Sep 17 00:00:00 2001 From: Akiru Date: Thu, 25 Jan 2024 08:35:11 +0000 Subject: [PATCH 02/12] =?UTF-8?q?monitoring/monitoring.sh=20hinzugef=C3=BC?= =?UTF-8?q?gt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- monitoring/monitoring.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 monitoring/monitoring.sh diff --git a/monitoring/monitoring.sh b/monitoring/monitoring.sh new file mode 100644 index 0000000..84abdbc --- /dev/null +++ b/monitoring/monitoring.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# This script has to be run as systemd service. It checks journalctl output for errors and restarts the bot automatically when they occur too often. + +# Define the regex pattern to search for occurrences of "GrammyError" and "sendMediaGroup" +ERROR_PATTERN="GrammyError.*sendMediaGroup" + +# Initialize the counter for consecutive occurrences +error_count=0 + +# Monitor the journalctl output +journalctl -xe -f | while read line; do + # Check if the line contains the pattern + if echo "$line" | grep -qE "$ERROR_PATTERN"; then + # Increment the error counter + ((error_count++)) + + # Check if the error has occurred 4 times in a row + if [ $error_count -eq 4 ]; then + # Restart the bot service + systemctl restart nyxthebot + # Reset the error counter + error_count=0 + fi + else + # Reset the error counter if the line does not contain the error + error_count=0 + fi +done From aefbc63a4671f97bca30524661b5215b16e87172 Mon Sep 17 00:00:00 2001 From: Akiru Date: Thu, 25 Jan 2024 08:38:14 +0000 Subject: [PATCH 03/12] =?UTF-8?q?monitoring/sleepy.sh=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- monitoring/sleepy.sh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 monitoring/sleepy.sh diff --git a/monitoring/sleepy.sh b/monitoring/sleepy.sh new file mode 100644 index 0000000..2bf0128 --- /dev/null +++ b/monitoring/sleepy.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# When the bot gets eepy sleepy, this script will restart it. It happens, when no jobs come in for multiple minutes. +# The script interfaces with the REST API of the bot and checks if the image count has changed. +# Run this script as cronjob all 4-5 minutes. + +# Define the URL and the stats file path +URL="https://YOUR_URL/api/stats" +STATS_FILE="YOUR_FILE_PATH/stats.txt" + +# Fetch the data and extract imageCount +imageCount=$(curl -s "$URL" | jq '.imageCount') + +# Check if stats file exists and read the last value +if [ -f "$STATS_FILE" ]; then + lastValue=$(tail -n 1 "$STATS_FILE") +else + lastValue="" +fi + +# Save the new value to the file +echo "$imageCount" >> "$STATS_FILE" + +# Keep only the last 2 values in the file +tail -n 2 "$STATS_FILE" > "$STATS_FILE.tmp" && mv "$STATS_FILE.tmp" "$STATS_FILE" + +# Compare the two values and restart the service if they are the same +if [ "$lastValue" == "$imageCount" ]; then + systemctl restart nyxthebot +fi From 85bd9b58615c10cf67a799cac5ea826179911f31 Mon Sep 17 00:00:00 2001 From: Akiru Date: Thu, 25 Jan 2024 08:51:39 +0000 Subject: [PATCH 04/12] bot/mod.ts aktualisiert --- bot/mod.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bot/mod.ts b/bot/mod.ts index 6f7fdda..527956a 100644 --- a/bot/mod.ts +++ b/bot/mod.ts @@ -13,6 +13,16 @@ import { pnginfoCommand, pnginfoQuestion } from "./pnginfoCommand.ts"; import { queueCommand } from "./queueCommand.ts"; import { txt2imgCommand, txt2imgQuestion } from "./txt2imgCommand.ts"; +// This section sets the configuration into the database. Limits the jobs per user and maximum jobs to safe defaults. +import { setConfig, getConfig } from "../app/config.ts"; + +// Set the new configuration +await setConfig({ maxUserJobs: 1, maxJobs: 500 }); + +// Log the updated configuration to the console, for debugging. +// const updatedConfig = await getConfig(); +// console.log("Updated Configuration:", updatedConfig); + interface SessionData { chat: ErisChatData; user: ErisUserData; From 128c4312d4dc8fe6557c80c1ce0028dda8a790a5 Mon Sep 17 00:00:00 2001 From: Akiru Date: Thu, 25 Jan 2024 08:53:35 +0000 Subject: [PATCH 05/12] ui/StatsPage.tsx aktualisiert Make the counters update faster to make it look more snappy. --- ui/StatsPage.tsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ui/StatsPage.tsx b/ui/StatsPage.tsx index 8c0cabe..c0c3201 100644 --- a/ui/StatsPage.tsx +++ b/ui/StatsPage.tsx @@ -7,7 +7,7 @@ export function StatsPage() { const getGlobalStats = useSWR( ["/stats", {}] as const, (args) => fetchApi(...args).then(handleResponse), - { refreshInterval: 2_000 }, + { refreshInterval: 1_00 }, ); return ( @@ -18,13 +18,13 @@ export function StatsPage() { className="font-bold text-zinc-700 dark:text-zinc-300" value={getGlobalStats.data?.pixelStepCount ?? 0} digits={15} - transitionDurationMs={3_000} + transitionDurationMs={1_00} />

@@ -34,13 +34,13 @@ export function StatsPage() { className="font-bold text-zinc-700 dark:text-zinc-300" value={getGlobalStats.data?.pixelCount ?? 0} digits={15} - transitionDurationMs={3_000} + transitionDurationMs={1_00} />

@@ -51,14 +51,14 @@ export function StatsPage() { className="font-bold text-zinc-700 dark:text-zinc-300" value={getGlobalStats.data?.stepCount ?? 0} digits={9} - transitionDurationMs={3_000} + transitionDurationMs={1_00} />

@@ -68,14 +68,14 @@ export function StatsPage() { className="font-bold text-zinc-700 dark:text-zinc-300" value={getGlobalStats.data?.imageCount ?? 0} digits={9} - transitionDurationMs={3_000} + transitionDurationMs={1_00} />

@@ -86,7 +86,7 @@ export function StatsPage() { className="font-bold text-zinc-700 dark:text-zinc-300" value={getGlobalStats.data?.userCount ?? 0} digits={6} - transitionDurationMs={1_500} + transitionDurationMs={1_00} />

From 29161fa58a3d4dc7be64d43b18f45c1fb5c3f667 Mon Sep 17 00:00:00 2001 From: Akiru Date: Thu, 25 Jan 2024 09:01:23 +0000 Subject: [PATCH 06/12] main.ts aktualisiert --- main.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/main.ts b/main.ts index 43a8d72..99ab22b 100644 --- a/main.ts +++ b/main.ts @@ -4,7 +4,9 @@ import { ConsoleHandler } from "std/log/handlers.ts"; import { LevelName, setup } from "std/log/mod.ts"; import { serveUi } from "./api/mod.ts"; import { runAllTasks } from "./app/mod.ts"; -import { runBot } from "./bot/mod.ts"; +// runbot shouldn't be needed for webhooks? +// import { runBot } from "./bot/mod.ts"; +import "./bot/mod.ts"; const logLevel = Deno.env.get("LOG_LEVEL")?.toUpperCase() as LevelName ?? "INFO"; @@ -20,7 +22,8 @@ setup({ // run parts of the app await Promise.all([ - runBot(), +// runbot shouldn't be needed for webhooks? +// runBot(), runAllTasks(), serveUi(), ]); From 04b0f9bdf5b41aad4b9b4866eb797361933c5526 Mon Sep 17 00:00:00 2001 From: Akiru Date: Thu, 25 Jan 2024 09:08:16 +0000 Subject: [PATCH 07/12] bot/mod.ts aktualisiert --- bot/mod.ts | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/bot/mod.ts b/bot/mod.ts index 527956a..71177bf 100644 --- a/bot/mod.ts +++ b/bot/mod.ts @@ -1,7 +1,11 @@ + +// This new serve here is an issue, since there is already another serve for the UI in /api/mod.ts +import { serve } from "https://deno.land/std/http/server.ts"; +// End of issue +import { sequentialize } from "grammy_runner"; import { Api, Bot, Context, RawApi, session, SessionFlavor } from "grammy"; import { FileFlavor, hydrateFiles } from "grammy_files"; import { hydrateReply, ParseModeFlavor } from "grammy_parse_mode"; -import { run, sequentialize } from "grammy_runner"; import { error, info, warning } from "std/log/mod.ts"; import { sessions } from "../api/sessionsRoute.ts"; import { formatUserChat } from "../utils/formatUserChat.ts"; @@ -13,16 +17,6 @@ import { pnginfoCommand, pnginfoQuestion } from "./pnginfoCommand.ts"; import { queueCommand } from "./queueCommand.ts"; import { txt2imgCommand, txt2imgQuestion } from "./txt2imgCommand.ts"; -// This section sets the configuration into the database. Limits the jobs per user and maximum jobs to safe defaults. -import { setConfig, getConfig } from "../app/config.ts"; - -// Set the new configuration -await setConfig({ maxUserJobs: 1, maxJobs: 500 }); - -// Log the updated configuration to the console, for debugging. -// const updatedConfig = await getConfig(); -// console.log("Updated Configuration:", updatedConfig); - interface SessionData { chat: ErisChatData; user: ErisUserData; @@ -183,7 +177,35 @@ bot.command("crash", () => { throw new Error("Crash command used"); }); -export async function runBot() { - const runner = run(bot, { runner: { silent: true } }); - await runner.task(); +// New section that uses a webhook instead of long polling. + +// Set up the webhook and initialize the bot +await bot.api.setWebhook('https://YOUR_URL:8443/webhook'); +await bot.init(); + +// Function to handle incoming requests +async function handleRequest(req: Request): Promise { + if (req.method === "POST" && new URL(req.url).pathname === "/webhook") { + try { + const body = await req.json(); + console.log("Received webhook data:", JSON.stringify(body, null, 2)); + + // Log before processing update + console.log("Processing update through handleUpdate..."); + await bot.handleUpdate(body); // Process the update + // Log after processing update + console.log("Update processed successfully."); + + return new Response(JSON.stringify({ status: 'ok' }), { headers: { 'Content-Type': 'application/json' } }); + } catch (error) { + // Detailed error logging + console.error("Error in handleRequest or handleUpdate:", error); + return new Response("Error", { status: 500 }); + } + } + return new Response("Not Found", { status: 404 }); } + +// Start the server +console.log("Listening for webhooks on https://nyx.akiru.de:8443/webhook"); +await serve(handleRequest, { port: 8443 }); From a7e41b63df6cea26f01ed5f80f49d72eca02229e Mon Sep 17 00:00:00 2001 From: Akiru Date: Fri, 26 Jan 2024 07:30:42 +0000 Subject: [PATCH 08/12] api/mod.ts aktualisiert Create "async function handleWebhook" --- api/mod.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/api/mod.ts b/api/mod.ts index d59b472..c03b8fa 100644 --- a/api/mod.ts +++ b/api/mod.ts @@ -3,10 +3,34 @@ import { serveSpa } from "serve_spa"; import { api } from "./serveApi.ts"; import { fromFileUrl } from "std/path/mod.ts"; +// Export the Webhook Route function so it can be used in bot/mod.ts +export async function handleWebhook(req: Request): Promise { + if (req.method === "POST" && new URL(req.url).pathname === "/webhook") { + try { + const body = await req.json(); + console.log("Received webhook data:", JSON.stringify(body, null, 2)); + + // Log before processing update + console.log("Processing update through handleUpdate..."); + await bot.handleUpdate(body); // Process the update + // Log after processing update + console.log("Update processed successfully."); + + return new Response(JSON.stringify({ status: 'ok' }), { headers: { 'Content-Type': 'application/json' } }); + } catch (error) { + // Detailed error logging + console.error("Error in handleRequest or handleUpdate:", error); + return new Response("Error", { status: 500 }); + } + } + return new Response("Not Found", { status: 404 }); +} + export async function serveUi() { - const server = Deno.serve({ port: 5999 }, (request) => + const server = Deno.serve({ port: 8443 }, (request) => route(request, { "/api/*": (request) => api.fetch(request), + "/webhook": handleWebhook, // Create the Webhook Route handle "/*": (request) => serveSpa(request, { fsRoot: fromFileUrl(new URL("../ui/", import.meta.url)), From c19f8c8f71d7e2e1bd539fe2d82e506c3e4fcce4 Mon Sep 17 00:00:00 2001 From: Akiru Date: Fri, 26 Jan 2024 07:40:32 +0000 Subject: [PATCH 09/12] bot/mod.ts aktualisiert --- bot/mod.ts | 49 ++++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/bot/mod.ts b/bot/mod.ts index 71177bf..1d0e761 100644 --- a/bot/mod.ts +++ b/bot/mod.ts @@ -1,7 +1,3 @@ - -// This new serve here is an issue, since there is already another serve for the UI in /api/mod.ts -import { serve } from "https://deno.land/std/http/server.ts"; -// End of issue import { sequentialize } from "grammy_runner"; import { Api, Bot, Context, RawApi, session, SessionFlavor } from "grammy"; import { FileFlavor, hydrateFiles } from "grammy_files"; @@ -177,35 +173,26 @@ bot.command("crash", () => { throw new Error("Crash command used"); }); -// New section that uses a webhook instead of long polling. - -// Set up the webhook and initialize the bot -await bot.api.setWebhook('https://YOUR_URL:8443/webhook'); +// Set up the webhook in the telegram API and initialize the bot +await bot.api.setWebhook('https://nyxdev.akiru.de:8443/webhook'); await bot.init(); -// Function to handle incoming requests -async function handleRequest(req: Request): Promise { - if (req.method === "POST" && new URL(req.url).pathname === "/webhook") { - try { - const body = await req.json(); - console.log("Received webhook data:", JSON.stringify(body, null, 2)); +// Function to handle incoming webhook requests +export async function handleWebhook(req: Request): Promise { + try { + const body = await req.json(); + console.log("Received webhook data:", JSON.stringify(body, null, 2)); - // Log before processing update - console.log("Processing update through handleUpdate..."); - await bot.handleUpdate(body); // Process the update - // Log after processing update - console.log("Update processed successfully."); + // Log before processing update + console.log("Processing update through handleUpdate..."); + await bot.handleUpdate(body); // Process the update + // Log after processing update + console.log("Update processed successfully."); - return new Response(JSON.stringify({ status: 'ok' }), { headers: { 'Content-Type': 'application/json' } }); - } catch (error) { - // Detailed error logging - console.error("Error in handleRequest or handleUpdate:", error); - return new Response("Error", { status: 500 }); - } + return new Response(JSON.stringify({ status: 'ok' }), { headers: { 'Content-Type': 'application/json' } }); + } catch (error) { + // Detailed error logging + console.error("Error in handleWebhook:", error); + return new Response("Error", { status: 500 }); } - return new Response("Not Found", { status: 404 }); -} - -// Start the server -console.log("Listening for webhooks on https://nyx.akiru.de:8443/webhook"); -await serve(handleRequest, { port: 8443 }); +} \ No newline at end of file From b7a551afc769c45bd72a63dd4b2da293142028a7 Mon Sep 17 00:00:00 2001 From: Akiru Date: Fri, 26 Jan 2024 07:42:44 +0000 Subject: [PATCH 10/12] api/mod.ts aktualisiert --- api/mod.ts | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/api/mod.ts b/api/mod.ts index c03b8fa..c20a30a 100644 --- a/api/mod.ts +++ b/api/mod.ts @@ -2,35 +2,15 @@ import { route } from "reroute"; import { serveSpa } from "serve_spa"; import { api } from "./serveApi.ts"; import { fromFileUrl } from "std/path/mod.ts"; +// New function that handles the webhook +import { handleWebhook } from "../bot/mod.ts"; -// Export the Webhook Route function so it can be used in bot/mod.ts -export async function handleWebhook(req: Request): Promise { - if (req.method === "POST" && new URL(req.url).pathname === "/webhook") { - try { - const body = await req.json(); - console.log("Received webhook data:", JSON.stringify(body, null, 2)); - - // Log before processing update - console.log("Processing update through handleUpdate..."); - await bot.handleUpdate(body); // Process the update - // Log after processing update - console.log("Update processed successfully."); - - return new Response(JSON.stringify({ status: 'ok' }), { headers: { 'Content-Type': 'application/json' } }); - } catch (error) { - // Detailed error logging - console.error("Error in handleRequest or handleUpdate:", error); - return new Response("Error", { status: 500 }); - } - } - return new Response("Not Found", { status: 404 }); -} export async function serveUi() { const server = Deno.serve({ port: 8443 }, (request) => route(request, { "/api/*": (request) => api.fetch(request), - "/webhook": handleWebhook, // Create the Webhook Route handle + "/webhook": handleWebhook, // Create the webhook route handle "/*": (request) => serveSpa(request, { fsRoot: fromFileUrl(new URL("../ui/", import.meta.url)), From 9f75621c706b0173de5c8dc9570adf9a0f792483 Mon Sep 17 00:00:00 2001 From: Akiru Date: Fri, 26 Jan 2024 12:54:05 +0000 Subject: [PATCH 11/12] bot/mod.ts aktualisiert - Comment logging in "handleWebhook" function - Handle Errors when setting the Bot commands so that the entire bot doesn't fail when they can't be set due to a temporary error - Set default configuration for the bot (Job Limit) --- bot/mod.ts | 66 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/bot/mod.ts b/bot/mod.ts index 1d0e761..27b2e8d 100644 --- a/bot/mod.ts +++ b/bot/mod.ts @@ -1,7 +1,7 @@ -import { sequentialize } from "grammy_runner"; import { Api, Bot, Context, RawApi, session, SessionFlavor } from "grammy"; import { FileFlavor, hydrateFiles } from "grammy_files"; import { hydrateReply, ParseModeFlavor } from "grammy_parse_mode"; +import { sequentialize } from "grammy_runner"; import { error, info, warning } from "std/log/mod.ts"; import { sessions } from "../api/sessionsRoute.ts"; import { formatUserChat } from "../utils/formatUserChat.ts"; @@ -12,6 +12,16 @@ import { img2imgCommand, img2imgQuestion } from "./img2imgCommand.ts"; import { pnginfoCommand, pnginfoQuestion } from "./pnginfoCommand.ts"; import { queueCommand } from "./queueCommand.ts"; import { txt2imgCommand, txt2imgQuestion } from "./txt2imgCommand.ts"; +import { setConfig, getConfig } from "../app/config.ts"; + +// Set the new configuration +await setConfig({ maxUserJobs: 1, maxJobs: 500 }); + +// Fetch the updated configuration +const updatedConfig = await getConfig(); + +// Log the updated configuration to the console +console.log("Updated Configuration:", updatedConfig); interface SessionData { chat: ErisChatData; @@ -107,18 +117,38 @@ bot.use(async (ctx, next) => { } }); -bot.api.setMyShortDescription("I can generate furry images from text"); -bot.api.setMyDescription( - "I can generate furry images from text. " + - "Send /txt2img to generate an image.", -); -bot.api.setMyCommands([ - { command: "txt2img", description: "Generate image from text" }, - { command: "img2img", description: "Generate image from image" }, - { command: "pnginfo", description: "Try to extract prompt from raw file" }, - { command: "queue", description: "Show the current queue" }, - { command: "cancel", description: "Cancel all your requests" }, -]); +// Wrap the calls in try-catch for error handling +async function setupBotCommands() { + try { + await bot.api.setMyShortDescription("Generate furry images in '704x704', '576x832', '832x576'. https://ko-fi.com/nyxthebot https://nyx.akiru.de/"); + } catch (err) { + error(`Failed to set short description: ${err.message}`); + } + + try { + await bot.api.setMyDescription( + "I can generate furry images from text. If you want a different size, use 'Size: 576x832' for example." + + "Send /txt2img to generate an image.", + ); + } catch (err) { + error(`Failed to set description: ${err.message}`); + } + + try { + await bot.api.setMyCommands([ + { command: "txt2img", description: "Generate image from text" }, + { command: "img2img", description: "Generate image from image" }, + { command: "pnginfo", description: "Try to extract prompt from raw file" }, + { command: "queue", description: "Show the current queue" }, + { command: "cancel", description: "Cancel all your requests" }, + ]); + } catch (err) { + error(`Failed to set commands: ${err.message}`); + } +} + +// Call the setup function +setupBotCommands(); bot.command("start", async (ctx) => { if (ctx.match) { @@ -174,20 +204,20 @@ bot.command("crash", () => { }); // Set up the webhook in the telegram API and initialize the bot -await bot.api.setWebhook('https://nyxdev.akiru.de:8443/webhook'); +await bot.api.setWebhook('https://nyx.akiru.de/webhook'); await bot.init(); // Function to handle incoming webhook requests export async function handleWebhook(req: Request): Promise { try { const body = await req.json(); - console.log("Received webhook data:", JSON.stringify(body, null, 2)); + // console.log("Received webhook data:", JSON.stringify(body, null, 2)); // Log before processing update - console.log("Processing update through handleUpdate..."); + // console.log("Processing update through handleUpdate..."); await bot.handleUpdate(body); // Process the update // Log after processing update - console.log("Update processed successfully."); + // console.log("Update processed successfully."); return new Response(JSON.stringify({ status: 'ok' }), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { @@ -195,4 +225,4 @@ export async function handleWebhook(req: Request): Promise { console.error("Error in handleWebhook:", error); return new Response("Error", { status: 500 }); } -} \ No newline at end of file +} From eaff7c0772f1fcda102880e403ddf8cf982a3be6 Mon Sep 17 00:00:00 2001 From: Akiru Date: Fri, 26 Jan 2024 13:13:31 +0000 Subject: [PATCH 12/12] README.md aktualisiert --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 96e5ef4..1d67d8d 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,12 @@ -# Eris the Bot - -[![Website](https://img.shields.io/website?url=https%3A%2F%2Feris.lisq.eu%2F)](https://eris.lisq.eu/) -![Unique users](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Feris.lisq.eu%2Fapi%2Fstats&query=%24.userCount&label=unique%20users) -![Generated images](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Feris.lisq.eu%2Fapi%2Fstats&query=%24.imageCount&label=images%20generated) -![Processed steps](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Feris.lisq.eu%2Fapi%2Fstats&query=%24.stepCount&label=steps%20processed) -![Painted pixels](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Feris.lisq.eu%2Fapi%2Fstats&query=%24.pixelCount&label=pixels%20painted) +# Nyx the Bot +Fork of Eris the Bot https://eris.lisq.eu Telegram bot for generating images from text. ## Requirements -- [Deno](https://deno.land/) -- [Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) +- [Deno](https://deno.land/) (for the bot server) +- [Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) (for the worker that generates images) ## Options @@ -20,17 +15,23 @@ You can put these in `.env` file or pass them as environment variables. - `TG_BOT_TOKEN` - Telegram bot token. Get yours from [@BotFather](https://t.me/BotFather). Required. - `DENO_KV_PATH` - [Deno KV](https://deno.land/api?s=Deno.openKv&unstable) database file path. A - temporary file is used by default. + temporary file is used by default. Example: /opt/data/botdata.kv - `LOG_LEVEL` - [Log level](https://deno.land/std@0.201.0/log/mod.ts?s=LogLevels). Default: `INFO`. ## Running 1. Start Eris: `deno task start` -2. Visit [Eris WebUI](http://localhost:5999/) and login via Telegram. +2. Visit [Eris WebUI](http://localhost:8443/) and login via Telegram. 3. Promote yourself to admin in the Eris WebUI. 4. Start Stable Diffusion WebUI: `./webui.sh --api` (in SD WebUI directory) 5. Add a new worker in the Eris WebUI. +## This fork requires the use of webhooks. + +1. You need a reverse Proxy and HTTPS certificate set up that proxies all requests from a domain on port 443 (e.g. nyx.akiru.de) to the backend of this bot (:8443). +2. Change the Webhook URL to your own one in /mod/bot.ts - There are also console log statements you can uncomment for troubleshooting. +3. Make sure the DNS and firewall are set up for the webhook to be reachable, because otherwise the bot fails to start. + ## Codegen The Stable Diffusion API types are auto-generated. To regenerate them, first start your SD WebUI @@ -38,8 +39,8 @@ with `--nowebui --api`, and then run `deno task generate` ## Project structure -- `/api` - Eris API served at `http://localhost:5999/api/`. +- `/api` - Eris API served at `http://localhost:8443/api/`. - `/app` - Queue handling and other core processes. - `/bot` - Handling bot commands and other updates from Telegram API. -- `/ui` - Eris WebUI frontend files served at `http://localhost:5999/`. +- `/ui` - Eris WebUI frontend files served at `http://localhost:8443/`. - `/util` - Utility functions shared by other parts.