-
-
Save soruly/c2f7da4ea4cc237f280447afa0b2c59b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TELEGRAM_TOKEN= # e.g. 111111111:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | |
TELEGRAM_WEBHOOK= # e.g. https://your.host.com/ | |
PORT= # (optional) Default: 3000 | |
NOVELAI_TOKEN= # e.g. "Bearer eyJhbxxxxxxxxxxxxxXVCJ9.eyJpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxbi9I" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "soruly-telegram-bot", | |
"version": "0.0.1", | |
"description": "", | |
"main": "server.js", | |
"type": "module", | |
"scripts": { | |
"start": "pm2 start ecosystem.config.json", | |
"stop": "pm2 stop ecosystem.config.json", | |
"restart": "pm2 restart ecosystem.config.json", | |
"reload": "pm2 reload ecosystem.config.json", | |
"delete": "pm2 delete ecosystem.config.json", | |
"prettier": "prettier", | |
"format": "prettier --write \"**/*.js\"", | |
"lint": "prettier --check \"**/*.js\"", | |
"test": "prettier --check \"**/*.js\"" | |
}, | |
"repository": { | |
"type": "git", | |
"url": "git+https://github.com/soruly/soruly-telegram-bot.git" | |
}, | |
"author": "soruly", | |
"license": "MIT", | |
"bugs": { | |
"url": "https://github.com/soruly/soruly-telegram-bot/issues" | |
}, | |
"homepage": "https://github.com/soruly/soruly-telegram-bot", | |
"dependencies": { | |
"dotenv": "^16.0.3", | |
"express": "^4.18.1", | |
"express-rate-limit": "^6.6.0", | |
"node-fetch": "^3.2.10" | |
}, | |
"devDependencies": { | |
"prettier": "^2.7.1" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "dotenv/config"; | |
import express from "express"; | |
import rateLimit from "express-rate-limit"; | |
import fetch, { FormData, File } from "node-fetch"; | |
const { PORT = 3000, TELEGRAM_TOKEN, TELEGRAM_WEBHOOK, NOVELAI_TOKEN } = process.env; | |
const TELEGRAM_API = "https://api.telegram.org"; | |
if (!TELEGRAM_TOKEN || !TELEGRAM_WEBHOOK || !NOVELAI_TOKEN) { | |
console.log("Please configure TELEGRAM_TOKEN and TELEGRAM_WEBHOOK and NOVELAI_TOKEN first"); | |
process.exit(); | |
} | |
console.log(`TELEGRAM_WEBHOOK: ${TELEGRAM_WEBHOOK}`); | |
console.log("Setting Telegram webhook..."); | |
await fetch( | |
`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/setWebhook?url=${TELEGRAM_WEBHOOK}&max_connections=100` | |
) | |
.then((e) => e.json()) | |
.then((e) => { | |
console.log(e); | |
}); | |
fetch(`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/getMe`) | |
.then((e) => e.json()) | |
.then((e) => { | |
console.log(e); | |
app.locals.botName = e.result?.username; | |
}); | |
fetch(`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/setMyCommands`, { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
commands: [ | |
{ command: "/portrait", description: "Generate image with 512x768" }, | |
{ command: "/landscape", description: "Generate image with 768x512" }, | |
{ command: "/square", description: "Generate image with 640x640" }, | |
{ command: "/portrait_nsfw", description: "Generate NSFW image with 512x768" }, | |
{ command: "/landscape_nsfw", description: "Generate NSFW image with 768x512" }, | |
{ command: "/square_nsfw", description: "Generate NSFW image with 640x640" }, | |
], | |
}), | |
}); | |
const app = express(); | |
app.disable("x-powered-by"); | |
app.set("trust proxy", 1); | |
app.use( | |
rateLimit({ | |
max: 100, // limit each IP to 100 requests | |
windowMs: 1000, // per second | |
delayMs: 0, // disable delaying - full speed until the max limit is reached | |
}) | |
); | |
app.use(express.json()); | |
const privateMessageHandler = async (message) => { | |
const responding_msg = message.reply_to_message ? message.reply_to_message : message; | |
console.log(responding_msg); | |
if (!responding_msg.entities?.length) { | |
return fetch(`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/sendMessage`, { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
chat_id: message.chat.id, | |
text: [ | |
"Usage:", | |
"`/portrait original, 1girl, highres, claw_pose, long_hair, animal_ears, sailor_collar`", | |
"`/landscape original, 1girl, highres, claw_pose, long_hair, animal_ears, sailor_collar`", | |
"`/square original, 1girl, highres, claw_pose, long_hair, animal_ears, sailor_collar`", | |
"NSFW:", | |
"`/portrait_nsfw original, 1girl, highres, long_hair, animal_ears, nude, small_breasts, wet`", | |
"With seed:", | |
"`/portrait@3310422351 original, 1girl, highres, claw_pose, long_hair, animal_ears, sailor_collar`", | |
].join("\n"), | |
reply_to_message_id: responding_msg.message_id, | |
parse_mode: "Markdown", | |
}), | |
}); | |
} | |
const entity = responding_msg.entities[0]; | |
const command = responding_msg.text.substr(entity.offset, entity.length).trim(); | |
let width = 640; | |
let height = 640; | |
if (command.startsWith("/landscape")) { | |
width = 768; | |
height = 512; | |
} else if (command.startsWith("/portrait")) { | |
width = 512; | |
height = 768; | |
} | |
const prompt = responding_msg.text.substring(responding_msg.entities[0].length).trim(); | |
const seed = command.includes("@") | |
? Number(command.split("@")[1]) | |
: 1000000000 + Math.floor(Math.random() * 2000000000); | |
if (!prompt || isNaN(seed)) { | |
return fetch(`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/sendMessage`, { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
chat_id: message.chat.id, | |
text: "Invalid input", | |
reply_to_message_id: responding_msg.message_id, | |
}), | |
}); | |
} | |
const r = await fetch(`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/sendMessage`, { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
chat_id: message.chat.id, | |
text: `Generating ${width}x${height} image with seed ${seed}\n\`${prompt}\``, | |
reply_to_message_id: responding_msg.message_id, | |
parse_mode: "Markdown", | |
}), | |
}).then((e) => e.json()); | |
console.log(r); | |
const res = await fetch("https://api.novelai.net/ai/generate-image", { | |
method: "post", | |
headers: { | |
authorization: NOVELAI_TOKEN, | |
"Content-Type": "application/json", | |
"user-agent": | |
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36", | |
}, | |
body: JSON.stringify({ | |
input: prompt, | |
model: command.includes("nsfw") ? "nai-diffusion" : "safe-diffusion", | |
parameters: { | |
width, | |
height, | |
scale: 11, | |
sampler: "k_euler_ancestral", | |
steps: 28, | |
seed, | |
n_samples: 1, | |
// strength: 0.7, | |
// noise: 0.2, | |
ucPreset: 0, | |
uc: "lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry", | |
}, | |
}), | |
}); | |
const text = await res.text(); | |
const base64Text = text.split("\n")[2].replace("data:", "").trim(); | |
const img = Buffer.from(base64Text, "base64"); | |
const formData = new FormData(); | |
const abc = new File([img.buffer], "demo.png", { type: "image/png" }); | |
formData.set("chat_id", message.chat.id); | |
formData.set("reply_to_message_id", responding_msg.message_id); | |
formData.set("photo", abc, "demo.png"); | |
formData.set("caption", `seed: ${seed}\nprompt: \`${prompt}\``); | |
formData.set("parse_mode", "Markdown"); | |
await fetch(`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/sendPhoto`, { | |
method: "POST", | |
body: formData, | |
}); | |
await fetch(`${TELEGRAM_API}/bot${TELEGRAM_TOKEN}/deleteMessage`, { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
chat_id: message.chat.id, | |
message_id: r.result.message_id, | |
}), | |
}).then((e) => e.json()); | |
}; | |
app.post("/", (req, res) => { | |
const message = req.body?.message; | |
if (message?.chat?.type === "private") { | |
privateMessageHandler(message); | |
} else if (message?.chat?.type === "group" || message?.chat?.type === "supergroup") { | |
// groupMessageHandler(message); | |
} | |
res.sendStatus(204); | |
}); | |
app.get("/", (req, res) => { | |
return res.send( | |
`<meta http-equiv="Refresh" content="0; URL=https://t.me/${app.locals.botName ?? ""}">` | |
); | |
}); | |
app.listen(PORT, "0.0.0.0", () => console.log(`server listening on port ${PORT}`)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment