feat(server): 整句联想来源开关接入配置与设置页
新增 [association] 段的五个开关(词格、Google、神经 desktop / keyboard、去重补位), 同步写入出厂模板、工作配置和两个设置窗口宿主的读写映射,设置页输入分区加对应选项。
This commit is contained in:
1 parent
e7f7addd4f
commit
16877cb2d0
16 files changed
+402
-6
No files matched your search
@@ -54,6 +54,23 @@ cloud_candidates = true
|
||||
# TODO: 极简模式。极简模式下,候选窗口使用 d2d 绘制,界面只作展示候选项,无其他功能。
|
||||
clean_mode = false
|
||||
|
||||
#
|
||||
# 整句联想:多音节输入时把整串拼音解码成一句,四个来源各一个开关,另有去重补位开关,默认全关,
|
||||
# 打开后才会在候选里出现对应整句。词格/Google 是传统 ngram 来源;神经两档是
|
||||
# chinese-ime-lm 的 Transformer,还需模型文件在数据目录里,desktop 更准也更慢。
|
||||
#
|
||||
[association]
|
||||
# 词格整句联想(kenlm 三元模型打分)
|
||||
sentence_wordlattice = false
|
||||
# Google 解码器整句联想
|
||||
sentence_google = false
|
||||
# 神经网络模型整句(效果优先 / desktop):内部生成最多 12 条 Trigram 备选并挑选,不依赖 sentence_wordlattice 开关
|
||||
sentence_neural_desktop = false
|
||||
# 神经网络模型整句(速度优先 / keyboard):同上;与 desktop 同时开启时各自独立给出结果
|
||||
sentence_neural_keyboard = false
|
||||
# 某个模型的首选与已有候选重复时,改为显示该模型排名最高的下一条不同结果
|
||||
sentence_show_next_on_duplicate = false
|
||||
|
||||
#
|
||||
# 腾讯云机器翻译(竖排候选项本地词库未命中时的补全)
|
||||
#
|
||||
|
||||
@@ -54,6 +54,23 @@ cloud_candidates = true
|
||||
# TODO: 极简模式。极简模式下,候选窗口使用 d2d 绘制,界面只作展示候选项,无其他功能。
|
||||
clean_mode = false
|
||||
|
||||
#
|
||||
# 整句联想:多音节输入时把整串拼音解码成一句,四个来源各一个开关,另有去重补位开关,默认全关,
|
||||
# 打开后才会在候选里出现对应整句。词格/Google 是传统 ngram 来源;神经两档是
|
||||
# chinese-ime-lm 的 Transformer,还需模型文件在数据目录里,desktop 更准也更慢。
|
||||
#
|
||||
[association]
|
||||
# 词格整句联想(kenlm 三元模型打分)
|
||||
sentence_wordlattice = false
|
||||
# Google 解码器整句联想
|
||||
sentence_google = false
|
||||
# 神经网络模型整句(效果优先 / desktop):内部生成最多 12 条 Trigram 备选并挑选,不依赖 sentence_wordlattice 开关
|
||||
sentence_neural_desktop = false
|
||||
# 神经网络模型整句(速度优先 / keyboard):同上;与 desktop 同时开启时各自独立给出结果
|
||||
sentence_neural_keyboard = false
|
||||
# 某个模型的首选与已有候选重复时,改为显示该模型排名最高的下一条不同结果
|
||||
sentence_show_next_on_duplicate = false
|
||||
|
||||
#
|
||||
# 腾讯云机器翻译(候选项本地词库未命中时的补全)
|
||||
#
|
||||
|
||||
@@ -122,6 +122,12 @@ bool g_english_candidates_enabled = false;
|
||||
bool g_candidate_translations_enabled = true;
|
||||
int g_english_mixed_input_min_chars = kEnglishMixedInputMinCharsDefault;
|
||||
bool g_cloud_candidates_enabled = true;
|
||||
// 整句候选来源与去重补位开关,默认全关。
|
||||
bool g_assoc_sentence_wordlattice = false;
|
||||
bool g_assoc_sentence_google = false;
|
||||
bool g_assoc_sentence_neural_desktop = false;
|
||||
bool g_assoc_sentence_neural_keyboard = false;
|
||||
bool g_assoc_sentence_show_next_on_duplicate = false;
|
||||
bool g_emoji_mixed_input_enabled = false;
|
||||
bool g_kaomoji_mixed_input_enabled = false;
|
||||
bool g_unicode_mode_enabled = true;
|
||||
@@ -1057,6 +1063,11 @@ bool LoadImeConfig()
|
||||
: kEnglishMixedInputMinCharsDefault;
|
||||
}
|
||||
g_cloud_candidates_enabled = tbl["general"]["cloud_candidates"].value_or(true);
|
||||
g_assoc_sentence_wordlattice = tbl["association"]["sentence_wordlattice"].value_or(false);
|
||||
g_assoc_sentence_google = tbl["association"]["sentence_google"].value_or(false);
|
||||
g_assoc_sentence_neural_desktop = tbl["association"]["sentence_neural_desktop"].value_or(false);
|
||||
g_assoc_sentence_neural_keyboard = tbl["association"]["sentence_neural_keyboard"].value_or(false);
|
||||
g_assoc_sentence_show_next_on_duplicate = tbl["association"]["sentence_show_next_on_duplicate"].value_or(false);
|
||||
g_emoji_mixed_input_enabled = tbl["general"]["emoji_mixed_input"].value_or(false);
|
||||
g_kaomoji_mixed_input_enabled = tbl["general"]["kaomoji_mixed_input"].value_or(false);
|
||||
g_unicode_mode_enabled = tbl["utility"]["unicode_mode"].value_or(true);
|
||||
@@ -3387,6 +3398,77 @@ bool SetConfiguredCloudCandidatesEnabled(bool enabled)
|
||||
return true;
|
||||
}
|
||||
|
||||
// 整句候选来源与去重补位开关的 getter / setter。写入 [association] 段,值域为布尔。
|
||||
bool GetConfiguredAssocSentenceWordLattice()
|
||||
{
|
||||
return g_assoc_sentence_wordlattice;
|
||||
}
|
||||
bool SetConfiguredAssocSentenceWordLattice(bool enabled)
|
||||
{
|
||||
if (!WriteConfiguredValue("association", "sentence_wordlattice", enabled ? "true" : "false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
g_assoc_sentence_wordlattice = enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetConfiguredAssocSentenceGoogle()
|
||||
{
|
||||
return g_assoc_sentence_google;
|
||||
}
|
||||
bool SetConfiguredAssocSentenceGoogle(bool enabled)
|
||||
{
|
||||
if (!WriteConfiguredValue("association", "sentence_google", enabled ? "true" : "false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
g_assoc_sentence_google = enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetConfiguredAssocSentenceNeuralDesktop()
|
||||
{
|
||||
return g_assoc_sentence_neural_desktop;
|
||||
}
|
||||
bool SetConfiguredAssocSentenceNeuralDesktop(bool enabled)
|
||||
{
|
||||
if (!WriteConfiguredValue("association", "sentence_neural_desktop", enabled ? "true" : "false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
g_assoc_sentence_neural_desktop = enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetConfiguredAssocSentenceNeuralKeyboard()
|
||||
{
|
||||
return g_assoc_sentence_neural_keyboard;
|
||||
}
|
||||
bool SetConfiguredAssocSentenceNeuralKeyboard(bool enabled)
|
||||
{
|
||||
if (!WriteConfiguredValue("association", "sentence_neural_keyboard", enabled ? "true" : "false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
g_assoc_sentence_neural_keyboard = enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetConfiguredAssocSentenceShowNextOnDuplicate()
|
||||
{
|
||||
return g_assoc_sentence_show_next_on_duplicate;
|
||||
}
|
||||
bool SetConfiguredAssocSentenceShowNextOnDuplicate(bool enabled)
|
||||
{
|
||||
if (!WriteConfiguredValue("association", "sentence_show_next_on_duplicate", enabled ? "true" : "false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
g_assoc_sentence_show_next_on_duplicate = enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetConfiguredUnicodeModeEnabled()
|
||||
{
|
||||
return g_unicode_mode_enabled;
|
||||
|
||||
@@ -277,6 +277,17 @@ bool GetConfiguredKaomojiMixedInputEnabled();
|
||||
bool SetConfiguredKaomojiMixedInputEnabled(bool enabled);
|
||||
bool GetConfiguredCloudCandidatesEnabled();
|
||||
bool SetConfiguredCloudCandidatesEnabled(bool enabled);
|
||||
// 整句候选来源与去重补位开关([association] 段),默认全关。
|
||||
bool GetConfiguredAssocSentenceWordLattice();
|
||||
bool SetConfiguredAssocSentenceWordLattice(bool enabled);
|
||||
bool GetConfiguredAssocSentenceGoogle();
|
||||
bool SetConfiguredAssocSentenceGoogle(bool enabled);
|
||||
bool GetConfiguredAssocSentenceNeuralDesktop();
|
||||
bool SetConfiguredAssocSentenceNeuralDesktop(bool enabled);
|
||||
bool GetConfiguredAssocSentenceNeuralKeyboard();
|
||||
bool SetConfiguredAssocSentenceNeuralKeyboard(bool enabled);
|
||||
bool GetConfiguredAssocSentenceShowNextOnDuplicate();
|
||||
bool SetConfiguredAssocSentenceShowNextOnDuplicate(bool enabled);
|
||||
bool GetConfiguredUnicodeModeEnabled();
|
||||
bool SetConfiguredUnicodeModeEnabled(bool enabled);
|
||||
bool GetConfiguredQuickPhraseEnabled();
|
||||
|
||||
@@ -31,14 +31,21 @@ inline size_t CountCanonicalSyllables(const std::string &canonical_pinyin) noexc
|
||||
return 1 + static_cast<size_t>(std::count(canonical_pinyin.begin(), canonical_pinyin.end(), '\''));
|
||||
}
|
||||
|
||||
// 整句候选(词格 Generated / Google 解码器 Fallback)独立上屏——不接在造词前缀
|
||||
// 后面、自己就是整条输入——时是否该落库。该落:整句是猜出来的,词库里没有它那一行,
|
||||
// 调频改的是已有的行,改不到它。不落库的话用户选多少次,下次它仍然要靠猜,也仍然
|
||||
// 排在词库里那条同音短语后面。
|
||||
// 猜出来的整句来源:词格 Generated、Google 解码器 Fallback,以及神经整句
|
||||
// NeuralDesktop / NeuralKeyboard。它们都不是词库里已有的行,落库/学习判定同类处理。
|
||||
constexpr bool IsGuessedSentenceSource(CandidateSource source) noexcept
|
||||
{
|
||||
return source == CandidateSource::Generated || source == CandidateSource::Fallback ||
|
||||
source == CandidateSource::NeuralDesktop || source == CandidateSource::NeuralKeyboard;
|
||||
}
|
||||
|
||||
// 整句候选独立上屏——不接在造词前缀后面、自己就是整条输入——时是否该落库。该落:整句是
|
||||
// 猜出来的,词库里没有它那一行,调频改的是已有的行,改不到它。不落库的话用户选多少次,
|
||||
// 下次它仍然要靠猜,也仍然排在词库里那条同音短语后面。
|
||||
inline bool ShouldStoreStandaloneSentence(CandidateSource source,
|
||||
const std::string &candidate_canonical_pinyin) noexcept
|
||||
{
|
||||
if (source != CandidateSource::Generated && source != CandidateSource::Fallback)
|
||||
if (!IsGuessedSentenceSource(source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -57,7 +64,11 @@ inline bool ShouldStoreEarlyReturnPhrase(CandidateSource source, bool creating_w
|
||||
const std::string &prefix_canonical_pinyin,
|
||||
const std::string &candidate_canonical_pinyin) noexcept
|
||||
{
|
||||
if (source != CandidateSource::Generated || candidate_canonical_pinyin.empty())
|
||||
// 与词格 Generated 同一支:神经整句同样带 canonical quanpin,可以结束一段造词或独立
|
||||
// 上屏。Google Fallback 沿用旧语义仍不走这条造词落库路径。
|
||||
const bool early_return_source = source == CandidateSource::Generated || source == CandidateSource::NeuralDesktop ||
|
||||
source == CandidateSource::NeuralKeyboard;
|
||||
if (!early_return_source || candidate_canonical_pinyin.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -717,6 +717,10 @@ void AppendAiContext(const std::string &committed_word)
|
||||
++cut;
|
||||
g_ai_context.erase(0, cut);
|
||||
}
|
||||
// 同一份上屏历史也是神经整句重排的前文(青简那边叫 InputHistory):下一次查询会随
|
||||
// QueryRequest 下发到词典层。词典层自己按 RerankOptions::context_chars 取末尾若干字。
|
||||
if (g_inputSession)
|
||||
g_inputSession->set_rescoring_context(g_ai_context);
|
||||
}
|
||||
|
||||
std::wstring BuildCreateWordPipePayload(const std::string &remaining_raw_input_with_cases,
|
||||
@@ -1207,6 +1211,16 @@ std::string BuildCurrentCandidatePage()
|
||||
view.badge = " ☁️";
|
||||
else if (item.source == CandidateSource::AiSuggestion)
|
||||
view.badge = " 🤖";
|
||||
// 整句来源标签与设置页名称保持一致,方便同时比较四个来源。两家选中同一句时只剩一行,
|
||||
// 标签归先保留下来的来源;开启去重补位后,其余来源会改为显示自己的下一条不同结果。
|
||||
else if (item.source == CandidateSource::Generated)
|
||||
view.badge = " 〔Trigram〕";
|
||||
else if (item.source == CandidateSource::Fallback)
|
||||
view.badge = " 〔Unigram〕";
|
||||
else if (item.source == CandidateSource::NeuralDesktop)
|
||||
view.badge = " 〔神经D〕";
|
||||
else if (item.source == CandidateSource::NeuralKeyboard)
|
||||
view.badge = " 〔神经K〕";
|
||||
view.fixed_position = item.fixed_position > 0;
|
||||
EnglishIme::TranslationQuery translation_query;
|
||||
if (!translation_page && BuildTranslationQuery(item, translation_query))
|
||||
@@ -1600,6 +1614,8 @@ enum class TaskType
|
||||
RefreshCandidatePage,
|
||||
ResetInputSessionCache,
|
||||
ExitEnglishInputMode,
|
||||
// 神经整句重排在后台线程里算完了,候选顺序需要就地更新一次。
|
||||
ApplyRescoredOrder,
|
||||
};
|
||||
|
||||
struct Task
|
||||
@@ -1830,6 +1846,7 @@ void ProcessSelectionKey(UINT keycode, uint64_t client_id, uint64_t activation_e
|
||||
void WaitForCandidateRenderSync(UINT keycode);
|
||||
void ApplyCloudCandidate(const std::string &candidate, const std::string &pinyin, uint64_t generation,
|
||||
const std::optional<metasequoia::OnlineQuery> &query);
|
||||
void ApplyRescoredOrder();
|
||||
void ApplyAiCandidate(const std::string &candidate, const std::string &identity, uint64_t generation,
|
||||
const std::optional<metasequoia::OnlineQuery> &query);
|
||||
void ApplyEnglishCandidates(std::vector<WordItem> candidates, const std::string &input, uint64_t generation);
|
||||
@@ -2408,6 +2425,11 @@ void WorkerThread()
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TaskType::ApplyRescoredOrder: {
|
||||
ApplyRescoredOrder();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2467,6 +2489,19 @@ void EnqueueCloudCandidate(const std::string &candidate, const std::string &piny
|
||||
pipe_queueCv.notify_one();
|
||||
}
|
||||
|
||||
// 后台线程算完了一批整句重排。它不知道自己算的是不是当前这次输入——那要在任务线程上、拿着
|
||||
// g_inputSession 才判断得了——所以这里只负责把「去看一眼」排进队列,判断留给 ApplyRescoredOrder。
|
||||
void EnqueueRescoredCandidates()
|
||||
{
|
||||
{
|
||||
std::lock_guard lock(queueMutex);
|
||||
Task task;
|
||||
task.type = TaskType::ApplyRescoredOrder;
|
||||
taskQueue.push(std::move(task));
|
||||
}
|
||||
pipe_queueCv.notify_one();
|
||||
}
|
||||
|
||||
void EnqueueAiCandidate(const std::string &candidate, const std::string &identity, uint64_t generation)
|
||||
{
|
||||
const AsyncRequestOrigin origin = FindAiRequestOrigin(identity, generation);
|
||||
@@ -3866,6 +3901,53 @@ void ApplyCloudCandidate(const std::string &candidate, const std::string &pinyin
|
||||
RefreshCandidatePageUi(true);
|
||||
}
|
||||
|
||||
// 候选列表当初是按词格的静态顺序发出去的,因为打分那会儿还没算完。现在算完了:把引擎的候选缓存
|
||||
// 丢掉重查一次,这一次 quanpin::make_neural_reranker 能在结果表里查到顺序,整句就落到它该在的位
|
||||
// 置上。重查本身不碰模型,走的还是词格那条快路。
|
||||
//
|
||||
// 后台线程算的可能已经是上一次输入的了(用户没停手),所以这里不认「哪一批」,只看重查出来的词
|
||||
// 序有没有真的变:没变就一个字节都不动 UI。这既挡掉了过期结果,也挡掉了模型弃权的情况。
|
||||
void ApplyRescoredOrder()
|
||||
{
|
||||
if (!g_inputSession || g_translation_candidates_active)
|
||||
return;
|
||||
// 造词界面和译文页各自占着 items,重排不该去动它们。
|
||||
if (GlobalIme::composition.creating_word.active)
|
||||
return;
|
||||
if (Global::candidate_ui.items.empty())
|
||||
return;
|
||||
const FanyImeIpc::CandidateUiOwner owner = SnapshotCandidateUiOwner();
|
||||
if (!owner || !IsPipeActivationCurrent(owner.client_id, owner.activation_epoch))
|
||||
return;
|
||||
|
||||
const std::vector<WordItem> before = g_inputSession->get_candidates();
|
||||
// 云/AI 候选只活在 series cache 里,reset_cache 会把它们一起清掉,而它们的请求早已回来、不会
|
||||
// 再发一次——不补回来,重排一落地它们就从列表里消失了。重查不推进在线请求的 generation,
|
||||
// 所以用当前的 online_query 原样回填即可;回填时若同一句已被整句候选占了,引擎自己会拒绝。
|
||||
std::vector<WordItem> online_items;
|
||||
std::copy_if(before.begin(), before.end(), std::back_inserter(online_items), [](const WordItem &item) {
|
||||
return item.source == CandidateSource::CloudSuggestion || item.source == CandidateSource::AiSuggestion;
|
||||
});
|
||||
g_inputSession->reset_cache();
|
||||
g_inputSession->recompute_candidates();
|
||||
if (!online_items.empty())
|
||||
{
|
||||
if (const auto query = g_inputSession->online_query())
|
||||
{
|
||||
for (const WordItem &item : online_items)
|
||||
g_inputSession->apply_online_candidate(*query, item.word, item.source);
|
||||
}
|
||||
}
|
||||
const std::vector<WordItem> &after = g_inputSession->get_candidates();
|
||||
if (after.size() == before.size() &&
|
||||
std::equal(before.begin(), before.end(), after.begin(),
|
||||
[](const WordItem &a, const WordItem &b) { return a.word == b.word; }))
|
||||
return;
|
||||
|
||||
PrepareCandidateList(owner.client_id, owner.activation_epoch);
|
||||
RequestShowCandidateWindow();
|
||||
}
|
||||
|
||||
void ApplyAiCandidate(const std::string &candidate, const std::string &identity, uint64_t generation,
|
||||
const std::optional<metasequoia::OnlineQuery> &engine_query)
|
||||
{
|
||||
|
||||
@@ -49,6 +49,8 @@ void ClearState();
|
||||
void RegisterStatusSnapshotWindow(HWND toolbar_window);
|
||||
void EnqueueCloudCandidate(const std::string &candidate, const std::string &pinyin, uint64_t generation);
|
||||
void EnqueueAiCandidate(const std::string &candidate, const std::string &identity, uint64_t generation);
|
||||
// 神经整句重排的后台线程算完一批后调这个;见 event_listener.cpp 的 ApplyRescoredOrder。
|
||||
void EnqueueRescoredCandidates();
|
||||
void CancelCloudCandidateRequest();
|
||||
void EnqueueEnglishCandidates(std::vector<WordItem> candidates, const std::string &input, uint64_t generation);
|
||||
void EnqueueCandidateTranslations(std::vector<EnglishIme::TranslationResult> results, uint64_t generation,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "english/english_ime.h"
|
||||
#include "emoji/emoji_ime.h"
|
||||
#include "kaomoji/kaomoji_ime.h"
|
||||
#include "engine/neural/rescore_worker.h"
|
||||
#include "utils/common_utils.h"
|
||||
#include "utils/single_instance.h"
|
||||
#include "session/session_factory.h"
|
||||
@@ -176,6 +177,9 @@ int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE /*hPrevInstance*/,
|
||||
AiAssistant::Start([](const std::string &candidate, const std::string &identity, uint64_t generation) {
|
||||
FanyNamedPipe::EnqueueAiCandidate(candidate, identity, generation);
|
||||
});
|
||||
// 神经整句重排:打分在引擎自己的后台线程上跑,算完通过这个回调回到任务队列,由队列去重查候选。
|
||||
// 不 Start 什么线程——没开这个开关的用户不会平白多一条。
|
||||
neural::RescoreWorker::instance().set_ready_callback([] { FanyNamedPipe::EnqueueRescoredCandidates(); });
|
||||
EnglishIme::Start(
|
||||
CommonUtils::get_ime_data_path() + "\\english.db",
|
||||
[](std::vector<WordItem> candidates, const std::string &input, uint64_t generation) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "engine_input_session.h"
|
||||
#include "config/ime_config.h"
|
||||
#include "engine/common/helpcode_utils.h"
|
||||
#include "engine/core/sentence_association_options.h"
|
||||
#include "engine/quanpin/quanpin_utils.h"
|
||||
|
||||
EngineInputSession::EngineInputSession(SchemeType scheme, const ShuangpinProfile &profile)
|
||||
@@ -38,6 +39,14 @@ void EngineInputSession::ApplyConfiguration()
|
||||
// converted quanpin syllables for shuangpin. Re-read on every key so setting
|
||||
// changes take effect immediately.
|
||||
session_.set_fuzzy_pinyin_options(GetConfiguredFuzzyPinyinOptions());
|
||||
// 整句候选来源与去重补位选项,每次击键重读,改设置立即生效。
|
||||
SentenceAssociationOptions association;
|
||||
association.word_lattice = GetConfiguredAssocSentenceWordLattice();
|
||||
association.google = GetConfiguredAssocSentenceGoogle();
|
||||
association.neural_desktop = GetConfiguredAssocSentenceNeuralDesktop();
|
||||
association.neural_keyboard = GetConfiguredAssocSentenceNeuralKeyboard();
|
||||
association.show_next_on_duplicate = GetConfiguredAssocSentenceShowNextOnDuplicate();
|
||||
session_.set_sentence_association(association);
|
||||
session_.set_shuangpin_preedit_uses_raw(GetConfiguredShuangpinPreeditMode() == "shuangpin");
|
||||
}
|
||||
|
||||
@@ -144,6 +153,11 @@ bool EngineInputSession::has_active_helpcode() const
|
||||
return session_.has_active_helpcode();
|
||||
}
|
||||
|
||||
void EngineInputSession::set_rescoring_context(std::string context)
|
||||
{
|
||||
return session_.set_rescoring_context(std::move(context));
|
||||
}
|
||||
|
||||
void EngineInputSession::set_pinyin_sequence(const std::string &pinyin_sequence)
|
||||
{
|
||||
return session_.set_pinyin_sequence(pinyin_sequence);
|
||||
|
||||
@@ -35,6 +35,7 @@ class EngineInputSession : public IInputSession
|
||||
bool wubi_four_code_is_complete() const override;
|
||||
bool has_active_helpcode() const override;
|
||||
|
||||
void set_rescoring_context(std::string context) override;
|
||||
void set_pinyin_sequence(const std::string &pinyin_sequence) override;
|
||||
void set_pinyin_sequence_with_cases(const std::string &pinyin_sequence) override;
|
||||
|
||||
|
||||
@@ -53,6 +53,11 @@ class IInputSession
|
||||
virtual bool wubi_four_code_is_complete() const = 0;
|
||||
virtual bool has_active_helpcode() const = 0;
|
||||
|
||||
// 本会话最近上屏的文本,给神经整句重排当前文。空实现:除引擎会话外没人需要前文。
|
||||
virtual void set_rescoring_context(std::string)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void set_pinyin_sequence(const std::string &pinyin_sequence) = 0;
|
||||
virtual void set_pinyin_sequence_with_cases(const std::string &pinyin_sequence) = 0;
|
||||
|
||||
|
||||
@@ -374,6 +374,12 @@ std::wstring BuildConfigMessage(bool refresh_skin_catalog)
|
||||
{"paging_page_up_down", GetConfiguredPagingPageUpDownEnabled()},
|
||||
{"paging_mouse_wheel", GetConfiguredPagingMouseWheelEnabled()},
|
||||
{"candidate_arrow_navigation", GetConfiguredCandidateArrowNavigationEnabled()}}},
|
||||
{"association",
|
||||
{{"sentence_wordlattice", GetConfiguredAssocSentenceWordLattice()},
|
||||
{"sentence_google", GetConfiguredAssocSentenceGoogle()},
|
||||
{"sentence_neural_desktop", GetConfiguredAssocSentenceNeuralDesktop()},
|
||||
{"sentence_neural_keyboard", GetConfiguredAssocSentenceNeuralKeyboard()},
|
||||
{"sentence_show_next_on_duplicate", GetConfiguredAssocSentenceShowNextOnDuplicate()}}},
|
||||
{"keybindings",
|
||||
{{"switch_language_shift", GetConfiguredSwitchLanguageShiftEnabled()},
|
||||
{"switch_language_ctrl", GetConfiguredSwitchLanguageCtrlEnabled()},
|
||||
@@ -681,6 +687,16 @@ bool ApplyConfigUpdate(const json::object &data)
|
||||
return SetConfiguredKaomojiMixedInputEnabled(json::value_to<bool>(data.at("value")));
|
||||
if (path == "general.cloud_candidates")
|
||||
return SetConfiguredCloudCandidatesEnabled(json::value_to<bool>(data.at("value")));
|
||||
if (path == "association.sentence_wordlattice")
|
||||
return SetConfiguredAssocSentenceWordLattice(json::value_to<bool>(data.at("value")));
|
||||
if (path == "association.sentence_google")
|
||||
return SetConfiguredAssocSentenceGoogle(json::value_to<bool>(data.at("value")));
|
||||
if (path == "association.sentence_neural_desktop")
|
||||
return SetConfiguredAssocSentenceNeuralDesktop(json::value_to<bool>(data.at("value")));
|
||||
if (path == "association.sentence_neural_keyboard")
|
||||
return SetConfiguredAssocSentenceNeuralKeyboard(json::value_to<bool>(data.at("value")));
|
||||
if (path == "association.sentence_show_next_on_duplicate")
|
||||
return SetConfiguredAssocSentenceShowNextOnDuplicate(json::value_to<bool>(data.at("value")));
|
||||
if (path == "utility.unicode_mode")
|
||||
return SetConfiguredUnicodeModeEnabled(json::value_to<bool>(data.at("value")));
|
||||
if (path == "utility.quick_phrase")
|
||||
|
||||
@@ -4267,6 +4267,46 @@ HRESULT OnControllerCreatedSettingsWnd( //
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path == "association.sentence_wordlattice")
|
||||
{
|
||||
const bool value = json::value_to<bool>(data.at("value"));
|
||||
if (SetConfiguredAssocSentenceWordLattice(value))
|
||||
{
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path == "association.sentence_google")
|
||||
{
|
||||
const bool value = json::value_to<bool>(data.at("value"));
|
||||
if (SetConfiguredAssocSentenceGoogle(value))
|
||||
{
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path == "association.sentence_neural_desktop")
|
||||
{
|
||||
const bool value = json::value_to<bool>(data.at("value"));
|
||||
if (SetConfiguredAssocSentenceNeuralDesktop(value))
|
||||
{
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path == "association.sentence_neural_keyboard")
|
||||
{
|
||||
const bool value = json::value_to<bool>(data.at("value"));
|
||||
if (SetConfiguredAssocSentenceNeuralKeyboard(value))
|
||||
{
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path == "association.sentence_show_next_on_duplicate")
|
||||
{
|
||||
const bool value = json::value_to<bool>(data.at("value"));
|
||||
if (SetConfiguredAssocSentenceShowNextOnDuplicate(value))
|
||||
{
|
||||
PostSettingsConfig();
|
||||
}
|
||||
}
|
||||
else if (path == "utility.unicode_mode")
|
||||
{
|
||||
const bool value = json::value_to<bool>(data.at("value"));
|
||||
@@ -4636,6 +4676,12 @@ void PostSettingsConfig()
|
||||
{"paging_page_up_down", GetConfiguredPagingPageUpDownEnabled()},
|
||||
{"paging_mouse_wheel", GetConfiguredPagingMouseWheelEnabled()},
|
||||
{"candidate_arrow_navigation", GetConfiguredCandidateArrowNavigationEnabled()}}},
|
||||
{"association",
|
||||
{{"sentence_wordlattice", GetConfiguredAssocSentenceWordLattice()},
|
||||
{"sentence_google", GetConfiguredAssocSentenceGoogle()},
|
||||
{"sentence_neural_desktop", GetConfiguredAssocSentenceNeuralDesktop()},
|
||||
{"sentence_neural_keyboard", GetConfiguredAssocSentenceNeuralKeyboard()},
|
||||
{"sentence_show_next_on_duplicate", GetConfiguredAssocSentenceShowNextOnDuplicate()}}},
|
||||
{"keybindings",
|
||||
{{"switch_language_shift", GetConfiguredSwitchLanguageShiftEnabled()},
|
||||
{"switch_language_ctrl", GetConfiguredSwitchLanguageCtrlEnabled()},
|
||||
|
||||
@@ -181,6 +181,21 @@ function applyConfigData(data: Record<string, any>, target?: string): void {
|
||||
if (typeof data?.general?.cloud_candidates === 'boolean') {
|
||||
applyToggleState('cloudCandidatesToggleBtn', data.general.cloud_candidates);
|
||||
}
|
||||
if (typeof data?.association?.sentence_wordlattice === 'boolean') {
|
||||
applyToggleState('sentenceWordLatticeToggleBtn', data.association.sentence_wordlattice);
|
||||
}
|
||||
if (typeof data?.association?.sentence_google === 'boolean') {
|
||||
applyToggleState('sentenceGoogleToggleBtn', data.association.sentence_google);
|
||||
}
|
||||
if (typeof data?.association?.sentence_neural_desktop === 'boolean') {
|
||||
applyToggleState('sentenceNeuralDesktopToggleBtn', data.association.sentence_neural_desktop);
|
||||
}
|
||||
if (typeof data?.association?.sentence_neural_keyboard === 'boolean') {
|
||||
applyToggleState('sentenceNeuralKeyboardToggleBtn', data.association.sentence_neural_keyboard);
|
||||
}
|
||||
if (typeof data?.association?.sentence_show_next_on_duplicate === 'boolean') {
|
||||
applyToggleState('sentenceShowNextOnDuplicateToggleBtn', data.association.sentence_show_next_on_duplicate);
|
||||
}
|
||||
if (typeof data?.utility?.unicode_mode === 'boolean') {
|
||||
applyToggleState('unicodeModeToggleBtn', data.utility.unicode_mode);
|
||||
}
|
||||
|
||||
@@ -345,6 +345,23 @@ export function setupInput(): void {
|
||||
setupToggleButton('cloudCandidatesToggleBtn', (active) => {
|
||||
updateConfig('general.cloud_candidates', active);
|
||||
});
|
||||
// 四个整句来源和一个去重补位开关,默认全关。两个神经来源会自行在词格中生成最多 12 条
|
||||
// 内部备选;补位打开后,某来源的首选重复时沿该来源自己的排名寻找下一条不同结果。
|
||||
setupToggleButton('sentenceWordLatticeToggleBtn', (active) => {
|
||||
updateConfig('association.sentence_wordlattice', active);
|
||||
});
|
||||
setupToggleButton('sentenceGoogleToggleBtn', (active) => {
|
||||
updateConfig('association.sentence_google', active);
|
||||
});
|
||||
setupToggleButton('sentenceNeuralDesktopToggleBtn', (active) => {
|
||||
updateConfig('association.sentence_neural_desktop', active);
|
||||
});
|
||||
setupToggleButton('sentenceNeuralKeyboardToggleBtn', (active) => {
|
||||
updateConfig('association.sentence_neural_keyboard', active);
|
||||
});
|
||||
setupToggleButton('sentenceShowNextOnDuplicateToggleBtn', (active) => {
|
||||
updateConfig('association.sentence_show_next_on_duplicate', active);
|
||||
});
|
||||
}
|
||||
|
||||
function setupFrequencyOptions(): void {
|
||||
|
||||
@@ -558,6 +558,62 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-header">
|
||||
<div>
|
||||
<div class="section-title">整句候选</div>
|
||||
<div class="input-setting-description">输入多个拼音音节时,提供整句候选</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frequency-option-content">
|
||||
<div class="section-header frequency-option-row">
|
||||
<div>
|
||||
<div class="section-title">Trigram 模型整句</div>
|
||||
<div class="input-setting-description">使用三元语言模型生成整句候选</div>
|
||||
</div>
|
||||
<div class="ftb-toggle-btn" id="sentenceWordLatticeToggleBtn" role="switch" aria-checked="false" tabindex="0">
|
||||
<div class="ftb-toggle-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-header frequency-option-row">
|
||||
<div>
|
||||
<div class="section-title">Unigram 模型整句</div>
|
||||
<div class="input-setting-description">使用 Google 拼音的一元语言模型生成整句候选</div>
|
||||
</div>
|
||||
<div class="ftb-toggle-btn" id="sentenceGoogleToggleBtn" role="switch" aria-checked="false" tabindex="0">
|
||||
<div class="ftb-toggle-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-header frequency-option-row">
|
||||
<div>
|
||||
<div class="section-title">神经网络模型整句(效果优先)</div>
|
||||
<div class="input-setting-description">结合已上屏的前文,从内部生成的最多 12 个备选句中选择,处理时间较长</div>
|
||||
</div>
|
||||
<div class="ftb-toggle-btn" id="sentenceNeuralDesktopToggleBtn" role="switch" aria-checked="false" tabindex="0">
|
||||
<div class="ftb-toggle-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-header frequency-option-row">
|
||||
<div>
|
||||
<div class="section-title">神经网络模型整句(速度优先)</div>
|
||||
<div class="input-setting-description">使用轻量模型从最多 12 个备选句中选择;两种模式可同时独立给出结果</div>
|
||||
</div>
|
||||
<div class="ftb-toggle-btn" id="sentenceNeuralKeyboardToggleBtn" role="switch" aria-checked="false" tabindex="0">
|
||||
<div class="ftb-toggle-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-header frequency-option-row">
|
||||
<div>
|
||||
<div class="section-title">去重后补充次选</div>
|
||||
<div class="input-setting-description">某个模型的首选与已有候选重复时,显示该模型排名最高的下一条不同结果</div>
|
||||
</div>
|
||||
<div class="ftb-toggle-btn" id="sentenceShowNextOnDuplicateToggleBtn" role="switch" aria-checked="false" tabindex="0">
|
||||
<div class="ftb-toggle-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-header"><div class="section-title">拼音方案调频</div></div>
|
||||
<div class="frequency-option-content">
|
||||
|
||||
Reference in new issue
Block a user