將用戶選字記憶機制整合入 InputMethodController
This commit is contained in:
parent
d672136843
commit
3e0e859feb
|
@ -47,10 +47,12 @@ namespace Formosa {
|
||||||
const vector<KeyValuePair>& candidates() const;
|
const vector<KeyValuePair>& candidates() const;
|
||||||
void selectCandidateAtIndex(size_t inIndex = 0, bool inFix = true);
|
void selectCandidateAtIndex(size_t inIndex = 0, bool inFix = true);
|
||||||
void resetCandidate();
|
void resetCandidate();
|
||||||
|
void selectFloatingCandidateAtIndex(size_t index, double score);
|
||||||
|
|
||||||
const string& key() const;
|
const string& key() const;
|
||||||
double score() const;
|
double score() const;
|
||||||
const KeyValuePair currentKeyValue() const;
|
const KeyValuePair currentKeyValue() const;
|
||||||
|
double highestUnigramScore() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const LanguageModel* m_LM;
|
const LanguageModel* m_LM;
|
||||||
|
@ -175,6 +177,16 @@ namespace Formosa {
|
||||||
m_score = m_unigrams[0].score;
|
m_score = m_unigrams[0].score;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Node::selectFloatingCandidateAtIndex(size_t index, double score) {
|
||||||
|
if (index >= m_unigrams.size()) {
|
||||||
|
m_selectedUnigramIndex = 0;
|
||||||
|
} else {
|
||||||
|
m_selectedUnigramIndex = index;
|
||||||
|
}
|
||||||
|
m_candidateFixed = false;
|
||||||
|
m_score = score;
|
||||||
|
}
|
||||||
|
|
||||||
inline const string& Node::key() const
|
inline const string& Node::key() const
|
||||||
{
|
{
|
||||||
|
@ -185,6 +197,13 @@ namespace Formosa {
|
||||||
{
|
{
|
||||||
return m_score;
|
return m_score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline double Node::highestUnigramScore() const {
|
||||||
|
if (m_unigrams.empty()) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return m_unigrams[0].score;
|
||||||
|
}
|
||||||
|
|
||||||
inline const KeyValuePair Node::currentKeyValue() const
|
inline const KeyValuePair Node::currentKeyValue() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#import "Mandarin.h"
|
#import "Mandarin.h"
|
||||||
#import "Gramambular.h"
|
#import "Gramambular.h"
|
||||||
#import "FastLM.h"
|
#import "FastLM.h"
|
||||||
|
#import "UserOverrideModel.h"
|
||||||
|
|
||||||
@interface McBopomofoInputMethodController : IMKInputController
|
@interface McBopomofoInputMethodController : IMKInputController
|
||||||
{
|
{
|
||||||
|
@ -53,6 +54,9 @@
|
||||||
// latest walked path (trellis) using the Viterbi algorithm
|
// latest walked path (trellis) using the Viterbi algorithm
|
||||||
std::vector<Formosa::Gramambular::NodeAnchor> _walkedNodes;
|
std::vector<Formosa::Gramambular::NodeAnchor> _walkedNodes;
|
||||||
|
|
||||||
|
// user override model
|
||||||
|
McBopomofo::UserOverrideModel *_uom;
|
||||||
|
|
||||||
// the latest composing buffer that is updated to the foreground app
|
// the latest composing buffer that is updated to the foreground app
|
||||||
NSMutableString *_composingBuffer;
|
NSMutableString *_composingBuffer;
|
||||||
NSInteger _latestReadingCursor;
|
NSInteger _latestReadingCursor;
|
||||||
|
|
|
@ -114,6 +114,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
// shared language model object that stores our phrase-term probability database
|
// shared language model object that stores our phrase-term probability database
|
||||||
FastLM gLanguageModel;
|
FastLM gLanguageModel;
|
||||||
FastLM gLanguageModelPlainBopomofo;
|
FastLM gLanguageModelPlainBopomofo;
|
||||||
|
McBopomofo::UserOverrideModel gUserOverrideModel(200, 60.0);
|
||||||
|
|
||||||
// https://clang-analyzer.llvm.org/faq.html
|
// https://clang-analyzer.llvm.org/faq.html
|
||||||
__attribute__((annotate("returns_localized_nsstring")))
|
__attribute__((annotate("returns_localized_nsstring")))
|
||||||
|
@ -176,6 +177,7 @@ public:
|
||||||
// create the lattice builder
|
// create the lattice builder
|
||||||
_languageModel = &gLanguageModel;
|
_languageModel = &gLanguageModel;
|
||||||
_builder = new BlockReadingBuilder(_languageModel);
|
_builder = new BlockReadingBuilder(_languageModel);
|
||||||
|
_uom = &gUserOverrideModel;
|
||||||
|
|
||||||
// each Mandarin syllable is separated by a hyphen
|
// each Mandarin syllable is separated by a hyphen
|
||||||
_builder->setJoinSeparator("-");
|
_builder->setJoinSeparator("-");
|
||||||
|
@ -659,6 +661,33 @@ public:
|
||||||
// then walk the lattice
|
// then walk the lattice
|
||||||
[self popOverflowComposingTextAndWalk:client];
|
[self popOverflowComposingTextAndWalk:client];
|
||||||
|
|
||||||
|
// get user override model suggestion
|
||||||
|
string overrideCandidate = _uom->suggest(_walkedNodes, _builder->cursorIndex(), [[NSDate date] timeIntervalSince1970]);
|
||||||
|
if (!overrideCandidate.empty()) {
|
||||||
|
size_t cursorIndex = [self actualCandidateCursorIndex];
|
||||||
|
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
|
||||||
|
|
||||||
|
double highestScore = 0.0;
|
||||||
|
for (auto ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
|
||||||
|
double score = ni->node->highestUnigramScore();
|
||||||
|
if (score > highestScore) {
|
||||||
|
highestScore = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
highestScore += 0.00001;
|
||||||
|
|
||||||
|
for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
|
||||||
|
const vector<KeyValuePair>& candidates = (*ni).node->candidates();
|
||||||
|
for (size_t i = 0, c = candidates.size(); i < c; ++i) {
|
||||||
|
if (candidates[i].value == overrideCandidate) {
|
||||||
|
// found our node
|
||||||
|
const_cast<Node*>((*ni).node)->selectFloatingCandidateAtIndex(i, highestScore);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// then update the text
|
// then update the text
|
||||||
_bpmfReadingBuffer->clear();
|
_bpmfReadingBuffer->clear();
|
||||||
[self updateClientComposingBuffer:client];
|
[self updateClientComposingBuffer:client];
|
||||||
|
@ -1373,6 +1402,7 @@ public:
|
||||||
|
|
||||||
size_t cursorIndex = [self actualCandidateCursorIndex];
|
size_t cursorIndex = [self actualCandidateCursorIndex];
|
||||||
_builder->grid().fixNodeSelectedCandidate(cursorIndex, selectedValue);
|
_builder->grid().fixNodeSelectedCandidate(cursorIndex, selectedValue);
|
||||||
|
_uom->observe(_walkedNodes, cursorIndex, selectedValue, [[NSDate date] timeIntervalSince1970]);
|
||||||
|
|
||||||
[_candidates removeAllObjects];
|
[_candidates removeAllObjects];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue