下一页箭头原先在当前页满时一律可点,为首字母候选分批展开留口子; 但只有单个首字母且首字母候选恰好截在 24 条时才能展开,其余情况 末页满页的右箭头点了没反应也不会变灰。 引擎新增只判断不查库的 can_expand_initial_candidates,与实际展开 共用前置条件;Server 发布候选页快照时,满页只有在还能展开时才算 有下一页。 Refs #1069
182 lines
7.2 KiB
C++
182 lines
7.2 KiB
C++
#include "engine.h"
|
|
#include "../common/helpcode_utils.h"
|
|
#include "quanpin_query.h"
|
|
#include "quanpin_utils.h"
|
|
|
|
namespace
|
|
{ // The request carries one bool per correction type; the dictionary layer gates
|
|
// the whole feature with a single mask, so bridge the two here. Design D2: any
|
|
// correction switch on also enables the deletion bit -- the user's intent to
|
|
// have typos fixed covers dropped letters -- while both off stays 0. The same
|
|
// linkage carries the insertion bit (design D4 of the insertion task).
|
|
unsigned autocorrect_types_from_request(const QueryRequest &request)
|
|
{
|
|
const unsigned legacy =
|
|
(request.enable_quanpin_autocorrect_transposition ? quanpin::kAutocorrectTransposition : 0u) |
|
|
(request.enable_quanpin_autocorrect_neighbor ? quanpin::kAutocorrectNeighbor : 0u);
|
|
return legacy == 0 ? 0u : legacy | quanpin::kAutocorrectDeletion | quanpin::kAutocorrectInsertion;
|
|
}
|
|
} // namespace
|
|
|
|
QuanpinEngine::QuanpinEngine(metasequoia::RuntimePaths paths)
|
|
: dictionary_({}, paths),
|
|
helpcodes_(HelpcodeUtils::load_helpcode_keymap(paths.resources, HelpcodeUtils::selected_helpcode_schema()))
|
|
{
|
|
}
|
|
|
|
QuanpinEngine::~QuanpinEngine() = default;
|
|
|
|
std::optional<WordItem> QuanpinEngine::find_candidate(const std::string &key, const std::string &value)
|
|
{
|
|
return dictionary_.find_candidate(key, value);
|
|
}
|
|
|
|
std::vector<WordItem> QuanpinEngine::query(const QueryRequest &request)
|
|
{
|
|
if (!request.valid)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
// 整句联想开关随请求下发到词典层,四条整句来源据此各自门控(见 query_series)。
|
|
dictionary_.set_sentence_association(request.sentence_association);
|
|
// 前文同理随请求下发;换了前文,按旧前文重排出来的缓存顺序作废。
|
|
dictionary_.set_rescoring_context(request.rescoring_context);
|
|
|
|
const size_t helpcode_length =
|
|
request.enable_quanpin_helpcode
|
|
? quanpin::detect_active_helpcode_length(request.raw_input, request.raw_input_with_cases)
|
|
: 0;
|
|
// 辅助码路径自己切出底串的显式切分交给词典,词典不会再按掩码重切,所以这里要和方案的
|
|
// build_request 走同一个开关,否则关掉纠错后带辅助码的输入仍被别名层改写。
|
|
const bool correction_aliases = quanpin::correction_aliases_enabled(autocorrect_types_from_request(request));
|
|
|
|
if (helpcode_length == 2)
|
|
{
|
|
const std::string base_raw_input =
|
|
quanpin::strip_active_helpcodes(request.raw_input, request.raw_input_with_cases);
|
|
const auto cuts = quanpin::cut_pinyin_by_mode(base_raw_input, "correction", correction_aliases);
|
|
const std::string base_segmentation = quanpin::join_segments(cuts.front());
|
|
const std::string help_codes = request.raw_input.substr(request.raw_input.size() - 2, 2);
|
|
const auto base_candidates = dictionary_.query(base_raw_input, base_segmentation,
|
|
autocorrect_types_from_request(request), request.fuzzy_pinyin);
|
|
return HelpcodeUtils::filter_candidates_with_double_helpcodes(base_candidates, help_codes, helpcodes_.get());
|
|
}
|
|
|
|
if (helpcode_length == 1)
|
|
{
|
|
const std::string base_raw_input =
|
|
quanpin::strip_active_helpcodes(request.raw_input, request.raw_input_with_cases);
|
|
const auto cuts = quanpin::cut_pinyin_by_mode(base_raw_input, "correction", correction_aliases);
|
|
const std::string base_segmentation = quanpin::join_segments(cuts.front());
|
|
const std::string help_code = request.raw_input.substr(request.raw_input.size() - 1, 1);
|
|
const auto base_candidates = dictionary_.query(base_raw_input, base_segmentation,
|
|
autocorrect_types_from_request(request), request.fuzzy_pinyin);
|
|
return HelpcodeUtils::reorder_candidates_with_single_helpcode(base_candidates, help_code, helpcodes_.get());
|
|
}
|
|
|
|
return dictionary_.query(request.raw_input, request.segmentation, autocorrect_types_from_request(request),
|
|
request.fuzzy_pinyin);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
// 能展开首字母候选时返回那个首字母,否则返回空串。
|
|
std::string expandable_initial_code(const QueryRequest &request)
|
|
{
|
|
if (request.scheme != SchemeType::Quanpin ||
|
|
(request.enable_quanpin_helpcode &&
|
|
quanpin::detect_active_helpcode_length(request.raw_input, request.raw_input_with_cases) > 0))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
const auto segments = quanpin::split_segments(request.segmentation);
|
|
if (segments.empty() || segments.front().size() != 1)
|
|
{
|
|
return {};
|
|
}
|
|
return segments.front();
|
|
}
|
|
} // namespace
|
|
|
|
bool QuanpinEngine::can_expand_initial_candidates(const QueryRequest &request,
|
|
const std::vector<WordItem> &candidates) const
|
|
{
|
|
const std::string code = expandable_initial_code(request);
|
|
return !code.empty() && QuanpinDictionary::can_expand_initial_candidates(code, candidates);
|
|
}
|
|
|
|
bool QuanpinEngine::expand_initial_candidates(const QueryRequest &request, std::vector<WordItem> &candidates)
|
|
{
|
|
const std::string code = expandable_initial_code(request);
|
|
if (code.empty())
|
|
{
|
|
return false;
|
|
}
|
|
return dictionary_.expand_initial_candidates(code, candidates);
|
|
}
|
|
|
|
int QuanpinEngine::handleVkCode(ImeKeyCode vk, ImeModifierMask modifiers_down, ImeCharacter wch)
|
|
{
|
|
return dictionary_.handleVkCode(vk, modifiers_down, wch);
|
|
}
|
|
|
|
int QuanpinEngine::create_word(std::string pinyin, std::string word)
|
|
{
|
|
return dictionary_.create_word(std::move(pinyin), std::move(word));
|
|
}
|
|
|
|
int QuanpinEngine::create_word_from_canonical_pinyin(std::string pinyin, std::string word)
|
|
{
|
|
return dictionary_.create_word_from_canonical_pinyin(std::move(pinyin), std::move(word));
|
|
}
|
|
|
|
int QuanpinEngine::update_weight_by_word(std::string word)
|
|
{
|
|
return dictionary_.update_weight_by_word(std::move(word));
|
|
}
|
|
|
|
int QuanpinEngine::update_weight_by_pinyin_and_word(std::string pinyin, std::string word)
|
|
{
|
|
return dictionary_.update_weight_by_pinyin_and_word(std::move(pinyin), std::move(word));
|
|
}
|
|
|
|
int QuanpinEngine::delete_by_pinyin_and_word(std::string pinyin, std::string word)
|
|
{
|
|
return dictionary_.delete_by_pinyin_and_word(std::move(pinyin), std::move(word));
|
|
}
|
|
|
|
int QuanpinEngine::insert_word_to_series_cache(const std::string &pinyin, const std::string &word,
|
|
CandidateSource source)
|
|
{
|
|
return dictionary_.insert_word_to_series_cache(pinyin, word, source);
|
|
}
|
|
|
|
int QuanpinEngine::insert_word_to_series_cache(const QueryRequest &request, const std::string &word,
|
|
CandidateSource source)
|
|
{
|
|
return dictionary_.insert_word_to_series_cache(request.raw_input, request.segmentation,
|
|
autocorrect_types_from_request(request), word, source);
|
|
}
|
|
|
|
std::string QuanpinEngine::search_sentence_from_ime_engine(const std::string &user_pinyin)
|
|
{
|
|
return dictionary_.search_sentence_from_ime_engine(user_pinyin);
|
|
}
|
|
|
|
void QuanpinEngine::reset_state()
|
|
{
|
|
dictionary_.reset_state();
|
|
}
|
|
|
|
void QuanpinEngine::reset_cache()
|
|
{
|
|
dictionary_.reset_cache();
|
|
}
|
|
|
|
void QuanpinEngine::reset_sentence_cache()
|
|
{
|
|
dictionary_.reset_sentence_cache();
|
|
}
|