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"));