Files
go-lcg/cmd/history.go

205 lines
6.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cmd
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"time"
)
type HistoryEntry struct {
Index int `json:"index"`
Command string `json:"command"`
Response string `json:"response"`
Explanation string `json:"explanation,omitempty"`
System string `json:"system_prompt"`
Timestamp time.Time `json:"timestamp"`
}
func read(historyPath string) ([]HistoryEntry, error) {
data, err := os.ReadFile(historyPath)
if err != nil {
// Если файл не существует, создаем пустой файл истории
if os.IsNotExist(err) {
emptyHistory := []HistoryEntry{}
if writeErr := write(historyPath, emptyHistory); writeErr != nil {
return nil, fmt.Errorf("не удалось создать файл истории: %v", writeErr)
}
return emptyHistory, nil
}
return nil, err
}
if len(data) == 0 {
return []HistoryEntry{}, nil
}
var items []HistoryEntry
if err := json.Unmarshal(data, &items); err != nil {
return nil, err
}
return items, nil
}
func write(historyPath string, entries []HistoryEntry) error {
for i := range entries {
entries[i].Index = i + 1
}
out, err := json.MarshalIndent(entries, "", " ")
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(historyPath), 0755); err != nil {
return err
}
return os.WriteFile(historyPath, out, 0644)
}
func ShowHistory(historyPath string, printColored func(string, string), colorYellow string) {
items, err := read(historyPath)
if err != nil || len(items) == 0 {
printColored("📝 История пуста\n", colorYellow)
return
}
// Сортируем записи по времени в убывающем порядке (новые сначала)
sort.Slice(items, func(i, j int) bool {
return items[i].Timestamp.After(items[j].Timestamp)
})
printColored("📝 История (из файла):\n", colorYellow)
for _, h := range items {
ts := h.Timestamp.Format("2006-01-02 15:04:05")
fmt.Printf("%d. [%s] %s → %s\n", h.Index, ts, h.Command, h.Response)
fmt.Printf("%s\n", "========================================================================================")
}
}
func ViewHistoryEntry(historyPath string, id int, printColored func(string, string), colorYellow, colorBold, colorGreen string) {
items, err := read(historyPath)
if err != nil || len(items) == 0 {
fmt.Println("История пуста или недоступна")
return
}
var h *HistoryEntry
for i := range items {
if items[i].Index == id {
h = &items[i]
break
}
}
if h == nil {
fmt.Println("Запись не найдена")
return
}
printColored("\n📋 Команда:\n", colorYellow)
printColored(fmt.Sprintf(" %s\n\n", h.Response), colorBold+colorGreen)
if strings.TrimSpace(h.Explanation) != "" {
printColored("\n📖 Подробное объяснение:\n\n", colorYellow)
fmt.Println(h.Explanation)
}
}
func DeleteHistoryEntry(historyPath string, id int) error {
items, err := read(historyPath)
if err != nil || len(items) == 0 {
return fmt.Errorf("история пуста или недоступна")
}
pos := -1
for i := range items {
if items[i].Index == id {
pos = i
break
}
}
if pos == -1 {
return fmt.Errorf("запись не найдена")
}
items = append(items[:pos], items[pos+1:]...)
return write(historyPath, items)
}
func SaveToHistory(historyPath, resultFolder, cmdText, response, system string, explanationOptional ...string) error {
var explanation string
if len(explanationOptional) > 0 {
explanation = explanationOptional[0]
}
items, _ := read(historyPath)
duplicateIndex := -1
for i, h := range items {
if strings.EqualFold(strings.TrimSpace(h.Command), strings.TrimSpace(cmdText)) {
duplicateIndex = i
break
}
}
entry := HistoryEntry{
Index: len(items) + 1,
Command: cmdText,
Response: response,
Explanation: explanation,
System: system,
Timestamp: time.Now(),
}
if duplicateIndex == -1 {
items = append(items, entry)
return write(historyPath, items)
}
fmt.Printf("\nЗапрос уже есть в истории от %s. Перезаписать? (y/N): ", items[duplicateIndex].Timestamp.Format("2006-01-02 15:04:05"))
var ans string
fmt.Scanln(&ans)
if strings.ToLower(ans) == "y" || strings.ToLower(ans) == "yes" {
entry.Index = items[duplicateIndex].Index
items[duplicateIndex] = entry
return write(historyPath, items)
}
return nil
}
// SaveToHistoryFromHistory сохраняет запись из истории без запроса о перезаписи
func SaveToHistoryFromHistory(historyPath, resultFolder, cmdText, response, system, explanation string) error {
items, _ := read(historyPath)
duplicateIndex := -1
for i, h := range items {
if strings.EqualFold(strings.TrimSpace(h.Command), strings.TrimSpace(cmdText)) {
duplicateIndex = i
break
}
}
entry := HistoryEntry{
Index: len(items) + 1,
Command: cmdText,
Response: response,
Explanation: explanation,
System: system,
Timestamp: time.Now(),
}
if duplicateIndex == -1 {
items = append(items, entry)
return write(historyPath, items)
}
// Если дубликат найден, перезаписываем без запроса
entry.Index = items[duplicateIndex].Index
items[duplicateIndex] = entry
return write(historyPath, items)
}
func CheckAndSuggestFromHistory(historyPath, cmdText string) (bool, *HistoryEntry) {
items, err := read(historyPath)
if err != nil || len(items) == 0 {
return false, nil
}
for _, h := range items {
if strings.EqualFold(strings.TrimSpace(h.Command), strings.TrimSpace(cmdText)) {
fmt.Printf("\nВ истории найден похожий запрос от %s. Показать сохраненный результат? (y/N): ", h.Timestamp.Format("2006-01-02 15:04:05"))
var ans string
fmt.Scanln(&ans)
if strings.ToLower(ans) == "y" || strings.ToLower(ans) == "yes" {
return true, &h
}
break
}
}
return false, nil
}