@beltoinc/slyos-sdk 1.5.0

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.
@@ -0,0 +1,634 @@
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
+ * Send message to AI and get response
296
+ */
297
+ async function sendMessage(userMessage) {
298
+ try {
299
+ console.log(`${colors.dim}Thinking...${colors.reset}`);
300
+
301
+ let assistantMessage = '';
302
+ let sourceInfo = '';
303
+
304
+ if (config.kbId) {
305
+ // RAG mode: call API directly to get relevant chunks, then generate locally with context
306
+ console.log(`${colors.dim}Searching knowledge base...${colors.reset}`);
307
+ try {
308
+ const token = await getAuthToken();
309
+ if (!token) throw new Error('Could not authenticate — check your API key');
310
+ // Adapt chunk count to model's context window
311
+ const modelCtx = sdk.getModelContextWindow?.() || 2048;
312
+ const topK = modelCtx <= 2048 ? 2 : modelCtx <= 4096 ? 3 : 5;
313
+ const ragRes = await fetch(`${config.server}/api/rag/knowledge-bases/${config.kbId}/query`, {
314
+ method: 'POST',
315
+ headers: {
316
+ 'Content-Type': 'application/json',
317
+ 'Authorization': `Bearer ${token}`
318
+ },
319
+ body: JSON.stringify({ query: userMessage, top_k: topK, model_id: config.model })
320
+ });
321
+ if (!ragRes.ok) {
322
+ const errText = await ragRes.text();
323
+ throw new Error(`RAG query failed: ${ragRes.status} - ${errText}`);
324
+ }
325
+ const ragData = await ragRes.json();
326
+ const chunks = ragData.retrieved_chunks || [];
327
+
328
+ // Check if chunks are relevant enough (similarity > 0.3)
329
+ const goodChunks = chunks.filter(c => (c.similarity_score || 0) > 0.3);
330
+
331
+ if (goodChunks.length > 0) {
332
+ // Keep context SHORT — small models need room to generate
333
+ const ctxWindow = sdk.getModelContextWindow?.() || 2048;
334
+ // Reserve at least 40% of context window for generation
335
+ const maxContextChars = ctxWindow <= 2048 ? 800 : ctxWindow <= 4096 ? 1500 : 3000;
336
+ const maxGenTokens = ctxWindow <= 2048 ? 150 : Math.min(300, Math.floor(ctxWindow / 4));
337
+
338
+ // Clean and truncate context — strip weird chars, fit model window
339
+ let context = goodChunks.map(c => c.content).join('\n')
340
+ .replace(/[^\x20-\x7E\n]/g, ' ') // Strip non-ASCII/control chars
341
+ .replace(/\s{3,}/g, ' ') // Collapse excessive whitespace
342
+ .replace(/<[^>]+>/g, ' ') // Strip any leftover HTML tags
343
+ .replace(/https?:\/\/\S+/g, '') // Strip URLs to save tokens
344
+ .trim();
345
+ if (context.length > maxContextChars) context = context.substring(0, maxContextChars);
346
+
347
+ // Instruction-style prompt that small models understand
348
+ const prompt = `Use the following information to answer the question.\n\nInfo: ${context}\n\nQuestion: ${userMessage}\nAnswer:`;
349
+ const response = await sdk.generate(config.model, prompt, {
350
+ temperature: 0.6,
351
+ maxTokens: maxGenTokens
352
+ });
353
+ assistantMessage = (typeof response === 'string' ? response : response?.text || response?.content || '') || '';
354
+
355
+ // Collect source names
356
+ const sources = [...new Set(goodChunks.map(c => c.document_name || c.source).filter(Boolean))];
357
+ if (sources.length > 0) {
358
+ sourceInfo = `\n${colors.dim}[Sources: ${sources.join(', ')}]${colors.reset}`;
359
+ }
360
+ } else {
361
+ // No relevant chunks — answer conversationally
362
+ console.log(`${colors.dim}No RAG context found, using plain generation...${colors.reset}`);
363
+ const prompt = `The user said: "${userMessage}"\nGive a brief, friendly response:\n`;
364
+ const response = await sdk.generate(config.model, prompt, {
365
+ temperature: 0.7,
366
+ maxTokens: 100
367
+ });
368
+ assistantMessage = (typeof response === 'string' ? response : response?.text || response?.content || '') || '';
369
+ }
370
+ } catch (ragErr) {
371
+ console.log(`${colors.yellow}RAG lookup failed: ${ragErr.message}${colors.reset}`);
372
+ const prompt = `The user said: "${userMessage}"\nGive a brief, friendly response:\n`;
373
+ const response = await sdk.generate(config.model, prompt, {
374
+ temperature: 0.7,
375
+ maxTokens: 100
376
+ });
377
+ assistantMessage = (typeof response === 'string' ? response : response?.text || response?.content || '') || '';
378
+ }
379
+ } else {
380
+ // Plain mode: direct generation (no RAG)
381
+ const prompt = `The user said: "${userMessage}"\nGive a brief, helpful response:\n`;
382
+ const response = await sdk.generate(config.model, prompt, {
383
+ temperature: 0.7,
384
+ maxTokens: 150
385
+ });
386
+ assistantMessage = (typeof response === 'string' ? response : response?.text || response?.content || '') || '';
387
+ }
388
+
389
+ // Clean up model output artifacts
390
+ assistantMessage = assistantMessage
391
+ // Strip repeated garbage chars (!!!, ???, etc)
392
+ .replace(/(.)\1{5,}/g, '')
393
+ // Strip leading role prefixes the model loves to emit
394
+ .replace(/^(assistant|system|answer|response|AI)\s*[:]\s*/i, '')
395
+ // Remove leading partial sentences (fragments before the real answer)
396
+ .replace(/^[a-z][^.!?]{0,40}\.\s*/i, function(match) {
397
+ // Only strip if it looks like a fragment (< 50 chars ending in period)
398
+ return match.length < 50 && !match.includes(' is ') ? '' : match;
399
+ })
400
+ // Stop at any hallucinated role prefixes mid-response
401
+ .split(/\n\s*(User|Human|System|Question):/i)[0]
402
+ // Strip any remaining leading role prefix after newline
403
+ .replace(/^\s*(assistant|AI)\s*[:]\s*/im, '')
404
+ .trim();
405
+
406
+ if (!assistantMessage || assistantMessage.length < 3) {
407
+ assistantMessage = '(No response generated — try rephrasing your question)';
408
+ }
409
+
410
+ console.log(`\n${colors.bright}${colors.magenta}AI:${colors.reset} ${assistantMessage}${sourceInfo}\n`);
411
+ } catch (error) {
412
+ console.error(`\n${colors.red}Error:${colors.reset} ${error.message}\n`);
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Prompt user for input
418
+ */
419
+ function promptUser() {
420
+ rl.question(`${colors.bright}${colors.green}You:${colors.reset} `, async (input) => {
421
+ const message = input.trim();
422
+
423
+ if (!message) {
424
+ promptUser();
425
+ return;
426
+ }
427
+
428
+ // Handle commands
429
+ if (message.toLowerCase() === 'exit' || message.toLowerCase() === 'quit') {
430
+ console.log(`\n${colors.bright}${colors.cyan}Thank you for chatting! Goodbye.${colors.reset}\n`);
431
+ rl.close();
432
+ process.exit(0);
433
+ }
434
+
435
+ if (message.toLowerCase() === 'clear') {
436
+ console.clear();
437
+ printWelcome();
438
+ console.log(`${colors.green}✓ Screen cleared${colors.reset}\n`);
439
+ promptUser();
440
+ return;
441
+ }
442
+
443
+ // Send message to AI
444
+ await sendMessage(message);
445
+ promptUser();
446
+ });
447
+ }
448
+
449
+ /**
450
+ * Main entry point
451
+ */
452
+ async function main() {
453
+ printWelcome();
454
+
455
+ try {
456
+ console.log(`${colors.cyan}Initializing SlyOS...${colors.reset}`);
457
+ await sdk.initialize();
458
+
459
+ console.log(`${colors.cyan}Loading model: ${config.model}...${colors.reset}`);
460
+ await sdk.loadModel(config.model);
461
+
462
+ console.log(`${colors.green}Ready! Start chatting below.${colors.reset}\n`);
463
+ console.log(`${colors.bright}${colors.cyan}─────────────────────────────────────────────────────────────${colors.reset}\n`);
464
+ } catch (error) {
465
+ console.error(`${colors.red}Failed to initialize: ${error.message}${colors.reset}`);
466
+ console.error(`${colors.dim}Make sure your API key is correct and you have internet access.${colors.reset}`);
467
+ process.exit(1);
468
+ }
469
+
470
+ promptUser();
471
+ }
472
+
473
+ // Handle process termination gracefully
474
+ process.on('SIGINT', () => {
475
+ console.log(`\n${colors.bright}${colors.cyan}Session ended. Goodbye!${colors.reset}\n`);
476
+ rl.close();
477
+ process.exit(0);
478
+ });
479
+
480
+ process.on('SIGTERM', () => {
481
+ rl.close();
482
+ process.exit(0);
483
+ });
484
+
485
+ // Start the chatbot
486
+ main();
487
+ CHATBOT_EOF
488
+
489
+ chmod +x app.mjs
490
+ print_success "Chatbot application created"
491
+
492
+ # Create .env.example file
493
+ print_step "Creating environment configuration example"
494
+ cat > .env.example << 'ENV_EOF'
495
+ # Slyos SDK Configuration
496
+ SLYOS_API_KEY=your_api_key_here
497
+ SLYOS_MODEL=quantum-1.7b
498
+ SLYOS_SERVER=https://api.slyos.world
499
+ ENV_EOF
500
+ print_success "Environment configuration template created"
501
+
502
+ # Create README
503
+ print_step "Creating README documentation"
504
+ cat > README.md << 'README_EOF'
505
+ # Slyos Interactive Chatbot
506
+
507
+ A simple yet powerful interactive chatbot powered by the Slyos SDK.
508
+
509
+ ## Features
510
+
511
+ - Interactive command-line interface with colored output
512
+ - Conversation history management
513
+ - Easy API configuration
514
+ - Cross-platform support (Mac, Windows, Linux)
515
+
516
+ ## Installation
517
+
518
+ 1. Clone or download this project
519
+ 2. Install dependencies: `npm install`
520
+ 3. Configure your API key (see Configuration)
521
+
522
+ ## Configuration
523
+
524
+ ### Environment Variables
525
+
526
+ Set these environment variables before running:
527
+
528
+ ```bash
529
+ export SLYOS_API_KEY=your_api_key_here
530
+ export SLYOS_MODEL=quantum-1.7b
531
+ export SLYOS_SERVER=https://api.slyos.world
532
+ ```
533
+
534
+ Or create a `.env` file based on `.env.example`.
535
+
536
+ ## Running the Chatbot
537
+
538
+ ### Direct Method
539
+ ```bash
540
+ npm start
541
+ ```
542
+
543
+ ### With Environment Variables
544
+ ```bash
545
+ SLYOS_API_KEY=your_key npm start
546
+ ```
547
+
548
+ ### Manual
549
+ ```bash
550
+ node app.mjs
551
+ ```
552
+
553
+ ## Usage
554
+
555
+ Once the chatbot starts:
556
+
557
+ - **Chat**: Type your message and press Enter
558
+ - **Clear History**: Type `clear` to reset conversation
559
+ - **Exit**: Type `exit` or `quit` to end session
560
+ - **Interrupt**: Press Ctrl+C to exit anytime
561
+
562
+ ## API Response Format
563
+
564
+ The chatbot supports multiple response formats from the SDK:
565
+
566
+ - `response.content` - Primary response text
567
+ - `response.text` - Alternative response field
568
+ - Direct string response - Fallback format
569
+
570
+ ## Troubleshooting
571
+
572
+ ### "Error initializing SDK"
573
+ - Check that your API key is valid
574
+ - Verify the Slyos server is accessible
575
+ - Ensure internet connection is active
576
+
577
+ ### "Cannot find module '@beltoinc/slyos-sdk'"
578
+ - Run `npm install` to install dependencies
579
+ - Check npm log: `npm list`
580
+
581
+ ### Placeholder API Key Warning
582
+ - Set the `SLYOS_API_KEY` environment variable with your actual key
583
+ - Or update `config.apiKey` in `app.mjs`
584
+
585
+ ## System Requirements
586
+
587
+ - Node.js 14+ (14.17.0 or higher recommended)
588
+ - npm 6+
589
+ - Internet connection for API access
590
+
591
+ ## License
592
+
593
+ MIT
594
+ README_EOF
595
+ print_success "README created"
596
+
597
+ # Set up environment with provided values
598
+ print_step "Configuring environment variables"
599
+ cat > .env << ENV_SETUP_EOF
600
+ SLYOS_API_KEY=${API_KEY}
601
+ SLYOS_MODEL=${MODEL}
602
+ SLYOS_SERVER=${SLYOS_SERVER}
603
+ SLYOS_KB_ID=${KB_ID}
604
+ ENV_SETUP_EOF
605
+ print_success "Environment configured"
606
+
607
+ # Final summary
608
+ echo ""
609
+ echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
610
+ echo -e "${BLUE}║${NC} ${GREEN}✓ Setup Complete!${NC} ${BLUE}║${NC}"
611
+ echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
612
+ echo ""
613
+ echo -e "${CYAN}Project Details:${NC}"
614
+ echo " Location: ${YELLOW}$(pwd)${NC}"
615
+ echo " API Key: ${YELLOW}${API_KEY}${NC}"
616
+ echo " Model: ${YELLOW}${MODEL}${NC}"
617
+ if [ -n "$KB_ID" ]; then
618
+ echo " Knowledge Base: ${GREEN}${KB_ID} (RAG enabled)${NC}"
619
+ fi
620
+ echo ""
621
+ echo -e "${CYAN}Next Steps:${NC}"
622
+ echo " 1. Review the .env file and update your API key if needed"
623
+ echo " 2. Run the chatbot: ${YELLOW}npm start${NC}"
624
+ echo " 3. Type messages to chat with the AI"
625
+ echo " 4. Type 'exit' to quit"
626
+ echo ""
627
+ echo -e "${GREEN}Ready to chat! 🚀${NC}"
628
+ echo ""
629
+
630
+ # Tell user how to start (can't auto-run when piped because stdin is closed)
631
+ echo -e "${CYAN}To start chatting, run:${NC}"
632
+ echo ""
633
+ echo -e " ${YELLOW}cd ${PROJECT_NAME} && npm start${NC}"
634
+ echo ""