hchunhui / librime-lua

Extending RIME with Lua scripts
BSD 3-Clause "New" or "Revised" License
359 stars 45 forks source link

请教一个 Memory 读取、写入用户词典的脚本问题 #301

Closed mirtlecn closed 10 months ago

mirtlecn commented 10 months ago

脚本有异常,问了 ChatGPT 没定位到问题,文档、示例脚本一些地方不理解,

下面的脚本是参考 sample script 里的 expand_translator 写的,脱敏后的方案和 lua 在压缩包里面。

功能是: 除特殊情况下,将用户的输入码做成 Phrase 候选,用户选中后更新到(指定的)用户词典。

问题是: 脚本会将一个条目写入两次用户词典,不清楚为什么会这样(以下是同步出来的用户词典) image

脚本如下:

-- 功能不明,似乎是写入用户词典,但删了不影响功能
local function memoryCallback(memory, commit)
    for i, dictentry in ipairs(commit:get()) do
        -- log.info(dictentry.text .. " " .. dictentry.weight .. " " .. dictentry.comment .. "")
        memory:update_userdict(dictentry, 1, "")
    end
    return true
end

local echo = {}

function echo.init(env)
    -- 读取设置
    local config = env.engine.schema.config
    env.name_space = env.name_space:gsub("^*", "")
    echo.always_on = config:get_bool(env.name_space .. "/always_on")
    echo.remain_punc = config:get_string(env.name_space .. "/remain_punc")
    local schema_name = config:get_string(env.name_space .. "/dict")
    -- 如果不设定用户词典的方案,则取当前方案
    if schema_name then
        env.mem = Memory(env.engine, Schema(schema_name))
    else
        env.mem = Memory(env.engine, env.engine.schema)
    end
    env.mem:memorize(function(commit) memoryCallback(env.mem, commit) end)
end

function echo.change_inp(s)
    -- 变化输入码,除了指定的符号,全部删除
    s = s:gsub('%.%.', ' ')
    local punc = echo.remain_punc:gsub("([%.%+%-%*%?%[%]%^%$%(%)%%])", "%%%1")
    local pattern = "[^a-zA-Z" .. punc .. "]"
    return s:gsub(pattern, "")
end

function echo.func(inp, seg, env)
    local input = echo.change_inp(inp)
    local lower_inp = input:lower()
    local is_open = env.engine.context:get_option('echo_translator')

    -- 总条件:在 ⌥Option 处或者 schema 设置开启造词
    if (not is_open) and (not echo.always_on) then
        return
    end

    -- 如果有用户词典完全匹配,不造词 *** 有问题,不起作用
    if env.mem:user_lookup(inp, false) then return end

    -- 如果主词典没有,则造词
    -- 输入码为删除符号,且小写形式的输入码
    -- 对应主词典算法中的全小写
    -- 放在后面让产生的候选排序在后面
    if 
        -- (not env.mem:user_lookup(inp, false)) and
        (not env.mem:dict_lookup(inp, false, 1)) -- 主词典中无完全匹配,主词典用 inp 匹配
        and (not inp:find("^[%p]")) -- 候选不以标点开头
        and (not inp:find("[0-9]")) -- 候选中无数字
        and (not inp:find("^%w+%.%w+")) -- 不记录网址
    then
        local dict = DictEntry()
        dict.text = inp:gsub('%.%.', ' ') -- 输入两个点号表示空格
        dict.custom_code = input
        dict.comment = '+'
        local ph = Phrase(env.mem, "echo", seg.start, seg._end, dict)
        yield(ph:toCandidate())
    end
    ::skip::
end
return echo

在输入方案中的配置如下:

translators:
   - lua_translator@*echo_translator
echo_translator:
  remain_punc: "_"
  always_on: false
  dict: en
mirtlecn commented 10 months ago

我发现 librime lua 能获取到的用户词典应该不是实时的。

env.mem:user_lookup(inp, false) 并不能匹配上刚刚输入的一次用户词汇,有时候重新部署后才能判断出来。不晓得是不是这个原因。所有 if env.mem:user_lookup(inp, false) then return end 这一句倒是不起作用。

另外,Phrase 这个构建候选词的功能,是不是只有提供了一个 memory 对象,提交后就能直接更新到用户词典,并不需要去用在 init 函数里面用调用 update_userdict 方法

shewer commented 10 months ago

會加兩次可能是因爲 方案中另一 個 translator 也使用用相同 的字典 它也 在commit 時 update user_dictionary

mirtlecn commented 10 months ago

會加兩次可能是因爲 方案中另一 個 translator 也使用用相同 的字典 它也 在commit 時 update user_dictionary

我尝试只启用这一个 lua 翻译器,主翻译器都不要,它仍然写入了两次条目。 @shewer

image

看写在 updateuserdict 方法前的 log,只产生了一次写入记录

    for i, dictentry in ipairs(commit:get()) do
        log.error('[echo_translator]:' .. dictentry.text .. "/" .. dictentry.weight .. "/" .. dictentry.comment .. "/")
        memory:update_userdict(dictentry, 1, "") -- do nothing to userdict
E20240118 22:11:48.997062  9900 types.cc:1342] [echo_translator]:init!
E20240118 22:11:59.906436 11144 types.cc:1342] [echo_translator]:input:M
E20240118 22:12:02.107204 11144 types.cc:1342] [echo_translator]:input:MM
E20240118 22:12:02.107204 11144 types.cc:1342] [echo_translator]:DictEntry:MM/MM
E20240118 22:12:03.066202 11144 types.cc:1342] [echo_translator]:input:MM
E20240118 22:12:03.066202 11144 types.cc:1342] [echo_translator]:DictEntry:MM /MM
E20240118 22:12:03.558094 11144 types.cc:1342] [echo_translator]:input:MMT
E20240118 22:12:03.558094 11144 types.cc:1342] [echo_translator]:DictEntry:MM T/MMT
E20240118 22:12:03.919859 11144 types.cc:1342] [echo_translator]:MM T/1.0/+/
E20240118 22:12:10.646337  2796 types.cc:1342] [echo_translator]:init!

还发现一些其他特征:

  1. db_class 为 tabledb 的时候不会这样,二进制用户词典的时候才会发生
  2. 同步一次,产生第一次用户词典条目,同步第二次,产生第二次用户词典条目
  3. 第二次用户词典条目的第一栏末多了一个空格

image

不清楚这个空格是怎么来的,明明写入的 dictentry 不可能有空格

echo_translator.lua.txt

shewer commented 10 months ago

我記得 librime 加詞 key 值 會多個空白 (偶數行 系統正常加入 的 ,奇數行不正常) key format: "碼\s\t字\s" image image

mirtlecn commented 10 months ago

谢谢,这个空格帮了大忙了,发现这个空格是 librime 有意加上的,所以反过来给 DictEntry() 的 custom_code 末尾加个空格就不会出现类似情况了,不清楚原理

dict = DictEntry()
dict.custom_code = input .. ' '

@shewer