erniecli.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #!/usr/bin/python3
  2. import requests
  3. import json
  4. import sys
  5. import time
  6. import _thread
  7. import os
  8. import subprocess
  9. ERNIE_API_KEY = ""
  10. ERNIE_SECRET_KEY = ""
  11. OPENAI_URL = ""
  12. OPENAI_API_KEY = ""
  13. OPENAI_MODEL = ""
  14. # 后端可选“openai”或“ernie”
  15. BACKEND = ""
  16. ernie_prompt = """\
  17. 你是一个Linux命令行专家,请将我的请求转换成一条可执行的bash命令。
  18. 只给一条命令,不要做任何解释或说明。
  19. 示例:
  20. 请求:显示系统版本信息。
  21. 输出:
  22. ```bash
  23. uname -a
  24. ```
  25. 我的请求是:{0}\
  26. """
  27. openai_prompt = """\
  28. 你是一个Linux命令行专家,请将我的请求转换成一条可执行的bash命令。
  29. 只给一条命令,不要做任何解释或说明。
  30. 示例:
  31. 请求:显示系统版本信息。
  32. 输出:
  33. ```bash
  34. uname -a
  35. ```\
  36. """
  37. # 设置API_KEY和SECRET_KEY
  38. def set_config():
  39. global ERNIE_API_KEY, ERNIE_SECRET_KEY, OPENAI_API_KEY, OPENAI_MODEL, OPENAI_URL, BACKEND
  40. if os.path.exists(os.path.expanduser('~/.config/erniecli/.ernierc')):
  41. get_config()
  42. elif not os.path.exists(os.path.expanduser('~/.config/erniecli')):
  43. os.makedirs(os.path.expanduser('~/.config/erniecli'))
  44. # 用黄色字体
  45. bidx = 0
  46. if BACKEND == "ernie":
  47. bidx = 1
  48. elif BACKEND == "openai":
  49. bidx = 2
  50. elif BACKEND == "":
  51. bidx = 0
  52. while True:
  53. choice_bidx = input("\033[1;33m请选择后端(0: None | 1: ernie | 2: openai)[current: {0}]:".format(bidx))
  54. if choice_bidx == '':
  55. bidx = bidx
  56. else:
  57. bidx = int(choice_bidx)
  58. if bidx == 1 or bidx == 2:
  59. break
  60. if bidx == 1:
  61. BACKEND = "ernie"
  62. elif bidx == 2:
  63. BACKEND = "openai"
  64. choice_ernie = input("\033[1;34m是否需要配置ernie?(y/N)")
  65. if choice_ernie == "y":
  66. apikey_value = input("\033[1;34m请输入API_KEY(当前值:"+ERNIE_API_KEY+"):")
  67. securekey_value = input("请输入SECRET_KEY(当前值"+ERNIE_SECRET_KEY+"):")
  68. if apikey_value != "":
  69. ERNIE_API_KEY = apikey_value.strip()
  70. if securekey_value != "":
  71. ERNIE_SECRET_KEY = securekey_value.strip()
  72. choice_openai = input("\033[1;36m是否需要配置openai?(y/N)")
  73. if choice_openai == "y":
  74. url_value = input("\033[1;36m请输入BASE URL(当前值:"+OPENAI_URL+"):")
  75. apikey_value = input("\033[1;36m请输入API_KEY(当前值:"+OPENAI_API_KEY+"):")
  76. model_value = input("请输入模型(当前值:"+OPENAI_MODEL+"):")
  77. if url_value != "":
  78. OPENAI_URL = url_value.strip()
  79. if apikey_value != "":
  80. OPENAI_API_KEY = apikey_value.strip()
  81. if model_value != "":
  82. OPENAI_MODEL = model_value.strip()
  83. with open(os.path.expanduser('~/.config/erniecli/.ernierc'), 'w', encoding='utf-8') as f:
  84. # 写入所有配置
  85. f.write("[GLOBAL]\n")
  86. f.write("BACKEND="+BACKEND+"\n")
  87. f.write("\n[ERNIE]\n")
  88. f.write("API_KEY="+ERNIE_API_KEY+"\n")
  89. f.write("SECRET_KEY="+ERNIE_SECRET_KEY+"\n")
  90. f.write("\n[OPENAI]\n")
  91. f.write("URL="+OPENAI_URL+"\n")
  92. f.write("API_KEY="+OPENAI_API_KEY+"\n")
  93. f.write("MODEL="+OPENAI_MODEL+"\n")
  94. print("\033[1;32m配置成功\033[0m")
  95. sys.exit(0)
  96. # 读取$HOME/.config/erniecli/.ernierc文件中API_KEY和SECRET_KEY
  97. def get_config():
  98. global ERNIE_API_KEY, ERNIE_SECRET_KEY, OPENAI_API_KEY, OPENAI_MODEL, OPENAI_URL, BACKEND
  99. config = os.path.expanduser('~/.config/erniecli/.ernierc')
  100. if not os.path.exists(config):
  101. print("\033[1;31m请进行使用erniecli进行配置\033[0m")
  102. sys.exit(0)
  103. # 读取配置文件,读取[global]的BACKEND
  104. group = "global"
  105. with open(config, 'r', encoding='utf-8') as f:
  106. for line in f.readlines():
  107. line = line.strip()
  108. if len(line) == 0 or line[0] == '#':
  109. continue
  110. elif line.startswith("["):
  111. group = line[1:-1]
  112. continue
  113. # 配置global
  114. if group == "GLOBAL":
  115. key, value = line.split('=')
  116. if key.strip() == "BACKEND":
  117. BACKEND = value.strip()
  118. if group == "ERNIE":
  119. key, value = line.split('=')
  120. if key.strip() == "API_KEY":
  121. ERNIE_API_KEY = value.strip()
  122. if key.strip() == "SECRET_KEY":
  123. ERNIE_SECRET_KEY = value.strip()
  124. if group == "OPENAI":
  125. key, value = line.split('=')
  126. if key.strip() == "API_KEY":
  127. OPENAI_API_KEY = value.strip()
  128. if key.strip() == "MODEL":
  129. OPENAI_MODEL = value.strip()
  130. if key.strip() == "URL":
  131. OPENAI_URL = value.strip()
  132. # 查询百度千帆
  133. def askERNIE(quest):
  134. url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=" + get_access_token()
  135. payload = json.dumps({
  136. "messages": [
  137. {
  138. "role": "user",
  139. "content": ernie_prompt.format(quest)
  140. }
  141. ],
  142. "temperature": 0.95,
  143. "top_p": 0.8,
  144. "penalty_score": 1,
  145. "disable_search": False,
  146. "enable_citation": False,
  147. "response_format": "text"
  148. })
  149. headers = {
  150. 'Content-Type': 'application/json'
  151. }
  152. response = requests.request("POST", url, headers=headers, data=payload)
  153. return response.text
  154. def get_access_token():
  155. """
  156. 使用 AK,SK 生成鉴权签名(Access Token)
  157. :return: access_token,或是None(如果错误)
  158. """
  159. url = "https://aip.baidubce.com/oauth/2.0/token"
  160. params = {"grant_type": "client_credentials", "client_id": ERNIE_API_KEY, "client_secret": ERNIE_SECRET_KEY}
  161. return str(requests.post(url, params=params).json().get("access_token"))
  162. # 查询OpenAI接口,如赞同模型
  163. def askOpenAI(quest):
  164. global OPENAI_URL
  165. # 如果OPENAI_URL是/结尾,去掉最后的/
  166. if OPENAI_URL[-1] == '/':
  167. OPENAI_URL = OPENAI_URL[:-1]
  168. url = "{0}/v1/chat/completions".format(OPENAI_URL)
  169. payload = json.dumps({
  170. "model": OPENAI_MODEL,
  171. "messages": [
  172. {
  173. "role": "system",
  174. "content": openai_prompt
  175. },
  176. {
  177. "role": "user",
  178. "content": quest
  179. }
  180. ],
  181. "temperature": 0.3
  182. })
  183. headers = {
  184. 'Content-Type': 'application/json',
  185. 'Authorization': 'Bearer '+OPENAI_API_KEY
  186. }
  187. response = requests.request("POST", url, headers=headers, data=payload)
  188. return response.text
  189. def parse(answer):
  190. answer = json.loads(answer)
  191. # 获取第一个结果
  192. if BACKEND=="ernie":
  193. result = answer['result']
  194. elif BACKEND=="openai":
  195. result = answer['choices'][0]['message']['content']
  196. lines = result.split('\n')
  197. # 获取lines中的```bash项编号
  198. try:
  199. index = lines.index('```bash')
  200. return lines[index+1]
  201. except ValueError:
  202. print("\033[1;31mAI没有找到可执行的命令\033[0m")
  203. sys.exit(0)
  204. def loading(lock):
  205. chars = ['⣾', '⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽']
  206. i = 0
  207. print('')
  208. while lock[0]:
  209. i = (i+1) % len(chars)
  210. print('\033[A%s %s' %
  211. (chars[i], lock[1] or '' if len(lock) >= 2 else ''))
  212. time.sleep(0.1)
  213. # 执行alias命令,获取输出结果保存为alias_result
  214. def alias():
  215. # 定义一个dict
  216. alias_result = {'egrep': 'egrep --color=auto'
  217. ,'grep': 'grep --color=auto'
  218. ,'fgrep': 'fgrep --color=auto'
  219. ,'grep': 'grep --color=auto'
  220. ,'l': 'ls -CF'
  221. ,'ll': 'ls -alF'
  222. ,'la': 'ls -A'
  223. ,'ls': 'ls --color=auto'}
  224. return alias_result
  225. def replaceAlias(cmd):
  226. # 获取alias_result
  227. alias_result = alias()
  228. # 获取cmd中的第一个单词
  229. cmd_first = cmd.split(' ')[0]
  230. # 如果cmd_first在alias_result中,则替换
  231. if cmd_first in alias_result:
  232. cmd = alias_result[cmd_first] + ' ' + cmd.replace(cmd_first, '')
  233. return cmd
  234. if __name__ == '__main__':
  235. # 如果没有参数
  236. if len(sys.argv) < 2:
  237. print("Copyright (c) 2024 Xiongwei Yu. Info-Terminal Copilot v1.0 \n\n \
  238. Usage: \n \
  239. erniecli command question : \"?? question\" or \"? question\" for short, quest a command and run\n \
  240. erniecli config : set your config\n \
  241. erniecli alias : show alias\n \
  242. erniecli version : show version")
  243. sys.exit(0)
  244. # 获取第一个参数
  245. cmd = sys.argv[1]
  246. if cmd == "config":
  247. set_config()
  248. # 设置??别名
  249. if cmd == "alias":
  250. print ("alias erniecli='erniecli.py'")
  251. print ("alias ??='erniecli.py command'")
  252. print ("alias ??='erniecli.py command'")
  253. print ("alias ?='erniecli.py command'")
  254. print ("alias ?='erniecli.py command'")
  255. # 显示版本信息
  256. if cmd == "version":
  257. # 紫色显示
  258. print("\033[1;95m终端助理 Version 0.1\n\033[0m")
  259. # 用绿色字体显示“基于文心一言的对话式命令行助理”
  260. print("\033[1;32m基于大语言模型的对话式终端助理\n可使用百度千帆文心大模型ERNIE-3.5-8K或其他OpenAI接口的大语言模型\n让命令行插上AI的翅膀🪽\033[0m")
  261. sys.exit(0)
  262. # 如果cmd为command,调用ask函数
  263. if cmd == "command":
  264. get_config()
  265. # 获取第二个参数
  266. # 如果第二个参数为空,则输出错误,用红色字体显示
  267. if len(sys.argv) < 3:
  268. print("\033[1;31m请输入你的意图\033[0m")
  269. sys.exit(0)
  270. # 获取后面的所有参数,并拼接成字符串
  271. question = ' '.join(sys.argv[2:])
  272. # question = sys.argv[2]
  273. # 如果question为空,则输出错误,用红色字体显示
  274. if question == "":
  275. print("\033[1;31m请输入你的意图\033[0m")
  276. sys.exit(0)
  277. # 调用ask函数,并输出结果
  278. # 显示转圈
  279. lock = [True, '']
  280. try:
  281. _thread.start_new_thread(loading, (lock,))
  282. except Exception as e:
  283. print(e)
  284. #使用绿色字体
  285. lock[1] ="\033[1;32m终端助理正在思考...\033[0m"
  286. # 百度千帆
  287. # answer = askERNIE(question)
  288. # cmd = parseERNIE(answer)
  289. if BACKEND=="ernie":
  290. query = askERNIE
  291. elif BACKEND=="openai":
  292. query = askOpenAI
  293. # OpenAI API
  294. answer = query(question)
  295. cmd = parse(answer)
  296. lock[0] = False
  297. print('\033[F\033[K',end = "\033[1;32m❯ \033[0m")
  298. print('\033[1;32m{0}\033[0m'.format(cmd))
  299. while True:
  300. choice = input('\033[1;32m? \033[0m\033[1;90m是否执行 ⬆ ? [Y/n]\033[0m')
  301. if choice == 'Y' or choice == 'y' or choice == '':
  302. sys.stdout.write('\033[A\r')
  303. sys.stdout.flush()
  304. sys.stdout.write('\033[K')
  305. sys.stdout.flush()
  306. # 执行命令,并输出结果
  307. # print('')
  308. cmd = replaceAlias(cmd)
  309. subprocess.run(cmd, shell=True)
  310. # print('')
  311. # os.system(cmd)
  312. break
  313. elif choice == 'N' or choice == 'n':
  314. print('已取消')
  315. sys.exit(0)
  316. else:
  317. print("请输入正确的选项")