#pragma once #include "spelling_graph.h" #include "../quanpin/quanpin_query.h" #include #include #include #include #include // 直接辅助码的整句解码:在按键位置上的拼写图里铺词,一次 Viterbi 同时决定切分与用字。 // // 和 quanpin::decode_word_lattice 用同一套打分(kenlm、词库权重平局、生僻读音先验、octagram // 搭配项),区别只在图:那边的节点是固定切分的音节序号,这里是输入串的按键位置,同一段按键 // 的不同切法(uia|uiq 与 ui|au|iq)各自成边,由整句分数裁决。这就是 librime 在万象里做的事。 // 打分函数是从 word_lattice.cpp 抄过来的,为的是不动全拼的解码器。 namespace direct_helpcode { // 按全拼跨度查词。constrained 为真时跨度里有辅码约束,查询不能在 SQL 里先截断(生僻字会被 // 截没),由解码器筛完约束再截。 using SpanLookup = std::function(const quanpin::Segments &span, bool constrained)>; // 这个汉字(UTF-8 单字)的辅码满不满足 first/second(second 为 0 只看第一码)。 using CharAccept = std::function; struct DecodeOptions { int beam = 32; int span_limit = 32; int max_phrase_syllables = 7; // 每个起点最多展开多少条拼写序列,防止长串上组合爆炸。 int max_sequences_per_start = 256; const ngram::LanguageModel *language_model = nullptr; double dictionary_tiebreak = 0.01; double reading_prior = 1.0; double reading_prior_share = 0.01; double reading_prior_floor = 5.0; double unigram_z = 1e6; double phrase_length_bonus = 3.0; // 单个声母(缩写)占位边的分数:没有字可出,只让切分走得通,任何真正出字的切法都比它好。 double initial_penalty = -12.0; quanpin::LatticeCollocationScorer collocation_scorer; double collocation_weight = 0.0; }; struct DecodedPath { std::vector syllables; std::string sentence; // 全拼键(' 分隔)与逐词文本,和 quanpin::LatticePath 同义,供词格合并直接复用。 std::string key; std::vector words; double log_prob = 0; // 路径上有占位边(声母缩写、查不到字的音节)时整句不完整,不能当整句候选。 bool complete = true; }; // 一条拼写序列(音节 + 辅码)铺出来的词,跨按键复用:多敲一个键时前面那些序列的查词、辅码筛选 // 和打分都不变。只和词库、码表、打分选项有关,三者变了由调用方清空。 struct CachedWord { std::string word; std::string key; double base_score = 0; ngram::WordIndex index = 0; }; using WordEdgeMemo = std::unordered_map>; std::optional decode_best_path(const SpellingGraph &graph, const SpanLookup &lookup, const CharAccept &accept, const DecodeOptions &options = {}, WordEdgeMemo *memo = nullptr); } // namespace direct_helpcode