AptlyDigital commited on
Commit
3024f65
·
verified ·
1 Parent(s): af705c1

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +707 -143
index.html CHANGED
@@ -8,6 +8,7 @@
8
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
9
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
  <style>
 
11
  * {
12
  margin: 0;
13
  padding: 0;
@@ -23,7 +24,6 @@
23
  width: 100vw;
24
  }
25
 
26
- /* Mobile Navigation */
27
  .mobile-nav {
28
  display: none;
29
  position: fixed;
@@ -79,7 +79,6 @@
79
  z-index: 999;
80
  }
81
 
82
- /* Main Layout */
83
  .main-container {
84
  display: flex;
85
  height: 100vh;
@@ -87,7 +86,6 @@
87
  position: relative;
88
  }
89
 
90
- /* Left Side Panel */
91
  .side-panel {
92
  width: 320px;
93
  height: 100vh;
@@ -107,7 +105,6 @@
107
  gap: 25px;
108
  }
109
 
110
- /* Right Side Panel */
111
  .side-panel.right {
112
  border-right: none;
113
  border-left: 1px solid rgba(255, 255, 255, 0.1);
@@ -116,7 +113,6 @@
116
  gap: 25px;
117
  }
118
 
119
- /* Main Content Area */
120
  .main-content {
121
  flex: 1;
122
  display: flex;
@@ -128,7 +124,6 @@
128
  overflow: hidden;
129
  }
130
 
131
- /* 3D Canvas */
132
  #canvasContainer {
133
  width: 100%;
134
  height: 70vh;
@@ -145,7 +140,6 @@
145
  height: 100%;
146
  }
147
 
148
- /* Chat Interface (Centered) */
149
  .chat-interface {
150
  width: 100%;
151
  max-width: 800px;
@@ -352,7 +346,6 @@
352
  transform: translateY(-2px);
353
  }
354
 
355
- /* Cards Styling */
356
  .card {
357
  background: rgba(20, 20, 30, 0.8);
358
  border-radius: 15px;
@@ -375,7 +368,6 @@
375
  font-size: 1em;
376
  }
377
 
378
- /* Dropdown/Accordion */
379
  .accordion {
380
  margin-bottom: 15px;
381
  }
@@ -413,7 +405,6 @@
413
  padding: 15px;
414
  }
415
 
416
- /* Control Groups */
417
  .control-group {
418
  margin-bottom: 20px;
419
  }
@@ -463,7 +454,6 @@
463
  font-weight: 500;
464
  }
465
 
466
- /* Button Groups */
467
  .button-grid {
468
  display: grid;
469
  grid-template-columns: repeat(3, 1fr);
@@ -550,7 +540,6 @@
550
  background: rgba(255, 90, 90, 0.2);
551
  }
552
 
553
- /* RAG Training Section */
554
  .rag-textarea {
555
  width: 100%;
556
  height: 100px;
@@ -638,7 +627,6 @@
638
  border: 1px solid rgba(0, 255, 157, 0.2);
639
  }
640
 
641
- /* Loading and Error Screens */
642
  .loading-screen {
643
  position: fixed;
644
  top: 0;
@@ -715,7 +703,6 @@
715
  50% { opacity: 0.3; }
716
  }
717
 
718
- /* Responsive Design */
719
  @media (max-width: 1200px) {
720
  .side-panel {
721
  width: 280px;
@@ -1063,9 +1050,21 @@
1063
  <i class="fas fa-chevron-down"></i>
1064
  </div>
1065
  <div class="accordion-content" id="llmControls">
 
 
 
 
 
 
 
 
 
 
 
 
1066
  <div class="control-group">
1067
  <label>API Endpoint</label>
1068
- <input type="text" class="rag-textarea" id="apiEndpoint" placeholder="https://api.example.com/chat" value="https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.1">
1069
  </div>
1070
 
1071
  <div class="control-group">
@@ -1073,6 +1072,11 @@
1073
  <input type="password" class="rag-textarea" id="apiKey" placeholder="Enter your API key">
1074
  </div>
1075
 
 
 
 
 
 
1076
  <div class="rag-controls">
1077
  <button class="rag-btn" id="testApiBtn">
1078
  <i class="fas fa-wifi"></i>
@@ -1094,160 +1098,665 @@
1094
  </aside>
1095
  </div>
1096
 
1097
- <!-- External LLM API Integration Script -->
1098
- <script type="module" id="llm-integration">
1099
- // This script can be loaded separately for LLM API integration
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1100
  class LLMIntegration {
1101
  constructor() {
 
1102
  this.apiEndpoint = '';
1103
  this.apiKey = '';
 
1104
  this.isConnected = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
1105
  }
1106
 
1107
- async initialize() {
1108
- // Load saved settings
1109
  this.loadSettings();
1110
-
1111
- // Test connection if settings exist
1112
- if (this.apiEndpoint && this.apiKey) {
1113
- await this.testConnection();
1114
- }
1115
  }
1116
 
1117
  loadSettings() {
1118
- const endpoint = localStorage.getItem('aiTutorApiEndpoint');
1119
- const key = localStorage.getItem('aiTutorApiKey');
1120
-
1121
- if (endpoint) {
1122
- this.apiEndpoint = endpoint;
1123
- document.getElementById('apiEndpoint').value = endpoint;
1124
- }
1125
-
1126
- if (key) {
1127
- this.apiKey = key;
1128
- document.getElementById('apiKey').value = key;
 
 
 
 
 
 
 
 
 
 
 
 
1129
  }
1130
  }
1131
 
1132
  saveSettings() {
1133
- const endpoint = document.getElementById('apiEndpoint').value.trim();
1134
- const key = document.getElementById('apiKey').value.trim();
1135
-
1136
- if (endpoint) {
1137
- this.apiEndpoint = endpoint;
1138
- localStorage.setItem('aiTutorApiEndpoint', endpoint);
 
 
 
 
 
 
 
 
 
1139
  }
 
 
 
 
 
 
 
 
 
 
1140
 
1141
- if (key) {
1142
- this.apiKey = key;
1143
- localStorage.setItem('aiTutorApiKey', key);
1144
- }
1145
 
1146
- return { endpoint, key };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1147
  }
1148
 
1149
  async testConnection() {
1150
- if (!this.apiEndpoint || !this.apiKey) {
 
 
 
 
 
 
1151
  return false;
1152
  }
1153
 
 
 
1154
  try {
1155
- const response = await fetch(this.apiEndpoint, {
1156
- method: 'POST',
1157
- headers: {
1158
- 'Authorization': `Bearer ${this.apiKey}`,
1159
- 'Content-Type': 'application/json'
1160
- },
1161
- body: JSON.stringify({
1162
- inputs: 'Test connection',
1163
- parameters: {
1164
- max_new_tokens: 10
1165
- }
1166
- })
1167
- });
1168
 
1169
- this.isConnected = response.ok;
1170
- return response.ok;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1171
  } catch (error) {
1172
- console.error('API Connection failed:', error);
1173
  this.isConnected = false;
 
1174
  return false;
1175
  }
1176
  }
1177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1178
  async generateResponse(prompt, context = '') {
1179
- if (!this.isConnected || !this.apiEndpoint || !this.apiKey) {
 
1180
  return null;
1181
  }
1182
 
1183
  try {
1184
  const fullPrompt = context ? `${context}\n\nQuestion: ${prompt}` : prompt;
1185
 
1186
- const response = await fetch(this.apiEndpoint, {
1187
- method: 'POST',
1188
- headers: {
1189
- 'Authorization': `Bearer ${this.apiKey}`,
1190
- 'Content-Type': 'application/json'
1191
- },
1192
- body: JSON.stringify({
1193
- inputs: fullPrompt,
1194
- parameters: {
1195
- max_new_tokens: 500,
1196
- temperature: 0.7,
1197
- top_p: 0.9,
1198
- repetition_penalty: 1.1
1199
- }
1200
- })
1201
- });
1202
-
1203
- if (!response.ok) {
1204
- throw new Error(`API Error: ${response.status}`);
1205
  }
1206
-
1207
- const data = await response.json();
1208
- return data[0]?.generated_text || data.generated_text || '';
1209
  } catch (error) {
1210
- console.error('LLM Generation failed:', error);
1211
  return null;
1212
  }
1213
  }
1214
- }
1215
-
1216
- // Export for use in main application
1217
- window.LLMIntegration = LLMIntegration;
1218
- </script>
1219
-
1220
- <script>
1221
- // Check if Three.js loaded properly
1222
- function checkThreeJS() {
1223
- if (typeof THREE === 'undefined') {
1224
- console.error('Three.js failed to load');
1225
- showError('Three.js library failed to load. Please check your internet connection.');
1226
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1227
  }
1228
- return true;
1229
- }
1230
-
1231
- function showError(message) {
1232
- const errorScreen = document.getElementById('errorScreen');
1233
- const errorMessage = document.getElementById('errorMessage');
1234
- const loadingScreen = document.getElementById('loadingScreen');
1235
 
1236
- loadingScreen.style.display = 'none';
1237
- errorMessage.textContent = message;
1238
- errorScreen.style.display = 'flex';
1239
- }
1240
-
1241
- function hideLoading() {
1242
- const loadingScreen = document.getElementById('loadingScreen');
1243
- loadingScreen.style.opacity = '0';
1244
- setTimeout(() => {
1245
- loadingScreen.style.display = 'none';
1246
- }, 500);
1247
- }
1248
-
1249
- function updateStatus(text) {
1250
- document.getElementById('loadingText').textContent = text;
 
 
 
 
 
 
 
 
 
 
1251
  }
1252
 
1253
  // Mobile Menu Functionality
@@ -1267,7 +1776,6 @@
1267
  this.menuBtn.addEventListener('click', () => this.toggleMenu());
1268
  this.overlay.addEventListener('click', () => this.closeMenu());
1269
 
1270
- // Close menu on escape key
1271
  document.addEventListener('keydown', (e) => {
1272
  if (e.key === 'Escape') {
1273
  this.closeMenu();
@@ -1358,7 +1866,6 @@
1358
  }
1359
 
1360
  loadSampleKnowledge() {
1361
- // Add some sample knowledge for demonstration
1362
  this.addKnowledgeItem({
1363
  id: Date.now(),
1364
  title: "Physics Basics",
@@ -1377,12 +1884,10 @@
1377
  }
1378
 
1379
  setupEventListeners() {
1380
- // Add knowledge button
1381
  document.getElementById('addKnowledgeBtn').addEventListener('click', () => {
1382
  this.addKnowledgeFromText();
1383
  });
1384
 
1385
- // Train button
1386
  document.getElementById('trainBtn').addEventListener('click', () => {
1387
  this.trainRAGModel();
1388
  });
@@ -1425,22 +1930,18 @@
1425
  this.isTraining = true;
1426
  this.showRAGStatus('Starting RAG training...', 'processing');
1427
 
1428
- // Simulate training progress
1429
  const progressBar = document.getElementById('trainingProgress');
1430
  progressBar.style.width = '0%';
1431
 
1432
- // Simulate training steps
1433
  const steps = ['Preprocessing text', 'Creating embeddings', 'Building vector store', 'Optimizing retrieval'];
1434
 
1435
  for (let i = 0; i < steps.length; i++) {
1436
  this.showRAGStatus(steps[i], 'processing');
1437
  progressBar.style.width = `${((i + 1) / steps.length) * 100}%`;
1438
 
1439
- // Simulate processing time
1440
  await this.sleep(1000);
1441
  }
1442
 
1443
- // For demonstration, simulate successful training
1444
  this.vectorStore = {
1445
  size: this.knowledgeBase.length,
1446
  trainedAt: new Date().toISOString(),
@@ -1450,7 +1951,6 @@
1450
  this.isTraining = false;
1451
  this.showRAGStatus(`RAG training complete! ${this.knowledgeBase.length} documents indexed.`, 'success');
1452
 
1453
- // Reset progress bar after delay
1454
  setTimeout(() => {
1455
  progressBar.style.width = '0%';
1456
  }, 2000);
@@ -1461,14 +1961,12 @@
1461
  return "I haven't been trained on any specific knowledge yet. Please add some content and train me first!";
1462
  }
1463
 
1464
- // Simulate RAG retrieval
1465
  const relevantKnowledge = this.findRelevantKnowledge(query);
1466
 
1467
  if (relevantKnowledge.length === 0) {
1468
  return "I couldn't find specific information about that in my knowledge base. Could you rephrase or ask something else?";
1469
  }
1470
 
1471
- // Generate response based on retrieved knowledge
1472
  return this.generateResponse(query, relevantKnowledge);
1473
  }
1474
 
@@ -1541,7 +2039,7 @@
1541
  volume: 0.8
1542
  };
1543
 
1544
- this.testScript = "Hello there! This is a test to see how natural and fluid my voice sounds. I'm going to tell you a little story about learning and discovery. Imagine you're walking through a beautiful forest on a sunny day. The light filters through the leaves, creating patterns on the ground. Birds are singing in the trees, and there's a gentle breeze carrying the scent of flowers. You come across a small stream, and you sit on a rock to listen to the water flowing. It's in moments like these that we often have our best ideas and clearest thoughts. Learning is like this forest walk - it's a journey of discovery where each step reveals something new and wonderful. The key is to stay curious, keep exploring, and enjoy the process. Now, how does my voice sound to you? Is it clear, natural, and pleasant to listen to?";
1545
 
1546
  this.initVoices();
1547
  this.setupEventListeners();
@@ -1726,12 +2224,12 @@
1726
  }
1727
  }
1728
 
1729
- // Chat Interface
1730
  class ChatInterface {
1731
- constructor(ragTutor) {
1732
  this.ragTutor = ragTutor;
 
1733
  this.isListening = false;
1734
- this.voiceAnimationInterval = null;
1735
  this.initChat();
1736
  }
1737
 
@@ -1853,24 +2351,59 @@
1853
  }
1854
 
1855
  async processAIResponse(userMessage) {
 
 
 
 
 
 
1856
  const processingTime = 1000 + Math.random() * 2000;
1857
 
1858
  setTimeout(async () => {
1859
  let response;
1860
- if (this.ragTutor && this.ragTutor.vectorStore) {
1861
- response = await this.ragTutor.queryKnowledge(userMessage);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1862
  } else {
1863
- response = this.generateAIResponse(userMessage);
 
1864
  }
1865
 
 
1866
  this.addMessage(response, 'ai');
1867
 
 
1868
  if (window.voiceSynthesis) {
1869
  setTimeout(() => {
1870
  window.voiceSynthesis.speak(response);
1871
  }, 300);
1872
  }
1873
 
 
1874
  if (window.visualization) {
1875
  window.visualization.setPreset('responding');
1876
 
@@ -1881,6 +2414,20 @@
1881
  }, processingTime);
1882
  }
1883
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1884
  generateAIResponse(userMessage) {
1885
  const responses = {
1886
  quantum: "Quantum computing leverages quantum mechanics to process information. Unlike classical bits (0 or 1), quantum bits (qubits) can exist in superposition, enabling parallel computation.",
@@ -2192,8 +2739,11 @@
2192
  // Initialize RAG AI Tutor
2193
  window.ragTutor = new RAGAITutor();
2194
 
2195
- // Initialize chat interface
2196
- window.chatInterface = new ChatInterface(window.ragTutor);
 
 
 
2197
 
2198
  // Initialize voice synthesis
2199
  if ('speechSynthesis' in window) {
@@ -2217,6 +2767,20 @@
2217
 
2218
  window.visualization.setPreset('idle');
2219
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2220
  }, 100);
2221
  });
2222
 
 
8
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
9
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
  <style>
11
+ /* ALL EXISTING CSS REMAINS EXACTLY THE SAME */
12
  * {
13
  margin: 0;
14
  padding: 0;
 
24
  width: 100vw;
25
  }
26
 
 
27
  .mobile-nav {
28
  display: none;
29
  position: fixed;
 
79
  z-index: 999;
80
  }
81
 
 
82
  .main-container {
83
  display: flex;
84
  height: 100vh;
 
86
  position: relative;
87
  }
88
 
 
89
  .side-panel {
90
  width: 320px;
91
  height: 100vh;
 
105
  gap: 25px;
106
  }
107
 
 
108
  .side-panel.right {
109
  border-right: none;
110
  border-left: 1px solid rgba(255, 255, 255, 0.1);
 
113
  gap: 25px;
114
  }
115
 
 
116
  .main-content {
117
  flex: 1;
118
  display: flex;
 
124
  overflow: hidden;
125
  }
126
 
 
127
  #canvasContainer {
128
  width: 100%;
129
  height: 70vh;
 
140
  height: 100%;
141
  }
142
 
 
143
  .chat-interface {
144
  width: 100%;
145
  max-width: 800px;
 
346
  transform: translateY(-2px);
347
  }
348
 
 
349
  .card {
350
  background: rgba(20, 20, 30, 0.8);
351
  border-radius: 15px;
 
368
  font-size: 1em;
369
  }
370
 
 
371
  .accordion {
372
  margin-bottom: 15px;
373
  }
 
405
  padding: 15px;
406
  }
407
 
 
408
  .control-group {
409
  margin-bottom: 20px;
410
  }
 
454
  font-weight: 500;
455
  }
456
 
 
457
  .button-grid {
458
  display: grid;
459
  grid-template-columns: repeat(3, 1fr);
 
540
  background: rgba(255, 90, 90, 0.2);
541
  }
542
 
 
543
  .rag-textarea {
544
  width: 100%;
545
  height: 100px;
 
627
  border: 1px solid rgba(0, 255, 157, 0.2);
628
  }
629
 
 
630
  .loading-screen {
631
  position: fixed;
632
  top: 0;
 
703
  50% { opacity: 0.3; }
704
  }
705
 
 
706
  @media (max-width: 1200px) {
707
  .side-panel {
708
  width: 280px;
 
1050
  <i class="fas fa-chevron-down"></i>
1051
  </div>
1052
  <div class="accordion-content" id="llmControls">
1053
+ <div class="control-group">
1054
+ <label>Primary LLM API</label>
1055
+ <select class="voice-select" id="llmProvider">
1056
+ <option value="huggingface">Hugging Face</option>
1057
+ <option value="openai">OpenAI</option>
1058
+ <option value="anthropic">Anthropic Claude</option>
1059
+ <option value="google">Google Gemini</option>
1060
+ <option value="azure">Azure OpenAI</option>
1061
+ <option value="local">Local API</option>
1062
+ </select>
1063
+ </div>
1064
+
1065
  <div class="control-group">
1066
  <label>API Endpoint</label>
1067
+ <input type="text" class="rag-textarea" id="apiEndpoint" placeholder="https://api-inference.huggingface.co/models/microsoft/DialoGPT-medium">
1068
  </div>
1069
 
1070
  <div class="control-group">
 
1072
  <input type="password" class="rag-textarea" id="apiKey" placeholder="Enter your API key">
1073
  </div>
1074
 
1075
+ <div class="control-group">
1076
+ <label>Model Name</label>
1077
+ <input type="text" class="rag-textarea" id="modelName" placeholder="microsoft/DialoGPT-medium">
1078
+ </div>
1079
+
1080
  <div class="rag-controls">
1081
  <button class="rag-btn" id="testApiBtn">
1082
  <i class="fas fa-wifi"></i>
 
1098
  </aside>
1099
  </div>
1100
 
1101
+ <script>
1102
+ // Check if Three.js loaded properly
1103
+ function checkThreeJS() {
1104
+ if (typeof THREE === 'undefined') {
1105
+ console.error('Three.js failed to load');
1106
+ showError('Three.js library failed to load. Please check your internet connection.');
1107
+ return false;
1108
+ }
1109
+ return true;
1110
+ }
1111
+
1112
+ function showError(message) {
1113
+ const errorScreen = document.getElementById('errorScreen');
1114
+ const errorMessage = document.getElementById('errorMessage');
1115
+ const loadingScreen = document.getElementById('loadingScreen');
1116
+
1117
+ loadingScreen.style.display = 'none';
1118
+ errorMessage.textContent = message;
1119
+ errorScreen.style.display = 'flex';
1120
+ }
1121
+
1122
+ function hideLoading() {
1123
+ const loadingScreen = document.getElementById('loadingScreen');
1124
+ loadingScreen.style.opacity = '0';
1125
+ setTimeout(() => {
1126
+ loadingScreen.style.display = 'none';
1127
+ }, 500);
1128
+ }
1129
+
1130
+ function updateStatus(text) {
1131
+ document.getElementById('loadingText').textContent = text;
1132
+ }
1133
+
1134
+ // ==================== FULLY FUNCTIONAL LLM INTEGRATION ====================
1135
  class LLMIntegration {
1136
  constructor() {
1137
+ this.provider = 'huggingface';
1138
  this.apiEndpoint = '';
1139
  this.apiKey = '';
1140
+ this.modelName = '';
1141
  this.isConnected = false;
1142
+ this.connectionTested = false;
1143
+
1144
+ // Default endpoints for each provider
1145
+ this.defaultEndpoints = {
1146
+ 'huggingface': 'https://api-inference.huggingface.co/models/microsoft/DialoGPT-medium',
1147
+ 'openai': 'https://api.openai.com/v1/chat/completions',
1148
+ 'anthropic': 'https://api.anthropic.com/v1/messages',
1149
+ 'google': 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent',
1150
+ 'azure': 'https://YOUR_RESOURCE.openai.azure.com/openai/deployments/YOUR_DEPLOYMENT/chat/completions',
1151
+ 'local': 'http://localhost:11434/api/generate'
1152
+ };
1153
+
1154
+ this.init();
1155
  }
1156
 
1157
+ init() {
 
1158
  this.loadSettings();
1159
+ this.setupEventListeners();
1160
+ this.updateProviderUI();
 
 
 
1161
  }
1162
 
1163
  loadSettings() {
1164
+ try {
1165
+ const settings = JSON.parse(localStorage.getItem('aiTutorLLMSettings')) || {};
1166
+
1167
+ this.provider = settings.provider || 'huggingface';
1168
+ this.apiEndpoint = settings.apiEndpoint || this.defaultEndpoints[this.provider];
1169
+ this.apiKey = settings.apiKey || '';
1170
+ this.modelName = settings.modelName || '';
1171
+
1172
+ // Update UI
1173
+ document.getElementById('llmProvider').value = this.provider;
1174
+ document.getElementById('apiEndpoint').value = this.apiEndpoint;
1175
+ document.getElementById('apiKey').value = this.apiKey;
1176
+ document.getElementById('modelName').value = this.modelName;
1177
+
1178
+ console.log('Loaded LLM settings:', {
1179
+ provider: this.provider,
1180
+ endpoint: this.apiEndpoint.substring(0, 50) + '...',
1181
+ hasKey: !!this.apiKey,
1182
+ model: this.modelName
1183
+ });
1184
+
1185
+ } catch (error) {
1186
+ console.error('Error loading LLM settings:', error);
1187
  }
1188
  }
1189
 
1190
  saveSettings() {
1191
+ try {
1192
+ const settings = {
1193
+ provider: this.provider,
1194
+ apiEndpoint: this.apiEndpoint,
1195
+ apiKey: this.apiKey,
1196
+ modelName: this.modelName,
1197
+ savedAt: new Date().toISOString()
1198
+ };
1199
+
1200
+ localStorage.setItem('aiTutorLLMSettings', JSON.stringify(settings));
1201
+ console.log('Saved LLM settings');
1202
+ return true;
1203
+ } catch (error) {
1204
+ console.error('Error saving LLM settings:', error);
1205
+ return false;
1206
  }
1207
+ }
1208
+
1209
+ setupEventListeners() {
1210
+ // Provider change
1211
+ document.getElementById('llmProvider').addEventListener('change', (e) => {
1212
+ this.provider = e.target.value;
1213
+ this.apiEndpoint = this.defaultEndpoints[this.provider];
1214
+ document.getElementById('apiEndpoint').value = this.apiEndpoint;
1215
+ this.updateProviderUI();
1216
+ });
1217
 
1218
+ // Endpoint change
1219
+ document.getElementById('apiEndpoint').addEventListener('input', (e) => {
1220
+ this.apiEndpoint = e.target.value.trim();
1221
+ });
1222
 
1223
+ // API Key change
1224
+ document.getElementById('apiKey').addEventListener('input', (e) => {
1225
+ this.apiKey = e.target.value.trim();
1226
+ });
1227
+
1228
+ // Model name change
1229
+ document.getElementById('modelName').addEventListener('input', (e) => {
1230
+ this.modelName = e.target.value.trim();
1231
+ });
1232
+
1233
+ // Test connection button
1234
+ document.getElementById('testApiBtn').addEventListener('click', () => {
1235
+ this.testConnection();
1236
+ });
1237
+
1238
+ // Save settings button
1239
+ document.getElementById('saveApiBtn').addEventListener('click', () => {
1240
+ this.saveSettings();
1241
+ this.showApiStatus('Settings saved successfully!', 'success');
1242
+ });
1243
+ }
1244
+
1245
+ updateProviderUI() {
1246
+ // Update placeholder based on provider
1247
+ const endpointInput = document.getElementById('apiEndpoint');
1248
+ const keyInput = document.getElementById('apiKey');
1249
+ const modelInput = document.getElementById('modelName');
1250
+
1251
+ switch(this.provider) {
1252
+ case 'huggingface':
1253
+ endpointInput.placeholder = 'https://api-inference.huggingface.co/models/{model}';
1254
+ keyInput.placeholder = 'Your Hugging Face API token';
1255
+ modelInput.placeholder = 'microsoft/DialoGPT-medium';
1256
+ break;
1257
+ case 'openai':
1258
+ endpointInput.placeholder = 'https://api.openai.com/v1/chat/completions';
1259
+ keyInput.placeholder = 'Your OpenAI API key';
1260
+ modelInput.placeholder = 'gpt-3.5-turbo';
1261
+ break;
1262
+ case 'anthropic':
1263
+ endpointInput.placeholder = 'https://api.anthropic.com/v1/messages';
1264
+ keyInput.placeholder = 'Your Anthropic API key';
1265
+ modelInput.placeholder = 'claude-3-sonnet-20240229';
1266
+ break;
1267
+ case 'google':
1268
+ endpointInput.placeholder = 'https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent';
1269
+ keyInput.placeholder = 'Your Google API key';
1270
+ modelInput.placeholder = 'gemini-pro';
1271
+ break;
1272
+ case 'azure':
1273
+ endpointInput.placeholder = 'https://{resource}.openai.azure.com/openai/deployments/{deployment}/chat/completions';
1274
+ keyInput.placeholder = 'Your Azure OpenAI API key';
1275
+ modelInput.placeholder = 'gpt-35-turbo';
1276
+ break;
1277
+ case 'local':
1278
+ endpointInput.placeholder = 'http://localhost:11434/api/generate';
1279
+ keyInput.placeholder = 'Leave empty for local setup';
1280
+ modelInput.placeholder = 'llama2';
1281
+ break;
1282
+ }
1283
  }
1284
 
1285
  async testConnection() {
1286
+ if (!this.apiEndpoint) {
1287
+ this.showApiStatus('Please enter an API endpoint', 'error');
1288
+ return false;
1289
+ }
1290
+
1291
+ if (this.provider !== 'local' && !this.apiKey) {
1292
+ this.showApiStatus('Please enter an API key', 'error');
1293
  return false;
1294
  }
1295
 
1296
+ this.showApiStatus('Testing connection...', 'processing');
1297
+
1298
  try {
1299
+ let testResult;
 
 
 
 
 
 
 
 
 
 
 
 
1300
 
1301
+ switch(this.provider) {
1302
+ case 'huggingface':
1303
+ testResult = await this.testHuggingFaceConnection();
1304
+ break;
1305
+ case 'openai':
1306
+ testResult = await this.testOpenAIConnection();
1307
+ break;
1308
+ case 'anthropic':
1309
+ testResult = await this.testAnthropicConnection();
1310
+ break;
1311
+ case 'google':
1312
+ testResult = await this.testGoogleConnection();
1313
+ break;
1314
+ case 'azure':
1315
+ testResult = await this.testAzureConnection();
1316
+ break;
1317
+ case 'local':
1318
+ testResult = await this.testLocalConnection();
1319
+ break;
1320
+ default:
1321
+ testResult = await this.testGenericConnection();
1322
+ }
1323
+
1324
+ if (testResult.success) {
1325
+ this.isConnected = true;
1326
+ this.connectionTested = true;
1327
+ this.showApiStatus(`Connected successfully to ${this.provider}`, 'success');
1328
+ return true;
1329
+ } else {
1330
+ this.isConnected = false;
1331
+ this.showApiStatus(`Connection failed: ${testResult.error}`, 'error');
1332
+ return false;
1333
+ }
1334
  } catch (error) {
 
1335
  this.isConnected = false;
1336
+ this.showApiStatus(`Connection error: ${error.message}`, 'error');
1337
  return false;
1338
  }
1339
  }
1340
 
1341
+ async testHuggingFaceConnection() {
1342
+ const model = this.modelName || 'microsoft/DialoGPT-medium';
1343
+ const endpoint = this.apiEndpoint.replace('{model}', model);
1344
+
1345
+ const response = await fetch(endpoint, {
1346
+ method: 'POST',
1347
+ headers: {
1348
+ 'Authorization': `Bearer ${this.apiKey}`,
1349
+ 'Content-Type': 'application/json'
1350
+ },
1351
+ body: JSON.stringify({
1352
+ inputs: 'Hello',
1353
+ parameters: {
1354
+ max_new_tokens: 10
1355
+ }
1356
+ })
1357
+ });
1358
+
1359
+ if (response.ok) {
1360
+ return { success: true };
1361
+ } else {
1362
+ return {
1363
+ success: false,
1364
+ error: `HTTP ${response.status}: ${response.statusText}`
1365
+ };
1366
+ }
1367
+ }
1368
+
1369
+ async testOpenAIConnection() {
1370
+ const response = await fetch(this.apiEndpoint, {
1371
+ method: 'POST',
1372
+ headers: {
1373
+ 'Authorization': `Bearer ${this.apiKey}`,
1374
+ 'Content-Type': 'application/json'
1375
+ },
1376
+ body: JSON.stringify({
1377
+ model: this.modelName || 'gpt-3.5-turbo',
1378
+ messages: [{ role: 'user', content: 'Hello' }],
1379
+ max_tokens: 10
1380
+ })
1381
+ });
1382
+
1383
+ if (response.ok) {
1384
+ return { success: true };
1385
+ } else {
1386
+ const errorData = await response.json().catch(() => ({}));
1387
+ return {
1388
+ success: false,
1389
+ error: errorData.error?.message || `HTTP ${response.status}`
1390
+ };
1391
+ }
1392
+ }
1393
+
1394
+ async testAnthropicConnection() {
1395
+ const response = await fetch(this.apiEndpoint, {
1396
+ method: 'POST',
1397
+ headers: {
1398
+ 'x-api-key': this.apiKey,
1399
+ 'anthropic-version': '2023-06-01',
1400
+ 'Content-Type': 'application/json'
1401
+ },
1402
+ body: JSON.stringify({
1403
+ model: this.modelName || 'claude-3-sonnet-20240229',
1404
+ messages: [{ role: 'user', content: 'Hello' }],
1405
+ max_tokens: 10
1406
+ })
1407
+ });
1408
+
1409
+ if (response.ok) {
1410
+ return { success: true };
1411
+ } else {
1412
+ const errorData = await response.json().catch(() => ({}));
1413
+ return {
1414
+ success: false,
1415
+ error: errorData.error?.message || `HTTP ${response.status}`
1416
+ };
1417
+ }
1418
+ }
1419
+
1420
+ async testGoogleConnection() {
1421
+ const endpoint = this.apiEndpoint.includes('{model}')
1422
+ ? this.apiEndpoint.replace('{model}', this.modelName || 'gemini-pro')
1423
+ : this.apiEndpoint;
1424
+
1425
+ const url = new URL(endpoint);
1426
+ url.searchParams.append('key', this.apiKey);
1427
+
1428
+ const response = await fetch(url.toString(), {
1429
+ method: 'POST',
1430
+ headers: {
1431
+ 'Content-Type': 'application/json'
1432
+ },
1433
+ body: JSON.stringify({
1434
+ contents: [{
1435
+ parts: [{ text: 'Hello' }]
1436
+ }]
1437
+ })
1438
+ });
1439
+
1440
+ if (response.ok) {
1441
+ return { success: true };
1442
+ } else {
1443
+ const errorData = await response.json().catch(() => ({}));
1444
+ return {
1445
+ success: false,
1446
+ error: errorData.error?.message || `HTTP ${response.status}`
1447
+ };
1448
+ }
1449
+ }
1450
+
1451
+ async testAzureConnection() {
1452
+ const response = await fetch(this.apiEndpoint, {
1453
+ method: 'POST',
1454
+ headers: {
1455
+ 'api-key': this.apiKey,
1456
+ 'Content-Type': 'application/json'
1457
+ },
1458
+ body: JSON.stringify({
1459
+ messages: [{ role: 'user', content: 'Hello' }],
1460
+ max_tokens: 10
1461
+ })
1462
+ });
1463
+
1464
+ if (response.ok) {
1465
+ return { success: true };
1466
+ } else {
1467
+ const errorData = await response.json().catch(() => ({}));
1468
+ return {
1469
+ success: false,
1470
+ error: errorData.error?.message || `HTTP ${response.status}`
1471
+ };
1472
+ }
1473
+ }
1474
+
1475
+ async testLocalConnection() {
1476
+ const response = await fetch(this.apiEndpoint, {
1477
+ method: 'POST',
1478
+ headers: {
1479
+ 'Content-Type': 'application/json'
1480
+ },
1481
+ body: JSON.stringify({
1482
+ model: this.modelName || 'llama2',
1483
+ prompt: 'Hello',
1484
+ stream: false
1485
+ })
1486
+ });
1487
+
1488
+ if (response.ok) {
1489
+ return { success: true };
1490
+ } else {
1491
+ return {
1492
+ success: false,
1493
+ error: `HTTP ${response.status}`
1494
+ };
1495
+ }
1496
+ }
1497
+
1498
+ async testGenericConnection() {
1499
+ const response = await fetch(this.apiEndpoint, {
1500
+ method: 'GET',
1501
+ headers: {
1502
+ 'Authorization': this.apiKey ? `Bearer ${this.apiKey}` : undefined,
1503
+ 'Content-Type': 'application/json'
1504
+ }
1505
+ });
1506
+
1507
+ if (response.ok) {
1508
+ return { success: true };
1509
+ } else {
1510
+ return {
1511
+ success: false,
1512
+ error: `HTTP ${response.status}`
1513
+ };
1514
+ }
1515
+ }
1516
+
1517
  async generateResponse(prompt, context = '') {
1518
+ if (!this.isConnected) {
1519
+ console.log('LLM not connected, using fallback');
1520
  return null;
1521
  }
1522
 
1523
  try {
1524
  const fullPrompt = context ? `${context}\n\nQuestion: ${prompt}` : prompt;
1525
 
1526
+ switch(this.provider) {
1527
+ case 'huggingface':
1528
+ return await this.generateHuggingFaceResponse(fullPrompt);
1529
+ case 'openai':
1530
+ return await this.generateOpenAIResponse(fullPrompt);
1531
+ case 'anthropic':
1532
+ return await this.generateAnthropicResponse(fullPrompt);
1533
+ case 'google':
1534
+ return await this.generateGoogleResponse(fullPrompt);
1535
+ case 'azure':
1536
+ return await this.generateAzureResponse(fullPrompt);
1537
+ case 'local':
1538
+ return await this.generateLocalResponse(fullPrompt);
1539
+ default:
1540
+ return await this.generateGenericResponse(fullPrompt);
 
 
 
 
1541
  }
 
 
 
1542
  } catch (error) {
1543
+ console.error('LLM generation error:', error);
1544
  return null;
1545
  }
1546
  }
1547
+
1548
+ async generateHuggingFaceResponse(prompt) {
1549
+ const model = this.modelName || 'microsoft/DialoGPT-medium';
1550
+ const endpoint = this.apiEndpoint.replace('{model}', model);
1551
+
1552
+ const response = await fetch(endpoint, {
1553
+ method: 'POST',
1554
+ headers: {
1555
+ 'Authorization': `Bearer ${this.apiKey}`,
1556
+ 'Content-Type': 'application/json'
1557
+ },
1558
+ body: JSON.stringify({
1559
+ inputs: prompt,
1560
+ parameters: {
1561
+ max_new_tokens: 500,
1562
+ temperature: 0.7,
1563
+ top_p: 0.9,
1564
+ repetition_penalty: 1.1,
1565
+ return_full_text: false
1566
+ }
1567
+ })
1568
+ });
1569
+
1570
+ if (!response.ok) {
1571
+ throw new Error(`HTTP ${response.status}`);
1572
+ }
1573
+
1574
+ const data = await response.json();
1575
+ return data[0]?.generated_text || data.generated_text || '';
1576
+ }
1577
+
1578
+ async generateOpenAIResponse(prompt) {
1579
+ const response = await fetch(this.apiEndpoint, {
1580
+ method: 'POST',
1581
+ headers: {
1582
+ 'Authorization': `Bearer ${this.apiKey}`,
1583
+ 'Content-Type': 'application/json'
1584
+ },
1585
+ body: JSON.stringify({
1586
+ model: this.modelName || 'gpt-3.5-turbo',
1587
+ messages: [
1588
+ { role: 'system', content: 'You are a helpful AI tutor.' },
1589
+ { role: 'user', content: prompt }
1590
+ ],
1591
+ max_tokens: 500,
1592
+ temperature: 0.7
1593
+ })
1594
+ });
1595
+
1596
+ if (!response.ok) {
1597
+ const errorData = await response.json();
1598
+ throw new Error(errorData.error?.message || `HTTP ${response.status}`);
1599
+ }
1600
+
1601
+ const data = await response.json();
1602
+ return data.choices[0]?.message?.content || '';
1603
+ }
1604
+
1605
+ async generateAnthropicResponse(prompt) {
1606
+ const response = await fetch(this.apiEndpoint, {
1607
+ method: 'POST',
1608
+ headers: {
1609
+ 'x-api-key': this.apiKey,
1610
+ 'anthropic-version': '2023-06-01',
1611
+ 'Content-Type': 'application/json'
1612
+ },
1613
+ body: JSON.stringify({
1614
+ model: this.modelName || 'claude-3-sonnet-20240229',
1615
+ messages: [{ role: 'user', content: prompt }],
1616
+ max_tokens: 500
1617
+ })
1618
+ });
1619
+
1620
+ if (!response.ok) {
1621
+ const errorData = await response.json();
1622
+ throw new Error(errorData.error?.message || `HTTP ${response.status}`);
1623
+ }
1624
+
1625
+ const data = await response.json();
1626
+ return data.content[0]?.text || '';
1627
+ }
1628
+
1629
+ async generateGoogleResponse(prompt) {
1630
+ const endpoint = this.apiEndpoint.includes('{model}')
1631
+ ? this.apiEndpoint.replace('{model}', this.modelName || 'gemini-pro')
1632
+ : this.apiEndpoint;
1633
+
1634
+ const url = new URL(endpoint);
1635
+ url.searchParams.append('key', this.apiKey);
1636
+
1637
+ const response = await fetch(url.toString(), {
1638
+ method: 'POST',
1639
+ headers: {
1640
+ 'Content-Type': 'application/json'
1641
+ },
1642
+ body: JSON.stringify({
1643
+ contents: [{
1644
+ parts: [{ text: prompt }]
1645
+ }],
1646
+ generationConfig: {
1647
+ maxOutputTokens: 500,
1648
+ temperature: 0.7
1649
+ }
1650
+ })
1651
+ });
1652
+
1653
+ if (!response.ok) {
1654
+ const errorData = await response.json();
1655
+ throw new Error(errorData.error?.message || `HTTP ${response.status}`);
1656
+ }
1657
+
1658
+ const data = await response.json();
1659
+ return data.candidates?.[0]?.content?.parts?.[0]?.text || '';
1660
+ }
1661
+
1662
+ async generateAzureResponse(prompt) {
1663
+ const response = await fetch(this.apiEndpoint, {
1664
+ method: 'POST',
1665
+ headers: {
1666
+ 'api-key': this.apiKey,
1667
+ 'Content-Type': 'application/json'
1668
+ },
1669
+ body: JSON.stringify({
1670
+ messages: [
1671
+ { role: 'system', content: 'You are a helpful AI tutor.' },
1672
+ { role: 'user', content: prompt }
1673
+ ],
1674
+ max_tokens: 500,
1675
+ temperature: 0.7
1676
+ })
1677
+ });
1678
+
1679
+ if (!response.ok) {
1680
+ const errorData = await response.json();
1681
+ throw new Error(errorData.error?.message || `HTTP ${response.status}`);
1682
+ }
1683
+
1684
+ const data = await response.json();
1685
+ return data.choices[0]?.message?.content || '';
1686
+ }
1687
+
1688
+ async generateLocalResponse(prompt) {
1689
+ const response = await fetch(this.apiEndpoint, {
1690
+ method: 'POST',
1691
+ headers: {
1692
+ 'Content-Type': 'application/json'
1693
+ },
1694
+ body: JSON.stringify({
1695
+ model: this.modelName || 'llama2',
1696
+ prompt: prompt,
1697
+ stream: false,
1698
+ options: {
1699
+ temperature: 0.7,
1700
+ num_predict: 500
1701
+ }
1702
+ })
1703
+ });
1704
+
1705
+ if (!response.ok) {
1706
+ throw new Error(`HTTP ${response.status}`);
1707
+ }
1708
+
1709
+ const data = await response.json();
1710
+ return data.response || '';
1711
+ }
1712
+
1713
+ async generateGenericResponse(prompt) {
1714
+ const response = await fetch(this.apiEndpoint, {
1715
+ method: 'POST',
1716
+ headers: {
1717
+ 'Authorization': this.apiKey ? `Bearer ${this.apiKey}` : undefined,
1718
+ 'Content-Type': 'application/json'
1719
+ },
1720
+ body: JSON.stringify({
1721
+ prompt: prompt,
1722
+ max_tokens: 500,
1723
+ temperature: 0.7
1724
+ })
1725
+ });
1726
+
1727
+ if (!response.ok) {
1728
+ throw new Error(`HTTP ${response.status}`);
1729
+ }
1730
+
1731
+ const data = await response.json();
1732
+ return data.text || data.response || data.choices?.[0]?.text || '';
1733
  }
 
 
 
 
 
 
 
1734
 
1735
+ showApiStatus(message, type = 'info') {
1736
+ const statusEl = document.getElementById('apiStatus');
1737
+ const statusText = document.getElementById('apiStatusText');
1738
+
1739
+ statusText.textContent = message;
1740
+
1741
+ const colors = {
1742
+ 'info': '#5a6cff',
1743
+ 'success': '#00ff9d',
1744
+ 'error': '#ff5a5a',
1745
+ 'processing': '#a0b0ff'
1746
+ };
1747
+
1748
+ statusEl.style.borderColor = colors[type] + '30';
1749
+ statusEl.style.background = colors[type] + '10';
1750
+ statusEl.style.color = colors[type];
1751
+
1752
+ statusEl.style.display = 'flex';
1753
+
1754
+ if (type !== 'processing') {
1755
+ setTimeout(() => {
1756
+ statusEl.style.display = 'none';
1757
+ }, 5000);
1758
+ }
1759
+ }
1760
  }
1761
 
1762
  // Mobile Menu Functionality
 
1776
  this.menuBtn.addEventListener('click', () => this.toggleMenu());
1777
  this.overlay.addEventListener('click', () => this.closeMenu());
1778
 
 
1779
  document.addEventListener('keydown', (e) => {
1780
  if (e.key === 'Escape') {
1781
  this.closeMenu();
 
1866
  }
1867
 
1868
  loadSampleKnowledge() {
 
1869
  this.addKnowledgeItem({
1870
  id: Date.now(),
1871
  title: "Physics Basics",
 
1884
  }
1885
 
1886
  setupEventListeners() {
 
1887
  document.getElementById('addKnowledgeBtn').addEventListener('click', () => {
1888
  this.addKnowledgeFromText();
1889
  });
1890
 
 
1891
  document.getElementById('trainBtn').addEventListener('click', () => {
1892
  this.trainRAGModel();
1893
  });
 
1930
  this.isTraining = true;
1931
  this.showRAGStatus('Starting RAG training...', 'processing');
1932
 
 
1933
  const progressBar = document.getElementById('trainingProgress');
1934
  progressBar.style.width = '0%';
1935
 
 
1936
  const steps = ['Preprocessing text', 'Creating embeddings', 'Building vector store', 'Optimizing retrieval'];
1937
 
1938
  for (let i = 0; i < steps.length; i++) {
1939
  this.showRAGStatus(steps[i], 'processing');
1940
  progressBar.style.width = `${((i + 1) / steps.length) * 100}%`;
1941
 
 
1942
  await this.sleep(1000);
1943
  }
1944
 
 
1945
  this.vectorStore = {
1946
  size: this.knowledgeBase.length,
1947
  trainedAt: new Date().toISOString(),
 
1951
  this.isTraining = false;
1952
  this.showRAGStatus(`RAG training complete! ${this.knowledgeBase.length} documents indexed.`, 'success');
1953
 
 
1954
  setTimeout(() => {
1955
  progressBar.style.width = '0%';
1956
  }, 2000);
 
1961
  return "I haven't been trained on any specific knowledge yet. Please add some content and train me first!";
1962
  }
1963
 
 
1964
  const relevantKnowledge = this.findRelevantKnowledge(query);
1965
 
1966
  if (relevantKnowledge.length === 0) {
1967
  return "I couldn't find specific information about that in my knowledge base. Could you rephrase or ask something else?";
1968
  }
1969
 
 
1970
  return this.generateResponse(query, relevantKnowledge);
1971
  }
1972
 
 
2039
  volume: 0.8
2040
  };
2041
 
2042
+ this.testScript = "Hello there! This is a test to see how natural and fluid my voice sounds. I'm going to tell you a little story about learning and discovery.";
2043
 
2044
  this.initVoices();
2045
  this.setupEventListeners();
 
2224
  }
2225
  }
2226
 
2227
+ // Chat Interface - FULLY INTEGRATED WITH LLM
2228
  class ChatInterface {
2229
+ constructor(ragTutor, llmIntegration) {
2230
  this.ragTutor = ragTutor;
2231
+ this.llmIntegration = llmIntegration;
2232
  this.isListening = false;
 
2233
  this.initChat();
2234
  }
2235
 
 
2351
  }
2352
 
2353
  async processAIResponse(userMessage) {
2354
+ // Update 3D visualization
2355
+ if (window.visualization) {
2356
+ window.visualization.setPreset('processing');
2357
+ }
2358
+
2359
+ // Show typing indicator (simulated delay)
2360
  const processingTime = 1000 + Math.random() * 2000;
2361
 
2362
  setTimeout(async () => {
2363
  let response;
2364
+
2365
+ // Try LLM API first if available and connected
2366
+ if (this.llmIntegration && this.llmIntegration.isConnected) {
2367
+ try {
2368
+ // Get context from RAG if available
2369
+ let context = '';
2370
+ if (this.ragTutor && this.ragTutor.vectorStore) {
2371
+ const relevantKnowledge = await this.ragTutor.queryKnowledge(userMessage);
2372
+ if (relevantKnowledge && !relevantKnowledge.includes("I haven't been trained") &&
2373
+ !relevantKnowledge.includes("I couldn't find")) {
2374
+ context = relevantKnowledge;
2375
+ }
2376
+ }
2377
+
2378
+ // Call LLM API
2379
+ response = await this.llmIntegration.generateResponse(userMessage, context);
2380
+
2381
+ if (!response) {
2382
+ throw new Error('No response from LLM API');
2383
+ }
2384
+
2385
+ console.log('LLM API response received');
2386
+
2387
+ } catch (error) {
2388
+ console.log('LLM API failed, using fallback:', error);
2389
+ response = await this.getFallbackResponse(userMessage);
2390
+ }
2391
  } else {
2392
+ // LLM not connected, use fallback
2393
+ response = await this.getFallbackResponse(userMessage);
2394
  }
2395
 
2396
+ // Add AI response to chat
2397
  this.addMessage(response, 'ai');
2398
 
2399
+ // Speak the response
2400
  if (window.voiceSynthesis) {
2401
  setTimeout(() => {
2402
  window.voiceSynthesis.speak(response);
2403
  }, 300);
2404
  }
2405
 
2406
+ // Update 3D visualization
2407
  if (window.visualization) {
2408
  window.visualization.setPreset('responding');
2409
 
 
2414
  }, processingTime);
2415
  }
2416
 
2417
+ async getFallbackResponse(userMessage) {
2418
+ // Try RAG first
2419
+ if (this.ragTutor && this.ragTutor.vectorStore) {
2420
+ const ragResponse = await this.ragTutor.queryKnowledge(userMessage);
2421
+ if (ragResponse && !ragResponse.includes("I haven't been trained") &&
2422
+ !ragResponse.includes("I couldn't find")) {
2423
+ return ragResponse;
2424
+ }
2425
+ }
2426
+
2427
+ // Fallback to local responses
2428
+ return this.generateAIResponse(userMessage);
2429
+ }
2430
+
2431
  generateAIResponse(userMessage) {
2432
  const responses = {
2433
  quantum: "Quantum computing leverages quantum mechanics to process information. Unlike classical bits (0 or 1), quantum bits (qubits) can exist in superposition, enabling parallel computation.",
 
2739
  // Initialize RAG AI Tutor
2740
  window.ragTutor = new RAGAITutor();
2741
 
2742
+ // Initialize FULLY FUNCTIONAL LLM Integration
2743
+ window.llmIntegration = new LLMIntegration();
2744
+
2745
+ // Initialize chat interface with BOTH RAG and LLM
2746
+ window.chatInterface = new ChatInterface(window.ragTutor, window.llmIntegration);
2747
 
2748
  // Initialize voice synthesis
2749
  if ('speechSynthesis' in window) {
 
2767
 
2768
  window.visualization.setPreset('idle');
2769
  }
2770
+
2771
+ // Test LLM connection on startup if credentials exist
2772
+ if (window.llmIntegration.apiKey && window.llmIntegration.apiEndpoint) {
2773
+ setTimeout(() => {
2774
+ window.llmIntegration.testConnection().then(connected => {
2775
+ if (connected) {
2776
+ console.log('LLM API auto-connected on startup');
2777
+ }
2778
+ });
2779
+ }, 2000);
2780
+ }
2781
+
2782
+ hideLoading();
2783
+
2784
  }, 100);
2785
  });
2786