Repository navigation
Expand file tree
/
Copy pathmain.py
More file actions
237 lines (213 loc) · 8.81 KB
/
Copy pathmain.py
File metadata and controls
237 lines (213 loc) · 8.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
"""
OpenIME - 微软拼音用户词库管家
无参数 / gui → 图形界面
带参数 → 命令行
"""
from __future__ import annotations
import argparse
import sys
def _wants_gui(argv) -> bool:
if len(argv) <= 1:
return True
if argv[1] in ("gui", "--gui", "/gui"):
return True
return False
def run_cli(argv) -> int:
import app_core
parser = argparse.ArgumentParser(
prog="OpenIME",
description="微软拼音用户词库管家(垂域术语导入 / 增删查改 / 备份)",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
OpenIME.exe # 图形界面
OpenIME.exe import -f 术语.txt # 文档导入
OpenIME.exe import -f 手册.pdf --mode lines
OpenIME.exe import -f 规范.docx
OpenIME.exe add 产品经理 需求评审
OpenIME.exe status
OpenIME.exe query -k 产品
OpenIME.exe export -o pack.json
OpenIME.exe import-pack -c pack.json
OpenIME.exe reload-ime # 词库写完让新词立即生效(重载输入法宿主,无需注销)
OpenIME.exe undo # 撤销最近一次导入
OpenIME.exe history # 查看操作历史
OpenIME.exe import-comp # 导入内置古诗文竞赛库(116 首)
""",
)
sub = parser.add_subparsers(dest="command")
p = sub.add_parser("import", help="从文档/文本导入并抽词")
p.add_argument("-f", "--file", action="append", help="文件路径,可重复")
p.add_argument("-t", "--text", help="直接文本")
p.add_argument("--mode", default="auto", choices=["auto", "lines", "sentences", "poetry"])
p.add_argument("--no-latin", action="store_true", help="不提取英文术语")
p.add_argument("--yes", "-y", action="store_true", help="不预览直接写入")
p = sub.add_parser("add", help="按字面添加词条")
p.add_argument("words", nargs="+")
p = sub.add_parser("delete", help="删除词条")
p.add_argument("words", nargs="+")
p = sub.add_parser("query", help="搜索/分页浏览")
p.add_argument("-k", "--keyword", default="")
p.add_argument("-l", "--limit", type=int, default=30)
p.add_argument("--page", type=int, default=0)
p.add_argument("--page-size", type=int, default=0, help="每页条数,默认用 --limit")
sub.add_parser("status", help="状态")
sub.add_parser("backup", help="备份")
sub.add_parser(
"reload-ime",
help="重载输入法宿主进程(TextInputHost),让词库改动立即生效;无需注销/重启电脑",
)
sub.add_parser("undo", help="撤销最近一次导入(删除那批词条)")
sub.add_parser("history", help="查看导入/删除/替换历史")
sub.add_parser(
"import-comp",
help="导入内置古诗文竞赛篇目库(116 首,整句+节奏组,幂等)",
)
p = sub.add_parser("restore", help="恢复备份")
p.add_argument("path")
p = sub.add_parser("export", help="导出词库包 JSON")
p.add_argument("-o", "--output")
p.add_argument("--name", default="OpenIME 词库包")
p = sub.add_parser("import-pack", help="导入词库包 JSON")
p.add_argument("-c", "--config", required=True)
p.add_argument("--replace", action="store_true", help="替换而非合并")
args = parser.parse_args(argv[1:])
if not args.command:
parser.print_help()
return 0
app_core.ensure_ready()
latin = not getattr(args, "no_latin", False)
mode = getattr(args, "mode", "auto")
if args.command == "import":
texts = []
if args.file:
from document_loader import load_many
docs, errors = load_many(args.file)
for e in errors:
print(f"[警告] {e}")
texts = [d.text for d in docs]
if not texts:
print("没有读到可用文本")
return 1
if args.text:
texts.append(args.text)
if not texts:
if sys.stdin is None:
# windowed exe 没有标准输入,直接读会崩
print("图形打包版没有命令行输入,请用 -f 文件 或 -t 文本 提供内容")
return 1
print("请粘贴内容,Windows 结束: Ctrl+Z 回车")
texts.append(sys.stdin.read())
from term_extractor import extract
terms = []
seen = set()
for t in texts:
for w in extract(t, mode=mode, include_latin=latin).get("terms") or []:
if w not in seen:
seen.add(w)
terms.append(w)
preview = app_core.preview_add(terms, source_desc="CLI 导入")
print(f"候选 {len(terms)},新增 {preview.add_count},已存在 {len(preview.already)}")
if not args.yes:
for w in preview.to_add[:30]:
print(" +", w)
if preview.add_count > 30:
print(f" … 共 {preview.add_count} 条")
# windowed exe 里 stdin 为 None,input() 会裸崩(第四轮只挡了 read 分支)
if sys.stdin is None:
print(f"图形打包版无法交互确认,请加 --yes 后重试(本次未写入,共 {preview.add_count} 条待确认)")
return 1
try:
ans = input(f"写入 {preview.add_count} 条? [y/N] ").strip().lower()
except (EOFError, RuntimeError):
print("未读到确认输入,已取消")
return 0
if ans not in ("y", "yes"):
print("已取消")
return 0
r = app_core.apply_tokens(preview.to_add, source_desc="CLI 导入")
elif args.command == "add":
r = app_core.add_words(args.words)
elif args.command == "delete":
r = app_core.delete_entries(args.words)
elif args.command == "query":
r = app_core.query_entries(
keyword=args.keyword,
page=args.page,
page_size=args.page_size or args.limit,
)
print(
f"词库 {r['total_all']} 条"
+ (f",筛选 {r['total']} 条" if r["keyword"] else "")
+ f",第 {r['page']+1}/{r['pages']} 页"
)
for e in r["items"]:
print(f" {e.word} {' '.join(e.pinyin)} [{e.jianpin_str.strip()}]")
return 0
elif args.command == "status":
s = app_core.status_summary()
print(f"词库路径: {s['path']}")
print(f"文件存在: {'是' if s['exists'] else '否'}")
print(f"当前词条: {s['count']}")
print(f"备份份数: {s['backups']}")
print(f"支持格式: {s['supported']}")
return 0
elif args.command == "undo":
r = app_core.undo_last_import()
elif args.command == "reload-ime":
r = app_core.reload_ime()
print(("成功" if r.ok else "失败") + f":{r.message}")
return 0 if r.ok else 1
elif args.command == "import-comp":
r = app_core.import_competition_library()
elif args.command == "history":
recs = app_core.list_history()
if not recs:
print("暂无历史记录")
return 0
for rec in recs[:30]:
action = rec.get("action", "?")
extra = {
"import": f"新增 {len(rec.get('added') or [])} 条",
"delete": f"删除 {len(rec.get('removed') or [])} 条",
"replace": f"替换为 {len(rec.get('added') or [])} 条",
"edit": "修改拼音",
"restore": "恢复备份",
}.get(action, "")
src = (rec.get("source") or "").splitlines()[0]
print(f"{rec.get('time', '?')} {action:<8} {extra:<14} {src}")
return 0
elif args.command == "backup":
path = app_core.backup_udl("cli")
if path:
print(f"已备份到: {path}")
return 0
print("没有可备份的词库文件")
return 1
elif args.command == "restore":
r = app_core.restore_backup(args.path)
elif args.command == "export":
r = app_core.export_pack(args.output, name=args.name)
elif args.command == "import-pack":
r = app_core.import_pack(args.config, merge=not args.replace)
else:
parser.print_help()
return 0
print(("成功" if r.ok else "失败") + f":{r.message}")
if r.detail:
print(r.detail)
return 0 if r.ok else 1
def main():
argv = sys.argv
if _wants_gui(argv):
try:
from gui import run_gui
run_gui()
return 0
except Exception as e:
sys.stderr.write(f"无法启动图形界面:{e}\n")
sys.stderr.write("可使用命令行:OpenIME.exe --help\n")
return 1
return run_cli(argv)
if __name__ == "__main__":
raise SystemExit(main())