Carbaz commited on
Commit
cc7a977
·
verified ·
1 Parent(s): 3aa82ed

Sync from GitHub

Browse files
Files changed (7) hide show
  1. .gitignore +1 -0
  2. src/__main__.py +18 -5
  3. src/compiler.py +9 -8
  4. src/interface.py +9 -11
  5. src/optimizer.py +18 -7
  6. src/prompts.py +21 -4
  7. src/tester.py +8 -4
.gitignore CHANGED
@@ -9,6 +9,7 @@ __pycache__/
9
  # Distribution / packaging
10
  .Python
11
  build/
 
12
  develop-eggs/
13
  dist/
14
  downloads/
 
9
  # Distribution / packaging
10
  .Python
11
  build/
12
+ compiled/
13
  develop-eggs/
14
  dist/
15
  downloads/
src/__main__.py CHANGED
@@ -1,7 +1,8 @@
1
  """Main entrypoint module for the AI Python C Extensions Generator application."""
2
 
3
  from logging import getLogger
4
- from os import getenv
 
5
  from sys import platform
6
 
7
  from .compiler import compile_extension
@@ -26,7 +27,19 @@ else:
26
  default_platform = "Linux"
27
 
28
  # Read compile stage flag from environment variable, defaulting to False if not set.
29
- compile_stage = getenv("COMPILE_STAGE", "False").lower() in ("true", "1", "yes")
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
 
32
  def main():
@@ -35,13 +48,13 @@ def main():
35
  _logger.info(f'AVAILABLE MODELS: {models}')
36
  # Prepare the interface configuration based.
37
  interface_config = {"models": models, "compile_stage": compile_stage,
38
- "optimize_function": optimize_function}
 
39
  if compile_stage:
40
- _logger.info('COMPILE STAGE ENABLED')
41
  interface_config.update({"compile_extension": compile_extension,
42
  "test_extension": test_extension})
43
  app = get_interface(**interface_config)
44
- app.launch(footer_links=[])
45
  # We return the app instance for potential use in autoreload scenarios.
46
  return app
47
 
 
1
  """Main entrypoint module for the AI Python C Extensions Generator application."""
2
 
3
  from logging import getLogger
4
+ from os import getenv, sep
5
+ from pathlib import Path
6
  from sys import platform
7
 
8
  from .compiler import compile_extension
 
27
  default_platform = "Linux"
28
 
29
  # Read compile stage flag from environment variable, defaulting to False if not set.
30
+ if compile_stage := getenv("COMPILE_STAGE", "False").lower() in ("true", "1", "yes"):
31
+ # Define the build directory for compiled extensions.
32
+ BUILD_DIR = Path("compiled")
33
+ # BUILD_DIR.mkdir(parents=True, exist_ok=True)
34
+ _logger.info('COMPILE STAGE ENABLED')
35
+ _logger.info(f'COMPILE DIRECTORY SET TO: .{sep}{BUILD_DIR}')
36
+
37
+
38
+ # CSS styles for the interface, defining background colors for C and Python code areas.
39
+ css = """
40
+ .c_ext {background-color: #050;}
41
+ .python {background-color: #306998;}
42
+ """
43
 
44
 
45
  def main():
 
48
  _logger.info(f'AVAILABLE MODELS: {models}')
49
  # Prepare the interface configuration based.
50
  interface_config = {"models": models, "compile_stage": compile_stage,
51
+ "optimize_function": optimize_function,
52
+ "compile_path": BUILD_DIR}
53
  if compile_stage:
 
54
  interface_config.update({"compile_extension": compile_extension,
55
  "test_extension": test_extension})
56
  app = get_interface(**interface_config)
57
+ app.launch(footer_links=[], css=css)
58
  # We return the app instance for potential use in autoreload scenarios.
59
  return app
60
 
src/compiler.py CHANGED
@@ -10,14 +10,15 @@ _logger = getLogger(__name__)
10
 
11
 
12
  # Define a function to write outputs to a file with a given filename.
13
- def write_file(data, filename):
14
  """Write data to a file with the specified filename."""
15
- with open(filename, "w") as file:
 
16
  file.write(data)
17
 
18
 
19
  # Extension compilation function.
20
- def build_extension():
21
  """Compile the C extension using 'setup.py' and return the compilation output."""
22
  # Set default COMSPEC to cmd.exe on Windows to avoid issues with some C compilers.
23
  if sys.platform == "win32":
@@ -27,7 +28,7 @@ def build_extension():
27
  try:
28
  _logger.info('STARTING COMPILATION PROCESS...')
29
  compile_cmd = ["python", "setup.py", "build_ext", "--inplace"]
30
- compile_result = subprocess.run(compile_cmd, env=os.environ,
31
  check=True, text=True, capture_output=True)
32
  except subprocess.CalledProcessError as ex:
33
  _logger.error(f"COMPILATION FAILED WITH ERROR:\n{ex.stdout}\n{ex.stderr}")
@@ -42,19 +43,19 @@ def build_extension():
42
 
43
 
44
  # Extension compilation function.
45
- def compile_extension(c_code, setup_code, module_name):
46
  """Build the C extension from the provided codes."""
47
  try: # Write the provided codes to their respective files.
48
  _logger.info('WRITING GENERATED C CODE TO FILE...')
49
- write_file(c_code, f"{module_name}.c")
50
  _logger.info('WRITING GENERATED SETUP CODE TO FILE...')
51
- write_file(setup_code, "setup.py")
52
  except Exception as ex:
53
  _logger.error(f"ERROR WHILE WRITING FILES:\n{ex}")
54
  return f"An error occurred while writing files:\n{ex}"
55
  try: # Build the extension and capture the output.
56
  _logger.info('BUILDING THE EXTENSION...')
57
- build_output = build_extension()
58
  except Exception as ex: # If build fails, return the error message.
59
  _logger.error(f"ERROR WHILE BUILDING EXTENSION:\n{ex}")
60
  return str(ex)
 
10
 
11
 
12
  # Define a function to write outputs to a file with a given filename.
13
+ def write_file(data, path):
14
  """Write data to a file with the specified filename."""
15
+ path.parent.mkdir(parents=True, exist_ok=True)
16
+ with open(path, "w") as file:
17
  file.write(data)
18
 
19
 
20
  # Extension compilation function.
21
+ def build_extension(compile_path):
22
  """Compile the C extension using 'setup.py' and return the compilation output."""
23
  # Set default COMSPEC to cmd.exe on Windows to avoid issues with some C compilers.
24
  if sys.platform == "win32":
 
28
  try:
29
  _logger.info('STARTING COMPILATION PROCESS...')
30
  compile_cmd = ["python", "setup.py", "build_ext", "--inplace"]
31
+ compile_result = subprocess.run(compile_cmd, env=os.environ, cwd=compile_path,
32
  check=True, text=True, capture_output=True)
33
  except subprocess.CalledProcessError as ex:
34
  _logger.error(f"COMPILATION FAILED WITH ERROR:\n{ex.stdout}\n{ex.stderr}")
 
43
 
44
 
45
  # Extension compilation function.
46
+ def compile_extension(c_code, setup_code, module_name, compile_path):
47
  """Build the C extension from the provided codes."""
48
  try: # Write the provided codes to their respective files.
49
  _logger.info('WRITING GENERATED C CODE TO FILE...')
50
+ write_file(c_code, compile_path / f"{module_name}.c")
51
  _logger.info('WRITING GENERATED SETUP CODE TO FILE...')
52
+ write_file(setup_code, compile_path / "setup.py")
53
  except Exception as ex:
54
  _logger.error(f"ERROR WHILE WRITING FILES:\n{ex}")
55
  return f"An error occurred while writing files:\n{ex}"
56
  try: # Build the extension and capture the output.
57
  _logger.info('BUILDING THE EXTENSION...')
58
+ build_output = build_extension(compile_path)
59
  except Exception as ex: # If build fails, return the error message.
60
  _logger.error(f"ERROR WHILE BUILDING EXTENSION:\n{ex}")
61
  return str(ex)
src/interface.py CHANGED
@@ -1,16 +1,11 @@
1
  """Interface module for the AI Python C Extensions Generator application."""
2
 
3
- from gradio import Blocks, Button, Dropdown, Examples, Markdown, Row, TextArea, Textbox
 
4
 
5
  from .examples import example_dict
6
 
7
 
8
- css = """
9
- .c_ext {background-color: #050;}
10
- .python {background-color: #306998;}
11
- """
12
-
13
-
14
  def _compile_extension():
15
  return "COMPILE_EXTENSION PLACEHOLDER"
16
 
@@ -23,9 +18,11 @@ def get_interface(optimize_function, compile_stage=False,
23
  compile_extension=_compile_extension,
24
  test_extension=_test_extension,
25
  default_platform="Windows",
 
26
  models=["gpt-5.1-codex-mini"]):
27
  """Get the Gradio Blocks interface for the AI Python C Extensions Generator."""
28
- with Blocks(css=css, title="AI Python C Extensions Generator") as ui:
 
29
  Markdown("## Convert code from Python to C Extension")
30
 
31
  with Row():
@@ -57,7 +54,8 @@ def get_interface(optimize_function, compile_stage=False,
57
  buttons=["copy"], elem_classes=["python"])
58
 
59
  get_extension.click(optimize_function,
60
- inputs=[python, module_name, platform, model],
 
61
  outputs=[c_code, setup_code, usage_code])
62
 
63
  # ######### BUILD AND TEST SECTIONS ######### #
@@ -75,11 +73,11 @@ def get_interface(optimize_function, compile_stage=False,
75
  elem_classes=["python"])
76
 
77
  compile_ext.click(compile_extension,
78
- inputs=[c_code, setup_code, module_name],
79
  outputs=[c_ext_out])
80
 
81
  test_run.click(test_extension,
82
- inputs=[usage_code],
83
  outputs=[test_out])
84
 
85
  return ui
 
1
  """Interface module for the AI Python C Extensions Generator application."""
2
 
3
+ from gradio import Blocks, Button, Dropdown, Examples, Markdown, Row, State, TextArea
4
+ from gradio import Textbox
5
 
6
  from .examples import example_dict
7
 
8
 
 
 
 
 
 
 
9
  def _compile_extension():
10
  return "COMPILE_EXTENSION PLACEHOLDER"
11
 
 
18
  compile_extension=_compile_extension,
19
  test_extension=_test_extension,
20
  default_platform="Windows",
21
+ compile_path="compile",
22
  models=["gpt-5.1-codex-mini"]):
23
  """Get the Gradio Blocks interface for the AI Python C Extensions Generator."""
24
+ with Blocks(title="AI Python C Extensions Generator") as ui:
25
+ compile_path_st = State(value=compile_path)
26
  Markdown("## Convert code from Python to C Extension")
27
 
28
  with Row():
 
54
  buttons=["copy"], elem_classes=["python"])
55
 
56
  get_extension.click(optimize_function,
57
+ inputs=[python, module_name, platform,
58
+ compile_path_st, model],
59
  outputs=[c_code, setup_code, usage_code])
60
 
61
  # ######### BUILD AND TEST SECTIONS ######### #
 
73
  elem_classes=["python"])
74
 
75
  compile_ext.click(compile_extension,
76
+ inputs=[c_code, setup_code, module_name, compile_path_st],
77
  outputs=[c_ext_out])
78
 
79
  test_run.click(test_extension,
80
+ inputs=[usage_code, compile_path_st],
81
  outputs=[test_out])
82
 
83
  return ui
src/optimizer.py CHANGED
@@ -4,7 +4,7 @@ from logging import getLogger
4
 
5
  from dotenv import load_dotenv
6
  from openai import OpenAI
7
- from pydantic import BaseModel
8
 
9
  from .prompts import messages_for
10
 
@@ -24,9 +24,18 @@ _logger.info(f'INITIALIZED OPTIMIZER MODULE')
24
 
25
  # Define Pydantic model class for GPT response parsing.
26
  class _extension_codes(BaseModel):
27
- c_code: str
28
- setup: str
29
- usage: str
 
 
 
 
 
 
 
 
 
30
 
31
  def __str__(self):
32
  """Return a string representation of the optimization codes."""
@@ -38,13 +47,15 @@ class _extension_codes(BaseModel):
38
 
39
 
40
  # Define optimization function using OpenAI's GPT model.
41
- def optimize_gpt(python_code, module_name, platform, model=OPENAI_MODEL):
42
  """Generate an optimized C extension for Python."""
43
  schema = _extension_codes.model_json_schema()
44
  _logger.info('SENDING OPTIMIZATION REQUEST TO OPENAI... '
45
- f'(MODEL: {model}, PLATFORM: {platform})')
 
46
  response = openai.responses.parse(
47
  model=model, text_format=_extension_codes,
48
- input=messages_for(python_code, module_name, schema, platform)).output_parsed
 
49
  _logger.info('RECEIVED OPTIMIZATION RESPONSE FROM OPENAI')
50
  return response.c_code, response.setup, response.usage
 
4
 
5
  from dotenv import load_dotenv
6
  from openai import OpenAI
7
+ from pydantic import BaseModel, Field
8
 
9
  from .prompts import messages_for
10
 
 
24
 
25
  # Define Pydantic model class for GPT response parsing.
26
  class _extension_codes(BaseModel):
27
+ c_code: str = Field(...,
28
+ description="Generated C extension source "
29
+ "code for the Python module.")
30
+ setup: str = Field(...,
31
+ description="The generated setup.py build script "
32
+ "used to compile the C extension module."
33
+ "It must assume the module is in the current folder "
34
+ "and not in any subfolder.")
35
+ usage: str = Field(...,
36
+ description="A Python usage example that imports the compiled "
37
+ "extension and compares its execution time with the "
38
+ "original Python implementation.")
39
 
40
  def __str__(self):
41
  """Return a string representation of the optimization codes."""
 
47
 
48
 
49
  # Define optimization function using OpenAI's GPT model.
50
+ def optimize_gpt(python_code, module_name, platform, compile_path, model=OPENAI_MODEL):
51
  """Generate an optimized C extension for Python."""
52
  schema = _extension_codes.model_json_schema()
53
  _logger.info('SENDING OPTIMIZATION REQUEST TO OPENAI... '
54
+ f'(MODEL: {model}, PLATFORM: {platform}, '
55
+ f'MODULE: {module_name}, COMPILE PATH: {compile_path})')
56
  response = openai.responses.parse(
57
  model=model, text_format=_extension_codes,
58
+ input=messages_for(python_code, module_name, schema, platform, compile_path)
59
+ ).output_parsed
60
  _logger.info('RECEIVED OPTIMIZATION RESPONSE FROM OPENAI')
61
  return response.c_code, response.setup, response.usage
src/prompts.py CHANGED
@@ -10,17 +10,20 @@ Your responses must always be a JSON with the following schema:
10
 
11
  Use comments sparingly and do not provide any explanation other than occasional comments.
12
 
13
- The C extension for Python needs to produce an identical output in the fastest possible
14
  time.
15
 
16
  Make sure the C extension for Python code is correct and can be compiled with
17
  'python setup.py build_ext' and used in Python.
18
 
19
  The usage example must include a time measurement and a comparison with the original
20
- Python code.
21
 
22
- Do not include any additional text or explanation outside the JSON structure.
 
 
23
 
 
24
  Make sure the JSON is correctly formatted.
25
  """
26
 
@@ -36,6 +39,19 @@ a few code comments.
36
  The module name, used to import, must be "{module_name}", the generated C file will
37
  be named "{module_name}.c".
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  Pay attention to number types to ensure no int overflows.
40
  Remember to #include all necessary C packages such as iomanip or <python.h>
41
 
@@ -52,10 +68,11 @@ Here is the Python code to reimplement:
52
 
53
 
54
  # Define function to create the messages for the LLM.
55
- def messages_for(python_code, module_name, schema, platform):
56
  """Create the messages given the Python code, module name, and platform."""
57
  return [
58
  {"role": "system", "content": system_message.format(schema=schema)},
59
  {"role": "user", "content": user_prompt.format(python_code=python_code,
60
  module_name=module_name,
 
61
  platform=platform)}]
 
10
 
11
  Use comments sparingly and do not provide any explanation other than occasional comments.
12
 
13
+ The C extension for Python needs to produce identical output in the fastest possible
14
  time.
15
 
16
  Make sure the C extension for Python code is correct and can be compiled with
17
  'python setup.py build_ext' and used in Python.
18
 
19
  The usage example must include a time measurement and a comparison with the original
20
+ Python code, absolute and proportional difference.
21
 
22
+ Do not include an `if __name__ == '__main__'` guard in the usage script.
23
+ The usage script must be importable, and the usage example must invoke its functions
24
+ directly.
25
 
26
+ Do not include any additional text or explanation outside the JSON structure.
27
  Make sure the JSON is correctly formatted.
28
  """
29
 
 
39
  The module name, used to import, must be "{module_name}", the generated C file will
40
  be named "{module_name}.c".
41
 
42
+ The generated C extension module will be located in the "{compile_path}" folder.
43
+ Only the usage example file should import the module from that folder:
44
+
45
+ from {compile_path} import {module_name}
46
+
47
+ Do not use "{compile_path}" inside the generated C source or in the generated setup.py
48
+ file. The generated C source and setup.py must behave as if they are in the current
49
+ folder and must not reference any external path.
50
+
51
+ Do not include an `if __name__ == '__main__'` guard in the generated module or the
52
+ usage example. The usage script must be importable, and the usage example must invoke
53
+ its functions directly.
54
+
55
  Pay attention to number types to ensure no int overflows.
56
  Remember to #include all necessary C packages such as iomanip or <python.h>
57
 
 
68
 
69
 
70
  # Define function to create the messages for the LLM.
71
+ def messages_for(python_code, module_name, schema, platform, compile_path):
72
  """Create the messages given the Python code, module name, and platform."""
73
  return [
74
  {"role": "system", "content": system_message.format(schema=schema)},
75
  {"role": "user", "content": user_prompt.format(python_code=python_code,
76
  module_name=module_name,
77
+ compile_path=compile_path,
78
  platform=platform)}]
src/tester.py CHANGED
@@ -9,9 +9,10 @@ _logger = getLogger(__name__)
9
 
10
 
11
  # Define a function to write outputs to a file with a given filename.
12
- def write_file(data, filename):
13
  """Write data to a file with the specified filename."""
14
- with open(filename, "w") as file:
 
15
  file.write(data)
16
 
17
 
@@ -25,6 +26,9 @@ def execute_python(code):
25
  sys.stdout = output
26
  # Execute the provided code in a clean global namespace.
27
  exec(code, {})
 
 
 
28
  finally:
29
  # Restore original stdout.
30
  sys.stdout = sys.__stdout__
@@ -32,10 +36,10 @@ def execute_python(code):
32
 
33
 
34
  # Extension testing function.
35
- def test_extension(usage_code):
36
  """Test the C extension executing the code and capture its output."""
37
  try: # Write the code to file.
38
- write_file(usage_code, "usage_example.py")
39
  except Exception as ex:
40
  return f"An error occurred while writing test file:\n{ex}"
41
  try:
 
9
 
10
 
11
  # Define a function to write outputs to a file with a given filename.
12
+ def write_file(data, path):
13
  """Write data to a file with the specified filename."""
14
+ path.parent.mkdir(parents=True, exist_ok=True)
15
+ with open(path, "w") as file:
16
  file.write(data)
17
 
18
 
 
26
  sys.stdout = output
27
  # Execute the provided code in a clean global namespace.
28
  exec(code, {})
29
+ except Exception as ex:
30
+ _logger.error(f"ERROR WHILE EXECUTING TEST CODE:\n{ex}")
31
+ return f"An error occurred while executing test code:\n{ex}"
32
  finally:
33
  # Restore original stdout.
34
  sys.stdout = sys.__stdout__
 
36
 
37
 
38
  # Extension testing function.
39
+ def test_extension(usage_code, compile_path):
40
  """Test the C extension executing the code and capture its output."""
41
  try: # Write the code to file.
42
+ write_file(usage_code, compile_path / "usage_example.py")
43
  except Exception as ex:
44
  return f"An error occurred while writing test file:\n{ex}"
45
  try: