109 lines
4.2 KiB
JavaScript
109 lines
4.2 KiB
JavaScript
import { Telegraf } from "telegraf";
|
||
import { config } from "dotenv";
|
||
import fetch from "node-fetch";
|
||
import OpenAI from "openai";
|
||
|
||
config();
|
||
|
||
const bot = new Telegraf(process.env.TELEGRAM_TOKEN);
|
||
|
||
// Initialize OpenAI client – environment provides base URL and API key
|
||
const openai = new OpenAI({
|
||
apiKey: process.env.AI_API_KEY,
|
||
baseURL: process.env.AI_BASE_URL,
|
||
});
|
||
|
||
// Helper: fetch recent emails via Lotus proxy
|
||
async function fetchRecentEmails(limit = 5) {
|
||
const base = process.env.LOTUS_BASE_URL;
|
||
const key = process.env.LOTUS_API_KEY;
|
||
if (!base || !key) {
|
||
return null;
|
||
}
|
||
const url = `${base}/emails?folder=inbox&count=${limit}`;
|
||
const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });
|
||
if (!res.ok) return null;
|
||
const data = await res.json();
|
||
return data?.data || [];
|
||
}
|
||
|
||
// Helper: fetch full email by unid
|
||
async function fetchEmail(unid) {
|
||
const base = process.env.LOTUS_BASE_URL;
|
||
const key = process.env.LOTUS_API_KEY;
|
||
if (!base || !key) return null;
|
||
const url = `${base}/email/${unid}`;
|
||
const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });
|
||
if (!res.ok) return null;
|
||
const data = await res.json();
|
||
return data?.data || null;
|
||
}
|
||
|
||
// /inbox – list recent emails
|
||
bot.command("inbox", async (ctx) => {
|
||
const emails = await fetchRecentEmails();
|
||
if (!emails) {
|
||
await ctx.reply("Lotus не подключён или произошла ошибка. Проверьте интеграцию Lotus.");
|
||
return;
|
||
}
|
||
if (emails.length === 0) {
|
||
await ctx.reply("Входящих писем нет.");
|
||
return;
|
||
}
|
||
let text = "Последние письма (отправьте номер, чтобы увидеть детали):\n";
|
||
emails.forEach((mail, idx) => {
|
||
const from = mail.from?.displayName || mail.from?.email || "Неизв. отправитель";
|
||
const subj = mail.subject || "(без темы)";
|
||
text += `${idx + 1}. ${from} – ${subj}\n`;
|
||
});
|
||
await ctx.reply(text);
|
||
// Store list in session for later selection
|
||
ctx.session = ctx.session || {};
|
||
ctx.session.inbox = emails;
|
||
});
|
||
|
||
// Handle numeric selection after /inbox
|
||
bot.on("text", async (ctx) => {
|
||
const txt = ctx.message.text.trim();
|
||
const num = parseInt(txt, 10);
|
||
if (ctx.session && ctx.session.inbox && !isNaN(num) && num >= 1 && num <= ctx.session.inbox.length) {
|
||
const mail = ctx.session.inbox[num - 1];
|
||
const full = await fetchEmail(mail.unid);
|
||
const body = full?.body?.text || "(нет текста)";
|
||
await ctx.reply(`*Тема:* ${mail.subject || "(без темы)"}\n*От:* ${mail.from?.displayName || mail.from?.email}\n\n${body}`, { parse_mode: "Markdown" });
|
||
// Save selected email for AI queries
|
||
ctx.session.currentMail = full;
|
||
return;
|
||
}
|
||
|
||
// If there is a selected email, treat the message as a question for AI
|
||
if (ctx.session && ctx.session.currentMail) {
|
||
const question = txt;
|
||
const emailText = ctx.session.currentMail.body?.text || "";
|
||
try {
|
||
const completion = await openai.chat.completions.create({
|
||
model: process.env.AI_MODEL || "gpt-4o-mini",
|
||
messages: [
|
||
{ role: "system", content: "Ты помогаешь отвечать на вопросы пользователя, используя содержание письма из Lotus. Сформулируй ответ кратко и по существу." },
|
||
{ role: "user", content: `Письмо:
|
||
${emailText}\n\nВопрос пользователя: ${question}` },
|
||
],
|
||
max_tokens: 500,
|
||
});
|
||
const answer = completion.choices[0].message.content;
|
||
await ctx.reply(answer);
|
||
} catch (e) {
|
||
await ctx.reply("Ошибка при обращении к AI: " + e.message);
|
||
}
|
||
return;
|
||
}
|
||
|
||
// Default fallback
|
||
await ctx.reply("Используй /inbox чтобы посмотреть последние письма, затем отправь номер письма. После этого можешь задавать вопросы, и я отвечу, используя содержание письма.");
|
||
});
|
||
|
||
bot.launch();
|
||
|
||
process.once("SIGINT", () => bot.stop("SIGINT"));
|
||
process.once("SIGTERM", () => bot.stop("SIGTERM"));
|