lmUserOverride // Another attempt to make it functional.
- Now it successfully generates keys and starts observing things. The rest issue is that it cannot give a useful suggestion.
This commit is contained in:
parent
dd317455e2
commit
b466c57137
|
@ -1,6 +1,5 @@
|
||||||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||||
// Refactored from the ObjCpp-version of this class by:
|
// Refactored from the ObjCpp-version of this class by Mengjuei Hsieh (MIT License).
|
||||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
|
||||||
/*
|
/*
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
@ -68,7 +67,7 @@ extension vChewing {
|
||||||
|
|
||||||
var mutCapacity: Int
|
var mutCapacity: Int
|
||||||
var mutDecayExponent: Double
|
var mutDecayExponent: Double
|
||||||
var mutLRUList = [KeyObservationPair]()
|
var mutLRUList: [KeyObservationPair] = []
|
||||||
var mutLRUMap: [String: KeyObservationPair] = [:]
|
var mutLRUMap: [String: KeyObservationPair] = [:]
|
||||||
let kDecayThreshold: Double = 1.0 / 1_048_576.0
|
let kDecayThreshold: Double = 1.0 / 1_048_576.0
|
||||||
|
|
||||||
|
@ -86,27 +85,27 @@ extension vChewing {
|
||||||
candidate: String,
|
candidate: String,
|
||||||
timestamp: Double
|
timestamp: Double
|
||||||
) {
|
) {
|
||||||
let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
let key = convertKeyFrom(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
||||||
guard !key.isEmpty
|
|
||||||
else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard mutLRUMap[key] != nil else {
|
guard mutLRUMap[key] != nil else {
|
||||||
var observation: Observation = .init()
|
var observation: Observation = .init()
|
||||||
observation.update(candidate: candidate, timestamp: timestamp)
|
observation.update(candidate: candidate, timestamp: timestamp)
|
||||||
mutLRUMap[key] = KeyObservationPair(key: key, observation: observation)
|
let koPair = KeyObservationPair(key: key, observation: observation)
|
||||||
mutLRUList.insert(KeyObservationPair(key: key, observation: observation), at: 0)
|
mutLRUMap[key] = koPair
|
||||||
|
mutLRUList.insert(koPair, at: 0)
|
||||||
|
|
||||||
if mutLRUList.count > mutCapacity {
|
if mutLRUList.count > mutCapacity {
|
||||||
mutLRUMap[mutLRUList.reversed()[0].key] = nil
|
mutLRUMap[mutLRUList[mutLRUList.endIndex].key] = nil
|
||||||
mutLRUList.removeLast()
|
mutLRUList.removeLast()
|
||||||
}
|
}
|
||||||
|
IME.prtDebugIntel("UOM: Observation finished with new observation: \(key)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mutLRUList.insert(contentsOf: mutLRUMap.values, at: 0)
|
if var theNeta = mutLRUMap[key] {
|
||||||
|
theNeta.observation.update(candidate: candidate, timestamp: timestamp)
|
||||||
if mutLRUMap[key] != nil {
|
mutLRUList.insert(theNeta, at: 0)
|
||||||
mutLRUMap[key]?.observation.update(candidate: candidate, timestamp: timestamp)
|
mutLRUMap[key] = theNeta
|
||||||
|
IME.prtDebugIntel("UOM: Observation finished with existing observation: \(key)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,25 +114,22 @@ extension vChewing {
|
||||||
cursorIndex: Int,
|
cursorIndex: Int,
|
||||||
timestamp: Double
|
timestamp: Double
|
||||||
) -> String {
|
) -> String {
|
||||||
let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
let key = convertKeyFrom(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
||||||
guard let keyValuePair = mutLRUMap[key],
|
guard let koPair = mutLRUMap[key] else {
|
||||||
!key.isEmpty
|
IME.prtDebugIntel("UOM: mutLRUMap[key] is nil, throwing blank suggestion for key: \(key).")
|
||||||
else {
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
IME.prtDebugIntel("Suggest - A: \(key)")
|
let observation = koPair.observation
|
||||||
IME.prtDebugIntel("Suggest - B: \(keyValuePair.key)")
|
|
||||||
|
|
||||||
let observation = keyValuePair.observation
|
|
||||||
|
|
||||||
var candidate = ""
|
var candidate = ""
|
||||||
var score = 0.0
|
var score = 0.0
|
||||||
for overrideNeta in Array(observation.overrides) {
|
for overrideNeta in Array(observation.overrides) {
|
||||||
let overrideScore = getScore(
|
let override: Override = overrideNeta.value
|
||||||
eventCount: overrideNeta.value.count,
|
let overrideScore: Double = getScore(
|
||||||
|
eventCount: override.count,
|
||||||
totalCount: observation.count,
|
totalCount: observation.count,
|
||||||
eventTimestamp: overrideNeta.value.timestamp,
|
eventTimestamp: override.timestamp,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
lambda: mutDecayExponent
|
lambda: mutDecayExponent
|
||||||
)
|
)
|
||||||
|
@ -147,11 +143,10 @@ extension vChewing {
|
||||||
score = overrideScore
|
score = overrideScore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return candidate
|
if candidate.isEmpty {
|
||||||
|
IME.prtDebugIntel("UOM: No usable suggestions in the result for key: \(key).")
|
||||||
}
|
}
|
||||||
|
return candidate
|
||||||
func isEndingPunctuation(value: String) -> Bool {
|
|
||||||
[",", "。", "!", "?", "」", "』", "”", "’"].contains(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getScore(
|
public func getScore(
|
||||||
|
@ -170,58 +165,51 @@ extension vChewing {
|
||||||
return prob * decay
|
return prob * decay
|
||||||
}
|
}
|
||||||
|
|
||||||
func getWalkedNodesToKey(
|
func convertKeyFrom(
|
||||||
walkedNodes: [Megrez.NodeAnchor], cursorIndex: Int
|
walkedNodes: [Megrez.NodeAnchor], cursorIndex: Int
|
||||||
) -> String {
|
) -> String {
|
||||||
var strOutput = ""
|
let arrEndingPunctuation = [",", "。", "!", "?", "」", "』", "”", "’"]
|
||||||
var arrNodes: [Megrez.NodeAnchor] = []
|
var arrNodesReversed: [Megrez.NodeAnchor] = []
|
||||||
var intLength = 0
|
var intLength = 0
|
||||||
for nodeNeta in walkedNodes {
|
for theNodeAnchor in walkedNodes {
|
||||||
arrNodes.append(nodeNeta)
|
// 這裡直接生成一個反向排序的陣列,之後就不用再「.reverse()」了。
|
||||||
intLength += nodeNeta.spanningLength
|
arrNodesReversed = [theNodeAnchor] + arrNodesReversed
|
||||||
|
intLength += theNodeAnchor.spanningLength
|
||||||
if intLength >= cursorIndex {
|
if intLength >= cursorIndex {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 一個被 .reversed 過的陣列不能直接使用,因為不是正常的 Swift 陣列。
|
if arrNodesReversed.isEmpty { return "" }
|
||||||
// 那就新開一個正常的陣列、然後將內容拓印過去。
|
|
||||||
var arrNodesReversed: [Megrez.NodeAnchor] = []
|
|
||||||
arrNodesReversed.append(contentsOf: arrNodes.reversed())
|
|
||||||
|
|
||||||
if arrNodesReversed.isEmpty {
|
var strCurrent = "()"
|
||||||
|
var strPrevious = "()"
|
||||||
|
var strAnterior = "()"
|
||||||
|
|
||||||
|
guard let kvCurrent = arrNodesReversed[0].node?.currentKeyValue(),
|
||||||
|
!arrEndingPunctuation.contains(kvCurrent.value)
|
||||||
|
else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var strCurrent = "()"
|
// 前置單元只記錄讀音,在其後的單元則同時記錄讀音與字詞
|
||||||
var strPrev = "()"
|
strCurrent = kvCurrent.key
|
||||||
var strAnterior = "()"
|
|
||||||
|
|
||||||
for (theIndex, theAnchor) in arrNodesReversed.enumerated() {
|
if arrNodesReversed.count >= 2,
|
||||||
if strCurrent != "()", let nodeCurrent = theAnchor.node {
|
let kvPrevious = arrNodesReversed[1].node?.currentKeyValue(),
|
||||||
let keyCurrent = nodeCurrent.currentKeyValue().key
|
!arrEndingPunctuation.contains(kvPrevious.value)
|
||||||
let valCurrent = nodeCurrent.currentKeyValue().value
|
{
|
||||||
strCurrent = "(\(keyCurrent), \(valCurrent))"
|
strPrevious = "(\(kvPrevious.key),\(kvPrevious.value))"
|
||||||
if let nodePrev = arrNodesReversed[theIndex + 1].node {
|
|
||||||
let keyPrev = nodePrev.currentKeyValue().key
|
|
||||||
let valPrev = nodePrev.currentKeyValue().value
|
|
||||||
strPrev = "(\(keyPrev), \(valPrev))"
|
|
||||||
}
|
|
||||||
if let nodeAnterior = arrNodesReversed[theIndex + 2].node {
|
|
||||||
let keyAnterior = nodeAnterior.currentKeyValue().key
|
|
||||||
let valAnterior = nodeAnterior.currentKeyValue().value
|
|
||||||
strAnterior = "(\(keyAnterior), \(valAnterior))"
|
|
||||||
}
|
|
||||||
break // 我們只取第一個有效結果。
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strOutput = "(\(strAnterior),\(strPrev),\(strCurrent))"
|
if arrNodesReversed.count >= 3,
|
||||||
if strOutput == "((),(),())" {
|
let kvAnterior = arrNodesReversed[2].node?.currentKeyValue(),
|
||||||
strOutput = ""
|
!arrEndingPunctuation.contains(kvAnterior.value)
|
||||||
|
{
|
||||||
|
strAnterior = "(\(kvAnterior.key),\(kvAnterior.value))"
|
||||||
}
|
}
|
||||||
|
|
||||||
return strOutput
|
return "(\(strAnterior),\(strPrevious),\(strCurrent))"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue