blob: 622e052a4e9582c48ee5ec05795a944792188714 [file] [log] [blame]
Andrew Moylanff6be512018-07-03 11:05:01 +10001// Copyright 2018 The Chromium OS 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 "ml/machine_learning_service_impl.h"
6
Michael Martisa74af932018-08-13 16:52:36 +10007#include <memory>
Andrew Moylanff6be512018-07-03 11:05:01 +10008#include <utility>
9
Michael Martisa74af932018-08-13 16:52:36 +100010#include <base/bind.h>
hscham4ce3c992021-02-19 16:37:23 +090011#include <base/callback_helpers.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090012#include <base/check.h>
Honglin Yuf33dce32019-12-05 15:10:39 +110013#include <base/files/file.h>
14#include <base/files/file_util.h>
Honglin Yu20391cd2020-10-27 15:58:49 +110015#include <base/files/memory_mapped_file.h>
Michael Martis8783c8e2019-06-26 17:30:54 +100016#include <tensorflow/lite/model.h>
Honglin Yuf33dce32019-12-05 15:10:39 +110017#include <unicode/putil.h>
18#include <unicode/udata.h>
19#include <utils/memory/mmap.h>
Michael Martisa74af932018-08-13 16:52:36 +100020
Jing Wang961b8af2020-10-26 12:40:35 +110021#include "ml/grammar_checker_impl.h"
22#include "ml/grammar_library.h"
charleszhao17777f92020-04-23 12:53:11 +100023#include "ml/handwriting.h"
24#include "ml/handwriting_recognizer_impl.h"
Michael Martisa74af932018-08-13 16:52:36 +100025#include "ml/model_impl.h"
charleszhao17777f92020-04-23 12:53:11 +100026#include "ml/mojom/handwriting_recognizer.mojom.h"
Hidehiko Abeaa488c32018-08-31 23:49:41 +090027#include "ml/mojom/model.mojom.h"
Honglin Yud2204272020-08-26 14:21:37 +100028#include "ml/mojom/soda.mojom.h"
Honglin Yu0f5b21d2021-04-06 23:39:04 +100029#include "ml/mojom/web_platform_handwriting.mojom.h"
Andrew Moylan44c352f2020-11-04 15:19:46 +110030#include "ml/request_metrics.h"
Honglin Yud2204272020-08-26 14:21:37 +100031#include "ml/soda_recognizer_impl.h"
Honglin Yuf33dce32019-12-05 15:10:39 +110032#include "ml/text_classifier_impl.h"
Curtis McMullanf11584f2021-01-13 12:21:36 +110033#include "ml/text_suggester_impl.h"
34#include "ml/text_suggestions.h"
Honglin Yu0f5b21d2021-04-06 23:39:04 +100035#include "ml/web_platform_handwriting_recognizer_impl.h"
Michael Martisa74af932018-08-13 16:52:36 +100036
Andrew Moylanff6be512018-07-03 11:05:01 +100037namespace ml {
38
Michael Martisa74af932018-08-13 16:52:36 +100039namespace {
40
Honglin Yu0ed72352019-08-27 17:42:01 +100041using ::chromeos::machine_learning::mojom::BuiltinModelId;
42using ::chromeos::machine_learning::mojom::BuiltinModelSpecPtr;
43using ::chromeos::machine_learning::mojom::FlatBufferModelSpecPtr;
Andrew Moylanb481af72020-07-09 15:22:00 +100044using ::chromeos::machine_learning::mojom::HandwritingRecognizer;
charleszhao05c5a4a2020-06-09 16:49:54 +100045using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpec;
46using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr;
Charles Zhao6d467e62020-08-31 10:02:03 +100047using ::chromeos::machine_learning::mojom::LoadHandwritingModelResult;
Michael Martisa74af932018-08-13 16:52:36 +100048using ::chromeos::machine_learning::mojom::LoadModelResult;
Andrew Moylanb481af72020-07-09 15:22:00 +100049using ::chromeos::machine_learning::mojom::MachineLearningService;
50using ::chromeos::machine_learning::mojom::Model;
Honglin Yud2204272020-08-26 14:21:37 +100051using ::chromeos::machine_learning::mojom::SodaClient;
52using ::chromeos::machine_learning::mojom::SodaConfigPtr;
53using ::chromeos::machine_learning::mojom::SodaRecognizer;
Andrew Moylanb481af72020-07-09 15:22:00 +100054using ::chromeos::machine_learning::mojom::TextClassifier;
Michael Martisa74af932018-08-13 16:52:36 +100055
56constexpr char kSystemModelDir[] = "/opt/google/chrome/ml_models/";
Andrew Moylan79b34a42020-07-08 11:13:11 +100057// Base name for UMA metrics related to model loading (`LoadBuiltinModel`,
58// `LoadFlatBufferModel`, `LoadTextClassifier` or LoadHandwritingModel).
Honglin Yu6adafcd2019-07-22 13:48:11 +100059constexpr char kMetricsRequestName[] = "LoadModelResult";
Michael Martisa74af932018-08-13 16:52:36 +100060
Honglin Yuf33dce32019-12-05 15:10:39 +110061constexpr char kIcuDataFilePath[] = "/opt/google/chrome/icudtl.dat";
62
Honglin Yu20391cd2020-10-27 15:58:49 +110063// Used to hold the mmap object of the icu data file. Each process should only
64// have one instance of it. Intentionally never close it.
65// We can not make it as a member of `MachineLearningServiceImpl` because it
66// will crash the unit test (because in that case, when the
67// `MachineLearningServiceImpl` object is destructed, the file will be
68// unmapped but the icu data can not be reset in the testing process).
69base::MemoryMappedFile* g_icu_data_mmap_file = nullptr;
70
71void InitIcuIfNeeded() {
72 if (!g_icu_data_mmap_file) {
73 g_icu_data_mmap_file = new base::MemoryMappedFile();
74 CHECK(g_icu_data_mmap_file->Initialize(
75 base::FilePath(kIcuDataFilePath),
76 base::MemoryMappedFile::Access::READ_ONLY));
77 // Init the Icu library.
78 UErrorCode err = U_ZERO_ERROR;
79 udata_setCommonData(const_cast<uint8_t*>(g_icu_data_mmap_file->data()),
80 &err);
81 DCHECK(err == U_ZERO_ERROR);
82 // Never try to load Icu data from files.
83 udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
84 DCHECK(err == U_ZERO_ERROR);
85 }
86}
87
Honglin Yu0f5b21d2021-04-06 23:39:04 +100088// Used to avoid duplicating code between two types of recognizers.
89// Currently used in function `LoadHandwritingModelFromDir`.
90template <class Recognizer>
91struct RecognizerTraits;
92
93template <>
94struct RecognizerTraits<HandwritingRecognizer> {
95 using SpecPtr = HandwritingRecognizerSpecPtr;
96 using Callback = MachineLearningServiceImpl::LoadHandwritingModelCallback;
97 using Impl = HandwritingRecognizerImpl;
98};
99
100template <>
101struct RecognizerTraits<
102 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer> {
103 using SpecPtr = chromeos::machine_learning::web_platform::mojom::
104 HandwritingModelConstraintPtr;
105 using Callback =
106 MachineLearningServiceImpl::LoadWebPlatformHandwritingModelCallback;
107 using Impl = WebPlatformHandwritingRecognizerImpl;
108};
109
Michael Martisa74af932018-08-13 16:52:36 +1000110} // namespace
111
Andrew Moylanff6be512018-07-03 11:05:01 +1000112MachineLearningServiceImpl::MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900113 mojo::PendingReceiver<
114 chromeos::machine_learning::mojom::MachineLearningService> receiver,
Andrew Moylanb481af72020-07-09 15:22:00 +1000115 base::Closure disconnect_handler,
Michael Martisa74af932018-08-13 16:52:36 +1000116 const std::string& model_dir)
Honglin Yu20391cd2020-10-27 15:58:49 +1100117 : builtin_model_metadata_(GetBuiltinModelMetadata()),
Michael Martisa74af932018-08-13 16:52:36 +1000118 model_dir_(model_dir),
hschamd13deea2021-03-08 09:46:15 +0900119 receiver_(this, std::move(receiver)) {
Andrew Moylanb481af72020-07-09 15:22:00 +1000120 receiver_.set_disconnect_handler(std::move(disconnect_handler));
Andrew Moylanff6be512018-07-03 11:05:01 +1000121}
122
Michael Martisa74af932018-08-13 16:52:36 +1000123MachineLearningServiceImpl::MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900124 mojo::PendingReceiver<
125 chromeos::machine_learning::mojom::MachineLearningService> receiver,
Charles Zhaod4fb7b62020-08-25 17:21:58 +1000126 base::Closure disconnect_handler,
127 dbus::Bus* bus)
Andrew Moylanb481af72020-07-09 15:22:00 +1000128 : MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900129 std::move(receiver), std::move(disconnect_handler), kSystemModelDir) {
Charles Zhaod4fb7b62020-08-25 17:21:58 +1000130 if (bus) {
131 dlcservice_client_ = std::make_unique<DlcserviceClient>(bus);
132 }
133}
Michael Martisa74af932018-08-13 16:52:36 +1000134
Andrew Moylanb481af72020-07-09 15:22:00 +1000135void MachineLearningServiceImpl::Clone(
136 mojo::PendingReceiver<MachineLearningService> receiver) {
137 clone_receivers_.Add(this, std::move(receiver));
Andrew Moylan2fb80af2020-07-08 10:52:08 +1000138}
139
Honglin Yu0ed72352019-08-27 17:42:01 +1000140void MachineLearningServiceImpl::LoadBuiltinModel(
141 BuiltinModelSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000142 mojo::PendingReceiver<Model> receiver,
Qijiang Fan5d381a02020-04-19 23:42:37 +0900143 LoadBuiltinModelCallback callback) {
Honglin Yu0ed72352019-08-27 17:42:01 +1000144 // Unsupported models do not have metadata entries.
145 const auto metadata_lookup = builtin_model_metadata_.find(spec->id);
146 if (metadata_lookup == builtin_model_metadata_.end()) {
Honglin Yua81145a2019-09-23 15:20:13 +1000147 LOG(WARNING) << "LoadBuiltinModel requested for unsupported model ID "
148 << spec->id << ".";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900149 std::move(callback).Run(LoadModelResult::MODEL_SPEC_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000150 RecordModelSpecificationErrorEvent();
151 return;
152 }
153
154 const BuiltinModelMetadata& metadata = metadata_lookup->second;
155
156 DCHECK(!metadata.metrics_model_name.empty());
157
charleszhao5a7050e2020-07-14 15:21:41 +1000158 RequestMetrics request_metrics(metadata.metrics_model_name,
159 kMetricsRequestName);
Honglin Yu0ed72352019-08-27 17:42:01 +1000160 request_metrics.StartRecordingPerformanceMetrics();
161
162 // Attempt to load model.
163 const std::string model_path = model_dir_ + metadata.model_file;
164 std::unique_ptr<tflite::FlatBufferModel> model =
165 tflite::FlatBufferModel::BuildFromFile(model_path.c_str());
166 if (model == nullptr) {
167 LOG(ERROR) << "Failed to load model file '" << model_path << "'.";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900168 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000169 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
170 return;
171 }
172
Honglin Yuc0cef102020-01-17 15:26:01 +1100173 ModelImpl::Create(metadata.required_inputs, metadata.required_outputs,
Andrew Moylanb481af72020-07-09 15:22:00 +1000174 std::move(model), std::move(receiver),
Honglin Yuc0cef102020-01-17 15:26:01 +1100175 metadata.metrics_model_name);
Honglin Yu0ed72352019-08-27 17:42:01 +1000176
Qijiang Fan5d381a02020-04-19 23:42:37 +0900177 std::move(callback).Run(LoadModelResult::OK);
Honglin Yu0ed72352019-08-27 17:42:01 +1000178
179 request_metrics.FinishRecordingPerformanceMetrics();
180 request_metrics.RecordRequestEvent(LoadModelResult::OK);
181}
182
183void MachineLearningServiceImpl::LoadFlatBufferModel(
184 FlatBufferModelSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000185 mojo::PendingReceiver<Model> receiver,
Qijiang Fan5d381a02020-04-19 23:42:37 +0900186 LoadFlatBufferModelCallback callback) {
Honglin Yu0ed72352019-08-27 17:42:01 +1000187 DCHECK(!spec->metrics_model_name.empty());
188
charleszhao5a7050e2020-07-14 15:21:41 +1000189 RequestMetrics request_metrics(spec->metrics_model_name, kMetricsRequestName);
Honglin Yu0ed72352019-08-27 17:42:01 +1000190 request_metrics.StartRecordingPerformanceMetrics();
191
Andrew Moylan79b34a42020-07-08 11:13:11 +1000192 // Take the ownership of the content of `model_string` because `ModelImpl` has
Honglin Yu0ed72352019-08-27 17:42:01 +1000193 // to hold the memory.
Andrew Moylan44c352f2020-11-04 15:19:46 +1100194 auto model_data =
195 std::make_unique<AlignedModelData>(std::move(spec->model_string));
Honglin Yu0ed72352019-08-27 17:42:01 +1000196
197 std::unique_ptr<tflite::FlatBufferModel> model =
Andrew Moylan44c352f2020-11-04 15:19:46 +1100198 tflite::FlatBufferModel::VerifyAndBuildFromBuffer(model_data->data(),
199 model_data->size());
Honglin Yu0ed72352019-08-27 17:42:01 +1000200 if (model == nullptr) {
201 LOG(ERROR) << "Failed to load model string of metric name: "
202 << spec->metrics_model_name << "'.";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900203 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000204 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
205 return;
206 }
207
Honglin Yuc0cef102020-01-17 15:26:01 +1100208 ModelImpl::Create(
Honglin Yu0ed72352019-08-27 17:42:01 +1000209 std::map<std::string, int>(spec->inputs.begin(), spec->inputs.end()),
210 std::map<std::string, int>(spec->outputs.begin(), spec->outputs.end()),
Andrew Moylan44c352f2020-11-04 15:19:46 +1100211 std::move(model), std::move(model_data), std::move(receiver),
Honglin Yu0ed72352019-08-27 17:42:01 +1000212 spec->metrics_model_name);
213
Qijiang Fan5d381a02020-04-19 23:42:37 +0900214 std::move(callback).Run(LoadModelResult::OK);
Honglin Yu0ed72352019-08-27 17:42:01 +1000215
216 request_metrics.FinishRecordingPerformanceMetrics();
217 request_metrics.RecordRequestEvent(LoadModelResult::OK);
218}
219
Honglin Yuf33dce32019-12-05 15:10:39 +1100220void MachineLearningServiceImpl::LoadTextClassifier(
Andrew Moylanb481af72020-07-09 15:22:00 +1000221 mojo::PendingReceiver<TextClassifier> receiver,
Honglin Yuf33dce32019-12-05 15:10:39 +1100222 LoadTextClassifierCallback callback) {
charleszhao5a7050e2020-07-14 15:21:41 +1000223 RequestMetrics request_metrics("TextClassifier", kMetricsRequestName);
Honglin Yuf33dce32019-12-05 15:10:39 +1100224 request_metrics.StartRecordingPerformanceMetrics();
225
Honglin Yuf33dce32019-12-05 15:10:39 +1100226 // Create the TextClassifier.
Honglin Yu3f99ff12020-10-15 00:40:11 +1100227 if (!TextClassifierImpl::Create(std::move(receiver))) {
Honglin Yuf33dce32019-12-05 15:10:39 +1100228 LOG(ERROR) << "Failed to create TextClassifierImpl object.";
229 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
230 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
231 return;
232 }
233
234 // initialize the icu library.
235 InitIcuIfNeeded();
236
237 std::move(callback).Run(LoadModelResult::OK);
238
239 request_metrics.FinishRecordingPerformanceMetrics();
240 request_metrics.RecordRequestEvent(LoadModelResult::OK);
241}
242
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000243template <class Recognizer>
Charles Zhao6d467e62020-08-31 10:02:03 +1000244void LoadHandwritingModelFromDir(
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000245 typename RecognizerTraits<Recognizer>::SpecPtr spec,
246 mojo::PendingReceiver<Recognizer> receiver,
247 typename RecognizerTraits<Recognizer>::Callback callback,
Charles Zhao6d467e62020-08-31 10:02:03 +1000248 const std::string& root_path) {
249 RequestMetrics request_metrics("HandwritingModel", kMetricsRequestName);
250 request_metrics.StartRecordingPerformanceMetrics();
251
252 // Returns error if root_path is empty.
253 if (root_path.empty()) {
254 std::move(callback).Run(LoadHandwritingModelResult::DLC_GET_PATH_ERROR);
255 request_metrics.RecordRequestEvent(
256 LoadHandwritingModelResult::DLC_GET_PATH_ERROR);
257 return;
258 }
259
260 // Load HandwritingLibrary.
261 auto* const hwr_library = ml::HandwritingLibrary::GetInstance(root_path);
262
263 if (hwr_library->GetStatus() != ml::HandwritingLibrary::Status::kOk) {
264 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
265 << static_cast<int>(hwr_library->GetStatus());
266
267 switch (hwr_library->GetStatus()) {
268 case ml::HandwritingLibrary::Status::kLoadLibraryFailed: {
269 std::move(callback).Run(
270 LoadHandwritingModelResult::LOAD_NATIVE_LIB_ERROR);
271 request_metrics.RecordRequestEvent(
272 LoadHandwritingModelResult::LOAD_NATIVE_LIB_ERROR);
273 return;
274 }
275 case ml::HandwritingLibrary::Status::kFunctionLookupFailed: {
276 std::move(callback).Run(
277 LoadHandwritingModelResult::LOAD_FUNC_PTR_ERROR);
278 request_metrics.RecordRequestEvent(
279 LoadHandwritingModelResult::LOAD_FUNC_PTR_ERROR);
280 return;
281 }
282 default: {
283 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
284 request_metrics.RecordRequestEvent(
285 LoadHandwritingModelResult::LOAD_MODEL_ERROR);
286 return;
287 }
288 }
289 }
290
291 // Create HandwritingRecognizer.
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000292 if (!RecognizerTraits<Recognizer>::Impl::Create(std::move(spec),
293 std::move(receiver))) {
Charles Zhao6d467e62020-08-31 10:02:03 +1000294 LOG(ERROR) << "LoadHandwritingRecognizer returned false.";
295 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
296 request_metrics.RecordRequestEvent(
297 LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
298 return;
299 }
300
301 std::move(callback).Run(LoadHandwritingModelResult::OK);
302 request_metrics.FinishRecordingPerformanceMetrics();
303 request_metrics.RecordRequestEvent(LoadHandwritingModelResult::OK);
304}
305
306void MachineLearningServiceImpl::LoadHandwritingModel(
307 chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr spec,
308 mojo::PendingReceiver<
309 chromeos::machine_learning::mojom::HandwritingRecognizer> receiver,
310 LoadHandwritingModelCallback callback) {
311 // If handwriting is installed on rootfs, load it from there.
312 if (ml::HandwritingLibrary::IsUseLibHandwritingEnabled()) {
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000313 LoadHandwritingModelFromDir<HandwritingRecognizer>(
Charles Zhao6d467e62020-08-31 10:02:03 +1000314 std::move(spec), std::move(receiver), std::move(callback),
315 ml::HandwritingLibrary::kHandwritingDefaultModelDir);
316 return;
317 }
318
319 // If handwriting is installed as DLC, get the dir and subsequently load it
320 // from there.
321 if (ml::HandwritingLibrary::IsUseLibHandwritingDlcEnabled()) {
322 dlcservice_client_->GetDlcRootPath(
323 "libhandwriting",
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000324 base::BindOnce(&LoadHandwritingModelFromDir<HandwritingRecognizer>,
325 std::move(spec), std::move(receiver),
326 std::move(callback)));
Charles Zhao6d467e62020-08-31 10:02:03 +1000327 return;
328 }
329
330 // If handwriting is not on rootfs and not in DLC, this function should not
331 // be called.
332 LOG(ERROR) << "Calling LoadHandwritingModel without Handwriting enabled "
333 "should never happen.";
334 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
charleszhao05c5a4a2020-06-09 16:49:54 +1000335}
336
337void MachineLearningServiceImpl::LoadHandwritingModelWithSpec(
338 HandwritingRecognizerSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000339 mojo::PendingReceiver<HandwritingRecognizer> receiver,
Charles Zhaoc882eb02020-07-27 10:02:35 +1000340 LoadHandwritingModelWithSpecCallback callback) {
charleszhao5a7050e2020-07-14 15:21:41 +1000341 RequestMetrics request_metrics("HandwritingModel", kMetricsRequestName);
charleszhao17777f92020-04-23 12:53:11 +1000342 request_metrics.StartRecordingPerformanceMetrics();
343
344 // Load HandwritingLibrary.
345 auto* const hwr_library = ml::HandwritingLibrary::GetInstance();
346
347 if (hwr_library->GetStatus() ==
348 ml::HandwritingLibrary::Status::kNotSupported) {
349 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
350 << static_cast<int>(hwr_library->GetStatus());
351
352 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
353 request_metrics.RecordRequestEvent(
354 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
355 return;
356 }
357
358 if (hwr_library->GetStatus() != ml::HandwritingLibrary::Status::kOk) {
359 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
360 << static_cast<int>(hwr_library->GetStatus());
361
362 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
363 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
364 return;
365 }
366
367 // Create HandwritingRecognizer.
Andrew Moylanb481af72020-07-09 15:22:00 +1000368 if (!HandwritingRecognizerImpl::Create(std::move(spec),
369 std::move(receiver))) {
charleszhao17777f92020-04-23 12:53:11 +1000370 LOG(ERROR) << "LoadHandwritingRecognizer returned false.";
371 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
372 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
373 return;
374 }
375
376 std::move(callback).Run(LoadModelResult::OK);
377 request_metrics.FinishRecordingPerformanceMetrics();
378 request_metrics.RecordRequestEvent(LoadModelResult::OK);
379}
380
Honglin Yud2204272020-08-26 14:21:37 +1000381void MachineLearningServiceImpl::LoadSpeechRecognizer(
382 SodaConfigPtr config,
383 mojo::PendingRemote<SodaClient> soda_client,
384 mojo::PendingReceiver<SodaRecognizer> soda_recognizer,
385 LoadSpeechRecognizerCallback callback) {
386 RequestMetrics request_metrics("Soda", kMetricsRequestName);
387 request_metrics.StartRecordingPerformanceMetrics();
388
389 // Create the SodaRecognizer.
390 if (!SodaRecognizerImpl::Create(std::move(config), std::move(soda_client),
391 std::move(soda_recognizer))) {
392 LOG(ERROR) << "Failed to create SodaRecognizerImpl object.";
393 // TODO(robsc): it may be better that SODA has its specific enum values to
394 // return, similar to handwriting. So before we finalize the impl of SODA
395 // Mojo API, we may revisit this return value.
396 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
397 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
398 return;
399 }
400
401 std::move(callback).Run(LoadModelResult::OK);
402
403 request_metrics.FinishRecordingPerformanceMetrics();
404 request_metrics.RecordRequestEvent(LoadModelResult::OK);
405}
406
Jing Wang961b8af2020-10-26 12:40:35 +1100407void MachineLearningServiceImpl::LoadGrammarChecker(
408 mojo::PendingReceiver<chromeos::machine_learning::mojom::GrammarChecker>
409 receiver,
410 LoadGrammarCheckerCallback callback) {
411 RequestMetrics request_metrics("GrammarChecker", kMetricsRequestName);
412 request_metrics.StartRecordingPerformanceMetrics();
413
414 // Load GrammarLibrary.
415 auto* const grammar_library = ml::GrammarLibrary::GetInstance();
416
417 if (grammar_library->GetStatus() ==
418 ml::GrammarLibrary::Status::kNotSupported) {
419 LOG(ERROR) << "Initialize ml::GrammarLibrary with error "
420 << static_cast<int>(grammar_library->GetStatus());
421
422 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
423 request_metrics.RecordRequestEvent(
424 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
425 return;
426 }
427
428 if (grammar_library->GetStatus() != ml::GrammarLibrary::Status::kOk) {
429 LOG(ERROR) << "Initialize ml::GrammarLibrary with error "
430 << static_cast<int>(grammar_library->GetStatus());
431
432 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
433 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
434 return;
435 }
436
437 // Create GrammarChecker.
438 if (!GrammarCheckerImpl::Create(std::move(receiver))) {
439 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
440 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
441 return;
442 }
443
444 std::move(callback).Run(LoadModelResult::OK);
445
446 request_metrics.FinishRecordingPerformanceMetrics();
447 request_metrics.RecordRequestEvent(LoadModelResult::OK);
448}
449
Curtis McMullanf11584f2021-01-13 12:21:36 +1100450void MachineLearningServiceImpl::LoadTextSuggester(
451 mojo::PendingReceiver<chromeos::machine_learning::mojom::TextSuggester>
452 receiver,
453 LoadTextSuggesterCallback callback) {
454 RequestMetrics request_metrics("TextSuggester", kMetricsRequestName);
455 request_metrics.StartRecordingPerformanceMetrics();
456
457 // Load TextSuggestions library.
458 auto* const text_suggestions = ml::TextSuggestions::GetInstance();
459
460 if (text_suggestions->GetStatus() ==
461 ml::TextSuggestions::Status::kNotSupported) {
462 LOG(ERROR) << "Initialize ml::TextSuggestions with error "
463 << static_cast<int>(text_suggestions->GetStatus());
464
465 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
466 request_metrics.RecordRequestEvent(
467 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
468 return;
469 }
470
471 if (text_suggestions->GetStatus() != ml::TextSuggestions::Status::kOk) {
472 LOG(ERROR) << "Initialize ml::TextSuggestions with error "
473 << static_cast<int>(text_suggestions->GetStatus());
474
475 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
476 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
477 return;
478 }
479
480 // Create TextSuggester.
481 if (!TextSuggesterImpl::Create(std::move(receiver))) {
482 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
483 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
484 return;
485 }
486
487 std::move(callback).Run(LoadModelResult::OK);
488
489 request_metrics.FinishRecordingPerformanceMetrics();
490 request_metrics.RecordRequestEvent(LoadModelResult::OK);
491}
492
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000493void MachineLearningServiceImpl::LoadWebPlatformHandwritingModel(
494 chromeos::machine_learning::web_platform::mojom::
495 HandwritingModelConstraintPtr constraint,
496 mojo::PendingReceiver<
497 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer>
498 receiver,
499 LoadWebPlatformHandwritingModelCallback callback) {
500 // If handwriting is installed on rootfs, load it from there.
501 if (ml::HandwritingLibrary::IsUseLibHandwritingEnabled()) {
502 LoadHandwritingModelFromDir<
503 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer>(
504 std::move(constraint), std::move(receiver), std::move(callback),
505 ml::HandwritingLibrary::kHandwritingDefaultModelDir);
506 return;
507 }
508
509 // If handwriting is installed as DLC, get the dir and subsequently load it
510 // from there.
511 if (ml::HandwritingLibrary::IsUseLibHandwritingDlcEnabled()) {
512 dlcservice_client_->GetDlcRootPath(
513 "libhandwriting",
514 base::BindOnce(&LoadHandwritingModelFromDir<
515 chromeos::machine_learning::web_platform::mojom::
516 HandwritingRecognizer>,
517 std::move(constraint), std::move(receiver),
518 std::move(callback)));
519 return;
520 }
521
522 // If handwriting is not on rootfs and not in DLC, this function should not
523 // be called.
524 LOG(ERROR) << "Calling LoadWebPlatformHandwritingModel without Handwriting "
525 "enabled should never happen.";
526 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
527}
528
Andrew Moylanff6be512018-07-03 11:05:01 +1000529} // namespace ml