9 Commits

Author SHA1 Message Date
melod1n 51db4ba9b5 fix using wrong dirs 2026-02-16 20:05:21 +03:00
melod1n c98528a54f fix 2026-02-16 20:00:25 +03:00
melod1n 2f0f10eed9 fix mkdir dirs 2026-02-16 19:57:35 +03:00
melod1n 8bec34413f some code cleanup 2026-02-16 19:52:28 +03:00
melod1n b8b3895310 update openAiGenImage params 2026-02-16 19:52:08 +03:00
melod1n 5b84376dc7 improve cache storage and cleanup (+ recursively) 2026-02-16 19:51:43 +03:00
melod1n 69ae37e05e /ae command now available if specifically set to 2026-02-16 19:50:07 +03:00
melod1n edcc0ddc91 Revert "move to debian-based runtime"
This reverts commit 751a0a1e15.
2026-02-16 16:40:28 +03:00
melod1n 751a0a1e15 move to debian-based runtime 2026-02-16 16:29:38 +03:00
7 changed files with 60 additions and 71 deletions
+6 -9
View File
@@ -2,7 +2,7 @@ import {ChatCommand} from "../base/chat-command";
import {Message} from "typescript-telegram-bot-api"; import {Message} from "typescript-telegram-bot-api";
import {Requirements} from "../base/requirements"; import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement"; import {Requirement} from "../base/requirement";
import {bot, openAi, photoDir} from "../index"; import {bot, openAi, photoGenDir} from "../index";
import fs from "node:fs"; import fs from "node:fs";
import path from "node:path"; import path from "node:path";
import {editMessageText, logError, replyToMessage} from "../util/utils"; import {editMessageText, logError, replyToMessage} from "../util/utils";
@@ -27,14 +27,9 @@ export class OpenAIGenImage extends ChatCommand {
try { try {
const totalParts = 3; const totalParts = 3;
const model = Environment.OPENAI_IMAGE_MODEL; const model = Environment.OPENAI_IMAGE_MODEL;
const size = "1024x1024";
const fileFullName = `${msg.chat.id}_${msg.message_id}.png`; const fileFullName = `${msg.chat.id}_${msg.message_id}.png`;
const getFileLocation = (fn: string) => { const getFileLocation = (fn: string) => {
const genRoot = path.join(photoDir, "gen"); return path.join(photoGenDir, fn);
if (!fs.existsSync(genRoot)) {
fs.mkdirSync(genRoot);
}
return path.join(genRoot, fn);
}; };
waitMessage = await replyToMessage({message: msg, text: "🌈 Генерирую изображение..."}); waitMessage = await replyToMessage({message: msg, text: "🌈 Генерирую изображение..."});
@@ -43,9 +38,11 @@ export class OpenAIGenImage extends ChatCommand {
model: model, model: model,
prompt: prompt, prompt: prompt,
n: 1, n: 1,
size: size, size: "auto",
stream: true, stream: true,
partial_images: totalParts, partial_images: totalParts,
moderation: "low",
output_format: "png",
}); });
const then = Date.now(); const then = Date.now();
@@ -89,7 +86,7 @@ export class OpenAIGenImage extends ChatCommand {
media: { media: {
type: "photo", type: "photo",
media: imageBuffer, media: imageBuffer,
caption: `🌈 Изображение по запросу "${prompt}" сгенерировано моделью "${model}" размеров ${size} за ${diff}ms` caption: `🌈 Изображение по запросу "${prompt}" сгенерировано моделью "${model}" размеров ${event.size} за ${diff}ms`
} }
}); });
break; break;
+3 -9
View File
@@ -12,8 +12,7 @@ import {
getUserAvatar, getUserAvatar,
logError, logError,
makeDarkGradientBgFancy, makeDarkGradientBgFancy,
oldReplyToMessage, replyToMessage
oldSendMessage
} from "../util/utils"; } from "../util/utils";
import {Requirements} from "../base/requirements"; import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement"; import {Requirement} from "../base/requirement";
@@ -50,15 +49,10 @@ export class Quote extends Command {
const chatId = msg.chat.id; const chatId = msg.chat.id;
const reply = msg.reply_to_message; const reply = msg.reply_to_message;
if (!reply) {
await oldReplyToMessage(msg, "Сделай /quote реплаем на сообщение 🙂").catch(logError);
return;
}
try { try {
const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim(); const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim();
if (quoteRaw.length === 0) { if (quoteRaw.length === 0) {
await oldReplyToMessage(msg, "Не нашёл в сообщении текста 😢").catch(logError); await replyToMessage({message: msg, text: "Не нашёл в сообщении текста 😢"}).catch(logError);
return; return;
} }
@@ -76,7 +70,7 @@ export class Quote extends Command {
}).catch(logError); }).catch(logError);
} catch (e) { } catch (e) {
logError(e); logError(e);
await oldSendMessage(msg, "Не смог собрать цитату 😢").catch(logError); await replyToMessage({message: msg, text: "Не смог собрать цитату 😢"}).catch(logError);
} }
} }
} }
+4
View File
@@ -19,6 +19,8 @@ export class Environment {
static ONLY_FOR_CREATOR_MODE: boolean; static ONLY_FOR_CREATOR_MODE: boolean;
static ENABLE_UNSAFE_EVAL: boolean;
static ANSWERS: Answers; static ANSWERS: Answers;
static USE_NAMES_IN_PROMPT: boolean; static USE_NAMES_IN_PROMPT: boolean;
@@ -65,6 +67,8 @@ export class Environment {
Environment.ONLY_FOR_CREATOR_MODE = ifTrue(process.env.ONLY_FOR_CREATOR_MODE); Environment.ONLY_FOR_CREATOR_MODE = ifTrue(process.env.ONLY_FOR_CREATOR_MODE);
Environment.ENABLE_UNSAFE_EVAL = ifTrue(process.env.ENABLE_UNSAFE_EVAL);
Environment.USE_NAMES_IN_PROMPT = ifTrue(process.env.USE_NAMES_IN_PROMPT); Environment.USE_NAMES_IN_PROMPT = ifTrue(process.env.USE_NAMES_IN_PROMPT);
Environment.MAX_PHOTO_SIZE = Number(process.env.MAX_PHOTO_SIZE || "1280"); Environment.MAX_PHOTO_SIZE = Number(process.env.MAX_PHOTO_SIZE || "1280");
+18 -12
View File
@@ -4,7 +4,6 @@ import {TelegramBot, User} from "typescript-telegram-bot-api";
import {Command} from "./base/command"; import {Command} from "./base/command";
import { import {
delay, delay,
ignore,
initSystemSpecs, initSystemSpecs,
logError, logError,
processCallbackQuery, processCallbackQuery,
@@ -132,7 +131,6 @@ export const commands: Command[] = [
new Start(), new Start(),
new Help(), new Help(),
new Test(), new Test(),
new Ae(),
new Ignore(), new Ignore(),
new Unignore(), new Unignore(),
new Ping(), new Ping(),
@@ -168,6 +166,10 @@ export const commands: Command[] = [
new YouTubeDownload() new YouTubeDownload()
]; ];
if (Environment.ENABLE_UNSAFE_EVAL) {
commands.push(new Ae());
}
export const callbackCommands: CallbackCommand[] = [ export const callbackCommands: CallbackCommand[] = [
new OllamaCancel() new OllamaCancel()
]; ];
@@ -215,8 +217,10 @@ if (Environment.OPENAI_API_KEY) {
); );
} }
export const photoDir = path.join(Environment.DATA_PATH, "photo"); export const cacheDir = path.join(Environment.DATA_PATH, "cache");
export const videoDir = path.join(Environment.DATA_PATH, "video"); export const photoDir = path.join(cacheDir, "photo");
export const photoGenDir = path.join(photoDir, "gen");
export const videoDir = path.join(cacheDir, "video");
let isShuttingDown = false; let isShuttingDown = false;
@@ -246,8 +250,12 @@ async function main() {
`DEFAULT_AI_PROVIDER: ${Environment.DEFAULT_AI_PROVIDER}` `DEFAULT_AI_PROVIDER: ${Environment.DEFAULT_AI_PROVIDER}`
); );
fs.mkdir(photoDir, ignore); const dirsToCheck = [cacheDir, photoDir, photoGenDir, videoDir];
fs.mkdir(videoDir, ignore); dirsToCheck.forEach(dir => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
});
const now = new Date(); const now = new Date();
@@ -256,15 +264,13 @@ async function main() {
midnight.setDate(now.getDate() + 1); midnight.setDate(now.getDate() + 1);
const diff = midnight.getTime() - now.getTime(); const diff = midnight.getTime() - now.getTime();
console.log("Clearing up videos and photos will be started in " + diff + "ms"); console.log("Clearing up cache will be started in " + diff + "ms");
clearUpFolderFromOldFiles(videoDir); clearUpFolderFromOldFiles(cacheDir);
clearUpFolderFromOldFiles(photoDir);
delay(diff).then(() => { delay(diff).then(() => {
setInterval(() => { setInterval(() => {
console.log("Started clearing up videos and photos"); console.log("Started clearing up cache");
clearUpFolderFromOldFiles(videoDir); clearUpFolderFromOldFiles(cacheDir);
clearUpFolderFromOldFiles(photoDir);
}, 1000 * 60 * 60 * 24); }, 1000 * 60 * 60 * 24);
}); });
+18 -15
View File
@@ -2,7 +2,7 @@ import {logError} from "./utils";
import fs from "node:fs"; import fs from "node:fs";
import path from "node:path"; import path from "node:path";
export function clearUpFolderFromOldFiles(folder: string) { export function clearUpFolderFromOldFiles(folder: string, recursive = true) {
fs.readdir(folder, (err, files) => { fs.readdir(folder, (err, files) => {
if (err) { if (err) {
logError(err); logError(err);
@@ -11,32 +11,35 @@ export function clearUpFolderFromOldFiles(folder: string) {
const filenamesToDelete: string[] = []; const filenamesToDelete: string[] = [];
files.forEach((filename, index) => { files.forEach(filename => {
fs.stat(path.join(folder, filename), (err, stats) => { const fullPath = path.join(folder, filename);
if (err) {
logError(err); try {
const stats = fs.statSync(fullPath);
if (stats.isDirectory() && recursive) {
clearUpFolderFromOldFiles(fullPath, recursive);
} else { } else {
const then = stats.mtime.getTime() / 1000; const then = stats.mtime.getTime() / 1000;
const now = Date.now() / 1000; const now = Date.now() / 1000;
const diff = Math.abs(now - then); const diff = Math.abs(now - then);
const moreThanOneDay = diff >= 60 * 60 * 24; const moreThanOneDay = diff >= 60 * 60 * 24;
if (moreThanOneDay) {
filenamesToDelete.push(filename);
}
if (index === files.length - 1) { if (stats.isFile() && moreThanOneDay) {
filenamesToDelete.push(fullPath);
}
}
} catch (e) {
logError(e);
}
});
console.log("filenamesToDelete", filenamesToDelete); console.log("filenamesToDelete", filenamesToDelete);
if (filenamesToDelete.length) { if (filenamesToDelete.length) {
filenamesToDelete.forEach((filename) => { filenamesToDelete.forEach((filename) => {
const fullPath = path.join(folder, filename); fs.rm(filename, (e) => {
fs.rm(fullPath, (e) => {
if (e) logError(e); if (e) logError(e);
}); });
}); });
} }
}
}
});
});
}); });
} }
+5 -15
View File
@@ -15,7 +15,7 @@ import {
} from "typescript-telegram-bot-api"; } from "typescript-telegram-bot-api";
import {Environment} from "../common/environment"; import {Environment} from "../common/environment";
import {TelegramError} from "typescript-telegram-bot-api/dist/errors"; import {TelegramError} from "typescript-telegram-bot-api/dist/errors";
import {bot, botUser, callbackCommands, commands, messageDao, ollama} from "../index"; import {bot, botUser, callbackCommands, commands, messageDao, ollama, photoDir} from "../index";
import os from "os"; import os from "os";
import axios from "axios"; import axios from "axios";
import {MessagePart} from "../common/message-part"; import {MessagePart} from "../common/message-part";
@@ -538,12 +538,7 @@ export async function loadImagesIfExists(msg: Message | StoredMessage): Promise<
const maxSize = await mapPhotoSizeToMax(getPhotoMaxSize(msg.photo)); const maxSize = await mapPhotoSizeToMax(getPhotoMaxSize(msg.photo));
if (maxSize) { if (maxSize) {
const imagePath = path.join(Environment.DATA_PATH, "photo"); let imageFilePath = path.join(photoDir, maxSize.unique_file_id + ".jpg");
if (!fs.existsSync(imagePath)) {
fs.mkdirSync(imagePath);
}
let imageFilePath = path.join(imagePath, maxSize.unique_file_id + ".jpg");
if (!fs.existsSync(imageFilePath)) { if (!fs.existsSync(imageFilePath)) {
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"}); const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
const src = Buffer.from(res.data); const src = Buffer.from(res.data);
@@ -567,11 +562,6 @@ export async function loadImagesIfExists(msg: Message | StoredMessage): Promise<
export async function loadImagesFromFileIds(sizes: PhotoSize[]): Promise<string[] | null> { export async function loadImagesFromFileIds(sizes: PhotoSize[]): Promise<string[] | null> {
if (!sizes?.length) return null; if (!sizes?.length) return null;
const dataPath = path.join(Environment.DATA_PATH, "photo");
if (!fs.existsSync(dataPath)) {
fs.mkdirSync(dataPath);
}
const existing = const existing =
sizes.filter(s => fs.existsSync(photoPathByUniqueId(s.file_unique_id))) sizes.filter(s => fs.existsSync(photoPathByUniqueId(s.file_unique_id)))
.map(s => s.file_unique_id); .map(s => s.file_unique_id);
@@ -589,7 +579,7 @@ export async function loadImagesFromFileIds(sizes: PhotoSize[]): Promise<string[
const paths = responses.map((res, index) => { const paths = responses.map((res, index) => {
try { try {
const uniqueFileId = maxSizes[index].unique_file_id; const uniqueFileId = maxSizes[index].unique_file_id;
const imageFilePath = path.join(dataPath, uniqueFileId + ".jpg"); const imageFilePath = path.join(photoDir, uniqueFileId + ".jpg");
const src = Buffer.from(res.data); const src = Buffer.from(res.data);
fs.writeFileSync(imageFilePath, src); fs.writeFileSync(imageFilePath, src);
return uniqueFileId; return uniqueFileId;
@@ -1063,7 +1053,7 @@ async function processAlbum(groupId: string): Promise<string[]> {
} }
export function photoPathByUniqueId(uniqueId: string): string { export function photoPathByUniqueId(uniqueId: string): string {
return path.join(Environment.DATA_PATH, "photo", uniqueId + ".jpg"); return path.join(photoDir, uniqueId + ".jpg");
} }
export function getCurrentModel(): string { export function getCurrentModel(): string {
@@ -1149,7 +1139,7 @@ export async function processNewMessage(msg: Message): Promise<void> {
logError(e); logError(e);
} }
if ((msg.new_chat_members?.length || 0 > 0)) { if ((msg.new_chat_members?.length)) {
await bot.sendMessage({chat_id: msg.chat.id, text: randomValue(Environment.ANSWERS.invite)}).catch(logError); await bot.sendMessage({chat_id: msg.chat.id, text: randomValue(Environment.ANSWERS.invite)}).catch(logError);
return; return;
} }
+2 -7
View File
@@ -1,7 +1,7 @@
import Innertube, {Platform, Types, Utils} from "youtubei.js"; import Innertube, {Platform, Types, Utils} from "youtubei.js";
import fs, {createWriteStream} from "node:fs"; import fs, {createWriteStream} from "node:fs";
import path from "node:path"; import path from "node:path";
import {Environment} from "../common/environment"; import {videoDir} from "../index";
export function getYouTubeVideoId(url: string): string { export function getYouTubeVideoId(url: string): string {
const regex = /(?:(?:youtube\.com|music\.youtube\.com)\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?|shorts|clip)\/|.*[?&]v=)|youtu\.be\/)([^"&?/\s]{11})/i; const regex = /(?:(?:youtube\.com|music\.youtube\.com)\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?|shorts|clip)\/|.*[?&]v=)|youtu\.be\/)([^"&?/\s]{11})/i;
@@ -20,12 +20,7 @@ export async function downloadVideoFromYouTube(url: string, targetQuality: strin
try { try {
const videoId = getYouTubeVideoId(url); const videoId = getYouTubeVideoId(url);
const videoFolder = path.join(Environment.DATA_PATH, "video"); const filePath = path.join(videoDir, `${videoId}.mp4`);
if (!fs.existsSync(videoFolder)) {
fs.mkdirSync(videoFolder);
}
const filePath = path.join(videoFolder, `${videoId}.mp4`);
if (fs.existsSync(filePath)) { if (fs.existsSync(filePath)) {
const buffer = Buffer.from(fs.readFileSync(filePath)); const buffer = Buffer.from(fs.readFileSync(filePath));
return { return {