blob: 277d46d7aa2b7344790020ba9525fe35923028be [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
Honglin Yu7b6c1192020-09-16 10:07:17 +100010#include <unistd.h>
11
Michael Martisa74af932018-08-13 16:52:36 +100012#include <base/bind.h>
hscham4ce3c992021-02-19 16:37:23 +090013#include <base/callback_helpers.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090014#include <base/check.h>
Honglin Yuf33dce32019-12-05 15:10:39 +110015#include <base/files/file.h>
16#include <base/files/file_util.h>
Honglin Yu20391cd2020-10-27 15:58:49 +110017#include <base/files/memory_mapped_file.h>
Michael Martis8783c8e2019-06-26 17:30:54 +100018#include <tensorflow/lite/model.h>
Honglin Yuf33dce32019-12-05 15:10:39 +110019#include <unicode/putil.h>
20#include <unicode/udata.h>
21#include <utils/memory/mmap.h>
Michael Martisa74af932018-08-13 16:52:36 +100022
Jing Wang961b8af2020-10-26 12:40:35 +110023#include "ml/grammar_checker_impl.h"
24#include "ml/grammar_library.h"
charleszhao17777f92020-04-23 12:53:11 +100025#include "ml/handwriting.h"
26#include "ml/handwriting_recognizer_impl.h"
Michael Martisa74af932018-08-13 16:52:36 +100027#include "ml/model_impl.h"
charleszhao17777f92020-04-23 12:53:11 +100028#include "ml/mojom/handwriting_recognizer.mojom.h"
Hidehiko Abeaa488c32018-08-31 23:49:41 +090029#include "ml/mojom/model.mojom.h"
Honglin Yud2204272020-08-26 14:21:37 +100030#include "ml/mojom/soda.mojom.h"
Honglin Yu0f5b21d2021-04-06 23:39:04 +100031#include "ml/mojom/web_platform_handwriting.mojom.h"
Honglin Yu7b6c1192020-09-16 10:07:17 +100032#include "ml/process.h"
Andrew Moylan44c352f2020-11-04 15:19:46 +110033#include "ml/request_metrics.h"
Honglin Yud2204272020-08-26 14:21:37 +100034#include "ml/soda_recognizer_impl.h"
Honglin Yuf33dce32019-12-05 15:10:39 +110035#include "ml/text_classifier_impl.h"
Curtis McMullanf11584f2021-01-13 12:21:36 +110036#include "ml/text_suggester_impl.h"
37#include "ml/text_suggestions.h"
Honglin Yu0f5b21d2021-04-06 23:39:04 +100038#include "ml/web_platform_handwriting_recognizer_impl.h"
Michael Martisa74af932018-08-13 16:52:36 +100039
Andrew Moylanff6be512018-07-03 11:05:01 +100040namespace ml {
41
Michael Martisa74af932018-08-13 16:52:36 +100042namespace {
43
Honglin Yu0ed72352019-08-27 17:42:01 +100044using ::chromeos::machine_learning::mojom::BuiltinModelId;
45using ::chromeos::machine_learning::mojom::BuiltinModelSpecPtr;
46using ::chromeos::machine_learning::mojom::FlatBufferModelSpecPtr;
Andrew Moylanb481af72020-07-09 15:22:00 +100047using ::chromeos::machine_learning::mojom::HandwritingRecognizer;
charleszhao05c5a4a2020-06-09 16:49:54 +100048using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpec;
49using ::chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr;
Charles Zhao6d467e62020-08-31 10:02:03 +100050using ::chromeos::machine_learning::mojom::LoadHandwritingModelResult;
Michael Martisa74af932018-08-13 16:52:36 +100051using ::chromeos::machine_learning::mojom::LoadModelResult;
Andrew Moylanb481af72020-07-09 15:22:00 +100052using ::chromeos::machine_learning::mojom::MachineLearningService;
53using ::chromeos::machine_learning::mojom::Model;
Honglin Yud2204272020-08-26 14:21:37 +100054using ::chromeos::machine_learning::mojom::SodaClient;
55using ::chromeos::machine_learning::mojom::SodaConfigPtr;
56using ::chromeos::machine_learning::mojom::SodaRecognizer;
Andrew Moylanb481af72020-07-09 15:22:00 +100057using ::chromeos::machine_learning::mojom::TextClassifier;
Michael Martisa74af932018-08-13 16:52:36 +100058
59constexpr char kSystemModelDir[] = "/opt/google/chrome/ml_models/";
Andrew Moylan79b34a42020-07-08 11:13:11 +100060// Base name for UMA metrics related to model loading (`LoadBuiltinModel`,
61// `LoadFlatBufferModel`, `LoadTextClassifier` or LoadHandwritingModel).
Honglin Yu6adafcd2019-07-22 13:48:11 +100062constexpr char kMetricsRequestName[] = "LoadModelResult";
Michael Martisa74af932018-08-13 16:52:36 +100063
Honglin Yuf33dce32019-12-05 15:10:39 +110064constexpr char kIcuDataFilePath[] = "/opt/google/chrome/icudtl.dat";
65
Honglin Yu20391cd2020-10-27 15:58:49 +110066// Used to hold the mmap object of the icu data file. Each process should only
67// have one instance of it. Intentionally never close it.
68// We can not make it as a member of `MachineLearningServiceImpl` because it
69// will crash the unit test (because in that case, when the
70// `MachineLearningServiceImpl` object is destructed, the file will be
71// unmapped but the icu data can not be reset in the testing process).
72base::MemoryMappedFile* g_icu_data_mmap_file = nullptr;
73
74void InitIcuIfNeeded() {
75 if (!g_icu_data_mmap_file) {
76 g_icu_data_mmap_file = new base::MemoryMappedFile();
77 CHECK(g_icu_data_mmap_file->Initialize(
78 base::FilePath(kIcuDataFilePath),
79 base::MemoryMappedFile::Access::READ_ONLY));
80 // Init the Icu library.
81 UErrorCode err = U_ZERO_ERROR;
82 udata_setCommonData(const_cast<uint8_t*>(g_icu_data_mmap_file->data()),
83 &err);
84 DCHECK(err == U_ZERO_ERROR);
85 // Never try to load Icu data from files.
86 udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
87 DCHECK(err == U_ZERO_ERROR);
88 }
89}
90
Honglin Yu0f5b21d2021-04-06 23:39:04 +100091// Used to avoid duplicating code between two types of recognizers.
92// Currently used in function `LoadHandwritingModelFromDir`.
93template <class Recognizer>
94struct RecognizerTraits;
95
96template <>
97struct RecognizerTraits<HandwritingRecognizer> {
98 using SpecPtr = HandwritingRecognizerSpecPtr;
99 using Callback = MachineLearningServiceImpl::LoadHandwritingModelCallback;
100 using Impl = HandwritingRecognizerImpl;
Honglin Yu7b6c1192020-09-16 10:07:17 +1000101 static constexpr char kModelName[] = "HandwritingModel";
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000102};
103
104template <>
105struct RecognizerTraits<
106 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer> {
107 using SpecPtr = chromeos::machine_learning::web_platform::mojom::
108 HandwritingModelConstraintPtr;
109 using Callback =
110 MachineLearningServiceImpl::LoadWebPlatformHandwritingModelCallback;
111 using Impl = WebPlatformHandwritingRecognizerImpl;
Honglin Yu7b6c1192020-09-16 10:07:17 +1000112 static constexpr char kModelName[] = "WebPlatformHandwritingModel";
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000113};
114
Michael Martisa74af932018-08-13 16:52:36 +1000115} // namespace
116
Andrew Moylanff6be512018-07-03 11:05:01 +1000117MachineLearningServiceImpl::MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900118 mojo::PendingReceiver<
119 chromeos::machine_learning::mojom::MachineLearningService> receiver,
Andrew Moylanb481af72020-07-09 15:22:00 +1000120 base::Closure disconnect_handler,
Michael Martisa74af932018-08-13 16:52:36 +1000121 const std::string& model_dir)
Honglin Yu20391cd2020-10-27 15:58:49 +1100122 : builtin_model_metadata_(GetBuiltinModelMetadata()),
Michael Martisa74af932018-08-13 16:52:36 +1000123 model_dir_(model_dir),
hschamd13deea2021-03-08 09:46:15 +0900124 receiver_(this, std::move(receiver)) {
Andrew Moylanb481af72020-07-09 15:22:00 +1000125 receiver_.set_disconnect_handler(std::move(disconnect_handler));
Andrew Moylanff6be512018-07-03 11:05:01 +1000126}
127
Michael Martisa74af932018-08-13 16:52:36 +1000128MachineLearningServiceImpl::MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900129 mojo::PendingReceiver<
130 chromeos::machine_learning::mojom::MachineLearningService> receiver,
Charles Zhaod4fb7b62020-08-25 17:21:58 +1000131 base::Closure disconnect_handler,
132 dbus::Bus* bus)
Andrew Moylanb481af72020-07-09 15:22:00 +1000133 : MachineLearningServiceImpl(
hschamd13deea2021-03-08 09:46:15 +0900134 std::move(receiver), std::move(disconnect_handler), kSystemModelDir) {
Charles Zhaod4fb7b62020-08-25 17:21:58 +1000135 if (bus) {
136 dlcservice_client_ = std::make_unique<DlcserviceClient>(bus);
137 }
138}
Michael Martisa74af932018-08-13 16:52:36 +1000139
Andrew Moylanb481af72020-07-09 15:22:00 +1000140void MachineLearningServiceImpl::Clone(
141 mojo::PendingReceiver<MachineLearningService> receiver) {
142 clone_receivers_.Add(this, std::move(receiver));
Andrew Moylan2fb80af2020-07-08 10:52:08 +1000143}
144
Honglin Yu0ed72352019-08-27 17:42:01 +1000145void MachineLearningServiceImpl::LoadBuiltinModel(
146 BuiltinModelSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000147 mojo::PendingReceiver<Model> receiver,
Qijiang Fan5d381a02020-04-19 23:42:37 +0900148 LoadBuiltinModelCallback callback) {
Honglin Yu0ed72352019-08-27 17:42:01 +1000149 // Unsupported models do not have metadata entries.
150 const auto metadata_lookup = builtin_model_metadata_.find(spec->id);
151 if (metadata_lookup == builtin_model_metadata_.end()) {
Honglin Yua81145a2019-09-23 15:20:13 +1000152 LOG(WARNING) << "LoadBuiltinModel requested for unsupported model ID "
153 << spec->id << ".";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900154 std::move(callback).Run(LoadModelResult::MODEL_SPEC_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000155 RecordModelSpecificationErrorEvent();
156 return;
157 }
158
159 const BuiltinModelMetadata& metadata = metadata_lookup->second;
160
161 DCHECK(!metadata.metrics_model_name.empty());
162
charleszhao5a7050e2020-07-14 15:21:41 +1000163 RequestMetrics request_metrics(metadata.metrics_model_name,
164 kMetricsRequestName);
Honglin Yu0ed72352019-08-27 17:42:01 +1000165 request_metrics.StartRecordingPerformanceMetrics();
166
167 // Attempt to load model.
168 const std::string model_path = model_dir_ + metadata.model_file;
169 std::unique_ptr<tflite::FlatBufferModel> model =
170 tflite::FlatBufferModel::BuildFromFile(model_path.c_str());
171 if (model == nullptr) {
172 LOG(ERROR) << "Failed to load model file '" << model_path << "'.";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900173 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000174 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
175 return;
176 }
177
Honglin Yuc0cef102020-01-17 15:26:01 +1100178 ModelImpl::Create(metadata.required_inputs, metadata.required_outputs,
Andrew Moylanb481af72020-07-09 15:22:00 +1000179 std::move(model), std::move(receiver),
Honglin Yuc0cef102020-01-17 15:26:01 +1100180 metadata.metrics_model_name);
Honglin Yu0ed72352019-08-27 17:42:01 +1000181
Qijiang Fan5d381a02020-04-19 23:42:37 +0900182 std::move(callback).Run(LoadModelResult::OK);
Honglin Yu0ed72352019-08-27 17:42:01 +1000183
184 request_metrics.FinishRecordingPerformanceMetrics();
185 request_metrics.RecordRequestEvent(LoadModelResult::OK);
186}
187
188void MachineLearningServiceImpl::LoadFlatBufferModel(
189 FlatBufferModelSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000190 mojo::PendingReceiver<Model> receiver,
Qijiang Fan5d381a02020-04-19 23:42:37 +0900191 LoadFlatBufferModelCallback callback) {
Honglin Yu0ed72352019-08-27 17:42:01 +1000192 DCHECK(!spec->metrics_model_name.empty());
193
charleszhao5a7050e2020-07-14 15:21:41 +1000194 RequestMetrics request_metrics(spec->metrics_model_name, kMetricsRequestName);
Honglin Yu0ed72352019-08-27 17:42:01 +1000195 request_metrics.StartRecordingPerformanceMetrics();
196
Andrew Moylan79b34a42020-07-08 11:13:11 +1000197 // Take the ownership of the content of `model_string` because `ModelImpl` has
Honglin Yu0ed72352019-08-27 17:42:01 +1000198 // to hold the memory.
Andrew Moylan44c352f2020-11-04 15:19:46 +1100199 auto model_data =
200 std::make_unique<AlignedModelData>(std::move(spec->model_string));
Honglin Yu0ed72352019-08-27 17:42:01 +1000201
202 std::unique_ptr<tflite::FlatBufferModel> model =
Andrew Moylan44c352f2020-11-04 15:19:46 +1100203 tflite::FlatBufferModel::VerifyAndBuildFromBuffer(model_data->data(),
204 model_data->size());
Honglin Yu0ed72352019-08-27 17:42:01 +1000205 if (model == nullptr) {
206 LOG(ERROR) << "Failed to load model string of metric name: "
207 << spec->metrics_model_name << "'.";
Qijiang Fan5d381a02020-04-19 23:42:37 +0900208 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
Honglin Yu0ed72352019-08-27 17:42:01 +1000209 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
210 return;
211 }
212
Honglin Yuc0cef102020-01-17 15:26:01 +1100213 ModelImpl::Create(
Honglin Yu0ed72352019-08-27 17:42:01 +1000214 std::map<std::string, int>(spec->inputs.begin(), spec->inputs.end()),
215 std::map<std::string, int>(spec->outputs.begin(), spec->outputs.end()),
Andrew Moylan44c352f2020-11-04 15:19:46 +1100216 std::move(model), std::move(model_data), std::move(receiver),
Honglin Yu0ed72352019-08-27 17:42:01 +1000217 spec->metrics_model_name);
218
Qijiang Fan5d381a02020-04-19 23:42:37 +0900219 std::move(callback).Run(LoadModelResult::OK);
Honglin Yu0ed72352019-08-27 17:42:01 +1000220
221 request_metrics.FinishRecordingPerformanceMetrics();
222 request_metrics.RecordRequestEvent(LoadModelResult::OK);
223}
224
Honglin Yuf33dce32019-12-05 15:10:39 +1100225void MachineLearningServiceImpl::LoadTextClassifier(
Andrew Moylanb481af72020-07-09 15:22:00 +1000226 mojo::PendingReceiver<TextClassifier> receiver,
Honglin Yuf33dce32019-12-05 15:10:39 +1100227 LoadTextClassifierCallback callback) {
charleszhao5a7050e2020-07-14 15:21:41 +1000228 RequestMetrics request_metrics("TextClassifier", kMetricsRequestName);
Honglin Yuf33dce32019-12-05 15:10:39 +1100229 request_metrics.StartRecordingPerformanceMetrics();
230
Honglin Yuf33dce32019-12-05 15:10:39 +1100231 // Create the TextClassifier.
Honglin Yu3f99ff12020-10-15 00:40:11 +1100232 if (!TextClassifierImpl::Create(std::move(receiver))) {
Honglin Yuf33dce32019-12-05 15:10:39 +1100233 LOG(ERROR) << "Failed to create TextClassifierImpl object.";
234 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
235 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
236 return;
237 }
238
239 // initialize the icu library.
240 InitIcuIfNeeded();
241
242 std::move(callback).Run(LoadModelResult::OK);
243
244 request_metrics.FinishRecordingPerformanceMetrics();
245 request_metrics.RecordRequestEvent(LoadModelResult::OK);
246}
247
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000248template <class Recognizer>
Charles Zhao6d467e62020-08-31 10:02:03 +1000249void LoadHandwritingModelFromDir(
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000250 typename RecognizerTraits<Recognizer>::SpecPtr spec,
251 mojo::PendingReceiver<Recognizer> receiver,
252 typename RecognizerTraits<Recognizer>::Callback callback,
Charles Zhao6d467e62020-08-31 10:02:03 +1000253 const std::string& root_path) {
Honglin Yu7b6c1192020-09-16 10:07:17 +1000254 RequestMetrics request_metrics(RecognizerTraits<Recognizer>::kModelName,
255 kMetricsRequestName);
Charles Zhao6d467e62020-08-31 10:02:03 +1000256 request_metrics.StartRecordingPerformanceMetrics();
257
258 // Returns error if root_path is empty.
259 if (root_path.empty()) {
260 std::move(callback).Run(LoadHandwritingModelResult::DLC_GET_PATH_ERROR);
261 request_metrics.RecordRequestEvent(
262 LoadHandwritingModelResult::DLC_GET_PATH_ERROR);
263 return;
264 }
265
266 // Load HandwritingLibrary.
267 auto* const hwr_library = ml::HandwritingLibrary::GetInstance(root_path);
268
269 if (hwr_library->GetStatus() != ml::HandwritingLibrary::Status::kOk) {
270 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
271 << static_cast<int>(hwr_library->GetStatus());
272
273 switch (hwr_library->GetStatus()) {
274 case ml::HandwritingLibrary::Status::kLoadLibraryFailed: {
275 std::move(callback).Run(
276 LoadHandwritingModelResult::LOAD_NATIVE_LIB_ERROR);
277 request_metrics.RecordRequestEvent(
278 LoadHandwritingModelResult::LOAD_NATIVE_LIB_ERROR);
279 return;
280 }
281 case ml::HandwritingLibrary::Status::kFunctionLookupFailed: {
282 std::move(callback).Run(
283 LoadHandwritingModelResult::LOAD_FUNC_PTR_ERROR);
284 request_metrics.RecordRequestEvent(
285 LoadHandwritingModelResult::LOAD_FUNC_PTR_ERROR);
286 return;
287 }
288 default: {
289 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
290 request_metrics.RecordRequestEvent(
291 LoadHandwritingModelResult::LOAD_MODEL_ERROR);
292 return;
293 }
294 }
295 }
296
297 // Create HandwritingRecognizer.
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000298 if (!RecognizerTraits<Recognizer>::Impl::Create(std::move(spec),
299 std::move(receiver))) {
Charles Zhao6d467e62020-08-31 10:02:03 +1000300 LOG(ERROR) << "LoadHandwritingRecognizer returned false.";
301 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
302 request_metrics.RecordRequestEvent(
303 LoadHandwritingModelResult::LOAD_MODEL_FILES_ERROR);
304 return;
305 }
306
307 std::move(callback).Run(LoadHandwritingModelResult::OK);
308 request_metrics.FinishRecordingPerformanceMetrics();
309 request_metrics.RecordRequestEvent(LoadHandwritingModelResult::OK);
310}
311
312void MachineLearningServiceImpl::LoadHandwritingModel(
313 chromeos::machine_learning::mojom::HandwritingRecognizerSpecPtr spec,
314 mojo::PendingReceiver<
315 chromeos::machine_learning::mojom::HandwritingRecognizer> receiver,
316 LoadHandwritingModelCallback callback) {
317 // If handwriting is installed on rootfs, load it from there.
318 if (ml::HandwritingLibrary::IsUseLibHandwritingEnabled()) {
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000319 LoadHandwritingModelFromDir<HandwritingRecognizer>(
Charles Zhao6d467e62020-08-31 10:02:03 +1000320 std::move(spec), std::move(receiver), std::move(callback),
321 ml::HandwritingLibrary::kHandwritingDefaultModelDir);
322 return;
323 }
324
325 // If handwriting is installed as DLC, get the dir and subsequently load it
326 // from there.
327 if (ml::HandwritingLibrary::IsUseLibHandwritingDlcEnabled()) {
328 dlcservice_client_->GetDlcRootPath(
329 "libhandwriting",
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000330 base::BindOnce(&LoadHandwritingModelFromDir<HandwritingRecognizer>,
331 std::move(spec), std::move(receiver),
332 std::move(callback)));
Charles Zhao6d467e62020-08-31 10:02:03 +1000333 return;
334 }
335
336 // If handwriting is not on rootfs and not in DLC, this function should not
337 // be called.
338 LOG(ERROR) << "Calling LoadHandwritingModel without Handwriting enabled "
339 "should never happen.";
340 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
charleszhao05c5a4a2020-06-09 16:49:54 +1000341}
342
343void MachineLearningServiceImpl::LoadHandwritingModelWithSpec(
344 HandwritingRecognizerSpecPtr spec,
Andrew Moylanb481af72020-07-09 15:22:00 +1000345 mojo::PendingReceiver<HandwritingRecognizer> receiver,
Charles Zhaoc882eb02020-07-27 10:02:35 +1000346 LoadHandwritingModelWithSpecCallback callback) {
charleszhao5a7050e2020-07-14 15:21:41 +1000347 RequestMetrics request_metrics("HandwritingModel", kMetricsRequestName);
charleszhao17777f92020-04-23 12:53:11 +1000348 request_metrics.StartRecordingPerformanceMetrics();
349
350 // Load HandwritingLibrary.
351 auto* const hwr_library = ml::HandwritingLibrary::GetInstance();
352
353 if (hwr_library->GetStatus() ==
354 ml::HandwritingLibrary::Status::kNotSupported) {
355 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
356 << static_cast<int>(hwr_library->GetStatus());
357
358 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
359 request_metrics.RecordRequestEvent(
360 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
361 return;
362 }
363
364 if (hwr_library->GetStatus() != ml::HandwritingLibrary::Status::kOk) {
365 LOG(ERROR) << "Initialize ml::HandwritingLibrary with error "
366 << static_cast<int>(hwr_library->GetStatus());
367
368 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
369 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
370 return;
371 }
372
373 // Create HandwritingRecognizer.
Andrew Moylanb481af72020-07-09 15:22:00 +1000374 if (!HandwritingRecognizerImpl::Create(std::move(spec),
375 std::move(receiver))) {
charleszhao17777f92020-04-23 12:53:11 +1000376 LOG(ERROR) << "LoadHandwritingRecognizer returned false.";
377 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
378 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
379 return;
380 }
381
382 std::move(callback).Run(LoadModelResult::OK);
383 request_metrics.FinishRecordingPerformanceMetrics();
384 request_metrics.RecordRequestEvent(LoadModelResult::OK);
385}
386
Honglin Yud2204272020-08-26 14:21:37 +1000387void MachineLearningServiceImpl::LoadSpeechRecognizer(
388 SodaConfigPtr config,
389 mojo::PendingRemote<SodaClient> soda_client,
390 mojo::PendingReceiver<SodaRecognizer> soda_recognizer,
391 LoadSpeechRecognizerCallback callback) {
392 RequestMetrics request_metrics("Soda", kMetricsRequestName);
393 request_metrics.StartRecordingPerformanceMetrics();
394
395 // Create the SodaRecognizer.
396 if (!SodaRecognizerImpl::Create(std::move(config), std::move(soda_client),
397 std::move(soda_recognizer))) {
398 LOG(ERROR) << "Failed to create SodaRecognizerImpl object.";
399 // TODO(robsc): it may be better that SODA has its specific enum values to
400 // return, similar to handwriting. So before we finalize the impl of SODA
401 // Mojo API, we may revisit this return value.
402 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
403 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
404 return;
405 }
406
407 std::move(callback).Run(LoadModelResult::OK);
408
409 request_metrics.FinishRecordingPerformanceMetrics();
410 request_metrics.RecordRequestEvent(LoadModelResult::OK);
411}
412
Jing Wang961b8af2020-10-26 12:40:35 +1100413void MachineLearningServiceImpl::LoadGrammarChecker(
414 mojo::PendingReceiver<chromeos::machine_learning::mojom::GrammarChecker>
415 receiver,
416 LoadGrammarCheckerCallback callback) {
417 RequestMetrics request_metrics("GrammarChecker", kMetricsRequestName);
418 request_metrics.StartRecordingPerformanceMetrics();
419
420 // Load GrammarLibrary.
421 auto* const grammar_library = ml::GrammarLibrary::GetInstance();
422
423 if (grammar_library->GetStatus() ==
424 ml::GrammarLibrary::Status::kNotSupported) {
425 LOG(ERROR) << "Initialize ml::GrammarLibrary with error "
426 << static_cast<int>(grammar_library->GetStatus());
427
428 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
429 request_metrics.RecordRequestEvent(
430 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
431 return;
432 }
433
434 if (grammar_library->GetStatus() != ml::GrammarLibrary::Status::kOk) {
435 LOG(ERROR) << "Initialize ml::GrammarLibrary with error "
436 << static_cast<int>(grammar_library->GetStatus());
437
438 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
439 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
440 return;
441 }
442
443 // Create GrammarChecker.
444 if (!GrammarCheckerImpl::Create(std::move(receiver))) {
445 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
446 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
447 return;
448 }
449
450 std::move(callback).Run(LoadModelResult::OK);
451
452 request_metrics.FinishRecordingPerformanceMetrics();
453 request_metrics.RecordRequestEvent(LoadModelResult::OK);
454}
455
Curtis McMullanf11584f2021-01-13 12:21:36 +1100456void MachineLearningServiceImpl::LoadTextSuggester(
457 mojo::PendingReceiver<chromeos::machine_learning::mojom::TextSuggester>
458 receiver,
459 LoadTextSuggesterCallback callback) {
460 RequestMetrics request_metrics("TextSuggester", kMetricsRequestName);
461 request_metrics.StartRecordingPerformanceMetrics();
462
463 // Load TextSuggestions library.
464 auto* const text_suggestions = ml::TextSuggestions::GetInstance();
465
466 if (text_suggestions->GetStatus() ==
467 ml::TextSuggestions::Status::kNotSupported) {
468 LOG(ERROR) << "Initialize ml::TextSuggestions with error "
469 << static_cast<int>(text_suggestions->GetStatus());
470
471 std::move(callback).Run(LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
472 request_metrics.RecordRequestEvent(
473 LoadModelResult::FEATURE_NOT_SUPPORTED_ERROR);
474 return;
475 }
476
477 if (text_suggestions->GetStatus() != ml::TextSuggestions::Status::kOk) {
478 LOG(ERROR) << "Initialize ml::TextSuggestions with error "
479 << static_cast<int>(text_suggestions->GetStatus());
480
481 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
482 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
483 return;
484 }
485
486 // Create TextSuggester.
487 if (!TextSuggesterImpl::Create(std::move(receiver))) {
488 std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
489 request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
490 return;
491 }
492
493 std::move(callback).Run(LoadModelResult::OK);
494
495 request_metrics.FinishRecordingPerformanceMetrics();
496 request_metrics.RecordRequestEvent(LoadModelResult::OK);
497}
498
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000499void MachineLearningServiceImpl::LoadWebPlatformHandwritingModel(
500 chromeos::machine_learning::web_platform::mojom::
501 HandwritingModelConstraintPtr constraint,
502 mojo::PendingReceiver<
503 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer>
504 receiver,
505 LoadWebPlatformHandwritingModelCallback callback) {
Honglin Yu7b6c1192020-09-16 10:07:17 +1000506 // If it is run in the control process, spawn a worker process and forward the
507 // request to it.
508 if (Process::GetInstance()->GetType() == Process::Type::kControl) {
509 pid_t worker_pid;
510 mojo::PlatformChannel channel;
511 constexpr char kModelName[] = "WebPlatformHandwritingModel";
512 if (!Process::GetInstance()->SpawnWorkerProcessAndGetPid(
513 channel, kModelName, &worker_pid)) {
514 // TODO(https://crbug.com/1202545): may need a better error code here.
515 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
516 return;
517 }
518 Process::GetInstance()
519 ->SendMojoInvitationAndGetRemote(worker_pid, std::move(channel),
520 kModelName)
521 ->LoadWebPlatformHandwritingModel(
522 std::move(constraint), std::move(receiver), std::move(callback));
523 return;
524 }
525
526 // From here below is in the worker process.
527
Honglin Yu0f5b21d2021-04-06 23:39:04 +1000528 // If handwriting is installed on rootfs, load it from there.
529 if (ml::HandwritingLibrary::IsUseLibHandwritingEnabled()) {
530 LoadHandwritingModelFromDir<
531 chromeos::machine_learning::web_platform::mojom::HandwritingRecognizer>(
532 std::move(constraint), std::move(receiver), std::move(callback),
533 ml::HandwritingLibrary::kHandwritingDefaultModelDir);
534 return;
535 }
536
537 // If handwriting is installed as DLC, get the dir and subsequently load it
538 // from there.
539 if (ml::HandwritingLibrary::IsUseLibHandwritingDlcEnabled()) {
540 dlcservice_client_->GetDlcRootPath(
541 "libhandwriting",
542 base::BindOnce(&LoadHandwritingModelFromDir<
543 chromeos::machine_learning::web_platform::mojom::
544 HandwritingRecognizer>,
545 std::move(constraint), std::move(receiver),
546 std::move(callback)));
547 return;
548 }
549
550 // If handwriting is not on rootfs and not in DLC, this function should not
551 // be called.
552 LOG(ERROR) << "Calling LoadWebPlatformHandwritingModel without Handwriting "
553 "enabled should never happen.";
554 std::move(callback).Run(LoadHandwritingModelResult::LOAD_MODEL_ERROR);
555}
556
Andrew Moylanff6be512018-07-03 11:05:01 +1000557} // namespace ml