mhndayesh commited on
Commit
b144a65
·
verified ·
1 Parent(s): a9eeb94

Upload app.js

Browse files
Files changed (1) hide show
  1. app.js +134 -0
app.js ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // --- CONFIGURATION ---
2
+ // Set this to your Railway URL (e.g., "https://your-app.up.railway.app")
3
+ // Leave as empty string "" if the frontend and backend are on the same server.
4
+ const BACKEND_URL = "";
5
+
6
+ const chatContainer = document.getElementById('chat-container');
7
+ const userInput = document.getElementById('user-input');
8
+ const sendBtn = document.getElementById('send-btn');
9
+ const statsDisplay = document.getElementById('pipeline-stats');
10
+
11
+ // BYOK Elements
12
+ const settingsToggle = document.getElementById('settings-toggle');
13
+ const settingsPanel = document.getElementById('settings-panel');
14
+ const apiKeyInput = document.getElementById('api-key-input');
15
+ const llmModelInput = document.getElementById('llm-model-input');
16
+ const embedModelInput = document.getElementById('embed-model-input');
17
+
18
+ // Load saved settings from localStorage
19
+ apiKeyInput.value = localStorage.getItem('byok_api_key') || '';
20
+ llmModelInput.value = localStorage.getItem('byok_llm_model') || 'openai/gpt-4o-mini';
21
+ embedModelInput.value = localStorage.getItem('byok_embed_model') || 'qwen/qwen3-embedding-8b';
22
+
23
+ // Toggle Settings Panel
24
+ settingsToggle.addEventListener('click', () => {
25
+ settingsPanel.classList.toggle('active');
26
+ });
27
+
28
+ /**
29
+ * Adds a message bubble to the chat container
30
+ */
31
+ function addMessage(text, role) {
32
+ // Remove welcome message if it exists
33
+ const welcome = document.querySelector('.welcome-message');
34
+ if (welcome) welcome.remove();
35
+
36
+ const msgDiv = document.createElement('div');
37
+ msgDiv.classList.add('message', `${role}-message`);
38
+ msgDiv.textContent = text;
39
+ chatContainer.appendChild(msgDiv);
40
+ chatContainer.scrollTop = chatContainer.scrollHeight;
41
+ return msgDiv;
42
+ }
43
+
44
+ /**
45
+ * Adds a visual typing indicator
46
+ */
47
+ function addLoadingIndicator() {
48
+ const loader = document.createElement('div');
49
+ loader.classList.add('message', 'bot-message', 'loading-msg');
50
+ loader.innerHTML = `
51
+ <div class="typing-indicator">
52
+ <span></span><span></span><span></span>
53
+ </div>
54
+ `;
55
+ chatContainer.appendChild(loader);
56
+ chatContainer.scrollTop = chatContainer.scrollHeight;
57
+ return loader;
58
+ }
59
+
60
+ /**
61
+ * Main function to send message and get BYOK response
62
+ */
63
+ async function sendMessage() {
64
+ const text = userInput.value.trim();
65
+ if (!text) return;
66
+
67
+ // Persist settings to localStorage
68
+ localStorage.setItem('byok_api_key', apiKeyInput.value);
69
+ localStorage.setItem('byok_llm_model', llmModelInput.value);
70
+ localStorage.setItem('byok_embed_model', embedModelInput.value);
71
+
72
+ // Clear input and add user message
73
+ userInput.value = '';
74
+ userInput.style.height = 'auto';
75
+ addMessage(text, 'user');
76
+
77
+ // Add loading indicator
78
+ const loader = addLoadingIndicator();
79
+
80
+ try {
81
+ const response = await fetch(`${BACKEND_URL}/chat`, {
82
+ method: 'POST',
83
+ headers: { 'Content-Type': 'application/json' },
84
+ body: JSON.stringify({
85
+ message: text,
86
+ api_key: apiKeyInput.value || null,
87
+ llm_model: llmModelInput.value || null,
88
+ embed_model: embedModelInput.value || null
89
+ })
90
+ });
91
+
92
+ const data = await response.json();
93
+
94
+ // Remove loader and add bot response
95
+ loader.remove();
96
+ if (data.answer) {
97
+ addMessage(data.answer, 'bot');
98
+
99
+ // Update performance stats
100
+ const pipeTime = data.total_time ? data.total_time.toFixed(1) : '--';
101
+ const retTime = data.timings && data.timings.retrieval ? data.timings.retrieval.toFixed(2) : '--';
102
+ statsDisplay.textContent = `Pipeline: ${pipeTime}s | Retrieval: ${retTime}s`;
103
+ } else {
104
+ addMessage('Error: No response from engine.', 'bot');
105
+ }
106
+ } catch (err) {
107
+ if (loader) loader.remove();
108
+ addMessage(`Error: ${err.message}`, 'bot');
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Helper for suggestion buttons
114
+ */
115
+ function useSuggestion(text) {
116
+ userInput.value = text;
117
+ sendMessage();
118
+ }
119
+
120
+ // Event Listeners
121
+ sendBtn.addEventListener('click', sendMessage);
122
+
123
+ userInput.addEventListener('keydown', (e) => {
124
+ if (e.key === 'Enter' && !e.shiftKey) {
125
+ e.preventDefault();
126
+ sendMessage();
127
+ }
128
+ });
129
+
130
+ // Auto-resize textarea as user types
131
+ userInput.addEventListener('input', function () {
132
+ this.style.height = 'auto';
133
+ this.style.height = (this.scrollHeight) + 'px';
134
+ });