gpt-pr 0.4.1__py3-none-any.whl → 0.5.0__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.
- {gpt_pr-0.4.1.dist-info → gpt_pr-0.5.0.dist-info}/METADATA +4 -4
- {gpt_pr-0.4.1.dist-info → gpt_pr-0.5.0.dist-info}/RECORD +9 -9
- gptpr/config.py +6 -3
- gptpr/prdata.py +49 -32
- gptpr/test_config.py +21 -4
- gptpr/version.py +1 -1
- {gpt_pr-0.4.1.dist-info → gpt_pr-0.5.0.dist-info}/WHEEL +0 -0
- {gpt_pr-0.4.1.dist-info → gpt_pr-0.5.0.dist-info}/entry_points.txt +0 -0
- {gpt_pr-0.4.1.dist-info → gpt_pr-0.5.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: gpt-pr
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Automate your GitHub workflow with GPT-PR: an OpenAI powered library for streamlined PR generation.
|
|
5
5
|
Home-page: http://github.com/alissonperez/gpt-pr
|
|
6
6
|
Author: Alisson R. Perez
|
|
@@ -8,20 +8,20 @@ Author-email: alissonperez@outlook.com
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Requires-Python: >=3.7
|
|
10
10
|
Requires-Dist: cffi ==1.15.1
|
|
11
|
-
Requires-Dist: cryptography ==
|
|
11
|
+
Requires-Dist: cryptography ==43.0.0
|
|
12
12
|
Requires-Dist: fire ==0.6.0
|
|
13
13
|
Requires-Dist: pycparser ==2.21
|
|
14
14
|
Requires-Dist: wcwidth ==0.2.13
|
|
15
15
|
Requires-Dist: charset-normalizer ==3.3.2 ; python_full_version >= "3.7.0"
|
|
16
16
|
Requires-Dist: prompt-toolkit ==3.0.43 ; python_full_version >= "3.7.0"
|
|
17
17
|
Requires-Dist: openai ==1.14.0 ; python_full_version >= "3.7.1"
|
|
18
|
-
Requires-Dist: exceptiongroup ==1.2.
|
|
18
|
+
Requires-Dist: exceptiongroup ==1.2.2 ; python_version < "3.11"
|
|
19
19
|
Requires-Dist: cached-property ==1.5.2 ; python_version < "3.8"
|
|
20
20
|
Requires-Dist: importlib-metadata ==6.7.0 ; python_version == "3.7"
|
|
21
21
|
Requires-Dist: six ==1.16.0 ; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2"
|
|
22
22
|
Requires-Dist: deprecated ==1.2.14 ; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3"
|
|
23
23
|
Requires-Dist: idna ==3.7 ; python_version >= "3.5"
|
|
24
|
-
Requires-Dist: certifi ==2024.
|
|
24
|
+
Requires-Dist: certifi ==2024.7.4 ; python_version >= "3.6"
|
|
25
25
|
Requires-Dist: distro ==1.9.0 ; python_version >= "3.6"
|
|
26
26
|
Requires-Dist: pynacl ==1.5.0 ; python_version >= "3.6"
|
|
27
27
|
Requires-Dist: wrapt ==1.16.0 ; python_version >= "3.6"
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
gptpr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
gptpr/checkversion.py,sha256=PmbGiYJelecs1Fv2aAZwdr6wn-qDC826nsYI4A6LLvk,2389
|
|
3
|
-
gptpr/config.py,sha256=
|
|
3
|
+
gptpr/config.py,sha256=XwHwveyVmeFoHqHpwZXI2BF1Ac3nT1hnEpclmP2TYhQ,2677
|
|
4
4
|
gptpr/consolecolor.py,sha256=_JmBMNjIflWMlgP2VkCWu6uQLR9oHBy52uV3TRJJgF4,800
|
|
5
5
|
gptpr/gh.py,sha256=uSWY_TzbrAM00neOBkyfV5vxDO4FzMtIrs-Zczp-Tck,1127
|
|
6
6
|
gptpr/gitutil.py,sha256=NBD3iRnbFEPRU47w7c5TowwtZieDYkU4zybvv0PoOU0,5783
|
|
7
7
|
gptpr/main.py,sha256=gen_8YXYAUJU0BpzULZ28j9Br6Y9PTqTr9JEm4nwsJI,2694
|
|
8
|
-
gptpr/prdata.py,sha256=
|
|
8
|
+
gptpr/prdata.py,sha256=h3RvlfGcAXWUSxy6wfVqem4uxk53gxpvSrmj7xxuYUc,6749
|
|
9
9
|
gptpr/test_checkversion.py,sha256=WtJ3v4MMkFG0Kob0R1wi_nwVhcQFd4mXtKCKZHajEhM,4266
|
|
10
|
-
gptpr/test_config.py,sha256=
|
|
10
|
+
gptpr/test_config.py,sha256=ucqbj2mbee4fDK1JwXVY_FfnPXMeRA3VMM6m4-x7OTU,3270
|
|
11
11
|
gptpr/test_prdata.py,sha256=rSJ-yqOdw-iYdBWyqnA2SXbdrhT8KgIkRTTf9SY1S1g,474
|
|
12
|
-
gptpr/version.py,sha256=
|
|
13
|
-
gpt_pr-0.
|
|
14
|
-
gpt_pr-0.
|
|
15
|
-
gpt_pr-0.
|
|
16
|
-
gpt_pr-0.
|
|
17
|
-
gpt_pr-0.
|
|
12
|
+
gptpr/version.py,sha256=LBK46heutvn3KmsCrKIYu8RQikbfnjZaj2xFrXaeCzQ,22
|
|
13
|
+
gpt_pr-0.5.0.dist-info/METADATA,sha256=Dt_i-Of-R8hHlBDFWGm2rzWij5diWPVE6cT2FKeXd1k,2638
|
|
14
|
+
gpt_pr-0.5.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
15
|
+
gpt_pr-0.5.0.dist-info/entry_points.txt,sha256=WhcbcQXqo5-IGliYWiYMhop4-Wm7bcH2ljFKLWrmO7c,81
|
|
16
|
+
gpt_pr-0.5.0.dist-info/top_level.txt,sha256=DZcbzlsjh4BD8njGcvhOeCZ83U_oYWgCn0w8qx5--04,6
|
|
17
|
+
gpt_pr-0.5.0.dist-info/RECORD,,
|
gptpr/config.py
CHANGED
|
@@ -7,7 +7,7 @@ def config_command_example(name, value_sample):
|
|
|
7
7
|
return f'gpt-pr-config set {name} {value_sample}'
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
CONFIG_README_SECTION = 'https://github.com/alissonperez/gpt-pr?tab=readme-ov-file#
|
|
10
|
+
CONFIG_README_SECTION = 'https://github.com/alissonperez/gpt-pr?tab=readme-ov-file#configuration'
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Config:
|
|
@@ -18,8 +18,11 @@ class Config:
|
|
|
18
18
|
# Github
|
|
19
19
|
'GH_TOKEN': '',
|
|
20
20
|
|
|
21
|
+
# LLM input MAX Tokens
|
|
22
|
+
'INPUT_MAX_TOKENS': '15000',
|
|
23
|
+
|
|
21
24
|
# Open AI info
|
|
22
|
-
'OPENAI_MODEL': 'gpt-4o',
|
|
25
|
+
'OPENAI_MODEL': 'gpt-4o-mini',
|
|
23
26
|
'OPENAI_API_KEY': '',
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -66,7 +69,7 @@ class Config:
|
|
|
66
69
|
|
|
67
70
|
def set_user_config(self, name, value):
|
|
68
71
|
self.load()
|
|
69
|
-
self._config['user'][name] = value
|
|
72
|
+
self._config['user'][name] = str(value)
|
|
70
73
|
|
|
71
74
|
def reset_user_config(self, name):
|
|
72
75
|
self.load()
|
gptpr/prdata.py
CHANGED
|
@@ -8,7 +8,6 @@ from gptpr.config import config
|
|
|
8
8
|
import gptpr.consolecolor as cc
|
|
9
9
|
|
|
10
10
|
TOKENIZER_RATIO = 4
|
|
11
|
-
MAX_TOKENS = 6000
|
|
12
11
|
|
|
13
12
|
DEFAULT_PR_TEMPLATE = ('### Ref. [Link]\n\n## What was done?\n[Fill here]\n\n'
|
|
14
13
|
'## How was it done?\n[Fill here]\n\n'
|
|
@@ -52,6 +51,10 @@ def _get_open_ai_key():
|
|
|
52
51
|
return api_key
|
|
53
52
|
|
|
54
53
|
|
|
54
|
+
def _count_tokens(text):
|
|
55
|
+
return len(text.split(' '))
|
|
56
|
+
|
|
57
|
+
|
|
55
58
|
@dataclass
|
|
56
59
|
class PrData():
|
|
57
60
|
branch_info: BranchInfo
|
|
@@ -91,6 +94,35 @@ functions = [
|
|
|
91
94
|
|
|
92
95
|
|
|
93
96
|
def get_pr_data(branch_info):
|
|
97
|
+
client = OpenAI(api_key=_get_open_ai_key())
|
|
98
|
+
|
|
99
|
+
messages = _get_messages(branch_info)
|
|
100
|
+
|
|
101
|
+
openai_model = config.get_user_config('OPENAI_MODEL')
|
|
102
|
+
print('Using OpenAI model:', cc.yellow(openai_model))
|
|
103
|
+
|
|
104
|
+
chat_completion = client.chat.completions.create(
|
|
105
|
+
messages=messages,
|
|
106
|
+
model=openai_model,
|
|
107
|
+
functions=functions,
|
|
108
|
+
function_call={'name': 'create_pr'},
|
|
109
|
+
temperature=0,
|
|
110
|
+
max_tokens=1000,
|
|
111
|
+
top_p=1,
|
|
112
|
+
frequency_penalty=0,
|
|
113
|
+
presence_penalty=0
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
arguments = _parse_json(chat_completion.choices[0].message.function_call.arguments)
|
|
117
|
+
|
|
118
|
+
return PrData(
|
|
119
|
+
branch_info=branch_info,
|
|
120
|
+
title=arguments['title'],
|
|
121
|
+
body=arguments['description']
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _get_messages(branch_info):
|
|
94
126
|
system_content = ('You are a development assistant designed to craft Git pull requests '
|
|
95
127
|
'by incorporating information from main and secondary commits, diff changes, '
|
|
96
128
|
'and adhering to a provided PR template. Your output includes a complete PR '
|
|
@@ -108,45 +140,30 @@ def get_pr_data(branch_info):
|
|
|
108
140
|
messages.append({'role': 'user', 'content': 'main commits: ' + '\n'.join(branch_info.highlight_commits)})
|
|
109
141
|
messages.append({'role': 'user', 'content': 'secondary commits: ' + '\n'.join(branch_info.commits)})
|
|
110
142
|
else:
|
|
111
|
-
messages.append({'role': 'user', 'content': 'git commits: ' + '\n'.join(branch_info.commits)})
|
|
143
|
+
messages.append({'role': 'user', 'content': 'git commits: \n' + '\n'.join(branch_info.commits)})
|
|
112
144
|
|
|
113
145
|
messages.append({'role': 'user', 'content': 'PR template:\n' + _get_pr_template()})
|
|
114
146
|
|
|
115
|
-
|
|
147
|
+
joined_messages = '\n'.join([m['content'] for m in messages])
|
|
148
|
+
current_total_tokens = _count_tokens(joined_messages)
|
|
116
149
|
|
|
117
|
-
|
|
118
|
-
raise Exception(f'Current total length {current_total_length} is greater than max tokens {MAX_TOKENS}')
|
|
150
|
+
input_max_tokens = int(config.get_user_config('INPUT_MAX_TOKENS'))
|
|
119
151
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
152
|
+
if current_total_tokens > input_max_tokens:
|
|
153
|
+
exp_message = (f'Length of {current_total_tokens} tokens for basic prompt '
|
|
154
|
+
f'(description and commits) is greater than max tokens {input_max_tokens} '
|
|
155
|
+
'(config \'input_max_tokens\')')
|
|
156
|
+
raise Exception(exp_message)
|
|
157
|
+
|
|
158
|
+
total_tokens_with_diff = current_total_tokens + _count_tokens(branch_info.diff)
|
|
159
|
+
if total_tokens_with_diff > input_max_tokens:
|
|
160
|
+
print_msg = (f'Length git changes with diff is too big (total is {total_tokens_with_diff}, '
|
|
161
|
+
f'\'input_max_tokens\' config is {input_max_tokens}).')
|
|
162
|
+
print(print_msg, cc.red('Skipping changes diff content...'))
|
|
123
163
|
else:
|
|
124
164
|
messages.append({'role': 'user', 'content': 'Diff changes:\n' + branch_info.diff})
|
|
125
165
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
openai_model = config.get_user_config('OPENAI_MODEL')
|
|
129
|
-
print('Using OpenAI model:', cc.yellow(openai_model))
|
|
130
|
-
|
|
131
|
-
chat_completion = client.chat.completions.create(
|
|
132
|
-
messages=messages,
|
|
133
|
-
model=openai_model,
|
|
134
|
-
functions=functions,
|
|
135
|
-
function_call={'name': 'create_pr'},
|
|
136
|
-
temperature=0,
|
|
137
|
-
max_tokens=512,
|
|
138
|
-
top_p=1,
|
|
139
|
-
frequency_penalty=0,
|
|
140
|
-
presence_penalty=0
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
arguments = _parse_json(chat_completion.choices[0].message.function_call.arguments)
|
|
144
|
-
|
|
145
|
-
return PrData(
|
|
146
|
-
branch_info=branch_info,
|
|
147
|
-
title=arguments['title'],
|
|
148
|
-
body=arguments['description']
|
|
149
|
-
)
|
|
166
|
+
return messages
|
|
150
167
|
|
|
151
168
|
|
|
152
169
|
def _parse_json(content):
|
gptpr/test_config.py
CHANGED
|
@@ -30,7 +30,7 @@ def test_init_config_file(temp_config):
|
|
|
30
30
|
assert os.path.isfile(os.path.join(str(temp_dir), config.config_filename))
|
|
31
31
|
|
|
32
32
|
_check_config(config, temp_dir, [
|
|
33
|
-
('DEFAULT', 'OPENAI_MODEL', 'gpt-4o'),
|
|
33
|
+
('DEFAULT', 'OPENAI_MODEL', 'gpt-4o-mini'),
|
|
34
34
|
('DEFAULT', 'OPENAI_API_KEY', ''),
|
|
35
35
|
])
|
|
36
36
|
|
|
@@ -66,6 +66,21 @@ def test_set_user_config(temp_config):
|
|
|
66
66
|
])
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
def test_set_user_config_with_int_value(temp_config):
|
|
70
|
+
config, temp_dir = temp_config
|
|
71
|
+
|
|
72
|
+
config.set_user_config('INPUT_MAX_TOKENS', 100)
|
|
73
|
+
config.persist()
|
|
74
|
+
|
|
75
|
+
# Read the configuration file and verify its contents
|
|
76
|
+
config_to_test = configparser.ConfigParser()
|
|
77
|
+
config_to_test.read(os.path.join(str(temp_dir), config.config_filename))
|
|
78
|
+
|
|
79
|
+
_check_config(config, temp_dir, [
|
|
80
|
+
('user', 'INPUT_MAX_TOKENS', '100'),
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
|
|
69
84
|
def test_all_values(temp_config):
|
|
70
85
|
config, temp_dir = temp_config
|
|
71
86
|
|
|
@@ -73,10 +88,12 @@ def test_all_values(temp_config):
|
|
|
73
88
|
|
|
74
89
|
assert all_values == [
|
|
75
90
|
('DEFAULT', 'gh_token', ''),
|
|
76
|
-
('DEFAULT', '
|
|
91
|
+
('DEFAULT', 'input_max_tokens', '15000'),
|
|
92
|
+
('DEFAULT', 'openai_model', 'gpt-4o-mini'),
|
|
77
93
|
('DEFAULT', 'openai_api_key', ''),
|
|
78
94
|
('user', 'gh_token', ''),
|
|
79
|
-
('user', '
|
|
95
|
+
('user', 'input_max_tokens', '15000'),
|
|
96
|
+
('user', 'openai_model', 'gpt-4o-mini'),
|
|
80
97
|
('user', 'openai_api_key', ''),
|
|
81
98
|
]
|
|
82
99
|
|
|
@@ -94,6 +111,6 @@ def test_reset_user_config(temp_config):
|
|
|
94
111
|
config_to_test.read(os.path.join(str(temp_dir), config.config_filename))
|
|
95
112
|
|
|
96
113
|
_check_config(config, temp_dir, [
|
|
97
|
-
('user', 'OPENAI_MODEL', 'gpt-4o'),
|
|
114
|
+
('user', 'OPENAI_MODEL', 'gpt-4o-mini'),
|
|
98
115
|
('user', 'OPENAI_API_KEY', ''),
|
|
99
116
|
])
|
gptpr/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.5.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|