From 6ea9e3896fec83a62bbd21054f0d295f57d75b8d Mon Sep 17 00:00:00 2001 From: isKonstantin Date: Sun, 18 Aug 2024 22:46:26 +0300 Subject: [PATCH] Files support --- build.gradle | 8 +- localhost-utils/docker-compose.yml | 2 +- .../java/app/finwave/telegrambot/Main.java | 10 +- .../finwave/telegrambot/scenes/MainScene.java | 94 ++++++++++++++++--- .../finwave/telegrambot/utils/AiWorker.java | 19 ++++ 5 files changed, 115 insertions(+), 18 deletions(-) diff --git a/build.gradle b/build.gradle index f59c695..5f9dde7 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group = 'app.finwave.telegrambot' -version = '1.5.0' +version = '1.6.0' mainClassName = group + ".Main" archivesBaseName = 'FinWave-Bot' @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'app.finwave.api:finwave-java-api:1.4.1' + implementation 'app.finwave.api:finwave-java-api:1.5.0' implementation 'app.finwave.tat:telegram-abstractions-tools:2.1.3' implementation 'app.finwave.scw:finwave-scw:0.4.1' @@ -54,7 +54,7 @@ dependencies { flyway { - url = 'jdbc:postgresql://localhost:5432/finwavebot' + url = 'jdbc:postgresql://localhost:5433/finwavebot' user = 'finwavebot' password = 'change_me' schemas = ['public'] @@ -71,7 +71,7 @@ jooq { generationTool { jdbc { driver = 'org.postgresql.Driver' - url = 'jdbc:postgresql://localhost:5432/finwavebot' + url = 'jdbc:postgresql://localhost:5433/finwavebot' user = 'finwavebot' password = 'change_me' properties { diff --git a/localhost-utils/docker-compose.yml b/localhost-utils/docker-compose.yml index 2a89cfe..6b66dac 100644 --- a/localhost-utils/docker-compose.yml +++ b/localhost-utils/docker-compose.yml @@ -7,4 +7,4 @@ services: POSTGRES_USER: "finwavebot" POSTGRES_PASSWORD: "change_me" ports: - - "5432:5432" + - "5433:5432" diff --git a/src/main/java/app/finwave/telegrambot/Main.java b/src/main/java/app/finwave/telegrambot/Main.java index 67bbd05..461228e 100644 --- a/src/main/java/app/finwave/telegrambot/Main.java +++ b/src/main/java/app/finwave/telegrambot/Main.java @@ -18,9 +18,13 @@ public class Main { protected static Injector INJ; protected static Logger log; + protected static String botToken; + public static void main(String[] args) throws IOException { ConfigWorker configWorker = new ConfigWorker(); - BotCore core = new BotCore(configWorker.telegram.apiToken); + botToken = configWorker.telegram.apiToken; + + BotCore core = new BotCore(botToken); INJ = Guice.createInjector(binder -> { binder.bind(BotCore.class).toInstance(core); @@ -40,6 +44,10 @@ public static void main(String[] args) throws IOException { log.info("Bot started"); } + public static String getBotToken() { + return botToken; + } + public static Injector getINJ() { return INJ; } diff --git a/src/main/java/app/finwave/telegrambot/scenes/MainScene.java b/src/main/java/app/finwave/telegrambot/scenes/MainScene.java index 7b27744..fc1911d 100644 --- a/src/main/java/app/finwave/telegrambot/scenes/MainScene.java +++ b/src/main/java/app/finwave/telegrambot/scenes/MainScene.java @@ -14,6 +14,7 @@ import app.finwave.tat.scene.BaseScene; import app.finwave.tat.utils.ComposedMessage; import app.finwave.tat.utils.MessageBuilder; +import app.finwave.telegrambot.Main; import app.finwave.telegrambot.config.CommonConfig; import app.finwave.telegrambot.database.ChatDatabase; import app.finwave.telegrambot.database.ChatPreferenceDatabase; @@ -23,10 +24,14 @@ import app.finwave.telegrambot.jooq.tables.records.ChatsRecord; import app.finwave.telegrambot.utils.*; import com.pengrad.telegrambot.model.Chat; +import com.pengrad.telegrambot.model.Document; +import com.pengrad.telegrambot.model.PhotoSize; import com.pengrad.telegrambot.model.WebAppInfo; import com.pengrad.telegrambot.model.request.ChatAction; import com.pengrad.telegrambot.model.request.InlineKeyboardButton; +import com.pengrad.telegrambot.request.GetFile; import com.pengrad.telegrambot.request.SendChatAction; +import com.pengrad.telegrambot.response.GetFileResponse; import java.math.BigDecimal; import java.net.MalformedURLException; @@ -163,6 +168,19 @@ public void start() { update(); } + protected CompletableFuture appendTelegramFile(String fileId, String mime, String name) { + return this.getChatHandler().getCore().execute(new GetFile(fileId)) + .thenApply((r) -> r.file().filePath()) + .thenApply((r) -> "https://api.telegram.org/file/bot" + Main.getBotToken() + "/" + r) + .thenApply((r) -> { + try { + return worker.appendFile(r, mime, name).get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }); + } + protected void gptAnswer(String message) { ignoreUpdates = true; @@ -205,42 +223,94 @@ protected void gptAnswer(String message) { } protected void newMessage(NewMessageEvent event) { - if (event.data.text() == null) - return; - - String text = event.data.text(); + Optional optionalText = Optional.ofNullable(event.data.text()); if (chatType != Chat.Type.Private) { String myUsername = ((ChatHandler) getChatHandler()).getMe().username(); boolean replyToMe = event.data.replyToMessage() != null && event.data.replyToMessage().from().username().equals(myUsername); - myUsername = "@" + myUsername + " "; + String myUsernameWithPing = "@" + myUsername + " "; - if (!text.contains(myUsername) && !replyToMe) + if ((optionalText.isEmpty() || !optionalText.get().contains(myUsernameWithPing)) && !replyToMe) return; - text = text.replace(myUsername, ""); + optionalText = optionalText.map( + (text) -> text.replace(myUsernameWithPing, "") + ); abstractChatHandler.deleteMessage(abstractChatHandler.getLastSentMessageId()); menu = new BaseMenu(this, false); } - String finalText = text; - - GPTMode gptMode = GPTMode.of(preferencesRecord.getGptMode()); - abstractChatHandler.deleteMessage(event.data.messageId()); menu.removeAllButtons(); menu.setMaxButtonsInRow(1); + if (optionalText.isEmpty() && worker != null) { + String caption = event.data.caption(); + CompletableFuture future = null; + + Document document = event.data.document(); + PhotoSize[] photoSizes = event.data.photo(); + + if (photoSizes != null && photoSizes.length > 0) { + future = appendTelegramFile(photoSizes[photoSizes.length - 1].fileId(), "image/jpeg", "Telegram Photo"); + }else if (document != null) { + future = appendTelegramFile(document.fileId(), document.mimeType(), document.fileName()); + } + + if (future == null) + return; + + try { + future.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + + menu.setMessage(MessageBuilder.text("Ошибка: недопустимый формат или серверный сбой")); + menu.apply(); + + return; + } + + if (caption != null && !caption.isBlank()) { + gptAnswer(caption); + + return; + } + + menu.setMessage(MessageBuilder.text("Файл прикреплен к контексту " + EmojiList.ACCEPT)); + + menu.addButton(new InlineKeyboardButton(EmojiList.CANCEL + " Отменить"), (e) -> { + worker.initContext(); + ignoreUpdates = false; + + if (!webSocketClient.isOpen() || !websocketAuthed) { + try { + updateState(); + } catch (ExecutionException | InterruptedException ignore) {} + } + + update(); + }); + + menu.apply(); + + return; + } + + String finalText = optionalText.get(); + + GPTMode gptMode = GPTMode.of(preferencesRecord.getGptMode()); + if (gptMode == GPTMode.ALWAYS && worker != null) { gptAnswer(finalText); return; } - IRequest newRequest = parser.parse(text, preferencesRecord.getPreferredAccountId()); + IRequest newRequest = parser.parse(finalText, preferencesRecord.getPreferredAccountId()); if (newRequest == null && (gptMode == GPTMode.DISABLED || worker == null)) { menu.setMessage(MessageBuilder.text("Не удалось понять запрос. Попробуйте еще раз.")); diff --git a/src/main/java/app/finwave/telegrambot/utils/AiWorker.java b/src/main/java/app/finwave/telegrambot/utils/AiWorker.java index 885ae6f..11016e8 100644 --- a/src/main/java/app/finwave/telegrambot/utils/AiWorker.java +++ b/src/main/java/app/finwave/telegrambot/utils/AiWorker.java @@ -1,6 +1,7 @@ package app.finwave.telegrambot.utils; import app.finwave.api.AiApi; +import app.finwave.api.FilesApi; import app.finwave.api.FinWaveClient; import java.util.Optional; @@ -43,4 +44,22 @@ public CompletableFuture ask(String message) { return client.runRequest(new AiApi.AskRequest(context, message), 2 * 60 * 1000, 2 * 60 * 1000) .thenApply(AiApi.AnswerResponse::answer); } + + public CompletableFuture appendFile(String telegramUrl, String mime, String name) { + long context = getCurrentContextId().orElseThrow(); + + return client.runRequest( + new FilesApi.UploadFromURLRequest(1, true, mime, name, null, telegramUrl) + ).thenApply((response -> { + try { + return client.runRequest(new AiApi.AttachFileRequest(context, response.fileId())).get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + + return null; + } + })).thenApply( + (r) -> r != null && r.message().equals("Attached successfully") + ); + } }