Coverage for aipyapp/__main__.py: 0%

133 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-11 12:02 +0200

1#!/usr/bin/env python 

2# coding: utf-8 

3 

4import os 

5import sys 

6 

7if "pythonw" in sys.executable.lower(): 

8 sys.stdout = open(os.devnull, "w", encoding='utf-8') 

9 sys.stderr = open(os.devnull, "w", encoding='utf-8') 

10 

11from loguru import logger 

12 

13logger.remove() 

14from .i18n import set_lang, T 

15from .aipy import CONFIG_DIR, ConfigManager 

16logger.add(CONFIG_DIR / "aipyapp.log", format="{time:HH:mm:ss} | {level} | {message} | {extra}", level='INFO') 

17 

18def parse_args(): 

19 import argparse 

20 config_help_message = ( 

21 f"Specify the configuration directory.\nDefaults to {CONFIG_DIR} if not provided." 

22 ) 

23 

24 parser = argparse.ArgumentParser(description="Python use - AIPython", formatter_class=argparse.RawTextHelpFormatter) 

25 parser.add_argument("-c", '--config-dir', default=CONFIG_DIR, type=str, help=config_help_message) 

26 parser.add_argument('--debug', default=False, action='store_true', help="Debug mode") 

27 

28 modes = parser.add_mutually_exclusive_group(required=False) 

29 modes.add_argument('-u', '--update', default=False, action='store_true', help="Update aipyapp to latest version") 

30 modes.add_argument('-s', '--sync', default=False, action='store_true', help="Sync content from trustoken") 

31 modes.add_argument('-p', '--python', default=False, action='store_true', help="Python mode") 

32 modes.add_argument('-i', '--ipython', default=False, action='store_true', help="IPython mode") 

33 modes.add_argument('-g', '--gui', default=False, action='store_true', help="GUI mode") 

34 modes.add_argument('-e', '--exec', default=None, help="CMD mode - execute an instruction") 

35 modes.add_argument('-a', '--agent', default=False, action='store_true', help='Agent mode - HTTP API server for n8n integration') 

36 parser.add_argument('--port', type=int, default=8848, help="Port for agent mode HTTP server (default: 8848)") 

37 parser.add_argument('--host', default='127.0.0.1', help="Host for agent mode HTTP server (default: 127.0.0.1)") 

38 parser.add_argument('--style', default=None, help="Style of the display, e.g. 'classic' or 'modern'") 

39 parser.add_argument('--role', default=None, help="Role to use") 

40 parser.add_argument('--beta', action='store_true', help='Include beta versions in update') 

41 

42 return parser.parse_args() 

43 

44def ensure_pkg(pkg): 

45 try: 

46 if pkg == 'wxpython': 

47 import wx 

48 elif pkg == 'ipython': 

49 import IPython 

50 elif pkg == 'fastapi': 

51 import fastapi 

52 elif pkg == 'uvicorn': 

53 import uvicorn 

54 except ImportError: 

55 import subprocess 

56 print(f"Installing required package: {pkg}") 

57 cp = subprocess.run([sys.executable, "-m", "pip", "install", pkg]) 

58 assert cp.returncode == 0 

59 

60def handle_update(args): 

61 """处理 update 命令""" 

62 import subprocess 

63 from . import __version__ 

64 

65 package_name = 'aipyapp' 

66 print(f"当前版本: {__version__}") 

67 

68 if args.beta: 

69 print(f"更新到最新版本 (包括测试版): {package_name}") 

70 cmd = [sys.executable, "-m", "pip", "install", "--upgrade", "--pre", package_name] 

71 else: 

72 print(f"更新到最新稳定版本: {package_name}") 

73 cmd = [sys.executable, "-m", "pip", "install", "--upgrade", package_name] 

74 

75 try: 

76 result = subprocess.run(cmd, check=True, capture_output=True, text=True) 

77 print("更新完成!") 

78 if result.stdout.strip(): 

79 print(result.stdout) 

80 except subprocess.CalledProcessError as e: 

81 print(f"更新失败: {e.stderr}") 

82 sys.exit(1) 

83 except Exception as e: 

84 print(f"更新失败: {str(e)}") 

85 sys.exit(1) 

86 

87def handle_sync(conf, args): 

88 """处理 sync 命令""" 

89 conf.fetch_config() 

90 

91def init_settings(conf, args): 

92 settings = conf.get_config() 

93 lang = settings.get('lang') 

94 if lang: set_lang(lang) 

95 settings.gui = args.gui 

96 settings.debug = args.debug 

97 settings.config_dir = args.config_dir 

98 if args.role: 

99 settings['role'] = args.role.lower() 

100 if args.style: 

101 display_config = settings.setdefault('display', {}) 

102 display_config['style'] = args.style 

103 if args.agent: 

104 settings['agent'] = {'port': args.port, 'host': args.host} 

105 

106 #TODO: remove these lines 

107 if conf.check_config(gui=True) == 'TrustToken': 

108 from .config import LLMConfig 

109 llm_config = LLMConfig(CONFIG_DIR / "config") 

110 if llm_config.need_config(): 

111 settings['llm_need_config'] = True 

112 if not args.gui: 

113 from .aipy.wizard import show_provider_config 

114 show_provider_config(llm_config) 

115 if llm_config.need_config(): 

116 print(f"{T('LLM configuration required')}") 

117 sys.exit(1) 

118 settings["llm"] = llm_config.config 

119 

120 settings['config_manager'] = conf 

121 return settings 

122 

123def get_aipy_main(args, settings): 

124 """根据参数获取对应的 aipy_main 函数""" 

125 if args.agent: 

126 ensure_pkg('fastapi') 

127 ensure_pkg('uvicorn') 

128 from .cli.cli_agent import main as aipy_main 

129 elif args.python: 

130 from .cli.cli_python import main as aipy_main 

131 elif args.ipython: 

132 ensure_pkg('ipython') 

133 from .cli.cli_ipython import main as aipy_main 

134 elif args.gui: 

135 settings['gui'] = True 

136 ensure_pkg('wxpython') 

137 from .gui.main import main as aipy_main 

138 else: 

139 if args.exec: 

140 settings['exec_cmd'] = args.exec 

141 from .cli.cli_task import main as aipy_main 

142 return aipy_main 

143 

144def main(): 

145 args = parse_args() 

146 

147 # 处理 update 子命令 

148 if args.update: 

149 handle_update(args) 

150 return 

151 

152 conf = ConfigManager(args.config_dir) 

153 if args.sync: 

154 handle_sync(conf, args) 

155 return 

156 

157 settings = init_settings(conf, args) 

158 aipy_main = get_aipy_main(args, settings) 

159 aipy_main(settings) 

160 

161def mainw(): 

162 args = parse_args() 

163 ensure_pkg('wxpython') 

164 from .gui.main import main as aipy_main 

165 aipy_main(args) 

166 

167if __name__ == '__main__': 

168 main()