Skip to content

Commit 7bc81d3

Browse files
authored
feat: consolidate token usage and test coverage (#223)
- Replace manual token printing with a single usage string call - Introduce a method that handles token counts and their details - Add tests verifying the usage string output in various scenarios Signed-off-by: Bo-Yi Wu <[email protected]>
1 parent 8868652 commit 7bc81d3

File tree

3 files changed

+83
-17
lines changed

3 files changed

+83
-17
lines changed

cmd/commit.go

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"html"
55
"os"
66
"path"
7-
"strconv"
87
"strings"
98
"time"
109

@@ -149,10 +148,7 @@ var commitCmd = &cobra.Command{
149148
return err
150149
}
151150
data[prompt.SummarizeMessageKey] = strings.TrimSpace(resp.Content)
152-
color.Magenta("PromptTokens: " + strconv.Itoa(resp.Usage.PromptTokens) +
153-
", CompletionTokens: " + strconv.Itoa(resp.Usage.CompletionTokens) +
154-
", TotalTokens: " + strconv.Itoa(resp.Usage.TotalTokens),
155-
)
151+
color.Magenta(resp.Usage.String())
156152
}
157153

158154
// Get summarize title from diff datas
@@ -174,10 +170,7 @@ var commitCmd = &cobra.Command{
174170
return err
175171
}
176172
summarizeTitle := resp.Content
177-
color.Magenta("PromptTokens: " + strconv.Itoa(resp.Usage.PromptTokens) +
178-
", CompletionTokens: " + strconv.Itoa(resp.Usage.CompletionTokens) +
179-
", TotalTokens: " + strconv.Itoa(resp.Usage.TotalTokens),
180-
)
173+
color.Magenta(resp.Usage.String())
181174

182175
// lowercase the first character of first word of the commit message and remove last period
183176
summarizeTitle = strings.TrimRight(strings.ToLower(string(summarizeTitle[0]))+summarizeTitle[1:], ".")
@@ -203,10 +196,7 @@ var commitCmd = &cobra.Command{
203196
}
204197
summaryPrix = resp.Content
205198

206-
color.Magenta("PromptTokens: " + strconv.Itoa(resp.Usage.PromptTokens) +
207-
", CompletionTokens: " + strconv.Itoa(resp.Usage.CompletionTokens) +
208-
", TotalTokens: " + strconv.Itoa(resp.Usage.TotalTokens),
209-
)
199+
color.Magenta(resp.Usage.String())
210200

211201
data[prompt.SummarizePrefixKey] = summaryPrix
212202
}
@@ -260,10 +250,7 @@ var commitCmd = &cobra.Command{
260250
if err != nil {
261251
return err
262252
}
263-
color.Magenta("PromptTokens: " + strconv.Itoa(resp.Usage.PromptTokens) +
264-
", CompletionTokens: " + strconv.Itoa(resp.Usage.CompletionTokens) +
265-
", TotalTokens: " + strconv.Itoa(resp.Usage.TotalTokens),
266-
)
253+
color.Magenta(resp.Usage.String())
267254
commitMessage = resp.Content
268255
}
269256

core/openai.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package core
22

33
import (
44
"context"
5+
"strconv"
56

67
"github.com/sashabaranov/go-openai"
78
)
@@ -18,6 +19,19 @@ type Usage struct {
1819
CompletionTokensDetails *openai.CompletionTokensDetails
1920
}
2021

22+
func (u Usage) String() string {
23+
s := "Prompt tokens: " + strconv.Itoa(u.PromptTokens)
24+
if u.PromptTokensDetails != nil && u.PromptTokensDetails.CachedTokens > 0 {
25+
s += " (CachedTokens: " + strconv.Itoa(u.PromptTokensDetails.CachedTokens) + ")"
26+
}
27+
s += ", Completion tokens: " + strconv.Itoa(u.CompletionTokens)
28+
if u.CompletionTokensDetails != nil && u.CompletionTokensDetails.ReasoningTokens > 0 {
29+
s += " (ReasoningTokens: " + strconv.Itoa(u.CompletionTokensDetails.ReasoningTokens) + ")"
30+
}
31+
s += ", Total tokens: " + strconv.Itoa(u.TotalTokens)
32+
return s
33+
}
34+
2135
// Response represents the structure of a response from the OpenAI API.
2236
// It contains the content of the response and the usage information.
2337
type Response struct {

core/openai_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package core
2+
3+
import (
4+
"testing"
5+
6+
"github.com/sashabaranov/go-openai"
7+
)
8+
9+
func TestUsageString(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
usage Usage
13+
expected string
14+
}{
15+
{
16+
name: "without details",
17+
usage: Usage{
18+
PromptTokens: 10,
19+
CompletionTokens: 20,
20+
TotalTokens: 30,
21+
},
22+
expected: "Prompt tokens: 10, Completion tokens: 20, Total tokens: 30",
23+
},
24+
{
25+
name: "with cached tokens",
26+
usage: Usage{
27+
PromptTokens: 10,
28+
CompletionTokens: 20,
29+
TotalTokens: 30,
30+
PromptTokensDetails: &openai.PromptTokensDetails{CachedTokens: 5},
31+
},
32+
expected: "Prompt tokens: 10 (CachedTokens: 5), Completion tokens: 20, Total tokens: 30",
33+
},
34+
{
35+
name: "with reasoning tokens",
36+
usage: Usage{
37+
PromptTokens: 10,
38+
CompletionTokens: 20,
39+
TotalTokens: 30,
40+
CompletionTokensDetails: &openai.CompletionTokensDetails{ReasoningTokens: 7},
41+
},
42+
expected: "Prompt tokens: 10, Completion tokens: 20 (ReasoningTokens: 7), Total tokens: 30",
43+
},
44+
{
45+
name: "with both details",
46+
usage: Usage{
47+
PromptTokens: 15,
48+
CompletionTokens: 25,
49+
TotalTokens: 40,
50+
PromptTokensDetails: &openai.PromptTokensDetails{CachedTokens: 3},
51+
CompletionTokensDetails: &openai.CompletionTokensDetails{ReasoningTokens: 9},
52+
},
53+
expected: "Prompt tokens: 15 (CachedTokens: 3), Completion tokens: 25 (ReasoningTokens: 9), Total tokens: 40",
54+
},
55+
}
56+
57+
for _, tc := range tests {
58+
t.Run(tc.name, func(t *testing.T) {
59+
result := tc.usage.String()
60+
if result != tc.expected {
61+
t.Errorf("Usage.String() = %q, expected %q", result, tc.expected)
62+
}
63+
})
64+
}
65+
}

0 commit comments

Comments
 (0)