own-rag-cli 0.0.1-snapshot
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MCP_USAGE.md +315 -0
- package/README.md +133 -0
- package/bin/docker-compose.yml +21 -0
- package/bin/download_model_from_hugginface.py +219 -0
- package/bin/download_model_from_modelscope.py +26 -0
- package/bin/indexer_full.py +1426 -0
- package/bin/mcp_server.py +1433 -0
- package/bin/postinstall.sh +102 -0
- package/bin/rag-remove.sh +198 -0
- package/bin/rag-wrapper.sh +186 -0
- package/bin/requirements.txt +21 -0
- package/chroma_monitor.sh +857 -0
- package/how-its-work.md +285 -0
- package/package.json +49 -0
- package/rag-setup-macos.run +1129 -0
- package/rag-setup.run +1179 -0
|
@@ -0,0 +1,857 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# chroma_monitor.sh — Monitor do banco de dados ChromaDB
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Uso:
|
|
6
|
+
# ./chroma_monitor.sh # menu interativo
|
|
7
|
+
# ./chroma_monitor.sh chunks # contagem de chunks (roda uma vez)
|
|
8
|
+
# ./chroma_monitor.sh watch # monitora chunks em tempo real (loop)
|
|
9
|
+
# ./chroma_monitor.sh disk # tamanho do banco no disco (watch)
|
|
10
|
+
# ./chroma_monitor.sh logs # logs em tempo real do container Docker
|
|
11
|
+
# ./chroma_monitor.sh mcp-logs # logs de uso das ferramentas MCP
|
|
12
|
+
# ./chroma_monitor.sh mcp-summary # resumo agregado de uso MCP (24h + geral)
|
|
13
|
+
# ./chroma_monitor.sh full # painel completo: chunks + disco + detalhes
|
|
14
|
+
# ./chroma_monitor.sh reset # zera o ChromaDB (remove todas as coleções)
|
|
15
|
+
# =============================================================================
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Cores e formatação
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
|
22
|
+
BLUE='\033[0;34m'; CYAN='\033[0;36m'; MAGENTA='\033[0;35m'
|
|
23
|
+
BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
# Configuração
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
CHROMA_HOST="localhost"
|
|
29
|
+
CHROMA_PORT="8000"
|
|
30
|
+
RAG_DB_DIR="${HOME}/.rag_db"
|
|
31
|
+
VENV_DIR="${HOME}/.rag_venv"
|
|
32
|
+
VENV_PYTHON="${VENV_DIR}/bin/python3"
|
|
33
|
+
VENV_PIP="${VENV_DIR}/bin/pip"
|
|
34
|
+
CONTAINER_NAME="chromadb-rag"
|
|
35
|
+
MCP_USAGE_LOG="${MCP_USAGE_LOG:-${HOME}/.rag_db/mcp_usage.log}"
|
|
36
|
+
REFRESH_INTERVAL=5
|
|
37
|
+
UI_LANG="${CHROMA_MONITOR_LANG:-${RAG_SETUP_LANG:-}}"
|
|
38
|
+
YES_NO_HINT="[s/N]"
|
|
39
|
+
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
# Idioma e i18n
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
set_lang_defaults() {
|
|
45
|
+
if [[ "$UI_LANG" == "en-us" ]]; then
|
|
46
|
+
YES_NO_HINT="[y/N]"
|
|
47
|
+
else
|
|
48
|
+
YES_NO_HINT="[s/N]"
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
select_ui_language() {
|
|
53
|
+
if [[ -n "$UI_LANG" ]]; then
|
|
54
|
+
UI_LANG="$(echo "$UI_LANG" | tr '[:upper:]' '[:lower:]')"
|
|
55
|
+
case "$UI_LANG" in
|
|
56
|
+
pt-br|pt|en-us|en) ;;
|
|
57
|
+
*) UI_LANG="pt-br" ;;
|
|
58
|
+
esac
|
|
59
|
+
[[ "$UI_LANG" == "pt" ]] && UI_LANG="pt-br"
|
|
60
|
+
[[ "$UI_LANG" == "en" ]] && UI_LANG="en-us"
|
|
61
|
+
set_lang_defaults
|
|
62
|
+
return
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if [[ ! -t 0 ]]; then
|
|
66
|
+
UI_LANG="pt-br"
|
|
67
|
+
set_lang_defaults
|
|
68
|
+
return
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
echo -e "${GREEN}Idioma / Language: [1] PT-BR [2] EN-US (padrão/default: 1)${NC}"
|
|
73
|
+
read -r -p "> " LANG_CHOICE
|
|
74
|
+
case "$LANG_CHOICE" in
|
|
75
|
+
2|en|EN|en-us|EN-US|english|English) UI_LANG="en-us" ;;
|
|
76
|
+
*) UI_LANG="pt-br" ;;
|
|
77
|
+
esac
|
|
78
|
+
set_lang_defaults
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
t() {
|
|
82
|
+
local key="$1"
|
|
83
|
+
if [[ "$UI_LANG" == "en-us" ]]; then
|
|
84
|
+
case "$key" in
|
|
85
|
+
err_prefix) echo "ERROR" ;;
|
|
86
|
+
py_missing) echo "python3 not found. Install: sudo apt install python3 python3-venv" ;;
|
|
87
|
+
py_venv_missing) echo "python3-venv not found. Install: sudo apt install python3-venv" ;;
|
|
88
|
+
creating_venv) echo "Creating virtual environment at" ;;
|
|
89
|
+
venv_created) echo "Venv created." ;;
|
|
90
|
+
installing_chromadb) echo "Installing chromadb in venv (first time only)..." ;;
|
|
91
|
+
chromadb_installed) echo "chromadb installed." ;;
|
|
92
|
+
header_title) echo "ChromaDB Monitor — Local RAG" ;;
|
|
93
|
+
db_label) echo "Database" ;;
|
|
94
|
+
data_label) echo "Data" ;;
|
|
95
|
+
querying_chroma) echo "Querying ChromaDB at" ;;
|
|
96
|
+
press_ctrl_c) echo "Press Ctrl+C to exit." ;;
|
|
97
|
+
dir_not_found) echo "Directory not found:" ;;
|
|
98
|
+
db_not_init) echo "Database not initialized yet." ;;
|
|
99
|
+
monitoring_size) echo "Monitoring size of" ;;
|
|
100
|
+
files_in_db) echo "Files in database" ;;
|
|
101
|
+
size_label) echo "Size" ;;
|
|
102
|
+
internal_files_short) echo "Internal files" ;;
|
|
103
|
+
docker_not_found) echo "Docker not found." ;;
|
|
104
|
+
container_not_running) echo "Container is not running:" ;;
|
|
105
|
+
active_containers) echo "Active containers:" ;;
|
|
106
|
+
none) echo "None." ;;
|
|
107
|
+
showing_logs) echo "Showing logs from" ;;
|
|
108
|
+
logs_tip) echo "Tip: run indexer in another terminal to see incoming requests." ;;
|
|
109
|
+
mcp_log_missing) echo "MCP log file not found:" ;;
|
|
110
|
+
mcp_log_hint1) echo "File is created automatically when MCP server receives calls." ;;
|
|
111
|
+
mcp_log_hint2) echo "Restart/update mcp-rag-server and use an MCP tool." ;;
|
|
112
|
+
mcp_log_hint_short) echo "File is created automatically when MCP server receives calls." ;;
|
|
113
|
+
showing_mcp_usage) echo "Showing MCP usage in real time (Ctrl+C to exit)" ;;
|
|
114
|
+
source) echo "Source" ;;
|
|
115
|
+
panel_updates) echo "Panel updates every" ;;
|
|
116
|
+
container_docker) echo "Docker container" ;;
|
|
117
|
+
running) echo "running" ;;
|
|
118
|
+
started) echo "started" ;;
|
|
119
|
+
offline) echo "offline" ;;
|
|
120
|
+
start_with) echo "Start with" ;;
|
|
121
|
+
disk_db) echo "Database on disk" ;;
|
|
122
|
+
internal_files) echo "internal files in" ;;
|
|
123
|
+
collections_chunks) echo "Collections and chunks" ;;
|
|
124
|
+
last_update) echo "Last update" ;;
|
|
125
|
+
next_in) echo "next in" ;;
|
|
126
|
+
reset_attention) echo "[WARNING] This action will delete all ChromaDB collections and chunks." ;;
|
|
127
|
+
reset_irreversible) echo "This operation is irreversible." ;;
|
|
128
|
+
confirm_continue) echo "Continue?" ;;
|
|
129
|
+
confirm_type_reset) echo "Type RESET to confirm:" ;;
|
|
130
|
+
reset_cancelled) echo "Reset canceled." ;;
|
|
131
|
+
status_online) echo "Status: ● ChromaDB online" ;;
|
|
132
|
+
status_offline) echo "Status: ● ChromaDB offline" ;;
|
|
133
|
+
choose_option) echo "Choose an option:" ;;
|
|
134
|
+
menu_1) echo "[1] Count chunks now (single snapshot)" ;;
|
|
135
|
+
menu_2) echo "[2] Watch chunks in real time (updates every ${REFRESH_INTERVAL}s)" ;;
|
|
136
|
+
menu_3) echo "[3] Watch disk size (watch ~/.rag_db)" ;;
|
|
137
|
+
menu_4) echo "[4] Show Docker logs (HTTP requests to ChromaDB)" ;;
|
|
138
|
+
menu_5) echo "[5] Show MCP usage logs (actor + tool)" ;;
|
|
139
|
+
menu_6) echo "[6] MCP usage summary (top tools/actors + 24h)" ;;
|
|
140
|
+
menu_7) echo "[7] Full dashboard (all in one, auto refresh)" ;;
|
|
141
|
+
menu_8) echo "[8] Reset ChromaDB (deletes all collections)" ;;
|
|
142
|
+
menu_0) echo "[0] Exit" ;;
|
|
143
|
+
option_prompt) echo "Option:" ;;
|
|
144
|
+
invalid_option) echo "Invalid option." ;;
|
|
145
|
+
unknown_mode) echo "Unknown mode" ;;
|
|
146
|
+
usage) echo "Usage: $0 [chunks|watch|disk|logs|mcp-logs|mcp-summary|full|reset|menu]" ;;
|
|
147
|
+
*) echo "$key" ;;
|
|
148
|
+
esac
|
|
149
|
+
else
|
|
150
|
+
case "$key" in
|
|
151
|
+
err_prefix) echo "ERRO" ;;
|
|
152
|
+
py_missing) echo "python3 não encontrado. Instale: sudo apt install python3 python3-venv" ;;
|
|
153
|
+
py_venv_missing) echo "python3-venv não encontrado. Instale: sudo apt install python3-venv" ;;
|
|
154
|
+
creating_venv) echo "Criando ambiente virtual em" ;;
|
|
155
|
+
venv_created) echo "Venv criado." ;;
|
|
156
|
+
installing_chromadb) echo "Instalando chromadb no venv (necessário apenas na primeira vez)..." ;;
|
|
157
|
+
chromadb_installed) echo "chromadb instalado." ;;
|
|
158
|
+
header_title) echo "Monitor ChromaDB — RAG Local" ;;
|
|
159
|
+
db_label) echo "Banco" ;;
|
|
160
|
+
data_label) echo "Dados" ;;
|
|
161
|
+
querying_chroma) echo "Consultando ChromaDB em" ;;
|
|
162
|
+
press_ctrl_c) echo "Pressione Ctrl+C para sair." ;;
|
|
163
|
+
dir_not_found) echo "Diretório não encontrado:" ;;
|
|
164
|
+
db_not_init) echo "O banco ainda não foi inicializado." ;;
|
|
165
|
+
monitoring_size) echo "Monitorando tamanho de" ;;
|
|
166
|
+
files_in_db) echo "Arquivos no banco" ;;
|
|
167
|
+
size_label) echo "Tamanho" ;;
|
|
168
|
+
internal_files_short) echo "Arquivos internos" ;;
|
|
169
|
+
docker_not_found) echo "Docker não encontrado." ;;
|
|
170
|
+
container_not_running) echo "Container não está rodando:" ;;
|
|
171
|
+
active_containers) echo "Containers ativos:" ;;
|
|
172
|
+
none) echo "Nenhum." ;;
|
|
173
|
+
showing_logs) echo "Exibindo logs de" ;;
|
|
174
|
+
logs_tip) echo "Dica: rode o indexer em outro terminal para ver as requisições entrando." ;;
|
|
175
|
+
mcp_log_missing) echo "Arquivo de log MCP não encontrado:" ;;
|
|
176
|
+
mcp_log_hint1) echo "O arquivo será criado automaticamente quando o MCP Server receber chamadas." ;;
|
|
177
|
+
mcp_log_hint2) echo "Reinicie/atualize o mcp-rag-server e use alguma ferramenta MCP." ;;
|
|
178
|
+
mcp_log_hint_short) echo "O arquivo será criado automaticamente quando o MCP Server receber chamadas." ;;
|
|
179
|
+
showing_mcp_usage) echo "Exibindo uso MCP em tempo real (Ctrl+C para sair)" ;;
|
|
180
|
+
source) echo "Fonte" ;;
|
|
181
|
+
panel_updates) echo "Painel atualiza a cada" ;;
|
|
182
|
+
container_docker) echo "Container Docker" ;;
|
|
183
|
+
running) echo "rodando" ;;
|
|
184
|
+
started) echo "iniciado" ;;
|
|
185
|
+
offline) echo "offline" ;;
|
|
186
|
+
start_with) echo "Inicie com" ;;
|
|
187
|
+
disk_db) echo "Banco em disco" ;;
|
|
188
|
+
internal_files) echo "arquivos internos em" ;;
|
|
189
|
+
collections_chunks) echo "Coleções e Chunks" ;;
|
|
190
|
+
last_update) echo "Última atualização" ;;
|
|
191
|
+
next_in) echo "próxima em" ;;
|
|
192
|
+
reset_attention) echo "[ATENÇÃO] Esta ação vai apagar todas as coleções e chunks do ChromaDB." ;;
|
|
193
|
+
reset_irreversible) echo "Essa operação é irreversível." ;;
|
|
194
|
+
confirm_continue) echo "Deseja continuar?" ;;
|
|
195
|
+
confirm_type_reset) echo "Digite ZERAR para confirmar:" ;;
|
|
196
|
+
reset_cancelled) echo "Reset cancelado." ;;
|
|
197
|
+
status_online) echo "Status: ● ChromaDB online" ;;
|
|
198
|
+
status_offline) echo "Status: ● ChromaDB offline" ;;
|
|
199
|
+
choose_option) echo "Escolha uma opção:" ;;
|
|
200
|
+
menu_1) echo "[1] Contar chunks agora (snapshot único)" ;;
|
|
201
|
+
menu_2) echo "[2] Monitorar chunks em tempo real (atualiza a cada ${REFRESH_INTERVAL}s)" ;;
|
|
202
|
+
menu_3) echo "[3] Monitorar tamanho no disco (watch no ~/.rag_db)" ;;
|
|
203
|
+
menu_4) echo "[4] Ver logs do Docker (requisições HTTP ao ChromaDB)" ;;
|
|
204
|
+
menu_5) echo "[5] Ver logs de uso MCP (quem acessa + ferramenta usada)" ;;
|
|
205
|
+
menu_6) echo "[6] Resumo de uso MCP (top ferramentas/atores e 24h)" ;;
|
|
206
|
+
menu_7) echo "[7] Painel completo (tudo junto, atualiza automático)" ;;
|
|
207
|
+
menu_8) echo "[8] Zerar ChromaDB (apaga todas as coleções)" ;;
|
|
208
|
+
menu_0) echo "[0] Sair" ;;
|
|
209
|
+
option_prompt) echo "Opção:" ;;
|
|
210
|
+
invalid_option) echo "Opção inválida." ;;
|
|
211
|
+
unknown_mode) echo "Modo desconhecido" ;;
|
|
212
|
+
usage) echo "Uso: $0 [chunks|watch|disk|logs|mcp-logs|mcp-summary|full|reset|menu]" ;;
|
|
213
|
+
*) echo "$key" ;;
|
|
214
|
+
esac
|
|
215
|
+
fi
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
log_info() { echo -e "${GREEN}[+]${NC} $*"; }
|
|
219
|
+
log_warn() { echo -e "${YELLOW}[!]${NC} $*"; }
|
|
220
|
+
log_error() { echo -e "${RED}[$(t err_prefix)]${NC} $*" >&2; }
|
|
221
|
+
|
|
222
|
+
# ---------------------------------------------------------------------------
|
|
223
|
+
# Funções: venv e dependências
|
|
224
|
+
# ---------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
ensure_venv() {
|
|
227
|
+
# Garante que o venv existe e tem o chromadb instalado
|
|
228
|
+
if [[ ! -f "${VENV_PYTHON}" ]]; then
|
|
229
|
+
if ! command -v python3 &>/dev/null; then
|
|
230
|
+
log_error "$(t py_missing)"
|
|
231
|
+
exit 1
|
|
232
|
+
fi
|
|
233
|
+
if ! python3 -m venv --help &>/dev/null; then
|
|
234
|
+
log_error "$(t py_venv_missing)"
|
|
235
|
+
exit 1
|
|
236
|
+
fi
|
|
237
|
+
log_info "$(t creating_venv) ${VENV_DIR}..."
|
|
238
|
+
python3 -m venv "${VENV_DIR}"
|
|
239
|
+
log_info "$(t venv_created)"
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
# Instala chromadb no venv se ainda não estiver lá
|
|
243
|
+
if ! "${VENV_PYTHON}" -c "import chromadb" 2>/dev/null; then
|
|
244
|
+
log_info "$(t installing_chromadb)"
|
|
245
|
+
"${VENV_PIP}" install --quiet --upgrade pip
|
|
246
|
+
"${VENV_PIP}" install --quiet chromadb
|
|
247
|
+
log_info "$(t chromadb_installed)"
|
|
248
|
+
fi
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
# ---------------------------------------------------------------------------
|
|
252
|
+
# Funções auxiliares
|
|
253
|
+
# ---------------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
is_chroma_running() {
|
|
256
|
+
"${VENV_PYTHON}" -c "
|
|
257
|
+
import chromadb, sys
|
|
258
|
+
try:
|
|
259
|
+
chromadb.HttpClient(host='${CHROMA_HOST}', port=${CHROMA_PORT}).heartbeat()
|
|
260
|
+
sys.exit(0)
|
|
261
|
+
except:
|
|
262
|
+
sys.exit(1)
|
|
263
|
+
" 2>/dev/null
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
print_header() {
|
|
267
|
+
clear
|
|
268
|
+
echo -e "${BOLD}${BLUE}"
|
|
269
|
+
echo " ╔══════════════════════════════════════════════════════╗"
|
|
270
|
+
printf " ║ %-44s║\n" "$(t header_title)"
|
|
271
|
+
echo " ╚══════════════════════════════════════════════════════╝"
|
|
272
|
+
echo -e "${NC}"
|
|
273
|
+
echo -e " ${DIM}$(t db_label): ${CHROMA_HOST}:${CHROMA_PORT} | $(t data_label): ${RAG_DB_DIR}${NC}"
|
|
274
|
+
echo ""
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
# ---------------------------------------------------------------------------
|
|
278
|
+
# Modo 1: chunks — contagem detalhada (roda uma vez)
|
|
279
|
+
# ---------------------------------------------------------------------------
|
|
280
|
+
cmd_chunks() {
|
|
281
|
+
ensure_venv
|
|
282
|
+
|
|
283
|
+
echo ""
|
|
284
|
+
echo -e "${BOLD}${CYAN} $(t querying_chroma) ${CHROMA_HOST}:${CHROMA_PORT}...${NC}"
|
|
285
|
+
echo ""
|
|
286
|
+
|
|
287
|
+
MONITOR_LANG="${UI_LANG}" "${VENV_PYTHON}" - << 'PYEOF'
|
|
288
|
+
import os
|
|
289
|
+
import sys
|
|
290
|
+
import chromadb
|
|
291
|
+
|
|
292
|
+
CHROMA_HOST = "localhost"
|
|
293
|
+
CHROMA_PORT = 8000
|
|
294
|
+
LANG = os.getenv("MONITOR_LANG", "pt-br").lower()
|
|
295
|
+
IS_EN = LANG == "en-us"
|
|
296
|
+
|
|
297
|
+
BOLD = "\033[1m"
|
|
298
|
+
GREEN = "\033[0;32m"
|
|
299
|
+
CYAN = "\033[0;36m"
|
|
300
|
+
YELLOW = "\033[1;33m"
|
|
301
|
+
RED = "\033[0;31m"
|
|
302
|
+
DIM = "\033[2m"
|
|
303
|
+
NC = "\033[0m"
|
|
304
|
+
|
|
305
|
+
try:
|
|
306
|
+
client = chromadb.HttpClient(host=CHROMA_HOST, port=CHROMA_PORT)
|
|
307
|
+
client.heartbeat()
|
|
308
|
+
except Exception as e:
|
|
309
|
+
if IS_EN:
|
|
310
|
+
print(f"{RED}[ERROR] ChromaDB offline or unreachable: {e}{NC}")
|
|
311
|
+
print(" Check: docker ps | grep chromadb")
|
|
312
|
+
else:
|
|
313
|
+
print(f"{RED}[ERRO] ChromaDB offline ou inacessível: {e}{NC}")
|
|
314
|
+
print(" Verifique: docker ps | grep chromadb")
|
|
315
|
+
sys.exit(1)
|
|
316
|
+
|
|
317
|
+
collections = client.list_collections()
|
|
318
|
+
|
|
319
|
+
if not collections:
|
|
320
|
+
if IS_EN:
|
|
321
|
+
print(f"{YELLOW} No collections found.{NC}")
|
|
322
|
+
print(" Run indexer to populate database.")
|
|
323
|
+
else:
|
|
324
|
+
print(f"{YELLOW} Nenhuma coleção encontrada.{NC}")
|
|
325
|
+
print(" Execute o indexer para popular o banco.")
|
|
326
|
+
sys.exit(0)
|
|
327
|
+
|
|
328
|
+
total_global = 0
|
|
329
|
+
|
|
330
|
+
print(f" {('Collection' if IS_EN else 'Coleção'):<25} {'Chunks':>10} {('Details' if IS_EN else 'Detalhes')}")
|
|
331
|
+
print(f" {'-'*60}")
|
|
332
|
+
|
|
333
|
+
for col in collections:
|
|
334
|
+
count = col.count()
|
|
335
|
+
total_global += count
|
|
336
|
+
|
|
337
|
+
sample = col.get(limit=1, include=["metadatas"])
|
|
338
|
+
meta_keys = []
|
|
339
|
+
if sample["metadatas"]:
|
|
340
|
+
meta_keys = list(sample["metadatas"][0].keys())
|
|
341
|
+
|
|
342
|
+
all_meta = col.get(include=["metadatas"])
|
|
343
|
+
unique_files = set()
|
|
344
|
+
for m in all_meta["metadatas"]:
|
|
345
|
+
if m and "file_path" in m:
|
|
346
|
+
unique_files.add(m["file_path"])
|
|
347
|
+
|
|
348
|
+
file_label = "unique files" if IS_EN else "arquivos únicos"
|
|
349
|
+
print(f" {GREEN}{BOLD}{col.name:<25}{NC} {CYAN}{count:>7} chunks{NC} "
|
|
350
|
+
f"{DIM}({len(unique_files)} {file_label}){NC}")
|
|
351
|
+
if meta_keys:
|
|
352
|
+
fields_label = "fields" if IS_EN else "campos"
|
|
353
|
+
print(f" {'':25} {'':10} {DIM}{fields_label}: {', '.join(meta_keys)}{NC}")
|
|
354
|
+
print()
|
|
355
|
+
|
|
356
|
+
print(f" {'-'*60}")
|
|
357
|
+
if IS_EN:
|
|
358
|
+
print(f" {BOLD}Global total: {CYAN}{total_global} chunks{NC}{BOLD} in {len(collections)} collection(s){NC}")
|
|
359
|
+
else:
|
|
360
|
+
print(f" {BOLD}Total global: {CYAN}{total_global} chunks{NC}{BOLD} em {len(collections)} coleção(ões){NC}")
|
|
361
|
+
print()
|
|
362
|
+
PYEOF
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
# ---------------------------------------------------------------------------
|
|
366
|
+
# Modo 2: watch — atualiza contagem a cada N segundos
|
|
367
|
+
# ---------------------------------------------------------------------------
|
|
368
|
+
cmd_watch() {
|
|
369
|
+
ensure_venv
|
|
370
|
+
|
|
371
|
+
echo -e "${DIM} $(t press_ctrl_c)${NC}"
|
|
372
|
+
echo ""
|
|
373
|
+
|
|
374
|
+
LAST_COUNT=-1
|
|
375
|
+
|
|
376
|
+
while true; do
|
|
377
|
+
RESULT=$("${VENV_PYTHON}" - 2>/dev/null << 'PYEOF'
|
|
378
|
+
import chromadb, sys
|
|
379
|
+
|
|
380
|
+
try:
|
|
381
|
+
client = chromadb.HttpClient(host="localhost", port=8000)
|
|
382
|
+
client.heartbeat()
|
|
383
|
+
cols = client.list_collections()
|
|
384
|
+
total = sum(c.count() for c in cols)
|
|
385
|
+
details = " | ".join(f"{c.name}: {c.count()}" for c in cols)
|
|
386
|
+
print(f"{total}||{details}||online")
|
|
387
|
+
except:
|
|
388
|
+
print("0||||offline")
|
|
389
|
+
PYEOF
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
TOTAL=$(echo "$RESULT" | cut -d'|' -f1)
|
|
393
|
+
DETAILS=$(echo "$RESULT" | cut -d'|' -f3)
|
|
394
|
+
STATUS=$(echo "$RESULT" | cut -d'|' -f5)
|
|
395
|
+
TIMESTAMP=$(date '+%H:%M:%S')
|
|
396
|
+
|
|
397
|
+
if [[ "$STATUS" == "offline" ]]; then
|
|
398
|
+
printf "\r ${RED}[%s]${NC} ChromaDB offline...%20s" "$TIMESTAMP" ""
|
|
399
|
+
else
|
|
400
|
+
DIFF=""
|
|
401
|
+
if [[ "$LAST_COUNT" -ge 0 ]] && [[ "$TOTAL" -ne "$LAST_COUNT" ]]; then
|
|
402
|
+
DELTA=$((TOTAL - LAST_COUNT))
|
|
403
|
+
if [[ "$DELTA" -gt 0 ]]; then
|
|
404
|
+
DIFF=" ${GREEN}(+${DELTA})${NC}"
|
|
405
|
+
else
|
|
406
|
+
DIFF=" ${RED}(${DELTA})${NC}"
|
|
407
|
+
fi
|
|
408
|
+
fi
|
|
409
|
+
|
|
410
|
+
printf "\r ${BOLD}[%s]${NC} Chunks: ${CYAN}${BOLD}%s${NC}%b ${DIM}%s${NC}%30s" \
|
|
411
|
+
"$TIMESTAMP" "$TOTAL" "$DIFF" "$DETAILS" ""
|
|
412
|
+
|
|
413
|
+
LAST_COUNT="$TOTAL"
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
sleep "$REFRESH_INTERVAL"
|
|
417
|
+
done
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
# ---------------------------------------------------------------------------
|
|
421
|
+
# Modo 3: disk — monitora tamanho do banco no disco
|
|
422
|
+
# ---------------------------------------------------------------------------
|
|
423
|
+
cmd_disk() {
|
|
424
|
+
if [[ ! -d "$RAG_DB_DIR" ]]; then
|
|
425
|
+
echo -e "${YELLOW}[!]${NC} $(t dir_not_found) ${RAG_DB_DIR}"
|
|
426
|
+
echo -e " $(t db_not_init)"
|
|
427
|
+
exit 1
|
|
428
|
+
fi
|
|
429
|
+
|
|
430
|
+
echo -e "${DIM} $(t monitoring_size) ${RAG_DB_DIR} (Ctrl+C)${NC}"
|
|
431
|
+
echo ""
|
|
432
|
+
|
|
433
|
+
if command -v watch &>/dev/null; then
|
|
434
|
+
watch -n "$REFRESH_INTERVAL" -d \
|
|
435
|
+
"du -sh ${RAG_DB_DIR} && echo '' && find ${RAG_DB_DIR} -type f | wc -l | xargs -I{} echo '$(t files_in_db): {}'"
|
|
436
|
+
else
|
|
437
|
+
while true; do
|
|
438
|
+
SIZE=$(du -sh "$RAG_DB_DIR" 2>/dev/null | cut -f1)
|
|
439
|
+
FILES=$(find "$RAG_DB_DIR" -type f 2>/dev/null | wc -l)
|
|
440
|
+
printf "\r ${BOLD}[%s]${NC} %s: ${CYAN}${BOLD}%s${NC} | %s: ${DIM}%s${NC}%20s" \
|
|
441
|
+
"$(date '+%H:%M:%S')" "$(t size_label)" "$SIZE" "$(t internal_files_short)" "$FILES" ""
|
|
442
|
+
sleep "$REFRESH_INTERVAL"
|
|
443
|
+
done
|
|
444
|
+
fi
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
# ---------------------------------------------------------------------------
|
|
448
|
+
# Modo 4: logs — logs do container Docker em tempo real
|
|
449
|
+
# ---------------------------------------------------------------------------
|
|
450
|
+
cmd_logs() {
|
|
451
|
+
if ! command -v docker &>/dev/null; then
|
|
452
|
+
log_error "$(t docker_not_found)"
|
|
453
|
+
exit 1
|
|
454
|
+
fi
|
|
455
|
+
|
|
456
|
+
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
457
|
+
echo -e "${YELLOW}[!]${NC} $(t container_not_running) '${CONTAINER_NAME}'."
|
|
458
|
+
echo ""
|
|
459
|
+
echo -e " $(t active_containers)"
|
|
460
|
+
docker ps --format " - {{.Names}} ({{.Status}})" 2>/dev/null || echo " $(t none)"
|
|
461
|
+
exit 1
|
|
462
|
+
fi
|
|
463
|
+
|
|
464
|
+
echo -e "${DIM} $(t showing_logs) '${CONTAINER_NAME}' (Ctrl+C)${NC}"
|
|
465
|
+
echo -e "${DIM} $(t logs_tip)${NC}"
|
|
466
|
+
echo ""
|
|
467
|
+
docker logs -f --tail=30 "$CONTAINER_NAME"
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
# ---------------------------------------------------------------------------
|
|
471
|
+
# Modo 5: mcp-logs — logs de uso do MCP (quem acessa + ferramenta)
|
|
472
|
+
# ---------------------------------------------------------------------------
|
|
473
|
+
cmd_mcp_logs() {
|
|
474
|
+
ensure_venv
|
|
475
|
+
|
|
476
|
+
if [[ ! -f "$MCP_USAGE_LOG" ]]; then
|
|
477
|
+
echo -e "${YELLOW}[!]${NC} $(t mcp_log_missing) ${MCP_USAGE_LOG}"
|
|
478
|
+
echo -e " $(t mcp_log_hint1)"
|
|
479
|
+
echo -e " $(t mcp_log_hint2)"
|
|
480
|
+
exit 1
|
|
481
|
+
fi
|
|
482
|
+
|
|
483
|
+
echo -e "${DIM} $(t showing_mcp_usage)${NC}"
|
|
484
|
+
echo -e "${DIM} $(t source): ${MCP_USAGE_LOG}${NC}"
|
|
485
|
+
echo ""
|
|
486
|
+
|
|
487
|
+
# Formata JSONL em linhas legíveis:
|
|
488
|
+
# [timestamp] actor=<ator> tool=<ferramenta> event=<start/end> status=<status> client=<processo>
|
|
489
|
+
tail -n 50 -f "$MCP_USAGE_LOG" | while IFS= read -r line; do
|
|
490
|
+
[[ -z "$line" ]] && continue
|
|
491
|
+
"${VENV_PYTHON}" - "$line" <<'PYEOF'
|
|
492
|
+
import json
|
|
493
|
+
import sys
|
|
494
|
+
|
|
495
|
+
raw = sys.argv[1]
|
|
496
|
+
try:
|
|
497
|
+
data = json.loads(raw)
|
|
498
|
+
except Exception:
|
|
499
|
+
print(raw)
|
|
500
|
+
sys.exit(0)
|
|
501
|
+
|
|
502
|
+
ts = data.get("timestamp", "-")
|
|
503
|
+
actor = data.get("actor", "-")
|
|
504
|
+
tool = data.get("tool", "-")
|
|
505
|
+
event = data.get("event", "-")
|
|
506
|
+
client = data.get("client_process", "-")
|
|
507
|
+
details = data.get("details", {}) or {}
|
|
508
|
+
status = details.get("status", "-")
|
|
509
|
+
|
|
510
|
+
print(f"[{ts}] actor={actor} tool={tool} event={event} status={status} client={client}")
|
|
511
|
+
PYEOF
|
|
512
|
+
done
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
# ---------------------------------------------------------------------------
|
|
516
|
+
# Modo 6: mcp-summary — visão agregada de uso do MCP
|
|
517
|
+
# ---------------------------------------------------------------------------
|
|
518
|
+
cmd_mcp_summary() {
|
|
519
|
+
ensure_venv
|
|
520
|
+
|
|
521
|
+
if [[ ! -f "$MCP_USAGE_LOG" ]]; then
|
|
522
|
+
echo -e "${YELLOW}[!]${NC} $(t mcp_log_missing) ${MCP_USAGE_LOG}"
|
|
523
|
+
echo -e " $(t mcp_log_hint_short)"
|
|
524
|
+
exit 1
|
|
525
|
+
fi
|
|
526
|
+
|
|
527
|
+
MONITOR_LANG="${UI_LANG}" "${VENV_PYTHON}" - "$MCP_USAGE_LOG" <<'PYEOF'
|
|
528
|
+
import json
|
|
529
|
+
import os
|
|
530
|
+
import sys
|
|
531
|
+
from collections import Counter
|
|
532
|
+
from datetime import datetime, timedelta, timezone
|
|
533
|
+
|
|
534
|
+
LANG = os.getenv("MONITOR_LANG", "pt-br").lower()
|
|
535
|
+
IS_EN = LANG == "en-us"
|
|
536
|
+
|
|
537
|
+
path = sys.argv[1]
|
|
538
|
+
now = datetime.now(timezone.utc)
|
|
539
|
+
window_24h = now - timedelta(hours=24)
|
|
540
|
+
|
|
541
|
+
total_events = 0
|
|
542
|
+
total_calls_end = 0
|
|
543
|
+
ok_calls = 0
|
|
544
|
+
error_calls = 0
|
|
545
|
+
|
|
546
|
+
tools_all = Counter()
|
|
547
|
+
actors_all = Counter()
|
|
548
|
+
tools_24h = Counter()
|
|
549
|
+
actors_24h = Counter()
|
|
550
|
+
status_24h = Counter()
|
|
551
|
+
|
|
552
|
+
def parse_ts(raw: str):
|
|
553
|
+
if not raw:
|
|
554
|
+
return None
|
|
555
|
+
try:
|
|
556
|
+
return datetime.fromisoformat(raw.replace("Z", "+00:00"))
|
|
557
|
+
except Exception:
|
|
558
|
+
return None
|
|
559
|
+
|
|
560
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
561
|
+
for line in f:
|
|
562
|
+
line = line.strip()
|
|
563
|
+
if not line:
|
|
564
|
+
continue
|
|
565
|
+
try:
|
|
566
|
+
item = json.loads(line)
|
|
567
|
+
except Exception:
|
|
568
|
+
continue
|
|
569
|
+
|
|
570
|
+
total_events += 1
|
|
571
|
+
tool = item.get("tool", "-")
|
|
572
|
+
actor = item.get("actor", "-")
|
|
573
|
+
event = item.get("event", "-")
|
|
574
|
+
details = item.get("details", {}) or {}
|
|
575
|
+
status = details.get("status", "-")
|
|
576
|
+
ts = parse_ts(item.get("timestamp", ""))
|
|
577
|
+
|
|
578
|
+
if event == "tool_call_end":
|
|
579
|
+
total_calls_end += 1
|
|
580
|
+
if status == "ok":
|
|
581
|
+
ok_calls += 1
|
|
582
|
+
elif status == "error":
|
|
583
|
+
error_calls += 1
|
|
584
|
+
tools_all[tool] += 1
|
|
585
|
+
actors_all[actor] += 1
|
|
586
|
+
|
|
587
|
+
if ts and ts >= window_24h:
|
|
588
|
+
tools_24h[tool] += 1
|
|
589
|
+
actors_24h[actor] += 1
|
|
590
|
+
status_24h[status] += 1
|
|
591
|
+
|
|
592
|
+
print("MCP usage summary" if IS_EN else "Resumo de uso MCP")
|
|
593
|
+
print("-" * 72)
|
|
594
|
+
print(f"{'Log file' if IS_EN else 'Arquivo de log'}: {path}")
|
|
595
|
+
print(f"{'Total events (start/end)' if IS_EN else 'Eventos totais (start/end)'}: {total_events}")
|
|
596
|
+
print(f"{'Completed calls (tool_call_end)' if IS_EN else 'Chamadas finalizadas (tool_call_end)'}: {total_calls_end}")
|
|
597
|
+
print(f"{'Completed status' if IS_EN else 'Status finalizadas'}: ok={ok_calls} | error={error_calls}")
|
|
598
|
+
print()
|
|
599
|
+
|
|
600
|
+
print("Top tools (overall)" if IS_EN else "Top ferramentas (geral)")
|
|
601
|
+
if tools_all:
|
|
602
|
+
for name, count in tools_all.most_common(10):
|
|
603
|
+
print(f" - {name}: {count}")
|
|
604
|
+
else:
|
|
605
|
+
print(" - no data" if IS_EN else " - sem dados")
|
|
606
|
+
print()
|
|
607
|
+
|
|
608
|
+
print("Top actors (overall)" if IS_EN else "Top atores (geral)")
|
|
609
|
+
if actors_all:
|
|
610
|
+
for name, count in actors_all.most_common(10):
|
|
611
|
+
print(f" - {name}: {count}")
|
|
612
|
+
else:
|
|
613
|
+
print(" - no data" if IS_EN else " - sem dados")
|
|
614
|
+
print()
|
|
615
|
+
|
|
616
|
+
print("Last 24h" if IS_EN else "Ultimas 24h")
|
|
617
|
+
print(f" - {'completed total' if IS_EN else 'total finalizadas'}: {sum(tools_24h.values())}")
|
|
618
|
+
print(f" - status: {dict(status_24h) if status_24h else ({'no_data': 0} if IS_EN else {'sem_dados': 0})}")
|
|
619
|
+
|
|
620
|
+
print(" - top tools (24h)" if IS_EN else " - top ferramentas (24h)")
|
|
621
|
+
if tools_24h:
|
|
622
|
+
for name, count in tools_24h.most_common(10):
|
|
623
|
+
print(f" * {name}: {count}")
|
|
624
|
+
else:
|
|
625
|
+
print(" * no data" if IS_EN else " * sem dados")
|
|
626
|
+
|
|
627
|
+
print(" - top actors (24h)" if IS_EN else " - top atores (24h)")
|
|
628
|
+
if actors_24h:
|
|
629
|
+
for name, count in actors_24h.most_common(10):
|
|
630
|
+
print(f" * {name}: {count}")
|
|
631
|
+
else:
|
|
632
|
+
print(" * no data" if IS_EN else " * sem dados")
|
|
633
|
+
PYEOF
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
# ---------------------------------------------------------------------------
|
|
637
|
+
# Modo 7: full — painel completo
|
|
638
|
+
# ---------------------------------------------------------------------------
|
|
639
|
+
cmd_full() {
|
|
640
|
+
ensure_venv
|
|
641
|
+
|
|
642
|
+
echo -e "${DIM} $(t panel_updates) ${REFRESH_INTERVAL}s — Ctrl+C${NC}"
|
|
643
|
+
echo ""
|
|
644
|
+
sleep 1
|
|
645
|
+
|
|
646
|
+
while true; do
|
|
647
|
+
print_header
|
|
648
|
+
|
|
649
|
+
# Status do container
|
|
650
|
+
echo -e " ${BOLD}$(t container_docker)${NC}"
|
|
651
|
+
if command -v docker &>/dev/null && docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^${CONTAINER_NAME}$"; then
|
|
652
|
+
UPTIME=$(docker inspect --format='{{.State.StartedAt}}' "$CONTAINER_NAME" 2>/dev/null | cut -c1-19 | tr 'T' ' ')
|
|
653
|
+
echo -e " ${GREEN}●${NC} ${CONTAINER_NAME} $(t running) ${DIM}($(t started): ${UPTIME}Z)${NC}"
|
|
654
|
+
else
|
|
655
|
+
echo -e " ${RED}●${NC} ${CONTAINER_NAME} $(t offline)"
|
|
656
|
+
fi
|
|
657
|
+
echo ""
|
|
658
|
+
|
|
659
|
+
# Tamanho em disco
|
|
660
|
+
echo -e " ${BOLD}$(t disk_db)${NC}"
|
|
661
|
+
if [[ -d "$RAG_DB_DIR" ]]; then
|
|
662
|
+
DISK_SIZE=$(du -sh "$RAG_DB_DIR" 2>/dev/null | cut -f1)
|
|
663
|
+
DISK_FILES=$(find "$RAG_DB_DIR" -type f 2>/dev/null | wc -l)
|
|
664
|
+
echo -e " ${CYAN}${DISK_SIZE}${NC} ${DIM}(${DISK_FILES} $(t internal_files) ${RAG_DB_DIR})${NC}"
|
|
665
|
+
else
|
|
666
|
+
echo -e "${YELLOW}$(t dir_not_found) ${RAG_DB_DIR}${NC}"
|
|
667
|
+
fi
|
|
668
|
+
echo ""
|
|
669
|
+
|
|
670
|
+
# Coleções e chunks
|
|
671
|
+
echo -e " ${BOLD}$(t collections_chunks)${NC}"
|
|
672
|
+
MONITOR_LANG="${UI_LANG}" "${VENV_PYTHON}" - 2>/dev/null << 'PYEOF'
|
|
673
|
+
import chromadb, os, sys
|
|
674
|
+
|
|
675
|
+
GREEN = "\033[0;32m"; CYAN = "\033[0;36m"
|
|
676
|
+
YELLOW = "\033[1;33m"; RED = "\033[0;31m"
|
|
677
|
+
BOLD = "\033[1m"; DIM = "\033[2m"; NC = "\033[0m"
|
|
678
|
+
LANG = os.getenv("MONITOR_LANG", "pt-br").lower()
|
|
679
|
+
IS_EN = LANG == "en-us"
|
|
680
|
+
|
|
681
|
+
try:
|
|
682
|
+
client = chromadb.HttpClient(host="localhost", port=8000)
|
|
683
|
+
client.heartbeat()
|
|
684
|
+
except Exception as e:
|
|
685
|
+
msg = "ChromaDB unreachable" if IS_EN else "ChromaDB inacessível"
|
|
686
|
+
print(f" {RED}{msg}: {e}{NC}")
|
|
687
|
+
sys.exit(0)
|
|
688
|
+
|
|
689
|
+
collections = client.list_collections()
|
|
690
|
+
|
|
691
|
+
if not collections:
|
|
692
|
+
if IS_EN:
|
|
693
|
+
print(f" {YELLOW}Database empty — no collections found.{NC}")
|
|
694
|
+
print(" Run: indexer_full.py")
|
|
695
|
+
else:
|
|
696
|
+
print(f" {YELLOW}Banco vazio — nenhuma coleção encontrada.{NC}")
|
|
697
|
+
print(" Execute: indexer_full.py")
|
|
698
|
+
sys.exit(0)
|
|
699
|
+
|
|
700
|
+
total_chunks = 0
|
|
701
|
+
total_files = 0
|
|
702
|
+
|
|
703
|
+
for col in collections:
|
|
704
|
+
count = col.count()
|
|
705
|
+
total_chunks += count
|
|
706
|
+
|
|
707
|
+
all_meta = col.get(include=["metadatas"])
|
|
708
|
+
unique_files = {m["file_path"] for m in all_meta["metadatas"] if m and "file_path" in m}
|
|
709
|
+
total_files += len(unique_files)
|
|
710
|
+
|
|
711
|
+
max_count = max(c.count() for c in collections) or 1
|
|
712
|
+
bar_len = min(30, int(count / max_count * 30))
|
|
713
|
+
bar = "█" * bar_len + "░" * (30 - bar_len)
|
|
714
|
+
|
|
715
|
+
print(f" {GREEN}{BOLD}{col.name}{NC}")
|
|
716
|
+
print(f" {CYAN}{bar}{NC} {BOLD}{count:,}{NC} chunks | {len(unique_files):,} {'files' if IS_EN else 'arquivos'}")
|
|
717
|
+
print()
|
|
718
|
+
|
|
719
|
+
print(f" {'─'*55}")
|
|
720
|
+
if IS_EN:
|
|
721
|
+
print(f" {BOLD}Total: {CYAN}{total_chunks:,} chunks{NC}{BOLD} in {total_files:,} file(s){NC}")
|
|
722
|
+
else:
|
|
723
|
+
print(f" {BOLD}Total: {CYAN}{total_chunks:,} chunks{NC}{BOLD} em {total_files:,} arquivo(s){NC}")
|
|
724
|
+
PYEOF
|
|
725
|
+
|
|
726
|
+
echo ""
|
|
727
|
+
echo -e " ${DIM}$(t last_update): $(date '+%H:%M:%S') — $(t next_in) ${REFRESH_INTERVAL}s${NC}"
|
|
728
|
+
|
|
729
|
+
sleep "$REFRESH_INTERVAL"
|
|
730
|
+
done
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
# ---------------------------------------------------------------------------
|
|
734
|
+
# Modo 8: reset — remove todas as coleções do ChromaDB
|
|
735
|
+
# ---------------------------------------------------------------------------
|
|
736
|
+
cmd_reset() {
|
|
737
|
+
ensure_venv
|
|
738
|
+
|
|
739
|
+
echo ""
|
|
740
|
+
echo -e "${RED}${BOLD}$(t reset_attention)${NC}"
|
|
741
|
+
echo -e "${YELLOW}$(t reset_irreversible)${NC}"
|
|
742
|
+
echo ""
|
|
743
|
+
|
|
744
|
+
read -rp "$(t confirm_continue) ${YES_NO_HINT}: " confirm_reset
|
|
745
|
+
confirm_reset="$(echo "${confirm_reset:-}" | tr '[:upper:]' '[:lower:]')"
|
|
746
|
+
if [[ "$confirm_reset" != "s" && "$confirm_reset" != "sim" && "$confirm_reset" != "y" && "$confirm_reset" != "yes" ]]; then
|
|
747
|
+
log_info "$(t reset_cancelled)"
|
|
748
|
+
exit 0
|
|
749
|
+
fi
|
|
750
|
+
|
|
751
|
+
local reset_keyword="ZERAR"
|
|
752
|
+
if [[ "$UI_LANG" == "en-us" ]]; then
|
|
753
|
+
reset_keyword="RESET"
|
|
754
|
+
fi
|
|
755
|
+
|
|
756
|
+
read -rp "$(t confirm_type_reset) " final_confirmation
|
|
757
|
+
if [[ "${final_confirmation:-}" != "${reset_keyword}" ]]; then
|
|
758
|
+
log_info "$(t reset_cancelled)"
|
|
759
|
+
exit 0
|
|
760
|
+
fi
|
|
761
|
+
|
|
762
|
+
MONITOR_LANG="${UI_LANG}" "${VENV_PYTHON}" - << 'PYEOF'
|
|
763
|
+
import os
|
|
764
|
+
import sys
|
|
765
|
+
import chromadb
|
|
766
|
+
|
|
767
|
+
CHROMA_HOST = "localhost"
|
|
768
|
+
CHROMA_PORT = 8000
|
|
769
|
+
LANG = os.getenv("MONITOR_LANG", "pt-br").lower()
|
|
770
|
+
IS_EN = LANG == "en-us"
|
|
771
|
+
|
|
772
|
+
try:
|
|
773
|
+
client = chromadb.HttpClient(host=CHROMA_HOST, port=CHROMA_PORT)
|
|
774
|
+
client.heartbeat()
|
|
775
|
+
except Exception as e:
|
|
776
|
+
if IS_EN:
|
|
777
|
+
print(f"[ERROR] Could not connect to ChromaDB at {CHROMA_HOST}:{CHROMA_PORT}: {e}")
|
|
778
|
+
else:
|
|
779
|
+
print(f"[ERRO] Não foi possível conectar ao ChromaDB em {CHROMA_HOST}:{CHROMA_PORT}: {e}")
|
|
780
|
+
sys.exit(1)
|
|
781
|
+
|
|
782
|
+
collections = client.list_collections()
|
|
783
|
+
removed = 0
|
|
784
|
+
for col in collections:
|
|
785
|
+
client.delete_collection(name=col.name)
|
|
786
|
+
removed += 1
|
|
787
|
+
|
|
788
|
+
if IS_EN:
|
|
789
|
+
print(f"[+] Reset completed. Collections removed: {removed}")
|
|
790
|
+
else:
|
|
791
|
+
print(f"[+] Reset concluído. Coleções removidas: {removed}")
|
|
792
|
+
PYEOF
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
# ---------------------------------------------------------------------------
|
|
796
|
+
# Menu interativo
|
|
797
|
+
# ---------------------------------------------------------------------------
|
|
798
|
+
cmd_menu() {
|
|
799
|
+
ensure_venv
|
|
800
|
+
print_header
|
|
801
|
+
|
|
802
|
+
if is_chroma_running; then
|
|
803
|
+
echo -e " ${GREEN}${BOLD}$(t status_online)${NC}"
|
|
804
|
+
else
|
|
805
|
+
echo -e " ${RED}${BOLD}$(t status_offline)${NC}"
|
|
806
|
+
echo -e " ${DIM}$(t start_with): docker compose -f ~/docker-chromadb/docker-compose.yml up -d${NC}"
|
|
807
|
+
fi
|
|
808
|
+
echo ""
|
|
809
|
+
echo -e " ${BOLD}$(t choose_option)${NC}"
|
|
810
|
+
echo ""
|
|
811
|
+
echo -e " ${CYAN}$(t menu_1)${NC}"
|
|
812
|
+
echo -e " ${CYAN}$(t menu_2)${NC}"
|
|
813
|
+
echo -e " ${CYAN}$(t menu_3)${NC}"
|
|
814
|
+
echo -e " ${CYAN}$(t menu_4)${NC}"
|
|
815
|
+
echo -e " ${CYAN}$(t menu_5)${NC}"
|
|
816
|
+
echo -e " ${CYAN}$(t menu_6)${NC}"
|
|
817
|
+
echo -e " ${CYAN}$(t menu_7)${NC}"
|
|
818
|
+
echo -e " ${CYAN}$(t menu_8)${NC}"
|
|
819
|
+
echo ""
|
|
820
|
+
echo -e " ${CYAN}$(t menu_0)${NC}"
|
|
821
|
+
echo ""
|
|
822
|
+
read -rp " $(t option_prompt) " choice
|
|
823
|
+
|
|
824
|
+
case "$choice" in
|
|
825
|
+
1) echo ""; cmd_chunks ;;
|
|
826
|
+
2) echo ""; cmd_watch ;;
|
|
827
|
+
3) cmd_disk ;;
|
|
828
|
+
4) cmd_logs ;;
|
|
829
|
+
5) cmd_mcp_logs ;;
|
|
830
|
+
6) cmd_mcp_summary ;;
|
|
831
|
+
7) cmd_full ;;
|
|
832
|
+
8) cmd_reset ;;
|
|
833
|
+
0) exit 0 ;;
|
|
834
|
+
*) echo -e "\n ${YELLOW}$(t invalid_option)${NC}"; sleep 1; cmd_menu ;;
|
|
835
|
+
esac
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
# ---------------------------------------------------------------------------
|
|
839
|
+
# Dispatcher
|
|
840
|
+
# ---------------------------------------------------------------------------
|
|
841
|
+
select_ui_language
|
|
842
|
+
case "${1:-menu}" in
|
|
843
|
+
chunks) cmd_chunks ;;
|
|
844
|
+
watch) cmd_watch ;;
|
|
845
|
+
disk) cmd_disk ;;
|
|
846
|
+
logs) cmd_logs ;;
|
|
847
|
+
mcp-logs) cmd_mcp_logs ;;
|
|
848
|
+
mcp-summary) cmd_mcp_summary ;;
|
|
849
|
+
full) cmd_full ;;
|
|
850
|
+
reset) cmd_reset ;;
|
|
851
|
+
menu) cmd_menu ;;
|
|
852
|
+
*)
|
|
853
|
+
echo -e "${RED}[$(t err_prefix)]${NC} $(t unknown_mode): '$1'"
|
|
854
|
+
echo "$(t usage)"
|
|
855
|
+
exit 1
|
|
856
|
+
;;
|
|
857
|
+
esac
|