Coverage for aipyapp/__main__.py: 0%

1#!/usr/bin/env python

2# coding: utf-8

3

4 import os

5 import sys

6

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

11 from loguru import logger

12

13 logger.remove()

14 from .i18n import set_lang, T

15 from .aipy import CONFIG_DIR, ConfigManager

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

17

18 def 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

44 def 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

60 def 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

87 def handle_sync(conf, args):

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

89 conf.fetch_config()

90

91 def 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

123 def 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

144 def 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

161 def mainw():

162 args = parse_args()

163 ensure_pkg('wxpython')

164 from .gui.main import main as aipy_main

165 aipy_main(args)

166

167 if __name__ == '__main__':

168 main()