-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain_gui.py
More file actions
351 lines (286 loc) · 12.6 KB
/
main_gui.py
File metadata and controls
351 lines (286 loc) · 12.6 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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
"""
GUI 主程序入口
实现图形用户界面,提供列表规范化和批量关键词检索功能。
"""
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
from datetime import datetime
import threading
from parser import parse_input_file
from retriever import search_and_retrieve_bibtex, batch_keyword_search
from formatter import format_bibtex_to_style, FORMAT_STYLES
from confidence_manager import evaluate_bibtex_string, get_confidence_level
class ReferenceProcessorGUI:
def __init__(self, root):
self.root = root
self.root.title("参考文献管理与检索系统")
self.root.geometry("1000x700")
# 创建主框架
self.create_widgets()
def create_widgets(self):
"""创建GUI组件"""
# 标题
title_label = tk.Label(
self.root,
text="参考文献管理与检索系统",
font=("Arial", 16, "bold")
)
title_label.pack(pady=10)
# 创建主容器
main_frame = ttk.Frame(self.root, padding="10")
main_frame.pack(fill=tk.BOTH, expand=True)
# 左侧面板 - 输入区
left_frame = ttk.LabelFrame(main_frame, text="输入区", padding="10")
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
# 功能区 A: 列表规范化
list_frame = ttk.LabelFrame(left_frame, text="列表规范化", padding="5")
list_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
list_label = tk.Label(list_frame, text="粘贴非标准文献列表:")
list_label.pack(anchor=tk.W)
self.list_input = scrolledtext.ScrolledText(
list_frame,
height=8,
wrap=tk.WORD,
font=("Consolas", 10)
)
self.list_input.pack(fill=tk.BOTH, expand=True)
# 功能区 B: 批量检索
batch_frame = ttk.LabelFrame(left_frame, text="批量关键词检索", padding="5")
batch_frame.pack(fill=tk.X, pady=(0, 10))
keyword_frame = ttk.Frame(batch_frame)
keyword_frame.pack(fill=tk.X, pady=5)
keyword_label = tk.Label(keyword_frame, text="关键词:")
keyword_label.pack(side=tk.LEFT, padx=(0, 5))
self.keyword_input = ttk.Entry(keyword_frame, width=30)
self.keyword_input.pack(side=tk.LEFT, fill=tk.X, expand=True)
count_frame = ttk.Frame(batch_frame)
count_frame.pack(fill=tk.X, pady=5)
count_label = tk.Label(count_frame, text="数量:")
count_label.pack(side=tk.LEFT, padx=(0, 5))
self.count_input = ttk.Entry(count_frame, width=10)
self.count_input.pack(side=tk.LEFT)
self.count_input.insert(0, "10")
# 通用设置
settings_frame = ttk.LabelFrame(left_frame, text="输出格式设置", padding="5")
settings_frame.pack(fill=tk.X)
format_label = tk.Label(settings_frame, text="格式:")
format_label.pack(side=tk.LEFT, padx=(0, 5))
self.format_var = tk.StringVar(value="GBT2015")
format_combo = ttk.Combobox(
settings_frame,
textvariable=self.format_var,
values=list(FORMAT_STYLES.keys()),
state="readonly",
width=15
)
format_combo.pack(side=tk.LEFT)
# 按钮区
button_frame = ttk.Frame(left_frame)
button_frame.pack(fill=tk.X, pady=10)
self.normalize_btn = ttk.Button(
button_frame,
text="执行列表规范化",
command=self.normalize_list,
width=20
)
self.normalize_btn.pack(side=tk.LEFT, padx=(0, 5))
self.batch_search_btn = ttk.Button(
button_frame,
text="执行批量检索",
command=self.batch_search,
width=20
)
self.batch_search_btn.pack(side=tk.LEFT)
# 右侧面板 - 输出区
right_frame = ttk.LabelFrame(main_frame, text="输出区", padding="10")
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
self.output_text = scrolledtext.ScrolledText(
right_frame,
wrap=tk.WORD,
font=("Consolas", 10),
state=tk.DISABLED
)
self.output_text.pack(fill=tk.BOTH, expand=True)
# 状态栏
self.status_var = tk.StringVar(value="就绪")
status_bar = ttk.Label(
self.root,
textvariable=self.status_var,
relief=tk.SUNKEN,
anchor=tk.W
)
status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def log_output(self, message):
"""在输出区添加消息"""
self.output_text.config(state=tk.NORMAL)
self.output_text.insert(tk.END, message + "\n")
self.output_text.see(tk.END)
self.output_text.config(state=tk.DISABLED)
self.root.update()
def update_status(self, message):
"""更新状态栏"""
self.status_var.set(message)
self.root.update()
def normalize_list(self):
"""执行列表规范化"""
# 获取输入
input_text = self.list_input.get("1.0", tk.END).strip()
if not input_text:
messagebox.showwarning("警告", "请输入文献列表")
return
# 获取格式
target_style = self.format_var.get()
# 禁用按钮
self.normalize_btn.config(state=tk.DISABLED)
self.batch_search_btn.config(state=tk.DISABLED)
# 在新线程中执行
thread = threading.Thread(
target=self._normalize_list_thread,
args=(input_text, target_style),
daemon=True
)
thread.start()
def _normalize_list_thread(self, input_text, target_style):
"""列表规范化的后台线程"""
try:
self.update_status("正在解析输入...")
self.log_output("=" * 60)
self.log_output(f"列表规范化 - {FORMAT_STYLES[target_style]}")
self.log_output(f"生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
self.log_output("=" * 60)
self.log_output("")
# 解析输入(使用临时文件)
import tempfile
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt', encoding='utf-8') as f:
f.write(input_text)
temp_file = f.name
try:
queries = parse_input_file(temp_file)
finally:
import os
os.unlink(temp_file)
if not queries:
self.log_output("错误:未能解析到任何文献查询。")
self.update_status("解析失败")
return
self.log_output(f"成功解析到 {len(queries)} 条文献查询。\n")
# 处理每条查询
formatted_references = []
failed_queries = []
for idx, query in enumerate(queries, 1):
self.update_status(f"处理第 {idx}/{len(queries)} 条文献...")
self.log_output(f"[{idx}/{len(queries)}] 处理查询:{query[:60]}...")
# 检索 BibTeX
result = search_and_retrieve_bibtex(query, return_key_info=True)
if isinstance(result, tuple):
bibtex, key_info = result
else:
bibtex = result
key_info = None
if bibtex:
# 评估置信度
confidence, warning, entry = evaluate_bibtex_string(bibtex)
# 格式化
formatted_ref = format_bibtex_to_style(
idx, bibtex, target_style, key_info, confidence, warning
)
formatted_references.append(formatted_ref)
self.log_output(formatted_ref)
self.log_output("")
else:
self.log_output(f"[{idx}] [检索失败] {query}")
self.log_output("")
formatted_references.append(f"[{idx}] [检索失败] {query}")
failed_queries.append((idx, query))
# 总结
self.log_output("=" * 60)
self.log_output(f"处理完成!")
self.log_output(f"成功格式化:{len(formatted_references) - len(failed_queries)} 条")
if failed_queries:
self.log_output(f"检索失败:{len(failed_queries)} 条")
self.log_output("=" * 60)
self.update_status("完成")
except Exception as e:
self.log_output(f"错误:{str(e)}")
self.update_status(f"错误:{str(e)}")
finally:
# 重新启用按钮
self.normalize_btn.config(state=tk.NORMAL)
self.batch_search_btn.config(state=tk.NORMAL)
def batch_search(self):
"""执行批量关键词检索"""
# 获取输入
keyword = self.keyword_input.get().strip()
if not keyword:
messagebox.showwarning("警告", "请输入搜索关键词")
return
try:
count = int(self.count_input.get().strip())
if count <= 0:
raise ValueError
except ValueError:
messagebox.showwarning("警告", "请输入有效的数量(正整数)")
return
# 获取格式
target_style = self.format_var.get()
# 禁用按钮
self.normalize_btn.config(state=tk.DISABLED)
self.batch_search_btn.config(state=tk.DISABLED)
# 在新线程中执行
thread = threading.Thread(
target=self._batch_search_thread,
args=(keyword, count, target_style),
daemon=True
)
thread.start()
def _batch_search_thread(self, keyword, count, target_style):
"""批量检索的后台线程"""
try:
self.update_status(f"正在搜索关键词:{keyword}...")
self.log_output("=" * 60)
self.log_output(f"批量关键词检索 - {FORMAT_STYLES[target_style]}")
self.log_output(f"关键词:{keyword}")
self.log_output(f"目标数量:{count} 条")
self.log_output(f"生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
self.log_output("=" * 60)
self.log_output("")
# 执行批量搜索
bibtex_list = batch_keyword_search(keyword, count)
if not bibtex_list:
self.log_output("未检索到任何文献。")
self.update_status("检索失败")
return
# 处理每条结果
formatted_references = []
for idx, bibtex in enumerate(bibtex_list, 1):
self.update_status(f"格式化第 {idx}/{len(bibtex_list)} 条文献...")
# 评估置信度
confidence, warning, entry = evaluate_bibtex_string(bibtex)
# 格式化
formatted_ref = format_bibtex_to_style(
idx, bibtex, target_style, None, confidence, warning
)
formatted_references.append(formatted_ref)
self.log_output(formatted_ref)
self.log_output("")
# 总结
self.log_output("=" * 60)
self.log_output(f"检索完成!")
self.log_output(f"成功检索并格式化:{len(formatted_references)} 条")
if len(formatted_references) < count:
self.log_output(f"⚠ 警告:仅检索到 {len(formatted_references)} 条文献,少于要求的 {count} 条")
self.log_output("=" * 60)
self.update_status("完成")
except Exception as e:
self.log_output(f"错误:{str(e)}")
self.update_status(f"错误:{str(e)}")
finally:
# 重新启用按钮
self.normalize_btn.config(state=tk.NORMAL)
self.batch_search_btn.config(state=tk.NORMAL)
def main():
root = tk.Tk()
app = ReferenceProcessorGUI(root)
root.mainloop()
if __name__ == '__main__':
main()