將用戶選字記憶機制整合入 InputMethodController
This commit is contained in:
parent
b5599f8a31
commit
d8356a7940
|
@ -46,10 +46,12 @@ namespace Formosa {
|
||||||
bool isCandidateFixed() const;
|
bool isCandidateFixed() const;
|
||||||
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 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;
|
||||||
|
@ -165,6 +167,16 @@ namespace Formosa {
|
||||||
m_candidateFixed = inFix;
|
m_candidateFixed = inFix;
|
||||||
m_score = 99;
|
m_score = 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
{
|
{
|
||||||
|
@ -175,6 +187,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;
|
||||||
|
|
|
@ -112,6 +112,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);
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
@interface McBopomofoInputMethodController () <VTCandidateControllerDelegate>
|
@interface McBopomofoInputMethodController () <VTCandidateControllerDelegate>
|
||||||
|
@ -175,6 +176,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("-");
|
||||||
|
@ -610,6 +612,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];
|
||||||
|
@ -1315,10 +1344,11 @@ public:
|
||||||
|
|
||||||
// candidate selected, override the node with selection
|
// candidate selected, override the node with selection
|
||||||
string selectedValue = [[_candidates objectAtIndex:index] UTF8String];
|
string selectedValue = [[_candidates objectAtIndex:index] UTF8String];
|
||||||
|
|
||||||
size_t cursorIndex = [self actualCandidateCursorIndex];
|
size_t cursorIndex = [self actualCandidateCursorIndex];
|
||||||
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
|
|
||||||
|
|
||||||
|
_uom->observe(_walkedNodes, cursorIndex, selectedValue, [[NSDate date] timeIntervalSince1970]);
|
||||||
|
|
||||||
|
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
|
||||||
for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
|
for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
|
||||||
const vector<KeyValuePair>& candidates = (*ni).node->candidates();
|
const vector<KeyValuePair>& candidates = (*ni).node->candidates();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue