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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gpt-pr
3
- Version: 0.4.1
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 ==42.0.7
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.1 ; python_version < "3.11"
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.2.2 ; python_version >= "3.6"
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=YVQgTuJYVwqAabqK-E3xSzlc4QUvZb0q4dUW-_pY2cg,2609
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=ejx4zLRViJ83OmqvlxGWnw7alo8RPL_YdlwEJFhMQ8g,6183
8
+ gptpr/prdata.py,sha256=h3RvlfGcAXWUSxy6wfVqem4uxk53gxpvSrmj7xxuYUc,6749
9
9
  gptpr/test_checkversion.py,sha256=WtJ3v4MMkFG0Kob0R1wi_nwVhcQFd4mXtKCKZHajEhM,4266
10
- gptpr/test_config.py,sha256=_vP-3RJf8WXGGQESr5bCUbmxf8owc1uVJXMSBF_MtH0,2712
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=pMtTmSUht-XtbR_7Doz6bsQqopJJd8rZ8I8zy2HwwoA,22
13
- gpt_pr-0.4.1.dist-info/METADATA,sha256=xcj4KIGRUS5pFaXrVe7AM5YOfy7dm9JA8VE-IVVwsHI,2638
14
- gpt_pr-0.4.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
15
- gpt_pr-0.4.1.dist-info/entry_points.txt,sha256=WhcbcQXqo5-IGliYWiYMhop4-Wm7bcH2ljFKLWrmO7c,81
16
- gpt_pr-0.4.1.dist-info/top_level.txt,sha256=DZcbzlsjh4BD8njGcvhOeCZ83U_oYWgCn0w8qx5--04,6
17
- gpt_pr-0.4.1.dist-info/RECORD,,
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#authentication--api-keys'
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
- current_total_length = sum([len(m['content']) for m in messages])
147
+ joined_messages = '\n'.join([m['content'] for m in messages])
148
+ current_total_tokens = _count_tokens(joined_messages)
116
149
 
117
- if current_total_length / TOKENIZER_RATIO > MAX_TOKENS:
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
- total_length_with_diff = current_total_length + len(branch_info.diff)
121
- if total_length_with_diff / TOKENIZER_RATIO > MAX_TOKENS:
122
- print('Total content length (with diff) is too big.', cc.red('Skipping diff content...'))
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
- client = OpenAI(api_key=_get_open_ai_key())
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', 'openai_model', 'gpt-4o'),
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', 'openai_model', 'gpt-4o'),
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.4.1"
1
+ __version__ = "0.5.0"
File without changes