@@ -378,22 +378,52 @@ def get_hq_prompt_options(self) -> List[str]:
378378 @pyqtSlot (str , str )
379379 def save_env_var (self , key : str , value : str ):
380380 self .config_service .save_env_var (key , value )
381- self . logger . info ( f"Saved { key } to .env file." )
381+ # 不再输出日志,避免刷屏
382382
383383 # region 预设管理
384384 def get_presets_list (self ) -> List [str ]:
385385 """获取所有预设名称列表"""
386386 return self .preset_service .get_presets_list ()
387387
388388 @pyqtSlot (str )
389- def save_preset (self , preset_name : str ) -> bool :
390- """保存当前.env配置为预设"""
389+ def save_preset (self , preset_name : str , copy_current : bool = False ) -> bool :
390+ """保存预设
391+
392+ Args:
393+ preset_name: 预设名称
394+ copy_current: 是否复制当前配置。False=创建空白预设,True=复制当前配置
395+ """
391396 try :
392- env_vars = self .config_service .load_env_vars ()
393- success = self .preset_service .save_preset (preset_name , env_vars )
394- if success :
395- self ._ui_log (f"预设已保存: { preset_name } " )
397+ if copy_current :
398+ # 复制当前配置模式:保存当前翻译器相关的环境变量
399+ current_translator = self .config_service .get_config ().translator .translator
400+ translator_env_vars = self .config_service .get_all_env_vars (current_translator )
401+ all_env_vars = self .config_service .load_env_vars ()
402+
403+ # 只保存当前翻译器相关的环境变量,并且只保存非空的值
404+ filtered_env_vars = {}
405+ for key in translator_env_vars :
406+ value = all_env_vars .get (key , "" )
407+ if value and value .strip ():
408+ filtered_env_vars [key ] = value
409+
410+ success = self .preset_service .save_preset (preset_name , filtered_env_vars )
411+ if success :
412+ # 不输出日志,避免刷屏
413+ pass
396414 else :
415+ # 创建空白预设模式:只保存空的环境变量结构
416+ current_translator = self .config_service .get_config ().translator .translator
417+ translator_env_vars = self .config_service .get_all_env_vars (current_translator )
418+
419+ # 创建空白的环境变量字典
420+ empty_env_vars = {key : "" for key in translator_env_vars }
421+
422+ success = self .preset_service .save_preset (preset_name , empty_env_vars )
423+ if success :
424+ self ._ui_log (f"预设已创建: { preset_name } (空白预设)" )
425+
426+ if not success :
397427 self ._ui_log (f"保存预设失败: { preset_name } " , "ERROR" )
398428 return success
399429 except Exception as e :
@@ -413,7 +443,8 @@ def load_preset(self, preset_name: str) -> bool:
413443 # 批量保存环境变量
414444 success = self .config_service .save_env_vars (env_vars )
415445 if success :
416- self ._ui_log (f"预设已加载: { preset_name } " )
446+ # 不输出日志,避免刷屏
447+ pass
417448 else :
418449 self ._ui_log (f"应用预设失败: { preset_name } " , "ERROR" )
419450 return success
@@ -437,6 +468,165 @@ def delete_preset(self, preset_name: str) -> bool:
437468 self ._ui_log (f"删除预设失败: { e } " , "ERROR" )
438469 return False
439470 # endregion
471+
472+ # region API测试
473+ async def test_api_connection_async (self , translator_key : str , api_key : str , api_base : str = None , model : str = None ) -> tuple [bool , str ]:
474+ """异步测试API连接(如果指定了模型,会测试该模型是否可用)"""
475+ try :
476+ if "openai" in translator_key .lower ():
477+ from openai import AsyncOpenAI
478+ client = AsyncOpenAI (
479+ api_key = api_key ,
480+ base_url = api_base or "https://api.openai.com/v1"
481+ )
482+
483+ # 如果指定了模型,测试该模型是否可用
484+ if model and model .strip ():
485+ try :
486+ # 尝试用该模型发送一个简单的测试请求
487+ response = await client .chat .completions .create (
488+ model = model ,
489+ messages = [{"role" : "user" , "content" : "test" }],
490+ max_tokens = 5
491+ )
492+ return True , f"连接成功,模型 { model } 可用"
493+ except Exception as e :
494+ # 如果模型测试失败,返回详细错误
495+ return False , f"连接成功但模型 { model } 不可用: { str (e )} "
496+ else :
497+ # 没有指定模型,只测试连接
498+ models = await client .models .list ()
499+ return True , "连接成功"
500+
501+ elif "gemini" in translator_key .lower ():
502+ import google .generativeai as genai
503+
504+ # 如果指定了自定义API Base,使用OpenAI兼容模式
505+ if api_base and api_base != "https://generativelanguage.googleapis.com" :
506+ from openai import AsyncOpenAI
507+ client = AsyncOpenAI (
508+ api_key = api_key ,
509+ base_url = api_base
510+ )
511+
512+ # 如果指定了模型,测试该模型
513+ if model and model .strip ():
514+ try :
515+ response = await client .chat .completions .create (
516+ model = model ,
517+ messages = [{"role" : "user" , "content" : "test" }],
518+ max_tokens = 5
519+ )
520+ return True , f"连接成功,模型 { model } 可用"
521+ except Exception as e :
522+ return False , f"连接成功但模型 { model } 不可用: { str (e )} "
523+ else :
524+ models = await client .models .list ()
525+ return True , "连接成功"
526+ else :
527+ # 使用官方Gemini API
528+ genai .configure (api_key = api_key )
529+
530+ # 如果指定了模型,测试该模型
531+ if model and model .strip ():
532+ try :
533+ test_model = genai .GenerativeModel (model )
534+ response = test_model .generate_content ("test" )
535+ return True , f"连接成功,模型 { model } 可用"
536+ except Exception as e :
537+ return False , f"连接成功但模型 { model } 不可用: { str (e )} "
538+ else :
539+ models = genai .list_models ()
540+ return True , "连接成功"
541+
542+ elif "sakura" in translator_key .lower ():
543+ # Sakura使用OpenAI兼容API
544+ from openai import AsyncOpenAI
545+ if not api_base :
546+ return False , "请先配置SAKURA_API_BASE"
547+ client = AsyncOpenAI (
548+ api_key = "sk-114514" , # Sakura使用固定密钥
549+ base_url = api_base
550+ )
551+
552+ # 如果指定了模型,测试该模型
553+ if model and model .strip ():
554+ try :
555+ response = await client .chat .completions .create (
556+ model = model ,
557+ messages = [{"role" : "user" , "content" : "test" }],
558+ max_tokens = 5
559+ )
560+ return True , f"连接成功,模型 { model } 可用"
561+ except Exception as e :
562+ return False , f"连接成功但模型 { model } 不可用: { str (e )} "
563+ else :
564+ models = await client .models .list ()
565+ return True , "连接成功"
566+
567+ else :
568+ return False , "该翻译器不支持API测试"
569+
570+ except Exception as e :
571+ return False , f"连接失败: { str (e )} "
572+
573+ async def get_available_models_async (self , translator_key : str , api_key : str , api_base : str = None ) -> tuple [bool , List [str ], str ]:
574+ """异步获取可用模型列表"""
575+ try :
576+ if "openai" in translator_key .lower ():
577+ from openai import AsyncOpenAI
578+ client = AsyncOpenAI (
579+ api_key = api_key ,
580+ base_url = api_base or "https://api.openai.com/v1"
581+ )
582+ models_response = await client .models .list ()
583+
584+ # 获取所有模型ID,不过滤
585+ model_ids = [m .id for m in models_response .data ]
586+ model_ids .sort (reverse = True ) # 新模型在前
587+
588+ return True , model_ids , "获取成功"
589+
590+ elif "gemini" in translator_key .lower ():
591+ import google .generativeai as genai
592+
593+ # 如果指定了自定义API Base,使用OpenAI兼容模式
594+ if api_base and api_base != "https://generativelanguage.googleapis.com" :
595+ from openai import AsyncOpenAI
596+ client = AsyncOpenAI (
597+ api_key = api_key ,
598+ base_url = api_base
599+ )
600+ models_response = await client .models .list ()
601+ model_ids = [m .id for m in models_response .data ]
602+ return True , model_ids , "获取成功"
603+ else :
604+ # 使用官方Gemini API - 返回所有模型,不过滤
605+ genai .configure (api_key = api_key )
606+ models = genai .list_models ()
607+ # 获取所有模型名称
608+ model_names = [m .name .replace ("models/" , "" ) for m in models ]
609+ return True , model_names , "获取成功"
610+
611+ elif "sakura" in translator_key .lower ():
612+ # Sakura使用OpenAI兼容API
613+ from openai import AsyncOpenAI
614+ if not api_base :
615+ return False , [], "请先配置SAKURA_API_BASE"
616+ client = AsyncOpenAI (
617+ api_key = "sk-114514" ,
618+ base_url = api_base
619+ )
620+ models_response = await client .models .list ()
621+ model_ids = [m .id for m in models_response .data ]
622+ return True , model_ids , "获取成功"
623+
624+ else :
625+ return False , [], "该翻译器不支持获取模型列表"
626+
627+ except Exception as e :
628+ return False , [], f"获取失败: { str (e )} "
629+ # endregion
440630
441631 # region 配置管理
442632 def load_config_file (self , config_path : str ) -> bool :
0 commit comments