llm-codegen-research 1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
llm_cgr/__init__.py ADDED
@@ -0,0 +1,19 @@
1
+ from llm_cgr import analyse, query
2
+ from llm_cgr.analyse import CodeBlock, CodeData, Markdown, analyse_code
3
+ from llm_cgr.json_utils import read_json, save_json
4
+ from llm_cgr.query import get_client, query_list, quick_generate
5
+
6
+
7
+ __all__ = [
8
+ "analyse",
9
+ "query",
10
+ "CodeBlock",
11
+ "CodeData",
12
+ "Markdown",
13
+ "analyse_code",
14
+ "read_json",
15
+ "save_json",
16
+ "get_client",
17
+ "query_list",
18
+ "quick_generate",
19
+ ]
@@ -0,0 +1,10 @@
1
+ from llm_cgr.analyse.classes import CodeBlock, Markdown
2
+ from llm_cgr.analyse.languages import CodeData, analyse_code
3
+
4
+
5
+ __all__ = [
6
+ "CodeBlock",
7
+ "Markdown",
8
+ "CodeData",
9
+ "analyse_code",
10
+ ]
@@ -0,0 +1,139 @@
1
+ """Classes for handling markdown responses from LLMs."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from llm_cgr.analyse.languages import analyse_code
6
+ from llm_cgr.analyse.regexes import CODE_BLOCK_REGEX
7
+ from llm_cgr.defaults import DEFAULT_CODEBLOCK_LANGUAGE
8
+
9
+
10
+ @dataclass
11
+ class CodeBlock:
12
+ """
13
+ A class to represent a block of code with it's language.
14
+ """
15
+
16
+ language: str | None
17
+ text: str
18
+ valid: bool | None # None if validity unknown, language not supported
19
+ error: str | None # only set if not valid
20
+ defined_funcs: list[str]
21
+ called_funcs: list[str]
22
+ packages: list[str]
23
+ imports: list[str]
24
+
25
+ def __init__(
26
+ self,
27
+ language: str | None,
28
+ text: str,
29
+ default_language: str | None = DEFAULT_CODEBLOCK_LANGUAGE,
30
+ ):
31
+ self.language = language.strip().lower() if language else None
32
+ self.text = text.strip()
33
+
34
+ code_data = analyse_code(
35
+ code=self.text, language=self.language or default_language
36
+ )
37
+
38
+ if self.language is None and not code_data.valid:
39
+ # if we hit errors after defaulting the language, ignore the results!
40
+ self.valid = None
41
+ self.error = None
42
+ self.defined_funcs = []
43
+ self.called_funcs = []
44
+ self.packages = []
45
+ self.imports = []
46
+
47
+ else:
48
+ self.language = self.language or default_language
49
+ self.valid = code_data.valid
50
+ self.error = code_data.error
51
+ self.defined_funcs = code_data.defined_funcs
52
+ self.called_funcs = code_data.called_funcs
53
+ self.packages = code_data.packages
54
+ self.imports = code_data.imports
55
+
56
+ def __repr__(self):
57
+ _language = f"language={self.language or 'unspecified'}"
58
+ _lines = f"lines={len(self.text.splitlines())}"
59
+ return f"{self.__class__.__name__}({_language}, {_lines})"
60
+
61
+ def __str__(self):
62
+ return self.text
63
+
64
+ @property
65
+ def markdown(self):
66
+ return f"```{self.language or ''}\n{self.text}\n```"
67
+
68
+
69
+ @dataclass
70
+ class Markdown:
71
+ """
72
+ A class to hold a markdown response from an LLM as a series of text and code blocks.
73
+ """
74
+
75
+ text: str
76
+ code_blocks: list[CodeBlock]
77
+ code_errors: list[str]
78
+ languages: list[str]
79
+
80
+ def __init__(
81
+ self,
82
+ text: str,
83
+ default_codeblock_language: str | None = DEFAULT_CODEBLOCK_LANGUAGE,
84
+ ):
85
+ """
86
+ Initialise the MarkdownResponse object with the text and code blocks.
87
+ Use `codeblock_language` when no language is specified for a code block.
88
+ """
89
+ self.text = text
90
+ self.code_blocks = self.extract_code_blocks(
91
+ response=text,
92
+ default_language=default_codeblock_language,
93
+ )
94
+ self.code_errors = [
95
+ f"{i}: {cb.error}" for i, cb in enumerate(self.code_blocks) if cb.error
96
+ ]
97
+ self.languages = sorted(
98
+ list({bl.language for bl in self.code_blocks if bl.language})
99
+ )
100
+
101
+ def __repr__(self):
102
+ _lines = f"lines={len(self.text.splitlines())}"
103
+ _code_blocks = f"code_blocks={len(self.code_blocks)}"
104
+ _languages = f"languages={','.join(self.languages)}"
105
+ return f"{self.__class__.__name__}({_lines}, {_code_blocks}, {_languages})"
106
+
107
+ def __str__(self):
108
+ return self.text
109
+
110
+ @staticmethod
111
+ def extract_code_blocks(
112
+ response: str,
113
+ default_language: str | None = DEFAULT_CODEBLOCK_LANGUAGE,
114
+ ) -> list[CodeBlock]:
115
+ """
116
+ Extract the code blocks from the markdown formatted text.
117
+ """
118
+ matches = CODE_BLOCK_REGEX.findall(string=response)
119
+ blocks = []
120
+ for match in matches:
121
+ language, text = match
122
+ blocks.append(
123
+ CodeBlock(
124
+ language=language if language else None,
125
+ text=text,
126
+ default_language=default_language,
127
+ )
128
+ )
129
+ return blocks
130
+
131
+ def first_code_block(self, language: str) -> CodeBlock | None:
132
+ """
133
+ Return the first code block of a certain language in the response.
134
+ """
135
+ for block in self.code_blocks:
136
+ if block.language == language:
137
+ return block
138
+
139
+ return None
@@ -0,0 +1,24 @@
1
+ from llm_cgr.analyse.languages.code_data import CodeData
2
+ from llm_cgr.analyse.languages.python import analyse_python_code
3
+
4
+
5
+ def analyse_code(code: str, language: str | None) -> CodeData:
6
+ """
7
+ Analyse code based on the language.
8
+ """
9
+ try:
10
+ if language == "python":
11
+ return analyse_python_code(code=code)
12
+ except Exception as exc:
13
+ return CodeData(
14
+ valid=False,
15
+ error=str(exc),
16
+ )
17
+
18
+ return CodeData()
19
+
20
+
21
+ __all__ = [
22
+ "analyse_code",
23
+ "CodeData",
24
+ ]
@@ -0,0 +1,34 @@
1
+ """Define the CodeData class, to store code analysis data."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Iterable
5
+
6
+
7
+ @dataclass
8
+ class CodeData:
9
+ """
10
+ A class to hold code analysis data.
11
+ """
12
+
13
+ valid: bool | None
14
+ error: str | None
15
+ defined_funcs: list[str]
16
+ called_funcs: list[str]
17
+ packages: list[str]
18
+ imports: list[str]
19
+
20
+ def __init__(
21
+ self,
22
+ valid: bool | None = None,
23
+ error: str | None = None,
24
+ defined_funcs: Iterable | None = None,
25
+ called_funcs: Iterable | None = None,
26
+ packages: Iterable | None = None,
27
+ imports: Iterable | None = None,
28
+ ):
29
+ self.valid = valid
30
+ self.error = error
31
+ self.defined_funcs = sorted(defined_funcs) if defined_funcs else []
32
+ self.called_funcs = sorted(called_funcs) if called_funcs else []
33
+ self.packages = sorted(packages) if packages else []
34
+ self.imports = sorted(imports) if imports else []
@@ -0,0 +1,86 @@
1
+ """Utility functions for Python code analysis."""
2
+
3
+ import ast
4
+ import sys
5
+
6
+ from llm_cgr.analyse.languages.code_data import CodeData
7
+
8
+
9
+ PYTHON_STDLIB = getattr(
10
+ sys, "stdlib_module_names", []
11
+ ) # use this below to determine packages
12
+
13
+
14
+ class PythonAnalyser(ast.NodeVisitor):
15
+ def __init__(self):
16
+ self.defined_funcs: set[str] = set()
17
+ self.called_funcs: set[str] = set()
18
+ self.imports: set[str] = set()
19
+ self.packages: set[str] = set()
20
+
21
+ def visit_FunctionDef(self, node: ast.FunctionDef):
22
+ # save defined functions
23
+ self.defined_funcs.add(node.name)
24
+ self.generic_visit(node)
25
+
26
+ def visit_Call(self, node: ast.Call):
27
+ func = node.func
28
+
29
+ # save `foo()` function calls
30
+ if isinstance(func, ast.Name):
31
+ self.called_funcs.add(func.id)
32
+
33
+ # save `lib.method()` function calls
34
+ elif isinstance(func, ast.Attribute):
35
+ if isinstance(func.value, ast.Name):
36
+ self.called_funcs.add(f"{func.value.id}.{func.attr}")
37
+ else:
38
+ self.called_funcs.add(func.attr)
39
+
40
+ self.generic_visit(node)
41
+
42
+ def visit_Import(self, node: ast.Import):
43
+ # save `import module` imports
44
+ for alias in node.names:
45
+ # save all imports
46
+ self.imports.add(alias.name)
47
+
48
+ # save external packages
49
+ top_level = alias.name.split(".")[0]
50
+ if top_level not in PYTHON_STDLIB:
51
+ self.packages.add(top_level)
52
+
53
+ self.generic_visit(node)
54
+
55
+ def visit_ImportFrom(self, node: ast.ImportFrom):
56
+ # save `from module import thing` imports
57
+ module = node.module or ""
58
+
59
+ # save external packages
60
+ # node.level is 0 for absolute imports, 1+ for relative imports
61
+ if module and module not in PYTHON_STDLIB and node.level == 0:
62
+ self.packages.add(module.split(".")[0])
63
+
64
+ # save all imports
65
+ for alias in node.names:
66
+ full = f"{module}.{alias.name}" if module else alias.name
67
+ self.imports.add(full)
68
+
69
+ self.generic_visit(node)
70
+
71
+
72
+ def analyse_python_code(code: str) -> CodeData:
73
+ """
74
+ Analyse Python code to extract functions and imports.
75
+ """
76
+ tree = ast.parse(code)
77
+ analyser = PythonAnalyser()
78
+ analyser.visit(tree)
79
+ return CodeData(
80
+ valid=True,
81
+ defined_funcs=analyser.defined_funcs,
82
+ called_funcs=analyser.called_funcs,
83
+ # packages lowercase for analysis (names are case-insensitive outside of code)
84
+ packages=[p.lower() for p in analyser.packages],
85
+ imports=analyser.imports,
86
+ )
@@ -0,0 +1,10 @@
1
+ """Regexes used to parse markdown."""
2
+
3
+ import re
4
+
5
+
6
+ # regex to extract code blocks from markdown text
7
+ CODE_BLOCK_REGEX = re.compile(
8
+ pattern=r"\`\`\`(\w*)\n(.*?)(?:\`\`\`|$)",
9
+ flags=re.DOTALL,
10
+ )
llm_cgr/defaults.py ADDED
@@ -0,0 +1,10 @@
1
+ """Collection of default values for the llm_cgr package."""
2
+
3
+ # the default model to be used across tasks
4
+ DEFAULT_MODEL = "gpt-4.1-mini-2025-04-14"
5
+
6
+ # the default language to assume for code blocks if not specified
7
+ DEFAULT_CODEBLOCK_LANGUAGE = "python"
8
+
9
+ # the default max_tokens to be used when prompting models
10
+ DEFAULT_MAX_TOKENS = 2000
llm_cgr/json_utils.py ADDED
@@ -0,0 +1,24 @@
1
+ """Simple utility functions to save and read json files."""
2
+
3
+ import json
4
+
5
+
6
+ def save_json(
7
+ data: dict | list,
8
+ file_path: str,
9
+ ):
10
+ """
11
+ Utility to save python dictionary or list to a json file.
12
+ """
13
+ with open(file_path, mode="w", encoding="utf-8") as f:
14
+ json.dump(obj=data, fp=f, indent=4)
15
+
16
+
17
+ def read_json(
18
+ file_path: str,
19
+ ) -> dict | list:
20
+ """
21
+ Utility to load python dictionary or list from a json file.
22
+ """
23
+ with open(file_path, mode="r", encoding="utf-8") as f:
24
+ return json.load(fp=f)
llm_cgr/py.typed ADDED
File without changes
@@ -0,0 +1,18 @@
1
+ from llm_cgr.query.api_utils import get_client, query_list, quick_generate
2
+ from llm_cgr.query.generate import (
3
+ AnthropicGenerationAPI,
4
+ OpenAIGenerationAPI,
5
+ TogetherGenerationAPI,
6
+ )
7
+ from llm_cgr.query.protocol import GenerationProtocol
8
+
9
+
10
+ __all__ = [
11
+ "get_client",
12
+ "query_list",
13
+ "quick_generate",
14
+ "AnthropicGenerationAPI",
15
+ "OpenAIGenerationAPI",
16
+ "TogetherGenerationAPI",
17
+ "GenerationProtocol",
18
+ ]
@@ -0,0 +1,99 @@
1
+ """API utilities for interfacing with the generation models."""
2
+
3
+ from typing import Literal
4
+
5
+ from llm_cgr.defaults import DEFAULT_MODEL
6
+ from llm_cgr.query.generate import (
7
+ AnthropicGenerationAPI,
8
+ OpenAIGenerationAPI,
9
+ TogetherGenerationAPI,
10
+ )
11
+ from llm_cgr.query.prompts import (
12
+ BASE_SYSTEM_PROMPT,
13
+ CODE_SYSTEM_PROMPT,
14
+ LIST_SYSTEM_PROMPT,
15
+ )
16
+ from llm_cgr.query.protocol import GenerationProtocol
17
+
18
+
19
+ def get_client(
20
+ model: str,
21
+ type: Literal["base", "code", "list"] | None = None,
22
+ ) -> GenerationProtocol:
23
+ """
24
+ Initialise the correct generation interface for the given model.
25
+ """
26
+ _system = None
27
+ match type:
28
+ case "base":
29
+ _system = BASE_SYSTEM_PROMPT
30
+ case "code":
31
+ _system = CODE_SYSTEM_PROMPT
32
+ case "list":
33
+ _system = LIST_SYSTEM_PROMPT
34
+
35
+ if "claude" in model:
36
+ return AnthropicGenerationAPI(model=model, system=_system)
37
+
38
+ if "gpt" in model or "o1" in model:
39
+ return OpenAIGenerationAPI(model=model, system=_system)
40
+
41
+ return TogetherGenerationAPI(model=model, system=_system)
42
+
43
+
44
+ def quick_generate(
45
+ user: str,
46
+ type: Literal["base", "code", "list"] | None = None,
47
+ model: str = DEFAULT_MODEL,
48
+ system: str | None = None,
49
+ temperature: float | None = None,
50
+ ) -> str:
51
+ """
52
+ Simple function to quickly prompt a model for a response.
53
+ """
54
+ client = get_client(model=model, type=type)
55
+
56
+ [result] = client.generate(
57
+ user=user,
58
+ system=system,
59
+ temperature=temperature,
60
+ )
61
+ return result
62
+
63
+
64
+ def query_list(
65
+ user: str,
66
+ system: str = LIST_SYSTEM_PROMPT,
67
+ model: str = DEFAULT_MODEL,
68
+ ) -> list[str]:
69
+ """
70
+ Simple function to quickly prompt a model for a list of words.
71
+ """
72
+ _response = quick_generate(
73
+ user=user,
74
+ system=system,
75
+ model=model,
76
+ )
77
+
78
+ # sometimes the LLM will return a code block with the list inside it
79
+ if _response.startswith("```python"):
80
+ _response = _response.split("```python")[1]
81
+ if _response.endswith("```"):
82
+ _response = _response.split("```")[0]
83
+ _response = _response.strip()
84
+
85
+ try:
86
+ _list = eval(_response)
87
+ except Exception as e:
88
+ print(f"Error evaluating response.\nresponse: {_response}\nexception: {e}")
89
+ _list = []
90
+
91
+ if not isinstance(_list, list):
92
+ print(f"Error querying list. Response is not a list: {_list}")
93
+ _list = []
94
+
95
+ if any(not isinstance(item, str) for item in _list):
96
+ print(f"Error querying list. Response contains non-string items: {_list}")
97
+ _list = []
98
+
99
+ return _list
@@ -0,0 +1,149 @@
1
+ """Classes for access to generation APIs of LLM services."""
2
+
3
+ import anthropic
4
+ import openai
5
+ import together
6
+
7
+ from llm_cgr.defaults import DEFAULT_MAX_TOKENS
8
+
9
+
10
+ class OpenAIGenerationAPI:
11
+ """
12
+ Class to access the OpenAI API.
13
+ """
14
+
15
+ def __init__(
16
+ self,
17
+ model: str | None = None,
18
+ system: str | None = None,
19
+ ) -> None:
20
+ self._model = model
21
+ self._system = system or openai.NOT_GIVEN
22
+ self._client = openai.OpenAI()
23
+
24
+ def generate(
25
+ self,
26
+ user: str,
27
+ system: str | None = None,
28
+ model: str | None = None,
29
+ samples: int = 1,
30
+ temperature: float | None = None,
31
+ max_tokens: int | None = None,
32
+ ) -> list[str]:
33
+ """
34
+ Generate a model response from the OpenAI API.
35
+
36
+ Returns
37
+ -------
38
+ The text response to the prompt.
39
+ """
40
+ _generations = []
41
+ for _ in range(samples):
42
+ response = self._client.responses.create(
43
+ input=user,
44
+ model=model or self._model,
45
+ instructions=system or self._system,
46
+ temperature=temperature or openai.NOT_GIVEN,
47
+ max_output_tokens=max_tokens or openai.NOT_GIVEN,
48
+ )
49
+ _generations.append(response.output_text)
50
+
51
+ return _generations
52
+
53
+
54
+ class TogetherGenerationAPI:
55
+ """
56
+ Class to access the TogetherAI API.
57
+ """
58
+
59
+ def __init__(
60
+ self,
61
+ model: str | None = None,
62
+ system: str | None = None,
63
+ ) -> None:
64
+ self._model = model
65
+ self._system = system
66
+ self._client = together.Together()
67
+
68
+ def generate(
69
+ self,
70
+ user: str,
71
+ system: str | None = None,
72
+ model: str | None = None,
73
+ samples: int = 1,
74
+ temperature: float | None = None,
75
+ max_tokens: int | None = None,
76
+ ) -> list[str]:
77
+ """
78
+ Generate a model response from the TogetherAI API.
79
+
80
+ Returns
81
+ -------
82
+ The text response to the prompt.
83
+ """
84
+ _input = [{"role": "user", "content": user}]
85
+ _system = system or self._system
86
+ if _system:
87
+ _input = [{"role": "system", "content": _system}] + _input
88
+
89
+ _generations = []
90
+ for _ in range(samples):
91
+ response = self._client.chat.completions.create(
92
+ model=model or self._model,
93
+ messages=_input,
94
+ temperature=temperature,
95
+ max_tokens=max_tokens,
96
+ )
97
+ _generations.append(response.choices[0].message.content)
98
+
99
+ return _generations
100
+
101
+
102
+ class AnthropicGenerationAPI:
103
+ """
104
+ Class to access the Anthropic Claude API.
105
+ """
106
+
107
+ def __init__(self, model: str | None = None, system: str | None = None) -> None:
108
+ self._model = model
109
+ self._system = system or anthropic.NOT_GIVEN
110
+ self._client = anthropic.Anthropic()
111
+
112
+ def generate(
113
+ self,
114
+ user: str,
115
+ system: str | None = None,
116
+ model: str | None = None,
117
+ samples: int = 1,
118
+ temperature: float | None = None,
119
+ max_tokens: int | None = None,
120
+ ) -> list[str]:
121
+ """
122
+ Generate a model response from the Anthropic Claude API.
123
+
124
+ Returns
125
+ -------
126
+ The text response to the prompt.
127
+ """
128
+ _generations = []
129
+ for _ in range(samples):
130
+ response = self._client.messages.create(
131
+ model=model or self._model,
132
+ system=system or self._system,
133
+ messages=[
134
+ {
135
+ "role": "user",
136
+ "content": [
137
+ {
138
+ "type": "text",
139
+ "text": user,
140
+ },
141
+ ],
142
+ },
143
+ ],
144
+ temperature=temperature or anthropic.NOT_GIVEN,
145
+ max_tokens=max_tokens or DEFAULT_MAX_TOKENS,
146
+ )
147
+ _generations.append(response.content[0].text)
148
+
149
+ return _generations
@@ -0,0 +1,13 @@
1
+ """All prompts used in the project are defined here."""
2
+
3
+ # the default system prompt to be used across tasks
4
+ BASE_SYSTEM_PROMPT = "You are a helpful assistant."
5
+
6
+ # the default system prompt to be used across coding tasks
7
+ CODE_SYSTEM_PROMPT = "You are a helpful and knowledgeable code assistant!"
8
+
9
+ # the system prompt to be used for generating lists of words
10
+ LIST_SYSTEM_PROMPT = (
11
+ "You are a helpful assistant that provides lists of words.\n"
12
+ "You only respond in correctly formatted python lists, containing only strings."
13
+ )
@@ -0,0 +1,20 @@
1
+ """Protocol for the completion API of an LLM service."""
2
+
3
+ from typing import Protocol
4
+
5
+
6
+ class GenerationProtocol(Protocol):
7
+ """
8
+ Protocol that describes how to access the generation API of an LLM service.
9
+ """
10
+
11
+ def generate(
12
+ self,
13
+ user: str,
14
+ system: str | None = None,
15
+ model: str | None = None,
16
+ samples: int = 1,
17
+ temperature: float | None = None,
18
+ max_tokens: int | None = None,
19
+ ) -> list[str]:
20
+ pass
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: llm-codegen-research
3
+ Version: 1.2
4
+ Summary: Utilities for use when research code-generation by LLMs.
5
+ Author-email: Lukas Twist <itsluketwist@gmail.com>
6
+ Project-URL: Homepage, https://github.com/itsluketwist/llm-codegen-research
7
+ Keywords: llm,code-generation,research,prompting,nlp
8
+ Classifier: Programming Language :: Python
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: anthropic>=0.49.0
14
+ Requires-Dist: openai>=1.78.1
15
+ Requires-Dist: together>=1.5.8
16
+ Dynamic: license-file
17
+
18
+ # **llm-codegen-research**
19
+
20
+
21
+ ![lint code workflow](https://github.com/itsluketwist/llm-codegen-research/actions/workflows/lint.yaml/badge.svg)
22
+ ![test code workflow](https://github.com/itsluketwist/llm-codegen-research/actions/workflows/test.yaml/badge.svg)
23
+ ![release workflow](https://github.com/itsluketwist/llm-codegen-research/actions/workflows/release.yaml/badge.svg)
24
+
25
+
26
+ <div>
27
+ <!-- badges from : https://shields.io/ -->
28
+ <!-- logos available : https://simpleicons.org/ -->
29
+ <a href="https://opensource.org/licenses/MIT">
30
+ <img alt="MIT License" src="https://img.shields.io/badge/Licence-MIT-yellow?style=for-the-badge&logo=docs&logoColor=white" />
31
+ </a>
32
+ <a href="https://www.python.org/">
33
+ <img alt="Python 3" src="https://img.shields.io/badge/Python_3-blue?style=for-the-badge&logo=python&logoColor=white" />
34
+ </a>
35
+ <a href="https://openai.com/blog/openai-api/">
36
+ <img alt="OpenAI API" src="https://img.shields.io/badge/OpenAI_API-412991?style=for-the-badge&logo=openai&logoColor=white" />
37
+ </a>
38
+ <a href="https://www.anthropic.com/api/">
39
+ <img alt="Anthropic API" src="https://img.shields.io/badge/Claude_API-D97757?style=for-the-badge&logo=claude&logoColor=white" />
40
+ </a>
41
+ <a href="https://api.together.ai/">
42
+ <img alt="together.ai API" src="https://img.shields.io/badge/together.ai_API-B5B5B5?style=for-the-badge&logoColor=white" />
43
+ </a>
44
+ </div>
45
+
46
+
47
+ ## *usage*
48
+
49
+ A collection of methods and classes I repeatedly use when conducting research on LLM code-generation.
50
+ Covers both prompting various LLMs, and analysing the markdown responses.
51
+
52
+ ```python
53
+ from llm_cgr import quick_complete, Markdown
54
+
55
+ response = quick_complete("Write python code to generate the nth fibonacci number.")
56
+
57
+ markdown = Markdown(text=response)
58
+ ```
59
+
60
+ ## *installation*
61
+
62
+ Install directly from PyPI, using pip:
63
+
64
+ ```shell
65
+ pip install llm-codegen-research
66
+ ```
67
+
68
+ ## *development*
69
+
70
+ Clone the repository code:
71
+
72
+ ```shell
73
+ git clone https://github.com/itsluketwist/llm-codegen-research.git
74
+ ```
75
+
76
+ We use [`uv`](https://astral.sh/blog/uv) for project management.
77
+ Once cloned, create a virtual environment and install uv and the project:
78
+
79
+ ```shell
80
+ python -m venv .venv
81
+
82
+ . .venv/bin/activate
83
+
84
+ pip install uv
85
+
86
+ uv sync
87
+ ```
88
+
89
+ Use `make` commands to lint and test:
90
+
91
+ ```shell
92
+ make lint
93
+
94
+ make test
95
+ ```
96
+
97
+ Use `uv` to add new dependencies into the project and `uv.lock`:
98
+
99
+ ```shell
100
+ uv add openai
101
+ ```
@@ -0,0 +1,20 @@
1
+ llm_cgr/__init__.py,sha256=hYIlrI6t9RKPAiH5gFgPt-Zzb7l-tj89DXOsnk1kq_U,429
2
+ llm_cgr/defaults.py,sha256=kBZ5iPeeWj_W9RBag0TK_04V2izb34Hj5kNmc2PTj0E,337
3
+ llm_cgr/json_utils.py,sha256=F243E1GpcVzKcYhd9SGQp2V--HCFhwBffajgBj627ng,542
4
+ llm_cgr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ llm_cgr/analyse/__init__.py,sha256=0f_-UkAsjyFqVjm6IKLbx1P5Wrs-iGJUZG4sX2IxEGY,202
6
+ llm_cgr/analyse/classes.py,sha256=Wm9wGYW_CaQ91bqnbZrKLfHbJizlv7mC6WsJXdxA2Fg,4315
7
+ llm_cgr/analyse/regexes.py,sha256=8hZWHE7ov52CfEIoNfBIibxoUZ-zVitbUf1GmjJw6mE,202
8
+ llm_cgr/analyse/languages/__init__.py,sha256=FehFCQfZCEzkrkQ8icyEID60f9ieoZZ32UTYDof7sO8,527
9
+ llm_cgr/analyse/languages/code_data.py,sha256=vse_m1NbXjWQyFcp7f_pO6QxNWXbUrgkTUmupaealeI,967
10
+ llm_cgr/analyse/languages/python.py,sha256=7bwuK419t_FQNNfa0FIE1OZCeLyJZW3w-J3wXrvubg8,2630
11
+ llm_cgr/query/__init__.py,sha256=V7vRvkUK9ecmn41FkVeAw_vAugbHV7hrMYZJKyIsj0A,434
12
+ llm_cgr/query/api_utils.py,sha256=bfmRoN6T4RnPZN0rvEQxuu6Eiy2R-3aLDhP6cJSwI9k,2628
13
+ llm_cgr/query/generate.py,sha256=mzHaGB4E9Ru_p4VW5IvuPGxqDSWLmRomkS1iI5XZrCA,4117
14
+ llm_cgr/query/prompts.py,sha256=4aHFs6XA4hxZoj7O_RBcJ5bZpT7YA__DiNLGJSn29nQ,534
15
+ llm_cgr/query/protocol.py,sha256=tI3CBLvuLmAOdOKYbMv_eIBTaQS5ar1BuJJ0Fd2cnTg,481
16
+ llm_codegen_research-1.2.dist-info/licenses/LICENSE,sha256=ywssDcJhpfEdT6kAZ2cLvnn79hg5D68z2Q6wfuiMkIo,1067
17
+ llm_codegen_research-1.2.dist-info/METADATA,sha256=lHT-5lDYr5NVjZPG5dJb1vmSpcgJ6pKEgtdJ9ZeEVE4,3024
18
+ llm_codegen_research-1.2.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
19
+ llm_codegen_research-1.2.dist-info/top_level.txt,sha256=ChJIktBUMP5vmX7WvEds2GZPE1zo0Fzmf4FqzH639iY,8
20
+ llm_codegen_research-1.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.7.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Luke Twist
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ llm_cgr