@beltoinc/slyos-sdk 1.5.4 → 1.5.6
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/README.md +434 -434
- package/{slyos-chatbot/app.mjs → create-chatbot.sh} +728 -370
- package/dist/index.js +26 -4
- package/package.json +35 -35
- package/src/index.ts +2147 -0
- package/tsconfig.json +15 -0
- package/slyos-chatbot/.env +0 -4
- package/slyos-chatbot/.env.example +0 -4
- package/slyos-chatbot/README.md +0 -89
- package/slyos-chatbot/package-lock.json +0 -1408
- package/slyos-chatbot/package.json +0 -23
|
@@ -1,370 +1,728 @@
|
|
|
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
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
#################################################################################
|
|
4
|
+
# Slyos Chatbot Setup Script
|
|
5
|
+
#
|
|
6
|
+
# This script creates a fully functional interactive chatbot using the Slyos SDK.
|
|
7
|
+
# Supports both Mac and Windows (via bash/powershell).
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# ./create-chatbot.sh [--api-key YOUR_KEY] [--model MODEL_NAME]
|
|
11
|
+
#
|
|
12
|
+
# Examples:
|
|
13
|
+
# ./create-chatbot.sh
|
|
14
|
+
# ./create-chatbot.sh --api-key sk_123456789 --model quantum-1.7b
|
|
15
|
+
#################################################################################
|
|
16
|
+
|
|
17
|
+
set -e
|
|
18
|
+
|
|
19
|
+
# Color codes for terminal output
|
|
20
|
+
RED='\033[0;31m'
|
|
21
|
+
GREEN='\033[0;32m'
|
|
22
|
+
YELLOW='\033[1;33m'
|
|
23
|
+
BLUE='\033[0;34m'
|
|
24
|
+
CYAN='\033[0;36m'
|
|
25
|
+
NC='\033[0m' # No Color
|
|
26
|
+
|
|
27
|
+
# Default values
|
|
28
|
+
API_KEY=""
|
|
29
|
+
MODEL="quantum-1.7b"
|
|
30
|
+
KB_ID=""
|
|
31
|
+
SLYOS_SERVER="https://api.slyos.world"
|
|
32
|
+
PROJECT_NAME="slyos-chatbot"
|
|
33
|
+
|
|
34
|
+
#################################################################################
|
|
35
|
+
# Helper Functions
|
|
36
|
+
#################################################################################
|
|
37
|
+
|
|
38
|
+
print_header() {
|
|
39
|
+
echo -e "\n${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
|
|
40
|
+
echo -e "${BLUE}║${NC} ${CYAN}Slyos Interactive Chatbot Setup${NC} ${BLUE}║${NC}"
|
|
41
|
+
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}\n"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
print_step() {
|
|
45
|
+
echo -e "${CYAN}▶${NC} $1"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
print_success() {
|
|
49
|
+
echo -e "${GREEN}✓${NC} $1"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
print_error() {
|
|
53
|
+
echo -e "${RED}✗${NC} $1" >&2
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
print_info() {
|
|
57
|
+
echo -e "${YELLOW}ℹ${NC} $1"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#################################################################################
|
|
61
|
+
# Argument Parsing
|
|
62
|
+
#################################################################################
|
|
63
|
+
|
|
64
|
+
while [[ $# -gt 0 ]]; do
|
|
65
|
+
case $1 in
|
|
66
|
+
--api-key)
|
|
67
|
+
API_KEY="$2"
|
|
68
|
+
shift 2
|
|
69
|
+
;;
|
|
70
|
+
--model)
|
|
71
|
+
MODEL="$2"
|
|
72
|
+
shift 2
|
|
73
|
+
;;
|
|
74
|
+
--kb-id)
|
|
75
|
+
KB_ID="$2"
|
|
76
|
+
shift 2
|
|
77
|
+
;;
|
|
78
|
+
-h|--help)
|
|
79
|
+
echo "Usage: $0 [OPTIONS]"
|
|
80
|
+
echo ""
|
|
81
|
+
echo "Options:"
|
|
82
|
+
echo " --api-key KEY Slyos API key (prompted if not provided)"
|
|
83
|
+
echo " --model MODEL AI model to use (default: quantum-1.7b)"
|
|
84
|
+
echo " --kb-id ID Knowledge base ID for RAG (optional)"
|
|
85
|
+
echo " -h, --help Show this help message"
|
|
86
|
+
exit 0
|
|
87
|
+
;;
|
|
88
|
+
*)
|
|
89
|
+
print_error "Unknown option: $1"
|
|
90
|
+
exit 1
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
#################################################################################
|
|
96
|
+
# Main Setup
|
|
97
|
+
#################################################################################
|
|
98
|
+
|
|
99
|
+
print_header
|
|
100
|
+
|
|
101
|
+
# Prompt for API key if not provided
|
|
102
|
+
if [ -z "$API_KEY" ]; then
|
|
103
|
+
if [ -t 0 ]; then
|
|
104
|
+
print_step "Enter your Slyos API key (or press Enter for placeholder)"
|
|
105
|
+
read -r -p " API Key: " API_KEY
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
if [ -z "$API_KEY" ]; then
|
|
109
|
+
API_KEY="YOUR_API_KEY"
|
|
110
|
+
print_info "Using placeholder API key — set SLYOS_API_KEY in .env later"
|
|
111
|
+
else
|
|
112
|
+
print_success "API key configured"
|
|
113
|
+
fi
|
|
114
|
+
else
|
|
115
|
+
print_success "API key provided via arguments"
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# Confirm model selection
|
|
119
|
+
print_step "AI Model Configuration"
|
|
120
|
+
echo -e " Current model: ${YELLOW}${MODEL}${NC}"
|
|
121
|
+
|
|
122
|
+
# Only prompt interactively if stdin is a terminal (not piped)
|
|
123
|
+
if [ -t 0 ]; then
|
|
124
|
+
read -p " Use this model? (y/n, default: y): " -r -n 1
|
|
125
|
+
echo
|
|
126
|
+
if [[ ! $REPLY =~ ^[Yy]?$ ]]; then
|
|
127
|
+
read -p " Enter model name: " -r MODEL
|
|
128
|
+
fi
|
|
129
|
+
fi
|
|
130
|
+
print_success "Model configured: ${YELLOW}${MODEL}${NC}"
|
|
131
|
+
|
|
132
|
+
# Check if project already exists
|
|
133
|
+
if [ -d "$PROJECT_NAME" ]; then
|
|
134
|
+
if [ -t 0 ]; then
|
|
135
|
+
print_error "Project folder '$PROJECT_NAME' already exists!"
|
|
136
|
+
read -p " Remove existing folder and continue? (y/n): " -r -n 1
|
|
137
|
+
echo
|
|
138
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
139
|
+
rm -rf "$PROJECT_NAME"
|
|
140
|
+
print_success "Existing folder removed"
|
|
141
|
+
else
|
|
142
|
+
print_error "Setup cancelled"
|
|
143
|
+
exit 1
|
|
144
|
+
fi
|
|
145
|
+
else
|
|
146
|
+
# Non-interactive: auto-remove
|
|
147
|
+
rm -rf "$PROJECT_NAME"
|
|
148
|
+
print_success "Existing folder removed"
|
|
149
|
+
fi
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# Create project directory
|
|
153
|
+
print_step "Creating project directory: ${CYAN}$PROJECT_NAME${NC}"
|
|
154
|
+
mkdir -p "$PROJECT_NAME"
|
|
155
|
+
cd "$PROJECT_NAME"
|
|
156
|
+
print_success "Project directory created"
|
|
157
|
+
|
|
158
|
+
# Initialize npm
|
|
159
|
+
print_step "Initializing npm package"
|
|
160
|
+
npm init -y > /dev/null 2>&1
|
|
161
|
+
print_success "npm initialized"
|
|
162
|
+
|
|
163
|
+
# Update package.json to use ES modules
|
|
164
|
+
print_step "Configuring ES module support"
|
|
165
|
+
cat > package.json << 'EOF'
|
|
166
|
+
{
|
|
167
|
+
"name": "slyos-chatbot",
|
|
168
|
+
"version": "1.0.0",
|
|
169
|
+
"description": "Interactive chatbot powered by Slyos SDK",
|
|
170
|
+
"main": "app.mjs",
|
|
171
|
+
"type": "module",
|
|
172
|
+
"scripts": {
|
|
173
|
+
"start": "node app.mjs",
|
|
174
|
+
"chat": "node app.mjs"
|
|
175
|
+
},
|
|
176
|
+
"keywords": ["chatbot", "slyos", "ai"],
|
|
177
|
+
"author": "",
|
|
178
|
+
"license": "MIT"
|
|
179
|
+
}
|
|
180
|
+
EOF
|
|
181
|
+
print_success "Package configuration updated"
|
|
182
|
+
|
|
183
|
+
# Install Slyos SDK + dotenv
|
|
184
|
+
print_step "Installing dependencies"
|
|
185
|
+
print_info "This may take a moment..."
|
|
186
|
+
npm install @beltoinc/slyos-sdk dotenv node-fetch > /dev/null 2>&1
|
|
187
|
+
print_success "Dependencies installed"
|
|
188
|
+
|
|
189
|
+
# Create the chatbot application
|
|
190
|
+
print_step "Creating interactive chatbot application: ${CYAN}app.mjs${NC}"
|
|
191
|
+
|
|
192
|
+
cat > app.mjs << 'CHATBOT_EOF'
|
|
193
|
+
#!/usr/bin/env node
|
|
194
|
+
|
|
195
|
+
import 'dotenv/config';
|
|
196
|
+
import readline from 'readline';
|
|
197
|
+
import fetch from 'node-fetch';
|
|
198
|
+
import SlyOS from '@beltoinc/slyos-sdk';
|
|
199
|
+
|
|
200
|
+
// Color codes for terminal output
|
|
201
|
+
const colors = {
|
|
202
|
+
reset: '\x1b[0m',
|
|
203
|
+
bright: '\x1b[1m',
|
|
204
|
+
dim: '\x1b[2m',
|
|
205
|
+
cyan: '\x1b[36m',
|
|
206
|
+
green: '\x1b[32m',
|
|
207
|
+
yellow: '\x1b[33m',
|
|
208
|
+
blue: '\x1b[34m',
|
|
209
|
+
red: '\x1b[31m',
|
|
210
|
+
magenta: '\x1b[35m'
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Configuration
|
|
214
|
+
const config = {
|
|
215
|
+
apiKey: process.env.SLYOS_API_KEY || 'YOUR_API_KEY',
|
|
216
|
+
model: process.env.SLYOS_MODEL || 'quantum-1.7b',
|
|
217
|
+
server: process.env.SLYOS_SERVER || 'https://api.slyos.world',
|
|
218
|
+
kbId: process.env.SLYOS_KB_ID || ''
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// Initialize SlyOS SDK
|
|
222
|
+
let sdk;
|
|
223
|
+
let authToken = null; // Store auth token for direct RAG API calls
|
|
224
|
+
try {
|
|
225
|
+
sdk = new SlyOS({
|
|
226
|
+
apiKey: config.apiKey,
|
|
227
|
+
onProgress: (e) => console.log(`${colors.dim}[${e.progress}%] ${e.message}${colors.reset}`)
|
|
228
|
+
});
|
|
229
|
+
} catch (error) {
|
|
230
|
+
console.error(`${colors.red}Error initializing SDK:${colors.reset}`, error.message);
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Get auth token directly for RAG API calls
|
|
235
|
+
async function getAuthToken() {
|
|
236
|
+
if (authToken) return authToken;
|
|
237
|
+
try {
|
|
238
|
+
const res = await fetch(`${config.server}/api/auth/sdk`, {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
headers: { 'Content-Type': 'application/json' },
|
|
241
|
+
body: JSON.stringify({ apiKey: config.apiKey })
|
|
242
|
+
});
|
|
243
|
+
if (!res.ok) {
|
|
244
|
+
console.log(`${colors.yellow}Auth failed: ${res.status} ${res.statusText}${colors.reset}`);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
const data = await res.json();
|
|
248
|
+
authToken = data.token;
|
|
249
|
+
return authToken;
|
|
250
|
+
} catch (e) {
|
|
251
|
+
console.log(`${colors.yellow}Auth error: ${e.message}${colors.reset}`);
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Create readline interface
|
|
257
|
+
const rl = readline.createInterface({
|
|
258
|
+
input: process.stdin,
|
|
259
|
+
output: process.stdout,
|
|
260
|
+
terminal: true
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Note: conversation history is not used for generation with small models
|
|
264
|
+
// They work better with single prompts
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Print welcome banner
|
|
268
|
+
*/
|
|
269
|
+
function printWelcome() {
|
|
270
|
+
console.clear();
|
|
271
|
+
console.log(`${colors.bright}${colors.cyan}╔════════════════════════════════════════════════════════════╗${colors.reset}`);
|
|
272
|
+
console.log(`${colors.bright}${colors.cyan}║${colors.reset} ${colors.bright}${colors.cyan}║${colors.reset}`);
|
|
273
|
+
console.log(`${colors.bright}${colors.cyan}║${colors.reset} ${colors.bright}Welcome to the Slyos Interactive Chatbot${colors.reset} ${colors.bright}${colors.cyan}║${colors.reset}`);
|
|
274
|
+
console.log(`${colors.bright}${colors.cyan}║${colors.reset} ${colors.bright}${colors.cyan}║${colors.reset}`);
|
|
275
|
+
console.log(`${colors.bright}${colors.cyan}╚════════════════════════════════════════════════════════════╝${colors.reset}\n`);
|
|
276
|
+
|
|
277
|
+
console.log(`${colors.blue}Model:${colors.reset} ${colors.yellow}${config.model}${colors.reset}`);
|
|
278
|
+
console.log(`${colors.blue}Server:${colors.reset} ${colors.yellow}${config.server}${colors.reset}`);
|
|
279
|
+
if (config.kbId) {
|
|
280
|
+
console.log(`${colors.blue}Knowledge Base:${colors.reset} ${colors.green}${config.kbId}${colors.reset} ${colors.green}(RAG enabled)${colors.reset}`);
|
|
281
|
+
} else {
|
|
282
|
+
console.log(`${colors.blue}Knowledge Base:${colors.reset} ${colors.dim}None (plain generation)${colors.reset}`);
|
|
283
|
+
}
|
|
284
|
+
if (config.apiKey === 'YOUR_API_KEY') {
|
|
285
|
+
console.log(`${colors.red}⚠ Using placeholder API key - set SLYOS_API_KEY environment variable${colors.reset}`);
|
|
286
|
+
}
|
|
287
|
+
console.log(`\n${colors.bright}Commands:${colors.reset}`);
|
|
288
|
+
console.log(` ${colors.green}Type your message and press Enter to chat${colors.reset}`);
|
|
289
|
+
console.log(` ${colors.green}Type 'clear' to clear conversation history${colors.reset}`);
|
|
290
|
+
console.log(` ${colors.green}Type 'exit' or 'quit' to end the session${colors.reset}`);
|
|
291
|
+
console.log(`\n${colors.bright}${colors.cyan}─────────────────────────────────────────────────────────────${colors.reset}\n`);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Clean up model output — stop hallucinated Q&A chains, strip artifacts
|
|
296
|
+
*/
|
|
297
|
+
function cleanResponse(text) {
|
|
298
|
+
return text
|
|
299
|
+
// CRITICAL: Cut at first hallucinated Q&A follow-up
|
|
300
|
+
.split(/\n\s*Q\s*:/)[0]
|
|
301
|
+
// Cut at hallucinated role prefixes
|
|
302
|
+
.split(/\n\s*(User|Human|System|Question|A:|Answer):/i)[0]
|
|
303
|
+
// Strip repeated garbage chars
|
|
304
|
+
.replace(/(.)\1{5,}/g, '')
|
|
305
|
+
// Strip leading role prefixes
|
|
306
|
+
.replace(/^(assistant|system|answer|response|AI)\s*[:]\s*/i, '')
|
|
307
|
+
// Strip any remaining mid-response role prefix
|
|
308
|
+
.replace(/^\s*(assistant|AI)\s*[:]\s*/im, '')
|
|
309
|
+
.trim();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Send message to AI and get response — with timing metrics and streaming
|
|
314
|
+
*/
|
|
315
|
+
async function sendMessage(userMessage) {
|
|
316
|
+
try {
|
|
317
|
+
const totalStart = Date.now();
|
|
318
|
+
let assistantMessage = '';
|
|
319
|
+
let sourceInfo = '';
|
|
320
|
+
let retrievalMs = 0;
|
|
321
|
+
let firstTokenMs = 0;
|
|
322
|
+
let generationMs = 0;
|
|
323
|
+
let tokensGenerated = 0;
|
|
324
|
+
|
|
325
|
+
if (config.kbId) {
|
|
326
|
+
// ── RAG MODE ──
|
|
327
|
+
console.log(`${colors.dim}Searching knowledge base...${colors.reset}`);
|
|
328
|
+
const retrievalStart = Date.now();
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
const token = await getAuthToken();
|
|
332
|
+
if (!token) throw new Error('Could not authenticate');
|
|
333
|
+
|
|
334
|
+
const modelCtx = sdk.getModelContextWindow?.() || 2048;
|
|
335
|
+
const memoryMB = 8192; // default; could read from sdk.getDeviceProfile()
|
|
336
|
+
const cpuCores = 8;
|
|
337
|
+
|
|
338
|
+
// Dynamic config based on device + model
|
|
339
|
+
const deviceTier = (memoryMB >= 8192 && cpuCores >= 8) ? 'high' : (memoryMB >= 4096) ? 'mid' : 'low';
|
|
340
|
+
const topK = deviceTier === 'high' ? 3 : deviceTier === 'mid' ? 2 : 1;
|
|
341
|
+
const maxContextChars = modelCtx <= 2048
|
|
342
|
+
? (deviceTier === 'high' ? 600 : deviceTier === 'mid' ? 400 : 300)
|
|
343
|
+
: modelCtx <= 4096
|
|
344
|
+
? (deviceTier === 'high' ? 1500 : 1000)
|
|
345
|
+
: 2000;
|
|
346
|
+
const maxGenTokens = modelCtx <= 2048
|
|
347
|
+
? (deviceTier === 'high' ? 200 : 150)
|
|
348
|
+
: Math.min(400, Math.floor(modelCtx / 4));
|
|
349
|
+
|
|
350
|
+
const ragRes = await fetch(`${config.server}/api/rag/knowledge-bases/${config.kbId}/query`, {
|
|
351
|
+
method: 'POST',
|
|
352
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
|
|
353
|
+
body: JSON.stringify({ query: userMessage, top_k: topK, model_id: config.model })
|
|
354
|
+
});
|
|
355
|
+
if (!ragRes.ok) throw new Error(`RAG ${ragRes.status}`);
|
|
356
|
+
const ragData = await ragRes.json();
|
|
357
|
+
const chunks = (ragData.retrieved_chunks || []).filter(c => (c.similarity_score || 0) > 0.3);
|
|
358
|
+
retrievalMs = Date.now() - retrievalStart;
|
|
359
|
+
|
|
360
|
+
if (chunks.length > 0) {
|
|
361
|
+
const bestChunk = chunks[0];
|
|
362
|
+
let context = bestChunk.content
|
|
363
|
+
.replace(/[^\x20-\x7E\n]/g, ' ').replace(/\s{2,}/g, ' ')
|
|
364
|
+
.replace(/<[^>]+>/g, ' ').replace(/https?:\/\/\S+/g, '')
|
|
365
|
+
.replace(/[{}()\[\]]/g, '').trim();
|
|
366
|
+
if (context.length > maxContextChars) context = context.substring(0, maxContextChars);
|
|
367
|
+
|
|
368
|
+
console.log(`${colors.dim}Context: ${context.length} chars from "${bestChunk.document_name}" [retrieval: ${retrievalMs}ms, tier: ${deviceTier}]${colors.reset}`);
|
|
369
|
+
|
|
370
|
+
// Use messages format — the model's chat template handles formatting
|
|
371
|
+
// This is critical: raw text prompts cause instruct models to generate only 1 token
|
|
372
|
+
const messages = [
|
|
373
|
+
{ role: 'system', content: 'Answer questions using only the following context. Be concise.\n\n' + context },
|
|
374
|
+
{ role: 'user', content: userMessage }
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
// Stream tokens
|
|
378
|
+
const genStart = Date.now();
|
|
379
|
+
let firstToken = false;
|
|
380
|
+
process.stdout.write(`\n${colors.bright}${colors.magenta}AI:${colors.reset} `);
|
|
381
|
+
|
|
382
|
+
if (sdk.generateStream) {
|
|
383
|
+
let streamedAny = false;
|
|
384
|
+
const result = await sdk.generateStream(config.model, messages, {
|
|
385
|
+
temperature: 0.6,
|
|
386
|
+
maxTokens: maxGenTokens,
|
|
387
|
+
onToken: (token, partial) => {
|
|
388
|
+
if (!firstToken) {
|
|
389
|
+
firstTokenMs = Date.now() - genStart;
|
|
390
|
+
firstToken = true;
|
|
391
|
+
}
|
|
392
|
+
streamedAny = true;
|
|
393
|
+
process.stdout.write(token);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
assistantMessage = result.text || '';
|
|
397
|
+
if (!firstToken) firstTokenMs = result.firstTokenMs || 0;
|
|
398
|
+
tokensGenerated = result.tokensGenerated || assistantMessage.split(/\s+/).length;
|
|
399
|
+
// If streaming callback didn't fire, print the full response
|
|
400
|
+
if (!streamedAny && assistantMessage) {
|
|
401
|
+
process.stdout.write(assistantMessage);
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
// Fallback: no streaming
|
|
405
|
+
const response = await sdk.generate(config.model, messages, {
|
|
406
|
+
temperature: 0.6,
|
|
407
|
+
maxTokens: maxGenTokens
|
|
408
|
+
});
|
|
409
|
+
assistantMessage = (typeof response === 'string' ? response : response?.text || '') || '';
|
|
410
|
+
firstTokenMs = Date.now() - genStart;
|
|
411
|
+
tokensGenerated = assistantMessage.split(/\s+/).length;
|
|
412
|
+
process.stdout.write(assistantMessage);
|
|
413
|
+
}
|
|
414
|
+
generationMs = Date.now() - genStart;
|
|
415
|
+
|
|
416
|
+
// Source info
|
|
417
|
+
const sources = [...new Set(chunks.map(c => c.document_name || c.source).filter(Boolean))];
|
|
418
|
+
if (sources.length > 0) sourceInfo = `\n${colors.dim}[Sources: ${sources.join(', ')}]${colors.reset}`;
|
|
419
|
+
} else {
|
|
420
|
+
console.log(`${colors.dim}No relevant context found [retrieval: ${retrievalMs}ms]${colors.reset}`);
|
|
421
|
+
const genStart = Date.now();
|
|
422
|
+
process.stdout.write(`\n${colors.bright}${colors.magenta}AI:${colors.reset} `);
|
|
423
|
+
|
|
424
|
+
const noCtxMessages = [{ role: 'user', content: userMessage }];
|
|
425
|
+
if (sdk.generateStream) {
|
|
426
|
+
let streamedAny = false;
|
|
427
|
+
const result = await sdk.generateStream(config.model, noCtxMessages, {
|
|
428
|
+
temperature: 0.7, maxTokens: 100,
|
|
429
|
+
onToken: (token) => {
|
|
430
|
+
if (!firstTokenMs) firstTokenMs = Date.now() - genStart;
|
|
431
|
+
streamedAny = true;
|
|
432
|
+
process.stdout.write(token);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
assistantMessage = result.text || '';
|
|
436
|
+
tokensGenerated = result.tokensGenerated || assistantMessage.split(/\s+/).length;
|
|
437
|
+
if (!streamedAny && assistantMessage) process.stdout.write(assistantMessage);
|
|
438
|
+
} else {
|
|
439
|
+
const response = await sdk.generate(config.model, noCtxMessages, {
|
|
440
|
+
temperature: 0.7, maxTokens: 100
|
|
441
|
+
});
|
|
442
|
+
assistantMessage = (typeof response === 'string' ? response : response?.text || '') || '';
|
|
443
|
+
firstTokenMs = Date.now() - genStart;
|
|
444
|
+
tokensGenerated = assistantMessage.split(/\s+/).length;
|
|
445
|
+
process.stdout.write(assistantMessage);
|
|
446
|
+
}
|
|
447
|
+
generationMs = Date.now() - genStart;
|
|
448
|
+
}
|
|
449
|
+
} catch (ragErr) {
|
|
450
|
+
console.log(`${colors.yellow}RAG failed: ${ragErr.message}${colors.reset}`);
|
|
451
|
+
const genStart = Date.now();
|
|
452
|
+
const response = await sdk.generate(config.model, [{ role: 'user', content: userMessage }], {
|
|
453
|
+
temperature: 0.7, maxTokens: 100
|
|
454
|
+
});
|
|
455
|
+
assistantMessage = (typeof response === 'string' ? response : response?.text || '') || '';
|
|
456
|
+
firstTokenMs = Date.now() - genStart;
|
|
457
|
+
generationMs = firstTokenMs;
|
|
458
|
+
tokensGenerated = assistantMessage.split(/\s+/).length;
|
|
459
|
+
process.stdout.write(`\n${colors.bright}${colors.magenta}AI:${colors.reset} ${assistantMessage}`);
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
// ── PLAIN MODE ──
|
|
463
|
+
const genStart = Date.now();
|
|
464
|
+
process.stdout.write(`\n${colors.bright}${colors.magenta}AI:${colors.reset} `);
|
|
465
|
+
|
|
466
|
+
const plainMessages = [{ role: 'user', content: userMessage }];
|
|
467
|
+
if (sdk.generateStream) {
|
|
468
|
+
let streamedAny = false;
|
|
469
|
+
const result = await sdk.generateStream(config.model, plainMessages, {
|
|
470
|
+
temperature: 0.7, maxTokens: 150,
|
|
471
|
+
onToken: (token) => {
|
|
472
|
+
if (!firstTokenMs) firstTokenMs = Date.now() - genStart;
|
|
473
|
+
streamedAny = true;
|
|
474
|
+
process.stdout.write(token);
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
assistantMessage = result.text || '';
|
|
478
|
+
tokensGenerated = result.tokensGenerated || assistantMessage.split(/\s+/).length;
|
|
479
|
+
if (!streamedAny && assistantMessage) process.stdout.write(assistantMessage);
|
|
480
|
+
} else {
|
|
481
|
+
const response = await sdk.generate(config.model, plainMessages, {
|
|
482
|
+
temperature: 0.7, maxTokens: 150
|
|
483
|
+
});
|
|
484
|
+
assistantMessage = (typeof response === 'string' ? response : response?.text || '') || '';
|
|
485
|
+
firstTokenMs = Date.now() - genStart;
|
|
486
|
+
tokensGenerated = assistantMessage.split(/\s+/).length;
|
|
487
|
+
process.stdout.write(assistantMessage);
|
|
488
|
+
}
|
|
489
|
+
generationMs = Date.now() - genStart;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Clean up hallucinated Q&A chains
|
|
493
|
+
assistantMessage = cleanResponse(assistantMessage);
|
|
494
|
+
|
|
495
|
+
const totalMs = Date.now() - totalStart;
|
|
496
|
+
const tokPerSec = generationMs > 0 ? (tokensGenerated / (generationMs / 1000)).toFixed(1) : '0';
|
|
497
|
+
|
|
498
|
+
// Print timing summary
|
|
499
|
+
console.log(sourceInfo);
|
|
500
|
+
console.log(`${colors.dim}⏱ retrieval: ${retrievalMs}ms | first token: ${firstTokenMs}ms | generation: ${generationMs}ms | total: ${totalMs}ms | ${tokensGenerated} tokens @ ${tokPerSec} tok/s${colors.reset}\n`);
|
|
501
|
+
|
|
502
|
+
if (!assistantMessage || assistantMessage.length < 3) {
|
|
503
|
+
console.log(`${colors.yellow}(No response generated — try rephrasing your question)${colors.reset}\n`);
|
|
504
|
+
}
|
|
505
|
+
} catch (error) {
|
|
506
|
+
console.error(`\n${colors.red}Error:${colors.reset} ${error.message}\n`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Prompt user for input
|
|
512
|
+
*/
|
|
513
|
+
function promptUser() {
|
|
514
|
+
rl.question(`${colors.bright}${colors.green}You:${colors.reset} `, async (input) => {
|
|
515
|
+
const message = input.trim();
|
|
516
|
+
|
|
517
|
+
if (!message) {
|
|
518
|
+
promptUser();
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Handle commands
|
|
523
|
+
if (message.toLowerCase() === 'exit' || message.toLowerCase() === 'quit') {
|
|
524
|
+
console.log(`\n${colors.bright}${colors.cyan}Thank you for chatting! Goodbye.${colors.reset}\n`);
|
|
525
|
+
rl.close();
|
|
526
|
+
process.exit(0);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (message.toLowerCase() === 'clear') {
|
|
530
|
+
console.clear();
|
|
531
|
+
printWelcome();
|
|
532
|
+
console.log(`${colors.green}✓ Screen cleared${colors.reset}\n`);
|
|
533
|
+
promptUser();
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Send message to AI
|
|
538
|
+
await sendMessage(message);
|
|
539
|
+
promptUser();
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Main entry point
|
|
545
|
+
*/
|
|
546
|
+
async function main() {
|
|
547
|
+
printWelcome();
|
|
548
|
+
|
|
549
|
+
try {
|
|
550
|
+
console.log(`${colors.cyan}Initializing SlyOS...${colors.reset}`);
|
|
551
|
+
await sdk.initialize();
|
|
552
|
+
|
|
553
|
+
console.log(`${colors.cyan}Loading model: ${config.model}...${colors.reset}`);
|
|
554
|
+
await sdk.loadModel(config.model);
|
|
555
|
+
|
|
556
|
+
console.log(`${colors.green}Ready! Start chatting below.${colors.reset}\n`);
|
|
557
|
+
console.log(`${colors.bright}${colors.cyan}─────────────────────────────────────────────────────────────${colors.reset}\n`);
|
|
558
|
+
} catch (error) {
|
|
559
|
+
console.error(`${colors.red}Failed to initialize: ${error.message}${colors.reset}`);
|
|
560
|
+
console.error(`${colors.dim}Make sure your API key is correct and you have internet access.${colors.reset}`);
|
|
561
|
+
process.exit(1);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
promptUser();
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Handle process termination gracefully
|
|
568
|
+
process.on('SIGINT', () => {
|
|
569
|
+
console.log(`\n${colors.bright}${colors.cyan}Session ended. Goodbye!${colors.reset}\n`);
|
|
570
|
+
rl.close();
|
|
571
|
+
process.exit(0);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
process.on('SIGTERM', () => {
|
|
575
|
+
rl.close();
|
|
576
|
+
process.exit(0);
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// Start the chatbot
|
|
580
|
+
main();
|
|
581
|
+
CHATBOT_EOF
|
|
582
|
+
|
|
583
|
+
chmod +x app.mjs
|
|
584
|
+
print_success "Chatbot application created"
|
|
585
|
+
|
|
586
|
+
# Create .env.example file
|
|
587
|
+
print_step "Creating environment configuration example"
|
|
588
|
+
cat > .env.example << 'ENV_EOF'
|
|
589
|
+
# Slyos SDK Configuration
|
|
590
|
+
SLYOS_API_KEY=your_api_key_here
|
|
591
|
+
SLYOS_MODEL=quantum-1.7b
|
|
592
|
+
SLYOS_SERVER=https://api.slyos.world
|
|
593
|
+
ENV_EOF
|
|
594
|
+
print_success "Environment configuration template created"
|
|
595
|
+
|
|
596
|
+
# Create README
|
|
597
|
+
print_step "Creating README documentation"
|
|
598
|
+
cat > README.md << 'README_EOF'
|
|
599
|
+
# Slyos Interactive Chatbot
|
|
600
|
+
|
|
601
|
+
A simple yet powerful interactive chatbot powered by the Slyos SDK.
|
|
602
|
+
|
|
603
|
+
## Features
|
|
604
|
+
|
|
605
|
+
- Interactive command-line interface with colored output
|
|
606
|
+
- Conversation history management
|
|
607
|
+
- Easy API configuration
|
|
608
|
+
- Cross-platform support (Mac, Windows, Linux)
|
|
609
|
+
|
|
610
|
+
## Installation
|
|
611
|
+
|
|
612
|
+
1. Clone or download this project
|
|
613
|
+
2. Install dependencies: `npm install`
|
|
614
|
+
3. Configure your API key (see Configuration)
|
|
615
|
+
|
|
616
|
+
## Configuration
|
|
617
|
+
|
|
618
|
+
### Environment Variables
|
|
619
|
+
|
|
620
|
+
Set these environment variables before running:
|
|
621
|
+
|
|
622
|
+
```bash
|
|
623
|
+
export SLYOS_API_KEY=your_api_key_here
|
|
624
|
+
export SLYOS_MODEL=quantum-1.7b
|
|
625
|
+
export SLYOS_SERVER=https://api.slyos.world
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Or create a `.env` file based on `.env.example`.
|
|
629
|
+
|
|
630
|
+
## Running the Chatbot
|
|
631
|
+
|
|
632
|
+
### Direct Method
|
|
633
|
+
```bash
|
|
634
|
+
npm start
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### With Environment Variables
|
|
638
|
+
```bash
|
|
639
|
+
SLYOS_API_KEY=your_key npm start
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Manual
|
|
643
|
+
```bash
|
|
644
|
+
node app.mjs
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
## Usage
|
|
648
|
+
|
|
649
|
+
Once the chatbot starts:
|
|
650
|
+
|
|
651
|
+
- **Chat**: Type your message and press Enter
|
|
652
|
+
- **Clear History**: Type `clear` to reset conversation
|
|
653
|
+
- **Exit**: Type `exit` or `quit` to end session
|
|
654
|
+
- **Interrupt**: Press Ctrl+C to exit anytime
|
|
655
|
+
|
|
656
|
+
## API Response Format
|
|
657
|
+
|
|
658
|
+
The chatbot supports multiple response formats from the SDK:
|
|
659
|
+
|
|
660
|
+
- `response.content` - Primary response text
|
|
661
|
+
- `response.text` - Alternative response field
|
|
662
|
+
- Direct string response - Fallback format
|
|
663
|
+
|
|
664
|
+
## Troubleshooting
|
|
665
|
+
|
|
666
|
+
### "Error initializing SDK"
|
|
667
|
+
- Check that your API key is valid
|
|
668
|
+
- Verify the Slyos server is accessible
|
|
669
|
+
- Ensure internet connection is active
|
|
670
|
+
|
|
671
|
+
### "Cannot find module '@beltoinc/slyos-sdk'"
|
|
672
|
+
- Run `npm install` to install dependencies
|
|
673
|
+
- Check npm log: `npm list`
|
|
674
|
+
|
|
675
|
+
### Placeholder API Key Warning
|
|
676
|
+
- Set the `SLYOS_API_KEY` environment variable with your actual key
|
|
677
|
+
- Or update `config.apiKey` in `app.mjs`
|
|
678
|
+
|
|
679
|
+
## System Requirements
|
|
680
|
+
|
|
681
|
+
- Node.js 14+ (14.17.0 or higher recommended)
|
|
682
|
+
- npm 6+
|
|
683
|
+
- Internet connection for API access
|
|
684
|
+
|
|
685
|
+
## License
|
|
686
|
+
|
|
687
|
+
MIT
|
|
688
|
+
README_EOF
|
|
689
|
+
print_success "README created"
|
|
690
|
+
|
|
691
|
+
# Set up environment with provided values
|
|
692
|
+
print_step "Configuring environment variables"
|
|
693
|
+
cat > .env << ENV_SETUP_EOF
|
|
694
|
+
SLYOS_API_KEY=${API_KEY}
|
|
695
|
+
SLYOS_MODEL=${MODEL}
|
|
696
|
+
SLYOS_SERVER=${SLYOS_SERVER}
|
|
697
|
+
SLYOS_KB_ID=${KB_ID}
|
|
698
|
+
ENV_SETUP_EOF
|
|
699
|
+
print_success "Environment configured"
|
|
700
|
+
|
|
701
|
+
# Final summary
|
|
702
|
+
echo ""
|
|
703
|
+
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
|
|
704
|
+
echo -e "${BLUE}║${NC} ${GREEN}✓ Setup Complete!${NC} ${BLUE}║${NC}"
|
|
705
|
+
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
|
|
706
|
+
echo ""
|
|
707
|
+
echo -e "${CYAN}Project Details:${NC}"
|
|
708
|
+
echo " Location: ${YELLOW}$(pwd)${NC}"
|
|
709
|
+
echo " API Key: ${YELLOW}${API_KEY}${NC}"
|
|
710
|
+
echo " Model: ${YELLOW}${MODEL}${NC}"
|
|
711
|
+
if [ -n "$KB_ID" ]; then
|
|
712
|
+
echo " Knowledge Base: ${GREEN}${KB_ID} (RAG enabled)${NC}"
|
|
713
|
+
fi
|
|
714
|
+
echo ""
|
|
715
|
+
echo -e "${CYAN}Next Steps:${NC}"
|
|
716
|
+
echo " 1. Review the .env file and update your API key if needed"
|
|
717
|
+
echo " 2. Run the chatbot: ${YELLOW}npm start${NC}"
|
|
718
|
+
echo " 3. Type messages to chat with the AI"
|
|
719
|
+
echo " 4. Type 'exit' to quit"
|
|
720
|
+
echo ""
|
|
721
|
+
echo -e "${GREEN}Ready to chat! 🚀${NC}"
|
|
722
|
+
echo ""
|
|
723
|
+
|
|
724
|
+
# Tell user how to start (can't auto-run when piped because stdin is closed)
|
|
725
|
+
echo -e "${CYAN}To start chatting, run:${NC}"
|
|
726
|
+
echo ""
|
|
727
|
+
echo -e " ${YELLOW}cd ${PROJECT_NAME} && npm start${NC}"
|
|
728
|
+
echo ""
|