app: wire new commands and update docs
This commit is contained in:
@@ -9,6 +9,13 @@ cp .env.example .env
|
|||||||
# Edit .env: add BOT_TOKEN, CREATOR_ID and configure optional AI models (GEMINI_API_KEY, MISTRAL_API_KEY, OLLAMA_ADDRESS)
|
# Edit .env: add BOT_TOKEN, CREATOR_ID and configure optional AI models (GEMINI_API_KEY, MISTRAL_API_KEY, OLLAMA_ADDRESS)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For local Ollama document RAG, install an embedding model locally and set it in `.env`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ollama pull nomic-embed-text
|
||||||
|
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
||||||
|
```
|
||||||
|
|
||||||
**With Bun (Recommended):**
|
**With Bun (Recommended):**
|
||||||
```bash
|
```bash
|
||||||
bun install
|
bun install
|
||||||
@@ -42,13 +49,14 @@ docker run -d --env-file .env -v $(pwd)/data:/config/data tg-bot-bun
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Node.js >= 18 OR Bun >= 1.0
|
- Node.js >= 20 OR Bun >= 1.0
|
||||||
- Docker (optional)
|
- Docker (optional)
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- AI chat (Gemini, Mistral, Ollama)
|
- AI chat (Gemini, Mistral, Ollama)
|
||||||
|
- Local document RAG for Ollama without third-party providers
|
||||||
- Custom answers and commands
|
- Custom answers and commands
|
||||||
- Admin management
|
- Admin management
|
||||||
- User blocking (mute/unmute)
|
- User blocking (mute/unmute)
|
||||||
|
|||||||
+33
-68
@@ -3,11 +3,11 @@ import {Environment} from "./common/environment";
|
|||||||
import {BotCommand, TelegramBot, User} from "typescript-telegram-bot-api";
|
import {BotCommand, TelegramBot, User} from "typescript-telegram-bot-api";
|
||||||
import {Command} from "./base/command";
|
import {Command} from "./base/command";
|
||||||
import {
|
import {
|
||||||
delay,
|
|
||||||
initSystemSpecs,
|
initSystemSpecs,
|
||||||
logError,
|
logError,
|
||||||
processCallbackQuery,
|
processCallbackQuery,
|
||||||
processEditedMessage,
|
processEditedMessage,
|
||||||
|
processGuestMessage,
|
||||||
processInlineQuery,
|
processInlineQuery,
|
||||||
processMyChatMember,
|
processMyChatMember,
|
||||||
processNewMessage
|
processNewMessage
|
||||||
@@ -27,10 +27,8 @@ import {When} from "./commands/when";
|
|||||||
import {RandomInt} from "./commands/random-int";
|
import {RandomInt} from "./commands/random-int";
|
||||||
import {Ban} from "./commands/ban";
|
import {Ban} from "./commands/ban";
|
||||||
import {Quote} from "./commands/quote";
|
import {Quote} from "./commands/quote";
|
||||||
import {Ollama} from "ollama";
|
|
||||||
import {OllamaSearch} from "./commands/ollama-search";
|
import {OllamaSearch} from "./commands/ollama-search";
|
||||||
import {Id} from "./commands/id";
|
import {Id} from "./commands/id";
|
||||||
import {OllamaPrompt} from "./commands/ollama-prompt";
|
|
||||||
import {AdminsAdd} from "./commands/admins-add";
|
import {AdminsAdd} from "./commands/admins-add";
|
||||||
import {AdminsRemove} from "./commands/admins-remove";
|
import {AdminsRemove} from "./commands/admins-remove";
|
||||||
import {Shutdown} from "./commands/shutdown";
|
import {Shutdown} from "./commands/shutdown";
|
||||||
@@ -49,16 +47,14 @@ import {MessageDao} from "./db/message-dao";
|
|||||||
import {DatabaseManager} from "./db/database-manager";
|
import {DatabaseManager} from "./db/database-manager";
|
||||||
import {UserDao} from "./db/user-dao";
|
import {UserDao} from "./db/user-dao";
|
||||||
import {UserStore} from "./common/user-store";
|
import {UserStore} from "./common/user-store";
|
||||||
import {OllamaRequest} from "./model/ollama-request";
|
|
||||||
import {CallbackCommand} from "./base/callback-command";
|
import {CallbackCommand} from "./base/callback-command";
|
||||||
import {OllamaCancel} from "./callback_commands/ollama-cancel";
|
import {AiCancel} from "./callback_commands/ai-cancel";
|
||||||
|
import {AiRegenerate} from "./callback_commands/ai-regenerate";
|
||||||
import {MistralChat} from "./commands/mistral-chat";
|
import {MistralChat} from "./commands/mistral-chat";
|
||||||
import {Transliteration} from "./commands/transliteration";
|
import {Transliteration} from "./commands/transliteration";
|
||||||
import {OllamaListModels} from "./commands/ollama-list-models";
|
import {OllamaListModels} from "./commands/ollama-list-models";
|
||||||
import {OllamaGetModel} from "./commands/ollama-get-model";
|
import {OllamaGetModel} from "./commands/ollama-get-model";
|
||||||
import {OllamaSetModel} from "./commands/ollama-set-model";
|
import {OllamaSetModel} from "./commands/ollama-set-model";
|
||||||
import {Mistral} from "@mistralai/mistralai";
|
|
||||||
import {GoogleGenAI} from "@google/genai";
|
|
||||||
import {MistralGetModel} from "./commands/mistral-get-model";
|
import {MistralGetModel} from "./commands/mistral-get-model";
|
||||||
import {MistralSetModel} from "./commands/mistral-set-model";
|
import {MistralSetModel} from "./commands/mistral-set-model";
|
||||||
import {MistralListModels} from "./commands/mistral-list-models";
|
import {MistralListModels} from "./commands/mistral-list-models";
|
||||||
@@ -66,20 +62,19 @@ import {GeminiListModels} from "./commands/gemini-list-models";
|
|||||||
import {GeminiGetModel} from "./commands/gemini-get-model";
|
import {GeminiGetModel} from "./commands/gemini-get-model";
|
||||||
import {GeminiSetModel} from "./commands/gemini-set-model";
|
import {GeminiSetModel} from "./commands/gemini-set-model";
|
||||||
import {Debug} from "./commands/debug";
|
import {Debug} from "./commands/debug";
|
||||||
import {GeminiGenerateImage} from "./commands/gemini-generate-image";
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import {setInterval} from "node:timers";
|
|
||||||
import {OpenAI} from "openai";
|
|
||||||
import {OpenAIChat} from "./commands/openai-chat";
|
import {OpenAIChat} from "./commands/openai-chat";
|
||||||
import {OpenAIListModels} from "./commands/openai-list-models";
|
import {OpenAIListModels} from "./commands/openai-list-models";
|
||||||
import {OpenAIGetModel} from "./commands/openai-get-model";
|
import {OpenAIGetModel} from "./commands/openai-get-model";
|
||||||
import {OpenAISetModel} from "./commands/openai-set-model";
|
import {OpenAISetModel} from "./commands/openai-set-model";
|
||||||
import {Info} from "./commands/info";
|
import {Info} from "./commands/info";
|
||||||
import {OpenAIGenImage} from "./commands/openai-gen-image";
|
|
||||||
import {clearUpFolderFromOldFiles} from "./util/files";
|
|
||||||
import {AdminsList} from "./commands/admins-list";
|
import {AdminsList} from "./commands/admins-list";
|
||||||
import {ExportDb} from "./commands/export-db";
|
import {ExportDb} from "./commands/export-db";
|
||||||
|
import {Settings} from "./commands/settings";
|
||||||
|
import {UserSettingsCallback} from "./callback_commands/user-settings";
|
||||||
|
import {TextToSpeech} from "./commands/text-to-speech";
|
||||||
|
import {SpeechToText} from "./commands/speech-to-text";
|
||||||
|
|
||||||
process.setUncaughtExceptionCaptureCallback(logError);
|
process.setUncaughtExceptionCaptureCallback(logError);
|
||||||
|
|
||||||
@@ -92,42 +87,6 @@ export const userDao = new UserDao();
|
|||||||
export const bot = new TelegramBot({botToken: Environment.BOT_TOKEN, testEnvironment: Environment.TEST_ENVIRONMENT});
|
export const bot = new TelegramBot({botToken: Environment.BOT_TOKEN, testEnvironment: Environment.TEST_ENVIRONMENT});
|
||||||
export let botUser: User;
|
export let botUser: User;
|
||||||
|
|
||||||
export const googleAi = new GoogleGenAI({apiKey: Environment.GEMINI_API_KEY});
|
|
||||||
export const mistralAi = new Mistral({apiKey: Environment.MISTRAL_API_KEY});
|
|
||||||
export const openAi = new OpenAI({apiKey: Environment.OPENAI_API_KEY, baseURL: Environment.OPENAI_BASE_URL, dangerouslyAllowBrowser: true});
|
|
||||||
|
|
||||||
export const ollama = new Ollama({
|
|
||||||
host: Environment.OLLAMA_ADDRESS,
|
|
||||||
headers: {"Authorization": `Bearer ${Environment.OLLAMA_API_KEY}`}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ollamaRequests: OllamaRequest[] = [];
|
|
||||||
|
|
||||||
export function getOllamaRequest(uuid: string): OllamaRequest | undefined {
|
|
||||||
return ollamaRequests.find(r => r.uuid === uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateOllamaRequest(uuid: string, request: OllamaRequest) {
|
|
||||||
const index = ollamaRequests.findIndex(r => r.uuid === uuid);
|
|
||||||
if (index >= 0) {
|
|
||||||
ollamaRequests[index] = request;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function abortOllamaRequest(uuid: string): boolean {
|
|
||||||
const request = getOllamaRequest(uuid);
|
|
||||||
if (!request || request.done) return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
request.stream.abort();
|
|
||||||
updateOllamaRequest(uuid, {...request, done: true});
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
logError(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const commands: Command[] = [
|
export const commands: Command[] = [
|
||||||
new Start(),
|
new Start(),
|
||||||
new Help(),
|
new Help(),
|
||||||
@@ -157,6 +116,9 @@ export const commands: Command[] = [
|
|||||||
new Transliteration(),
|
new Transliteration(),
|
||||||
new Debug(),
|
new Debug(),
|
||||||
new Info(),
|
new Info(),
|
||||||
|
new Settings(),
|
||||||
|
new TextToSpeech(),
|
||||||
|
new SpeechToText(),
|
||||||
|
|
||||||
new AdminsAdd(),
|
new AdminsAdd(),
|
||||||
new AdminsRemove(),
|
new AdminsRemove(),
|
||||||
@@ -173,13 +135,14 @@ if (Environment.ENABLE_UNSAFE_EVAL) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const callbackCommands: CallbackCommand[] = [
|
export const callbackCommands: CallbackCommand[] = [
|
||||||
new OllamaCancel(),
|
new AiCancel(),
|
||||||
|
new AiRegenerate(),
|
||||||
|
new UserSettingsCallback(),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_MODEL) {
|
if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_CHAT_MODEL) {
|
||||||
commands.push(
|
commands.push(
|
||||||
new OllamaChat(),
|
new OllamaChat(),
|
||||||
new OllamaPrompt(),
|
|
||||||
new OllamaListModels(),
|
new OllamaListModels(),
|
||||||
new OllamaGetModel(),
|
new OllamaGetModel(),
|
||||||
new OllamaSetModel()
|
new OllamaSetModel()
|
||||||
@@ -196,7 +159,6 @@ if (Environment.GEMINI_API_KEY) {
|
|||||||
new GeminiListModels(),
|
new GeminiListModels(),
|
||||||
new GeminiGetModel(),
|
new GeminiGetModel(),
|
||||||
new GeminiSetModel(),
|
new GeminiSetModel(),
|
||||||
new GeminiGenerateImage()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,14 +177,16 @@ if (Environment.OPENAI_API_KEY) {
|
|||||||
new OpenAIListModels(),
|
new OpenAIListModels(),
|
||||||
new OpenAIGetModel(),
|
new OpenAIGetModel(),
|
||||||
new OpenAISetModel(),
|
new OpenAISetModel(),
|
||||||
new OpenAIGenImage()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const cacheDir = path.join(Environment.DATA_PATH, "cache");
|
export const cacheDir = path.join(Environment.DATA_PATH, "cache");
|
||||||
export const photoDir = path.join(cacheDir, "photo");
|
export const photoDir = path.join(cacheDir, "photo");
|
||||||
export const photoGenDir = path.join(photoDir, "gen");
|
export const photoGenDir = path.join(photoDir, "gen");
|
||||||
|
export const documentDir = path.join(cacheDir, "document");
|
||||||
|
export const audioDir = path.join(cacheDir, "audio");
|
||||||
export const videoDir = path.join(cacheDir, "video");
|
export const videoDir = path.join(cacheDir, "video");
|
||||||
|
export const videoNotesDir = path.join(cacheDir, "video-note");
|
||||||
export const videoTempDir = path.join(videoDir, "temp");
|
export const videoTempDir = path.join(videoDir, "temp");
|
||||||
|
|
||||||
let isShuttingDown = false;
|
let isShuttingDown = false;
|
||||||
@@ -253,29 +217,29 @@ async function main() {
|
|||||||
`DEFAULT_AI_PROVIDER: ${Environment.DEFAULT_AI_PROVIDER}`
|
`DEFAULT_AI_PROVIDER: ${Environment.DEFAULT_AI_PROVIDER}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const dirsToCheck = [cacheDir, photoDir, photoGenDir, videoDir, videoTempDir];
|
const dirsToCheck = [cacheDir, photoDir, photoGenDir, documentDir, audioDir, videoDir, videoNotesDir, videoTempDir];
|
||||||
dirsToCheck.forEach(dir => {
|
dirsToCheck.forEach(dir => {
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
fs.mkdirSync(dir);
|
fs.mkdirSync(dir, {recursive: true});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const now = new Date();
|
// const now = new Date();
|
||||||
|
|
||||||
const midnight = new Date();
|
// const midnight = new Date();
|
||||||
midnight.setHours(0, 0, 0, 0);
|
// midnight.setHours(0, 0, 0, 0);
|
||||||
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 cache will be started in " + diff + "ms");
|
// console.log("Clearing up cache will be started in " + diff + "ms");
|
||||||
|
|
||||||
clearUpFolderFromOldFiles(cacheDir);
|
// clearUpFolderFromOldFiles(cacheDir);
|
||||||
delay(diff).then(() => {
|
// delay(diff).then(() => {
|
||||||
setInterval(() => {
|
// setInterval(() => {
|
||||||
console.log("Started clearing up cache");
|
// console.log("Started clearing up cache");
|
||||||
clearUpFolderFromOldFiles(cacheDir);
|
// clearUpFolderFromOldFiles(cacheDir);
|
||||||
}, 1000 * 60 * 60 * 24);
|
// }, 1000 * 60 * 60 * 24);
|
||||||
});
|
// });
|
||||||
|
|
||||||
const cmds = commands.filter(cmd => {
|
const cmds = commands.filter(cmd => {
|
||||||
return cmd.title && cmd.title.startsWith("/") && cmd.title.split(" ").length === 1 && cmd.description;
|
return cmd.title && cmd.title.startsWith("/") && cmd.title.split(" ").length === 1 && cmd.description;
|
||||||
@@ -311,6 +275,7 @@ bot.on("edited_message", processEditedMessage);
|
|||||||
bot.on("message", processNewMessage);
|
bot.on("message", processNewMessage);
|
||||||
bot.on("inline_query", processInlineQuery);
|
bot.on("inline_query", processInlineQuery);
|
||||||
bot.on("callback_query", processCallbackQuery);
|
bot.on("callback_query", processCallbackQuery);
|
||||||
|
bot.on("guest_message", processGuestMessage);
|
||||||
|
|
||||||
process.on("SIGTERM", () => {
|
process.on("SIGTERM", () => {
|
||||||
shutdown("SIGTERM").catch(logError);
|
shutdown("SIGTERM").catch(logError);
|
||||||
|
|||||||
Reference in New Issue
Block a user