Coverage for aipyapp/gui/apimarket.py: 0%
374 statements
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-11 12:02 +0200
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-11 12:02 +0200
2import traceback
4import wx
5from loguru import logger
6from wx.lib.scrolledpanel import ScrolledPanel
8from .. import T
10class ApiItemPanel(wx.Panel):
11 """单个API配置项面板"""
12 def __init__(self, parent, api_name, api_config, on_edit=None, on_delete=None):
13 super().__init__(parent, style=wx.BORDER_SIMPLE)
14 self.api_name = api_name
15 self.api_config = api_config
16 self.on_edit = on_edit
17 self.on_delete = on_delete
19 # 创建布局
20 main_sizer = wx.BoxSizer(wx.VERTICAL)
22 # API名称
23 name_sizer = wx.BoxSizer(wx.HORIZONTAL)
24 name_label = wx.StaticText(self, label=f"{T('API Name')}: {api_name}")
25 name_label.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
26 name_sizer.Add(name_label, 1, wx.EXPAND | wx.ALL, 5)
28 # 添加按钮
29 button_sizer = wx.BoxSizer(wx.HORIZONTAL)
30 edit_button = wx.Button(self, label=T("Edit"))
31 edit_button.Bind(wx.EVT_BUTTON, self.on_edit_click)
32 delete_button = wx.Button(self, label=T("Delete"))
33 delete_button.Bind(wx.EVT_BUTTON, self.on_delete_click)
35 button_sizer.Add(edit_button, 0, wx.ALL, 5)
36 button_sizer.Add(delete_button, 0, wx.ALL, 5)
37 name_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
39 main_sizer.Add(name_sizer, 0, wx.EXPAND | wx.ALL, 5)
41 # API详情
42 details_sizer = wx.BoxSizer(wx.VERTICAL)
44 # 显示API KEY(s)
45 envs = api_config.get('env', {})
46 for key_name in envs:
47 key_value = envs[key_name]
48 if isinstance(key_value, list) and len(key_value) > 0:
49 masked_key = self.mask_api_key(key_value[0])
50 display_key = key_name
51 key_text = wx.StaticText(self, label=f"{display_key}: {masked_key}")
52 details_sizer.Add(key_text, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
54 # 显示描述
55 if 'desc' in api_config:
56 desc_text = wx.StaticText(self, label=f"{T('Description')}: {api_config['desc']}")
57 details_sizer.Add(desc_text, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 10)
59 main_sizer.Add(details_sizer, 0, wx.EXPAND | wx.ALL, 5)
61 self.SetSizer(main_sizer)
62 self.Layout()
64 def mask_api_key(self, key):
65 """将API密钥进行掩码处理,只显示前3位和后3位"""
66 if not key or len(key) < 8:
67 return key
68 return key[:3] + "..." + key[-3:]
70 def on_edit_click(self, event):
71 if self.on_edit:
72 self.on_edit(self.api_name, self.api_config)
74 def on_delete_click(self, event):
75 if self.on_delete:
76 dlg = wx.MessageDialog(
77 self,
78 f"{T('Are you sure to delete API')} '{self.api_name}'?",
79 T("Confirm Delete"),
80 wx.YES_NO | wx.ICON_QUESTION
81 )
82 result = dlg.ShowModal()
83 dlg.Destroy()
85 if result == wx.ID_YES and self.on_delete:
86 self.on_delete(self.api_name)
89class ApiEditDialog(wx.Dialog):
90 """API编辑对话框"""
91 def __init__(self, parent, api_name="", api_config=None, is_new=True):
92 title = T("Add API") if is_new else T("Edit API")
93 super().__init__(parent, title=title, size=(600, 500))
95 self.is_new = is_new
96 self.api_name = api_name
97 self.api_config = api_config or {"desc": ""}
99 self._init_ui()
101 def _init_ui(self):
102 """初始化UI界面"""
103 main_sizer = wx.BoxSizer(wx.VERTICAL)
105 # API名称
106 name_sizer = wx.BoxSizer(wx.HORIZONTAL)
107 name_label = wx.StaticText(self, label=T("API Name"))
108 self.name_input = wx.TextCtrl(self)
109 if not self.is_new:
110 self.name_input.SetValue(self.api_name)
111 self.name_input.Enable(False) # 编辑模式下不允许更改名称
113 name_sizer.Add(name_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
114 name_sizer.Add(self.name_input, 1, wx.ALL | wx.EXPAND, 5)
116 main_sizer.Add(name_sizer, 0, wx.EXPAND | wx.ALL, 10)
118 # API环境变量标题行
119 env_header_sizer = wx.BoxSizer(wx.HORIZONTAL)
120 env_label = wx.StaticText(self, label=T("API Key Settings"))
121 add_env_button = wx.Button(self, label=T("Add Environment Variable"))
122 add_env_button.Bind(wx.EVT_BUTTON, self.on_add_env)
124 env_header_sizer.Add(env_label, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 10)
125 env_header_sizer.Add(add_env_button, 0, wx.ALIGN_CENTER_VERTICAL)
126 main_sizer.Add(env_header_sizer, 0, wx.ALL, 10)
128 # 环境变量列表
129 self.env_panel = wx.ScrolledWindow(self)
130 self.env_panel.SetScrollRate(0, 20)
131 self.env_sizer = wx.BoxSizer(wx.VERTICAL)
132 self.env_panel.SetSizer(self.env_sizer)
134 # 添加已有的环境变量
135 self.env_controls = []
137 # 查找环境变量键
138 env_vars = {}
139 if 'env' in self.api_config and isinstance(self.api_config['env'], dict):
140 for key, value in self.api_config['env'].items():
141 env_vars[key] = value
143 # 添加找到的环境变量
144 for var_name, value in env_vars.items():
145 self.add_env_control(var_name, value)
147 # 如果是新建API且没有环境变量,则默认添加一个空的环境变量控件
148 if self.is_new and not env_vars:
149 self.add_env_control("api_key", [T("Enter your API key"), T("API key description")])
151 main_sizer.Add(self.env_panel, 2, wx.EXPAND | wx.ALL, 10) # 增加比例权重到2
153 # 描述
154 desc_sizer = wx.BoxSizer(wx.VERTICAL)
155 desc_label = wx.StaticText(self, label=T("API Description"))
157 # 使用更大的多行文本框
158 self.desc_input = wx.TextCtrl(self, style=wx.TE_MULTILINE)
159 # 设置更大的字体和最小高度
160 font = wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
161 self.desc_input.SetFont(font)
162 self.desc_input.SetMinSize((-1, 100)) # 设置最小高度
164 if 'desc' in self.api_config:
165 self.desc_input.SetValue(self.api_config['desc'])
167 # 添加提示文本
168 desc_hint = wx.StaticText(self, label=T("Hint: Description supports multi-line text, will be saved in markdown format"))
169 desc_hint.SetFont(wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
171 desc_sizer.Add(desc_label, 0, wx.ALL, 5)
172 desc_sizer.Add(self.desc_input, 1, wx.EXPAND | wx.ALL, 5)
173 desc_sizer.Add(desc_hint, 0, wx.LEFT | wx.BOTTOM, 5)
175 main_sizer.Add(desc_sizer, 1, wx.EXPAND | wx.ALL, 10)
177 # 按钮
178 button_sizer = wx.BoxSizer(wx.HORIZONTAL)
179 save_button = wx.Button(self, wx.ID_OK, T("Save and Apply"))
180 cancel_button = wx.Button(self, wx.ID_CANCEL, T("Cancel"))
182 button_sizer.Add(save_button, 0, wx.ALL, 5)
183 button_sizer.Add(cancel_button, 0, wx.ALL, 5)
185 main_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 10)
187 self.SetSizer(main_sizer)
188 self.Layout()
190 # 设置最小窗口大小
191 self.SetMinSize((600, 500))
193 def add_env_control(self, key_name="", key_value=None):
194 """添加一个环境变量控制项"""
195 if len(self.env_controls) >= 2:
196 return
198 if key_value is None:
199 key_value = ["", T("API key description")]
201 env_item = wx.Panel(self.env_panel)
202 item_sizer = wx.BoxSizer(wx.HORIZONTAL)
204 # 变量名
205 key_name_label = wx.StaticText(env_item, label=f"{T('Variable Name')}:")
206 key_name_input = wx.TextCtrl(env_item, size=(150, -1))
207 key_name_input.SetValue(key_name)
209 # 值
210 key_value_label = wx.StaticText(env_item, label=f"{T('Value')}:")
211 key_value_input = wx.TextCtrl(env_item, size=(150, -1))
212 if isinstance(key_value, list) and len(key_value) > 0:
213 key_value_input.SetValue(key_value[0])
215 # 描述
216 key_desc_label = wx.StaticText(env_item, label=f"{T('Description')}:")
217 key_desc_input = wx.TextCtrl(env_item, size=(150, -1))
218 if isinstance(key_value, list) and len(key_value) > 1:
219 key_desc_input.SetValue(key_value[1])
221 # 删除按钮
222 delete_button = wx.Button(env_item, label=T("Remove"))
223 delete_button.Bind(wx.EVT_BUTTON, lambda evt, item=env_item: self.remove_env_item(item))
225 # 添加到布局
226 item_sizer.Add(key_name_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
227 item_sizer.Add(key_name_input, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
228 item_sizer.Add(key_value_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
229 item_sizer.Add(key_value_input, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
230 item_sizer.Add(key_desc_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
231 item_sizer.Add(key_desc_input, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
232 item_sizer.Add(delete_button, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
234 env_item.SetSizer(item_sizer)
235 self.env_sizer.Add(env_item, 0, wx.EXPAND | wx.ALL, 5)
237 # 添加分隔线
238 separator = wx.StaticLine(self.env_panel)
239 self.env_sizer.Add(separator, 0, wx.EXPAND | wx.ALL, 5)
241 self.env_controls.append({
242 'panel': env_item,
243 'name': key_name_input,
244 'value': key_value_input,
245 'desc': key_desc_input
246 })
248 self.env_panel.Layout()
249 # 确保新添加的控件可见
250 self.env_panel.Scroll(0, self.env_sizer.GetSize().GetHeight())
252 def remove_env_item(self, item):
253 """移除环境变量控制项"""
254 for i, ctrl in enumerate(self.env_controls):
255 if ctrl['panel'] == item:
256 item.Destroy()
257 self.env_controls.pop(i)
258 break
260 self.env_panel.Layout()
261 self.env_panel.SetupScrolling()
263 def on_add_env(self, event):
264 """添加新的环境变量"""
265 if len(self.env_controls) >= 2:
266 wx.MessageBox(T("You can only add two environment variables at most"), T("Hint"), wx.OK | wx.ICON_INFORMATION)
267 return
268 self.add_env_control()
270 def get_api_config(self):
271 """获取编辑后的API配置"""
272 name = self.name_input.GetValue().strip()
274 config = {
275 "desc": self.desc_input.GetValue() # 保留原始格式,包括换行
276 }
278 env = {}
279 for ctrl in self.env_controls:
280 # 获取用户输入的键名
281 key_name = ctrl['name'].GetValue().strip()
283 # 如果键名为空,则跳过
284 if not key_name:
285 continue
287 key_value = ctrl['value'].GetValue().strip()
288 key_desc = ctrl['desc'].GetValue().strip()
290 env[key_name] = [key_value, key_desc]
292 if env: config['env'] = env
293 return name, config
296class ApiDetailsDialog(wx.Dialog):
297 """API详情对话框"""
298 def __init__(self, parent, api_name, api_config):
299 super().__init__(parent, title=f"{T('API Details')}: {api_name}", size=(500, 400))
301 self.api_name = api_name
302 self.api_config = api_config
303 self._init_ui()
305 def _init_ui(self):
306 """初始化UI界面"""
307 main_sizer = wx.BoxSizer(wx.VERTICAL)
309 # 创建滚动面板
310 scroll_panel = ScrolledPanel(self)
311 scroll_sizer = wx.BoxSizer(wx.VERTICAL)
313 # 描述
314 if 'desc' in self.api_config and self.api_config['desc']:
315 desc_group = wx.StaticBox(scroll_panel, label=T("Description"))
316 desc_sizer = wx.StaticBoxSizer(desc_group, wx.VERTICAL)
318 desc_text = wx.StaticText(scroll_panel, label=self.api_config['desc'])
319 desc_text.Wrap(450) # 设置自动换行宽度
321 desc_sizer.Add(desc_text, 0, wx.ALL | wx.EXPAND, 10)
322 scroll_sizer.Add(desc_sizer, 0, wx.ALL | wx.EXPAND, 5)
324 # 查找环境变量键
325 envs = self.api_config.get('env')
326 if envs:
327 env_group = wx.StaticBox(scroll_panel, label=T("Environment Variables"))
328 env_sizer = wx.StaticBoxSizer(env_group, wx.VERTICAL)
330 for i, key_name in enumerate(envs.keys()):
331 key_value = envs[key_name]
332 display_key = key_name
334 env_panel = wx.Panel(scroll_panel)
336 env_box = wx.BoxSizer(wx.VERTICAL)
338 name_text = wx.StaticText(env_panel, label=f"{T('Variable Name')}: {display_key}")
339 name_text.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
341 if isinstance(key_value, list):
342 if len(key_value) > 0:
343 # 使用掩码显示API密钥
344 masked_key = key_value[0]
345 if len(masked_key) > 8:
346 masked_key = masked_key[:3] + "..." + masked_key[-3:]
347 value_text = wx.StaticText(env_panel, label=f"{T('Value')}: {masked_key}")
349 if len(key_value) > 1 and key_value[1]:
350 desc_text = wx.StaticText(env_panel, label=f"{T('Description')}: {key_value[1]}")
351 desc_text.Wrap(400)
353 env_box.Add(name_text, 0, wx.ALL, 5)
354 env_box.Add(value_text, 0, wx.ALL, 5)
355 if len(key_value) > 1 and key_value[1]:
356 env_box.Add(desc_text, 0, wx.ALL, 5)
358 env_panel.SetSizer(env_box)
359 env_sizer.Add(env_panel, 0, wx.ALL | wx.EXPAND, 5)
361 # 添加分隔线,除了最后一个
362 if i < len(envs) - 1:
363 env_sizer.Add(wx.StaticLine(scroll_panel), 0, wx.EXPAND | wx.ALL, 5)
365 scroll_sizer.Add(env_sizer, 0, wx.ALL | wx.EXPAND, 5)
367 scroll_panel.SetSizer(scroll_sizer)
368 scroll_panel.SetupScrolling()
370 main_sizer.Add(scroll_panel, 1, wx.EXPAND | wx.ALL, 10)
372 # 关闭按钮
373 close_button = wx.Button(self, wx.ID_OK, T("Close"))
374 main_sizer.Add(close_button, 0, wx.ALIGN_CENTER | wx.ALL, 10)
376 self.SetSizer(main_sizer)
377 self.Layout()
380class ApiMarketDialog(wx.Dialog):
381 """API市场对话框 - 列表视图"""
382 def __init__(self, parent, config_manager):
383 super().__init__(parent, title=T("API Market"), size=(800, 600))
385 self.config_manager = config_manager
386 self.log = logger.bind(src="apimarket")
388 # 确保获取最新配置
389 self.config_manager.reload_config()
390 self.settings = config_manager.get_config()
392 # 复制API配置
393 self.api_configs = self.settings.get('api', {})
395 # 创建界面
396 self._init_ui()
398 def _init_ui(self):
399 """初始化UI界面"""
400 main_sizer = wx.BoxSizer(wx.VERTICAL)
402 # 标题
403 title_text = wx.StaticText(self, label=T("API Market - Manage Your API Configurations"))
404 title_text.SetFont(wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
405 main_sizer.Add(title_text, 0, wx.ALIGN_CENTER | wx.ALL, 10)
407 # 介绍说明
408 desc_text = wx.StaticText(self, label=T("Manage your API configurations here, including adding new APIs, viewing and editing existing ones."))
409 main_sizer.Add(desc_text, 0, wx.ALIGN_CENTER | wx.BOTTOM, 10)
411 # 工具栏
412 toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
414 add_button = wx.Button(self, label=T("Add New API"))
415 add_button.Bind(wx.EVT_BUTTON, self.on_add_api)
416 refresh_button = wx.Button(self, label=T("Refresh List"))
417 refresh_button.Bind(wx.EVT_BUTTON, self.on_refresh)
419 toolbar_sizer.Add(add_button, 0, wx.ALL, 5)
420 toolbar_sizer.Add(refresh_button, 0, wx.ALL, 5)
422 main_sizer.Add(toolbar_sizer, 0, wx.LEFT, 10)
424 # 创建列表控件
425 self.api_list = wx.ListCtrl(self, style=wx.LC_REPORT | wx.BORDER_SUNKEN)
426 self.api_list.InsertColumn(0, T("API Name"), width=200)
427 self.api_list.InsertColumn(1, T("Number of Keys"), width=100)
428 self.api_list.InsertColumn(2, T("Description"), width=450)
430 # 添加操作提示
431 help_text = wx.StaticText(self, label=T("Tip: Right-click on API item to view, edit and delete"))
432 help_text.SetFont(wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_ITALIC, wx.FONTWEIGHT_NORMAL))
434 # 加载API配置到列表
435 self.load_api_configs()
437 main_sizer.Add(self.api_list, 1, wx.EXPAND | wx.ALL, 10)
438 main_sizer.Add(help_text, 0, wx.LEFT | wx.BOTTOM, 15)
440 # 右键菜单绑定
441 self.api_list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_right_click)
443 # 双击查看详情
444 self.api_list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_item_activated)
446 # 底部按钮
447 button_sizer = wx.BoxSizer(wx.HORIZONTAL)
448 save_button = wx.Button(self, label=T("Save and Apply"))
449 save_button.Bind(wx.EVT_BUTTON, self.on_save)
450 cancel_button = wx.Button(self, wx.ID_CANCEL, T("Cancel"))
452 button_sizer.Add(save_button, 0, wx.ALL, 5)
453 button_sizer.Add(cancel_button, 0, wx.ALL, 5)
455 main_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 10)
457 self.SetSizer(main_sizer)
458 self.Layout()
460 def load_api_configs(self):
461 """加载API配置到列表"""
462 self.api_list.DeleteAllItems()
463 if not self.api_configs:
464 no_api_item = self.api_list.InsertItem(0, T("No API configured"))
465 self.api_list.SetItem(no_api_item, 2, T("Click `Add New API` button to add API configuration"))
466 return
468 idx = 0
469 for api_name, api_config in self.api_configs.items():
470 item = self.api_list.InsertItem(idx, api_name)
472 env_count = len(api_config.get('env', {}))
473 self.api_list.SetItem(item, 1, str(env_count))
475 # 添加描述
476 desc = api_config.get('desc', '')
477 if len(desc) > 60:
478 desc = desc[:57] + "..."
479 self.api_list.SetItem(item, 2, desc)
481 idx += 1
483 def on_item_activated(self, event):
484 """双击列表项查看详情"""
485 idx = event.GetIndex()
486 api_name = self.api_list.GetItemText(idx)
488 if api_name in self.api_configs:
489 self.show_api_details(api_name)
491 def show_api_details(self, api_name):
492 """显示API详情"""
493 api_config = self.api_configs.get(api_name)
494 if api_config:
495 dialog = ApiDetailsDialog(self, api_name, api_config)
496 dialog.ShowModal()
497 dialog.Destroy()
499 def on_right_click(self, event):
500 """右键菜单"""
501 if not self.api_list.GetItemCount():
502 return
504 idx = event.GetIndex()
505 if idx == -1:
506 return
508 api_name = self.api_list.GetItemText(idx)
510 # 如果是"暂无API配置"提示项,不显示菜单
511 if api_name == T("No API configured"):
512 return
514 menu = wx.Menu()
516 view_item = menu.Append(wx.ID_VIEW_DETAILS, T("View Details"))
517 edit_item = menu.Append(wx.ID_EDIT, T("Edit"))
518 delete_item = menu.Append(wx.ID_DELETE, T("Delete"))
520 self.Bind(wx.EVT_MENU, lambda evt, name=api_name: self.show_api_details(name), view_item)
521 self.Bind(wx.EVT_MENU, lambda evt, name=api_name: self.on_edit_api(name), edit_item)
522 self.Bind(wx.EVT_MENU, lambda evt, name=api_name: self.on_delete_api(name), delete_item)
524 self.PopupMenu(menu)
525 menu.Destroy()
527 def on_add_api(self, event=None):
528 """添加新API"""
529 dialog = ApiEditDialog(self, is_new=True)
530 result = dialog.ShowModal()
532 if result == wx.ID_OK:
533 api_name, api_config = dialog.get_api_config()
535 if not api_name:
536 wx.MessageBox(T("API name cannot be empty"), T("Error"), wx.OK | wx.ICON_ERROR)
537 return
539 if api_name in self.api_configs:
540 wx.MessageBox(T("API name already exists"), T("Error"), wx.OK | wx.ICON_ERROR)
541 return
543 self.api_configs[api_name] = api_config
544 self.load_api_configs()
546 dialog.Destroy()
548 def on_edit_api(self, api_name):
549 """编辑API配置"""
550 if api_name not in self.api_configs:
551 return
553 api_config = self.api_configs[api_name]
554 dialog = ApiEditDialog(self, api_name, api_config, is_new=False)
555 result = dialog.ShowModal()
557 if result == wx.ID_OK:
558 _, updated_config = dialog.get_api_config()
559 self.api_configs[api_name] = updated_config
560 self.load_api_configs()
562 dialog.Destroy()
564 def on_delete_api(self, api_name):
565 """删除API配置"""
566 if api_name not in self.api_configs:
567 return
569 dlg = wx.MessageDialog(
570 self,
571 f"{T('Are you sure to delete API')} '{api_name}'?",
572 T("Confirm Delete"),
573 wx.YES_NO | wx.ICON_QUESTION
574 )
575 result = dlg.ShowModal()
576 dlg.Destroy()
578 if result == wx.ID_YES:
579 del self.api_configs[api_name]
580 self.load_api_configs()
582 self.config_manager.update_api_config({'api': self.api_configs})
584 def on_refresh(self, event):
585 """刷新API列表"""
586 # 重新加载配置
587 self.config_manager.reload_config()
588 self.settings = self.config_manager.get_config()
590 # 重新加载API配置
591 self.api_configs = self.settings.get('api', {})
593 # 更新列表
594 self.load_api_configs()
596 def on_save(self, event):
597 """保存API配置"""
598 try:
599 self.config_manager.update_sys_config({'api': self.api_configs})
600 self.settings = self.config_manager.reload_config()
602 # 更新父窗口的配置
603 if hasattr(self.Parent, 'tm'):
604 self.Parent.tm.settings = self.config_manager.get_config()
605 if hasattr(self.Parent.tm, 'config'):
606 self.Parent.tm.config = self.config_manager.get_config()
608 # 显示保存成功的消息
609 wx.MessageBox(T("API configuration saved and applied"), T("Success"), wx.OK | wx.ICON_INFORMATION)
610 self.EndModal(wx.ID_OK)
611 except Exception as e:
612 traceback.print_exc()
613 wx.MessageBox(f"{T('Failed to save configuration')}: {str(e)}", T("Error"), wx.OK | wx.ICON_ERROR)
614 traceback.print_exc()