You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

GPTtrace.py 6.3 kB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #! /bin/env python3
  2. import argparse
  3. import os
  4. import time
  5. from pathlib import Path
  6. from typing import List, Optional, Tuple
  7. import pygments
  8. from marko.block import FencedCode
  9. from marko.inline import RawText
  10. from marko.parser import Parser
  11. from prompt_toolkit import print_formatted_text
  12. from prompt_toolkit.formatted_text import PygmentsTokens
  13. from pygments.token import Token
  14. from pygments_markdown_lexer import MarkdownLexer
  15. from revChatGPT.V1 import Chatbot
  16. ENV_UUID = "GPTTRACE_CONV_UUID"
  17. ENV_ACCESS_TOKEN = "GPTTRACE_ACCESS_TOKEN"
  18. PROMPTS_DIR = Path("./prompts")
  19. def pretty_print(input, lexer=MarkdownLexer, *args, **kwargs):
  20. tokens = list(pygments.lex(input, lexer=lexer()))
  21. print_formatted_text(PygmentsTokens(tokens), *args, **kwargs)
  22. # print = pretty_print
  23. def main():
  24. parser = argparse.ArgumentParser(
  25. prog="GPTtrace",
  26. description="Use ChatGPT to write eBPF programs (bpftrace, etc.)",
  27. )
  28. group = parser.add_mutually_exclusive_group()
  29. group.add_argument(
  30. "-i", "--info", help="Let ChatGPT explain what's eBPF", action="store_true"
  31. )
  32. group.add_argument(
  33. "-e",
  34. "--execute",
  35. help="Generate commands using your input with ChatGPT, and run it",
  36. action="store",
  37. metavar="TEXT",
  38. )
  39. group.add_argument(
  40. "-g", "--generate", help="Generate eBPF programs using your input with ChatGPT", action="store", metavar="TEXT")
  41. group.add_argument(
  42. "--train", help="Train ChatGPT with conversions we provided", action="store_true")
  43. parser.add_argument("-v", "--verbose",
  44. help="Show more details", action="store_true")
  45. parser.add_argument(
  46. "-u",
  47. "--uuid",
  48. help=f"Conversion UUID to use, or passed through environment variable `{ENV_UUID}`",
  49. )
  50. parser.add_argument(
  51. "-t",
  52. "--access-token",
  53. help=f"ChatGPT access token, see `https://chat.openai.com/api/auth/session` or passed through `{ENV_ACCESS_TOKEN}`",
  54. )
  55. args = parser.parse_args()
  56. access_token = args.access_token or os.environ.get(ENV_ACCESS_TOKEN, None)
  57. conv_uuid = args.uuid or os.environ.get(ENV_UUID, None)
  58. if access_token is None:
  59. print(
  60. f"Either provide your access token through `-t` or through environment variable {ENV_ACCESS_TOKEN}"
  61. )
  62. return
  63. chatbot = Chatbot(config={"access_token": access_token})
  64. if args.info:
  65. generate_result(chatbot, "Explain what's eBPF", conv_uuid, True)
  66. elif args.execute is not None:
  67. desc: str = args.execute
  68. print("Sending query to ChatGPT: " + desc)
  69. ret_val, _ = generate_result(
  70. chatbot, construct_running_prompt(desc), conv_uuid, args.verbose)
  71. # print(ret_val)
  72. parsed = make_executable_command(ret_val)
  73. # print(f"Command to run: {parsed}")
  74. print("Press Ctrl+C to stop the program....")
  75. os.system("sudo " + parsed)
  76. elif args.generate is not None:
  77. desc: str = args.generate
  78. print("Sending query to ChatGPT: " + desc)
  79. ret_val, _ = generate_result(
  80. chatbot, construct_generate_prompt(desc), conv_uuid)
  81. pretty_print(ret_val)
  82. parsed = extract_code_blocks(ret_val)
  83. # print(f"Command to run: {parsed}")
  84. with open("generated.bpf.c", "w") as f:
  85. for code in parsed:
  86. f.write(code)
  87. elif args.train:
  88. prompts = os.listdir(PROMPTS_DIR)
  89. prompts.sort()
  90. # conv_uuid could be None, in which we will create a new session and use it in the next steps
  91. session = conv_uuid
  92. for file in prompts:
  93. info = f"Training ChatGPT with `{file}`"
  94. print("-"*len(info))
  95. print(info)
  96. print("-"*len(info))
  97. with open(PROMPTS_DIR/file, "r") as f:
  98. input_data = f.read()
  99. if args.verbose:
  100. print(input_data)
  101. resp, session = generate_result(
  102. chatbot, input_data, conv_uuid, args.verbose)
  103. time.sleep(2.4)
  104. print(f"Trained session: {session}")
  105. else:
  106. parser.print_help()
  107. def construct_generate_prompt(text: str) -> str:
  108. return f"""You are now a translater from human language to {os.uname()[0]} eBPF programs.
  109. Please write eBPF programs for me.
  110. No explanation required, no instruction required, don't tell me how to compile and run.
  111. What I want is a eBPF program for: {text}."""
  112. def construct_running_prompt(text: str) -> str:
  113. return f"""You are now a translater from human language to {os.uname()[0]} shell bpftrace command.
  114. No explanation required.
  115. respond with only the raw shell bpftrace command.
  116. It should be start with `bpftrace`.
  117. Your response should be able to put into a shell and run directly.
  118. Just output in one line, without any description, or any other text that cannot be run in shell.
  119. What should I type to shell to trace using bpftrace for: {text}, in one line."""
  120. def make_executable_command(command: str) -> str:
  121. if command.startswith("\n"):
  122. command = command[1:]
  123. if command.endswith("\n"):
  124. command = command[:-1]
  125. if command.startswith("`"):
  126. command = command[1:]
  127. if command.endswith("`"):
  128. command = command[:-1]
  129. command = command.strip()
  130. command = command.split("User: ")[0]
  131. return command
  132. def generate_result(bot: Chatbot, text: str, session: Optional[str] = None, print_out: bool = False) -> Tuple[str, str]:
  133. from io import StringIO
  134. prev_text = ""
  135. buf = StringIO()
  136. received_session = ""
  137. for data in bot.ask(
  138. text, conversation_id=session
  139. ):
  140. received_session = data["conversation_id"]
  141. message = data["message"][len(prev_text):]
  142. if print_out:
  143. print(message, end="", flush=True)
  144. buf.write(message)
  145. prev_text = data["message"]
  146. if print_out:
  147. print()
  148. return buf.getvalue(), received_session
  149. def extract_code_blocks(text: str) -> List[str]:
  150. result = []
  151. parser = Parser()
  152. for block in parser.parse(text).children:
  153. if type(block) is FencedCode:
  154. block: FencedCode
  155. blk: RawText = block.children[0]
  156. result.append(blk.children)
  157. return result
  158. if __name__ == "__main__":
  159. main()

Generate eBPF programs and tracing with ChatGPT and natural language