ollama/progress/bar.go

156 lines
2.9 KiB
Go
Raw Normal View History

2023-11-15 00:33:16 +00:00
package progress
import (
"fmt"
2023-11-19 16:00:43 +00:00
"math"
2023-11-15 00:33:16 +00:00
"os"
"strings"
"time"
"github.com/jmorganca/ollama/format"
"golang.org/x/term"
)
type Stats struct {
rate int64
value int64
remaining time.Duration
}
2023-11-15 00:33:16 +00:00
type Bar struct {
message string
messageWidth int
maxValue int64
initialValue int64
currentValue int64
started time.Time
stats Stats
statted time.Time
2023-11-15 00:33:16 +00:00
}
func NewBar(message string, maxValue, initialValue int64) *Bar {
return &Bar{
message: message,
messageWidth: -1,
maxValue: maxValue,
initialValue: initialValue,
currentValue: initialValue,
started: time.Now(),
}
}
func (b *Bar) String() string {
termWidth, _, err := term.GetSize(int(os.Stderr.Fd()))
if err != nil {
2023-11-20 04:50:45 +00:00
termWidth = 80
2023-11-15 00:33:16 +00:00
}
var pre, mid, suf strings.Builder
if b.message != "" {
message := strings.TrimSpace(b.message)
if b.messageWidth > 0 && len(message) > b.messageWidth {
message = message[:b.messageWidth]
}
fmt.Fprintf(&pre, "%s", message)
if b.messageWidth-pre.Len() >= 0 {
pre.WriteString(strings.Repeat(" ", b.messageWidth-pre.Len()))
}
pre.WriteString(" ")
}
2023-11-19 16:00:43 +00:00
fmt.Fprintf(&pre, "%3.0f%% ", math.Floor(b.percent()))
fmt.Fprintf(&suf, "(%s/%s", format.HumanBytes(b.currentValue), format.HumanBytes(b.maxValue))
2023-11-15 00:33:16 +00:00
stats := b.Stats()
rate := int64(stats.rate)
if rate > 0 {
fmt.Fprintf(&suf, ", %s/s", format.HumanBytes(rate))
}
fmt.Fprintf(&suf, ")")
elapsed := time.Since(b.started)
if b.percent() < 100 && rate > 0 {
fmt.Fprintf(&suf, " [%s:%s]", elapsed.Round(time.Second), stats.remaining)
} else {
fmt.Fprintf(&suf, " ")
}
2023-11-15 00:33:16 +00:00
2023-11-19 14:54:33 +00:00
mid.WriteString("▕")
2023-11-15 00:33:16 +00:00
// add 3 extra spaces: 2 boundary characters and 1 space at the end
f := termWidth - pre.Len() - suf.Len() - 3
2023-11-15 00:33:16 +00:00
n := int(float64(f) * b.percent() / 100)
2023-11-19 14:54:33 +00:00
if n > 0 {
mid.WriteString(strings.Repeat("█", n))
2023-11-15 00:33:16 +00:00
}
if f-n > 0 {
mid.WriteString(strings.Repeat(" ", f-n))
}
2023-11-19 14:54:33 +00:00
mid.WriteString("▏")
2023-11-15 00:33:16 +00:00
return pre.String() + mid.String() + suf.String()
}
func (b *Bar) Set(value int64) {
if value >= b.maxValue {
value = b.maxValue
}
b.currentValue = value
}
func (b *Bar) percent() float64 {
if b.maxValue > 0 {
return float64(b.currentValue) / float64(b.maxValue) * 100
}
return 0
}
func (b *Bar) Stats() Stats {
2023-11-20 19:22:39 +00:00
if time.Since(b.statted) < time.Second {
return b.stats
2023-11-15 22:52:21 +00:00
}
2023-11-20 19:22:39 +00:00
switch {
case b.statted.IsZero():
b.stats = Stats{
2023-11-20 19:33:46 +00:00
value: b.initialValue,
2023-11-20 19:22:39 +00:00
rate: 0,
remaining: 0,
}
2023-11-20 19:33:46 +00:00
case b.currentValue >= b.maxValue:
b.stats = Stats{
2023-11-20 19:33:46 +00:00
value: b.maxValue,
rate: 0,
remaining: 0,
}
2023-11-20 19:22:39 +00:00
default:
rate := b.currentValue - b.stats.value
var remaining time.Duration
if rate > 0 {
remaining = time.Second * time.Duration((float64(b.maxValue-b.currentValue))/(float64(rate)))
}
2023-11-15 00:33:16 +00:00
b.stats = Stats{
value: b.currentValue,
rate: rate,
remaining: remaining,
}
2023-11-15 00:33:16 +00:00
}
b.statted = time.Now()
return b.stats
2023-11-15 00:33:16 +00:00
}