diff --git a/src/bot-menu.ts b/src/bot-menu.ts index cae0d8b..b2d676c 100644 --- a/src/bot-menu.ts +++ b/src/bot-menu.ts @@ -1,61 +1,11 @@ import bot from '@bot' import { triggerHHStart } from '@/hh/bot-commands' -import { askLLM } from '@/openai' - -export function sendMenu(chatId: number, isFirstTime: boolean) { - const text = isFirstTime - ? '👋 Добро пожаловать! Это твой первый вход' - : '💼 Главное меню' - - return bot.sendMessage(chatId, text, { - reply_markup: { - keyboard: [ - [{ text: '💼 Меню' }], - [{ text: '👤 Debug' }], - ], - resize_keyboard: true, - one_time_keyboard: false, - is_persistent: true, - }, - }) -} bot.on('message', async (msg) => { - const chatId = msg.chat.id - const text = msg.text - - if (!text || text.startsWith('/')) + if (!msg.text || msg.text.startsWith('/')) return - switch (text) { - case '💼 Меню': - - triggerHHStart(chatId) - break - - case '👤 Debug': { - askLLM('Привет, как дела?') - // const resume = await getResume(chatId) - // - // await bot.sendMessage(chatId, resume || '--') - - // const letter = await askGPT('test') - // - // const user = await prisma.user.findUnique({ - // where: { telegramId: BigInt(chatId) }, - // }) - // - // await bot.sendMessage( - // chatId, - // `👤:\n\n - // Username: @${user?.username ?? 'нет'}\n - // Письмо: ${letter}\n - // HH Email: ${user?.hhEmail}\n - // Создан: ${user?.createdAt} - // - // `, - // ) - // break - } + if (msg.text === '💼 Меню') { + await triggerHHStart(msg.chat.id) } }) diff --git a/src/hh/bot-commands.ts b/src/hh/bot-commands.ts index d8a7d32..132fe85 100644 --- a/src/hh/bot-commands.ts +++ b/src/hh/bot-commands.ts @@ -3,6 +3,10 @@ import prisma from '@prisma' import cron, { type ScheduledTask } from 'node-cron' import { applyToJobs, checkIsAuth, listResumes, login, type ResumeListItem, saveResume } from './scraper.js' +function escapeHtml(text: string): string { + return text.replace(/&/g, '&').replace(//g, '>') +} + interface UserState { autoCron: ScheduledTask | null awaitingEmail: boolean @@ -10,6 +14,8 @@ interface UserState { awaitingMax: boolean tempEmail: string pendingResumes: ResumeListItem[] + menuMessageId: number | null + loginPromptMessageId: number | null } function makeUserState(): UserState { @@ -20,6 +26,8 @@ function makeUserState(): UserState { awaitingMax: false, tempEmail: '', pendingResumes: [], + menuMessageId: null, + loginPromptMessageId: null, } } @@ -31,42 +39,114 @@ function getState(chatId: number): UserState { return states.get(chatId)! } -async function sendResumeSelector(chatId: number, resumes: ResumeListItem[]) { - getState(chatId).pendingResumes = resumes - await bot.sendMessage(chatId, '📄 Выбери резюме:', { +const MAIN_MARKUP = { + inline_keyboard: [ + [{ text: '🚀 Откликнуться сейчас', callback_data: 'hh_apply' }], + [ + { text: '🔍 Изменить запрос', callback_data: 'hh_query' }, + { text: '🔢 Макс откликов', callback_data: 'hh_max' }, + ], + [ + { text: '⏰ Авто вкл', callback_data: 'hh_auto_start' }, + { text: '⛔ Авто выкл', callback_data: 'hh_auto_stop' }, + ], + [ + { text: '🔑 Логин', callback_data: 'hh_login' }, + { text: '⚙️ Статус', callback_data: 'hh_status' }, + ], + [ + { text: '📄 Выбрать резюме', callback_data: 'hh_resume_list' }, + { text: '📋 Моё резюме', callback_data: 'hh_my_resume' }, + ], + ], +} + +const BACK_MARKUP = { + inline_keyboard: [[{ text: '◀️ Назад', callback_data: 'hh_back' }]], +} + +// Редактирует существующее сообщение-меню или отправляет новое +async function showMenu(chatId: number, messageId?: number | null): Promise { + const state = getState(chatId) + const targetId = messageId ?? state.menuMessageId + + if (targetId) { + try { + await bot.editMessageText('🤖 HH Auto-Apply', { + chat_id: chatId, + message_id: targetId, + reply_markup: MAIN_MARKUP, + }) + state.menuMessageId = targetId + return + } + catch { + // Сообщение устарело или недоступно — отправим новое + } + } + + const msg = await bot.sendMessage(chatId, '🤖 HH Auto-Apply', { + reply_markup: MAIN_MARKUP, + }) + state.menuMessageId = msg.message_id +} + +// Редактирует сообщение с меню: показывает текст + кнопку "Назад" +async function showResult(chatId: number, messageId: number, text: string): Promise { + await bot.editMessageText(text, { + chat_id: chatId, + message_id: messageId, + reply_markup: BACK_MARKUP, + }) +} + +async function sendResumeSelector(chatId: number, resumes: ResumeListItem[], messageId: number): Promise { + const state = getState(chatId) + state.pendingResumes = resumes + await bot.editMessageText('📄 Выбери резюме:', { + chat_id: chatId, + message_id: messageId, reply_markup: { - inline_keyboard: resumes.map((r, i) => [ - { text: r.title, callback_data: `hh_resume_pick_${i}` }, - ]), + inline_keyboard: [ + ...resumes.map((r, i) => [{ text: r.title, callback_data: `hh_resume_pick_${i}` }]), + [{ text: '◀️ Назад', callback_data: 'hh_back' }], + ], }, }) } -export function triggerHHStart(chatId: number): void { - bot.sendMessage(chatId, '🤖 HH Auto-Apply', { - reply_markup: { - inline_keyboard: [ - [ - { text: '🚀 Откликнуться сейчас', callback_data: 'hh_apply' }, - ], - [ - { text: '🔍 Изменить запрос', callback_data: 'hh_query' }, - { text: '🔢 Макс откликов', callback_data: 'hh_max' }, - ], - [ - { text: '⏰ Авто вкл', callback_data: 'hh_auto_start' }, - { text: '⛔ Авто выкл', callback_data: 'hh_auto_stop' }, - ], - [ - { text: '🔑 Логин', callback_data: 'hh_login' }, - { text: '⚙️ Статус', callback_data: 'hh_status' }, - ], - [ - { text: '📄 Выбрать резюме', callback_data: 'hh_resume_list' }, - ], - ], - }, - }) +async function doLogin(chatId: number, email: string): Promise { + await bot.sendMessage(chatId, '🔄 Логинюсь...') + try { + await login(email, chatId) + await prisma.user.update({ where: { telegramId: chatId }, data: { hhEmail: email } }) + + const resumes = await listResumes(chatId) + const state = getState(chatId) + + if (resumes.length === 0) { + await bot.sendMessage(chatId, '⚠️ Резюме не найдены. Создайте резюме на hh.ru') + } + else if (resumes.length === 1) { + await saveResume(chatId, resumes[0].href) + await bot.sendMessage(chatId, `✅ Резюме сохранено: ${resumes[0].title}`) + } + else if (state.menuMessageId) { + await sendResumeSelector(chatId, resumes, state.menuMessageId) + return + } + + await bot.sendMessage(chatId, '✅ Авторизован! Куки сохранены.') + await showMenu(chatId) + } + catch (e) { + await bot.sendMessage(chatId, `❌ Ошибка: ${(e as Error).message}`) + await showMenu(chatId) + } +} + +export async function triggerHHStart(chatId: number): Promise { + await showMenu(chatId) } export function registerHHCommands() { @@ -77,91 +157,194 @@ export function registerHHCommands() { bot.on('callback_query', async (query) => { if (!query.message) return + const chatId = query.message.chat.id + const messageId = query.message.message_id const state = getState(chatId) - bot.answerCallbackQuery(query.id) + await bot.answerCallbackQuery(query.id) const user = await prisma.user.findUnique({ where: { telegramId: chatId }, include: { Settings: true }, }) - const settings = user!.Settings! switch (query.data) { - case 'hh_apply': - await bot.sendMessage(chatId, `🚀 Ищу: "${settings.searchQuery}"...`) - applyToJobs({ query: settings.searchQuery, maxApplies: settings.maxApplies }, { - chatId, - }).then((result) => { - if (result.error) - return bot.sendMessage(chatId, `❌ ${result.error}`) - const lines = result.applied.map((v, i) => `${i + 1}. ${v}`).join('\n') - bot.sendMessage(chatId, `✅ Откликнулся: ${result.applied.length}\n${lines}\n\n` - + `⏭ Пропущено: ${result.skipped.length}\n${ - result.errors.length ? `❌ Ошибок: ${result.errors.length}` : ''}`) - }) + case 'hh_back': + await showMenu(chatId, messageId) break - case 'hh_status': - await bot.sendMessage(chatId, `⚙️ Настройки:\n - Запрос: ${settings.searchQuery}\n - Макс откликов: ${settings.maxApplies}\n - Авто: ${state.autoCron ? '✅ включено' : '❌ выключено'}\n - Авторизован: ${await checkIsAuth(chatId)}`) + case 'hh_apply': { + await bot.editMessageText(`🔄 Ищу вакансии по запросу "${settings.searchQuery}"...`, { + chat_id: chatId, + message_id: messageId, + reply_markup: { inline_keyboard: [] }, + }) + state.menuMessageId = null + + applyToJobs({ query: settings.searchQuery, maxApplies: settings.maxApplies }, { chatId }) + .then(async (result) => { + if (result.error) { + await bot.sendMessage(chatId, `❌ ${result.error}`) + } + else { + const lines: string[] = [] + + lines.push(`📊 Итого по запросу «${settings.searchQuery}»`) + lines.push(`✅ Откликнулся: ${result.applied.length}`) + lines.push(`⏭ Пропущено: ${result.skipped.length}`) + if (result.errors.length) + lines.push(`❌ Ошибок: ${result.errors.length}`) + + if (result.skipped.length) { + lines.push('') + lines.push('⏭ Пропущенные:') + result.skipped.forEach(v => lines.push(`• ${v.title}`)) + } + + if (result.errors.length) { + lines.push('') + lines.push('❌ Ошибки:') + result.errors.forEach(v => lines.push(`• ${v.title} — ${v.message}`)) + } + + await bot.sendMessage(chatId, lines.join('\n'), { + parse_mode: 'HTML', + disable_web_page_preview: true, + }) + } + await showMenu(chatId) + }) break + } + + case 'hh_status': { + const isAuth = await checkIsAuth(chatId) + await showResult( + chatId, + messageId, + `⚙️ Настройки:\n\nЗапрос: ${settings.searchQuery}\nМакс откликов: ${settings.maxApplies}\nАвто: ${state.autoCron ? '✅ включено' : '😬 выключено'}\nАвторизован: ${isAuth}`, + ) + break + } + + case 'hh_my_resume': { + const resume = await prisma.resume.findFirst({ + where: { telegramId: chatId }, + orderBy: { id: 'asc' }, + }) + if (!resume) { + await showResult(chatId, messageId, '📋 Резюме не найдено.\n\nВыбери резюме через кнопку 📄 Выбрать резюме.') + break + } + + const MAX = 3800 + const text = resume.data.length > MAX + ? `${resume.data.slice(0, MAX)}\n\n… (текст обрезан)` + : resume.data + + await bot.editMessageText( + `📋 Твоё резюме\n
${escapeHtml(text)}
`, + { + chat_id: chatId, + message_id: messageId, + parse_mode: 'HTML', + reply_markup: BACK_MARKUP, + }, + ) + break + } case 'hh_login': - state.awaitingEmail = true + state.menuMessageId = messageId if (!user?.hhEmail) { + state.awaitingEmail = true await bot.sendMessage(chatId, '📧 Введи email от hh.ru:') } else { - await bot.sendMessage(chatId, `📧 Email от hh.ru: ${user?.hhEmail}`) + state.awaitingEmail = true + const prompt = await bot.sendMessage( + chatId, + `📧 Текущий email: ${user.hhEmail}\n\nИспользовать его или введи другой:`, + { + parse_mode: 'HTML', + reply_markup: { + inline_keyboard: [[ + { text: `✅ Войти как ${user.hhEmail}`, callback_data: 'hh_login_use_current' }, + ]], + }, + }, + ) + state.loginPromptMessageId = prompt.message_id } break + case 'hh_login_use_current': { + state.awaitingEmail = false + await bot.deleteMessage(chatId, messageId).catch(() => {}) + state.loginPromptMessageId = null + const email = user?.hhEmail + if (!email) { + await bot.sendMessage(chatId, '❌ Email не найден, введи вручную') + state.awaitingEmail = true + break + } + await doLogin(chatId, email) + break + } + case 'hh_query': state.awaitingQuery = true + state.menuMessageId = messageId await bot.sendMessage(chatId, '🔍 Введи поисковый запрос:') break case 'hh_max': state.awaitingMax = true + state.menuMessageId = messageId await bot.sendMessage(chatId, '🔢 Введи максимальное количество откликов (1-50):') break case 'hh_auto_start': if (state.autoCron) { - await bot.sendMessage(chatId, 'Уже запущено!') + await showResult(chatId, messageId, '⚠️ Авто уже запущено') break } state.autoCron = cron.schedule('0 10 * * 1-5', async () => { await bot.sendMessage(chatId, '⏰ Авто-отклик...') }) - await bot.sendMessage(chatId, '✅ Авто включён (пн-пт, 10:00)') + await showResult(chatId, messageId, '✅ Авто включён (пн-пт, 10:00)') break case 'hh_auto_stop': state.autoCron?.stop() state.autoCron = null - await bot.sendMessage(chatId, '⛔ Авто остановлен') + await showResult(chatId, messageId, '⛔ Авто остановлен') break case 'hh_resume_list': { - await bot.sendMessage(chatId, '🔄 Загружаю список резюме...') + await bot.editMessageText('🔄 Загружаю список резюме...', { + chat_id: chatId, + message_id: messageId, + reply_markup: { inline_keyboard: [] }, + }) const resumes = await listResumes(chatId) if (resumes.length === 0) { - await bot.sendMessage(chatId, '❌ Резюме не найдены. Создайте резюме на hh.ru') + await showResult(chatId, messageId, '😬 Резюме не найдены. Создайте резюме на hh.ru') } else if (resumes.length === 1) { - await bot.sendMessage(chatId, '🔄 Сохраняю резюме...') + await bot.editMessageText('🔄 Сохраняю резюме...', { + chat_id: chatId, + message_id: messageId, + reply_markup: { inline_keyboard: [] }, + }) await saveResume(chatId, resumes[0].href) - await bot.sendMessage(chatId, `✅ Резюме сохранено: ${resumes[0].title}`) + await showResult(chatId, messageId, `✅ Резюме сохранено: ${resumes[0].title}`) } else { - await sendResumeSelector(chatId, resumes) + state.menuMessageId = messageId + await sendResumeSelector(chatId, resumes, messageId) } break } @@ -171,13 +354,17 @@ export function registerHHCommands() { const idx = Number(query.data.replace('hh_resume_pick_', '')) const resume = state.pendingResumes[idx] if (!resume) { - await bot.sendMessage(chatId, '❌ Резюме не найдено, попробуйте снова') + await showResult(chatId, messageId, '😬 Резюме не найдено, попробуйте снова') break } - await bot.sendMessage(chatId, '🔄 Сохраняю резюме...') + await bot.editMessageText('🔄 Сохраняю резюме...', { + chat_id: chatId, + message_id: messageId, + reply_markup: { inline_keyboard: [] }, + }) await saveResume(chatId, resume.href) - await bot.sendMessage(chatId, `✅ Резюме выбрано: ${resume.title}`) state.pendingResumes = [] + await showResult(chatId, messageId, `✅ Резюме выбрано: ${resume.title}`) } break } @@ -198,62 +385,42 @@ export function registerHHCommands() { }) if (state.awaitingEmail) { - state.tempEmail = user?.hhEmail || msg.text state.awaitingEmail = false - await bot.deleteMessage(chatId, msg.message_id).catch(() => {}) - await bot.sendMessage(chatId, '🔄 Логинюсь...') - try { - await login(state.tempEmail, chatId) - await bot.sendMessage(chatId, '✅ Авторизован! Куки сохранены.') - - await prisma.user.update({ - where: { telegramId: chatId }, - data: { hhEmail: state.tempEmail }, - }) - - const resumes = await listResumes(chatId) - if (resumes.length === 0) { - await bot.sendMessage(chatId, '❌ Резюме не найдены. Создайте резюме на hh.ru') - } - else if (resumes.length === 1) { - await saveResume(chatId, resumes[0].href) - await bot.sendMessage(chatId, `✅ Резюме сохранено: ${resumes[0].title}`) - } - else { - await sendResumeSelector(chatId, resumes) - } - - triggerHHStart(chatId) - } - catch (e) { - await bot.sendMessage(chatId, `😬 Ошибка: ${(e as Error).message}`) + if (state.loginPromptMessageId) { + await bot.deleteMessage(chatId, state.loginPromptMessageId).catch(() => {}) + state.loginPromptMessageId = null } + await doLogin(chatId, msg.text) return } if (state.awaitingQuery) { state.awaitingQuery = false + await bot.deleteMessage(chatId, msg.message_id).catch(() => {}) const updated = await prisma.settings.update({ where: { telegramId: chatId }, data: { searchQuery: msg.text }, }) await bot.sendMessage(chatId, `✅ Запрос: "${updated.searchQuery}"`) + await showMenu(chatId) return } if (state.awaitingMax) { - state.awaitingMax = false const num = Number(msg.text) - if (num < 1 || num > 50) { - await bot.sendMessage(chatId, '❌ Число от 1 до 50') + if (Number.isNaN(num) || num < 1 || num > 50) { + await bot.sendMessage(chatId, '😬 Введи число от 1 до 50:') return } + state.awaitingMax = false + await bot.deleteMessage(chatId, msg.message_id).catch(() => {}) const updated = await prisma.settings.update({ where: { telegramId: chatId }, data: { maxApplies: num }, }) await bot.sendMessage(chatId, `✅ Макс откликов: ${updated.maxApplies}`) + await showMenu(chatId) } }) } diff --git a/src/hh/scraper.ts b/src/hh/scraper.ts index 6d4d66e..e89f701 100644 --- a/src/hh/scraper.ts +++ b/src/hh/scraper.ts @@ -12,10 +12,15 @@ interface ApplyOptions { maxApplies?: number } +interface VacancyRef { + title: string + href: string +} + interface ApplyResult { - applied: string[] - skipped: string[] - errors: string[] + applied: VacancyRef[] + skipped: VacancyRef[] + errors: Array error?: string } @@ -76,7 +81,7 @@ export async function login( await bot.sendMessage(chatId, `Browser is connected: ${browser.isConnected()}`) if (!browser.version()) return - await bot.sendMessage(chatId, `Browser version: ${browser.version()}`) + // await bot.sendMessage(chatId, `Browser version: ${browser.version()}`) const context = await browser.newContext() const page = await context.newPage() @@ -136,7 +141,12 @@ export async function login( }, }) - await bot.sendMessage(chatId, `cookies: ${cookies.length}`) + if (cookies.length > 0) { + await bot.sendMessage(chatId, `✅ Авторизация выполнена`) + } + else { + await bot.sendMessage(chatId, `😬 Произошла ошибка`) + } await browser.close() } @@ -230,6 +240,25 @@ export async function applyToJobs({ const page = await context.newPage() const results: ApplyResult = { applied: [], skipped: [], errors: [] } + let statusMsgId: number | null = null + + async function status(text: string): Promise { + if (statusMsgId) { + await bot.deleteMessage(chatId, statusMsgId).catch(() => {}) + statusMsgId = null + } + const msg = await bot.sendMessage(chatId, text) + statusMsgId = msg.message_id + } + + async function keep(text: string): Promise { + if (statusMsgId) { + await bot.deleteMessage(chatId, statusMsgId).catch(() => {}) + statusMsgId = null + } + await bot.sendMessage(chatId, text, { parse_mode: 'HTML' }) + } + try { await loadSession(page, chatId) @@ -237,12 +266,11 @@ export async function applyToJobs({ await page.goto(url, { waitUntil: 'networkidle' }) const isLoggedIn = await page.$('[data-qa="profileAndResumes-button"]') - // await page.$('[data-qa="mainmenu_myResumes"]') if (!isLoggedIn) { return { ...results, error: 'Не авторизован. Выполните login' } } - await bot.sendMessage(chatId, `✅ Авторизация выполнена`) + await status(`✅ Авторизация выполнена`) const vacancies = await page.$$eval( '[data-qa="serp-item__title"]', @@ -252,65 +280,49 @@ export async function applyToJobs({ })), ) - await bot.sendMessage(chatId, `✅ Вакансий найдено: ${vacancies.length}`) + await status(`✅ Вакансий найдено: ${vacancies.length}`) + + const resume = await prisma.resume.findFirst({ where: { telegramId: chatId } }) + const user = await prisma.user.findUnique({ where: { telegramId: chatId } }) + + if (!resume?.data) { + await keep('❌ Резюме не выбрано — выбери резюме через меню') + return results + } for (const vacancy of vacancies.slice(0, maxApplies)) { + const ref: VacancyRef = { title: vacancy.title, href: vacancy.href } try { - await bot.sendMessage(chatId, `🔄 Обрабатывается вакансия: ${vacancy.title}`) + await status(`🔄 Обрабатывается: ${vacancy.title}`) await page.goto(vacancy.href, { waitUntil: 'networkidle' }) const description = await page .locator('[data-qa="vacancy-description"]') .innerText() + .catch(() => '') if (!description) { - await bot.sendMessage(chatId, `😬 Ошибка с получением описания`) + results.skipped.push(ref) continue } - await bot.sendMessage(chatId, `✅ Описание получено`) + await status(`✍️ Генерирую письмо: ${vacancy.title}`) - const resume = await prisma.resume.findFirst({ - where: { telegramId: chatId }, - }) + const letter = await createMessage(resume.data, description, user!.prompt) - if (!resume?.data) { - results.errors.push(`${vacancy.title}: резюме не выбрано — выберите резюме через меню`) - continue - } + await keep(`✅ ${vacancy.title}\n\n${letter}`) - const user = await prisma.user.findUnique({ - where: { telegramId: chatId }, - }) - - const letter = await createMessage(resume!.data, description, user!.prompt) - - await bot.sendMessage(chatId, `✅ Сопроводительное письмо отправлено: ${letter}`) - - // const applyBtn = await page.$('[data-qa="vacancy-response-link-top"]') - // if (!applyBtn) { - // results.skipped.push(vacancy.title) - // continue - // } - // - // await randomScroll(page) - // - // await applyBtn.click() - // await page.waitForTimeout(randomDelay()) - // - // const submitBtn = await page.$('[data-qa="vacancy-response-popup-submit"]') - // if (submitBtn) { - // await submitBtn.click() - // await page.waitForTimeout(randomDelay()) - // } - - results.applied.push(vacancy.title) - // await page.waitForTimeout(3000 + Math.random() * 2000) + results.applied.push(ref) } catch (err) { - results.errors.push(`${vacancy.title}: ${(err as Error).message}`) + results.errors.push({ ...ref, message: (err as Error).message }) } } + + if (statusMsgId) { + await bot.deleteMessage(chatId, statusMsgId).catch(() => {}) + statusMsgId = null + } } finally { await browser.close() diff --git a/src/index.ts b/src/index.ts index 308b8d0..eb33e2c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import bot from '@bot' import prisma from '@prisma' -import { sendMenu } from './bot-menu' +import { triggerHHStart } from './hh/bot-commands.js' import { registerHHCommands } from './hh/bot-commands.js' registerHHCommands() @@ -10,17 +10,11 @@ bot.onText(/\/start/, async (msg) => { const chatId = msg.chat.id const telegramId = BigInt(chatId) - const existingUser = await prisma.user.findUnique({ - where: { telegramId }, - }) - - const isFirstTime = !existingUser + const existingUser = await prisma.user.findUnique({ where: { telegramId } }) await prisma.user.upsert({ where: { telegramId }, - update: { - username: msg.from?.username ?? null, - }, + update: { username: msg.from?.username ?? null }, create: { telegramId, username: msg.from?.username ?? null, @@ -29,7 +23,14 @@ bot.onText(/\/start/, async (msg) => { }, }) - await sendMenu(chatId, isFirstTime) + if (!existingUser) { + await bot.sendMessage( + chatId, + `👋 Привет, ${msg.from?.first_name ?? 'друг'}!\n\nЭто бот для авто-откликов на hh.ru.\nНачни с логина — нажми 🔑 Логин.`, + ) + } + + await triggerHHStart(chatId) }) console.log('Bot started 🚀') diff --git a/src/openai.ts b/src/openai.ts index fc432fd..b9e53a8 100644 --- a/src/openai.ts +++ b/src/openai.ts @@ -81,25 +81,26 @@ export async function askLLM(userMessage: string) { return textPart?.text ?? '' } -export async function createMessage(resume: string, message: string, prompt: string) { +export async function createMessage(resume: string, message: string, prompt?: string) { const client = await getClient() const session = await client.session.create({ body: { title: 'Cover letter' } }) const sessionId = session.data!.id + const finalPromt = 'Ты — помощник по написанию сопроводительных писем. Отвечай только текстом самого письма, без вступлений, ремарок и пояснений. Пиши по короче и простыми словами. В конце письма оставляй все контакты для связи.' // Задаём роль без ответа await client.session.prompt({ path: { id: sessionId }, body: { noReply: true, - parts: [{ type: 'text', text: 'Ты — помощник по написанию сопроводительных писем. Отвечай только текстом самого письма, без вступлений, ремарок и пояснений.' }], + parts: [{ type: 'text', text: finalPromt }], }, }) - + // ${prompt}\n\n const result = await client.session.prompt({ path: { id: sessionId }, body: { - parts: [{ type: 'text', text: `${prompt}\n\nРезюме:\n${resume}\n\nВакансия:\n${message}` }], + parts: [{ type: 'text', text: `Резюме:\n${resume}\n\nВакансия:\n${message}` }], }, })