Coverage for aipyapp/gui/apimarket.py: 0%

1

2 import traceback

3

4 import wx

5 from loguru import logger

6 from wx.lib.scrolledpanel import ScrolledPanel

7

8 from .. import T

9

10 class 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

18

19 # 创建布局

20 main_sizer = wx.BoxSizer(wx.VERTICAL)

21

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)

27

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)

34

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)

38

39 main_sizer.Add(name_sizer, 0, wx.EXPAND | wx.ALL, 5)

40

41 # API详情

42 details_sizer = wx.BoxSizer(wx.VERTICAL)

43

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)

53

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)

58

59 main_sizer.Add(details_sizer, 0, wx.EXPAND | wx.ALL, 5)

60

61 self.SetSizer(main_sizer)

62 self.Layout()

63

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:]

69

70 def on_edit_click(self, event):

71 if self.on_edit:

72 self.on_edit(self.api_name, self.api_config)

73

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()

84

85 if result == wx.ID_YES and self.on_delete:

86 self.on_delete(self.api_name)

87

88

89 class 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))

94

95 self.is_new = is_new

96 self.api_name = api_name

97 self.api_config = api_config or {"desc": ""}

98

99 self._init_ui()

100

101 def _init_ui(self):

102 """初始化UI界面"""

103 main_sizer = wx.BoxSizer(wx.VERTICAL)

104

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) # 编辑模式下不允许更改名称

112

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)

115

116 main_sizer.Add(name_sizer, 0, wx.EXPAND | wx.ALL, 10)

117

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)

123

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)

127

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)

133

134 # 添加已有的环境变量

135 self.env_controls = []

136

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

142

143 # 添加找到的环境变量

144 for var_name, value in env_vars.items():

145 self.add_env_control(var_name, value)

146

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")])

150

151 main_sizer.Add(self.env_panel, 2, wx.EXPAND | wx.ALL, 10) # 增加比例权重到2

152

153 # 描述

154 desc_sizer = wx.BoxSizer(wx.VERTICAL)

155 desc_label = wx.StaticText(self, label=T("API Description"))

156

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)) # 设置最小高度

163

164 if 'desc' in self.api_config:

165 self.desc_input.SetValue(self.api_config['desc'])

166

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))

170

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)

174

175 main_sizer.Add(desc_sizer, 1, wx.EXPAND | wx.ALL, 10)

176

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"))

181

182 button_sizer.Add(save_button, 0, wx.ALL, 5)

183 button_sizer.Add(cancel_button, 0, wx.ALL, 5)

184

185 main_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 10)

186

187 self.SetSizer(main_sizer)

188 self.Layout()

189

190 # 设置最小窗口大小

191 self.SetMinSize((600, 500))

192

193 def add_env_control(self, key_name="", key_value=None):

194 """添加一个环境变量控制项"""

195 if len(self.env_controls) >= 2:

196 return

197

198 if key_value is None:

199 key_value = ["", T("API key description")]

200

201 env_item = wx.Panel(self.env_panel)

202 item_sizer = wx.BoxSizer(wx.HORIZONTAL)

203

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)

208

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])

214

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])

220

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))

224

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)

233

234 env_item.SetSizer(item_sizer)

235 self.env_sizer.Add(env_item, 0, wx.EXPAND | wx.ALL, 5)

236

237 # 添加分隔线

238 separator = wx.StaticLine(self.env_panel)

239 self.env_sizer.Add(separator, 0, wx.EXPAND | wx.ALL, 5)

240

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 })

247

248 self.env_panel.Layout()

249 # 确保新添加的控件可见

250 self.env_panel.Scroll(0, self.env_sizer.GetSize().GetHeight())

251

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

259

260 self.env_panel.Layout()

261 self.env_panel.SetupScrolling()

262

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()

269

270 def get_api_config(self):

271 """获取编辑后的API配置"""

272 name = self.name_input.GetValue().strip()

273

274 config = {

275 "desc": self.desc_input.GetValue() # 保留原始格式，包括换行

276 }

277

278 env = {}

279 for ctrl in self.env_controls:

280 # 获取用户输入的键名

281 key_name = ctrl['name'].GetValue().strip()

282

283 # 如果键名为空，则跳过

284 if not key_name:

285 continue

286

287 key_value = ctrl['value'].GetValue().strip()

288 key_desc = ctrl['desc'].GetValue().strip()

289

290 env[key_name] = [key_value, key_desc]

291

292 if env: config['env'] = env

293 return name, config

294

295

296 class 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))

300

301 self.api_name = api_name

302 self.api_config = api_config

303 self._init_ui()

304

305 def _init_ui(self):

306 """初始化UI界面"""

307 main_sizer = wx.BoxSizer(wx.VERTICAL)

308

309 # 创建滚动面板

310 scroll_panel = ScrolledPanel(self)

311 scroll_sizer = wx.BoxSizer(wx.VERTICAL)

312

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)

317

318 desc_text = wx.StaticText(scroll_panel, label=self.api_config['desc'])

319 desc_text.Wrap(450) # 设置自动换行宽度

320

321 desc_sizer.Add(desc_text, 0, wx.ALL | wx.EXPAND, 10)

322 scroll_sizer.Add(desc_sizer, 0, wx.ALL | wx.EXPAND, 5)

323

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)

329

330 for i, key_name in enumerate(envs.keys()):

331 key_value = envs[key_name]

332 display_key = key_name

333

334 env_panel = wx.Panel(scroll_panel)

335

336 env_box = wx.BoxSizer(wx.VERTICAL)

337

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))

340

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}")

348

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)

352

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)

357

358 env_panel.SetSizer(env_box)

359 env_sizer.Add(env_panel, 0, wx.ALL | wx.EXPAND, 5)

360

361 # 添加分隔线，除了最后一个

362 if i < len(envs) - 1:

363 env_sizer.Add(wx.StaticLine(scroll_panel), 0, wx.EXPAND | wx.ALL, 5)

364

365 scroll_sizer.Add(env_sizer, 0, wx.ALL | wx.EXPAND, 5)

366

367 scroll_panel.SetSizer(scroll_sizer)

368 scroll_panel.SetupScrolling()

369

370 main_sizer.Add(scroll_panel, 1, wx.EXPAND | wx.ALL, 10)

371

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)

375

376 self.SetSizer(main_sizer)

377 self.Layout()

378

379

380 class ApiMarketDialog(wx.Dialog):

381 """API市场对话框 - 列表视图"""

382 def __init__(self, parent, config_manager):

383 super().__init__(parent, title=T("API Market"), size=(800, 600))

384

385 self.config_manager = config_manager

386 self.log = logger.bind(src="apimarket")

387

388 # 确保获取最新配置

389 self.config_manager.reload_config()

390 self.settings = config_manager.get_config()

391

392 # 复制API配置

393 self.api_configs = self.settings.get('api', {})

394

395 # 创建界面

396 self._init_ui()

397

398 def _init_ui(self):

399 """初始化UI界面"""

400 main_sizer = wx.BoxSizer(wx.VERTICAL)

401

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)

406

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)

410

411 # 工具栏

412 toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)

413

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)

418

419 toolbar_sizer.Add(add_button, 0, wx.ALL, 5)

420 toolbar_sizer.Add(refresh_button, 0, wx.ALL, 5)

421

422 main_sizer.Add(toolbar_sizer, 0, wx.LEFT, 10)

423

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)

429

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))

433

434 # 加载API配置到列表

435 self.load_api_configs()

436

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)

439

440 # 右键菜单绑定

441 self.api_list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_right_click)

442

443 # 双击查看详情

444 self.api_list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_item_activated)

445

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"))

451

452 button_sizer.Add(save_button, 0, wx.ALL, 5)

453 button_sizer.Add(cancel_button, 0, wx.ALL, 5)

454

455 main_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 10)

456

457 self.SetSizer(main_sizer)

458 self.Layout()

459

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

467

468 idx = 0

469 for api_name, api_config in self.api_configs.items():

470 item = self.api_list.InsertItem(idx, api_name)

471

472 env_count = len(api_config.get('env', {}))

473 self.api_list.SetItem(item, 1, str(env_count))

474

475 # 添加描述

476 desc = api_config.get('desc', '')

477 if len(desc) > 60:

478 desc = desc[:57] + "..."

479 self.api_list.SetItem(item, 2, desc)

480

481 idx += 1

482

483 def on_item_activated(self, event):

484 """双击列表项查看详情"""

485 idx = event.GetIndex()

486 api_name = self.api_list.GetItemText(idx)

487

488 if api_name in self.api_configs:

489 self.show_api_details(api_name)

490

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()

498

499 def on_right_click(self, event):

500 """右键菜单"""

501 if not self.api_list.GetItemCount():

502 return

503

504 idx = event.GetIndex()

505 if idx == -1:

506 return

507

508 api_name = self.api_list.GetItemText(idx)

509

510 # 如果是"暂无API配置"提示项，不显示菜单

511 if api_name == T("No API configured"):

512 return

513

514 menu = wx.Menu()

515

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"))

519

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)

523

524 self.PopupMenu(menu)

525 menu.Destroy()

526

527 def on_add_api(self, event=None):

528 """添加新API"""

529 dialog = ApiEditDialog(self, is_new=True)

530 result = dialog.ShowModal()

531

532 if result == wx.ID_OK:

533 api_name, api_config = dialog.get_api_config()

534

535 if not api_name:

536 wx.MessageBox(T("API name cannot be empty"), T("Error"), wx.OK | wx.ICON_ERROR)

537 return

538

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

542

543 self.api_configs[api_name] = api_config

544 self.load_api_configs()

545

546 dialog.Destroy()

547

548 def on_edit_api(self, api_name):

549 """编辑API配置"""

550 if api_name not in self.api_configs:

551 return

552

553 api_config = self.api_configs[api_name]

554 dialog = ApiEditDialog(self, api_name, api_config, is_new=False)

555 result = dialog.ShowModal()

556

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()

561

562 dialog.Destroy()

563

564 def on_delete_api(self, api_name):

565 """删除API配置"""

566 if api_name not in self.api_configs:

567 return

568

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()

577

578 if result == wx.ID_YES:

579 del self.api_configs[api_name]

580 self.load_api_configs()

581

582 self.config_manager.update_api_config({'api': self.api_configs})

583

584 def on_refresh(self, event):

585 """刷新API列表"""

586 # 重新加载配置

587 self.config_manager.reload_config()

588 self.settings = self.config_manager.get_config()

589

590 # 重新加载API配置

591 self.api_configs = self.settings.get('api', {})

592

593 # 更新列表

594 self.load_api_configs()

595

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()

601

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()

607

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()