-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsmart-cli.sh
More file actions
executable file
·337 lines (292 loc) · 12.4 KB
/
smart-cli.sh
File metadata and controls
executable file
·337 lines (292 loc) · 12.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
#!/bin/bash
set -e
# Obtener la ruta del script actual
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
SCRIPT_PATH="$SCRIPT_DIR/$(basename "${BASH_SOURCE[0]}")"
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/smart-cli"
HISTORY_DIR="$CONFIG_DIR/history"
CONFIG_FILE="$CONFIG_DIR/config.json"
# Debug mode por si falla
DEBUG_MODE=false
# Función de registro para depuración
log_debug() {
if [ "$DEBUG_MODE" = true ]; then
echo "DEBUG: $1" >&2
fi
}
# Crear los directorios si no existen
mkdir -p "$CONFIG_DIR"
mkdir -p "$HISTORY_DIR"
# Función para obtener los tokens de API y configurar el modelo
get_api_tokens() {
log_debug "Obteniendo tokens de API y configurando el modelo"
if [ ! -f "$CONFIG_FILE" ]; then
log_debug "Archivo de configuración no existe, creando uno nuevo"
echo '{"chatgpt_model": "gpt-3.5-turbo", "default_llm": "chatgpt"}' > "$CONFIG_FILE"
fi
CHATGPT_TOKEN=$(jq -r '.chatgpt_token' "$CONFIG_FILE")
CLAUDE_TOKEN=$(jq -r '.claude_token' "$CONFIG_FILE")
CHATGPT_MODEL=$(jq -r '.chatgpt_model' "$CONFIG_FILE")
if [ "$CHATGPT_TOKEN" == "null" ] || [ -z "$CHATGPT_TOKEN" ]; then
read -p "Introduce tu ChatGPT API token: " CHATGPT_TOKEN
jq --arg token "$CHATGPT_TOKEN" '.chatgpt_token = $token' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
fi
if [ "$CLAUDE_TOKEN" == "null" ] || [ -z "$CLAUDE_TOKEN" ]; then
read -p "Introduce tu Claude API token: " CLAUDE_TOKEN
jq --arg token "$CLAUDE_TOKEN" '.claude_token = $token' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
fi
if [ "$CHATGPT_MODEL" == "null" ] || [ -z "$CHATGPT_MODEL" ]; then
CHATGPT_MODEL="gpt-3.5-turbo"
jq --arg model "$CHATGPT_MODEL" '.chatgpt_model = $model' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
fi
log_debug "Tokens y modelo guardados en el archivo de configuración"
log_debug "Configuración actual: $(cat $CONFIG_FILE)"
}
# Función para enviar solicitud a ChatGPT
send_chatgpt_request() {
local history=$1
local model=$(jq -r '.chatgpt_model' "$CONFIG_FILE")
log_debug "Enviando solicitud a ChatGPT. Modelo: $model"
log_debug "Historia: $history"
log_debug "Token: ${CHATGPT_TOKEN:0:5}...${CHATGPT_TOKEN: -5}"
local response=$(curl -s https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $CHATGPT_TOKEN" \
-d '{
"model": "'"${model}"'",
"messages": '"${history}"'
}')
log_debug "Respuesta completa de ChatGPT: $response"
echo "$response" | jq -r '.choices[0].message.content // "Error: No se pudo obtener una respuesta válida"'
}
# Función para enviar solicitud a Claude (implementación básica)
send_claude_request() {
local history=$1
log_debug "Enviando solicitud a Claude"
log_debug "Historia: $history"
log_debug "Token: ${CLAUDE_TOKEN:0:5}...${CLAUDE_TOKEN: -5}"
local response=$(curl -s https://api.anthropic.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $CLAUDE_TOKEN" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-3-opus-20240229",
"max_tokens": 1000,
"messages": '"${history}"'
}')
log_debug "Respuesta completa de Claude: $response"
echo "$response" | jq -r '.content[0].text // "Error: No se pudo obtener una respuesta válida"'
}
# Función para extraer preguntas del historial
extract_questions() {
local history="$1"
echo "$history" | jq -r '.[] | select(.role == "user") | .content'
}
# Función para mostrar el historial y continuar la conversación
show_history() {
echo "Historial de conversaciones:"
files=($(ls -t "$HISTORY_DIR" | head -n 10))
select file in "${files[@]}"; do
if [ -n "$file" ]; then
echo "Archivo seleccionado: $file"
HISTORY=$(cat "$HISTORY_DIR/$file")
echo "$HISTORY"
# Extraer y mostrar solo las preguntas del usuario
echo "Preguntas realizadas en esta conversación:"
extract_questions "$HISTORY"
# Preguntar al usuario si quiere continuar esta conversación
read -p "¿Quieres continuar esta conversación? (s/n): " continue_convo
if [[ $continue_convo == "s" || $continue_convo == "S" ]]; then
# Extraer el LLM del nombre del archivo
if [[ $file == *"_chatgpt_"* ]]; then
LLM="chatgpt"
else
LLM="claude"
fi
# Continuar la conversación
while true; do
read -p "Tú: " user_input
if [ "$user_input" == "exit" ]; then
break
elif [ "$user_input" == "history" ]; then
echo "Preguntas realizadas en esta conversación:"
extract_questions "$HISTORY"
continue
fi
HISTORY=$(echo "$HISTORY" | jq --arg content "$user_input" '. + [{"role": "user", "content": $content}]')
if [ "$LLM" == "chatgpt" ]; then
RESPONSE_MESSAGE=$(send_chatgpt_request "$HISTORY")
else
RESPONSE_MESSAGE=$(send_claude_request "$HISTORY")
fi
echo "$LLM: $RESPONSE_MESSAGE"
HISTORY=$(echo "$HISTORY" | jq --arg content "$RESPONSE_MESSAGE" '. + [{"role": "assistant", "content": $content}]')
done
# Guardar la conversación actualizada
echo "$HISTORY" > "$HISTORY_DIR/$file"
echo "Conversación guardada."
fi
break
else
echo "Selección inválida. Intenta de nuevo."
fi
done
}
# Función para seleccionar el modelo
select_model() {
local llm=$(jq -r '.default_llm' "$CONFIG_FILE")
if [ "$llm" == "chatgpt" ]; then
echo "Selecciona el modelo de ChatGPT:"
models=$(curl -s https://api.openai.com/v1/models \
-H "Authorization: Bearer $CHATGPT_TOKEN" \
| jq -r '.data[].id' | grep -E 'gpt-3.5-turbo|gpt-4')
select model in $models; do
if [ -n "$model" ]; then
jq --arg model "$model" '.chatgpt_model = $model' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
echo "Modelo de ChatGPT seleccionado: $model"
break
else
echo "Selección inválida. Intenta de nuevo."
fi
done
elif [ "$llm" == "claude" ]; then
echo "Selecciona el modelo de Claude:"
# Nota: Esta lista de modelos puede necesitar actualizaciones según las ofertas actuales de Anthropic
models="claude-3-5-sonnet-20240620 claude-3-opus-20240229 claude-3-sonnet-20240229 claude-2.1 claude-2.0 claude-instant-1.2"
select model in $models; do
if [ -n "$model" ]; then
jq --arg model "$model" '.claude_model = $model' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
echo "Modelo de Claude seleccionado: $model"
break
else
echo "Selección inválida. Intenta de nuevo."
fi
done
else
echo "LLM no reconocido. Por favor, selecciona primero un LLM válido usando 'sli -l'."
exit 1
fi
}
# Modo interactivo
interactive_mode() {
local llm=$(jq -r '.default_llm' "$CONFIG_FILE")
local timestamp=$(date +%Y%m%d%H%M%S)
local session_file="$HISTORY_DIR/history_${llm}_$timestamp.json"
local HISTORY='[]'
echo "Modo interactivo iniciado. Escribe 'exit' para salir o 'history' para ver el historial."
while true; do
read -p "Tú: " user_input
if [ "$user_input" == "exit" ]; then
break
elif [ "$user_input" == "history" ]; then
echo "Historial de la conversación:"
echo "$HISTORY" | jq -r '.[] | select(.role == "user") | .content'
continue
fi
HISTORY=$(echo "$HISTORY" | jq --arg content "$user_input" '. + [{"role": "user", "content": $content}]')
if [ "$llm" == "chatgpt" ]; then
response=$(send_chatgpt_request "$HISTORY")
elif [ "$llm" == "claude" ]; then
response=$(send_claude_request "$HISTORY")
else
response="Error: LLM no reconocido"
fi
if [[ $response == Error:* ]]; then
echo "Se produjo un error: $response"
echo "¿Deseas continuar la conversación? (s/n)"
read continue_choice
if [[ $continue_choice != "s" && $continue_choice != "S" ]]; then
break
fi
continue
fi
echo "$llm: $response"
HISTORY=$(echo "$HISTORY" | jq --arg content "$response" '. + [{"role": "assistant", "content": $content}]')
# Guardar la conversación actualizada después de cada interacción
echo "$HISTORY" > "$session_file"
done
echo "Conversación guardada en: $session_file"
}
# Función principal
main() {
log_debug "Iniciando Smart CLI desde $SCRIPT_PATH"
get_api_tokens
# Cargar configuración
DEFAULT_LLM=$(jq -r '.default_llm // "chatgpt"' "$CONFIG_FILE")
CHATGPT_TOKEN=$(jq -r '.chatgpt_token' "$CONFIG_FILE")
CLAUDE_TOKEN=$(jq -r '.claude_token' "$CONFIG_FILE")
CHATGPT_MODEL=$(jq -r '.chatgpt_model' "$CONFIG_FILE")
CLAUDE_MODEL=$(jq -r '.claude_model' "$CONFIG_FILE")
log_debug "Configuración cargada. LLM por defecto: $DEFAULT_LLM"
log_debug "Modelo ChatGPT: $CHATGPT_MODEL"
log_debug "Modelo Claude: $CLAUDE_MODEL"
# Procesar opciones
while getopts ":imhl" opt; do
case ${opt} in
i )
interactive_mode
exit 0
;;
m )
select_model
exit 0
;;
h )
show_history
exit 0
;;
l )
echo "Selecciona el LLM por defecto:"
select LLM in "chatgpt" "claude"; do
if [ -n "$LLM" ]; then
jq --arg llm "$LLM" '.default_llm = $llm' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
echo "LLM seleccionado: $LLM"
break
else
echo "Selección inválida. Intenta de nuevo."
fi
done
exit 0
;;
d )
DEBUG_MODE=true
;;
\? )
echo "Opción inválida: $OPTARG" 1>&2
exit 1
;;
: )
echo "La opción -$OPTARG requiere un argumento." 1>&2
exit 1
;;
esac
done
shift $((OPTIND -1))
# Modo de una sola pregunta si no se pasó ninguna opción
if [ $# -ne 0 ]; then
USER_MESSAGE="$*"
HISTORY=$(jq -n --arg content "$USER_MESSAGE" '[{"role": "user", "content": $content}]')
echo "$DEFAULT_LLM (procesando...)"
if [[ "$DEFAULT_LLM" == "chatgpt" ]]; then
RESPONSE_MESSAGE=$(send_chatgpt_request "$HISTORY")
else
RESPONSE_MESSAGE=$(send_claude_request "$HISTORY")
fi
tput cuu1 && tput el
echo "$DEFAULT_LLM: $RESPONSE_MESSAGE"
# Guardar la interacción en el historial
timestamp=$(date +%Y%m%d%H%M%S)
session_file="$HISTORY_DIR/history_${DEFAULT_LLM}_$timestamp.json"
HISTORY=$(jq --arg content "$RESPONSE_MESSAGE" '. + [{"role": "assistant", "content": $content}]' <<< "$HISTORY")
echo "$HISTORY" > "$session_file"
else
echo "Uso: sli [opción] o sli 'tu pregunta'"
echo "Opciones:"
echo " -i Modo interactivo"
echo " -m Seleccionar modelo"
echo " -h Mostrar historial"
echo " -l Seleccionar LLM (ChatGPT o Claude)"
fi
}
# Ejecutar la función principal
main "$@"