@@ -3,7 +3,10 @@ package cc.unitmesh.devti.gui.chat.ui
33import cc.unitmesh.devti.llm2.TokenUsageEvent
44import cc.unitmesh.devti.llm2.TokenUsageListener
55import cc.unitmesh.devti.llms.custom.Usage
6+ import cc.unitmesh.devti.settings.AutoDevSettingsState
7+ import cc.unitmesh.devti.settings.model.LLMModelManager
68import com.intellij.openapi.application.ApplicationManager
9+ import com.intellij.openapi.components.service
710import com.intellij.openapi.project.Project
811import com.intellij.ui.components.JBLabel
912import com.intellij.util.ui.JBUI
@@ -12,8 +15,11 @@ import com.intellij.util.ui.components.BorderLayoutPanel
1215import java.awt.BorderLayout
1316import java.awt.Color
1417import java.awt.Font
18+ import java.awt.GridBagConstraints
19+ import java.awt.GridBagLayout
1520import javax.swing.Box
1621import javax.swing.JPanel
22+ import javax.swing.JProgressBar
1723import javax.swing.SwingConstants
1824
1925/* *
@@ -25,9 +31,12 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
2531private val completionTokensLabel= JBLabel (" 0" ,SwingConstants .RIGHT )
2632private val totalTokensLabel= JBLabel (" 0" ,SwingConstants .RIGHT )
2733private val modelLabel= JBLabel (" " ,SwingConstants .LEFT )
34+ private val progressBar= JProgressBar (0 ,100 )
35+ private val usageRatioLabel= JBLabel (" " ,SwingConstants .CENTER )
2836
2937private var currentUsage= Usage ()
3038private var currentModel: String? = null
39+ private var maxContextWindowTokens: Long = 0
3140
3241init {
3342 setupUI()
@@ -38,13 +47,55 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
3847 isOpaque= false
3948 border= JBUI .Borders .empty(4 ,8 )
4049
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
4176// Create left panel for model info
4277val leftPanel= JPanel (BorderLayout ())
4378 leftPanel.isOpaque= false
4479 modelLabel.font= modelLabel.font.deriveFont(Font .PLAIN ,11f )
4580 modelLabel.foreground= UIUtil .getContextHelpForeground()
4681 leftPanel.add(modelLabel,BorderLayout .WEST )
4782
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
4899// Create right panel for token stats
49100val rightPanel= JPanel ()
50101 rightPanel.isOpaque= false
@@ -77,9 +128,14 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
77128 })
78129 rightPanel.add(totalTokensLabel)
79130
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+
80137// Add panels to main layout
81- addToLeft(leftPanel)
82- addToRight(rightPanel)
138+ addToCenter(mainPanel)
83139
84140// Initially hidden
85141 isVisible= false
@@ -99,10 +155,17 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
99155 currentUsage= event.usage
100156 currentModel= event.model
101157
158+ // Get max tokens for current model
159+ updateMaxTokens()
160+
161+ // Update token displays
102162 promptTokensLabel.text= formatTokenCount(event.usage.promptTokens? : 0 )
103163 completionTokensLabel.text= formatTokenCount(event.usage.completionTokens? : 0 )
104164 totalTokensLabel.text= formatTokenCount(event.usage.totalTokens? : 0 )
105165
166+ // Update progress bar
167+ updateProgressBar(event.usage.totalTokens? : 0 )
168+
106169if (! event.model.isNullOrBlank()) {
107170 modelLabel.text= " Model:${event.model} "
108171 }
@@ -114,6 +177,45 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
114177 }
115178 }
116179
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+
117219private fun formatTokenCount (count : Long ):String {
118220return when {
119221 count>= 1_000_000 -> String .format(" %.1fM" , count/ 1_000_000.0 )
@@ -129,10 +231,15 @@ class TokenUsagePanel(private val project: Project) : BorderLayoutPanel() {
129231ApplicationManager .getApplication().invokeLater {
130232 currentUsage= Usage ()
131233 currentModel= null
234+ maxContextWindowTokens= 0
132235 promptTokensLabel.text= " 0"
133236 completionTokensLabel.text= " 0"
134237 totalTokensLabel.text= " 0"
135238 modelLabel.text= " "
239+ progressBar.value= 0
240+ progressBar.isVisible= false
241+ usageRatioLabel.text= " "
242+ usageRatioLabel.isVisible= false
136243 isVisible= false
137244 revalidate()
138245 repaint()