Add AI filter and suggest

This commit is contained in:
2025-02-19 20:14:23 +03:00
parent 548c2f9d40
commit 1ca8f506a9
8 changed files with 131 additions and 9 deletions
@@ -66,22 +66,21 @@ public class KeyboardHelper {
} }
public static ReplyKeyboardMarkup getBookMenuKeyboard() { public static ReplyKeyboardMarkup getBookMenuKeyboard() {
List<KeyboardRow> keyboardRows = new ArrayList<>();
KeyboardRow row1 = new KeyboardRow(); KeyboardRow row1 = new KeyboardRow();
row1.add(new KeyboardButton(ADD_BOOK)); row1.add(new KeyboardButton(ADD_BOOK));
row1.add(new KeyboardButton(LIST_BOOKS)); row1.add(new KeyboardButton(EDIT_BOOKS));
KeyboardRow row2 = new KeyboardRow(); KeyboardRow row2 = new KeyboardRow();
row2.add(new KeyboardButton(EDIT_BOOKS)); row2.add(new KeyboardButton(LIST_BOOKS));
row2.add(new KeyboardButton(FILTER_BOOKS));
KeyboardRow row3 = new KeyboardRow(); KeyboardRow row3 = new KeyboardRow();
row3.add(new KeyboardButton(RECOMMEND_BOOKS));
row3.add(new KeyboardButton(SET_BOOKS_GOAL_FROM_BOOKS)); row3.add(new KeyboardButton(SET_BOOKS_GOAL_FROM_BOOKS));
row3.add(new KeyboardButton(BACK)); row3.add(new KeyboardButton(BACK));
keyboardRows.add(row1); List<KeyboardRow> keyboardRows = List.of(row1,row2,row3);
keyboardRows.add(row2);
keyboardRows.add(row3);
ReplyKeyboardMarkup keyboardMarkup = new ReplyKeyboardMarkup(keyboardRows); ReplyKeyboardMarkup keyboardMarkup = new ReplyKeyboardMarkup(keyboardRows);
keyboardMarkup.setResizeKeyboard(true); keyboardMarkup.setResizeKeyboard(true);
@@ -202,4 +201,33 @@ public class KeyboardHelper {
} }
public static ReplyKeyboardMarkup getAiMenuKeyboard(BotUser.WorkingMode workingMode) {
KeyboardRow row1 = new KeyboardRow();
KeyboardRow row2 = new KeyboardRow();
switch (workingMode) {
case AI_FILTER -> {
row1.add(new KeyboardButton(AI_FILTER_GENRE));
row2.add(new KeyboardButton(AI_FILTER_RATING));
}
case AI_SUGGEST -> {
row1.add(new KeyboardButton(AI_SUGGEST_GENRE));
row2.add(new KeyboardButton(AI_SUGGEST_SIMILAR));
}
}
KeyboardRow row3 = new KeyboardRow();
row3.add(new KeyboardButton(BACK));
List<KeyboardRow> keyboardRows = List.of(row1,row2,row3);
ReplyKeyboardMarkup keyboardMarkup = new ReplyKeyboardMarkup(keyboardRows);
keyboardMarkup.setResizeKeyboard(true);
keyboardMarkup.setOneTimeKeyboard(false);
return keyboardMarkup;
}
} }
@@ -21,7 +21,7 @@ public class BotUser {
USER, ADMIN } USER, ADMIN }
public enum WorkingMode { public enum WorkingMode {
BOOK,TORRENT,AI,EDIT_PROFILE,NO_MODE BOOK,TORRENT,AI,EDIT_PROFILE,NO_MODE,AI_FILTER,AI_SUGGEST
} }
private Integer booksToRead; private Integer booksToRead;
@@ -3,7 +3,12 @@ package ru.cathub.telegabot.model;
public enum TextRole { public enum TextRole {
DEFAULT("Ты книжный ассистент в Telegram-боте. Отвечай, используй эмоджи, разметку Markdown (*для\n" + DEFAULT("Ты книжный ассистент в Telegram-боте. Отвечай, используй эмоджи, разметку Markdown (*для\n" +
" выделения*, _для наклонного_). Отвечай ТОЛЬКО на русском языке."), " выделения*, _для наклонного_). Отвечай ТОЛЬКО на русском языке."),
REVIEWER("Анализируй текст как профессиональный редактор"), SUGGESTER("Ты книжный ассистент в Telegram-боте, который помогает находить новые книги. Отвечай, используй эмоджи, разметку Markdown (*для\n" +
" выделения*, _для наклонного_). Тебе будет передан список книг пользователя и ты должен проанализировать\n" +
" этот список, и далее отвечать операясь на предпочтения пользоватья из этого списка"),
FILTERER("Ты книжный ассистент в Telegram-боте, который фильтрует списки. Отвечай, используй эмоджи, разметку Markdown (*для\n" +
" выделения*, _для наклонного_). Тебе будет передан список книг пользователя и ты должен вывести книги,\n"+
" которые удовлетворяют запросу пользователя из этого списка. Если таких книг нет, то отвечай, что книги не найдены"),
RECOMMENDER("Рекомендуй книги на основе предпочтений"); RECOMMENDER("Рекомендуй книги на основе предпочтений");
private final String systemPrompt; private final String systemPrompt;
@@ -0,0 +1,9 @@
package ru.cathub.telegabot.service;
import ru.cathub.telegabot.model.BotUser;
public interface BookAiService {
void processAiRequest(BotUser user, String text, BotUser.WorkingMode workingMode);
void handleAiStartMessage(BotUser botUser, BotUser.WorkingMode workingMode);
}
@@ -0,0 +1,58 @@
package ru.cathub.telegabot.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.cathub.telegabot.bot.KeyboardHelper;
import ru.cathub.telegabot.model.BotUser;
import ru.cathub.telegabot.model.TextRole;
import ru.cathub.telegabot.repository.UserRepository;
import ru.cathub.telegabot.service.BookAiService;
import ru.cathub.telegabot.service.TelegramClientService;
import static ru.cathub.telegabot.model.BotUser.WorkingMode.*;
import static ru.cathub.telegabot.utils.BookFormatUtils.escapeNonMarkdown;
@Service
@RequiredArgsConstructor
@Slf4j
public class BookAiServiceImpl implements BookAiService {
private final UserRepository userRepository;
private final TelegramClientService telegramClientService;
private final OpenRouterServiceImpl openRouterServiceImpl;
@Override
public void processAiRequest(BotUser user, String text, BotUser.WorkingMode workingMode) {
try {
String response = null;
switch (workingMode) {
case AI_FILTER -> {response = openRouterServiceImpl.getChatResponse(text, TextRole.FILTERER);}
case AI_SUGGEST -> {response =openRouterServiceImpl.getChatResponse(text, TextRole.SUGGESTER);}
}
telegramClientService.sendMessageWithMarkdown(user, escapeNonMarkdown(response));
}
catch (Exception e) {
log.error("Error processing AI request for user {}", user.getId(), e);
telegramClientService.sendMessage(user, "x Ошибка в ответе от AI");
}
}
@Override
public void handleAiStartMessage(BotUser botUser, BotUser.WorkingMode workingMode) {
botUser.setWorkingMode(workingMode);
userRepository.save(botUser);
telegramClientService.sendMessageWithMarkdown(botUser
, getWelcomeMessage(workingMode)
, KeyboardHelper.getAiMenuKeyboard(workingMode));
}
private String getWelcomeMessage(BotUser.WorkingMode workingMode) {
if (workingMode == AI_FILTER) {
return "Введите запрос к AI для фильтрации книг или выберите один из примеров запроса";
} else if (workingMode == AI_SUGGEST) {
return "Введите запрос к AI для предложения книг или выберите один из примеров запроса";
}
return "Введите запрос к AI";
}
}
@@ -11,6 +11,8 @@ import ru.cathub.telegabot.repository.BookRepository;
import ru.cathub.telegabot.repository.UserRepository; import ru.cathub.telegabot.repository.UserRepository;
import ru.cathub.telegabot.service.*; import ru.cathub.telegabot.service.*;
import static ru.cathub.telegabot.model.BotUser.WorkingMode.AI_FILTER;
import static ru.cathub.telegabot.model.BotUser.WorkingMode.AI_SUGGEST;
import static ru.cathub.telegabot.utils.Constants.*; import static ru.cathub.telegabot.utils.Constants.*;
@@ -26,6 +28,7 @@ public class BookManageServiceImpl implements BookManageService {
private final BookCacheService bookCacheService; private final BookCacheService bookCacheService;
private final BookRepository bookRepository; private final BookRepository bookRepository;
private final TelegramClientService telegramClientService; private final TelegramClientService telegramClientService;
private final BookAiService bookAiService;
@@ -52,6 +55,12 @@ public class BookManageServiceImpl implements BookManageService {
bookCacheService.clearBookEditCache(userId); bookCacheService.clearBookEditCache(userId);
bookCreationService.handleNewAddRequest(user, text); bookCreationService.handleNewAddRequest(user, text);
break; break;
case RECOMMEND_BOOKS:
bookAiService.handleAiStartMessage(user, AI_SUGGEST);
break;
case FILTER_BOOKS:
bookAiService.handleAiStartMessage(user, AI_FILTER);;
break;
default: default:
if (creationCache != null && creationCache.getCreationState() != null) { if (creationCache != null && creationCache.getCreationState() != null) {
// Handle book creation states // Handle book creation states
@@ -21,6 +21,7 @@ public class TelegramBotServiceImpl implements TelegramBotService {
private final BookManageService bookManageService; private final BookManageService bookManageService;
private final ProfileService profileService; private final ProfileService profileService;
private final UserRepository userRepository; private final UserRepository userRepository;
private final BookAiServiceImpl bookAiServiceImpl;
@Override @Override
public void processInput(BotUser botUser, String text) throws ServiceException { public void processInput(BotUser botUser, String text) throws ServiceException {
@@ -61,6 +62,9 @@ public class TelegramBotServiceImpl implements TelegramBotService {
case EDIT_PROFILE: case EDIT_PROFILE:
profileService.handleProfileUpdate(botUser, text); profileService.handleProfileUpdate(botUser, text);
break; break;
case AI_FILTER,AI_SUGGEST:
bookAiServiceImpl.processAiRequest(botUser,text,botUser.getWorkingMode());
break;
} }
} }
} }
@@ -13,7 +13,9 @@ public class Constants {
public static final String LIST_BOOKS = "Список книг"; public static final String LIST_BOOKS = "Список книг";
public static final String BACK = "Назад"; public static final String BACK = "Назад";
public static final String EDIT_BOOKS = "Редактировать книги"; public static final String EDIT_BOOKS = "Редактировать книги";
public static final String RECOMMEND_BOOKS = "Рекомендации книг";
public static final String FILTER_BOOKS = "Фильтр по прочитанным";
// Cache names // Cache names
public static final String BOOK_CACHE_NAME = "bookCache"; public static final String BOOK_CACHE_NAME = "bookCache";
public static final String BOOK_CACHE_LIST = "bookListCache"; public static final String BOOK_CACHE_LIST = "bookListCache";
@@ -38,4 +40,11 @@ public class Constants {
public static final String ERROR_DELETE_BOOKS = "❌ Ошибка при удвлении книги"; public static final String ERROR_DELETE_BOOKS = "❌ Ошибка при удвлении книги";
public static final String ERROR_NO_ACTION = "❌ Нет текущего действия. Выберите действие из меню или перейдите в начальное меню командой /start"; public static final String ERROR_NO_ACTION = "❌ Нет текущего действия. Выберите действие из меню или перейдите в начальное меню командой /start";
public static final String ERROR_INVALID_DATE_FORMAT = "Неверный формат даты. Используйте ДД.ММ.ГГГГ"; public static final String ERROR_INVALID_DATE_FORMAT = "Неверный формат даты. Используйте ДД.ММ.ГГГГ";
// AI
public static final String AI_FILTER_GENRE = "Отфильтруй книги по жанру комедия";
public static final String AI_FILTER_RATING = "Отфильтруй книги по по рейтингу больше 8";
public static final String AI_SUGGEST_SIMILAR = "Предложи похожие книги";
public static final String AI_SUGGEST_GENRE = "Предложи еше книги в жанре фентези";
} }