Skip to content

Commit 5b28791

Browse files
authored
feat: show model param sizes (#179)
* feat: param sizes * feat: param sizes * feat: param sizes * minor updates
1 parent 5755965 commit 5b28791

File tree

8 files changed

+181
-17
lines changed

8 files changed

+181
-17
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ echo "alias g=gollama" >> ~/.zshrc
124124
- `m`: Sort by modified
125125
- `k`: Sort by quantisation
126126
- `f`: Sort by family
127+
- `B`: Sort by parameter size
127128
- `l`: Link model to LM Studio
128129
- `L`: Link all models to LM Studio
129130
- `r`: Rename model _**(Work in progress)**_

app_model.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"fmt"
77
"sort"
8+
"strconv"
89
"strings"
910
"time"
1011

@@ -240,6 +241,8 @@ func (m *AppModel) handleKeyMsg(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
240241
return m.handleSortByQuantKey()
241242
case key.Matches(msg, m.keys.SortByFamily):
242243
return m.handleSortByFamilyKey()
244+
case key.Matches(msg, m.keys.SortByParamSize):
245+
return m.handleSortByParamSizeKey()
243246
case key.Matches(msg, m.keys.RunModel):
244247
return m.handleRunModelKey()
245248
case key.Matches(msg, m.keys.AltScreen):
@@ -512,6 +515,41 @@ func (m *AppModel) handleSortByFamilyKey() (tea.Model, tea.Cmd) {
512515
return m, nil
513516
}
514517

518+
func (m *AppModel) handleSortByParamSizeKey() (tea.Model, tea.Cmd) {
519+
logging.DebugLogger.Println("SortByParamSize key matched")
520+
m.cfg.SortOrder = "paramsize"
521+
522+
// Helper function to extract numeric value from parameter size strings
523+
getParamSizeValue := func(paramSize string) float64 {
524+
if paramSize == "" {
525+
return 0
526+
}
527+
528+
// Remove the "B" suffix if present
529+
numStr := paramSize
530+
if len(paramSize) > 0 && paramSize[len(paramSize)-1] == 'B' {
531+
numStr = paramSize[:len(paramSize)-1]
532+
}
533+
534+
// Parse the numeric part
535+
size, err := strconv.ParseFloat(numStr, 64)
536+
if err != nil {
537+
return 0
538+
}
539+
return size
540+
}
541+
542+
// Sort models by parameter size (largest first)
543+
sort.Slice(m.models, func(i, j int) bool {
544+
sizeI := getParamSizeValue(m.models[i].ParameterSize)
545+
sizeJ := getParamSizeValue(m.models[j].ParameterSize)
546+
return sizeI > sizeJ
547+
})
548+
549+
m.refreshList()
550+
return m, nil
551+
}
552+
515553
func (m *AppModel) handleRunModelKey() (tea.Model, tea.Cmd) {
516554
logging.DebugLogger.Println("RunModel key matched")
517555
if item, ok := m.list.SelectedItem().(Model); ok {
@@ -861,10 +899,19 @@ func (m *AppModel) inspectModelView(model Model) string {
861899
{"Name", model.Name},
862900
{"ID", model.ID},
863901
{"Size (GB)", fmt.Sprintf("%.2f", model.Size)},
864-
{"quantisation Level", model.QuantizationLevel},
902+
}
903+
904+
// Add parameter size if available
905+
if model.ParameterSize != "" {
906+
rows = append(rows, table.Row{"Parameter Size", model.ParameterSize})
907+
}
908+
909+
// Add remaining fields
910+
rows = append(rows, []table.Row{
911+
{"Quantisation Level", model.QuantizationLevel},
865912
{"Modified", model.Modified.Format("2006-01-02")},
866913
{"Family", model.Family},
867-
}
914+
}...)
868915

869916
// getModelParams returns a map of model parameters, so we need to iterate over the map and add the parameters to the rows
870917
for key, value := range modelParams {
@@ -980,7 +1027,7 @@ func (m *AppModel) topView() string {
9801027
func (k KeyMap) FullHelp() [][]key.Binding {
9811028
return [][]key.Binding{
9821029
{k.Space, k.Delete, k.RunModel, k.LinkModel, k.LinkAllModels, k.CopyModel, k.PushModel}, // first column
983-
{k.SortByName, k.SortBySize, k.SortByModified, k.SortByQuant, k.SortByFamily}, // second column
1030+
{k.SortByName, k.SortBySize, k.SortByModified, k.SortByQuant, k.SortByFamily, k.SortByParamSize}, // second column
9841031
{k.Top, k.EditModel, k.InspectModel, k.Quit}, // third column
9851032
}
9861033
}

helpers.go

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"strings"
88

9+
"github.com/charmbracelet/lipgloss"
910
"github.com/sammcj/gollama/config"
1011
"github.com/sammcj/gollama/logging"
1112
"github.com/sammcj/gollama/styles"
@@ -26,6 +27,7 @@ func parseAPIResponse(resp *api.ListResponse) []Model {
2627
QuantizationLevel: modelResp.Details.QuantizationLevel,
2728
Family: modelResp.Details.Family,
2829
Modified: modelResp.ModifiedAt,
30+
ParameterSize: modelResp.Details.ParameterSize,
2931
}
3032
}
3133
logging.DebugLogger.Println("Models:", models)
@@ -36,14 +38,18 @@ func normalizeSize(size float64) float64 {
3638
return size // Sizes are already in GB in the API response
3739
}
3840

39-
func calculateColumnWidths(totalWidth int) (nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth int) {
41+
// Constant for parameter size column width
42+
const minParamSizeWidth = 10
43+
44+
func calculateColumnWidths(totalWidth int) (nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth, paramSizeWidth int) {
4045
// Calculate column widths
41-
nameWidth = int(0.45 * float64(totalWidth))
46+
nameWidth = int(0.40 * float64(totalWidth))
4247
sizeWidth = int(0.05 * float64(totalWidth))
4348
quantWidth = int(0.05 * float64(totalWidth))
4449
familyWidth = int(0.05 * float64(totalWidth))
4550
modifiedWidth = int(0.05 * float64(totalWidth))
4651
idWidth = int(0.02 * float64(totalWidth))
52+
paramSizeWidth = int(0.05 * float64(totalWidth))
4753

4854
// Set the absolute minimum width for each column
4955
if nameWidth < minNameWidth {
@@ -64,10 +70,13 @@ func calculateColumnWidths(totalWidth int) (nameWidth, sizeWidth, quantWidth, mo
6470
if familyWidth < minFamilyWidth {
6571
familyWidth = minFamilyWidth
6672
}
73+
if paramSizeWidth < minParamSizeWidth {
74+
paramSizeWidth = minParamSizeWidth
75+
}
6776

6877
// If the total width is less than the sum of the minimum column widths, adjust the name column width and make sure all columns are aligned
69-
if totalWidth < nameWidth+sizeWidth+quantWidth+familyWidth+modifiedWidth+idWidth {
70-
nameWidth = totalWidth - sizeWidth - quantWidth - familyWidth - modifiedWidth - idWidth
78+
if totalWidth < nameWidth+sizeWidth+quantWidth+familyWidth+modifiedWidth+idWidth+paramSizeWidth {
79+
nameWidth = totalWidth - sizeWidth - quantWidth - familyWidth - modifiedWidth - idWidth - paramSizeWidth
7180
}
7281

7382
return
@@ -109,7 +118,7 @@ func wrapText(text string, width int) string {
109118
return wrapped
110119
}
111120

112-
func calculateColumnWidthsTerminal() (nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth int) {
121+
func calculateColumnWidthsTerminal() (nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth, paramSizeWidth int) {
113122
// use the terminal width to calculate column widths
114123
minWidth := 120
115124

@@ -140,16 +149,17 @@ func listModels(models []Model) {
140149
}
141150

142151
stripString := cfg.StripString
143-
nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth := calculateColumnWidthsTerminal()
152+
nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth, paramSizeWidth := calculateColumnWidthsTerminal()
144153

145154
// Add extra spacing between columns
146155
colSpacing := 2
147156
longestNameAllowed := 60
148157

149158
// Create the header with proper padding and alignment
150-
header := fmt.Sprintf("%-*s%-*s%-*s%-*s%-*s%-*s",
159+
header := fmt.Sprintf("%-*s%-*s%-*s%-*s%-*s%-*s%-*s",
151160
nameWidth, "Name",
152161
sizeWidth+colSpacing, "Size",
162+
paramSizeWidth+colSpacing, "Params",
153163
quantWidth+colSpacing, "Quant",
154164
familyWidth+colSpacing, "Family",
155165
modifiedWidth+colSpacing, "Modified",
@@ -163,7 +173,7 @@ func listModels(models []Model) {
163173
}
164174

165175
// Prepare columns for padding
166-
var names, sizes, quants, families, modified, ids []string
176+
var names, sizes, quants, families, modified, ids, paramSizes []string
167177
var longestName int
168178
for _, model := range models {
169179
if len(model.Name) > longestName {
@@ -175,6 +185,7 @@ func listModels(models []Model) {
175185
}
176186
names = append(names, model.Name)
177187
sizes = append(sizes, fmt.Sprintf("%.2fGB", model.Size))
188+
paramSizes = append(paramSizes, model.ParameterSize)
178189
quants = append(quants, model.QuantizationLevel)
179190
families = append(families, model.Family)
180191
modified = append(modified, model.Modified.Format("2006-01-02"))
@@ -184,6 +195,7 @@ func listModels(models []Model) {
184195
// Calculate maximum width for each column
185196
maxNameWidth := nameWidth
186197
maxSizeWidth := sizeWidth + colSpacing
198+
maxParamSizeWidth := paramSizeWidth + colSpacing
187199
maxQuantWidth := quantWidth + colSpacing
188200
maxFamilyWidth := familyWidth + colSpacing
189201
maxModifiedWidth := modifiedWidth + colSpacing
@@ -193,14 +205,21 @@ func listModels(models []Model) {
193205
for i := range names {
194206
names[i] = fmt.Sprintf("%-*s", maxNameWidth, names[i])
195207
sizes[i] = fmt.Sprintf("%-*s", maxSizeWidth, sizes[i])
208+
paramSizes[i] = fmt.Sprintf("%-*s", maxParamSizeWidth, paramSizes[i])
196209
quants[i] = fmt.Sprintf("%-*s", maxQuantWidth, quants[i])
197210
families[i] = fmt.Sprintf("%-*s", maxFamilyWidth, families[i])
198211
modified[i] = fmt.Sprintf("%-*s", maxModifiedWidth, modified[i])
199212
// if the longest name is more than longestNameAllowed characters, don't display the model sha
200213
if longestName > longestNameAllowed {
201214
ids[i] = ""
202215
// remove the ID header
203-
header = fmt.Sprintf("%-*s%-*s%-*s%-*s%-*s", nameWidth, "Name", sizeWidth+colSpacing, "Size", quantWidth+colSpacing, "Quant", familyWidth+colSpacing, "Family", modifiedWidth, "Modified")
216+
header = fmt.Sprintf("%-*s%-*s%-*s%-*s%-*s%-*s",
217+
nameWidth, "Name",
218+
sizeWidth+colSpacing, "Size",
219+
paramSizeWidth+colSpacing, "Params",
220+
quantWidth+colSpacing, "Quant",
221+
familyWidth+colSpacing, "Family",
222+
modifiedWidth, "Modified")
204223
} else {
205224
ids[i] = fmt.Sprintf("%-*s", maxIdWidth, ids[i])
206225
}
@@ -215,13 +234,24 @@ func listModels(models []Model) {
215234
name := styles.ItemNameStyle(index).Render(names[index])
216235
id := styles.ItemIDStyle().Render(ids[index])
217236
size := styles.SizeStyle(model.Size).Render(sizes[index])
237+
// Apply direct color based on parameter size
238+
var paramSize string
239+
if paramSizes[index] != "" {
240+
// Format the string first
241+
formattedParamSize := fmt.Sprintf("%-*s", maxParamSizeWidth, paramSizes[index])
242+
// Apply color directly using paramSizeColour
243+
paramSize = lipgloss.NewStyle().Foreground(paramSizeColour(paramSizes[index])).Render(formattedParamSize)
244+
} else {
245+
paramSize = fmt.Sprintf("%-*s", maxParamSizeWidth, paramSizes[index])
246+
}
218247
family := styles.FamilyStyle(model.Family).Render(families[index])
219248
quant := styles.QuantStyle(model.QuantizationLevel).Render(quants[index])
220249
modified := styles.ItemIDStyle().Render(modified[index])
221250

222-
row := fmt.Sprintf("%-*s%-*s%-*s%-*s%-*s%-*s",
251+
row := fmt.Sprintf("%-*s%-*s%-*s%-*s%-*s%-*s%-*s",
223252
maxNameWidth, name,
224253
maxSizeWidth, size,
254+
maxParamSizeWidth, paramSize,
225255
maxQuantWidth, quant,
226256
maxFamilyWidth, family,
227257
maxModifiedWidth, modified,

item_delegate.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,22 +109,23 @@ func (d itemDelegate) Render(w io.Writer, m list.Model, index int, item list.Ite
109109
quantStyle = selectedStyle.Inherit(quantStyle)
110110
}
111111

112-
nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth := calculateColumnWidths(m.Width())
112+
nameWidth, sizeWidth, quantWidth, modifiedWidth, idWidth, familyWidth, paramSizeWidth := calculateColumnWidths(m.Width())
113113

114114
// Ensure the text fits within the terminal width
115115
// Add consistent padding between columns
116116
padding := 2
117117
name := nameStyle.Width(nameWidth).Render(truncate(model.Name, nameWidth-padding))
118118
size := sizeStyle.Width(sizeWidth).Render(fmt.Sprintf("%*.2fGB", sizeWidth-padding-2, model.Size))
119+
paramSize := styles.ParamSizeStyle(model.ParameterSize).Width(paramSizeWidth).Render(fmt.Sprintf("%-*s", paramSizeWidth-padding, model.ParameterSize))
119120
quant := quantStyle.Width(quantWidth).Render(fmt.Sprintf("%-*s", quantWidth-padding, model.QuantizationLevel))
120121
family := familyStyle.Width(familyWidth).Render(fmt.Sprintf("%-*s", familyWidth-padding, model.Family))
121122
modified := dateStyle.Width(modifiedWidth).Render(fmt.Sprintf("%-*s", modifiedWidth-padding, model.Modified.Format("2006-01-02")))
122123
id := shaStyle.Width(idWidth).Render(fmt.Sprintf("%-*s", idWidth-padding, model.ID))
123124

124125
// Add padding between columns
125126
spacer := strings.Repeat(" ", padding)
126-
row := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s",
127-
name, spacer, size, spacer, quant, spacer, family, spacer, modified, spacer, id)
127+
row := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s",
128+
name, spacer, size, spacer, paramSize, spacer, quant, spacer, family, spacer, modified, spacer, id)
128129

129130
fmt.Fprint(w, row)
130131
}

keymap.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type KeyMap struct {
1313
SortByModified key.Binding
1414
SortByQuant key.Binding
1515
SortByFamily key.Binding
16+
SortByParamSize key.Binding
1617
RunModel key.Binding
1718
ConfirmYes key.Binding
1819
ConfirmNo key.Binding
@@ -65,6 +66,7 @@ func NewKeyMap() *KeyMap {
6566
SortByFamily: key.NewBinding(key.WithKeys("f"), key.WithHelp("f", "^family")),
6667
SortByModified: key.NewBinding(key.WithKeys("m"), key.WithHelp("m", "^modified")),
6768
SortByName: key.NewBinding(key.WithKeys("n"), key.WithHelp("n", "^name")),
69+
SortByParamSize: key.NewBinding(key.WithKeys("B"), key.WithHelp("B", "^params")),
6870
SortByQuant: key.NewBinding(key.WithKeys("K"), key.WithHelp("K", "^quant")),
6971
SortBySize: key.NewBinding(key.WithKeys("s"), key.WithHelp("s", "^size")),
7072
Top: key.NewBinding(key.WithKeys("t"), key.WithHelp("t", "top")),

model.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Model struct {
1414
Modified time.Time
1515
Selected bool
1616
Family string
17+
ParameterSize string
1718
}
1819

1920
func (m Model) SelectedStr() string {
@@ -24,7 +25,11 @@ func (m Model) SelectedStr() string {
2425
}
2526

2627
func (m Model) Description() string {
27-
return fmt.Sprintf("ID: %s, Size: %.2f GB, Quant: %s, Modified: %s", m.ID, m.Size, m.QuantizationLevel, m.Modified.Format("2006-01-02"))
28+
paramSizeStr := ""
29+
if m.ParameterSize != "" {
30+
paramSizeStr = fmt.Sprintf(", Parameters: %s", m.ParameterSize)
31+
}
32+
return fmt.Sprintf("ID: %s, Size: %.2f GB, Quant: %s%s, Modified: %s", m.ID, m.Size, m.QuantizationLevel, paramSizeStr, m.Modified.Format("2006-01-02"))
2833
}
2934

3035
func (m Model) FilterValue() string {

styles.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33

44
import (
55
"math"
6+
"strconv"
67

78
"github.com/charmbracelet/lipgloss"
89
)
@@ -82,6 +83,34 @@ func sizeColour(size float64) lipgloss.Color {
8283
return lipgloss.Color(synthGradient[index])
8384
}
8485

86+
func paramSizeColour(paramSize string) lipgloss.Color {
87+
// Extract the numeric part from parameter size strings like "7.6B", "32B", etc.
88+
if paramSize == "" {
89+
return lipgloss.Color(synthGradient[0])
90+
}
91+
92+
// Remove the "B" suffix if present
93+
numStr := paramSize
94+
if paramSize[len(paramSize)-1] == 'B' {
95+
numStr = paramSize[:len(paramSize)-1]
96+
}
97+
98+
// Parse the numeric part
99+
size, err := strconv.ParseFloat(numStr, 64)
100+
if err != nil {
101+
// Default to first color if parsing fails
102+
return lipgloss.Color(synthGradient[0])
103+
}
104+
105+
// Use logarithmic scale similar to sizeColour but adjusted for parameter sizes
106+
// Parameter sizes typically range from 1B to 100B+
107+
index := int(math.Log10(size+1) * 3)
108+
if index >= len(synthGradient) {
109+
index = len(synthGradient) - 1
110+
}
111+
return lipgloss.Color(synthGradient[index])
112+
}
113+
85114
func familyColour(family string, index int) lipgloss.Color {
86115
colour, exists := familyColours[family]
87116
if !exists {

0 commit comments

Comments
 (0)