@@ -3,7 +3,10 @@ package cc.unitmesh.devti.gui.chat.ui
3
3
import cc.unitmesh.devti.llm2.TokenUsageEvent
4
4
import cc.unitmesh.devti.llm2.TokenUsageListener
5
5
import cc.unitmesh.devti.llms.custom.Usage
6
+ import cc.unitmesh.devti.settings.AutoDevSettingsState
7
+ import cc.unitmesh.devti.settings.model.LLMModelManager
6
8
import com.intellij.openapi.application.ApplicationManager
9
+ import com.intellij.openapi.components.service
7
10
import com.intellij.openapi.project.Project
8
11
import com.intellij.ui.components.JBLabel
9
12
import com.intellij.util.ui.JBUI
@@ -12,8 +15,11 @@ import com.intellij.util.ui.components.BorderLayoutPanel
12
15
import java.awt.BorderLayout
13
16
import java.awt.Color
14
17
import java.awt.Font
18
+ import java.awt.GridBagConstraints
19
+ import java.awt.GridBagLayout
15
20
import javax.swing.Box
16
21
import javax.swing.JPanel
22
+ import javax.swing.JProgressBar
17
23
import javax.swing.SwingConstants
18
24
19
25
/* *
@@ -25,9 +31,12 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
25
31
private val completionTokensLabel = JBLabel (" 0" , SwingConstants .RIGHT )
26
32
private val totalTokensLabel = JBLabel (" 0" , SwingConstants .RIGHT )
27
33
private val modelLabel = JBLabel (" " , SwingConstants .LEFT )
34
+ private val progressBar = JProgressBar (0 , 100 )
35
+ private val usageRatioLabel = JBLabel (" " , SwingConstants .CENTER )
28
36
29
37
private var currentUsage = Usage ()
30
38
private var currentModel: String? = null
39
+ private var maxContextWindowTokens: Long = 0
31
40
32
41
init {
33
42
setupUI()
@@ -38,13 +47,55 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
38
47
isOpaque = false
39
48
border = JBUI .Borders .empty(4 , 8 )
40
49
50
+ // Setup progress bar
51
+ progressBar.apply {
52
+ isStringPainted = false
53
+ preferredSize = java.awt.Dimension (150 , 16 )
54
+ minimumSize = java.awt.Dimension (100 , 16 )
55
+ font = font.deriveFont(Font .PLAIN , 10f )
56
+ isOpaque = false
57
+ }
58
+
59
+ // Setup usage ratio label
60
+ usageRatioLabel.apply {
61
+ font = font.deriveFont(Font .PLAIN , 10f )
62
+ foreground = UIUtil .getContextHelpForeground()
63
+ }
64
+
65
+ // Create main layout
66
+ val mainPanel = JPanel (GridBagLayout ())
67
+ mainPanel.isOpaque = false
68
+
69
+ val gbc = GridBagConstraints ()
70
+
71
+ // Top row: Model info and progress bar
72
+ gbc.gridx = 0
73
+ gbc.gridy = 0
74
+ gbc.anchor = GridBagConstraints .WEST
75
+ gbc.fill = GridBagConstraints .NONE
41
76
// Create left panel for model info
42
77
val leftPanel = JPanel (BorderLayout ())
43
78
leftPanel.isOpaque = false
44
79
modelLabel.font = modelLabel.font.deriveFont(Font .PLAIN , 11f )
45
80
modelLabel.foreground = UIUtil .getContextHelpForeground()
46
81
leftPanel.add(modelLabel, BorderLayout .WEST )
47
82
83
+ mainPanel.add(leftPanel, gbc)
84
+
85
+ // Progress bar and ratio in the middle
86
+ gbc.gridx = 1
87
+ gbc.weightx = 1.0
88
+ gbc.fill = GridBagConstraints .HORIZONTAL
89
+ gbc.insets = JBUI .insets(0 , 8 , 0 , 8 )
90
+
91
+ val progressPanel = JPanel (BorderLayout ())
92
+ progressPanel.isOpaque = false
93
+ progressPanel.add(progressBar, BorderLayout .CENTER )
94
+ progressPanel.add(usageRatioLabel, BorderLayout .SOUTH )
95
+
96
+ mainPanel.add(progressPanel, gbc)
97
+
98
+ // Bottom row: Token stats
48
99
// Create right panel for token stats
49
100
val rightPanel = JPanel ()
50
101
rightPanel.isOpaque = false
@@ -77,9 +128,14 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
77
128
})
78
129
rightPanel.add(totalTokensLabel)
79
130
131
+ gbc.gridx = 2
132
+ gbc.weightx = 0.0
133
+ gbc.fill = GridBagConstraints .NONE
134
+ gbc.insets = JBUI .insets(0 , 0 , 0 , 0 )
135
+ mainPanel.add(rightPanel, gbc)
136
+
80
137
// Add panels to main layout
81
- addToLeft(leftPanel)
82
- addToRight(rightPanel)
138
+ addToCenter(mainPanel)
83
139
84
140
// Initially hidden
85
141
isVisible = false
@@ -99,10 +155,17 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
99
155
currentUsage = event.usage
100
156
currentModel = event.model
101
157
158
+ // Get max tokens for current model
159
+ updateMaxTokens()
160
+
161
+ // Update token displays
102
162
promptTokensLabel.text = formatTokenCount(event.usage.promptTokens ? : 0 )
103
163
completionTokensLabel.text = formatTokenCount(event.usage.completionTokens ? : 0 )
104
164
totalTokensLabel.text = formatTokenCount(event.usage.totalTokens ? : 0 )
105
165
166
+ // Update progress bar
167
+ updateProgressBar(event.usage.totalTokens ? : 0 )
168
+
106
169
if (! event.model.isNullOrBlank()) {
107
170
modelLabel.text = " Model: ${event.model} "
108
171
}
@@ -114,6 +177,45 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
114
177
}
115
178
}
116
179
180
+ private fun updateMaxTokens () {
181
+ try {
182
+ val settings = AutoDevSettingsState .getInstance()
183
+ val modelManager = LLMModelManager (project, settings) {}
184
+ val limits = modelManager.getUsedMaxToken()
185
+ maxContextWindowTokens = limits.maxContextWindowTokens?.toLong() ? : 0
186
+ } catch (e: Exception ) {
187
+ // Fallback to default if unable to get limits
188
+ maxContextWindowTokens = 4096
189
+ }
190
+ }
191
+
192
+ private fun updateProgressBar (totalTokens : Long ) {
193
+ if (maxContextWindowTokens <= 0 ) {
194
+ progressBar.isVisible = false
195
+ usageRatioLabel.isVisible = false
196
+ return
197
+ }
198
+
199
+ val usageRatio = (totalTokens.toDouble() / maxContextWindowTokens * 100 ).toInt()
200
+ progressBar.value = usageRatio.coerceIn(0 , 100 )
201
+
202
+ // Update color based on usage ratio
203
+ progressBar.foreground = when {
204
+ usageRatio >= 90 -> Color .RED
205
+ usageRatio >= 75 -> Color .ORANGE
206
+ usageRatio >= 50 -> Color .YELLOW
207
+ else -> UIUtil .getPanelBackground().brighter()
208
+ }
209
+
210
+ // Update ratio label
211
+ usageRatioLabel.text = " ${formatTokenCount(totalTokens)} /${formatTokenCount(maxContextWindowTokens)} (${usageRatio} %)"
212
+
213
+ progressBar.isVisible = true
214
+ usageRatioLabel.isVisible = true
215
+
216
+ progressBar.toolTipText = " Token usage: $usageRatio % of context window"
217
+ }
218
+
117
219
private fun formatTokenCount (count : Long ): String {
118
220
return when {
119
221
count >= 1_000_000 -> String .format(" %.1fM" , count / 1_000_000.0 )
@@ -129,10 +231,15 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
129
231
ApplicationManager .getApplication().invokeLater {
130
232
currentUsage = Usage ()
131
233
currentModel = null
234
+ maxContextWindowTokens = 0
132
235
promptTokensLabel.text = " 0"
133
236
completionTokensLabel.text = " 0"
134
237
totalTokensLabel.text = " 0"
135
238
modelLabel.text = " "
239
+ progressBar.value = 0
240
+ progressBar.isVisible = false
241
+ usageRatioLabel.text = " "
242
+ usageRatioLabel.isVisible = false
136
243
isVisible = false
137
244
revalidate()
138
245
repaint()
0 commit comments