blob: 1a738944421ea6ab05edf388e846ebeefb187bea [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SERVICES_ON_DEVICE_TRANSLATION_TRANSLATE_KIT_CLIENT_H_
#define COMPONENTS_SERVICES_ON_DEVICE_TRANSLATION_TRANSLATE_KIT_CLIENT_H_
#include <cstddef>
#include <map>
#include <optional>
#include <string>
#include <utility>
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_native_library.h"
#include "base/types/expected.h"
#include "base/types/pass_key.h"
#include "components/services/on_device_translation/public/mojom/on_device_translation_service.mojom.h"
#include "components/services/on_device_translation/translate_kit_structs.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace on_device_translation {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// LINT.IfChange(LoadTranslateKitResult)
enum class LoadTranslateKitResult {
// kUnknown = 0, Deprecated
// Success to load TranslateKit library.
kSuccess = 1,
// Fails due to invalid TranslateKit binary.
kInvalidBinary = 2,
// Success to load TranslateKit binary but fails due to invalid function
// pointers.
kInvalidFunctionPointer = 3,
// Success to load TranslateKit binary but the binary version is invalid.
kInvalidVersion = 4,
kMaxValue = kInvalidVersion,
};
// LINT.ThenChange(/tools/metrics/histograms/metadata/ai/enums.xml:LoadTranslateKitResult)
// The client that wraps the plain C-style interfaces between Chrome and the
// TranslateKit. Changes to the interfaces must be backwards compatible and
// reflected in the Google3-side definition.
class TranslateKitClient {
public:
// Translator provides access to translation functionality.
class Translator {
public:
virtual ~Translator() = default;
virtual std::optional<std::string> Translate(const std::string& text) = 0;
virtual std::vector<std::string> SplitSentences(
const std::string& text) = 0;
};
static TranslateKitClient* Get();
static std::unique_ptr<TranslateKitClient> CreateForTest(
const base::FilePath& library_path);
TranslateKitClient(const base::FilePath& library_path,
base::PassKey<TranslateKitClient>);
~TranslateKitClient();
// Not copyable.
TranslateKitClient(const TranslateKitClient&) = delete;
TranslateKitClient& operator=(const TranslateKitClient&) = delete;
void SetConfig(mojom::OnDeviceTranslationServiceConfigPtr config);
// Returns if the translation from `source_lang` to `target_lang` is
// supported.
bool CanTranslate(const std::string& source_lang,
const std::string& target_lang);
// Returns a Translator instance for the given pair of languages, or an error
// of type `mojom::CreateTranslatorResult` if fails to create such Translator.
base::expected<Translator*, mojom::CreateTranslatorResult> GetTranslator(
const std::string& source_lang,
const std::string& target_lang);
private:
// TranslatorImpl manages an instance of translator created by TranslateKit
// library and provides access to its translation functionality.
class TranslatorImpl : public Translator {
public:
static std::unique_ptr<TranslatorImpl> MaybeCreate(
TranslateKitClient* client,
const std::string& source_lang,
const std::string& target_lang);
TranslatorImpl(base::PassKey<TranslatorImpl>,
TranslateKitClient* client,
const std::string& source_lang,
std::uintptr_t translator_ptr);
~TranslatorImpl() override;
// Not copyable.
TranslatorImpl(const TranslatorImpl&) = delete;
TranslatorImpl& operator=(const TranslatorImpl&) = delete;
std::optional<std::string> Translate(const std::string& text) override;
std::vector<std::string> SplitSentences(const std::string& text) override;
private:
// Guaranteed to exist, as `client_` owns `this`.
raw_ptr<TranslateKitClient> client_;
const std::string source_lang_;
// A pointer to a Translator instance created by the TranslateKit.
// It should only be instantiated and deleted by the TranslateKit library.
std::uintptr_t translator_ptr_;
};
static bool FileExists(const char* file_name,
size_t file_name_size,
bool* is_directory,
std::uintptr_t user_data);
static std::uintptr_t OpenForReadOnlyMemoryMap(const char* file_name,
size_t file_name_size,
std::uintptr_t user_data);
bool FileExistsImpl(const char* file_name,
size_t file_name_size,
bool* is_directory);
std::uintptr_t OpenForReadOnlyMemoryMapImpl(const char* file_name,
size_t file_name_size);
// Checks if the TranslateKit binary is valid and all the function pointers
// are valid. And sets the `maybe_kit_ptr_` to the error code if any.
LoadTranslateKitResult CheckLoadTranslateKitResult();
// Checks if the loaded TranslateKit version is valid.
bool IsTranslateKitVersionValid();
// Initializes the TranslateKit instance only when first needed, provided the
// underlying library has loaded successfully. Returns true if initialization
// was successful, false otherwise.
bool MaybeInitialize();
// The TranslateKit binary.
base::ScopedNativeLibrary lib_;
using TranslatorKey = std::pair<std::string, std::string>;
// Manages all instances of `Translator` created by this client.
std::map<TranslatorKey, std::unique_ptr<Translator>> translators_;
// WARNING:
// Changes to the below interfaces must be backwards compatible and
// reflected in the Google3-side definition.
typedef bool (*GetTranslateKitVersionFn)(TranslateKitVersion* version);
GetTranslateKitVersionFn get_translate_kit_version_func_;
typedef void (*InitializeStorageBackendFn)(
FileExistsFn file_exists,
OpenForReadOnlyMemoryMapFn open_for_read_only_memory_map,
DeleteReadOnlyMemoryRegionFn delete_read_only_memory_region,
ReadOnlyMemoryRegionDataFn read_only_memory_region_data,
ReadOnlyMemoryRegionLengthFn read_only_memory_region_length,
std::uintptr_t user_data);
InitializeStorageBackendFn initialize_storage_backend_fnc_;
typedef std::uintptr_t (*CreateTranslateKitFn)();
CreateTranslateKitFn create_translate_kit_fnc_;
typedef void (*DeleteTranslateKitFn)(std::uintptr_t);
DeleteTranslateKitFn delete_tanslate_kit_fnc_;
typedef bool (*TranslateKitSetLanguagePackagesFn)(
uintptr_t kit_ptr,
TranslateKitSetLanguagePackagesArgs args);
TranslateKitSetLanguagePackagesFn set_language_packages_func_;
typedef uintptr_t (*TranslateKitCreateTranslatorFn)(std::uintptr_t,
TranslateKitLanguage,
TranslateKitLanguage);
TranslateKitCreateTranslatorFn translate_kit_create_translator_func_;
typedef void (*DeleteTranslatorFn)(std::uintptr_t);
DeleteTranslatorFn delete_translator_fnc_;
typedef void (*TranslateCallbackFn)(TranslateKitOutputText, std::uintptr_t);
typedef bool (*TranslatorTranslateFn)(std::uintptr_t translator_ptr,
TranslateKitInputText,
TranslateCallbackFn,
std::uintptr_t user_data);
TranslatorTranslateFn translator_translate_func_;
typedef void (*SentenceSplitCallbackFn)(TranslateKitOutputText,
std::uintptr_t);
typedef bool (*TranslateKitSplitSentencesFn)(TranslateKitInputText,
TranslateKitLanguage,
SentenceSplitCallbackFn,
std::uintptr_t user_data);
TranslateKitSplitSentencesFn translate_kit_sentence_split_func_;
// The pointer to the TranslateKit instance or 0 if not initialized or
// error `mojom::CreateTranslatorResult` if failed to initialize.
base::expected<std::uintptr_t, mojom::CreateTranslatorResult> maybe_kit_ptr_{
0};
mojo::Remote<mojom::FileOperationProxy> file_operation_proxy_;
};
} // namespace on_device_translation
#endif // COMPONENTS_SERVICES_ON_DEVICE_TRANSLATION_TRANSLATE_KIT_CLIENT_H_