diff options
| author | Grail Finder <wohilas@gmail.com> | 2025-11-21 16:48:44 +0300 |
|---|---|---|
| committer | Grail Finder <wohilas@gmail.com> | 2025-11-21 16:48:44 +0300 |
| commit | 5fe03fa66c30f5d7ca6cdf9de1b1cfa2c38d6a45 (patch) | |
| tree | 5b2f3a49b934eaadaf9bcce4454169ce00985579 | |
| parent | bccbbe657e3aff084370b442efddeca7fbbf3e3e (diff) | |
Enha: rag loader
| -rw-r--r-- | tables.go | 152 | ||||
| -rw-r--r-- | tui.go | 36 |
2 files changed, 115 insertions, 73 deletions
@@ -307,59 +307,105 @@ func makeRAGTable(fileList []string) *tview.Flex { return ragflex } -// func makeLoadedRAGTable(fileList []string) *tview.Table { -// actions := []string{"delete"} -// rows, cols := len(fileList), len(actions)+1 -// fileTable := tview.NewTable(). -// SetBorders(true) -// for r := 0; r < rows; r++ { -// for c := 0; c < cols; c++ { -// color := tcell.ColorWhite -// if c < 1 { -// fileTable.SetCell(r, c, -// tview.NewTableCell(fileList[r]). -// SetTextColor(color). -// SetAlign(tview.AlignCenter)) -// } else { -// fileTable.SetCell(r, c, -// tview.NewTableCell(actions[c-1]). -// SetTextColor(color). -// SetAlign(tview.AlignCenter)) -// } -// } -// } -// fileTable.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) { -// if key == tcell.KeyEsc || key == tcell.KeyF1 { -// pages.RemovePage(RAGPage) -// return -// } -// if key == tcell.KeyEnter { -// fileTable.SetSelectable(true, true) -// } -// }).SetSelectedFunc(func(row int, column int) { -// defer pages.RemovePage(RAGPage) -// tc := fileTable.GetCell(row, column) -// tc.SetTextColor(tcell.ColorRed) -// fileTable.SetSelectable(false, false) -// fpath := fileList[row] -// // notification := fmt.Sprintf("chat: %s; action: %s", fpath, tc.Text) -// switch tc.Text { -// case "delete": -// if err := ragger.RemoveFile(fpath); err != nil { -// logger.Error("failed to delete file", "filename", fpath, "error", err) -// return -// } -// if err := notifyUser("chat deleted", fpath+" was deleted"); err != nil { -// logger.Error("failed to send notification", "error", err) -// } -// return -// default: -// // pages.RemovePage(RAGPage) -// return -// } -// }) -// return fileTable -// } +func makeLoadedRAGTable(fileList []string) *tview.Flex { + actions := []string{"delete"} + rows, cols := len(fileList), len(actions)+1 + // Add 1 extra row for the "exit" option at the top + fileTable := tview.NewTable(). + SetBorders(true) + longStatusView := tview.NewTextView() + longStatusView.SetText("Loaded RAG files list") + longStatusView.SetBorder(true).SetTitle("status") + longStatusView.SetChangedFunc(func() { + app.Draw() + }) + ragflex := tview.NewFlex().SetDirection(tview.FlexRow). + AddItem(longStatusView, 0, 10, false). + AddItem(fileTable, 0, 60, true) + + // Add the exit option as the first row (row 0) + fileTable.SetCell(0, 0, + tview.NewTableCell("Exit Loaded Files manager"). + SetTextColor(tcell.ColorWhite). + SetAlign(tview.AlignCenter)) + fileTable.SetCell(0, 1, + tview.NewTableCell("(Close without action)"). + SetTextColor(tcell.ColorGray). + SetAlign(tview.AlignCenter)) + fileTable.SetCell(0, 2, + tview.NewTableCell("exit"). + SetTextColor(tcell.ColorGray). + SetAlign(tview.AlignCenter)) + + // Add the file rows starting from row 1 + for r := 0; r < rows; r++ { + for c := 0; c < cols; c++ { + color := tcell.ColorWhite + if c < 1 { + fileTable.SetCell(r+1, c, // +1 to account for the exit row at index 0 + tview.NewTableCell(fileList[r]). + SetTextColor(color). + SetAlign(tview.AlignCenter)) + } else { + fileTable.SetCell(r+1, c, // +1 to account for the exit row at index 0 + tview.NewTableCell(actions[c-1]). + SetTextColor(color). + SetAlign(tview.AlignCenter)) + } + } + } + + fileTable.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) { + if key == tcell.KeyEsc || key == tcell.KeyF1 || key == tcell.Key('x') || key == tcell.KeyCtrlX { + pages.RemovePage(RAGLoadedPage) + return + } + if key == tcell.KeyEnter { + fileTable.SetSelectable(true, true) + } + }).SetSelectedFunc(func(row int, column int) { + tc := fileTable.GetCell(row, column) + tc.SetTextColor(tcell.ColorRed) + fileTable.SetSelectable(false, false) + + // Check if the selected row is the exit row (row 0) - do this first to avoid index issues + if row == 0 { + pages.RemovePage(RAGLoadedPage) + return + } + + // For file rows, get the filename (row index - 1 because of the exit row at index 0) + fpath := fileList[row-1] // -1 to account for the exit row at index 0 + + switch tc.Text { + case "delete": + if err := ragger.RemoveFile(fpath); err != nil { + logger.Error("failed to delete file from RAG", "filename", fpath, "error", err) + longStatusView.SetText(fmt.Sprintf("Error deleting file: %v", err)) + return + } + if err := notifyUser("RAG file deleted", fpath+" was deleted from RAG system"); err != nil { + logger.Error("failed to send notification", "error", err) + } + longStatusView.SetText(fpath + " was deleted from RAG system") + return + default: + pages.RemovePage(RAGLoadedPage) + return + } + }) + + // Add input capture to the flex container to handle 'x' key for closing + ragflex.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { + if event.Key() == tcell.KeyRune && event.Rune() == 'x' { + pages.RemovePage(RAGLoadedPage) + return nil + } + return event + }) + + return ragflex +} func makeAgentTable(agentList []string) *tview.Table { actions := []string{"filepath", "load"} @@ -39,6 +39,7 @@ var ( helpPage = "helpPage" renamePage = "renamePage" RAGPage = "RAGPage" + RAGLoadedPage = "RAGLoadedPage" propsPage = "propsPage" codeBlockPage = "codeBlockPage" imgPage = "imgPage" @@ -75,6 +76,7 @@ var ( [yellow]Ctrl+j[white]: if chat agent is char.png will show the image; then any key to return [yellow]Ctrl+a[white]: interrupt tts (needs tts server) [yellow]Ctrl+g[white]: open RAG file manager (load files for context retrieval) +[yellow]Ctrl+y[white]: list loaded RAG files (view and manage loaded files) [yellow]Ctrl+q[white]: cycle through mentioned chars in chat, to pick persona to send next msg as [yellow]Ctrl+x[white]: cycle through mentioned chars in chat, to pick persona to send next msg as (for llm) RAG Window: [yellow]x[white]: close window | [yellow]Enter[white]: select action @@ -823,26 +825,6 @@ func init() { pages.AddPage(imgPage, imgView, true, true) return nil } - // DEPRECATED: rag is deprecated until I change my mind - // if event.Key() == tcell.KeyCtrlR && cfg.HFToken != "" { - // // rag load - // // menu of the text files from defined rag directory - // files, err := os.ReadDir(cfg.RAGDir) - // if err != nil { - // logger.Error("failed to read dir", "dir", cfg.RAGDir, "error", err) - // return nil - // } - // fileList := []string{} - // for _, f := range files { - // if f.IsDir() { - // continue - // } - // fileList = append(fileList, f.Name()) - // } - // chatRAGTable := makeRAGTable(fileList) - // pages.AddPage(RAGPage, chatRAGTable, true, true) - // return nil - // } if event.Key() == tcell.KeyCtrlR && cfg.STT_ENABLED { defer updateStatusLine() if asr.IsRecording() { @@ -961,6 +943,20 @@ func init() { pages.AddPage(RAGPage, chatRAGTable, true, true) return nil } + if event.Key() == tcell.KeyCtrlY { // Use Ctrl+Y to list loaded RAG files + // List files already loaded into the RAG system + fileList, err := ragger.ListLoaded() + if err != nil { + logger.Error("failed to list loaded RAG files", "error", err) + if notifyerr := notifyUser("failed to list RAG files", err.Error()); notifyerr != nil { + logger.Error("failed to send notification", "error", notifyerr) + } + return nil + } + chatLoadedRAGTable := makeLoadedRAGTable(fileList) + pages.AddPage(RAGLoadedPage, chatLoadedRAGTable, true, true) + return nil + } // cannot send msg in editMode or botRespMode if event.Key() == tcell.KeyEscape && !editMode && !botRespMode { // read all text into buffer |
