dejanseo commited on
Commit
f8dc3a0
·
verified ·
1 Parent(s): 6f18aef

Upload 29 files

Browse files
19/DEPS ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ include_rules = [
2
+ "+chromeos/dbus",
3
+ "+mojo/core/embedder",
4
+ "+mojo/public",
5
+ ]
19/DIR_METADATA ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ monorail {
2
+ component: "UI>ML>Service"
3
+ }
19/OWNERS ADDED
@@ -0,0 +1,4 @@
 
 
 
 
19/cpp/ash/handwriting_model_loader.cc ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2020 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include "chromeos/services/machine_learning/cpp/ash/handwriting_model_loader.h"
6
+
7
+ #include <string>
8
+ #include <utility>
9
+
10
+ #include "ash/constants/ash_switches.h"
11
+ #include "base/callback_helpers.h"
12
+ #include "base/command_line.h"
13
+ #include "base/metrics/histogram_macros.h"
14
+ #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
15
+ #include "third_party/cros_system_api/dbus/service_constants.h"
16
+
17
+ namespace ash {
18
+ namespace machine_learning {
19
+ namespace {
20
+
21
+ using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr;
22
+ using ::chromeos::machine_learning::mojom::LoadHandwritingModelResult;
23
+ using HandwritingRecognizer = mojo::PendingReceiver<
24
+ ::chromeos::machine_learning::mojom::HandwritingRecognizer>;
25
+ using LoadHandwritingModelCallback = ::chromeos::machine_learning::mojom::
26
+ MachineLearningService::LoadHandwritingModelCallback;
27
+
28
+ // Records CrOSActionRecorder event.
29
+ void RecordLoadHandwritingModelResult(const LoadHandwritingModelResult val) {
30
+ UMA_HISTOGRAM_ENUMERATION(
31
+ "MachineLearningService.HandwritingModel.LoadModelResult.Event", val,
32
+ LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
33
+ }
34
+
35
+ constexpr char kLibHandwritingDlcId[] = "libhandwriting";
36
+ // A list of supported language code.
37
+ constexpr char kLanguageCodeEn[] = "en";
38
+ constexpr char kLanguageCodeGesture[] = "gesture_in_context";
39
+
40
+ // Returns whether the `value` is set for command line switch
41
+ // kOndeviceHandwritingSwitch.
42
+ bool HandwritingSwitchHasValue(const std::string& value) {
43
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
44
+ return command_line->HasSwitch(ash::switches::kOndeviceHandwritingSwitch) &&
45
+ command_line->GetSwitchValueASCII(
46
+ ash::switches::kOndeviceHandwritingSwitch) == value;
47
+ }
48
+
49
+ // Returns true if switch kOndeviceHandwritingSwitch is set to use_rootfs.
50
+ bool IsLibHandwritingRootfsEnabled() {
51
+ return HandwritingSwitchHasValue("use_rootfs");
52
+ }
53
+
54
+ // Returns true if switch kOndeviceHandwritingSwitch is set to use_dlc.
55
+ bool IsLibHandwritingDlcEnabled() {
56
+ return HandwritingSwitchHasValue("use_dlc");
57
+ }
58
+
59
+ // Called when InstallDlc completes.
60
+ // Returns an error if the `result.error` is not dlcservice::kErrorNone.
61
+ // Calls mlservice to LoadHandwritingModel otherwise.
62
+ void OnInstallDlcComplete(
63
+ HandwritingRecognizerSpecPtr spec,
64
+ HandwritingRecognizer receiver,
65
+ LoadHandwritingModelCallback callback,
66
+ const chromeos::DlcserviceClient::InstallResult& result) {
67
+ // Call LoadHandwritingModelWithSpec if no error was found.
68
+ if (result.error == dlcservice::kErrorNone) {
69
+ chromeos::machine_learning::ServiceConnection::GetInstance()
70
+ ->GetMachineLearningService()
71
+ .LoadHandwritingModel(std::move(spec), std::move(receiver),
72
+ std::move(callback));
73
+ return;
74
+ }
75
+
76
+ RecordLoadHandwritingModelResult(
77
+ LoadHandwritingModelResult::DLC_INSTALL_ERROR);
78
+ std::move(callback).Run(LoadHandwritingModelResult::DLC_INSTALL_ERROR);
79
+ }
80
+
81
+ // Called when the existing-dlc-list is returned.
82
+ // Returns an error if libhandwriting is not in the existing-dlc-list.
83
+ // Calls InstallDlc otherwise.
84
+ void OnGetExistingDlcsComplete(
85
+ HandwritingRecognizerSpecPtr spec,
86
+ HandwritingRecognizer receiver,
87
+ LoadHandwritingModelCallback callback,
88
+ chromeos::DlcserviceClient* const dlc_client,
89
+ const std::string& err,
90
+ const dlcservice::DlcsWithContent& dlcs_with_content) {
91
+ // Loop over dlcs_with_content, and installs libhandwriting if already exists.
92
+ // Since we don't want to trigger downloading here, we only install(mount)
93
+ // the handwriting dlc if it is already on device.
94
+ for (const auto& dlc_info : dlcs_with_content.dlc_infos()) {
95
+ if (dlc_info.id() == kLibHandwritingDlcId) {
96
+ dlc_client->Install(
97
+ kLibHandwritingDlcId,
98
+ base::BindOnce(&OnInstallDlcComplete, std::move(spec),
99
+ std::move(receiver), std::move(callback)),
100
+ base::DoNothing());
101
+ return;
102
+ }
103
+ }
104
+
105
+ // Returns error if the handwriting dlc is not on the device.
106
+ RecordLoadHandwritingModelResult(
107
+ LoadHandwritingModelResult::DLC_DOES_NOT_EXIST);
108
+ std::move(callback).Run(LoadHandwritingModelResult::DLC_DOES_NOT_EXIST);
109
+ }
110
+
111
+ } // namespace
112
+
113
+ void LoadHandwritingModelFromRootfsOrDlc(
114
+ HandwritingRecognizerSpecPtr spec,
115
+ HandwritingRecognizer receiver,
116
+ LoadHandwritingModelCallback callback,
117
+ chromeos::DlcserviceClient* const dlc_client) {
118
+ // Returns FEATURE_NOT_SUPPORTED_ERROR if both rootfs and dlc are not enabled.
119
+ if (!IsLibHandwritingRootfsEnabled() && !IsLibHandwritingDlcEnabled()) {
120
+ RecordLoadHandwritingModelResult(
121
+ LoadHandwritingModelResult::FEATURE_NOT_SUPPORTED_ERROR);
122
+ std::move(callback).Run(
123
+ LoadHandwritingModelResult::FEATURE_NOT_SUPPORTED_ERROR);
124
+ return;
125
+ }
126
+
127
+ // Returns LANGUAGE_NOT_SUPPORTED_ERROR if the language is not supported yet.
128
+ if (spec->language != kLanguageCodeEn &&
129
+ spec->language != kLanguageCodeGesture) {
130
+ RecordLoadHandwritingModelResult(
131
+ LoadHandwritingModelResult::LANGUAGE_NOT_SUPPORTED_ERROR);
132
+ std::move(callback).Run(
133
+ LoadHandwritingModelResult::LANGUAGE_NOT_SUPPORTED_ERROR);
134
+ return;
135
+ }
136
+
137
+ // Load from rootfs if enabled.
138
+ if (IsLibHandwritingRootfsEnabled()) {
139
+ chromeos::machine_learning::ServiceConnection::GetInstance()
140
+ ->GetMachineLearningService()
141
+ .LoadHandwritingModel(std::move(spec), std::move(receiver),
142
+ std::move(callback));
143
+ return;
144
+ }
145
+
146
+ // Gets existing dlc list and based on the presence of libhandwriting
147
+ // either returns an error or installs the libhandwriting dlc.
148
+ dlc_client->GetExistingDlcs(
149
+ base::BindOnce(&OnGetExistingDlcsComplete, std::move(spec),
150
+ std::move(receiver), std::move(callback), dlc_client));
151
+ }
152
+
153
+ } // namespace machine_learning
154
+ } // namespace ash
19/cpp/ash/handwriting_model_loader.h ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2020 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #ifndef CHROMEOS_SERVICES_MACHINE_LEARNING_CPP_ASH_HANDWRITING_MODEL_LOADER_H_
6
+ #define CHROMEOS_SERVICES_MACHINE_LEARNING_CPP_ASH_HANDWRITING_MODEL_LOADER_H_
7
+
8
+ #include "chromeos/dbus/dlcservice/dlcservice_client.h"
9
+ #include "chromeos/services/machine_learning/public/mojom/handwriting_recognizer.mojom.h"
10
+ #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
11
+ #include "mojo/public/cpp/bindings/pending_receiver.h"
12
+
13
+ namespace ash {
14
+ namespace machine_learning {
15
+
16
+ // Helper function decides either to load handwriting model from rootfs or dlc.
17
+ // New Handwriting clients should call this helper instead of calling
18
+ // ServiceConnection::GetInstance()->LoadHandwritingModel.
19
+ // Three typical examples of the callstack are:
20
+ // Case 1: handwriting in enabled on rootfs.
21
+ // client calls LoadHandwritingModelFromRootfsOrDlc("en", receiver, callback)
22
+ // which calls LoadHandwritingModel -> handwriting model loaded from rootfs.
23
+ // Case 2: handwriting is enabled for dlc and dlc is already on the device.
24
+ // client calls LoadHandwritingModelFromRootfsOrDlc("en", receiver, callback)
25
+ // which calls -> GetExistingDlcs -> libhandwriting dlc already exists
26
+ // -> InstallDlc -> LoadHandwritingModel
27
+ // The correct handwriting model will be loaded and bond to the receiver.
28
+ // Case 3: handwriting is enabled for dlc and dlc is not on the device yet.
29
+ // client calls LoadHandwritingModelFromRootfsOrDlc("en", receiver, callback)
30
+ // which calls -> GetExistingDlcs -> NO libhandwriting dlc exists
31
+ // -> Return error DLC_NOT_EXISTED.
32
+ // Then it will be the client's duty to install the dlc and then calls
33
+ // LoadHandwritingModelFromRootfsOrDlc("en", receiver, callback) again.
34
+ //
35
+ // `dlc_client` should only be replaced with non-default value in unit tests.
36
+ void LoadHandwritingModelFromRootfsOrDlc(
37
+ chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr spec,
38
+ mojo::PendingReceiver<
39
+ chromeos::machine_learning::mojom::HandwritingRecognizer> receiver,
40
+ chromeos::machine_learning::mojom::MachineLearningService::
41
+ LoadHandwritingModelCallback callback,
42
+ chromeos::DlcserviceClient* dlc_client = chromeos::DlcserviceClient::Get());
43
+
44
+ } // namespace machine_learning
45
+ } // namespace ash
46
+
47
+ #endif // CHROMEOS_SERVICES_MACHINE_LEARNING_CPP_ASH_HANDWRITING_MODEL_LOADER_H_
19/cpp/ash/handwriting_model_loader_unittest.cc ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2020 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include "chromeos/services/machine_learning/cpp/ash/handwriting_model_loader.h"
6
+
7
+ #include <string>
8
+
9
+ #include "ash/constants/ash_switches.h"
10
+ #include "base/bind.h"
11
+ #include "base/command_line.h"
12
+ #include "base/run_loop.h"
13
+ #include "base/test/scoped_command_line.h"
14
+ #include "base/test/task_environment.h"
15
+ #include "chromeos/dbus/dlcservice/fake_dlcservice_client.h"
16
+ #include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
17
+ #include "testing/gtest/include/gtest/gtest.h"
18
+ #include "third_party/cros_system_api/dbus/service_constants.h"
19
+
20
+ namespace ash {
21
+ namespace machine_learning {
22
+
23
+ using ::base::test::ScopedCommandLine;
24
+ using ::base::test::TaskEnvironment;
25
+ using ::chromeos::machine_learning::mojom::LoadHandwritingModelResult;
26
+
27
+ constexpr char kLibHandwritingDlcId[] = "libhandwriting";
28
+
29
+ class HandwritingModelLoaderTest : public testing::Test {
30
+ protected:
31
+ void SetUp() override {
32
+ chromeos::machine_learning::ServiceConnection::
33
+ UseFakeServiceConnectionForTesting(&fake_service_connection_);
34
+ chromeos::machine_learning::ServiceConnection::GetInstance()->Initialize();
35
+ result_ = LoadHandwritingModelResult::DEPRECATED_MODEL_SPEC_ERROR;
36
+ language_ = "en";
37
+ }
38
+
39
+ // Callback that called when loader_->Load() is over to save the returned
40
+ // result.
41
+ void OnHandwritingModelLoaderComplete(
42
+ const LoadHandwritingModelResult result) {
43
+ result_ = result;
44
+ }
45
+
46
+ // Runs loader_->Load() and check the returned result as expected.
47
+ void ExpectLoadHandwritingModelResult(
48
+ const LoadHandwritingModelResult expected_result) {
49
+ LoadHandwritingModelFromRootfsOrDlc(
50
+ chromeos::machine_learning::mojom::HandwritingRecognizerSpec::New(
51
+ language_),
52
+ recognizer_.BindNewPipeAndPassReceiver(),
53
+ base::BindOnce(
54
+ &HandwritingModelLoaderTest::OnHandwritingModelLoaderComplete,
55
+ base::Unretained(this)),
56
+ &fake_client_);
57
+
58
+ base::RunLoop().RunUntilIdle();
59
+ EXPECT_EQ(result_, expected_result);
60
+ }
61
+
62
+ void SetLanguage(const std::string& language) { language_ = language; }
63
+
64
+ // Creates a dlc list with one dlc inside.
65
+ void AddDlcsWithContent(const std::string& dlc_id) {
66
+ dlcservice::DlcsWithContent dlcs_with_content;
67
+ dlcs_with_content.add_dlc_infos()->set_id(dlc_id);
68
+ fake_client_.set_dlcs_with_content(dlcs_with_content);
69
+ }
70
+
71
+ // Sets InstallDlc error.
72
+ void SetInstallError(const std::string& error) {
73
+ fake_client_.set_install_error(error);
74
+ fake_client_.set_install_root_path("/any-path");
75
+ }
76
+
77
+ // Sets "ondevice_handwriting" value.
78
+ void SetSwitchValue(const std::string& switch_value) {
79
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
80
+ ash::switches::kOndeviceHandwritingSwitch, switch_value);
81
+ }
82
+
83
+ private:
84
+ TaskEnvironment task_environment_{
85
+ TaskEnvironment::MainThreadType::DEFAULT,
86
+ TaskEnvironment::ThreadPoolExecutionMode::QUEUED};
87
+ ScopedCommandLine scoped_command_line_;
88
+ chromeos::FakeDlcserviceClient fake_client_;
89
+ chromeos::machine_learning::FakeServiceConnectionImpl
90
+ fake_service_connection_;
91
+ LoadHandwritingModelResult result_;
92
+ std::string language_;
93
+ mojo::Remote<chromeos::machine_learning::mojom::HandwritingRecognizer>
94
+ recognizer_;
95
+ };
96
+
97
+ TEST_F(HandwritingModelLoaderTest, HandwritingNotEnabled) {
98
+ SetSwitchValue("random_string");
99
+
100
+ // Random switch value should return FEATURE_NOT_SUPPORTED_ERROR.
101
+ ExpectLoadHandwritingModelResult(
102
+ LoadHandwritingModelResult::FEATURE_NOT_SUPPORTED_ERROR);
103
+ }
104
+
105
+ TEST_F(HandwritingModelLoaderTest, LoadingWithInvalidLanguage) {
106
+ SetSwitchValue("use_rootfs");
107
+
108
+ SetLanguage("random string as language");
109
+
110
+ // Random language code should return LANGUAGE_NOT_SUPPORTED_ERROR.
111
+ ExpectLoadHandwritingModelResult(
112
+ LoadHandwritingModelResult::LANGUAGE_NOT_SUPPORTED_ERROR);
113
+ }
114
+
115
+ TEST_F(HandwritingModelLoaderTest, LoadingWithUseRootfs) {
116
+ SetSwitchValue("use_rootfs");
117
+
118
+ // Load from rootfs should return success.
119
+ ExpectLoadHandwritingModelResult(LoadHandwritingModelResult::OK);
120
+ }
121
+
122
+ TEST_F(HandwritingModelLoaderTest, LoadingWithoutDlcOnDevice) {
123
+ SetSwitchValue("use_dlc");
124
+
125
+ AddDlcsWithContent("random dlc-id");
126
+
127
+ // Random dlc id should return DLC_DOES_NOT_EXIST.
128
+ ExpectLoadHandwritingModelResult(
129
+ LoadHandwritingModelResult::DLC_DOES_NOT_EXIST);
130
+ }
131
+
132
+ TEST_F(HandwritingModelLoaderTest, DlcInstalledWithError) {
133
+ SetSwitchValue("use_dlc");
134
+
135
+ AddDlcsWithContent(kLibHandwritingDlcId);
136
+ SetInstallError("random error");
137
+
138
+ // InstallDlc error should return DLC_INSTALL_ERROR.
139
+ ExpectLoadHandwritingModelResult(
140
+ LoadHandwritingModelResult::DLC_INSTALL_ERROR);
141
+ }
142
+
143
+ TEST_F(HandwritingModelLoaderTest, DlcInstalledWithoutError) {
144
+ SetSwitchValue("use_dlc");
145
+
146
+ AddDlcsWithContent(kLibHandwritingDlcId);
147
+ SetInstallError(dlcservice::kErrorNone);
148
+
149
+ // InstallDlc without an error should return success.
150
+ ExpectLoadHandwritingModelResult(LoadHandwritingModelResult::OK);
151
+ }
152
+
153
+ } // namespace machine_learning
154
+ } // namespace ash
19/cpp/ash/service_connection_ash.cc ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
6
+
7
+ #include <utility>
8
+
9
+ #include "base/bind.h"
10
+ #include "base/component_export.h"
11
+ #include "base/no_destructor.h"
12
+ #include "base/sequence_checker.h"
13
+ #include "base/task/sequenced_task_runner.h"
14
+ #include "chromeos/dbus/machine_learning/machine_learning_client.h"
15
+ #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
16
+ #include "mojo/public/cpp/bindings/remote.h"
17
+ #include "mojo/public/cpp/platform/platform_channel.h"
18
+ #include "mojo/public/cpp/system/invitation.h"
19
+ #include "third_party/cros_system_api/dbus/service_constants.h"
20
+
21
+ namespace ash {
22
+ namespace machine_learning {
23
+
24
+ namespace {
25
+
26
+ // Real Impl of ServiceConnection
27
+ class COMPONENT_EXPORT(CHROMEOS_MLSERVICE) ServiceConnectionAsh
28
+ : public chromeos::machine_learning::ServiceConnection {
29
+ public:
30
+ ServiceConnectionAsh();
31
+ ServiceConnectionAsh(const ServiceConnectionAsh&) = delete;
32
+ ServiceConnectionAsh& operator=(const ServiceConnectionAsh&) = delete;
33
+
34
+ ~ServiceConnectionAsh() override;
35
+
36
+ chromeos::machine_learning::mojom::MachineLearningService&
37
+ GetMachineLearningService() override;
38
+
39
+ void BindMachineLearningService(
40
+ mojo::PendingReceiver<
41
+ chromeos::machine_learning::mojom::MachineLearningService> receiver)
42
+ override;
43
+
44
+ void Initialize() override;
45
+
46
+ private:
47
+ // Binds the primordial, top-level interface |machine_learning_service_| to an
48
+ // implementation in the ML Service daemon, if it is not already bound. The
49
+ // binding is accomplished via D-Bus bootstrap.
50
+ void BindPrimordialMachineLearningServiceIfNeeded();
51
+
52
+ // Mojo disconnect handler. Resets |machine_learning_service_|, which
53
+ // will be reconnected upon next use.
54
+ void OnMojoDisconnect();
55
+
56
+ // Response callback for MlClient::BootstrapMojoConnection.
57
+ void OnBootstrapMojoConnectionResponse(bool success);
58
+
59
+ mojo::Remote<chromeos::machine_learning::mojom::MachineLearningService>
60
+ machine_learning_service_;
61
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
62
+
63
+ SEQUENCE_CHECKER(sequence_checker_);
64
+ };
65
+
66
+ ServiceConnectionAsh::ServiceConnectionAsh() {
67
+ DETACH_FROM_SEQUENCE(sequence_checker_);
68
+ }
69
+
70
+ ServiceConnectionAsh::~ServiceConnectionAsh() = default;
71
+
72
+ chromeos::machine_learning::mojom::MachineLearningService&
73
+ ServiceConnectionAsh::GetMachineLearningService() {
74
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
75
+ DCHECK(task_runner_)
76
+ << "Call Initialize before first use of ServiceConnection.";
77
+ BindPrimordialMachineLearningServiceIfNeeded();
78
+ return *machine_learning_service_.get();
79
+ }
80
+
81
+ void ServiceConnectionAsh::BindMachineLearningService(
82
+ mojo::PendingReceiver<
83
+ chromeos::machine_learning::mojom::MachineLearningService> receiver) {
84
+ DCHECK(task_runner_)
85
+ << "Call Initialize before first use of ServiceConnection.";
86
+ if (!task_runner_->RunsTasksInCurrentSequence()) {
87
+ task_runner_->PostTask(
88
+ FROM_HERE,
89
+ base::BindOnce(&ServiceConnectionAsh::BindMachineLearningService,
90
+ base::Unretained(this), std::move(receiver)));
91
+ return;
92
+ }
93
+
94
+ GetMachineLearningService().Clone(std::move(receiver));
95
+ }
96
+
97
+ void ServiceConnectionAsh::Initialize() {
98
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
99
+ DCHECK(!task_runner_) << "Initialize must be called only once.";
100
+
101
+ task_runner_ = base::SequencedTaskRunnerHandle::Get();
102
+ }
103
+
104
+ void ServiceConnectionAsh::BindPrimordialMachineLearningServiceIfNeeded() {
105
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
106
+ if (machine_learning_service_) {
107
+ return;
108
+ }
109
+
110
+ mojo::PlatformChannel platform_channel;
111
+
112
+ // Prepare a Mojo invitation to send through |platform_channel|.
113
+ mojo::OutgoingInvitation invitation;
114
+ // Include an initial Mojo pipe in the invitation.
115
+ mojo::ScopedMessagePipeHandle pipe =
116
+ invitation.AttachMessagePipe(ml::kBootstrapMojoConnectionChannelToken);
117
+ mojo::OutgoingInvitation::Send(std::move(invitation),
118
+ base::kNullProcessHandle,
119
+ platform_channel.TakeLocalEndpoint());
120
+
121
+ // Bind our end of |pipe| to our mojo::Remote<MachineLearningService>. The
122
+ // daemon should bind its end to a MachineLearningService implementation.
123
+ machine_learning_service_.Bind(
124
+ mojo::PendingRemote<
125
+ chromeos::machine_learning::mojom::MachineLearningService>(
126
+ std::move(pipe), 0u /* version */));
127
+ machine_learning_service_.set_disconnect_handler(base::BindOnce(
128
+ &ServiceConnectionAsh::OnMojoDisconnect, base::Unretained(this)));
129
+
130
+ // Send the file descriptor for the other end of |platform_channel| to the
131
+ // ML service daemon over D-Bus.
132
+ chromeos::MachineLearningClient::Get()->BootstrapMojoConnection(
133
+ platform_channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD(),
134
+ base::BindOnce(&ServiceConnectionAsh::OnBootstrapMojoConnectionResponse,
135
+ base::Unretained(this)));
136
+ }
137
+
138
+ void ServiceConnectionAsh::OnMojoDisconnect() {
139
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
140
+ // Connection errors are not expected so log a warning.
141
+ LOG(WARNING) << "ML Service Mojo connection closed";
142
+ machine_learning_service_.reset();
143
+ }
144
+
145
+ void ServiceConnectionAsh::OnBootstrapMojoConnectionResponse(
146
+ const bool success) {
147
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
148
+ if (!success) {
149
+ LOG(WARNING) << "BootstrapMojoConnection D-Bus call failed";
150
+ machine_learning_service_.reset();
151
+ }
152
+ }
153
+
154
+ } // namespace
155
+
156
+ } // namespace machine_learning
157
+ } // namespace ash
158
+
159
+ namespace chromeos {
160
+ namespace machine_learning {
161
+
162
+ ServiceConnection* ServiceConnection::CreateRealInstance() {
163
+ static base::NoDestructor<ash::machine_learning::ServiceConnectionAsh>
164
+ service_connection;
165
+ return service_connection.get();
166
+ }
167
+
168
+ } // namespace machine_learning
169
+ } // namespace chromeos
19/cpp/lacros/service_connection_lacros.cc ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
6
+
7
+ #include <utility>
8
+
9
+ #include "base/component_export.h"
10
+ #include "base/no_destructor.h"
11
+ #include "chromeos/lacros/lacros_service.h"
12
+ #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
13
+ #include "mojo/public/cpp/bindings/remote.h"
14
+
15
+ namespace lacros {
16
+ namespace machine_learning {
17
+ namespace {
18
+
19
+ // Real Impl of ServiceConnection
20
+ class COMPONENT_EXPORT(CHROMEOS_MLSERVICE) ServiceConnectionLacros
21
+ : public chromeos::machine_learning::ServiceConnection {
22
+ public:
23
+ ServiceConnectionLacros();
24
+ ServiceConnectionLacros(const ServiceConnectionLacros&) = delete;
25
+ ServiceConnectionLacros& operator=(const ServiceConnectionLacros&) = delete;
26
+
27
+ ~ServiceConnectionLacros() override;
28
+
29
+ chromeos::machine_learning::mojom::MachineLearningService&
30
+ GetMachineLearningService() override;
31
+
32
+ void BindMachineLearningService(
33
+ mojo::PendingReceiver<
34
+ chromeos::machine_learning::mojom::MachineLearningService> receiver)
35
+ override;
36
+
37
+ void Initialize() override;
38
+ };
39
+
40
+ ServiceConnectionLacros::ServiceConnectionLacros() = default;
41
+
42
+ ServiceConnectionLacros::~ServiceConnectionLacros() = default;
43
+
44
+ chromeos::machine_learning::mojom::MachineLearningService&
45
+ ServiceConnectionLacros::GetMachineLearningService() {
46
+ mojo::Remote<chromeos::machine_learning::mojom::MachineLearningService>&
47
+ machine_learning_service_remote =
48
+ chromeos::LacrosService::Get()
49
+ ->GetRemote<
50
+ chromeos::machine_learning::mojom::MachineLearningService>();
51
+ return *machine_learning_service_remote.get();
52
+ }
53
+
54
+ void ServiceConnectionLacros::BindMachineLearningService(
55
+ mojo::PendingReceiver<
56
+ chromeos::machine_learning::mojom::MachineLearningService> receiver) {
57
+ chromeos::LacrosService::Get()->BindMachineLearningService(
58
+ std::move(receiver));
59
+ }
60
+
61
+ void ServiceConnectionLacros::Initialize() {}
62
+
63
+ } // namespace
64
+
65
+ } // namespace machine_learning
66
+ } // namespace lacros
67
+
68
+ namespace chromeos {
69
+ namespace machine_learning {
70
+
71
+ ServiceConnection* ServiceConnection::CreateRealInstance() {
72
+ static base::NoDestructor<lacros::machine_learning::ServiceConnectionLacros>
73
+ service_connection;
74
+ return service_connection.get();
75
+ }
76
+
77
+ } // namespace machine_learning
78
+ } // namespace chromeos
19/public/cpp/BUILD.gn ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2018 The Chromium Authors. All rights reserved.
2
+ # Use of this source code is governed by a BSD-style license that can be
3
+ # found in the LICENSE file.
4
+
5
+ import("//build/config/chromeos/ui_mode.gni")
6
+
7
+ assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
8
+
9
+ source_set("cpp") {
10
+ sources = [
11
+ "service_connection.cc",
12
+ "service_connection.h",
13
+ ]
14
+ defines = [ "IS_CHROMEOS_MLSERVICE_IMPL" ]
15
+ deps = [
16
+ "//base",
17
+ "//chromeos/services/machine_learning/public/mojom",
18
+ ]
19
+
20
+ if (is_chromeos_ash) {
21
+ sources += [
22
+ "../../cpp/ash/handwriting_model_loader.cc",
23
+ "../../cpp/ash/handwriting_model_loader.h",
24
+ "../../cpp/ash/service_connection_ash.cc",
25
+ ]
26
+ deps += [
27
+ "//ash/constants:constants",
28
+ "//chromeos/dbus/dlcservice",
29
+ "//chromeos/dbus/dlcservice:dlcservice_proto",
30
+ "//chromeos/dbus/machine_learning",
31
+ ]
32
+ } else if (is_chromeos_lacros) {
33
+ sources += [ "../../cpp/lacros/service_connection_lacros.cc" ]
34
+ deps += [
35
+ "//chromeos/lacros",
36
+ "//mojo/public/cpp/bindings",
37
+ "//skia",
38
+ ]
39
+ }
40
+ }
41
+
42
+ component("stub") {
43
+ sources = [
44
+ "fake_service_connection.cc",
45
+ "fake_service_connection.h",
46
+ ]
47
+ defines = [ "IS_CHROMEOS_MLSERVICE_IMPL" ]
48
+ deps = [
49
+ "//base",
50
+ "//chromeos/services/machine_learning/public/mojom",
51
+ "//mojo/public/cpp/bindings",
52
+ ]
53
+ public_deps = [ ":cpp" ]
54
+ }
55
+
56
+ source_set("unit_tests") {
57
+ testonly = true
58
+ sources = [ "service_connection_unittest.cc" ]
59
+ deps = [
60
+ ":cpp",
61
+ ":stub",
62
+ "//base/test:test_support",
63
+ "//chromeos/dbus/machine_learning",
64
+ "//chromeos/services/machine_learning/public/mojom",
65
+ "//mojo/core/embedder",
66
+ "//mojo/public/cpp/bindings",
67
+ "//testing/gtest",
68
+ ]
69
+ }
70
+
71
+ if (is_chromeos_ash) {
72
+ source_set("ash_unit_tests") {
73
+ sources = [ "../../cpp/ash/handwriting_model_loader_unittest.cc" ]
74
+ testonly = true
75
+ deps = [
76
+ ":cpp",
77
+ "//ash/constants:constants",
78
+ "//base/test:test_support",
79
+ "//chromeos/dbus/dlcservice",
80
+ "//chromeos/services/machine_learning/public/cpp:stub",
81
+ "//testing/gtest",
82
+ ]
83
+ }
84
+ }
19/public/cpp/fake_service_connection.cc ADDED
@@ -0,0 +1,574 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2019 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
6
+
7
+ #include <utility>
8
+
9
+ #include "base/bind.h"
10
+ #include "base/notreached.h"
11
+ #include "third_party/abseil-cpp/absl/types/optional.h"
12
+
13
+ namespace chromeos {
14
+ namespace machine_learning {
15
+
16
+ FakeServiceConnectionImpl::FakeServiceConnectionImpl()
17
+ : output_tensor_(mojom::Tensor::New()),
18
+ load_handwriting_model_result_(mojom::LoadHandwritingModelResult::OK),
19
+ load_web_platform_handwriting_model_result_(
20
+ mojom::LoadHandwritingModelResult::OK),
21
+ load_model_result_(mojom::LoadModelResult::OK),
22
+ load_text_classifier_result_(mojom::LoadModelResult::OK),
23
+ load_soda_result_(mojom::LoadModelResult::OK),
24
+ create_graph_executor_result_(mojom::CreateGraphExecutorResult::OK),
25
+ execute_result_(mojom::ExecuteResult::OK),
26
+ async_mode_(false) {}
27
+
28
+ FakeServiceConnectionImpl::~FakeServiceConnectionImpl() {}
29
+
30
+ mojom::MachineLearningService&
31
+ FakeServiceConnectionImpl::GetMachineLearningService() {
32
+ DCHECK(machine_learning_service_)
33
+ << "Call Initialize() before GetMachineLearningService()";
34
+ return *machine_learning_service_.get();
35
+ }
36
+
37
+ void FakeServiceConnectionImpl::BindMachineLearningService(
38
+ mojo::PendingReceiver<mojom::MachineLearningService> receiver) {
39
+ DCHECK(machine_learning_service_)
40
+ << "Call Initialize() before BindMachineLearningService()";
41
+ machine_learning_service_->Clone(std::move(receiver));
42
+ }
43
+
44
+ void FakeServiceConnectionImpl::Clone(
45
+ mojo::PendingReceiver<mojom::MachineLearningService> receiver) {
46
+ clone_ml_service_receivers_.Add(this, std::move(receiver));
47
+ }
48
+
49
+ void FakeServiceConnectionImpl::Initialize() {
50
+ clone_ml_service_receivers_.Add(
51
+ this, machine_learning_service_.BindNewPipeAndPassReceiver());
52
+ }
53
+
54
+ void FakeServiceConnectionImpl::LoadBuiltinModel(
55
+ mojom::BuiltinModelSpecPtr spec,
56
+ mojo::PendingReceiver<mojom::Model> receiver,
57
+ mojom::MachineLearningService::LoadBuiltinModelCallback callback) {
58
+ ScheduleCall(base::BindOnce(
59
+ &FakeServiceConnectionImpl::HandleLoadBuiltinModelCall,
60
+ base::Unretained(this), std::move(receiver), std::move(callback)));
61
+ }
62
+
63
+ void FakeServiceConnectionImpl::LoadFlatBufferModel(
64
+ mojom::FlatBufferModelSpecPtr spec,
65
+ mojo::PendingReceiver<mojom::Model> receiver,
66
+ mojom::MachineLearningService::LoadFlatBufferModelCallback callback) {
67
+ ScheduleCall(base::BindOnce(
68
+ &FakeServiceConnectionImpl::HandleLoadFlatBufferModelCall,
69
+ base::Unretained(this), std::move(receiver), std::move(callback)));
70
+ }
71
+
72
+ void FakeServiceConnectionImpl::REMOVED_0(
73
+ mojo::PendingReceiver<mojom::GraphExecutor> receiver,
74
+ mojom::Model::REMOVED_0Callback callback) {
75
+ NOTIMPLEMENTED();
76
+ }
77
+
78
+ void FakeServiceConnectionImpl::REMOVED_4(
79
+ mojom::HandwritingRecognizerSpecPtr spec,
80
+ mojo::PendingReceiver<mojom::HandwritingRecognizer> receiver,
81
+ mojom::MachineLearningService::REMOVED_4Callback callback) {
82
+ NOTIMPLEMENTED();
83
+ }
84
+
85
+ void FakeServiceConnectionImpl::CreateGraphExecutor(
86
+ mojom::GraphExecutorOptionsPtr options,
87
+ mojo::PendingReceiver<mojom::GraphExecutor> receiver,
88
+ mojom::Model::CreateGraphExecutorCallback callback) {
89
+ ScheduleCall(
90
+ base::BindOnce(&FakeServiceConnectionImpl::HandleCreateGraphExecutorCall,
91
+ base::Unretained(this), std::move(options),
92
+ std::move(receiver), std::move(callback)));
93
+ }
94
+
95
+ void FakeServiceConnectionImpl::LoadTextClassifier(
96
+ mojo::PendingReceiver<mojom::TextClassifier> receiver,
97
+ mojom::MachineLearningService::LoadTextClassifierCallback callback) {
98
+ ScheduleCall(base::BindOnce(
99
+ &FakeServiceConnectionImpl::HandleLoadTextClassifierCall,
100
+ base::Unretained(this), std::move(receiver), std::move(callback)));
101
+ }
102
+
103
+ void FakeServiceConnectionImpl::LoadHandwritingModel(
104
+ mojom::HandwritingRecognizerSpecPtr spec,
105
+ mojo::PendingReceiver<mojom::HandwritingRecognizer> receiver,
106
+ mojom::MachineLearningService::LoadHandwritingModelCallback callback) {
107
+ ScheduleCall(base::BindOnce(
108
+ &FakeServiceConnectionImpl::HandleLoadHandwritingModelCall,
109
+ base::Unretained(this), std::move(receiver), std::move(callback)));
110
+ }
111
+
112
+ void FakeServiceConnectionImpl::HandleLoadWebPlatformHandwritingModelCall(
113
+ mojo::PendingReceiver<web_platform::mojom::HandwritingRecognizer> receiver,
114
+ mojom::MachineLearningService::LoadHandwritingModelCallback callback) {
115
+ if (load_handwriting_model_result_ == mojom::LoadHandwritingModelResult::OK)
116
+ web_platform_handwriting_receivers_.Add(this, std::move(receiver));
117
+ std::move(callback).Run(load_web_platform_handwriting_model_result_);
118
+ }
119
+
120
+ void FakeServiceConnectionImpl::LoadWebPlatformHandwritingModel(
121
+ web_platform::mojom::HandwritingModelConstraintPtr constraint,
122
+ mojo::PendingReceiver<web_platform::mojom::HandwritingRecognizer> receiver,
123
+ mojom::MachineLearningService::LoadWebPlatformHandwritingModelCallback
124
+ callback) {
125
+ ScheduleCall(base::BindOnce(
126
+ &FakeServiceConnectionImpl::HandleLoadWebPlatformHandwritingModelCall,
127
+ base::Unretained(this), std::move(receiver), std::move(callback)));
128
+ }
129
+
130
+ void FakeServiceConnectionImpl::LoadGrammarChecker(
131
+ mojo::PendingReceiver<mojom::GrammarChecker> receiver,
132
+ mojom::MachineLearningService::LoadGrammarCheckerCallback callback) {
133
+ ScheduleCall(base::BindOnce(
134
+ &FakeServiceConnectionImpl::HandleLoadGrammarCheckerCall,
135
+ base::Unretained(this), std::move(receiver), std::move(callback)));
136
+ }
137
+
138
+ void FakeServiceConnectionImpl::LoadSpeechRecognizer(
139
+ mojom::SodaConfigPtr soda_config,
140
+ mojo::PendingRemote<mojom::SodaClient> soda_client,
141
+ mojo::PendingReceiver<mojom::SodaRecognizer> soda_recognizer,
142
+ mojom::MachineLearningService::LoadSpeechRecognizerCallback callback) {
143
+ ScheduleCall(
144
+ base::BindOnce(&FakeServiceConnectionImpl::HandleLoadSpeechRecognizerCall,
145
+ base::Unretained(this), std::move(soda_client),
146
+ std::move(soda_recognizer), std::move(callback)));
147
+ }
148
+
149
+ void FakeServiceConnectionImpl::LoadTextSuggester(
150
+ mojo::PendingReceiver<mojom::TextSuggester> receiver,
151
+ mojom::TextSuggesterSpecPtr spec,
152
+ mojom::MachineLearningService::LoadTextSuggesterCallback callback) {
153
+ ScheduleCall(
154
+ base::BindOnce(&FakeServiceConnectionImpl::HandleLoadTextSuggesterCall,
155
+ base::Unretained(this), std::move(receiver),
156
+ std::move(spec), std::move(callback)));
157
+ }
158
+
159
+ void FakeServiceConnectionImpl::LoadDocumentScanner(
160
+ mojo::PendingReceiver<mojom::DocumentScanner> receiver,
161
+ mojom::MachineLearningService::LoadDocumentScannerCallback callback) {
162
+ ScheduleCall(base::BindOnce(
163
+ &FakeServiceConnectionImpl::HandleLoadDocumentScannerCall,
164
+ base::Unretained(this), std::move(receiver), std::move(callback)));
165
+ }
166
+
167
+ void FakeServiceConnectionImpl::Execute(
168
+ base::flat_map<std::string, mojom::TensorPtr> inputs,
169
+ const std::vector<std::string>& output_names,
170
+ mojom::GraphExecutor::ExecuteCallback callback) {
171
+ ScheduleCall(base::BindOnce(&FakeServiceConnectionImpl::HandleExecuteCall,
172
+ base::Unretained(this), std::move(callback)));
173
+ }
174
+
175
+ void FakeServiceConnectionImpl::SetLoadModelFailure() {
176
+ load_model_result_ = mojom::LoadModelResult::LOAD_MODEL_ERROR;
177
+ }
178
+
179
+ void FakeServiceConnectionImpl::SetCreateGraphExecutorFailure() {
180
+ load_model_result_ = mojom::LoadModelResult::OK;
181
+ create_graph_executor_result_ =
182
+ mojom::CreateGraphExecutorResult::MODEL_INTERPRETATION_ERROR;
183
+ }
184
+
185
+ void FakeServiceConnectionImpl::SetExecuteFailure() {
186
+ load_model_result_ = mojom::LoadModelResult::OK;
187
+ create_graph_executor_result_ = mojom::CreateGraphExecutorResult::OK;
188
+ execute_result_ = mojom::ExecuteResult::EXECUTION_ERROR;
189
+ }
190
+
191
+ void FakeServiceConnectionImpl::SetExecuteSuccess() {
192
+ load_model_result_ = mojom::LoadModelResult::OK;
193
+ create_graph_executor_result_ = mojom::CreateGraphExecutorResult::OK;
194
+ execute_result_ = mojom::ExecuteResult::OK;
195
+ }
196
+
197
+ void FakeServiceConnectionImpl::SetTextClassifierSuccess() {
198
+ load_text_classifier_result_ = mojom::LoadModelResult::OK;
199
+ }
200
+
201
+ void FakeServiceConnectionImpl::SetLoadTextClassifierFailure() {
202
+ load_text_classifier_result_ = mojom::LoadModelResult::LOAD_MODEL_ERROR;
203
+ }
204
+
205
+ void FakeServiceConnectionImpl::SetOutputValue(
206
+ const std::vector<int64_t>& shape,
207
+ const std::vector<double>& value) {
208
+ output_tensor_->shape = mojom::Int64List::New();
209
+ output_tensor_->shape->value = shape;
210
+ output_tensor_->data = mojom::ValueList::New();
211
+ output_tensor_->data->set_float_list(mojom::FloatList::New());
212
+ output_tensor_->data->get_float_list()->value = value;
213
+ }
214
+
215
+ void FakeServiceConnectionImpl::SetAsyncMode(bool async_mode) {
216
+ async_mode_ = async_mode;
217
+ }
218
+
219
+ void FakeServiceConnectionImpl::RunPendingCalls() {
220
+ for (auto& call : pending_calls_) {
221
+ std::move(call).Run();
222
+ }
223
+
224
+ pending_calls_.clear();
225
+ }
226
+
227
+ void FakeServiceConnectionImpl::FlushForTesting() {
228
+ clone_ml_service_receivers_.FlushForTesting();
229
+ machine_learning_service_.FlushForTesting();
230
+ model_receivers_.FlushForTesting();
231
+ graph_receivers_.FlushForTesting();
232
+ text_classifier_receivers_.FlushForTesting();
233
+ handwriting_receivers_.FlushForTesting();
234
+ web_platform_handwriting_receivers_.FlushForTesting();
235
+ grammar_checker_receivers_.FlushForTesting();
236
+ soda_recognizer_receivers_.FlushForTesting();
237
+ text_suggester_receivers_.FlushForTesting();
238
+ document_scanner_receivers_.FlushForTesting();
239
+ soda_client_remotes_.FlushForTesting();
240
+ }
241
+
242
+ void FakeServiceConnectionImpl::HandleLoadBuiltinModelCall(
243
+ mojo::PendingReceiver<mojom::Model> receiver,
244
+ mojom::MachineLearningService::LoadBuiltinModelCallback callback) {
245
+ if (load_model_result_ == mojom::LoadModelResult::OK)
246
+ model_receivers_.Add(this, std::move(receiver));
247
+
248
+ std::move(callback).Run(load_model_result_);
249
+ }
250
+
251
+ void FakeServiceConnectionImpl::HandleLoadTextClassifierCall(
252
+ mojo::PendingReceiver<mojom::TextClassifier> receiver,
253
+ mojom::MachineLearningService::LoadTextClassifierCallback callback) {
254
+ if (load_text_classifier_result_ == mojom::LoadModelResult::OK)
255
+ text_classifier_receivers_.Add(this, std::move(receiver));
256
+
257
+ std::move(callback).Run(load_text_classifier_result_);
258
+ }
259
+
260
+ void FakeServiceConnectionImpl::ScheduleCall(base::OnceClosure call) {
261
+ if (async_mode_)
262
+ pending_calls_.push_back(std::move(call));
263
+ else
264
+ std::move(call).Run();
265
+ }
266
+
267
+ void FakeServiceConnectionImpl::HandleLoadFlatBufferModelCall(
268
+ mojo::PendingReceiver<mojom::Model> receiver,
269
+ mojom::MachineLearningService::LoadFlatBufferModelCallback callback) {
270
+ if (load_model_result_ == mojom::LoadModelResult::OK)
271
+ model_receivers_.Add(this, std::move(receiver));
272
+
273
+ std::move(callback).Run(load_model_result_);
274
+ }
275
+
276
+ void FakeServiceConnectionImpl::HandleCreateGraphExecutorCall(
277
+ mojom::GraphExecutorOptionsPtr options,
278
+ mojo::PendingReceiver<mojom::GraphExecutor> receiver,
279
+ mojom::Model::CreateGraphExecutorCallback callback) {
280
+ if (create_graph_executor_result_ == mojom::CreateGraphExecutorResult::OK)
281
+ graph_receivers_.Add(this, std::move(receiver));
282
+
283
+ std::move(callback).Run(create_graph_executor_result_);
284
+ }
285
+
286
+ void FakeServiceConnectionImpl::HandleExecuteCall(
287
+ mojom::GraphExecutor::ExecuteCallback callback) {
288
+ if (execute_result_ != mojom::ExecuteResult::OK) {
289
+ std::move(callback).Run(execute_result_, absl::nullopt);
290
+ return;
291
+ }
292
+
293
+ std::vector<mojom::TensorPtr> output_tensors;
294
+ output_tensors.push_back(output_tensor_.Clone());
295
+ std::move(callback).Run(execute_result_, std::move(output_tensors));
296
+ }
297
+
298
+ void FakeServiceConnectionImpl::HandleAnnotateCall(
299
+ mojom::TextAnnotationRequestPtr request,
300
+ mojom::TextClassifier::AnnotateCallback callback) {
301
+ std::vector<mojom::TextAnnotationPtr> annotations;
302
+ for (auto const& annotate : annotate_result_) {
303
+ annotations.emplace_back(annotate.Clone());
304
+ }
305
+ std::move(callback).Run(std::move(annotations));
306
+ }
307
+
308
+ void FakeServiceConnectionImpl::HandleFindLanguagesCall(
309
+ std::string request,
310
+ mojom::TextClassifier::FindLanguagesCallback callback) {
311
+ std::vector<mojom::TextLanguagePtr> languages;
312
+ for (auto const& language : find_languages_result_) {
313
+ languages.emplace_back(language.Clone());
314
+ }
315
+ std::move(callback).Run(std::move(languages));
316
+ }
317
+
318
+ void FakeServiceConnectionImpl::SetOutputAnnotation(
319
+ const std::vector<mojom::TextAnnotationPtr>& annotations) {
320
+ annotate_result_.clear();
321
+ for (auto const& annotate : annotations) {
322
+ annotate_result_.emplace_back(annotate.Clone());
323
+ }
324
+ }
325
+
326
+ void FakeServiceConnectionImpl::SetOutputLanguages(
327
+ const std::vector<mojom::TextLanguagePtr>& languages) {
328
+ find_languages_result_.clear();
329
+ for (auto const& language : languages) {
330
+ find_languages_result_.emplace_back(language.Clone());
331
+ }
332
+ }
333
+
334
+ void FakeServiceConnectionImpl::SetOutputHandwritingRecognizerResult(
335
+ const mojom::HandwritingRecognizerResultPtr& result) {
336
+ handwriting_result_ = result.Clone();
337
+ }
338
+
339
+ void FakeServiceConnectionImpl::SetOutputWebPlatformHandwritingRecognizerResult(
340
+ const std::vector<web_platform::mojom::HandwritingPredictionPtr>&
341
+ predictions) {
342
+ web_platform_handwriting_result_.clear();
343
+ for (auto const& prediction : predictions) {
344
+ web_platform_handwriting_result_.emplace_back(prediction.Clone());
345
+ }
346
+ }
347
+
348
+ void FakeServiceConnectionImpl::SetOutputGrammarCheckerResult(
349
+ const mojom::GrammarCheckerResultPtr& result) {
350
+ grammar_checker_result_ = result.Clone();
351
+ }
352
+
353
+ void FakeServiceConnectionImpl::SetOutputTextSuggesterResult(
354
+ const mojom::TextSuggesterResultPtr& result) {
355
+ text_suggester_result_ = result.Clone();
356
+ }
357
+
358
+ void FakeServiceConnectionImpl::SetOutputDetectCornersResult(
359
+ const mojom::DetectCornersResultPtr& result) {
360
+ detect_corners_result_ = result.Clone();
361
+ }
362
+
363
+ void FakeServiceConnectionImpl::SetOutputDoPostProcessingResult(
364
+ const mojom::DoPostProcessingResultPtr& result) {
365
+ do_post_processing_result_ = result.Clone();
366
+ }
367
+
368
+ void FakeServiceConnectionImpl::Annotate(
369
+ mojom::TextAnnotationRequestPtr request,
370
+ mojom::TextClassifier::AnnotateCallback callback) {
371
+ ScheduleCall(base::BindOnce(&FakeServiceConnectionImpl::HandleAnnotateCall,
372
+ base::Unretained(this), std::move(request),
373
+ std::move(callback)));
374
+ }
375
+
376
+ void FakeServiceConnectionImpl::FindLanguages(
377
+ const std::string& text,
378
+ mojom::TextClassifier::FindLanguagesCallback callback) {
379
+ ScheduleCall(
380
+ base::BindOnce(&FakeServiceConnectionImpl::HandleFindLanguagesCall,
381
+ base::Unretained(this), text, std::move(callback)));
382
+ }
383
+
384
+ void FakeServiceConnectionImpl::REMOVED_1(
385
+ mojom::REMOVED_TextSuggestSelectionRequestPtr request,
386
+ mojom::TextClassifier::REMOVED_1Callback callback) {
387
+ NOTIMPLEMENTED();
388
+ }
389
+
390
+ void FakeServiceConnectionImpl::Recognize(
391
+ mojom::HandwritingRecognitionQueryPtr query,
392
+ mojom::HandwritingRecognizer::RecognizeCallback callback) {
393
+ ScheduleCall(base::BindOnce(&FakeServiceConnectionImpl::HandleRecognizeCall,
394
+ base::Unretained(this), std::move(query),
395
+ std::move(callback)));
396
+ }
397
+
398
+ void FakeServiceConnectionImpl::GetPrediction(
399
+ std::vector<web_platform::mojom::HandwritingStrokePtr> strokes,
400
+ web_platform::mojom::HandwritingHintsPtr hints,
401
+ web_platform::mojom::HandwritingRecognizer::GetPredictionCallback
402
+ callback) {
403
+ ScheduleCall(
404
+ base::BindOnce(&FakeServiceConnectionImpl::HandleGetPredictionCall,
405
+ base::Unretained(this), std::move(strokes),
406
+ std::move(hints), std::move(callback)));
407
+ }
408
+
409
+ void FakeServiceConnectionImpl::Check(
410
+ mojom::GrammarCheckerQueryPtr query,
411
+ mojom::GrammarChecker::CheckCallback callback) {
412
+ ScheduleCall(base::BindOnce(
413
+ &FakeServiceConnectionImpl::HandleGrammarCheckerQueryCall,
414
+ base::Unretained(this), std::move(query), std::move(callback)));
415
+ }
416
+ void FakeServiceConnectionImpl::HandleStopCall() {
417
+ // Do something on the client
418
+ }
419
+
420
+ void FakeServiceConnectionImpl::HandleStartCall() {
421
+ // Do something on the client.
422
+ }
423
+
424
+ void FakeServiceConnectionImpl::HandleMarkDoneCall() {
425
+ HandleStopCall();
426
+ }
427
+
428
+ void FakeServiceConnectionImpl::AddAudio(const std::vector<uint8_t>& audio) {}
429
+ void FakeServiceConnectionImpl::Stop() {
430
+ ScheduleCall(base::BindOnce(&FakeServiceConnectionImpl::HandleStopCall,
431
+ base::Unretained(this)));
432
+ }
433
+ void FakeServiceConnectionImpl::Start() {
434
+ ScheduleCall(base::BindOnce(&FakeServiceConnectionImpl::HandleStartCall,
435
+ base::Unretained(this)));
436
+ }
437
+ void FakeServiceConnectionImpl::MarkDone() {
438
+ ScheduleCall(base::BindOnce(&FakeServiceConnectionImpl::HandleMarkDoneCall,
439
+ base::Unretained(this)));
440
+ }
441
+
442
+ void FakeServiceConnectionImpl::Suggest(
443
+ mojom::TextSuggesterQueryPtr query,
444
+ mojom::TextSuggester::SuggestCallback callback) {
445
+ ScheduleCall(base::BindOnce(
446
+ &FakeServiceConnectionImpl::HandleTextSuggesterSuggestCall,
447
+ base::Unretained(this), std::move(query), std::move(callback)));
448
+ }
449
+
450
+ void FakeServiceConnectionImpl::DetectCornersFromNV12Image(
451
+ base::ReadOnlySharedMemoryRegion nv12_image,
452
+ mojom::DocumentScanner::DetectCornersFromNV12ImageCallback callback) {
453
+ ScheduleCall(base::BindOnce(
454
+ &FakeServiceConnectionImpl::HandleDocumentScannerDetectNV12Call,
455
+ base::Unretained(this), std::move(nv12_image), std::move(callback)));
456
+ }
457
+
458
+ void FakeServiceConnectionImpl::DetectCornersFromJPEGImage(
459
+ base::ReadOnlySharedMemoryRegion jpeg_image,
460
+ mojom::DocumentScanner::DetectCornersFromJPEGImageCallback callback) {
461
+ ScheduleCall(base::BindOnce(
462
+ &FakeServiceConnectionImpl::HandleDocumentScannerDetectJPEGCall,
463
+ base::Unretained(this), std::move(jpeg_image), std::move(callback)));
464
+ }
465
+
466
+ void FakeServiceConnectionImpl::DoPostProcessing(
467
+ base::ReadOnlySharedMemoryRegion jpeg_image,
468
+ const std::vector<gfx::PointF>& corners,
469
+ chromeos::machine_learning::mojom::Rotation rotation,
470
+ mojom::DocumentScanner::DoPostProcessingCallback callback) {
471
+ ScheduleCall(base::BindOnce(
472
+ &FakeServiceConnectionImpl::HandleDocumentScannerPostProcessingCall,
473
+ base::Unretained(this), std::move(jpeg_image), std::move(corners),
474
+ std::move(callback)));
475
+ }
476
+
477
+ void FakeServiceConnectionImpl::HandleLoadHandwritingModelCall(
478
+ mojo::PendingReceiver<mojom::HandwritingRecognizer> receiver,
479
+ mojom::MachineLearningService::LoadHandwritingModelCallback callback) {
480
+ if (load_handwriting_model_result_ == mojom::LoadHandwritingModelResult::OK)
481
+ handwriting_receivers_.Add(this, std::move(receiver));
482
+ std::move(callback).Run(load_handwriting_model_result_);
483
+ }
484
+
485
+ void FakeServiceConnectionImpl::HandleRecognizeCall(
486
+ mojom::HandwritingRecognitionQueryPtr query,
487
+ mojom::HandwritingRecognizer::RecognizeCallback callback) {
488
+ std::move(callback).Run(handwriting_result_.Clone());
489
+ }
490
+
491
+ void FakeServiceConnectionImpl::HandleGetPredictionCall(
492
+ std::vector<web_platform::mojom::HandwritingStrokePtr> strokes,
493
+ web_platform::mojom::HandwritingHintsPtr hints,
494
+ web_platform::mojom::HandwritingRecognizer::GetPredictionCallback
495
+ callback) {
496
+ std::vector<web_platform::mojom::HandwritingPredictionPtr> predictions;
497
+ for (auto const& prediction : web_platform_handwriting_result_) {
498
+ predictions.emplace_back(prediction.Clone());
499
+ }
500
+ std::move(callback).Run(std::move(predictions));
501
+ }
502
+
503
+ void FakeServiceConnectionImpl::HandleLoadGrammarCheckerCall(
504
+ mojo::PendingReceiver<mojom::GrammarChecker> receiver,
505
+ mojom::MachineLearningService::LoadGrammarCheckerCallback callback) {
506
+ if (load_model_result_ == mojom::LoadModelResult::OK)
507
+ grammar_checker_receivers_.Add(this, std::move(receiver));
508
+
509
+ std::move(callback).Run(load_model_result_);
510
+ }
511
+
512
+ void FakeServiceConnectionImpl::HandleLoadSpeechRecognizerCall(
513
+ mojo::PendingRemote<mojom::SodaClient> soda_client,
514
+ mojo::PendingReceiver<mojom::SodaRecognizer> soda_recognizer,
515
+ mojom::MachineLearningService::LoadSpeechRecognizerCallback callback) {
516
+ if (load_soda_result_ == mojom::LoadModelResult::OK) {
517
+ soda_recognizer_receivers_.Add(this, std::move(soda_recognizer));
518
+ soda_client_remotes_.Add(std::move(soda_client));
519
+ }
520
+ std::move(callback).Run(load_soda_result_);
521
+ }
522
+
523
+ void FakeServiceConnectionImpl::HandleGrammarCheckerQueryCall(
524
+ mojom::GrammarCheckerQueryPtr query,
525
+ mojom::GrammarChecker::CheckCallback callback) {
526
+ std::move(callback).Run(grammar_checker_result_.Clone());
527
+ }
528
+
529
+ void FakeServiceConnectionImpl::HandleLoadTextSuggesterCall(
530
+ mojo::PendingReceiver<mojom::TextSuggester> receiver,
531
+ mojom::TextSuggesterSpecPtr spec,
532
+ mojom::MachineLearningService::LoadTextSuggesterCallback callback) {
533
+ if (load_model_result_ == mojom::LoadModelResult::OK)
534
+ text_suggester_receivers_.Add(this, std::move(receiver));
535
+
536
+ std::move(callback).Run(load_model_result_);
537
+ }
538
+
539
+ void FakeServiceConnectionImpl::HandleTextSuggesterSuggestCall(
540
+ mojom::TextSuggesterQueryPtr query,
541
+ mojom::TextSuggester::SuggestCallback callback) {
542
+ std::move(callback).Run(text_suggester_result_.Clone());
543
+ }
544
+
545
+ void FakeServiceConnectionImpl::HandleLoadDocumentScannerCall(
546
+ mojo::PendingReceiver<mojom::DocumentScanner> receiver,
547
+ mojom::MachineLearningService::LoadDocumentScannerCallback callback) {
548
+ if (load_model_result_ == mojom::LoadModelResult::OK)
549
+ document_scanner_receivers_.Add(this, std::move(receiver));
550
+
551
+ std::move(callback).Run(load_model_result_);
552
+ }
553
+
554
+ void FakeServiceConnectionImpl::HandleDocumentScannerDetectNV12Call(
555
+ base::ReadOnlySharedMemoryRegion nv12_image,
556
+ mojom::DocumentScanner::DetectCornersFromNV12ImageCallback callback) {
557
+ std::move(callback).Run(detect_corners_result_.Clone());
558
+ }
559
+
560
+ void FakeServiceConnectionImpl::HandleDocumentScannerDetectJPEGCall(
561
+ base::ReadOnlySharedMemoryRegion jpeg_image,
562
+ mojom::DocumentScanner::DetectCornersFromJPEGImageCallback callback) {
563
+ std::move(callback).Run(detect_corners_result_.Clone());
564
+ }
565
+
566
+ void FakeServiceConnectionImpl::HandleDocumentScannerPostProcessingCall(
567
+ base::ReadOnlySharedMemoryRegion jpeg_image,
568
+ const std::vector<gfx::PointF>& corners,
569
+ mojom::DocumentScanner::DoPostProcessingCallback callback) {
570
+ std::move(callback).Run(do_post_processing_result_.Clone());
571
+ }
572
+
573
+ } // namespace machine_learning
574
+ } // namespace chromeos
19/public/cpp/fake_service_connection.h ADDED
@@ -0,0 +1,383 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2019 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #ifndef CHROMEOS_SERVICES_MACHINE_LEARNING_PUBLIC_CPP_FAKE_SERVICE_CONNECTION_H_
6
+ #define CHROMEOS_SERVICES_MACHINE_LEARNING_PUBLIC_CPP_FAKE_SERVICE_CONNECTION_H_
7
+
8
+ #include <memory>
9
+ #include <vector>
10
+
11
+ #include "base/callback_forward.h"
12
+ #include "base/component_export.h"
13
+ #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
14
+ #include "chromeos/services/machine_learning/public/mojom/document_scanner.mojom.h"
15
+ #include "chromeos/services/machine_learning/public/mojom/grammar_checker.mojom.h"
16
+ #include "chromeos/services/machine_learning/public/mojom/graph_executor.mojom.h"
17
+ #include "chromeos/services/machine_learning/public/mojom/handwriting_recognizer.mojom.h"
18
+ #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
19
+ #include "chromeos/services/machine_learning/public/mojom/model.mojom.h"
20
+ #include "chromeos/services/machine_learning/public/mojom/soda.mojom.h"
21
+ #include "chromeos/services/machine_learning/public/mojom/tensor.mojom.h"
22
+ #include "chromeos/services/machine_learning/public/mojom/text_classifier.mojom.h"
23
+ #include "chromeos/services/machine_learning/public/mojom/text_suggester.mojom.h"
24
+ #include "chromeos/services/machine_learning/public/mojom/web_platform_handwriting.mojom.h"
25
+ #include "mojo/public/cpp/bindings/pending_receiver.h"
26
+ #include "mojo/public/cpp/bindings/receiver_set.h"
27
+ #include "mojo/public/cpp/bindings/remote_set.h"
28
+
29
+ namespace chromeos {
30
+ namespace machine_learning {
31
+
32
+ // Fake implementation of chromeos::machine_learning::ServiceConnection.
33
+ // Handles LoadModel (and Model::CreateGraphExecutor) by binding to itself.
34
+ // Handles GraphExecutor::Execute by always returning the value specified by
35
+ // a previous call to SetOutputValue.
36
+ // Handles TextClassifier::Annotate by always returning the value specified by
37
+ // a previous call to SetOutputAnnotation.
38
+ // For use with ServiceConnection::UseFakeServiceConnectionForTesting().
39
+ class COMPONENT_EXPORT(CHROMEOS_MLSERVICE) FakeServiceConnectionImpl
40
+ : public ServiceConnection,
41
+ public mojom::MachineLearningService,
42
+ public mojom::Model,
43
+ public mojom::TextClassifier,
44
+ public mojom::HandwritingRecognizer,
45
+ public mojom::GrammarChecker,
46
+ public mojom::GraphExecutor,
47
+ public mojom::SodaRecognizer,
48
+ public mojom::TextSuggester,
49
+ public mojom::DocumentScanner,
50
+ public web_platform::mojom::HandwritingRecognizer {
51
+ public:
52
+ FakeServiceConnectionImpl();
53
+
54
+ FakeServiceConnectionImpl(const FakeServiceConnectionImpl&) = delete;
55
+ FakeServiceConnectionImpl& operator=(const FakeServiceConnectionImpl&) =
56
+ delete;
57
+
58
+ ~FakeServiceConnectionImpl() override;
59
+
60
+ // ServiceConnection:
61
+ mojom::MachineLearningService& GetMachineLearningService() override;
62
+ void BindMachineLearningService(
63
+ mojo::PendingReceiver<mojom::MachineLearningService> receiver) override;
64
+ void Initialize() override;
65
+
66
+ // mojom::MachineLearningService:
67
+ void Clone(
68
+ mojo::PendingReceiver<mojom::MachineLearningService> receiver) override;
69
+
70
+ // It's safe to execute LoadBuiltinModel, LoadFlatBufferModel and
71
+ // LoadTextClassifier for multi times, but all the receivers will be bound to
72
+ // the same instance.
73
+ void LoadBuiltinModel(mojom::BuiltinModelSpecPtr spec,
74
+ mojo::PendingReceiver<mojom::Model> receiver,
75
+ mojom::MachineLearningService::LoadBuiltinModelCallback
76
+ callback) override;
77
+ void LoadFlatBufferModel(
78
+ mojom::FlatBufferModelSpecPtr spec,
79
+ mojo::PendingReceiver<mojom::Model> receiver,
80
+ mojom::MachineLearningService::LoadFlatBufferModelCallback callback)
81
+ override;
82
+
83
+ void LoadTextClassifier(
84
+ mojo::PendingReceiver<mojom::TextClassifier> receiver,
85
+ mojom::MachineLearningService::LoadTextClassifierCallback callback)
86
+ override;
87
+
88
+ void LoadHandwritingModel(
89
+ mojom::HandwritingRecognizerSpecPtr spec,
90
+ mojo::PendingReceiver<mojom::HandwritingRecognizer> receiver,
91
+ mojom::MachineLearningService::LoadHandwritingModelCallback
92
+ result_callback) override;
93
+
94
+ // Dedicated HWR API for Web Platform.
95
+ void LoadWebPlatformHandwritingModel(
96
+ web_platform::mojom::HandwritingModelConstraintPtr constraint,
97
+ mojo::PendingReceiver<web_platform::mojom::HandwritingRecognizer>
98
+ receiver,
99
+ LoadWebPlatformHandwritingModelCallback callback) override;
100
+
101
+ void LoadGrammarChecker(
102
+ mojo::PendingReceiver<mojom::GrammarChecker> receiver,
103
+ mojom::MachineLearningService::LoadGrammarCheckerCallback callback)
104
+ override;
105
+
106
+ void LoadSpeechRecognizer(
107
+ mojom::SodaConfigPtr soda_config,
108
+ mojo::PendingRemote<mojom::SodaClient> soda_client,
109
+ mojo::PendingReceiver<mojom::SodaRecognizer> soda_recognizer,
110
+ mojom::MachineLearningService::LoadSpeechRecognizerCallback callback)
111
+ override;
112
+
113
+ void LoadTextSuggester(
114
+ mojo::PendingReceiver<mojom::TextSuggester> receiver,
115
+ mojom::TextSuggesterSpecPtr spec,
116
+ mojom::MachineLearningService::LoadTextSuggesterCallback callback)
117
+ override;
118
+
119
+ void LoadDocumentScanner(
120
+ mojo::PendingReceiver<mojom::DocumentScanner> receiver,
121
+ mojom::MachineLearningService::LoadDocumentScannerCallback callback)
122
+ override;
123
+
124
+ // mojom::Model:
125
+ void REMOVED_0(mojo::PendingReceiver<mojom::GraphExecutor> receiver,
126
+ mojom::Model::REMOVED_0Callback callback) override;
127
+
128
+ // mojom::Model:
129
+ void REMOVED_4(mojom::HandwritingRecognizerSpecPtr spec,
130
+ mojo::PendingReceiver<mojom::HandwritingRecognizer> receiver,
131
+ mojom::MachineLearningService::REMOVED_4Callback
132
+ result_callback) override;
133
+
134
+ // mojom::Model:
135
+ void CreateGraphExecutor(
136
+ mojom::GraphExecutorOptionsPtr options,
137
+ mojo::PendingReceiver<mojom::GraphExecutor> receiver,
138
+ mojom::Model::CreateGraphExecutorCallback callback) override;
139
+
140
+ // mojom::GraphExecutor:
141
+ // Execute() will return the tensor set by SetOutputValue() as the output.
142
+ void Execute(base::flat_map<std::string, mojom::TensorPtr> inputs,
143
+ const std::vector<std::string>& output_names,
144
+ mojom::GraphExecutor::ExecuteCallback callback) override;
145
+
146
+ // Useful for simulating a failure at different stage.
147
+ // There are different error codes at each stage, we just randomly pick one.
148
+ void SetLoadModelFailure();
149
+ void SetCreateGraphExecutorFailure();
150
+ void SetExecuteFailure();
151
+ void SetLoadTextClassifierFailure();
152
+ // Reset all the Model related failures and make Execute succeed.
153
+ void SetExecuteSuccess();
154
+ // Reset all the TextClassifier related failures and make LoadTextClassifier
155
+ // succeed.
156
+ // Currently, there are two interfaces related to TextClassifier
157
+ // (|LoadTextClassifier|, |Annotate|) but only
158
+ // |LoadTextClassifier| can fail.
159
+ void SetTextClassifierSuccess();
160
+
161
+ // Call SetOutputValue() before Execute() to set the output tensor.
162
+ void SetOutputValue(const std::vector<int64_t>& shape,
163
+ const std::vector<double>& value);
164
+
165
+ // In async mode, FakeServiceConnectionImpl adds requests like
166
+ // LoadBuiltinModel, CreateGraphExecutor to |pending_calls_| instead of
167
+ // responding immediately. Calls in |pending_calls_| will run when
168
+ // RunPendingCalls() is called.
169
+ // It's useful when an unit test wants to test the async behaviour of real
170
+ // ml-service.
171
+ void SetAsyncMode(bool async_mode);
172
+ void RunPendingCalls();
173
+
174
+ // Call SetOutputAnnotation() before Annotate() to set the output annotation.
175
+ void SetOutputAnnotation(
176
+ const std::vector<mojom::TextAnnotationPtr>& annotation);
177
+
178
+ // Call SetOutputLanguages() before FindLanguages() to set the output
179
+ // languages.
180
+ void SetOutputLanguages(const std::vector<mojom::TextLanguagePtr>& languages);
181
+
182
+ // Call SetOutputGrammarCheckerResult() before Check() to set the output of
183
+ // grammar checker.
184
+ void SetOutputGrammarCheckerResult(
185
+ const mojom::GrammarCheckerResultPtr& result);
186
+
187
+ // Call SetOutputHandwritingRecognizerResult() before Recognize() to set the
188
+ // output of handwriting.
189
+ void SetOutputHandwritingRecognizerResult(
190
+ const mojom::HandwritingRecognizerResultPtr& result);
191
+
192
+ // Call SetOutputWebPlatformHandwritingRecognizerResult() before
193
+ // GetPrediction() to set the output of handwriting.
194
+ void SetOutputWebPlatformHandwritingRecognizerResult(
195
+ const std::vector<web_platform::mojom::HandwritingPredictionPtr>&
196
+ predictions);
197
+
198
+ // Call SetOutputTextSuggesterResult() before Suggest() to set the
199
+ // output of a text suggestion query.
200
+ void SetOutputTextSuggesterResult(
201
+ const mojom::TextSuggesterResultPtr& result);
202
+
203
+ // Call SetOutputDetectCornersResult() before
204
+ // DetectCornersFrom{NV12/JPEG}Image() to set the output of corners detection.
205
+ void SetOutputDetectCornersResult(
206
+ const mojom::DetectCornersResultPtr& result);
207
+
208
+ // Call SetOutputDoPostProcessingResult() before DoPostProcessing() to set the
209
+ // output of document post processing.
210
+ void SetOutputDoPostProcessingResult(
211
+ const mojom::DoPostProcessingResultPtr& result);
212
+
213
+ // mojom::TextClassifier:
214
+ void Annotate(mojom::TextAnnotationRequestPtr request,
215
+ mojom::TextClassifier::AnnotateCallback callback) override;
216
+
217
+ // mojom::TextClassifier:
218
+ void FindLanguages(
219
+ const std::string& text,
220
+ mojom::TextClassifier::FindLanguagesCallback callback) override;
221
+
222
+ // mojom::TextClassifier:
223
+ void REMOVED_1(
224
+ mojom::REMOVED_TextSuggestSelectionRequestPtr request,
225
+ mojom::TextClassifier::REMOVED_1Callback callback) override;
226
+
227
+ // mojom::HandwritingRecognizer:
228
+ void Recognize(
229
+ mojom::HandwritingRecognitionQueryPtr query,
230
+ mojom::HandwritingRecognizer::RecognizeCallback callback) override;
231
+
232
+ // web_platform::mojom::HandwritingRecognizer
233
+ void GetPrediction(
234
+ std::vector<web_platform::mojom::HandwritingStrokePtr> strokes,
235
+ web_platform::mojom::HandwritingHintsPtr hints,
236
+ web_platform::mojom::HandwritingRecognizer::GetPredictionCallback
237
+ callback) override;
238
+
239
+ // mojom::GrammarChecker:
240
+ void Check(mojom::GrammarCheckerQueryPtr query,
241
+ mojom::GrammarChecker::CheckCallback callback) override;
242
+
243
+ // mojom::SpeechRecognizer
244
+ void AddAudio(const std::vector<uint8_t>& audio) override;
245
+ void Stop() override;
246
+ void Start() override;
247
+ void MarkDone() override;
248
+
249
+ // mojom::TextSuggester:
250
+ void Suggest(mojom::TextSuggesterQueryPtr query,
251
+ mojom::TextSuggester::SuggestCallback callback) override;
252
+
253
+ // mojom::DocumentScanner:
254
+ void DetectCornersFromNV12Image(
255
+ base::ReadOnlySharedMemoryRegion nv12_image,
256
+ mojom::DocumentScanner::DetectCornersFromNV12ImageCallback callback)
257
+ override;
258
+ void DetectCornersFromJPEGImage(
259
+ base::ReadOnlySharedMemoryRegion jpeg_image,
260
+ mojom::DocumentScanner::DetectCornersFromJPEGImageCallback callback)
261
+ override;
262
+ void DoPostProcessing(
263
+ base::ReadOnlySharedMemoryRegion jpeg_image,
264
+ const std::vector<gfx::PointF>& corners,
265
+ chromeos::machine_learning::mojom::Rotation rotation,
266
+ mojom::DocumentScanner::DoPostProcessingCallback callback) override;
267
+
268
+ // Flush all relevant Mojo pipes.
269
+ void FlushForTesting();
270
+
271
+ private:
272
+ void ScheduleCall(base::OnceClosure call);
273
+ void HandleLoadBuiltinModelCall(
274
+ mojo::PendingReceiver<mojom::Model> receiver,
275
+ mojom::MachineLearningService::LoadBuiltinModelCallback callback);
276
+ void HandleLoadFlatBufferModelCall(
277
+ mojo::PendingReceiver<mojom::Model> receiver,
278
+ mojom::MachineLearningService::LoadFlatBufferModelCallback callback);
279
+ void HandleCreateGraphExecutorCall(
280
+ mojom::GraphExecutorOptionsPtr options,
281
+ mojo::PendingReceiver<mojom::GraphExecutor> receiver,
282
+ mojom::Model::CreateGraphExecutorCallback callback);
283
+ void HandleExecuteCall(mojom::GraphExecutor::ExecuteCallback callback);
284
+ void HandleLoadTextClassifierCall(
285
+ mojo::PendingReceiver<mojom::TextClassifier> receiver,
286
+ mojom::MachineLearningService::LoadTextClassifierCallback callback);
287
+ void HandleAnnotateCall(mojom::TextAnnotationRequestPtr request,
288
+ mojom::TextClassifier::AnnotateCallback callback);
289
+ void HandleFindLanguagesCall(
290
+ std::string text,
291
+ mojom::TextClassifier::FindLanguagesCallback callback);
292
+ void HandleLoadHandwritingModelCall(
293
+ mojo::PendingReceiver<mojom::HandwritingRecognizer> receiver,
294
+ mojom::MachineLearningService::LoadHandwritingModelCallback callback);
295
+ void HandleLoadWebPlatformHandwritingModelCall(
296
+ mojo::PendingReceiver<web_platform::mojom::HandwritingRecognizer>
297
+ receiver,
298
+ mojom::MachineLearningService::LoadHandwritingModelCallback callback);
299
+ void HandleRecognizeCall(
300
+ mojom::HandwritingRecognitionQueryPtr query,
301
+ mojom::HandwritingRecognizer::RecognizeCallback callback);
302
+ void HandleGetPredictionCall(
303
+ std::vector<web_platform::mojom::HandwritingStrokePtr> strokes,
304
+ web_platform::mojom::HandwritingHintsPtr hints,
305
+ web_platform::mojom::HandwritingRecognizer::GetPredictionCallback
306
+ callback);
307
+ void HandleLoadGrammarCheckerCall(
308
+ mojo::PendingReceiver<mojom::GrammarChecker> receiver,
309
+ mojom::MachineLearningService::LoadGrammarCheckerCallback callback);
310
+ void HandleGrammarCheckerQueryCall(
311
+ mojom::GrammarCheckerQueryPtr query,
312
+ mojom::GrammarChecker::CheckCallback callback);
313
+ void HandleLoadSpeechRecognizerCall(
314
+ mojo::PendingRemote<mojom::SodaClient> soda_client,
315
+ mojo::PendingReceiver<mojom::SodaRecognizer> soda_recognizer,
316
+ mojom::MachineLearningService::LoadSpeechRecognizerCallback callback);
317
+ void HandleLoadTextSuggesterCall(
318
+ mojo::PendingReceiver<mojom::TextSuggester> receiver,
319
+ mojom::TextSuggesterSpecPtr spec,
320
+ mojom::MachineLearningService::LoadTextSuggesterCallback callback);
321
+ void HandleTextSuggesterSuggestCall(
322
+ mojom::TextSuggesterQueryPtr query,
323
+ mojom::TextSuggester::SuggestCallback callback);
324
+ void HandleLoadDocumentScannerCall(
325
+ mojo::PendingReceiver<mojom::DocumentScanner> receiver,
326
+ mojom::MachineLearningService::LoadDocumentScannerCallback callback);
327
+ void HandleDocumentScannerDetectNV12Call(
328
+ base::ReadOnlySharedMemoryRegion nv12_image,
329
+ mojom::DocumentScanner::DetectCornersFromNV12ImageCallback callback);
330
+ void HandleDocumentScannerDetectJPEGCall(
331
+ base::ReadOnlySharedMemoryRegion jpeg_image,
332
+ mojom::DocumentScanner::DetectCornersFromJPEGImageCallback callback);
333
+ void HandleDocumentScannerPostProcessingCall(
334
+ base::ReadOnlySharedMemoryRegion jpeg_image,
335
+ const std::vector<gfx::PointF>& corners,
336
+ mojom::DocumentScanner::DoPostProcessingCallback callback);
337
+
338
+ void HandleStopCall();
339
+ void HandleStartCall();
340
+ void HandleMarkDoneCall();
341
+
342
+ // Additional receivers bound via `Clone`.
343
+ mojo::ReceiverSet<mojom::MachineLearningService> clone_ml_service_receivers_;
344
+
345
+ mojo::Remote<mojom::MachineLearningService> machine_learning_service_;
346
+ mojo::ReceiverSet<mojom::Model> model_receivers_;
347
+ mojo::ReceiverSet<mojom::GraphExecutor> graph_receivers_;
348
+ mojo::ReceiverSet<mojom::TextClassifier> text_classifier_receivers_;
349
+ mojo::ReceiverSet<mojom::HandwritingRecognizer> handwriting_receivers_;
350
+ mojo::ReceiverSet<web_platform::mojom::HandwritingRecognizer>
351
+ web_platform_handwriting_receivers_;
352
+ mojo::ReceiverSet<mojom::GrammarChecker> grammar_checker_receivers_;
353
+ mojo::ReceiverSet<mojom::SodaRecognizer> soda_recognizer_receivers_;
354
+ mojo::ReceiverSet<mojom::TextSuggester> text_suggester_receivers_;
355
+ mojo::ReceiverSet<mojom::DocumentScanner> document_scanner_receivers_;
356
+ mojo::RemoteSet<mojom::SodaClient> soda_client_remotes_;
357
+ mojom::TensorPtr output_tensor_;
358
+ mojom::LoadHandwritingModelResult load_handwriting_model_result_;
359
+ mojom::LoadHandwritingModelResult load_web_platform_handwriting_model_result_;
360
+ mojom::LoadModelResult load_model_result_;
361
+ mojom::LoadModelResult load_text_classifier_result_;
362
+ mojom::LoadModelResult load_soda_result_;
363
+ mojom::CreateGraphExecutorResult create_graph_executor_result_;
364
+ mojom::ExecuteResult execute_result_;
365
+ std::vector<mojom::TextAnnotationPtr> annotate_result_;
366
+ mojom::CodepointSpanPtr suggest_selection_result_;
367
+ std::vector<mojom::TextLanguagePtr> find_languages_result_;
368
+ mojom::HandwritingRecognizerResultPtr handwriting_result_;
369
+ std::vector<web_platform::mojom::HandwritingPredictionPtr>
370
+ web_platform_handwriting_result_;
371
+ mojom::GrammarCheckerResultPtr grammar_checker_result_;
372
+ mojom::TextSuggesterResultPtr text_suggester_result_;
373
+ mojom::DetectCornersResultPtr detect_corners_result_;
374
+ mojom::DoPostProcessingResultPtr do_post_processing_result_;
375
+
376
+ bool async_mode_;
377
+ std::vector<base::OnceClosure> pending_calls_;
378
+ };
379
+
380
+ } // namespace machine_learning
381
+ } // namespace chromeos
382
+
383
+ #endif // CHROMEOS_SERVICES_MACHINE_LEARNING_PUBLIC_CPP_FAKE_SERVICE_CONNECTION_H_
19/public/cpp/service_connection.cc ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
6
+
7
+ namespace chromeos {
8
+ namespace machine_learning {
9
+
10
+ namespace {
11
+ static ServiceConnection* g_fake_service_connection_for_testing = nullptr;
12
+ } // namespace
13
+
14
+ ServiceConnection* ServiceConnection::GetInstance() {
15
+ if (g_fake_service_connection_for_testing) {
16
+ return g_fake_service_connection_for_testing;
17
+ }
18
+
19
+ // The real impl lies in service_connection_ash.cc and
20
+ // service_connection_lacros.cc.
21
+ return CreateRealInstance();
22
+ }
23
+
24
+ void ServiceConnection::UseFakeServiceConnectionForTesting(
25
+ ServiceConnection* const fake_service_connection) {
26
+ g_fake_service_connection_for_testing = fake_service_connection;
27
+ }
28
+
29
+ } // namespace machine_learning
30
+ } // namespace chromeos
19/public/cpp/service_connection.h ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #ifndef CHROMEOS_SERVICES_MACHINE_LEARNING_PUBLIC_CPP_SERVICE_CONNECTION_H_
6
+ #define CHROMEOS_SERVICES_MACHINE_LEARNING_PUBLIC_CPP_SERVICE_CONNECTION_H_
7
+
8
+ #include "base/component_export.h"
9
+ #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
10
+ #include "mojo/public/cpp/bindings/pending_receiver.h"
11
+
12
+ namespace chromeos {
13
+ namespace machine_learning {
14
+
15
+ // Encapsulates a connection to the Chrome OS ML Service daemon via its Mojo
16
+ // interface.
17
+ //
18
+ // Usage for BindMachineLearningService:
19
+ // mojo::Remote<mojom::MachineLearningService> ml_service;
20
+ // chromeos::machine_learning::ServiceConnection::GetInstance()
21
+ // ->BindMachineLearningService(
22
+ // ml_service.BindNewPipeAndPassReceiver());
23
+ // // Use ml_service to LoadBuiltinModel(), LoadFlatBufferModel() etc. e.g
24
+ // ml_service->LoadBuiltinModel(...);
25
+ //
26
+ // Usage for GetMachineLearningService:
27
+ // chromeos::machine_learning::ServiceConnection::GetInstance()
28
+ // ->GetMachineLearningService()
29
+ // .LoadBuiltinModel(...);
30
+ //
31
+ // Sequencing: BindMachineLearningService can be called from any sequence, while
32
+ // GetMachineLearningService must be called from the sequence that the instance
33
+ // is created on.
34
+ class COMPONENT_EXPORT(CHROMEOS_MLSERVICE) ServiceConnection {
35
+ public:
36
+ // Gets the ServiceConnection singleton, or a test fake if one has been
37
+ // specified.
38
+ static ServiceConnection* GetInstance();
39
+ // Overrides the result of GetInstance() for use in tests.
40
+ // Does not take ownership of |fake_service_connection|.
41
+ // Note: Caller is responsible for calling Initialize() on
42
+ // `fake_service_connection`.
43
+ static void UseFakeServiceConnectionForTesting(
44
+ ServiceConnection* fake_service_connection);
45
+
46
+ // Gets the primordial top-level machine learning service interface.
47
+ // Must be called from the sequence that the instance is created on.
48
+ virtual mojom::MachineLearningService& GetMachineLearningService() = 0;
49
+
50
+ // Binds the receiver to a Clone of the primordial top-level interface.
51
+ // May be called from any sequence.
52
+ // Note: A mojo::Remote<mojom::MachineLearningService> bound using this method
53
+ // does not control the lifetime of the underlying ML Service daemon. It is
54
+ // safe to release the mojo::Remote<mojom::MachineLearningService> as soon as
55
+ // you are finished called methods on it and processing callbacks. The ML
56
+ // Service daemon (and any other mojo remotes subsequently bound to it) will
57
+ // continue.
58
+ virtual void BindMachineLearningService(
59
+ mojo::PendingReceiver<mojom::MachineLearningService> receiver) = 0;
60
+
61
+ // Call this once at startup (e.g. PostBrowserStart) on the sequence that
62
+ // should own the Mojo connection to MachineLearningService (e.g. UI thread).
63
+ virtual void Initialize() = 0;
64
+
65
+ protected:
66
+ ServiceConnection() = default;
67
+ virtual ~ServiceConnection() {}
68
+
69
+ private:
70
+ // Creates the ServiceConnection singleton.
71
+ static ServiceConnection* CreateRealInstance();
72
+ };
73
+
74
+ } // namespace machine_learning
75
+ } // namespace chromeos
76
+
77
+ #endif // CHROMEOS_SERVICES_MACHINE_LEARNING_PUBLIC_CPP_SERVICE_CONNECTION_H_
19/public/cpp/service_connection_unittest.cc ADDED
@@ -0,0 +1,800 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
6
+
7
+ #include <utility>
8
+ #include <vector>
9
+
10
+ #include "base/bind.h"
11
+ #include "base/memory/read_only_shared_memory_region.h"
12
+ #include "base/message_loop/message_pump_type.h"
13
+ #include "base/run_loop.h"
14
+ #include "base/test/bind.h"
15
+ #include "base/test/task_environment.h"
16
+ #include "base/threading/thread.h"
17
+ #include "chromeos/dbus/machine_learning/machine_learning_client.h"
18
+ #include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
19
+ #include "chromeos/services/machine_learning/public/mojom/graph_executor.mojom.h"
20
+ #include "chromeos/services/machine_learning/public/mojom/handwriting_recognizer.mojom.h"
21
+ #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
22
+ #include "chromeos/services/machine_learning/public/mojom/model.mojom.h"
23
+ #include "chromeos/services/machine_learning/public/mojom/tensor.mojom.h"
24
+ #include "chromeos/services/machine_learning/public/mojom/text_suggester.mojom.h"
25
+ #include "mojo/core/embedder/embedder.h"
26
+ #include "mojo/core/embedder/scoped_ipc_support.h"
27
+ #include "mojo/public/cpp/bindings/remote.h"
28
+ #include "testing/gtest/include/gtest/gtest.h"
29
+
30
+ namespace chromeos {
31
+ namespace machine_learning {
32
+ namespace {
33
+
34
+ class ServiceConnectionTest : public testing::Test {
35
+ public:
36
+ ServiceConnectionTest() = default;
37
+
38
+ ServiceConnectionTest(const ServiceConnectionTest&) = delete;
39
+ ServiceConnectionTest& operator=(const ServiceConnectionTest&) = delete;
40
+
41
+ void SetUp() override { MachineLearningClient::InitializeFake(); }
42
+
43
+ void TearDown() override { MachineLearningClient::Shutdown(); }
44
+
45
+ protected:
46
+ static void SetUpTestCase() {
47
+ task_environment_ = new base::test::TaskEnvironment();
48
+ static base::Thread ipc_thread("ipc");
49
+ ipc_thread.StartWithOptions(
50
+ base::Thread::Options(base::MessagePumpType::IO, 0));
51
+ static mojo::core::ScopedIPCSupport ipc_support(
52
+ ipc_thread.task_runner(),
53
+ mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
54
+ ServiceConnection::GetInstance()->Initialize();
55
+ }
56
+
57
+ static void TearDownTestCase() {
58
+ if (task_environment_) {
59
+ delete task_environment_;
60
+ task_environment_ = nullptr;
61
+ }
62
+ }
63
+
64
+ private:
65
+ static base::test::TaskEnvironment* task_environment_;
66
+ };
67
+
68
+ base::test::TaskEnvironment* ServiceConnectionTest::task_environment_;
69
+
70
+ // Tests that LoadBuiltinModel runs OK (no crash) in a basic Mojo
71
+ // environment.
72
+ TEST_F(ServiceConnectionTest, LoadBuiltinModel) {
73
+ mojo::Remote<mojom::Model> model;
74
+
75
+ mojo::Remote<mojom::MachineLearningService> ml_service;
76
+ ServiceConnection::GetInstance()->BindMachineLearningService(
77
+ ml_service.BindNewPipeAndPassReceiver());
78
+
79
+ ml_service->LoadBuiltinModel(
80
+ mojom::BuiltinModelSpec::New(mojom::BuiltinModelId::TEST_MODEL),
81
+ model.BindNewPipeAndPassReceiver(),
82
+ base::BindOnce([](mojom::LoadModelResult result) {}));
83
+
84
+ // Also tests GetMachineLearningService runs OK.
85
+ model.reset();
86
+ ServiceConnection::GetInstance()
87
+ ->GetMachineLearningService()
88
+ .LoadBuiltinModel(
89
+ mojom::BuiltinModelSpec::New(mojom::BuiltinModelId::TEST_MODEL),
90
+ model.BindNewPipeAndPassReceiver(),
91
+ base::BindOnce([](mojom::LoadModelResult result) {}));
92
+ }
93
+
94
+ // Tests that LoadFlatBufferModel runs OK (no crash) in a basic Mojo
95
+ // environment.
96
+ TEST_F(ServiceConnectionTest, LoadFlatBufferModel) {
97
+ mojo::Remote<mojom::MachineLearningService> ml_service;
98
+ ServiceConnection::GetInstance()->BindMachineLearningService(
99
+ ml_service.BindNewPipeAndPassReceiver());
100
+
101
+ mojo::Remote<mojom::Model> model;
102
+ ml_service->LoadFlatBufferModel(
103
+ mojom::FlatBufferModelSpec::New(), model.BindNewPipeAndPassReceiver(),
104
+ base::BindOnce([](mojom::LoadModelResult result) {}));
105
+
106
+ model.reset();
107
+ ServiceConnection::GetInstance()
108
+ ->GetMachineLearningService()
109
+ .LoadFlatBufferModel(
110
+ mojom::FlatBufferModelSpec::New(), model.BindNewPipeAndPassReceiver(),
111
+ base::BindOnce([](mojom::LoadModelResult result) {}));
112
+ }
113
+
114
+ // Tests that LoadTextClassifier runs OK (no crash) in a basic Mojo
115
+ // environment.
116
+ TEST_F(ServiceConnectionTest, LoadTextClassifier) {
117
+ mojo::Remote<mojom::MachineLearningService> ml_service;
118
+ ServiceConnection::GetInstance()->BindMachineLearningService(
119
+ ml_service.BindNewPipeAndPassReceiver());
120
+
121
+ mojo::Remote<mojom::TextClassifier> text_classifier;
122
+ ml_service->LoadTextClassifier(
123
+ text_classifier.BindNewPipeAndPassReceiver(),
124
+ base::BindOnce([](mojom::LoadModelResult result) {}));
125
+
126
+ text_classifier.reset();
127
+ ServiceConnection::GetInstance()
128
+ ->GetMachineLearningService()
129
+ .LoadTextClassifier(text_classifier.BindNewPipeAndPassReceiver(),
130
+ base::BindOnce([](mojom::LoadModelResult result) {}));
131
+ }
132
+
133
+ // Tests that LoadHandwritingModel runs OK (no crash) in a basic Mojo
134
+ // environment.
135
+ TEST_F(ServiceConnectionTest, LoadHandwritingModel) {
136
+ mojo::Remote<mojom::MachineLearningService> ml_service;
137
+ ServiceConnection::GetInstance()->BindMachineLearningService(
138
+ ml_service.BindNewPipeAndPassReceiver());
139
+
140
+ mojo::Remote<mojom::HandwritingRecognizer> handwriting_recognizer;
141
+ ml_service->LoadHandwritingModel(
142
+ mojom::HandwritingRecognizerSpec::New("en"),
143
+ handwriting_recognizer.BindNewPipeAndPassReceiver(),
144
+ base::BindOnce([](mojom::LoadHandwritingModelResult result) {}));
145
+
146
+ handwriting_recognizer.reset();
147
+ ServiceConnection::GetInstance()
148
+ ->GetMachineLearningService()
149
+ .LoadHandwritingModel(
150
+ mojom::HandwritingRecognizerSpec::New("en"),
151
+ handwriting_recognizer.BindNewPipeAndPassReceiver(),
152
+ base::BindOnce([](mojom::LoadHandwritingModelResult result) {}));
153
+ }
154
+
155
+ // Tests that LoadGrammarChecker runs OK (no crash) in a basic Mojo environment.
156
+ TEST_F(ServiceConnectionTest, LoadGrammarModel) {
157
+ mojo::Remote<mojom::MachineLearningService> ml_service;
158
+ ServiceConnection::GetInstance()->BindMachineLearningService(
159
+ ml_service.BindNewPipeAndPassReceiver());
160
+
161
+ mojo::Remote<mojom::GrammarChecker> grammar_checker;
162
+ ml_service->LoadGrammarChecker(
163
+ grammar_checker.BindNewPipeAndPassReceiver(),
164
+ base::BindOnce([](mojom::LoadModelResult result) {}));
165
+
166
+ grammar_checker.reset();
167
+ ServiceConnection::GetInstance()
168
+ ->GetMachineLearningService()
169
+ .LoadGrammarChecker(grammar_checker.BindNewPipeAndPassReceiver(),
170
+ base::BindOnce([](mojom::LoadModelResult result) {}));
171
+ }
172
+
173
+ // Tests the fake ML service for binding ml_service receiver.
174
+ TEST_F(ServiceConnectionTest, BindMachineLearningService) {
175
+ FakeServiceConnectionImpl fake_service_connection;
176
+ ServiceConnection::UseFakeServiceConnectionForTesting(
177
+ &fake_service_connection);
178
+ ServiceConnection::GetInstance()->Initialize();
179
+
180
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
181
+ mojo::Remote<mojom::MachineLearningService> ml_service;
182
+ base::OnceClosure callback =
183
+ base::BindOnce(&ServiceConnection::BindMachineLearningService,
184
+ base::Unretained(ServiceConnection::GetInstance()),
185
+ ml_service.BindNewPipeAndPassReceiver())
186
+ .Then(run_loop->QuitClosure());
187
+ std::move(callback).Run();
188
+ run_loop->Run();
189
+ ASSERT_TRUE(ml_service.is_bound());
190
+
191
+ // Check the bound ml_service remote can be used to call
192
+ // MachineLearningService methods.
193
+ mojo::Remote<mojom::Model> model;
194
+ bool callback_done = false;
195
+
196
+ run_loop.reset(new base::RunLoop);
197
+ ml_service->LoadBuiltinModel(
198
+ mojom::BuiltinModelSpec::New(mojom::BuiltinModelId::TEST_MODEL),
199
+ model.BindNewPipeAndPassReceiver(),
200
+ base::BindOnce(
201
+ [](bool* callback_done, mojom::LoadModelResult result) {
202
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
203
+ *callback_done = true;
204
+ },
205
+ &callback_done)
206
+ .Then(run_loop->QuitClosure()));
207
+
208
+ run_loop->Run();
209
+ EXPECT_TRUE(callback_done);
210
+ EXPECT_TRUE(model.is_bound());
211
+ }
212
+
213
+ class TestSodaClient : public mojom::SodaClient {
214
+ void OnStop() override {}
215
+ void OnStart() override {}
216
+ void OnSpeechRecognizerEvent(mojom::SpeechRecognizerEventPtr event) override {
217
+ }
218
+ };
219
+
220
+ // Tests that LoadSpeechRecognizer runs OK without a crash in a basic Mojo
221
+ // Environment.
222
+ TEST_F(ServiceConnectionTest, LoadSpeechRecognizerAndCallback) {
223
+ mojo::Remote<mojom::SodaRecognizer> soda_recognizer;
224
+ TestSodaClient test_client;
225
+ FakeServiceConnectionImpl fake_service_connection;
226
+ ServiceConnection::UseFakeServiceConnectionForTesting(
227
+ &fake_service_connection);
228
+ ServiceConnection::GetInstance()->Initialize();
229
+
230
+ mojo::Receiver<mojom::SodaClient> soda_client{&test_client};
231
+ bool callback_done = false;
232
+ auto config = mojom::SodaConfig::New();
233
+ base::RunLoop run_loop;
234
+ ServiceConnection::GetInstance()
235
+ ->GetMachineLearningService()
236
+ .LoadSpeechRecognizer(
237
+ std::move(config), soda_client.BindNewPipeAndPassRemote(),
238
+ soda_recognizer.BindNewPipeAndPassReceiver(),
239
+ base::BindLambdaForTesting([&](mojom::LoadModelResult result) {
240
+ callback_done = true;
241
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
242
+ run_loop.Quit();
243
+ }));
244
+ run_loop.Run();
245
+ ASSERT_TRUE(callback_done);
246
+ }
247
+
248
+ // Tests the fake ML service for builtin model.
249
+ TEST_F(ServiceConnectionTest, FakeServiceConnectionForBuiltinModel) {
250
+ mojo::Remote<mojom::Model> model;
251
+ bool callback_done = false;
252
+ FakeServiceConnectionImpl fake_service_connection;
253
+ ServiceConnection::UseFakeServiceConnectionForTesting(
254
+ &fake_service_connection);
255
+ ServiceConnection::GetInstance()->Initialize();
256
+
257
+ const double expected_value = 200.002;
258
+ fake_service_connection.SetOutputValue(std::vector<int64_t>{1L},
259
+ std::vector<double>{expected_value});
260
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
261
+ ServiceConnection::GetInstance()
262
+ ->GetMachineLearningService()
263
+ .LoadBuiltinModel(
264
+ mojom::BuiltinModelSpec::New(mojom::BuiltinModelId::TEST_MODEL),
265
+ model.BindNewPipeAndPassReceiver(),
266
+ base::BindOnce(
267
+ [](bool* callback_done, mojom::LoadModelResult result) {
268
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
269
+ *callback_done = true;
270
+ },
271
+ &callback_done)
272
+ .Then(run_loop->QuitClosure()));
273
+ run_loop->Run();
274
+ ASSERT_TRUE(callback_done);
275
+ ASSERT_TRUE(model.is_bound());
276
+
277
+ callback_done = false;
278
+ mojo::Remote<mojom::GraphExecutor> graph;
279
+ run_loop.reset(new base::RunLoop);
280
+ model->CreateGraphExecutor(
281
+ mojom::GraphExecutorOptions::New(), graph.BindNewPipeAndPassReceiver(),
282
+ base::BindOnce(
283
+ [](bool* callback_done, mojom::CreateGraphExecutorResult result) {
284
+ EXPECT_EQ(result, mojom::CreateGraphExecutorResult::OK);
285
+ *callback_done = true;
286
+ },
287
+ &callback_done)
288
+ .Then(run_loop->QuitClosure()));
289
+ run_loop->Run();
290
+ ASSERT_TRUE(callback_done);
291
+ ASSERT_TRUE(graph.is_bound());
292
+
293
+ callback_done = false;
294
+ base::flat_map<std::string, mojom::TensorPtr> inputs;
295
+ std::vector<std::string> outputs;
296
+ run_loop.reset(new base::RunLoop);
297
+ graph->Execute(std::move(inputs), std::move(outputs),
298
+ base::BindOnce(
299
+ [](bool* callback_done, double expected_value,
300
+ const mojom::ExecuteResult result,
301
+ absl::optional<std::vector<mojom::TensorPtr>> outputs) {
302
+ EXPECT_EQ(result, mojom::ExecuteResult::OK);
303
+ ASSERT_TRUE(outputs.has_value());
304
+ ASSERT_EQ(outputs->size(), 1LU);
305
+ mojom::TensorPtr& tensor = (*outputs)[0];
306
+ EXPECT_EQ(tensor->data->get_float_list()->value[0],
307
+ expected_value);
308
+
309
+ *callback_done = true;
310
+ },
311
+ &callback_done, expected_value)
312
+ .Then(run_loop->QuitClosure()));
313
+
314
+ run_loop->Run();
315
+ ASSERT_TRUE(callback_done);
316
+ }
317
+
318
+ // Tests the fake ML service for flatbuffer model.
319
+ TEST_F(ServiceConnectionTest, FakeServiceConnectionForFlatBufferModel) {
320
+ mojo::Remote<mojom::Model> model;
321
+ bool callback_done = false;
322
+ FakeServiceConnectionImpl fake_service_connection;
323
+ ServiceConnection::UseFakeServiceConnectionForTesting(
324
+ &fake_service_connection);
325
+ ServiceConnection::GetInstance()->Initialize();
326
+
327
+ const double expected_value = 200.002;
328
+ fake_service_connection.SetOutputValue(std::vector<int64_t>{1L},
329
+ std::vector<double>{expected_value});
330
+
331
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
332
+ ServiceConnection::GetInstance()
333
+ ->GetMachineLearningService()
334
+ .LoadFlatBufferModel(
335
+ mojom::FlatBufferModelSpec::New(), model.BindNewPipeAndPassReceiver(),
336
+ base::BindOnce(
337
+ [](bool* callback_done, mojom::LoadModelResult result) {
338
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
339
+ *callback_done = true;
340
+ },
341
+ &callback_done)
342
+ .Then(run_loop->QuitClosure()));
343
+ run_loop->Run();
344
+ ASSERT_TRUE(callback_done);
345
+ ASSERT_TRUE(model.is_bound());
346
+
347
+ callback_done = false;
348
+ mojo::Remote<mojom::GraphExecutor> graph;
349
+ run_loop.reset(new base::RunLoop);
350
+ model->CreateGraphExecutor(
351
+ mojom::GraphExecutorOptions::New(), graph.BindNewPipeAndPassReceiver(),
352
+ base::BindOnce(
353
+ [](bool* callback_done, mojom::CreateGraphExecutorResult result) {
354
+ EXPECT_EQ(result, mojom::CreateGraphExecutorResult::OK);
355
+ *callback_done = true;
356
+ },
357
+ &callback_done)
358
+ .Then(run_loop->QuitClosure()));
359
+ run_loop->Run();
360
+ ASSERT_TRUE(callback_done);
361
+ ASSERT_TRUE(graph.is_bound());
362
+
363
+ callback_done = false;
364
+ base::flat_map<std::string, mojom::TensorPtr> inputs;
365
+ std::vector<std::string> outputs;
366
+ run_loop.reset(new base::RunLoop);
367
+ graph->Execute(std::move(inputs), std::move(outputs),
368
+ base::BindOnce(
369
+ [](bool* callback_done, double expected_value,
370
+ const mojom::ExecuteResult result,
371
+ absl::optional<std::vector<mojom::TensorPtr>> outputs) {
372
+ EXPECT_EQ(result, mojom::ExecuteResult::OK);
373
+ ASSERT_TRUE(outputs.has_value());
374
+ ASSERT_EQ(outputs->size(), 1LU);
375
+ mojom::TensorPtr& tensor = (*outputs)[0];
376
+ EXPECT_EQ(tensor->data->get_float_list()->value[0],
377
+ expected_value);
378
+
379
+ *callback_done = true;
380
+ },
381
+ &callback_done, expected_value)
382
+ .Then(run_loop->QuitClosure()));
383
+ run_loop->Run();
384
+ ASSERT_TRUE(callback_done);
385
+ }
386
+
387
+ // Tests the fake ML service for text classifier annotation.
388
+ TEST_F(ServiceConnectionTest,
389
+ FakeServiceConnectionForTextClassifierAnnotation) {
390
+ mojo::Remote<mojom::TextClassifier> text_classifier;
391
+ bool callback_done = false;
392
+ FakeServiceConnectionImpl fake_service_connection;
393
+ ServiceConnection::UseFakeServiceConnectionForTesting(
394
+ &fake_service_connection);
395
+ ServiceConnection::GetInstance()->Initialize();
396
+
397
+ auto dummy_data = mojom::TextEntityData::New();
398
+ dummy_data->set_numeric_value(123456789.);
399
+ std::vector<mojom::TextEntityPtr> entities;
400
+ entities.emplace_back(
401
+ mojom::TextEntity::New("dummy", // Entity name.
402
+ 1.0, // Confidence score.
403
+ std::move(dummy_data))); // Data extracted.
404
+ auto dummy_annotation = mojom::TextAnnotation::New(123, // Start offset.
405
+ 321, // End offset.
406
+ std::move(entities));
407
+ std::vector<mojom::TextAnnotationPtr> annotations;
408
+ annotations.emplace_back(std::move(dummy_annotation));
409
+ fake_service_connection.SetOutputAnnotation(annotations);
410
+
411
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
412
+ ServiceConnection::GetInstance()
413
+ ->GetMachineLearningService()
414
+ .LoadTextClassifier(
415
+ text_classifier.BindNewPipeAndPassReceiver(),
416
+ base::BindOnce(
417
+ [](bool* callback_done, mojom::LoadModelResult result) {
418
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
419
+ *callback_done = true;
420
+ },
421
+ &callback_done)
422
+ .Then(run_loop->QuitClosure()));
423
+ run_loop->Run();
424
+ ASSERT_TRUE(callback_done);
425
+ ASSERT_TRUE(text_classifier.is_bound());
426
+
427
+ auto request = mojom::TextAnnotationRequest::New();
428
+ bool infer_callback_done = false;
429
+ run_loop.reset(new base::RunLoop);
430
+ text_classifier->Annotate(
431
+ std::move(request),
432
+ base::BindOnce(
433
+ [](bool* infer_callback_done,
434
+ std::vector<mojom::TextAnnotationPtr> annotations) {
435
+ *infer_callback_done = true;
436
+ // Check if the annotation is correct.
437
+ EXPECT_EQ(annotations[0]->start_offset, 123u);
438
+ EXPECT_EQ(annotations[0]->end_offset, 321u);
439
+ EXPECT_EQ(annotations[0]->entities[0]->name, "dummy");
440
+ EXPECT_EQ(annotations[0]->entities[0]->confidence_score, 1.0);
441
+ EXPECT_EQ(annotations[0]->entities[0]->data->get_numeric_value(),
442
+ 123456789.);
443
+ },
444
+ &infer_callback_done)
445
+ .Then(run_loop->QuitClosure()));
446
+ run_loop->Run();
447
+ ASSERT_TRUE(infer_callback_done);
448
+ }
449
+
450
+ // Tests the fake ML service for text classifier language identification.
451
+ TEST_F(ServiceConnectionTest,
452
+ FakeServiceConnectionForTextClassifierFindLanguages) {
453
+ mojo::Remote<mojom::TextClassifier> text_classifier;
454
+ bool callback_done = false;
455
+ FakeServiceConnectionImpl fake_service_connection;
456
+ ServiceConnection::UseFakeServiceConnectionForTesting(
457
+ &fake_service_connection);
458
+ ServiceConnection::GetInstance()->Initialize();
459
+
460
+ std::vector<mojom::TextLanguagePtr> languages;
461
+ languages.emplace_back(mojom::TextLanguage::New("en", 0.9));
462
+ languages.emplace_back(mojom::TextLanguage::New("fr", 0.1));
463
+ fake_service_connection.SetOutputLanguages(languages);
464
+
465
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
466
+ ServiceConnection::GetInstance()
467
+ ->GetMachineLearningService()
468
+ .LoadTextClassifier(
469
+ text_classifier.BindNewPipeAndPassReceiver(),
470
+ base::BindOnce(
471
+ [](bool* callback_done, mojom::LoadModelResult result) {
472
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
473
+ *callback_done = true;
474
+ },
475
+ &callback_done)
476
+ .Then(run_loop->QuitClosure()));
477
+ run_loop->Run();
478
+ ASSERT_TRUE(callback_done);
479
+ ASSERT_TRUE(text_classifier.is_bound());
480
+
481
+ std::string input_text = "dummy input text";
482
+ bool infer_callback_done = false;
483
+ run_loop.reset(new base::RunLoop);
484
+ text_classifier->FindLanguages(
485
+ input_text, base::BindOnce(
486
+ [](bool* infer_callback_done,
487
+ std::vector<mojom::TextLanguagePtr> languages) {
488
+ *infer_callback_done = true;
489
+ // Check if the suggestion is correct.
490
+ ASSERT_EQ(languages.size(), 2ul);
491
+ EXPECT_EQ(languages[0]->locale, "en");
492
+ EXPECT_EQ(languages[0]->confidence, 0.9f);
493
+ EXPECT_EQ(languages[1]->locale, "fr");
494
+ EXPECT_EQ(languages[1]->confidence, 0.1f);
495
+ },
496
+ &infer_callback_done)
497
+ .Then(run_loop->QuitClosure()));
498
+ run_loop->Run();
499
+ ASSERT_TRUE(infer_callback_done);
500
+ }
501
+
502
+ // Tests the fake ML service for handwriting.
503
+ TEST_F(ServiceConnectionTest, FakeHandWritingRecognizer) {
504
+ mojo::Remote<mojom::HandwritingRecognizer> recognizer;
505
+ bool callback_done = false;
506
+ FakeServiceConnectionImpl fake_service_connection;
507
+ ServiceConnection::UseFakeServiceConnectionForTesting(
508
+ &fake_service_connection);
509
+ ServiceConnection::GetInstance()->Initialize();
510
+
511
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
512
+ ServiceConnection::GetInstance()
513
+ ->GetMachineLearningService()
514
+ .LoadHandwritingModel(
515
+ mojom::HandwritingRecognizerSpec::New("en"),
516
+ recognizer.BindNewPipeAndPassReceiver(),
517
+ base::BindOnce(
518
+ [](bool* callback_done,
519
+ mojom::LoadHandwritingModelResult result) {
520
+ EXPECT_EQ(result, mojom::LoadHandwritingModelResult::OK);
521
+ *callback_done = true;
522
+ },
523
+ &callback_done)
524
+ .Then(run_loop->QuitClosure()));
525
+ run_loop->Run();
526
+ ASSERT_TRUE(callback_done);
527
+ ASSERT_TRUE(recognizer.is_bound());
528
+
529
+ // Construct fake output.
530
+ mojom::HandwritingRecognizerResultPtr result =
531
+ mojom::HandwritingRecognizerResult::New();
532
+ result->status = mojom::HandwritingRecognizerResult::Status::OK;
533
+ mojom::HandwritingRecognizerCandidatePtr candidate =
534
+ mojom::HandwritingRecognizerCandidate::New();
535
+ candidate->text = "cat";
536
+ candidate->score = 0.5f;
537
+ result->candidates.emplace_back(std::move(candidate));
538
+ fake_service_connection.SetOutputHandwritingRecognizerResult(result);
539
+
540
+ auto query = mojom::HandwritingRecognitionQuery::New();
541
+ bool infer_callback_done = false;
542
+ run_loop.reset(new base::RunLoop);
543
+ recognizer->Recognize(
544
+ std::move(query),
545
+ base::BindOnce(
546
+ [](bool* infer_callback_done,
547
+ mojom::HandwritingRecognizerResultPtr result) {
548
+ *infer_callback_done = true;
549
+ // Check if the annotation is correct.
550
+ ASSERT_EQ(result->status,
551
+ mojom::HandwritingRecognizerResult::Status::OK);
552
+ EXPECT_EQ(result->candidates.at(0)->text, "cat");
553
+ EXPECT_EQ(result->candidates.at(0)->score, 0.5f);
554
+ },
555
+ &infer_callback_done)
556
+ .Then(run_loop->QuitClosure()));
557
+ run_loop->Run();
558
+ ASSERT_TRUE(infer_callback_done);
559
+ }
560
+
561
+ // Tests the fake ML service for web platform handwriting recognizer.
562
+ TEST_F(ServiceConnectionTest, FakeWebPlatformHandWritingRecognizer) {
563
+ mojo::Remote<web_platform::mojom::HandwritingRecognizer> recognizer;
564
+ bool callback_done = false;
565
+ FakeServiceConnectionImpl fake_service_connection;
566
+ ServiceConnection::UseFakeServiceConnectionForTesting(
567
+ &fake_service_connection);
568
+ ServiceConnection::GetInstance()->Initialize();
569
+ auto constraint = web_platform::mojom::HandwritingModelConstraint::New();
570
+ constraint->languages.emplace_back("en");
571
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
572
+ ServiceConnection::GetInstance()
573
+ ->GetMachineLearningService()
574
+ .LoadWebPlatformHandwritingModel(
575
+ std::move(constraint), recognizer.BindNewPipeAndPassReceiver(),
576
+ base::BindOnce(
577
+ [](bool* callback_done,
578
+ mojom::LoadHandwritingModelResult result) {
579
+ EXPECT_EQ(result, mojom::LoadHandwritingModelResult::OK);
580
+ *callback_done = true;
581
+ },
582
+ &callback_done)
583
+ .Then(run_loop->QuitClosure()));
584
+ run_loop->Run();
585
+ ASSERT_TRUE(callback_done);
586
+ ASSERT_TRUE(recognizer.is_bound());
587
+
588
+ // Construct fake output.
589
+ std::vector<web_platform::mojom::HandwritingPredictionPtr> predictions;
590
+ auto prediction1 = web_platform::mojom::HandwritingPrediction::New();
591
+ prediction1->text = "recognition1";
592
+ predictions.emplace_back(std::move(prediction1));
593
+ fake_service_connection.SetOutputWebPlatformHandwritingRecognizerResult(
594
+ predictions);
595
+
596
+ std::vector<web_platform::mojom::HandwritingStrokePtr> strokes;
597
+ auto hints = web_platform::mojom::HandwritingHints::New();
598
+ bool infer_callback_done = false;
599
+ run_loop.reset(new base::RunLoop);
600
+ recognizer->GetPrediction(
601
+ std::move(strokes), std::move(hints),
602
+ base::BindOnce(
603
+ [](bool* infer_callback_done,
604
+ absl::optional<std::vector<
605
+ web_platform::mojom::HandwritingPredictionPtr>> predictions) {
606
+ *infer_callback_done = true;
607
+ ASSERT_TRUE(predictions.has_value());
608
+ ASSERT_EQ(predictions.value().size(), 1u);
609
+ },
610
+ &infer_callback_done)
611
+ .Then(run_loop->QuitClosure()));
612
+ run_loop->Run();
613
+ ASSERT_TRUE(infer_callback_done);
614
+ }
615
+
616
+ TEST_F(ServiceConnectionTest, FakeGrammarChecker) {
617
+ mojo::Remote<mojom::GrammarChecker> checker;
618
+ bool callback_done = false;
619
+ FakeServiceConnectionImpl fake_service_connection;
620
+ ServiceConnection::UseFakeServiceConnectionForTesting(
621
+ &fake_service_connection);
622
+ ServiceConnection::GetInstance()->Initialize();
623
+
624
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
625
+ ServiceConnection::GetInstance()
626
+ ->GetMachineLearningService()
627
+ .LoadGrammarChecker(
628
+ checker.BindNewPipeAndPassReceiver(),
629
+ base::BindOnce(
630
+ [](bool* callback_done, mojom::LoadModelResult result) {
631
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
632
+ *callback_done = true;
633
+ },
634
+ &callback_done)
635
+ .Then(run_loop->QuitClosure()));
636
+ run_loop->Run();
637
+ ASSERT_TRUE(callback_done);
638
+ ASSERT_TRUE(checker.is_bound());
639
+
640
+ // Construct fake output
641
+ mojom::GrammarCheckerResultPtr result = mojom::GrammarCheckerResult::New();
642
+ result->status = mojom::GrammarCheckerResult::Status::OK;
643
+ mojom::GrammarCheckerCandidatePtr candidate =
644
+ mojom::GrammarCheckerCandidate::New();
645
+ candidate->text = "cat";
646
+ candidate->score = 0.5f;
647
+ mojom::GrammarCorrectionFragmentPtr fragment =
648
+ mojom::GrammarCorrectionFragment::New();
649
+ fragment->offset = 3;
650
+ fragment->length = 5;
651
+ fragment->replacement = "dog";
652
+ candidate->fragments.emplace_back(std::move(fragment));
653
+ result->candidates.emplace_back(std::move(candidate));
654
+ fake_service_connection.SetOutputGrammarCheckerResult(result);
655
+
656
+ auto query = mojom::GrammarCheckerQuery::New();
657
+ bool infer_callback_done = false;
658
+ run_loop.reset(new base::RunLoop);
659
+ checker->Check(
660
+ std::move(query),
661
+ base::BindOnce(
662
+ [](bool* infer_callback_done, mojom::GrammarCheckerResultPtr result) {
663
+ *infer_callback_done = true;
664
+ // Check if the annotation is correct.
665
+ ASSERT_EQ(result->status, mojom::GrammarCheckerResult::Status::OK);
666
+ ASSERT_EQ(result->candidates.size(), 1UL);
667
+ EXPECT_EQ(result->candidates.at(0)->text, "cat");
668
+ EXPECT_EQ(result->candidates.at(0)->score, 0.5f);
669
+
670
+ ASSERT_EQ(result->candidates.at(0)->fragments.size(), 1UL);
671
+ EXPECT_EQ(result->candidates.at(0)->fragments.at(0)->offset, 3U);
672
+ EXPECT_EQ(result->candidates.at(0)->fragments.at(0)->length, 5U);
673
+ EXPECT_EQ(result->candidates.at(0)->fragments.at(0)->replacement,
674
+ "dog");
675
+ },
676
+ &infer_callback_done)
677
+ .Then(run_loop->QuitClosure()));
678
+ run_loop->Run();
679
+ ASSERT_TRUE(infer_callback_done);
680
+ }
681
+
682
+ TEST_F(ServiceConnectionTest, FakeTextSuggester) {
683
+ mojo::Remote<mojom::TextSuggester> suggester;
684
+ bool callback_done = false;
685
+ FakeServiceConnectionImpl fake_service_connection;
686
+ ServiceConnection::UseFakeServiceConnectionForTesting(
687
+ &fake_service_connection);
688
+ ServiceConnection::GetInstance()->Initialize();
689
+
690
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
691
+ ServiceConnection::GetInstance()
692
+ ->GetMachineLearningService()
693
+ .LoadTextSuggester(
694
+ suggester.BindNewPipeAndPassReceiver(),
695
+ mojom::TextSuggesterSpec::New(),
696
+ base::BindOnce(
697
+ [](bool* callback_done, mojom::LoadModelResult result) {
698
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
699
+ *callback_done = true;
700
+ },
701
+ &callback_done)
702
+ .Then(run_loop->QuitClosure()));
703
+ run_loop->Run();
704
+ ASSERT_TRUE(callback_done);
705
+ ASSERT_TRUE(suggester.is_bound());
706
+
707
+ // Construct fake output
708
+ mojom::TextSuggesterResultPtr result = mojom::TextSuggesterResult::New();
709
+ result->status = mojom::TextSuggesterResult::Status::OK;
710
+
711
+ mojom::MultiWordSuggestionCandidatePtr multi_word =
712
+ mojom::MultiWordSuggestionCandidate::New();
713
+ multi_word->text = "hello";
714
+ multi_word->normalized_score = 0.5f;
715
+ mojom::TextSuggestionCandidatePtr candidate =
716
+ mojom::TextSuggestionCandidate::New();
717
+ candidate->set_multi_word(std::move(multi_word));
718
+
719
+ result->candidates.emplace_back(std::move(candidate));
720
+ fake_service_connection.SetOutputTextSuggesterResult(result);
721
+
722
+ auto query = mojom::TextSuggesterQuery::New();
723
+ bool infer_callback_done = false;
724
+ run_loop.reset(new base::RunLoop);
725
+ suggester->Suggest(
726
+ std::move(query),
727
+ base::BindOnce(
728
+ [](bool* infer_callback_done, mojom::TextSuggesterResultPtr result) {
729
+ *infer_callback_done = true;
730
+ // Check the fake suggestion is returned
731
+ ASSERT_EQ(result->status, mojom::TextSuggesterResult::Status::OK);
732
+ ASSERT_EQ(result->candidates.size(), 1UL);
733
+ ASSERT_TRUE(result->candidates.at(0)->is_multi_word());
734
+ EXPECT_EQ(result->candidates.at(0)->get_multi_word()->text,
735
+ "hello");
736
+ EXPECT_EQ(
737
+ result->candidates.at(0)->get_multi_word()->normalized_score,
738
+ 0.5f);
739
+ },
740
+ &infer_callback_done)
741
+ .Then(run_loop->QuitClosure()));
742
+ run_loop->Run();
743
+ ASSERT_TRUE(infer_callback_done);
744
+ }
745
+
746
+ // Tests the fake ML service for document scanner.
747
+ TEST_F(ServiceConnectionTest, FakeDocumentScanner) {
748
+ mojo::Remote<mojom::DocumentScanner> scanner;
749
+ bool callback_done = false;
750
+ FakeServiceConnectionImpl fake_service_connection;
751
+ ServiceConnection::UseFakeServiceConnectionForTesting(
752
+ &fake_service_connection);
753
+ ServiceConnection::GetInstance()->Initialize();
754
+
755
+ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
756
+ ServiceConnection::GetInstance()
757
+ ->GetMachineLearningService()
758
+ .LoadDocumentScanner(
759
+ scanner.BindNewPipeAndPassReceiver(),
760
+ base::BindOnce(
761
+ [](bool* callback_done, mojom::LoadModelResult result) {
762
+ EXPECT_EQ(result, mojom::LoadModelResult::OK);
763
+ *callback_done = true;
764
+ },
765
+ &callback_done)
766
+ .Then(run_loop->QuitClosure()));
767
+ run_loop->Run();
768
+ ASSERT_TRUE(callback_done);
769
+ ASSERT_TRUE(scanner.is_bound());
770
+
771
+ constexpr int kNv12ImageSize = 256 * 256;
772
+ std::vector<uint8_t> fake_nv12_data(kNv12ImageSize, 0);
773
+ base::MappedReadOnlyRegion memory =
774
+ base::ReadOnlySharedMemoryRegion::Create(fake_nv12_data.size());
775
+ memcpy(memory.mapping.memory(), fake_nv12_data.data(), fake_nv12_data.size());
776
+
777
+ mojom::DetectCornersResultPtr result = mojom::DetectCornersResult::New();
778
+ result->status = mojom::DocumentScannerResultStatus::OK;
779
+ result->corners = {};
780
+ fake_service_connection.SetOutputDetectCornersResult(std::move(result));
781
+
782
+ bool infer_callback_done = false;
783
+ run_loop.reset(new base::RunLoop);
784
+ scanner->DetectCornersFromNV12Image(
785
+ std::move(memory.region),
786
+ base::BindOnce(
787
+ [](bool* infer_callback_done, mojom::DetectCornersResultPtr result) {
788
+ *infer_callback_done = true;
789
+ ASSERT_EQ(result->status, mojom::DocumentScannerResultStatus::OK);
790
+ ASSERT_TRUE(result->corners.size() == 0);
791
+ },
792
+ &infer_callback_done)
793
+ .Then(run_loop->QuitClosure()));
794
+ run_loop->Run();
795
+ ASSERT_TRUE(infer_callback_done);
796
+ }
797
+
798
+ } // namespace
799
+ } // namespace machine_learning
800
+ } // namespace chromeos
19/public/mojom/BUILD.gn ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2018 The Chromium Authors. All rights reserved.
2
+ # Use of this source code is governed by a BSD-style license that can be
3
+ # found in the LICENSE file.
4
+
5
+ import("//mojo/public/tools/bindings/mojom.gni")
6
+
7
+ mojom_component("mojom") {
8
+ sources = [
9
+ "document_scanner.mojom",
10
+ "grammar_checker.mojom",
11
+ "graph_executor.mojom",
12
+ "handwriting_recognizer.mojom",
13
+ "machine_learning_service.mojom",
14
+ "model.mojom",
15
+ "soda.mojom",
16
+ "tensor.mojom",
17
+ "text_classifier.mojom",
18
+ "text_suggester.mojom",
19
+ "web_platform_handwriting.mojom",
20
+ ]
21
+
22
+ public_deps = [
23
+ ":document_scanner_param_types",
24
+ "//mojo/public/mojom/base",
25
+ ]
26
+
27
+ deps = [ "//ui/gfx/geometry/mojom" ]
28
+
29
+ output_prefix = "mlservice_mojom"
30
+ macro_prefix = "MLSERVICE_MOJOM"
31
+ }
32
+
33
+ mojom("document_scanner_param_types") {
34
+ sources = [ "document_scanner_param_types.mojom" ]
35
+ webui_module_path = "/chromeos/services/machine_learning/public/mojom"
36
+ }
19/public/mojom/OWNERS ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ per-file *.mojom=set noparent
2
+ per-file *.mojom=file://ipc/SECURITY_OWNERS
19/public/mojom/document_scanner.mojom ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Next MinVersion: 2
6
+
7
+ // Datatypes and interfaces of document scanner API.
8
+
9
+ // NOTE: This mojom exists in two places and must be kept in sync:
10
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
11
+ // Chrome OS: src/platform2/ml/mojom/
12
+ // Note: Other repos downstream of Chromium might also use this mojom.
13
+ // Example: A backwards-compatible mojom change (and corresponding
14
+ // implementation change) can be made in Chrome OS first, then replicated to the
15
+ // clients (Chromium, other downstream repos) later.
16
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
17
+ // replicate Chrome OS-side changes over to Chromium.
18
+
19
+ module chromeos.machine_learning.mojom;
20
+
21
+ import "chromeos/services/machine_learning/public/mojom/document_scanner_param_types.mojom";
22
+ import "ui/gfx/geometry/mojom/geometry.mojom";
23
+ import "mojo/public/mojom/base/shared_memory.mojom";
24
+
25
+ // Status of the document scanner response.
26
+ [Stable, Extensible]
27
+ enum DocumentScannerResultStatus {
28
+ OK = 0,
29
+ ERROR = 1,
30
+ };
31
+
32
+ // The corner detection response.
33
+ // Next min field ID: 2
34
+ [Stable]
35
+ struct DetectCornersResult {
36
+ // Status of the result. Even when there is no corners detected, the detection
37
+ // can still be considered successful if there is no error occurs.
38
+ DocumentScannerResultStatus status@0;
39
+
40
+ // Detected document corners.
41
+ array<gfx.mojom.PointF> corners@1;
42
+ };
43
+
44
+ // The post processing response.
45
+ // Next min field ID: 2
46
+ [Stable]
47
+ struct DoPostProcessingResult {
48
+ // Status of the result.
49
+ DocumentScannerResultStatus status@0;
50
+
51
+ // Image data after processing. Will be in JPG format.
52
+ array<uint8> processed_jpeg_image@1;
53
+ };
54
+
55
+ // The mojom interface for performing document scanning.
56
+ // Next ordinal: 3
57
+ [Stable]
58
+ interface DocumentScanner {
59
+ // Detect document corners for given `nv12_image` which is in 256x256 size.
60
+ DetectCornersFromNV12Image@0(
61
+ mojo_base.mojom.ReadOnlySharedMemoryRegion nv12_image)
62
+ => (DetectCornersResult result);
63
+
64
+ // Detect document corners for given `jpeg_image`.
65
+ DetectCornersFromJPEGImage@1(
66
+ mojo_base.mojom.ReadOnlySharedMemoryRegion jpeg_image)
67
+ => (DetectCornersResult result);
68
+
69
+ // Do post processing such as rectification for the document region, contrast
70
+ // enhancement on the given `jpeg_image` according to document `corners`,
71
+ // clockwise rotation in `rotation` degrees.
72
+ DoPostProcessing@2(mojo_base.mojom.ReadOnlySharedMemoryRegion jpeg_image,
73
+ array<gfx.mojom.PointF> corners,
74
+ [MinVersion=1] Rotation rotation)
75
+ => (DoPostProcessingResult result);
76
+ };
19/public/mojom/document_scanner_param_types.mojom ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Common datatypes shared between document scanner API and camera app.
6
+
7
+ // NOTE: This mojom exists in two places and must be kept in sync:
8
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
9
+ // Chrome OS: src/platform2/ml/mojom/
10
+ // Note: Other repos downstream of Chromium might also use this mojom.
11
+ // Example: A backwards-compatible mojom change (and corresponding
12
+ // implementation change) can be made in Chrome OS first, then replicated to the
13
+ // clients (Chromium, other downstream repos) later.
14
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
15
+ // replicate Chrome OS-side changes over to Chromium.
16
+
17
+ module chromeos.machine_learning.mojom;
18
+
19
+ // Image rotation in clockwise direction.
20
+ [Stable, Extensible]
21
+ enum Rotation {
22
+ // 0 degree rotation (no rotation).
23
+ ROTATION_0 = 0,
24
+ // 90 degree rotation.
25
+ ROTATION_90 = 1,
26
+ // 180 degree rotation.
27
+ ROTATION_180 = 2,
28
+ // 270 degree rotation.
29
+ ROTATION_270 = 3,
30
+ };
19/public/mojom/grammar_checker.mojom ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2020 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Datatypes and interfaces of grammar checker API.
6
+
7
+ // NOTE: This mojom exists in two places and must be kept in sync:
8
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
9
+ // Chrome OS: src/platform2/ml/mojom/
10
+ // Note: Other repos downstream of Chromium might also use this mojom.
11
+ // Example: A backwards-compatible mojom change (and corresponding
12
+ // implementation change) can be made in Chrome OS first, then replicated to the
13
+ // clients (Chromium, other downstream repos) later.
14
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
15
+ // replicate Chrome OS-side changes over to Chromium.
16
+
17
+ module chromeos.machine_learning.mojom;
18
+
19
+ // Defines a grammar check query.
20
+ [Stable]
21
+ struct GrammarCheckerQuery {
22
+ // Required: Text to be checked. This is expected to be a full sentence.
23
+ string text;
24
+
25
+ // Required: Language of the text to be checked, in BCP-47 format.
26
+ string language;
27
+ };
28
+
29
+ // A span with suggested corrections.
30
+ [Stable]
31
+ struct GrammarCorrectionFragment {
32
+ // The start offset in the original text.
33
+ uint32 offset;
34
+
35
+ // The length of the fragment in the original text.
36
+ uint32 length;
37
+
38
+ // The replacement string.
39
+ string replacement;
40
+ };
41
+
42
+ // One possible candidate returned from the grammar checker model.
43
+ [Stable]
44
+ struct GrammarCheckerCandidate {
45
+ // Corrected text.
46
+ string text;
47
+
48
+ // Score of the text. Log of conditional probability.
49
+ float score;
50
+
51
+ // The list of individual corrections.
52
+ array<GrammarCorrectionFragment> fragments;
53
+ };
54
+
55
+ // The grammar check response.
56
+ [Stable]
57
+ struct GrammarCheckerResult {
58
+ // Status of the response.
59
+ [Stable, Extensible]
60
+ enum Status {
61
+ // Grammar check succeeded.
62
+ OK = 0,
63
+ // Grammar check failed. In this case, candidates will be empty.
64
+ ERROR = 1,
65
+ };
66
+ Status status;
67
+
68
+ // Candidates of corrected text and their scores, sorted by higher score
69
+ // first.
70
+ array<GrammarCheckerCandidate> candidates;
71
+ };
72
+
73
+ // The mojom interface for performing the grammar check.
74
+ // Next ordinal: 1
75
+ [Stable]
76
+ interface GrammarChecker {
77
+ // Performs grammar check on a piece of text, and returns a set of
78
+ // candidates of corrected text and their scores.
79
+ Check@0(GrammarCheckerQuery query) => (GrammarCheckerResult result);
80
+ };
19/public/mojom/graph_executor.mojom ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // NOTE: This mojom exists in two places and must be kept in sync:
6
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
7
+ // Chrome OS: src/platform2/ml/mojom/
8
+ // Note: Other repos downstream of Chromium might also use this mojom.
9
+ // Example: A backwards-compatible mojom change (and corresponding
10
+ // implementation change) can be made in Chrome OS first, then replicated to the
11
+ // clients (Chromium, other downstream repos) later.
12
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
13
+ // replicate Chrome OS-side changes over to Chromium.
14
+
15
+ module chromeos.machine_learning.mojom;
16
+
17
+ // NOTE: The base directory for 'import' statements is expected to differ
18
+ // between Chromium and Chrome OS versions of this file.
19
+ import "chromeos/services/machine_learning/public/mojom/tensor.mojom";
20
+
21
+ // These values are persisted to logs. Entries should not be renumbered and
22
+ // numeric values should never be reused.
23
+ [Stable, Extensible]
24
+ enum ExecuteResult {
25
+ OK = 0,
26
+ INPUT_MISSING_ERROR = 1,
27
+ UNKNOWN_INPUT_ERROR = 2,
28
+ INPUT_TYPE_ERROR = 3,
29
+ INPUT_SHAPE_ERROR = 4,
30
+ INPUT_FORMAT_ERROR = 5,
31
+ OUTPUT_MISSING_ERROR = 6,
32
+ UNKNOWN_OUTPUT_ERROR = 7,
33
+ DUPLICATE_OUTPUT_ERROR = 8,
34
+ EXECUTION_ERROR = 9,
35
+ };
36
+
37
+ // API for performing inference on a TensorFlow graph. A given graph can be
38
+ // executed multiple times with a single instance of GraphExecutor.
39
+ // Next ordinal: 1
40
+ [Stable]
41
+ interface GraphExecutor {
42
+ // Initializes input node values as specified in `inputs`, then executes the
43
+ // graph. The returned `outputs` are the values for the nodes specified in
44
+ // `output_names`.
45
+ Execute@0(map<string, Tensor> inputs, array<string> output_names)
46
+ => (ExecuteResult result, array<Tensor>? outputs);
47
+ };
19/public/mojom/handwriting_recognizer.mojom ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2020 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Next MinVersion: 2
6
+
7
+ // Datatypes and interfaces of handwriting recognition API.
8
+
9
+ // NOTE: This mojom exists in two places and must be kept in sync:
10
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
11
+ // Chrome OS: src/platform2/ml/mojom/
12
+ // Note: Other repos downstream of Chromium might also use this mojom.
13
+ // Example: A backwards-compatible mojom change (and corresponding
14
+ // implementation change) can be made in Chrome OS first, then replicated to the
15
+ // clients (Chromium, other downstream repos) later.
16
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
17
+ // replicate Chrome OS-side changes over to Chromium.
18
+
19
+ module chromeos.machine_learning.mojom;
20
+
21
+ import "mojo/public/mojom/base/time.mojom";
22
+
23
+ // A single point in an ink stroke.
24
+ [Stable]
25
+ struct InkPoint {
26
+ // (x, y) coordinates of the point. The upper-left corner of the writing area
27
+ // is (0, 0). The positive x-axis points to the right. The positive y-axis
28
+ // points down.
29
+ float x;
30
+ float y;
31
+ // Optional TimeDelta from the point was captured relative to the beginning of
32
+ // the ink. So first point of a request should have t=0.
33
+ mojo_base.mojom.TimeDelta? t;
34
+ };
35
+
36
+ // A single ink stroke.
37
+ [Stable]
38
+ struct InkStroke {
39
+ // The set of points representing the stroke.
40
+ array<InkPoint> points;
41
+ };
42
+
43
+ // The writing guide shown to the user during input.
44
+ [Stable]
45
+ struct WritingGuide {
46
+ // Size of the writing area. The writing area must have (0, 0) at the top
47
+ // left.
48
+ // width is the max value of x-axis (to the right) and height is the max
49
+ // value of y-axis (to the bottom).
50
+ float width;
51
+ float height;
52
+ };
53
+
54
+ // Options that will influence the recognition output.
55
+ [Stable]
56
+ struct RecognitionContext {
57
+ // The writing guide shown to the user when the ink was captured.
58
+ WritingGuide? writing_guide;
59
+ // The context before the written text.
60
+ string? pre_context;
61
+ };
62
+
63
+ // Defines a handwriting recognition query.
64
+ [Stable]
65
+ struct HandwritingRecognitionQuery {
66
+ // The set of ink strokes to be recognized.
67
+ array<InkStroke> ink;
68
+ // The optional context in which the ink was generated.
69
+ RecognitionContext? context;
70
+ // Maximum number of results to be returned.
71
+ uint32 max_num_results;
72
+ // If true, returns the segmentation results. This will make the response
73
+ // struct much larger.
74
+ bool return_segmentation;
75
+ };
76
+
77
+ // Represents a contiguous range of ink. Start and end strokes / points are
78
+ // inclusive.
79
+ [Stable]
80
+ struct HandwritingRecognizerInkRange {
81
+ // Zero-based start- and end-stroke indices in the ink strokes.
82
+ uint32 start_stroke;
83
+ uint32 end_stroke;
84
+ // Zero-based start- and end-point indices with the start / end strokes.
85
+ uint32 start_point;
86
+ uint32 end_point;
87
+ };
88
+
89
+ // A segment defines the substrokes that are associated with a substring of the
90
+ // recognized text.
91
+ [Stable]
92
+ struct HandwritingRecognizerSegment {
93
+ // The substring of the recognized text represented by this segment.
94
+ string sublabel;
95
+ // The ink ranges represented by this segment.
96
+ array<HandwritingRecognizerInkRange> ink_ranges;
97
+ };
98
+
99
+ // The ink segmentation information.
100
+ [Stable]
101
+ struct HandwritingRecognizerSegmentation {
102
+ // The grouping of the cut strokes into characters.
103
+ array<HandwritingRecognizerSegment> segments;
104
+ };
105
+
106
+ // One possible candidate from the handwriting recognition.
107
+ [Stable]
108
+ struct HandwritingRecognizerCandidate {
109
+ // The recognized text.
110
+ string text;
111
+ // Scores will most often correspond to -log(p(c)) or a scaling thereof, so
112
+ // lower scores represent higher confidence.
113
+ float score;
114
+ // The stroke segmentation that was used to generate the result.
115
+ HandwritingRecognizerSegmentation? segmentation;
116
+ };
117
+
118
+ // The handwriting recognition response.
119
+ [Stable]
120
+ struct HandwritingRecognizerResult {
121
+ // Status of the recognition response.
122
+ [Stable, Extensible]
123
+ enum Status {
124
+ OK = 0,
125
+ ERROR = 1,
126
+ };
127
+ Status status;
128
+
129
+ // The recognition candidates with additional alternatives, sorted by lower
130
+ // score first (lower score present higher confidence).
131
+ array<HandwritingRecognizerCandidate> candidates;
132
+ };
133
+
134
+ // The specification of a handwriting recognizer.
135
+ [Stable]
136
+ struct HandwritingRecognizerSpec {
137
+ // The language the recognizer will handle. Only "en" (for english) and
138
+ // "gesture_in_context" (for gesture) are supported.
139
+ string language;
140
+
141
+ // Path to the language pack to use (downloaded by Chrome via DLC).
142
+ [MinVersion=1] string? language_pack_path;
143
+ };
144
+
145
+ // The mojom interface for performing the recognition of handwritten text.
146
+ // Next ordinal: 1
147
+ [Stable]
148
+ interface HandwritingRecognizer {
149
+ // Performs handwriting recognition on a set of ink strokes, and returns a set
150
+ // of alternative recognition results.
151
+ Recognize@0(HandwritingRecognitionQuery query) =>
152
+ (HandwritingRecognizerResult result);
153
+ };
154
+
155
+ // Enum indicates the result of LoadHandwritingModel in mlservice.
156
+ [Stable, Extensible]
157
+ enum LoadHandwritingModelResult {
158
+ OK = 0,
159
+
160
+ // Deprecated enum values.
161
+ DEPRECATED_MODEL_SPEC_ERROR = 1,
162
+ LOAD_MODEL_ERROR = 2,
163
+
164
+ // If both USE.ondevice_handwriting and USE.ondevice_handwriting_dlc
165
+ // are not defined. (checked in chrome)
166
+ FEATURE_NOT_SUPPORTED_ERROR = 3,
167
+
168
+ // If the required language is not in an allowlist, "en" and
169
+ // "gesture_in_context" for now. (checked in chrome)
170
+ LANGUAGE_NOT_SUPPORTED_ERROR = 4,
171
+
172
+ // If the user goes to chrome://flag page and manually disable
173
+ // handwriting or handwriting_dlc. (checked in chrome)
174
+ FEATURE_DISABLED_BY_USER = 5,
175
+
176
+ // if the USE.ondevice_handwriting_dlc is enabled, but dlc is not
177
+ // on the device. (checked in chrome)
178
+ DLC_DOES_NOT_EXIST = 6,
179
+
180
+ // If the dlc is on the device, but InstallDlc returns an error.
181
+ // (checked in chrome).
182
+ DLC_INSTALL_ERROR = 7,
183
+
184
+ // If dlc is installed successfully, but GetDlcState returns an error.
185
+ // (checked inside MachineLearningServiceImpl)
186
+ DLC_GET_PATH_ERROR = 8,
187
+
188
+ // if loading libhandwriting.so fails. (checked inside HandWritingLibrary)
189
+ LOAD_NATIVE_LIB_ERROR = 9,
190
+
191
+ // if getting the function pointers fails. (checked inside HandWritingLibrary)
192
+ LOAD_FUNC_PTR_ERROR = 10,
193
+
194
+ // If loading model files fails. (checked inside HandWritingLibrary)
195
+ LOAD_MODEL_FILES_ERROR = 11,
196
+ };
19/public/mojom/machine_learning_service.mojom ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Next MinVersion: 5
6
+
7
+ // Top-level API of the Machine Learning Service: loading models for inference.
8
+
9
+ // NOTE: This mojom exists in two places and must be kept in sync:
10
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
11
+ // Chrome OS: src/platform2/ml/mojom/
12
+ // Note: Other repos downstream of Chromium might also use this mojom.
13
+ // Example: A backwards-compatible mojom change (and corresponding
14
+ // implementation change) can be made in Chrome OS first, then replicated to the
15
+ // clients (Chromium, other downstream repos) later.
16
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
17
+ // replicate Chrome OS-side changes over to Chromium.
18
+
19
+ module chromeos.machine_learning.mojom;
20
+
21
+ // NOTE: The base directory for 'import' statements is expected to differ
22
+ // between Chromium and Chrome OS versions of this file.
23
+ import "chromeos/services/machine_learning/public/mojom/document_scanner.mojom";
24
+ import "chromeos/services/machine_learning/public/mojom/grammar_checker.mojom";
25
+ import "chromeos/services/machine_learning/public/mojom/handwriting_recognizer.mojom";
26
+ import "chromeos/services/machine_learning/public/mojom/model.mojom";
27
+ import "chromeos/services/machine_learning/public/mojom/soda.mojom";
28
+ import "chromeos/services/machine_learning/public/mojom/text_classifier.mojom";
29
+ import "chromeos/services/machine_learning/public/mojom/text_suggester.mojom";
30
+ import "chromeos/services/machine_learning/public/mojom/web_platform_handwriting.mojom";
31
+
32
+ // These values are persisted to logs. Entries should not be renumbered and
33
+ // numeric values should never be reused.
34
+ [Stable, Extensible]
35
+ enum LoadModelResult {
36
+ OK = 0,
37
+ MODEL_SPEC_ERROR = 1,
38
+ LOAD_MODEL_ERROR = 2,
39
+ FEATURE_NOT_SUPPORTED_ERROR = 3,
40
+ LANGUAGE_NOT_SUPPORTED_ERROR = 4,
41
+ };
42
+
43
+ // Top-level interface between Chromium browser process and the ML Service
44
+ // daemon.
45
+ // Next ordinal: 11
46
+ [Stable, Uuid="9e5e4750-40cc-4eda-ac09-3457d06a45ab"]
47
+ interface MachineLearningService {
48
+ // Binds another pipe to this instance.
49
+ Clone@5(pending_receiver<MachineLearningService> receiver);
50
+
51
+ // The BuiltinModelId inside BuiltinModelSpec is used to specify the model to
52
+ // be loaded.
53
+ LoadBuiltinModel@0(BuiltinModelSpec spec, pending_receiver<Model> receiver)
54
+ => (LoadModelResult result);
55
+ // The FlatbufferModelSpec contains both of the flatbuffer content and the
56
+ // metadata.
57
+ LoadFlatBufferModel@1(FlatBufferModelSpec spec,
58
+ pending_receiver<Model> receiver)
59
+ => (LoadModelResult result);
60
+ // Create a new TextClassifier.
61
+ LoadTextClassifier@2(pending_receiver<TextClassifier> receiver)
62
+ => (LoadModelResult result);
63
+ // Create and initialize a handwriting recognizer with given `spec`.
64
+ LoadHandwritingModel@3(
65
+ HandwritingRecognizerSpec spec,
66
+ pending_receiver<HandwritingRecognizer> receiver)
67
+ => (LoadHandwritingModelResult result);
68
+ // Create and initialize a speech recognizer with given `config`.
69
+ LoadSpeechRecognizer@6(SodaConfig config,
70
+ pending_remote<SodaClient> soda_client,
71
+ pending_receiver<SodaRecognizer> soda_recognizer)
72
+ => (LoadModelResult result);
73
+ // Create and initialize a grammar checker.
74
+ LoadGrammarChecker@7(pending_receiver<GrammarChecker> receiver)
75
+ => (LoadModelResult result);
76
+ // Create and initialize a text suggester.
77
+ [MinVersion=2] LoadTextSuggester@8(
78
+ pending_receiver<TextSuggester> receiver,
79
+ [MinVersion=3] TextSuggesterSpec? spec)
80
+ => (LoadModelResult result);
81
+ // Create a handwriting recognizer for web platform API.
82
+ // This API shares the same HWR engine with `LoadHandwritingModel`
83
+ // but with a different interface. This API is as identical to
84
+ // the Web Platform HWR API as possible so that we do not
85
+ // need to convert the input/output in the browser process.
86
+ // This is required for security reasons.
87
+ [MinVersion=1] LoadWebPlatformHandwritingModel@9(
88
+ chromeos.machine_learning.web_platform.mojom.HandwritingModelConstraint
89
+ constraint,
90
+ pending_receiver<
91
+ chromeos.machine_learning.web_platform.mojom.HandwritingRecognizer>
92
+ receiver)
93
+ => (LoadHandwritingModelResult result);
94
+ // Create and initialize a document scanner.
95
+ [MinVersion=4] LoadDocumentScanner@10(
96
+ pending_receiver<DocumentScanner> receiver)
97
+ => (LoadModelResult result);
98
+ // Deprecated `LoadHandwritingModelWithSpec`
99
+ REMOVED_4@4(
100
+ HandwritingRecognizerSpec spec,
101
+ pending_receiver<HandwritingRecognizer> receiver)
102
+ => (LoadModelResult result);
103
+ };
19/public/mojom/model.mojom ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Next MinVersion: 2
6
+
7
+ // Datatypes and interfaces of models for the Machine Learning API.
8
+
9
+ // NOTE: This mojom exists in two places and must be kept in sync:
10
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
11
+ // Chrome OS: src/platform2/ml/mojom/
12
+ // Note: Other repos downstream of Chromium might also use this mojom.
13
+ // Example: A backwards-compatible mojom change (and corresponding
14
+ // implementation change) can be made in Chrome OS first, then replicated to the
15
+ // clients (Chromium, other downstream repos) later.
16
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
17
+ // replicate Chrome OS-side changes over to Chromium.
18
+
19
+ module chromeos.machine_learning.mojom;
20
+
21
+ // NOTE: The base directory for 'import' statements is expected to differ
22
+ // between Chromium and Chrome OS versions of this file.
23
+ import "chromeos/services/machine_learning/public/mojom/graph_executor.mojom";
24
+
25
+ // These values are persisted to logs. Entries should not be renumbered and
26
+ // numeric values should never be reused.
27
+ // ModelIds prefixed with UNSUPPORTED_ are no longer supported. Attempts to load
28
+ // them will produce an error.
29
+ [Stable, Extensible]
30
+ enum BuiltinModelId {
31
+ // Unknown ML model. It is marked as unsupported.
32
+ UNSUPPORTED_UNKNOWN = 0,
33
+ // Test ML model.
34
+ TEST_MODEL = 1,
35
+ // The Smart Dim (20181115) ML model.
36
+ UNSUPPORTED_SMART_DIM_20181115 = 2,
37
+ // The Smart Dim (20190221) ML model.
38
+ UNSUPPORTED_SMART_DIM_20190221 = 3,
39
+ // The Top Cat (20190722) ML model.
40
+ UNSUPPORTED_TOP_CAT_20190722 = 4,
41
+ // The Smart Dim (20190521) ML model.
42
+ SMART_DIM_20190521 = 5,
43
+ // The Search Ranker (20190923) ML model.
44
+ SEARCH_RANKER_20190923 = 6,
45
+ // The Adaptive Charging (20211105) ML model.
46
+ [MinVersion=1] ADAPTIVE_CHARGING_20211105 = 7,
47
+ };
48
+
49
+ // Options for creating the executor. Options are used for testing and
50
+ // development. They are not typically used in normal, production code.
51
+ [Stable]
52
+ struct GraphExecutorOptions {
53
+ bool use_nnapi = false;
54
+ [MinVersion=1] bool use_gpu = false;
55
+ };
56
+
57
+ // These values are persisted to logs. Entries should not be renumbered and
58
+ // numeric values should never be reused.
59
+ [Stable, Extensible]
60
+ enum CreateGraphExecutorResult {
61
+ OK = 0,
62
+ MODEL_INTERPRETATION_ERROR = 1,
63
+ MEMORY_ALLOCATION_ERROR = 2,
64
+ NNAPI_UNAVAILABLE = 3,
65
+ NNAPI_USE_ERROR = 4,
66
+ [MinVersion=1] GPU_UNAVAILABLE = 5,
67
+ [MinVersion=1] GPU_USE_ERROR = 6,
68
+ [MinVersion=1] DELEGATE_CONFIG_ERROR = 7,
69
+ [MinVersion=1] NOT_FULLY_DELEGABLE = 8,
70
+ };
71
+
72
+ // Model specification for builtin models.
73
+ // Because ml-service can retrieve a builtin model's content and metadata, only
74
+ // an `id` is needed to specify it.
75
+ [Stable]
76
+ struct BuiltinModelSpec {
77
+ BuiltinModelId id;
78
+ };
79
+
80
+ // Model specification for downloaded models.
81
+ // For a downloaded model, both of the model content and metadata must be
82
+ // specified.
83
+ [Stable]
84
+ struct FlatBufferModelSpec {
85
+ // The content of the model's tflite model file.
86
+ string model_string;
87
+ // A map from input nodes' names to their indices.
88
+ map<string, int32> inputs;
89
+ // A map from output nodes' names to their indices.
90
+ map<string, int32> outputs;
91
+ // Used in naming the UMA metric histograms of the model. An example of the
92
+ // names of the histograms is:
93
+ //
94
+ // MachineLearningService.`metrics_model_name`.ExecuteResult.CpuTimeMicrosec
95
+ //
96
+ // This variable must NOT be empty.
97
+ string metrics_model_name;
98
+ };
99
+
100
+ // The lifetime of the cached model is tied to the lifetime of the Model
101
+ // interface pipe. The Model interface pipe can be used to acquire multiple
102
+ // separate GraphExecutor instances.
103
+ // Next ordinal: 2
104
+ [Stable]
105
+ interface Model {
106
+ // Deprecated messages:
107
+ REMOVED_0@0(pending_receiver<GraphExecutor> receiver) =>
108
+ (CreateGraphExecutorResult result);
109
+
110
+ // Creates a new GraphExecutor with the specified `options` and binds it to
111
+ // `receiver`. The GraphExecutor can be used to repeatedly evaluate this
112
+ // `Model`.
113
+ // * A Model can have more than one GraphExecutor.
114
+ // * Releasing this GraphExecutor frees the associated memory (but
115
+ // doesn't free the Model unless its pipe is also closed).
116
+ CreateGraphExecutor@1(GraphExecutorOptions options,
117
+ pending_receiver<GraphExecutor> receiver) =>
118
+ (CreateGraphExecutorResult result);
119
+ };
19/public/mojom/roll_mojoms.sh ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Copyright 2019 The Chromium Authors. All rights reserved.
4
+ # Use of this source code is governed by a BSD-style license that can be
5
+ # found in the LICENSE file.
6
+
7
+ usage() {
8
+ echo "Usage: $0 CROS_SRC_DIR"
9
+ echo ""
10
+ echo "Rolls (copies) ML Service *.mojom files from Chrome OS to current"
11
+ echo "directory, with appropriate boilerplate modifications for use in"
12
+ echo "Chromium."
13
+ echo ""
14
+ echo "CROS_SRC_DIR: Path to Chromium OS source, e.g. ~/chromiumos/src."
15
+ }
16
+
17
+ CROS_SRC_DIR="$1"
18
+
19
+ if [ -z "$CROS_SRC_DIR" ]; then
20
+ usage
21
+ exit 1
22
+ fi
23
+
24
+ if [ ! -d "$CROS_SRC_DIR" ]; then
25
+ echo "$CROS_SRC_DIR not a directory"
26
+ usage
27
+ exit 1
28
+ fi
29
+
30
+ if [ "$(basename $CROS_SRC_DIR)" != "src" ]; then
31
+ echo "$CROS_SRC_DIR should end with /src"
32
+ usage
33
+ exit 1
34
+ fi
35
+
36
+ if ! git diff-index --quiet HEAD -- ; then
37
+ echo "'git status' not clean. Commit your changes first."
38
+ exit 1
39
+ fi
40
+
41
+ readonly EXPECTED_PATH="chromeos/services/machine_learning/public/mojom"
42
+ if [[ "$(pwd)" != *"${EXPECTED_PATH}" ]]; then
43
+ echo "Please run from within ${EXPECTED_PATH}."
44
+ exit 1;
45
+ fi
46
+
47
+ echo "Copying mojoms from Chrome OS side ..."
48
+ cp $1/platform2/ml/mojom/*.mojom . || exit 1
49
+
50
+ echo "Removing time.mojom ..."
51
+ rm time.mojom || exit 1
52
+
53
+ echo "Removing shared_memory.mojom ..."
54
+ rm shared_memory.mojom || exit 1
55
+
56
+ echo "Removing geometry.mojom ..."
57
+ rm geometry.mojom || exit 1
58
+
59
+ echo "Changing import paths ..."
60
+ sed --in-place --regexp-extended \
61
+ -e 's~^import "ml/mojom/geometry.mojom~import "ui/gfx/geometry/mojom/geometry.mojom~g' \
62
+ -e 's~^import "ml/mojom/shared_memory.mojom~import "mojo/public/mojom/base/shared_memory.mojom~g' \
63
+ -e 's~^import "ml/mojom/time.mojom~import "mojo/public/mojom/base/time.mojom~g' \
64
+ -e 's~^import "ml~import "chromeos/services/machine_learning/public~g' \
65
+ *.mojom
66
+
67
+ echo "OK. Now:"
68
+ echo "1. Examine 'git diff' to double-check the results of this tool."
69
+ echo "2. After submitting, also update any google3 files generated from these "
70
+ echo " mojoms (e.g. javascript bindings)."
19/public/mojom/soda.mojom ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2020 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Datatypes and interfaces of speech recognition API.
6
+
7
+ // NOTE: This mojom exists in two places and must be kept in sync:
8
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
9
+ // Chrome OS: src/platform2/ml/mojom/
10
+ // Note: Other repos downstream of Chromium might also use this mojom.
11
+ // Example: A backwards-compatible mojom change (and corresponding
12
+ // implementation change) can be made in Chrome OS first, then replicated to the
13
+ // clients (Chromium, other downstream repos) later.
14
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
15
+ // replicate Chrome OS-side changes over to Chromium.
16
+ // Versions list:
17
+ // Version 0: Initial
18
+ // Version 1: Include HypothesisPart Info in Final result.
19
+ // Version 2: Include enable formatting in request config.
20
+ // Version 3: Include recognition mode in request config.
21
+ module chromeos.machine_learning.mojom;
22
+
23
+ import "mojo/public/mojom/base/time.mojom";
24
+
25
+ // Augments a bool to include an 'unknown' value.
26
+ [Stable, Extensible]
27
+ enum OptionalBool {
28
+ [Default] kUnknown = 0,
29
+ kFalse,
30
+ kTrue,
31
+ };
32
+
33
+ [Stable, Extensible]
34
+ enum SodaRecognitionMode {
35
+ [Default] kCaption,
36
+ kIme,
37
+ };
38
+
39
+ // The configuration used to load Soda recognizer.
40
+ [Stable]
41
+ struct SodaConfig {
42
+ // Number of channels of the audio that will be sent to Soda recognizer.
43
+ uint32 channel_count;
44
+ // Sample rate of the audio that will be sent to Soda recognizer.
45
+ uint32 sample_rate;
46
+ // The api key for Soda library.
47
+ string api_key;
48
+ // Path to already-installed SODA library.
49
+ string library_dlc_path;
50
+ // Path to already-installed SODA language pack to use.
51
+ string language_dlc_path;
52
+ // Whether to enable automated punctuation. Defaults to true as this
53
+ // is the default in the underlying protocol buffer.
54
+ [MinVersion=2] OptionalBool enable_formatting = kTrue;
55
+ // Which mode to execute in: IME or CAPTION. Default CAPTION.
56
+ [MinVersion=3] SodaRecognitionMode recognition_mode = kCaption;
57
+ };
58
+
59
+ // From the endpointer, What kind of endpointer event to record.
60
+ [Stable, Extensible]
61
+ enum EndpointerType {
62
+ // Speech detected.
63
+ START_OF_SPEECH,
64
+ // End of speech detected, but audio continues.
65
+ END_OF_SPEECH,
66
+ // Audio is terminated.
67
+ END_OF_AUDIO,
68
+ // Query is terminated.
69
+ END_OF_UTTERANCE
70
+ };
71
+
72
+ // Common information about the timing of reported SODA events.
73
+ [Stable]
74
+ struct TimingInfo {
75
+ // Epoch time of the first audio buffer of the main query that is fed into
76
+ // ASR. This is the wall time read from the system clock when the first audio
77
+ // buffer is received by the terse processor.
78
+ mojo_base.mojom.Time audio_start_epoch;
79
+
80
+ // Start time in audio time from the start of the SODA session.
81
+ // This time measures the amount of audio input into SODA.
82
+ mojo_base.mojom.TimeDelta audio_start_time;
83
+
84
+ // Elapsed wall time usec since the first frame.
85
+ mojo_base.mojom.TimeDelta elapsed_wall_time;
86
+
87
+ // Elapsed processed audio usec from first frame after preamble.
88
+ mojo_base.mojom.TimeDelta event_end_time;
89
+
90
+ // On device benchmark latency as defined in go/asr-latency-metrics.
91
+ mojo_base.mojom.TimeDelta latency;
92
+
93
+ // On device counter part of E2E normalized latency as defined in
94
+ // go/asr-latency-metrics. This metric is mainly for non-continuous
95
+ // conversation.
96
+ float normalized_latency;
97
+
98
+ // Timing for each word as an offset from audio_start_time_usec.
99
+ array<mojo_base.mojom.TimeDelta> word_alignments;
100
+ };
101
+
102
+ // Start/end events.
103
+ [Stable]
104
+ struct EndpointerEvent {
105
+ EndpointerType endpointer_type;
106
+ TimingInfo? timing_event;
107
+ };
108
+
109
+ // A result _during_ a recognition. Could change at any time with the
110
+ // next partial or the final recognition for this chunk.
111
+ [Stable]
112
+ struct PartialResult {
113
+ // Most likely hypothesis so far. First is the most likely, followed by others.
114
+ // Note: the relationship from first to other hypothess is not guaranteed in
115
+ // any way.
116
+ array<string> partial_text;
117
+ TimingInfo? timing_event;
118
+ };
119
+
120
+ [Stable, Extensible]
121
+ enum EndpointReason {
122
+ // Default value, unknown reason.
123
+ ENDPOINT_UNKNOWN,
124
+ // Due to end_of_speech detection by endpointer.
125
+ ENDPOINT_END_OF_SPEECH,
126
+ // Due to end_of_utterance detection by endpointer.
127
+ ENDPOINT_END_OF_UTTERANCE,
128
+ // Due to the end of mics audio. This could be due to a mic event or SODA
129
+ // being stopped.
130
+ ENDPOINT_END_OF_AUDIO,
131
+ };
132
+
133
+
134
+ // Detail about a part of a hypothesis in a result. Only makes sense
135
+ // in context of an array of them for a hypothesis.
136
+ [Stable]
137
+ struct HypothesisPartInResult {
138
+ // Typically 1 item for a a word/piece of text. If formatting is
139
+ // enabled, the raw text is the second item.
140
+ array<string> text;
141
+
142
+ // Offset from the beginning of this part of the hypothesis from
143
+ // audio_start_time in TimingInfo.
144
+ mojo_base.mojom.TimeDelta alignment;
145
+ };
146
+
147
+ [Stable]
148
+ struct FinalResult {
149
+ // Sorted in decreasing order of probability.
150
+ array<string> final_hypotheses;
151
+ EndpointReason endpoint_reason;
152
+ TimingInfo? timing_event;
153
+
154
+ // If populated, this array contains the hypothesis parts for the
155
+ // first final hypothesis in the array of final_hypotheses.
156
+ [MinVersion=1] array<HypothesisPartInResult>? hypothesis_part;
157
+ };
158
+
159
+ // Frequent event from recognizer, almost from every frame. Gives an indication
160
+ // of speechiness and audio level.
161
+ [Stable]
162
+ struct AudioLevelEvent {
163
+ // RMS audio level, from PowerEvaluator . Score is [0, 1)
164
+ float rms;
165
+ // Speech likelihood score, from TerseProcessor. Score is [0, 1)
166
+ float audio_level;
167
+ };
168
+
169
+ // This essentially mirrors the subset of SODA's SodaEvent proto we will
170
+ // support.
171
+ [Stable]
172
+ union SpeechRecognizerEvent {
173
+ AudioLevelEvent audio_event;
174
+ PartialResult partial_result;
175
+ EndpointerEvent endpointer_event;
176
+ FinalResult final_result;
177
+ };
178
+
179
+ // This interface is called upon by the SodaRecognizer. Implemented by
180
+ // the client, SODA then calls these as 'events' with appropriate details
181
+ // when recognition occurs.
182
+ // Next ordinal: 3
183
+ [Stable]
184
+ interface SodaClient {
185
+ // After SODA successfully starts / warms up / stops, in case the client
186
+ // cares:
187
+ OnStart@0();
188
+ OnStop@1();
189
+
190
+ // This is how the client receives actual recognized text as well as other
191
+ // conclusions from the SODA model like "speech ended".
192
+ OnSpeechRecognizerEvent@2(SpeechRecognizerEvent event);
193
+ };
194
+
195
+ // The mojom interface for performing the recognition of handwritten text.
196
+ // Next ordinal: 4
197
+ [Stable]
198
+ interface SodaRecognizer {
199
+ // Add Audio for speech recognition.
200
+ AddAudio@0(array<uint8> audio);
201
+
202
+ // Instruct SODA to stop processing immediately. Stopping is
203
+ // confirmed when SodaClient::OnStop is called back.
204
+ Stop@1();
205
+
206
+ // Instruct SODA to start processing. Noop if already
207
+ // processing. When Stopped, causes a SodAclient::OnStart callback.
208
+ Start@2();
209
+
210
+ // Instruct SODA to stop processing after all queued audio is
211
+ // processed. Will eventually result in a SodaClient::OnStop, but only
212
+ // after all audio currently in queue is decoded.
213
+ MarkDone@3();
214
+ };
19/public/mojom/tensor.mojom ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2018 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Datatypes used in the Machine Learning API.
6
+ // This module is derived from the Feature proto definition of TensorFlow.
7
+ // See /tensorflow/core/example/feature.proto in the TensorFlow code.
8
+
9
+ // NOTE: This mojom exists in two places and must be kept in sync:
10
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
11
+ // Chrome OS: src/platform2/ml/mojom/
12
+ // Note: Other repos downstream of Chromium might also use this mojom.
13
+ // Example: A backwards-compatible mojom change (and corresponding
14
+ // implementation change) can be made in Chrome OS first, then replicated to the
15
+ // clients (Chromium, other downstream repos) later.
16
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
17
+ // replicate Chrome OS-side changes over to Chromium.
18
+
19
+ module chromeos.machine_learning.mojom;
20
+
21
+ [Stable]
22
+ struct StringList {
23
+ array<string> value;
24
+ };
25
+
26
+ [Stable]
27
+ struct FloatList {
28
+ array<double> value;
29
+ };
30
+
31
+ [Stable]
32
+ struct Int64List {
33
+ array<int64> value;
34
+ };
35
+
36
+ // The union of all supported tensor types. Supporting a new type comprises the
37
+ // following:
38
+ // - Adding a new struct above (e.g. BoolList),
39
+ // - Adding this new struct to the union below,
40
+ // - Adding template specializations for the new type to
41
+ // platform2/ml/tensor_view.{h,cc}.
42
+ // - Updating platform2/ml/graph_executor_impl.cc to use a TensorView of the
43
+ // new type.
44
+ //
45
+ // TODO(chromium:836098): add new types (e.g. uint8, bool) as they become
46
+ // useful.
47
+ [Stable]
48
+ union ValueList {
49
+ StringList string_list;
50
+ FloatList float_list;
51
+ Int64List int64_list;
52
+ };
53
+
54
+ // A Tensor is a multi-dimensional array with dimensions `shape`, flattened into
55
+ // the one-dimensional array `data`.
56
+ // It is used for both the inputs (in the form of a map<string, Tensor>) and
57
+ // outputs (in the form of an array<Tensor>) of ML inference.
58
+ [Stable]
59
+ struct Tensor {
60
+ ValueList data;
61
+
62
+ // Each integer is the size of that dimension.
63
+ Int64List shape;
64
+ };
19/public/mojom/text_classifier.mojom ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2020 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // API of the text classifier (libtextclassifier).
6
+
7
+ // NOTE: This mojom exists in two places and must be kept in sync:
8
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
9
+ // Chrome OS: src/platform2/ml/mojom/
10
+ // Note: Other repos downstream of Chromium might also use this mojom.
11
+ // Example: A backwards-compatible mojom change (and corresponding
12
+ // implementation change) can be made in Chrome OS first, then replicated to the
13
+ // clients (Chromium, other downstream repos) later.
14
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
15
+ // replicate Chrome OS-side changes over to Chromium.
16
+
17
+ module chromeos.machine_learning.mojom;
18
+
19
+ // NOTE: The base directory for 'import' statements is expected to differ
20
+ // between Chromium and Chrome OS versions of this file.
21
+ // And for "time.mojom", on the chromium side, we have to use the version
22
+ // under mojo folder, that is, "mojo/public/mojom/base/time.mojom".
23
+ import "mojo/public/mojom/base/time.mojom";
24
+
25
+ // Enum for specifying the annotation usecase.
26
+ // Must be consistent with `AnnotationUsecase` in model.fb in libtextclassifier.
27
+ [Stable, Extensible]
28
+ enum AnnotationUsecase {
29
+ // Results are optimized for Smart{Select,Share,Linkify}
30
+ ANNOTATION_USECASE_SMART = 0,
31
+ // Results are optimized for using TextClassifier as an infrastructure that
32
+ // annotates as much as possible.
33
+ ANNOTATION_USECASE_RAW = 1,
34
+ };
35
+
36
+ // Stores data extracted from each text entity.
37
+ // Currently, only for "number" type, the real number value is stored in
38
+ // `numeric_value`. For the other types, the substring annotated is stored
39
+ // in `string_value`.
40
+ // The values come from the class `ClassificationResult` of tclib. (See
41
+ // "tclib/annotator/types.h").
42
+ // TODO(honglinyu): add data extraction for more types when needed and
43
+ // available. For example, when "date" data is needed, probably we should add
44
+ // a new struct "Date" and add a new member "Data date_value" to the following
45
+ // union.
46
+ [Stable]
47
+ union TextEntityData {
48
+ // A numeric value.
49
+ // - For "number", it is the value.
50
+ // e.g. it is "34.3" for input string "34.3".
51
+ double numeric_value@0;
52
+ // Could be "url", "address" etc.
53
+ string string_value@1;
54
+ };
55
+
56
+ // Types of text (can be phone numbers, addresses, emails and urls etc.).
57
+ // This struct is a distillation of the `ClassificationResult` of tclib. (See
58
+ // "tclib/annotator/types.h").
59
+ [Stable]
60
+ struct TextEntity {
61
+ // The name of the type (e.g. "phone", "address", "email" and "url" etc.).
62
+ string name@0;
63
+ // The confidence score of the entity annotation, and the range is 0-1.
64
+ float confidence_score@1;
65
+ // Additional data extracted from the text.
66
+ TextEntityData data@2;
67
+ };
68
+
69
+ // A substring of the annotated text and possible associated entities.
70
+ // This struct is a simplification of the `AnnotatedSpan` class of tclib. (See
71
+ // "tclib/annotator/types.h").
72
+ [Stable]
73
+ struct TextAnnotation {
74
+ // The offset of the first character of the annotation.
75
+ uint32 start_offset@0;
76
+ // The offset of the last character of the annotation.
77
+ uint32 end_offset@1;
78
+ // The set of entity types associated with the substring.
79
+ array<TextEntity> entities@2;
80
+ };
81
+
82
+ // Contains the input and parameters used to annotate the text.
83
+ // This is a combination of string and `AnnotationOptions` in tclib (see
84
+ // "tclib/annotator/types.h").
85
+ [Stable]
86
+ struct TextAnnotationRequest {
87
+ // The text to be annotated.
88
+ string text@0;
89
+ // Comma-delimited locales (e.g., "en", "en,es").
90
+ string? default_locales@1;
91
+ // Comma-separated list of language tags.
92
+ string? detected_text_language_tags@2;
93
+ // Tailors the output annotations according to the specified use-case.
94
+ AnnotationUsecase annotation_usecase@3 = ANNOTATION_USECASE_SMART;
95
+ // For parsing relative datetimes, the reference now time against which the
96
+ // relative datetimes get resolved.
97
+ mojo_base.mojom.Time? reference_time@4;
98
+ // Timezone in which the input text was written (format as accepted by ICU).
99
+ // If empty (default), will use the system's timezone.
100
+ string? reference_timezone@5;
101
+ // Enabled entities. If empty (default), all types of entities will be
102
+ // enabled.
103
+ array<string>? enabled_entities@6;
104
+ };
105
+
106
+ // Marks a span in a sequence of codepoints.
107
+ // This struct is consistent with the type `CodepointSpan` of tclib. (See
108
+ // "tclib/annotator/types.h").
109
+ [Stable]
110
+ struct CodepointSpan {
111
+ // The offset of the first character of the span.
112
+ uint32 start_offset@0;
113
+ // The offset of the last character of the span.
114
+ uint32 end_offset@1;
115
+ };
116
+
117
+ // Represent a language detection result.
118
+ [Stable]
119
+ struct TextLanguage {
120
+ // The BCP-47 language code like "en", "fr", "zh" etc.
121
+ string locale;
122
+ // The confidence score of the language detected (range: 0~1).
123
+ float confidence;
124
+ };
125
+
126
+ // Contains the input and parameters used to suggest selection.
127
+ // This is a combination of the inputs of the `SuggestSelection` function
128
+ // of tclib. (See "tclib/annotator/annotate.h").
129
+ [Stable, RenamedFrom="chromeos.machine_learning.mojom.TextSuggestSelectionRequest"]
130
+ struct REMOVED_TextSuggestSelectionRequest {
131
+ // The candidate text.
132
+ string text@0;
133
+ // Where the user selects.
134
+ CodepointSpan user_selection@1;
135
+ // Comma-delimited locales (e.g., "en", "en,es").
136
+ string? default_locales@2;
137
+ // Comma-separated list of BCP 47 language tags.
138
+ string? detected_text_language_tags@3;
139
+ // Tailors the output annotations according to the specified use-case.
140
+ AnnotationUsecase annotation_usecase@4 = ANNOTATION_USECASE_SMART;
141
+ };
142
+
143
+ // Used to annotate entities within text strings.
144
+ // Next ordinal: 3
145
+ [Stable]
146
+ interface TextClassifier {
147
+ // Annotate a text string and returns the detected substrings and possible
148
+ // entities.
149
+ Annotate@0(TextAnnotationRequest request) =>
150
+ (array<TextAnnotation> outputs);
151
+ // Identify the languages the text is possibly written in.
152
+ // The returned results are sorted according to the confidence score, from the
153
+ // highest to the lowest.
154
+ // The maximum number of results returned is determined internally.
155
+ // Will return an empty array if the language can not be determined.
156
+ FindLanguages@2(string text) => (array<TextLanguage> outputs);
157
+ // Deprecated `SuggestSelection`
158
+ REMOVED_1@1(REMOVED_TextSuggestSelectionRequest request) =>
159
+ (CodepointSpan outputs);
160
+ };
19/public/mojom/text_suggester.mojom ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Next MinVersion: 3
6
+
7
+ // Datatypes and interfaces of text suggester API.
8
+
9
+ // NOTE: This mojom exists in two places and must be kept in sync:
10
+ // Chromium: //chromeos/services/machine_learning/public/mojom/
11
+ // Chrome OS: src/platform2/ml/mojom/
12
+ // Note: Other repos downstream of Chromium might also use this mojom.
13
+
14
+ // Example: A backwards-compatible mojom change (and corresponding
15
+ // implementation change) can be made in Chrome OS first, then replicated to the
16
+ // clients (Chromium, other downstream repos) later.
17
+ // Use //chromeos/services/machine_learning/public/mojom/roll_mojoms.sh to help
18
+ // replicate Chrome OS-side changes over to Chromium.
19
+
20
+ module chromeos.machine_learning.mojom;
21
+
22
+ // Represents a single completion candidate
23
+ // Next ordinal: 2
24
+ [Stable]
25
+ struct NextWordCompletionCandidate {
26
+ // The completing text suggested
27
+ string text@0;
28
+
29
+ // The normalized confidence score for the generated candidate
30
+ float normalized_score@1;
31
+ };
32
+
33
+ // The mode with which a suggestion should be used by a consumer
34
+ [Stable, Extensible]
35
+ enum TextSuggestionMode {
36
+ // A prediction suggestion is the text predicted after a word. For example
37
+ // the preceding text could be "how are", and the suggested text would be
38
+ // "you".
39
+ [Default] kPrediction = 1,
40
+
41
+ // A completion suggestion is similar to a prediction, however the suggestion
42
+ // also completes any unfinished words in the preceding text. For example,
43
+ // the preceding text could be "how ar", and the suggested text would be
44
+ // "e you".
45
+ kCompletion = 2,
46
+ };
47
+
48
+ // Defines a query for text suggestions
49
+ // Next ordinal: 3
50
+ [Stable]
51
+ struct TextSuggesterQuery {
52
+ // The text used to generate suggestions
53
+ string text@0;
54
+
55
+ // Optional: completion candidates for the final word in the text
56
+ array<NextWordCompletionCandidate> next_word_candidates@1;
57
+
58
+ // The types of suggestions requested
59
+ [MinVersion=1] TextSuggestionMode suggestion_mode@2;
60
+ };
61
+
62
+ // Represents a single generated multi word suggestion candidate.
63
+ // Next ordinal: 2
64
+ [Stable]
65
+ struct MultiWordSuggestionCandidate {
66
+ // The text suggested
67
+ string text@0;
68
+
69
+ // The normalized confidence score for this candidate
70
+ float normalized_score@1;
71
+ };
72
+
73
+ // Represents all types of suggestion candidates generated by the service.
74
+ //
75
+ // TODO(crbug/1201949): Note that the Extensible keyword is not supported for
76
+ // union types. We may need to revisit this type in the future.
77
+ //
78
+ // Next ordinal: 1
79
+ [Stable, Extensible]
80
+ union TextSuggestionCandidate {
81
+ MultiWordSuggestionCandidate multi_word@0;
82
+ };
83
+
84
+ // The result to text suggestion queries, contains any candidates generated.
85
+ // Next ordinal: 2
86
+ [Stable]
87
+ struct TextSuggesterResult {
88
+ // Status of the response
89
+ [Stable, Extensible, Default=ERROR]
90
+ enum Status {
91
+ // Text suggestions generated successfully
92
+ OK = 0,
93
+ // There was an error while generating candidates, no candidates will be
94
+ // returned with this result.
95
+ ERROR = 1,
96
+ };
97
+
98
+ Status status@0;
99
+
100
+ // The list of candidates generated by the text suggester service
101
+ array<TextSuggestionCandidate> candidates@1;
102
+ };
103
+
104
+ // Experiment groups for multi word suggestions
105
+ // Next value: 5
106
+ [Stable, Extensible]
107
+ enum MultiWordExperimentGroup {
108
+ [Default] kDefault = 0,
109
+ kGboard = 1,
110
+ // Experiment groups used for the relaxed gboard settings finch experiment
111
+ [MinVersion=2] kGboardRelaxedA = 2,
112
+ [MinVersion=2] kGboardRelaxedB = 3,
113
+ [MinVersion=2] kGboardRelaxedC = 4
114
+ };
115
+
116
+ // Encapsulates any settings details for a TextSuggester
117
+ // Next ordinal: 1
118
+ [Stable]
119
+ struct TextSuggesterSpec {
120
+ // The experimental group for multi word suggestions
121
+ MultiWordExperimentGroup multi_word_experiment@0;
122
+ };
123
+
124
+ // The top level interface for requesting text based suggestions in the Chromium
125
+ // browser process from the sandboxed ML service process.
126
+ // Next ordinal: 1
127
+ [Stable]
128
+ interface TextSuggester {
129
+ // Generates text suggestions from the given context
130
+ Suggest@0(TextSuggesterQuery query) => (TextSuggesterResult result);
131
+ };
19/public/mojom/web_platform_handwriting.mojom ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Next MinVersion: 2
6
+
7
+ module chromeos.machine_learning.web_platform.mojom;
8
+
9
+ // https://github.com/WICG/handwriting-recognition/blob/main/explainer.md
10
+
11
+ // This mojom file is copied from the file below in chromium repo,
12
+ // "//third_party/blink/public/mojom/handwriting/handwriting.mojom"
13
+ // Notice that some modifications are made,
14
+ // 1. The module is changed to `chromeos.machine_learning.web_platform.mojom`.
15
+ // 2. `[Stable]` tags are added.
16
+ // 3. Interface `HandwritingRecognitionService`
17
+ // and `CreateHandwritingRecognizerResult` are removed because they not
18
+ // used here.
19
+ // 4. The paths of imported mojoms are changed.
20
+ // 5. Feature query related structs are removed because they are not being
21
+ // used for now.
22
+ // For the overlapping definitions, the two files should be kept consistent.
23
+
24
+ import "mojo/public/mojom/base/time.mojom";
25
+ import "ui/gfx/geometry/mojom/geometry.mojom";
26
+
27
+ // Represents a single point in a handwriting stroke.
28
+ // Corresponds to handwriting_point.idl.
29
+ [Stable]
30
+ struct HandwritingPoint {
31
+ // Represent the horizontal (location.x) and vertical (location.y) location
32
+ // of the point.
33
+ // The top-left corner coordinate is (location.x=0, location.y=0).
34
+ gfx.mojom.PointF location;
35
+ // The time elapsed since the starting time (e.g. when the first ink point
36
+ // of the drawing is captured).
37
+ mojo_base.mojom.TimeDelta? t;
38
+ };
39
+
40
+ // Represents a stroke which is just a series of points.
41
+ // Corresponds to handwriting_stroke.idl.
42
+ [Stable]
43
+ struct HandwritingStroke {
44
+ array<HandwritingPoint> points;
45
+ };
46
+
47
+ // Represents a segment of a handwriting stroke in the grapheme detected.
48
+ // One `HandwritingDrawingSegment` can only refer one stroke, denoted by
49
+ // `stroke_index` which is the index of the stroke in the input stroke arrays
50
+ // (i.e., the first parameter of the `HandwritingRecognizer::GetPrediction`
51
+ // function).
52
+ // The reason we need this struct is that different parts of one single stroke
53
+ // can belong to different grapheme detected.
54
+ // Corresponds to handwriting_drawing_segment.idl.
55
+ [Stable]
56
+ struct HandwritingDrawingSegment {
57
+ // The index of the corresponding stroke in the input stroke array.
58
+ uint32 stroke_index;
59
+ // The index of the first point in the stroke that belongs to this drawing
60
+ // segment.
61
+ uint32 begin_point_index;
62
+ // The index of the last point in the stroke that belongs to this drawing
63
+ // segment.
64
+ uint32 end_point_index;
65
+ };
66
+
67
+ // Represents a segment detected.
68
+ // Corresponds to handwriting_segment.idl.
69
+ [Stable]
70
+ struct HandwritingSegment {
71
+ // The string representation of this grapheme.
72
+ string grapheme;
73
+ // HandwritingPrediction.text.slice(begin_index, end_index) === grapheme
74
+ // If the grapheme spans multiple Unicode code points,
75
+ // `end_index - begin_index` is greater than 1.
76
+ uint32 begin_index;
77
+ uint32 end_index;
78
+ array<HandwritingDrawingSegment> drawing_segments;
79
+ };
80
+
81
+ // Represents one single prediction result.
82
+ // The final prediction output is an array of it.
83
+ // Corresponds to handwriting_prediction.idl.
84
+ [Stable]
85
+ struct HandwritingPrediction {
86
+ string text;
87
+ array<HandwritingSegment> segmentation_result;
88
+ };
89
+
90
+ // Represents the hints provided to the recognizer for better performance.
91
+ // Corresponds to handwriting_hints.idl.
92
+ [Stable]
93
+ struct HandwritingHints {
94
+ // The type of content to be recognized. The recognizer may use these to
95
+ // better rank the recognition results. (e.g. "text", "email", "number",
96
+ // "per-character").
97
+ string recognition_type@0;
98
+ // Identifies how the strokes are captured. (e.g. "touch", "mouse", "pen")
99
+ string input_type@1;
100
+ // Deprecated because we want to change `text_context` to be optional, see
101
+ // the comment of `text_context` below.
102
+ string deprecated_text_context@2;
103
+ // The maximum number of alternative predictions to generate.
104
+ uint32 alternatives@3;
105
+ // The text that comes before the handwriting. This can be texts that were
106
+ // previously recognized, or were given as the writing context (e.g.
107
+ // "Write your name here:"). This is the linguistic context to help
108
+ // disambiguate the handwriting (e.g. “Hello world” vs. “Hello word”).
109
+ [MinVersion=1] string? text_context@4;
110
+ };
111
+
112
+ // Used in creating recognizer.
113
+ // Corresponds to handwriting_model_constraint.idl.
114
+ [Stable]
115
+ struct HandwritingModelConstraint {
116
+ // Languages are IETF BCP 47 language tags, e.g., "en", "zh-CN", "zh-Hans".
117
+ array<string> languages;
118
+ };
119
+
120
+ // Interface for a renderer to use a specific handwriting recognition backend.
121
+ // The browser handles the requests and forwards them to the appropriate
122
+ // backend.
123
+ [Stable]
124
+ interface HandwritingRecognizer {
125
+ // Does the recognition and outputs the prediction result.
126
+ // This is used by IDL API `blink::HandwritingDrawing::getPrediction`.
127
+ // The input `strokes` and `hints` should both come from
128
+ // `blink::HandwritingDrawing`.
129
+ // If the returned `Optional` has no value, it means there is some error in
130
+ // recognition. If the returned `Optional` has value but the array is empty,
131
+ // it means the recognizer can not recognize anything from the input.
132
+ GetPrediction@0(array<HandwritingStroke> strokes, HandwritingHints hints)
133
+ => (array<HandwritingPrediction>? prediction);
134
+ };