Skip to content

Commit 963b9ac

Browse files
author
Fcitx Bot
committed
Merge remote-tracking branch 'origin/master' into fcitx
2 parents 0bfbb62 + afbf1d0 commit 963b9ac

10 files changed

Lines changed: 295 additions & 176 deletions

src/prediction/realtime_decoder.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ bool RealtimeDecoder::PushBackTopConversionResult(
141141
// This method emulates usual converter's behavior so here disable
142142
// partial candidates.
143143
options.create_partial_candidates = false;
144+
options.used_in_predictor_realtime_conversion = true;
144145
options.request_type = ConversionRequest::CONVERSION;
145146
const ConversionRequest tmp_request = ConversionRequestBuilder()
146147
.SetConversionRequestView(request)
@@ -286,6 +287,7 @@ std::optional<Result> RealtimeDecoder::DecodeSuffix(
286287
options.create_partial_candidates = false;
287288
options.kana_modifier_insensitive_conversion = false;
288289
options.use_actual_converter_for_realtime_conversion = false;
290+
options.used_in_predictor_realtime_conversion = true;
289291

290292
const bool has_prefix = prefix_rid != 0;
291293

src/prediction/user_history_predictor.cc

Lines changed: 111 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,7 @@ bool UserHistoryPredictor::LookupEntry(
11101110
const ConversionRequest& request, absl::string_view request_key,
11111111
absl::string_view key_base,
11121112
const Trie<std::string>* absl_nullable key_expanded, const Entry& entry,
1113-
const Entry* absl_nullable prev_entry,
1113+
const Entry* absl_nullable prev_entry, bool exact_match_only,
11141114
EntryPriorityQueue& entry_queue) const {
11151115
Entry* result = nullptr;
11161116

@@ -1139,15 +1139,25 @@ bool UserHistoryPredictor::LookupEntry(
11391139
return false;
11401140
}
11411141

1142+
// `exact_match_only` is called on the conversion that only requires exact
1143+
// match result.
1144+
// RIGHT_PREFIX_MATCH automatically fills the remaining suffix with
1145+
// the logic of partial match.
1146+
if (exact_match_only && mtype != MatchType::RIGHT_PREFIX_MATCH &&
1147+
mtype != MatchType::EXACT_MATCH) {
1148+
return false;
1149+
}
1150+
11421151
// Full sentence with low frequency is suppressed unless
11431152
// AllowLowFreqFullSentenceEntryMatch() returns true.
1144-
if (IsLowFreqFullSentenceEntry(request, entry) &&
1153+
if (!exact_match_only && IsLowFreqFullSentenceEntry(request, entry) &&
11451154
!AllowLowFreqFullSentenceEntryMatch(request, request_key, mtype, entry)) {
11461155
return false;
11471156
}
11481157

11491158
// For mobile, prefer exact match.
1150-
const bool prefer_exact_match = IsMixedConversionEnabled(request);
1159+
const bool prefer_exact_match =
1160+
IsMixedConversionEnabled(request) || exact_match_only;
11511161

11521162
left_last_access_time = entry.last_access_time();
11531163
left_most_last_access_time =
@@ -1182,13 +1192,18 @@ bool UserHistoryPredictor::LookupEntry(
11821192
uint32_t result_attribute = 0;
11831193
converter::InnerSegmentBoundary inner_segment_boundary;
11841194

1185-
if (GetKeyValueForExactAndRightPrefixMatch(
1195+
if (!exact_match_only &&
1196+
GetKeyValueForExactAndRightPrefixMatch(
11861197
request, request_key, prefer_exact_match, entry, last_entry,
11871198
left_last_access_time, left_most_last_access_time, key, value,
1188-
inner_segment_boundary) ||
1189-
GetKeyValueForPartialMatch(request, request_key, entry, key, value,
1190-
result_attribute, inner_segment_boundary,
1191-
entry_queue)) {
1199+
inner_segment_boundary)) {
1200+
result =
1201+
AddEntryWithNewKeyValue(request, std::move(key), std::move(value),
1202+
inner_segment_boundary, entry, entry_queue);
1203+
SetAttribute(*result, result_attribute);
1204+
} else if (GetKeyValueForPartialMatch(
1205+
request, request_key, entry, key, value, result_attribute,
1206+
inner_segment_boundary, entry_queue)) {
11921207
result =
11931208
AddEntryWithNewKeyValue(request, std::move(key), std::move(value),
11941209
inner_segment_boundary, entry, entry_queue);
@@ -1268,8 +1283,8 @@ bool UserHistoryPredictor::LookupEntry(
12681283
entry_queue.Push(result);
12691284
}
12701285

1271-
if (IsMixedConversionEnabled(request)) {
1272-
// For mobile, we don't generate joined result.
1286+
// For mobile or conversion mode, we don't generate joined result.
1287+
if (IsMixedConversionEnabled(request) || exact_match_only) {
12731288
return true;
12741289
}
12751290

@@ -1369,7 +1384,7 @@ std::vector<Result> UserHistoryPredictor::Predict(
13691384
max_prediction_size = 3;
13701385
}
13711386

1372-
EntryPriorityQueue entry_queue = CreateEntryQueueFromHistory(
1387+
EntryPriorityQueue entry_queue = CreateEntryQueueFromHistoryForPrediction(
13731388
request, prev_entry.get(), max_prediction_size * 5);
13741389

13751390
if (entry_queue.size() == 0) {
@@ -1381,48 +1396,75 @@ std::vector<Result> UserHistoryPredictor::Predict(
13811396
entry_queue);
13821397
}
13831398

1384-
bool UserHistoryPredictor::ShouldPredict(
1399+
std::vector<Result> UserHistoryPredictor::Convert(
13851400
const ConversionRequest& request) const {
1386-
if (storage_.IsSyncerInCriticalSection()) {
1387-
MOZC_VLOG(2) << "Syncer is running";
1388-
return false;
1401+
if (!ShouldPredict(request)) {
1402+
return {};
13891403
}
13901404

1391-
if (request.incognito_mode()) {
1392-
MOZC_VLOG(2) << "incognito mode";
1393-
return false;
1405+
ConstEntrySnapshot prev_entry = LookupPrevEntry(request);
1406+
1407+
constexpr int kMaxCandidatesSize = 5;
1408+
1409+
EntryPriorityQueue entry_queue = CreateEntryQueueFromHistoryForConversion(
1410+
request, prev_entry.get(), kMaxCandidatesSize);
1411+
1412+
if (entry_queue.size() == 0) {
1413+
MOZC_VLOG(2) << "no prefix match candidate is found.";
1414+
return {};
13941415
}
13951416

1396-
if (request.config().history_learning_level() == config::Config::NO_HISTORY) {
1397-
MOZC_VLOG(2) << "history learning level is NO_HISTORY";
1417+
return MakeResults(request, kMaxCandidatesSize,
1418+
0 /* max_prediction_char_coverage */, entry_queue);
1419+
}
1420+
1421+
bool UserHistoryPredictor::ShouldPredict(
1422+
const ConversionRequest& request) const {
1423+
if (storage_.IsSyncerInCriticalSection()) {
1424+
MOZC_VLOG(2) << "Syncer is running";
13981425
return false;
13991426
}
14001427

1401-
if (request.request_type() == ConversionRequest::CONVERSION) {
1402-
MOZC_VLOG(2) << "request type is CONVERSION";
1428+
if (storage_.IsEmpty()) {
1429+
MOZC_VLOG(2) << "dic is empty";
14031430
return false;
14041431
}
14051432

1406-
if (!request.config().use_history_suggest()) {
1407-
MOZC_VLOG(2) << "no history suggest";
1433+
if (request.incognito_mode()) {
1434+
MOZC_VLOG(2) << "incognito mode";
14081435
return false;
14091436
}
14101437

1411-
if (storage_.IsEmpty()) {
1412-
MOZC_VLOG(2) << "dic is empty";
1438+
if (request.config().history_learning_level() == config::Config::NO_HISTORY) {
1439+
MOZC_VLOG(2) << "history learning level is NO_HISTORY";
14131440
return false;
14141441
}
14151442

14161443
absl::string_view request_key = request.key();
14171444

1418-
if (request_key.empty() && !IsZeroQuerySuggestionEnabled(request)) {
1419-
MOZC_VLOG(2) << "key length is 0";
1420-
return false;
1421-
}
1445+
// Prediction/suggestion specific rules.
1446+
if (request.request_type() == ConversionRequest::SUGGESTION ||
1447+
request.request_type() == ConversionRequest::PREDICTION ||
1448+
request.request_type() == ConversionRequest::PARTIAL_SUGGESTION ||
1449+
request.request_type() == ConversionRequest::PARTIAL_PREDICTION) {
1450+
if (request_key.empty() && !IsZeroQuerySuggestionEnabled(request)) {
1451+
MOZC_VLOG(2) << "key length is 0";
1452+
return false;
1453+
}
14221454

1423-
if (StartsWithPunctuation(request_key)) {
1424-
MOZC_VLOG(2) << "request_key starts with punctuations";
1425-
return false;
1455+
if (!request.config().use_history_suggest()) {
1456+
MOZC_VLOG(2) << "no history suggest";
1457+
return false;
1458+
}
1459+
1460+
if (StartsWithPunctuation(request_key)) {
1461+
MOZC_VLOG(2) << "request_key starts with punctuations";
1462+
return false;
1463+
}
1464+
} else if (request.request_type() == ConversionRequest::CONVERSION) {
1465+
if (request_key.empty()) {
1466+
return false;
1467+
}
14261468
}
14271469

14281470
return true;
@@ -1481,8 +1523,8 @@ UserHistoryPredictor::ConstEntrySnapshot UserHistoryPredictor::LookupPrevEntry(
14811523
}
14821524

14831525
UserHistoryPredictor::EntryPriorityQueue
1484-
UserHistoryPredictor::CreateEntryQueueFromHistory(
1485-
const ConversionRequest& request, const Entry* prev_entry,
1526+
UserHistoryPredictor::CreateEntryQueueFromHistoryForPrediction(
1527+
const ConversionRequest& request, const Entry* absl_nullable prev_entry,
14861528
size_t max_entry_queue_size) const {
14871529
// Gets romanized input key if the given preedit looks misspelled.
14881530
const std::string roman_request_key = GetRomanMisspelledKey(request);
@@ -1521,10 +1563,12 @@ UserHistoryPredictor::CreateEntryQueueFromHistory(
15211563
return true;
15221564
}
15231565

1566+
static constexpr bool kDisableExactMatchOnly = false;
1567+
15241568
// Lookup key from elm_value and prev_entry.
15251569
// If a new entry is found, the entry is pushed to the entry_queue.
15261570
if (LookupEntry(request, request_key, base_key, expanded.get(), entry,
1527-
prev_entry, entry_queue)) {
1571+
prev_entry, kDisableExactMatchOnly, entry_queue)) {
15281572
return true;
15291573
}
15301574

@@ -1549,7 +1593,7 @@ UserHistoryPredictor::CreateEntryQueueFromHistory(
15491593
// in dictionary predictor.
15501594
if (c.score > 0.0 &&
15511595
LookupEntry(request, c.correction, c.correction, nullptr, entry,
1552-
prev_entry, entry_queue)) {
1596+
prev_entry, kDisableExactMatchOnly, entry_queue)) {
15531597
break;
15541598
}
15551599
}
@@ -1560,6 +1604,36 @@ UserHistoryPredictor::CreateEntryQueueFromHistory(
15601604
return entry_queue;
15611605
}
15621606

1607+
UserHistoryPredictor::EntryPriorityQueue
1608+
UserHistoryPredictor::CreateEntryQueueFromHistoryForConversion(
1609+
const ConversionRequest& request, const Entry* absl_nullable prev_entry,
1610+
size_t max_entry_queue_size) const {
1611+
const std::string request_key = request.composer().GetQueryForConversion();
1612+
EntryPriorityQueue entry_queue;
1613+
1614+
storage_.ForEach([&](uint64_t fp, const Entry& entry) {
1615+
// already found enough entry_queue.
1616+
if (entry_queue.size() >= max_entry_queue_size) {
1617+
return false;
1618+
}
1619+
1620+
if (!IsValidEntryIgnoringRemovedField(entry)) {
1621+
return true;
1622+
}
1623+
1624+
static constexpr bool kEnableExactMatchOnly = true;
1625+
1626+
if (LookupEntry(request, request_key, request_key, nullptr, entry,
1627+
prev_entry, kEnableExactMatchOnly, entry_queue)) {
1628+
return true;
1629+
}
1630+
1631+
return true;
1632+
});
1633+
1634+
return entry_queue;
1635+
}
1636+
15631637
// static
15641638
std::tuple<std::string, std::string, std::unique_ptr<Trie<std::string>>>
15651639
UserHistoryPredictor::GetInputKeyFromRequest(const ConversionRequest& request) {

src/prediction/user_history_predictor.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class UserHistoryPredictor : public PredictorInterface {
7070

7171
std::vector<Result> Predict(const ConversionRequest& request) const override;
7272

73+
// TODO(taku): Make it a virtual method of PredictorInterface.
74+
std::vector<Result> Convert(const ConversionRequest& request) const;
75+
7376
// Hook(s) for all mutable operations.
7477
void Finish(const ConversionRequest& request,
7578
absl::Span<const Result> results, uint32_t revert_id) override;
@@ -180,6 +183,8 @@ class UserHistoryPredictor : public PredictorInterface {
180183
};
181184

182185
// Returns true if this predictor should return results for the input.
186+
// TODO(taku): better to rename this function as it is used both for
187+
// prediction and conversion.
183188
bool ShouldPredict(const ConversionRequest& request) const;
184189

185190
// Gets match type from two strings
@@ -275,6 +280,7 @@ class UserHistoryPredictor : public PredictorInterface {
275280
absl::string_view request_key, absl::string_view key_base,
276281
const Trie<std::string>* absl_nullable key_expanded,
277282
const Entry& entry, const Entry* absl_nullable prev_entry,
283+
bool exact_match_only,
278284
EntryPriorityQueue& entry_queue) const;
279285

280286
// For the EXACT and RIGHT_PREFIX match, we will generate joined
@@ -323,8 +329,13 @@ class UserHistoryPredictor : public PredictorInterface {
323329
converter::InnerSegmentBoundarySpan inner_segment_boundary, Entry entry,
324330
EntryPriorityQueue& entry_queue) const;
325331

326-
// Creates entry queue from request and history storage.
327-
EntryPriorityQueue CreateEntryQueueFromHistory(
332+
// Creates entry queue from request and history storage on prediction mode.
333+
EntryPriorityQueue CreateEntryQueueFromHistoryForPrediction(
334+
const ConversionRequest& request, const Entry* absl_nullable prev_entry,
335+
size_t max_entry_queue_size) const;
336+
337+
// Creates entry queue from request and history storage on conversion mode.
338+
EntryPriorityQueue CreateEntryQueueFromHistoryForConversion(
328339
const ConversionRequest& request, const Entry* absl_nullable prev_entry,
329340
size_t max_entry_queue_size) const;
330341

0 commit comments

Comments
 (0)