11import time
22import requests
3+ import tiktoken
34from commitgen .config import load_api_key , load_prompt_template
45
56
67# --- constants
7- LLM_MODEL = 'gpt-4o-mini'
8+ MODEL_PRICING = {
9+ "gpt-4" : {"prompt" : 0.03 , "completion" : 0.06 },
10+ "gpt-4.0" : {"prompt" : 0.03 , "completion" : 0.06 },
11+ "gpt-4.1" : {"prompt" : 0.03 , "completion" : 0.06 },
12+ "gpt-3.5-turbo" : {"prompt" : 0.0015 , "completion" : 0.002 },
13+ }
14+
15+ LLM_MODEL = 'gpt-4.1'
816OpenAI_API = load_api_key ()
917
1018MAX_RETRIES = 5
1725
1826
1927# --- utils
28+ def count_tokens (messages , model = "gpt-4" ):
29+ """Estimate number of tokens used in messages for a chat completion."""
30+ try :
31+ encoding = tiktoken .encoding_for_model (model )
32+ except KeyError :
33+ encoding = tiktoken .get_encoding ("cl100k_base" ) # fallback
34+
35+ num_tokens = 0
36+ for message in messages :
37+ num_tokens += 4 # role, name overhead
38+ for key , value in message .items ():
39+ num_tokens += len (encoding .encode (value ))
40+ num_tokens += 2 # reply priming
41+ return num_tokens
42+
43+
2044def get_openai_api_result (
2145 system_prompt = '' ,
2246 user_prompt = '' ,
2347 llm_model = LLM_MODEL ,
2448 headers = HEADERS ,
2549 max_retries = MAX_RETRIES ,
2650 retry_delay = RETRY_DELAY ,
27- ):
51+ return_usage = True
52+ ):
53+
54+ messages = [
55+ {"role" : "system" , "content" : system_prompt },
56+ {"role" : "user" , "content" : user_prompt }
57+ ]
2858
2959 payload = {
3060 "model" : llm_model ,
31- "messages" : [
32- {
33- "role" : "system" ,
34- "content" : system_prompt
35- },
36- {
37- "role" : "user" ,
38- "content" : user_prompt
39- }
40- ],
61+ "messages" : messages ,
4162 "max_tokens" : 4096 ,
4263 "temperature" : 0 ,
43- "top_p" : .7 ,
64+ "top_p" : 0 .7 ,
4465 }
4566
67+ # retry loop
4668 for attempt in range (max_retries ):
4769 response = requests .post (
4870 "https://api.openai.com/v1/chat/completions" ,
@@ -51,16 +73,36 @@ def get_openai_api_result(
5173 )
5274
5375 if response .status_code == 200 :
54- result = response .json ()
55- content = result ['choices' ][0 ]['message' ]['content' ]
56- break
76+ result = response .json ()
77+ content = result ['choices' ][0 ]['message' ]['content' ]
78+ usage = result .get ("usage" , {})
79+ prompt_tokens = usage .get ("prompt_tokens" , 0 )
80+ completion_tokens = usage .get ("completion_tokens" , 0 )
81+ total_tokens = usage .get ("total_tokens" , prompt_tokens + completion_tokens )
82+ break
5783 else :
5884 if attempt < max_retries - 1 :
5985 time .sleep (retry_delay )
6086 else :
6187 content = ''
62-
63- return content
88+ prompt_tokens = completion_tokens = total_tokens = 0
89+
90+ if return_usage :
91+ pricing = MODEL_PRICING .get (llm_model , {"prompt" : 0.03 , "completion" : 0.06 })
92+ input_cost = (prompt_tokens / 1000 ) * pricing ["prompt" ]
93+ output_cost = (completion_tokens / 1000 ) * pricing ["completion" ]
94+ total_cost = input_cost + output_cost
95+
96+ return content , {
97+ "prompt_tokens" : prompt_tokens ,
98+ "completion_tokens" : completion_tokens ,
99+ "total_tokens" : total_tokens ,
100+ "input_cost" : input_cost ,
101+ "output_cost" : output_cost ,
102+ "total_cost" : total_cost
103+ }
104+ else :
105+ return content
64106
65107
66108def generate_commit_message (
@@ -87,5 +129,13 @@ def generate_commit_message(
87129{ git_diff_text }
88130"""
89131
90- response = get_openai_api_result (system_prompt = system_prompt , user_prompt = user_prompt , llm_model = llm_model , max_retries = max_retries )
91- return response
132+ message , usage = get_openai_api_result (
133+ system_prompt = system_prompt ,
134+ user_prompt = user_prompt ,
135+ llm_model = llm_model ,
136+ max_retries = max_retries ,
137+ return_usage = True
138+ )
139+
140+ return message , usage
141+
0 commit comments