Implement lmcli ls
This commit is contained in:
parent
ae424530f9
commit
b0a1299e0b
@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -24,17 +25,21 @@ var lsCmd = &cobra.Command{
|
|||||||
Short: "List existing conversations",
|
Short: "List existing conversations",
|
||||||
Long: `List all existing conversations in descending order of recent activity.`,
|
Long: `List all existing conversations in descending order of recent activity.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Println("Listing conversations...")
|
conversations, err := store.GetConversations()
|
||||||
// Example output, asterisk to indicate current converation
|
if err != nil {
|
||||||
|
fmt.Println("Could not fetch conversations.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// $ lm ls
|
// Example output
|
||||||
|
// $ lmcli ls
|
||||||
// last hour:
|
// last hour:
|
||||||
// 98sg - 12 minutes ago - Project discussion
|
// 98sg - 12 minutes ago - Project discussion
|
||||||
// last day:
|
// last day:
|
||||||
// tj3l - 10 hours ago - Deep learning concepts
|
// tj3l - 10 hours ago - Deep learning concepts
|
||||||
// last week:
|
// last week:
|
||||||
// bwfm - 2 days ago - Machine learning study
|
// bwfm - 2 days ago - Machine learning study
|
||||||
// * 8n3h - 3 days ago - Weekend plans
|
// 8n3h - 3 days ago - Weekend plans
|
||||||
// f3n7 - 6 days ago - CLI development
|
// f3n7 - 6 days ago - CLI development
|
||||||
// last month:
|
// last month:
|
||||||
// 5hn2 - 8 days ago - Book club discussion
|
// 5hn2 - 8 days ago - Book club discussion
|
||||||
@ -45,6 +50,63 @@ var lsCmd = &cobra.Command{
|
|||||||
// g8d9 - 3 months ago - History book club
|
// g8d9 - 3 months ago - History book club
|
||||||
// 4lk3 - 4 months ago - Local events and meetups
|
// 4lk3 - 4 months ago - Local events and meetups
|
||||||
// 43jn - 6 months ago - Mobile photography techniques
|
// 43jn - 6 months ago - Mobile photography techniques
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
categories := []string{
|
||||||
|
"recent",
|
||||||
|
"last hour",
|
||||||
|
"last day",
|
||||||
|
"last week",
|
||||||
|
"last month",
|
||||||
|
"last 6 months",
|
||||||
|
"older",
|
||||||
|
}
|
||||||
|
categorized := map[string][]string{}
|
||||||
|
|
||||||
|
for _, conversation := range conversations {
|
||||||
|
lastMessage, err := store.GetLastMessage(&conversation)
|
||||||
|
if lastMessage == nil || err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
messageAge := now.Sub(lastMessage.CreatedAt)
|
||||||
|
|
||||||
|
var category string
|
||||||
|
switch {
|
||||||
|
case messageAge <= 10*time.Minute:
|
||||||
|
category = "recent"
|
||||||
|
case messageAge <= time.Hour:
|
||||||
|
category = "last hour"
|
||||||
|
case messageAge <= 24*time.Hour:
|
||||||
|
category = "last day"
|
||||||
|
case messageAge <= 7*24*time.Hour:
|
||||||
|
category = "last week"
|
||||||
|
case messageAge <= 30*24*time.Hour:
|
||||||
|
category = "last month"
|
||||||
|
case messageAge <= 6*30*24*time.Hour: // Approximate as 6 months
|
||||||
|
category = "last 6 months"
|
||||||
|
default:
|
||||||
|
category = "older"
|
||||||
|
}
|
||||||
|
|
||||||
|
formatted := fmt.Sprintf(
|
||||||
|
"%s - %s - %s",
|
||||||
|
conversation.ShortName.String,
|
||||||
|
humanTimeElapsedSince(messageAge),
|
||||||
|
conversation.Title,
|
||||||
|
)
|
||||||
|
categorized[category] = append(categorized[category], formatted)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, category := range categories {
|
||||||
|
conversations, ok := categorized[category]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("%s:\n", category)
|
||||||
|
for _, conv := range conversations {
|
||||||
|
fmt.Printf(" %s\n", conv)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,6 +236,7 @@ var promptCmd = &cobra.Command{
|
|||||||
|
|
||||||
func NewRootCmd() *cobra.Command {
|
func NewRootCmd() *cobra.Command {
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
|
lsCmd,
|
||||||
newCmd,
|
newCmd,
|
||||||
promptCmd,
|
promptCmd,
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
sqids "github.com/sqids/sqids-go"
|
sqids "github.com/sqids/sqids-go"
|
||||||
"gorm.io/driver/sqlite"
|
"gorm.io/driver/sqlite"
|
||||||
@ -22,6 +23,7 @@ type Message struct {
|
|||||||
Conversation Conversation
|
Conversation Conversation
|
||||||
OriginalContent string
|
OriginalContent string
|
||||||
Role string // 'user' or 'assistant'
|
Role string // 'user' or 'assistant'
|
||||||
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type Conversation struct {
|
type Conversation struct {
|
||||||
@ -98,3 +100,9 @@ func (s *Store) GetMessages(conversation *Conversation) ([]Message, error) {
|
|||||||
err := s.db.Where("conversation_id = ?", conversation.ID).Find(&messages).Error
|
err := s.db.Where("conversation_id = ?", conversation.ID).Find(&messages).Error
|
||||||
return messages, err
|
return messages, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetLastMessage(conversation *Conversation) (*Message, error) {
|
||||||
|
var message Message
|
||||||
|
err := s.db.Where("conversation_id = ?", conversation.ID).Last(&message).Error
|
||||||
|
return &message, err
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InputFromEditor retrieves user input by opening an editor (one specified by
|
// InputFromEditor retrieves user input by opening an editor (one specified by
|
||||||
@ -48,3 +50,44 @@ func InputFromEditor(placeholder string, pattern string) (string, error) {
|
|||||||
|
|
||||||
return strings.Trim(content, "\n \t"), nil
|
return strings.Trim(content, "\n \t"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// humanTimeElapsedSince returns a human-friendly representation of the given time
|
||||||
|
// duration.
|
||||||
|
func humanTimeElapsedSince(d time.Duration) string {
|
||||||
|
seconds := d.Seconds()
|
||||||
|
minutes := seconds / 60
|
||||||
|
hours := minutes / 60
|
||||||
|
days := hours / 24
|
||||||
|
weeks := days / 7
|
||||||
|
months := days / 30
|
||||||
|
years := days / 365
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case seconds < 60:
|
||||||
|
return "seconds ago"
|
||||||
|
case minutes < 2:
|
||||||
|
return "1 minute ago"
|
||||||
|
case minutes < 60:
|
||||||
|
return fmt.Sprintf("%d minutes ago", int64(minutes))
|
||||||
|
case hours < 2:
|
||||||
|
return "1 hour ago"
|
||||||
|
case hours < 24:
|
||||||
|
return fmt.Sprintf("%d hours ago", int64(hours))
|
||||||
|
case days < 2:
|
||||||
|
return "1 day ago"
|
||||||
|
case days < 7:
|
||||||
|
return fmt.Sprintf("%d days ago", int64(days))
|
||||||
|
case weeks < 2:
|
||||||
|
return "1 week ago"
|
||||||
|
case weeks <= 4:
|
||||||
|
return fmt.Sprintf("%d weeks ago", int64(weeks))
|
||||||
|
case months < 2:
|
||||||
|
return "1 month ago"
|
||||||
|
case months < 12:
|
||||||
|
return fmt.Sprintf("%d months ago", int64(months))
|
||||||
|
case years < 2:
|
||||||
|
return "1 year ago"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%d years ago", int64(years))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user