// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/telegram/TranslationManager.h" #include "td/telegram/Global.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" #include "td/utils/algorithm.h" #include "td/utils/buffer.h" #include "td/utils/logging.h" #include "td/utils/Status.h" namespace td { class TranslateTextQuery final : public Td::ResultHandler { Promise>> promise_; public: explicit TranslateTextQuery(Promise>> &&promise) : promise_(std::move(promise)) { } void send(vector &&texts, const string &to_language_code) { int flags = telegram_api::messages_translateText::TEXT_MASK; auto input_texts = transform(std::move(texts), [user_manager = td_->user_manager_.get()](FormattedText &&text) { return get_input_text_with_entities(user_manager, std::move(text), "TranslateTextQuery"); }); send_query(G()->net_query_creator().create(telegram_api::messages_translateText( flags, nullptr, vector{}, std::move(input_texts), to_language_code))); } void on_result(BufferSlice packet) final { auto result_ptr = fetch_result(packet); if (result_ptr.is_error()) { return on_error(result_ptr.move_as_error()); } auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for TranslateTextQuery: " << to_string(ptr); promise_.set_value(std::move(ptr->result_)); } void on_error(Status status) final { if (status.message() == "INPUT_TEXT_EMPTY") { vector> result; result.push_back(telegram_api::make_object(string(), Auto())); return promise_.set_value(std::move(result)); } promise_.set_error(std::move(status)); } }; TranslationManager::TranslationManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { } void TranslationManager::tear_down() { parent_.reset(); } void TranslationManager::translate_text(td_api::object_ptr &&text, const string &to_language_code, Promise> &&promise) { if (text == nullptr) { return promise.set_error(Status::Error(400, "Text must be non-empty")); } bool skip_bot_commands = true; int32 max_media_timestamp = -1; for (const auto &entity : text->entities_) { if (entity == nullptr || entity->type_ == nullptr) { continue; } switch (entity->type_->get_id()) { case td_api::textEntityTypeBotCommand::ID: skip_bot_commands = false; break; case td_api::textEntityTypeMediaTimestamp::ID: max_media_timestamp = td::max(max_media_timestamp, static_cast(entity->type_.get())->media_timestamp_); break; default: // nothing to do break; } } TRY_RESULT_PROMISE(promise, entities, get_message_entities(td_->user_manager_.get(), std::move(text->entities_))); TRY_STATUS_PROMISE(promise, fix_formatted_text(text->text_, entities, true, true, true, true, true)); translate_text(FormattedText{std::move(text->text_), std::move(entities)}, skip_bot_commands, max_media_timestamp, to_language_code, std::move(promise)); } void TranslationManager::translate_text(FormattedText text, bool skip_bot_commands, int32 max_media_timestamp, const string &to_language_code, Promise> &&promise) { vector texts; texts.push_back(std::move(text)); auto query_promise = PromiseCreator::lambda( [actor_id = actor_id(this), skip_bot_commands, max_media_timestamp, promise = std::move(promise)]( Result>> result) mutable { if (result.is_error()) { return promise.set_error(result.move_as_error()); } send_closure(actor_id, &TranslationManager::on_get_translated_texts, result.move_as_ok(), skip_bot_commands, max_media_timestamp, std::move(promise)); }); td_->create_handler(std::move(query_promise))->send(std::move(texts), to_language_code); } void TranslationManager::on_get_translated_texts(vector> texts, bool skip_bot_commands, int32 max_media_timestamp, Promise> &&promise) { TRY_STATUS_PROMISE(promise, G()->close_status()); if (texts.size() != 1u) { return promise.set_error(Status::Error(500, "Receive invalid number of results")); } auto formatted_text = get_formatted_text(td_->user_manager_.get(), std::move(texts[0]), max_media_timestamp == -1, true, "on_get_translated_texts"); promise.set_value(get_formatted_text_object(formatted_text, skip_bot_commands, max_media_timestamp)); } } // namespace td