Update grammar check mojo api and service client.
1. Uprev mojo api of grammar check from chromeos. The mojom interface is generated with the script "chromeos/services/machine_learning/public/mojom/roll_mojoms.sh" from https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2611147 this change need to be submitted after it. 2. The new api will return correction fragments, so update the service client accordingly, now the grammar correct results are parsed from fragments. 3. Don't show grammar error when the proposal is to delete the whole sentence, i.e. when result->candidates.at(0)->text.empty() is true. 4. Update unit tests, in ServiceConnectionTest, move LoadGrammarModel test before soda test so that it won't crash. Bug: 1132699 Test: Passed unit tests, also manually tested on nocturne. Change-Id: I85529f3a26f134e5eea7785bae5ac9c7f9e776f8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2612788 Commit-Queue: Jing Wang <jiwan@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Honglin Yu <honglinyu@chromium.org> Reviewed-by: Darren Shen <shend@chromium.org> Cr-Commit-Position: refs/heads/master@{#845006}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
e437a995e1
commit
1185042aff
chrome/browser/chromeos/input_method
chromeos/services/machine_learning/public
@ -62,12 +62,29 @@ void GrammarServiceClient::ParseGrammarCheckerResult(
|
||||
chromeos::machine_learning::mojom::GrammarCheckerResultPtr result) const {
|
||||
if (result->status == GrammarCheckerResult::Status::OK &&
|
||||
!result->candidates.empty()) {
|
||||
std::vector<SpellCheckResult> grammar_results;
|
||||
grammar_results.emplace_back(
|
||||
SpellCheckResult::GRAMMAR, 0, text.size(),
|
||||
base::UTF8ToUTF16(result->candidates.at(0)->text));
|
||||
std::move(callback).Run(true, grammar_results);
|
||||
const auto& top_candidate = result->candidates.front();
|
||||
if (!top_candidate->text.empty() && !top_candidate->fragments.empty()) {
|
||||
std::vector<SpellCheckResult> grammar_results;
|
||||
for (const auto& fragment : top_candidate->fragments) {
|
||||
uint32_t end;
|
||||
if (!base::CheckAdd(fragment->offset, fragment->length)
|
||||
.AssignIfValid(&end) ||
|
||||
end > text.size()) {
|
||||
DLOG(ERROR) << "Grammar checker returns invalid correction "
|
||||
"fragement, offset: "
|
||||
<< fragment->offset << ", length: " << fragment->length
|
||||
<< ", but the text length is " << text.size();
|
||||
} else {
|
||||
grammar_results.emplace_back(
|
||||
SpellCheckResult::GRAMMAR, fragment->offset, fragment->length,
|
||||
base::UTF8ToUTF16(fragment->replacement));
|
||||
}
|
||||
}
|
||||
std::move(callback).Run(true, grammar_results);
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::move(callback).Run(false, {});
|
||||
}
|
||||
|
||||
bool GrammarServiceClient::IsAvailable(Profile* profile) const {
|
||||
|
@ -64,15 +64,19 @@ TEST_F(GrammarServiceClientTest, ParsesResults) {
|
||||
spellcheck::prefs::kSpellCheckUseSpellingService, true);
|
||||
|
||||
// Construct fake output
|
||||
const base::string16 input_text = base::UTF8ToUTF16("fake input");
|
||||
const base::string16 expected_output = base::UTF8ToUTF16("fake output");
|
||||
machine_learning::mojom::GrammarCheckerResultPtr result =
|
||||
machine_learning::mojom::GrammarCheckerResult::New();
|
||||
result->status = machine_learning::mojom::GrammarCheckerResult::Status::OK;
|
||||
machine_learning::mojom::GrammarCheckerCandidatePtr candidate =
|
||||
machine_learning::mojom::GrammarCheckerCandidate::New();
|
||||
candidate->text = base::UTF16ToUTF8(expected_output);
|
||||
candidate->text = "fake output";
|
||||
candidate->score = 0.5f;
|
||||
machine_learning::mojom::GrammarCorrectionFragmentPtr fragment =
|
||||
machine_learning::mojom::GrammarCorrectionFragment::New();
|
||||
fragment->offset = 3;
|
||||
fragment->length = 5;
|
||||
fragment->replacement = "fake replacement";
|
||||
candidate->fragments.emplace_back(std::move(fragment));
|
||||
result->candidates.emplace_back(std::move(candidate));
|
||||
fake_service_connection.SetOutputGrammarCheckerResult(result);
|
||||
|
||||
@ -80,19 +84,18 @@ TEST_F(GrammarServiceClientTest, ParsesResults) {
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
client.RequestTextCheck(
|
||||
profile.get(), input_text,
|
||||
profile.get(), base::UTF8ToUTF16("fake input"),
|
||||
base::BindOnce(
|
||||
[](const base::string16& text, const base::string16& expected_output,
|
||||
bool success, const std::vector<SpellCheckResult>& results) {
|
||||
[](bool success, const std::vector<SpellCheckResult>& results) {
|
||||
EXPECT_TRUE(success);
|
||||
ASSERT_EQ(results.size(), 1U);
|
||||
EXPECT_EQ(results[0].decoration, SpellCheckResult::GRAMMAR);
|
||||
EXPECT_EQ(results[0].location, 0);
|
||||
EXPECT_EQ(results[0].length, static_cast<int>(text.size()));
|
||||
EXPECT_EQ(results[0].location, 3);
|
||||
EXPECT_EQ(results[0].length, 5);
|
||||
ASSERT_EQ(results[0].replacements.size(), 1U);
|
||||
EXPECT_EQ(results[0].replacements[0], expected_output);
|
||||
},
|
||||
input_text, expected_output));
|
||||
EXPECT_EQ(results[0].replacements[0],
|
||||
base::UTF8ToUTF16("fake replacement"));
|
||||
}));
|
||||
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
@ -523,6 +523,12 @@ TEST_F(ServiceConnectionTest, FakeGrammarChecker) {
|
||||
mojom::GrammarCheckerCandidate::New();
|
||||
candidate->text = "cat";
|
||||
candidate->score = 0.5f;
|
||||
mojom::GrammarCorrectionFragmentPtr fragment =
|
||||
mojom::GrammarCorrectionFragment::New();
|
||||
fragment->offset = 3;
|
||||
fragment->length = 5;
|
||||
fragment->replacement = "dog";
|
||||
candidate->fragments.emplace_back(std::move(fragment));
|
||||
result->candidates.emplace_back(std::move(candidate));
|
||||
fake_service_connection.SetOutputGrammarCheckerResult(result);
|
||||
|
||||
@ -535,8 +541,15 @@ TEST_F(ServiceConnectionTest, FakeGrammarChecker) {
|
||||
*infer_callback_done = true;
|
||||
// Check if the annotation is correct.
|
||||
ASSERT_EQ(result->status, mojom::GrammarCheckerResult::Status::OK);
|
||||
ASSERT_EQ(result->candidates.size(), 1UL);
|
||||
EXPECT_EQ(result->candidates.at(0)->text, "cat");
|
||||
EXPECT_EQ(result->candidates.at(0)->score, 0.5f);
|
||||
|
||||
ASSERT_EQ(result->candidates.at(0)->fragments.size(), 1UL);
|
||||
EXPECT_EQ(result->candidates.at(0)->fragments.at(0)->offset, 3U);
|
||||
EXPECT_EQ(result->candidates.at(0)->fragments.at(0)->length, 5U);
|
||||
EXPECT_EQ(result->candidates.at(0)->fragments.at(0)->replacement,
|
||||
"dog");
|
||||
},
|
||||
&infer_callback_done));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
@ -3,6 +3,10 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Datatypes and interfaces of grammar checker API.
|
||||
// Grammar check API is implemented in Chrome OS platform2 repo
|
||||
// src/platform2/ml/grammar_checker_impl.h
|
||||
// It is running inside the ML sandbox and consumed only from the Chrome browser
|
||||
// process.
|
||||
|
||||
// NOTE: This mojom exists in two places and must be kept in sync:
|
||||
// Chromium: //chromeos/services/machine_learning/public/mojom/
|
||||
@ -25,6 +29,18 @@ struct GrammarCheckerQuery {
|
||||
string language;
|
||||
};
|
||||
|
||||
// A span with suggested corrections.
|
||||
struct GrammarCorrectionFragment {
|
||||
// The start offset in the original text.
|
||||
uint32 offset;
|
||||
|
||||
// The length of the fragment in the original text.
|
||||
uint32 length;
|
||||
|
||||
// The replacement string.
|
||||
string replacement;
|
||||
};
|
||||
|
||||
// One possible candidate returned from the grammar checker model.
|
||||
struct GrammarCheckerCandidate {
|
||||
// Corrected text.
|
||||
@ -32,6 +48,9 @@ struct GrammarCheckerCandidate {
|
||||
|
||||
// Score of the text. Log of conditional probability.
|
||||
float score;
|
||||
|
||||
// The list of individual corrections.
|
||||
array<GrammarCorrectionFragment> fragments;
|
||||
};
|
||||
|
||||
// The grammar check response.
|
||||
|
Reference in New Issue
Block a user