webscout 8.3.2__py3-none-any.whl → 8.3.3__py3-none-any.whl
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.
Potentially problematic release.
This version of webscout might be problematic. Click here for more details.
- webscout/AIutel.py +146 -37
- webscout/Bing_search.py +1 -2
- webscout/Provider/AISEARCH/__init__.py +1 -0
- webscout/Provider/AISEARCH/stellar_search.py +132 -0
- webscout/Provider/ExaChat.py +84 -58
- webscout/Provider/HeckAI.py +85 -80
- webscout/Provider/Jadve.py +56 -50
- webscout/Provider/MiniMax.py +207 -0
- webscout/Provider/Nemotron.py +41 -13
- webscout/Provider/Netwrck.py +34 -51
- webscout/Provider/OPENAI/BLACKBOXAI.py +0 -1
- webscout/Provider/OPENAI/MiniMax.py +298 -0
- webscout/Provider/OPENAI/README.md +30 -29
- webscout/Provider/OPENAI/TogetherAI.py +4 -17
- webscout/Provider/OPENAI/__init__.py +3 -1
- webscout/Provider/OPENAI/autoproxy.py +752 -17
- webscout/Provider/OPENAI/base.py +7 -76
- webscout/Provider/OPENAI/deepinfra.py +42 -108
- webscout/Provider/OPENAI/flowith.py +179 -166
- webscout/Provider/OPENAI/friendli.py +233 -0
- webscout/Provider/OPENAI/monochat.py +329 -0
- webscout/Provider/OPENAI/pydantic_imports.py +1 -172
- webscout/Provider/OPENAI/toolbaz.py +1 -0
- webscout/Provider/OPENAI/typegpt.py +1 -1
- webscout/Provider/OPENAI/utils.py +19 -42
- webscout/Provider/OPENAI/x0gpt.py +14 -2
- webscout/Provider/OpenGPT.py +54 -32
- webscout/Provider/PI.py +58 -84
- webscout/Provider/StandardInput.py +32 -13
- webscout/Provider/TTI/README.md +9 -9
- webscout/Provider/TTI/__init__.py +2 -1
- webscout/Provider/TTI/aiarta.py +92 -78
- webscout/Provider/TTI/infip.py +212 -0
- webscout/Provider/TTI/monochat.py +220 -0
- webscout/Provider/TeachAnything.py +11 -3
- webscout/Provider/TextPollinationsAI.py +78 -70
- webscout/Provider/TogetherAI.py +32 -48
- webscout/Provider/Venice.py +37 -46
- webscout/Provider/VercelAI.py +27 -24
- webscout/Provider/WiseCat.py +35 -35
- webscout/Provider/WrDoChat.py +22 -26
- webscout/Provider/WritingMate.py +26 -22
- webscout/Provider/__init__.py +2 -2
- webscout/Provider/granite.py +48 -57
- webscout/Provider/koala.py +51 -39
- webscout/Provider/learnfastai.py +49 -64
- webscout/Provider/llmchat.py +79 -93
- webscout/Provider/llmchatco.py +63 -78
- webscout/Provider/multichat.py +51 -40
- webscout/Provider/oivscode.py +1 -1
- webscout/Provider/scira_chat.py +159 -96
- webscout/Provider/scnet.py +13 -13
- webscout/Provider/searchchat.py +13 -13
- webscout/Provider/sonus.py +12 -11
- webscout/Provider/toolbaz.py +25 -8
- webscout/Provider/turboseek.py +41 -42
- webscout/Provider/typefully.py +27 -12
- webscout/Provider/typegpt.py +41 -46
- webscout/Provider/uncovr.py +55 -90
- webscout/Provider/x0gpt.py +33 -17
- webscout/Provider/yep.py +79 -96
- webscout/auth/__init__.py +12 -1
- webscout/auth/providers.py +27 -5
- webscout/auth/routes.py +128 -104
- webscout/auth/server.py +367 -312
- webscout/client.py +121 -116
- webscout/litagent/Readme.md +68 -55
- webscout/litagent/agent.py +99 -9
- webscout/version.py +1 -1
- {webscout-8.3.2.dist-info → webscout-8.3.3.dist-info}/METADATA +102 -90
- {webscout-8.3.2.dist-info → webscout-8.3.3.dist-info}/RECORD +75 -87
- webscout/Provider/TTI/fastflux.py +0 -233
- webscout/Provider/Writecream.py +0 -246
- webscout/auth/static/favicon.svg +0 -11
- webscout/auth/swagger_ui.py +0 -203
- webscout/auth/templates/components/authentication.html +0 -237
- webscout/auth/templates/components/base.html +0 -103
- webscout/auth/templates/components/endpoints.html +0 -750
- webscout/auth/templates/components/examples.html +0 -491
- webscout/auth/templates/components/footer.html +0 -75
- webscout/auth/templates/components/header.html +0 -27
- webscout/auth/templates/components/models.html +0 -286
- webscout/auth/templates/components/navigation.html +0 -70
- webscout/auth/templates/static/api.js +0 -455
- webscout/auth/templates/static/icons.js +0 -168
- webscout/auth/templates/static/main.js +0 -784
- webscout/auth/templates/static/particles.js +0 -201
- webscout/auth/templates/static/styles.css +0 -3353
- webscout/auth/templates/static/ui.js +0 -374
- webscout/auth/templates/swagger_ui.html +0 -170
- {webscout-8.3.2.dist-info → webscout-8.3.3.dist-info}/WHEEL +0 -0
- {webscout-8.3.2.dist-info → webscout-8.3.3.dist-info}/entry_points.txt +0 -0
- {webscout-8.3.2.dist-info → webscout-8.3.3.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.3.2.dist-info → webscout-8.3.3.dist-info}/top_level.txt +0 -0
|
@@ -1,784 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WebScout API Documentation - Main JavaScript
|
|
3
|
-
* Handles UI interactions, API testing, and dynamic content
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Global application state
|
|
7
|
-
window.WebScoutApp = {
|
|
8
|
-
config: {},
|
|
9
|
-
currentApiKey: '',
|
|
10
|
-
activeTab: 'endpoints',
|
|
11
|
-
|
|
12
|
-
// Initialize the application
|
|
13
|
-
init() {
|
|
14
|
-
console.log('WebScout App initializing...');
|
|
15
|
-
this.config = window.WEBSCOUT_CONFIG || {};
|
|
16
|
-
this.loadSavedApiKey();
|
|
17
|
-
this.setupEventListeners();
|
|
18
|
-
this.initializePage();
|
|
19
|
-
this.initScrollIndicator();
|
|
20
|
-
this.hideLoadingScreen();
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
// Load saved API key from localStorage
|
|
24
|
-
loadSavedApiKey() {
|
|
25
|
-
const savedApiKey = localStorage.getItem('webscout_api_key');
|
|
26
|
-
if (savedApiKey) {
|
|
27
|
-
this.currentApiKey = savedApiKey;
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
// Setup all event listeners
|
|
32
|
-
setupEventListeners() {
|
|
33
|
-
// Tab navigation
|
|
34
|
-
document.querySelectorAll('.nav-tab').forEach(tab => {
|
|
35
|
-
tab.addEventListener('click', (e) => {
|
|
36
|
-
const tabName = e.target.closest('.nav-tab').dataset.tab;
|
|
37
|
-
this.showTab(tabName);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// Endpoint toggles - add direct event listeners
|
|
42
|
-
this.setupEndpointToggles();
|
|
43
|
-
|
|
44
|
-
// Example language tabs
|
|
45
|
-
document.querySelectorAll('.example-tab').forEach(tab => {
|
|
46
|
-
tab.addEventListener('click', (e) => {
|
|
47
|
-
const language = e.target.closest('.example-tab').dataset.language;
|
|
48
|
-
this.showExampleLanguage(language);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// View toggle for models
|
|
53
|
-
document.querySelectorAll('.view-btn').forEach(btn => {
|
|
54
|
-
btn.addEventListener('click', (e) => {
|
|
55
|
-
const view = e.target.closest('.view-btn').dataset.view;
|
|
56
|
-
this.toggleModelsView(view);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Search functionality
|
|
61
|
-
const searchInput = document.getElementById('model-search');
|
|
62
|
-
if (searchInput) {
|
|
63
|
-
searchInput.addEventListener('input', (e) => {
|
|
64
|
-
this.searchModels(e.target.value);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Filter functionality
|
|
69
|
-
const filterSelect = document.getElementById('model-filter');
|
|
70
|
-
if (filterSelect) {
|
|
71
|
-
filterSelect.addEventListener('change', (e) => {
|
|
72
|
-
this.filterModels(e.target.value);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Copy code buttons
|
|
77
|
-
document.addEventListener('click', (e) => {
|
|
78
|
-
if (e.target.classList.contains('copy-code-btn') || e.target.closest('.copy-code-btn')) {
|
|
79
|
-
const btn = e.target.closest('.copy-code-btn');
|
|
80
|
-
const codeId = btn.getAttribute('onclick')?.match(/copyCode\('([^']+)'\)/)?.[1];
|
|
81
|
-
if (codeId) {
|
|
82
|
-
this.copyCode(codeId);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
// Setup endpoint toggle functionality
|
|
89
|
-
setupEndpointToggles() {
|
|
90
|
-
// Wait for DOM to be fully ready
|
|
91
|
-
setTimeout(() => {
|
|
92
|
-
const headers = document.querySelectorAll('.endpoint-header');
|
|
93
|
-
console.log('Setting up endpoint toggles for', headers.length, 'headers');
|
|
94
|
-
|
|
95
|
-
headers.forEach((header, index) => {
|
|
96
|
-
// Remove any existing listeners
|
|
97
|
-
header.replaceWith(header.cloneNode(true));
|
|
98
|
-
const newHeader = document.querySelectorAll('.endpoint-header')[index];
|
|
99
|
-
|
|
100
|
-
newHeader.addEventListener('click', (e) => {
|
|
101
|
-
e.preventDefault();
|
|
102
|
-
e.stopPropagation();
|
|
103
|
-
console.log(`Endpoint header ${index} clicked`);
|
|
104
|
-
this.toggleEndpoint(newHeader);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Ensure it's clickable
|
|
108
|
-
newHeader.style.cursor = 'pointer';
|
|
109
|
-
console.log(`Added click handler to header ${index}`);
|
|
110
|
-
});
|
|
111
|
-
}, 100);
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
// Initialize page content
|
|
115
|
-
initializePage() {
|
|
116
|
-
// Update status indicator
|
|
117
|
-
this.updateStatusIndicator();
|
|
118
|
-
|
|
119
|
-
// Initialize syntax highlighting
|
|
120
|
-
if (typeof hljs !== 'undefined') {
|
|
121
|
-
hljs.highlightAll();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Set up periodic status checks
|
|
125
|
-
setInterval(() => {
|
|
126
|
-
this.updateStatusIndicator();
|
|
127
|
-
}, 30000);
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
// Hide loading screen
|
|
131
|
-
hideLoadingScreen() {
|
|
132
|
-
setTimeout(() => {
|
|
133
|
-
const loadingScreen = document.getElementById('loading-screen');
|
|
134
|
-
if (loadingScreen) {
|
|
135
|
-
loadingScreen.classList.add('hidden');
|
|
136
|
-
setTimeout(() => {
|
|
137
|
-
loadingScreen.style.display = 'none';
|
|
138
|
-
}, 300);
|
|
139
|
-
}
|
|
140
|
-
}, 1000);
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
// Show specific tab
|
|
144
|
-
showTab(tabName) {
|
|
145
|
-
// Hide all tab contents
|
|
146
|
-
document.querySelectorAll('.tab-content').forEach(tab => {
|
|
147
|
-
tab.classList.remove('active');
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// Remove active class from all nav tabs
|
|
151
|
-
document.querySelectorAll('.nav-tab').forEach(tab => {
|
|
152
|
-
tab.classList.remove('active');
|
|
153
|
-
tab.setAttribute('aria-selected', 'false');
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// Show selected tab content
|
|
157
|
-
const targetTab = document.getElementById(`${tabName}-panel`);
|
|
158
|
-
if (targetTab) {
|
|
159
|
-
targetTab.classList.add('active');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Add active class to selected nav tab
|
|
163
|
-
const activeNavTab = document.getElementById(`${tabName}-tab`);
|
|
164
|
-
if (activeNavTab) {
|
|
165
|
-
activeNavTab.classList.add('active');
|
|
166
|
-
activeNavTab.setAttribute('aria-selected', 'true');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
this.activeTab = tabName;
|
|
170
|
-
|
|
171
|
-
// Load models if models tab is selected
|
|
172
|
-
if (tabName === 'models') {
|
|
173
|
-
this.loadModels();
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
|
|
177
|
-
// Load models for the models tab
|
|
178
|
-
async loadModels() {
|
|
179
|
-
if (typeof loadModels === 'function') {
|
|
180
|
-
await loadModels();
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
// Search models
|
|
185
|
-
searchModels(query) {
|
|
186
|
-
if (typeof WebScoutUI !== 'undefined' && WebScoutUI.searchModels) {
|
|
187
|
-
WebScoutUI.searchModels(query);
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
// Filter models
|
|
192
|
-
filterModels(filter) {
|
|
193
|
-
if (typeof WebScoutUI !== 'undefined' && WebScoutUI.filterModels) {
|
|
194
|
-
WebScoutUI.filterModels(filter);
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
|
|
198
|
-
// Toggle endpoint expansion
|
|
199
|
-
toggleEndpoint(header) {
|
|
200
|
-
console.log('toggleEndpoint called with:', header);
|
|
201
|
-
const body = header.nextElementSibling;
|
|
202
|
-
const icon = header.querySelector('.expand-icon');
|
|
203
|
-
|
|
204
|
-
console.log('Body element:', body);
|
|
205
|
-
console.log('Icon element:', icon);
|
|
206
|
-
|
|
207
|
-
if (body && icon) {
|
|
208
|
-
const isExpanded = header.classList.contains('expanded');
|
|
209
|
-
console.log('Is expanded:', isExpanded);
|
|
210
|
-
|
|
211
|
-
if (isExpanded) {
|
|
212
|
-
header.classList.remove('expanded');
|
|
213
|
-
body.classList.remove('expanded');
|
|
214
|
-
body.style.display = 'none';
|
|
215
|
-
console.log('Collapsed endpoint');
|
|
216
|
-
} else {
|
|
217
|
-
header.classList.add('expanded');
|
|
218
|
-
body.classList.add('expanded');
|
|
219
|
-
body.style.display = 'block';
|
|
220
|
-
console.log('Expanded endpoint');
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Add animation class for smooth transition
|
|
224
|
-
body.classList.add('animate-slideDown');
|
|
225
|
-
setTimeout(() => {
|
|
226
|
-
body.classList.remove('animate-slideDown');
|
|
227
|
-
}, 300);
|
|
228
|
-
} else {
|
|
229
|
-
console.log('Missing body or icon element');
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
// Show example language
|
|
234
|
-
showExampleLanguage(language) {
|
|
235
|
-
// Hide all language examples
|
|
236
|
-
document.querySelectorAll('.language-examples').forEach(example => {
|
|
237
|
-
example.classList.remove('active');
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// Remove active class from all example tabs
|
|
241
|
-
document.querySelectorAll('.example-tab').forEach(tab => {
|
|
242
|
-
tab.classList.remove('active');
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
// Show selected language examples
|
|
246
|
-
const targetExample = document.getElementById(`${language}-examples`);
|
|
247
|
-
if (targetExample) {
|
|
248
|
-
targetExample.classList.add('active');
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Add active class to selected example tab
|
|
252
|
-
const activeTab = document.querySelector(`[data-language="${language}"]`);
|
|
253
|
-
if (activeTab) {
|
|
254
|
-
activeTab.classList.add('active');
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Re-highlight syntax
|
|
258
|
-
if (typeof hljs !== 'undefined') {
|
|
259
|
-
setTimeout(() => {
|
|
260
|
-
hljs.highlightAll();
|
|
261
|
-
}, 100);
|
|
262
|
-
}
|
|
263
|
-
},
|
|
264
|
-
|
|
265
|
-
// Toggle models view (grid/list)
|
|
266
|
-
toggleModelsView(view) {
|
|
267
|
-
const container = document.getElementById('models-container');
|
|
268
|
-
const buttons = document.querySelectorAll('.view-btn');
|
|
269
|
-
|
|
270
|
-
if (container) {
|
|
271
|
-
container.className = view === 'list' ? 'models-list' : 'models-grid';
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
buttons.forEach(btn => {
|
|
275
|
-
btn.classList.toggle('active', btn.dataset.view === view);
|
|
276
|
-
});
|
|
277
|
-
},
|
|
278
|
-
|
|
279
|
-
// Copy code to clipboard
|
|
280
|
-
copyCode(elementId) {
|
|
281
|
-
const element = document.getElementById(elementId);
|
|
282
|
-
if (element) {
|
|
283
|
-
const text = element.textContent || element.innerText;
|
|
284
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
285
|
-
this.showToast('Code copied to clipboard!', 'success');
|
|
286
|
-
}).catch(() => {
|
|
287
|
-
this.showToast('Failed to copy code', 'error');
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
// Update status indicator
|
|
293
|
-
async updateStatusIndicator() {
|
|
294
|
-
try {
|
|
295
|
-
const response = await fetch(`${this.config.baseUrl}/health`);
|
|
296
|
-
const indicator = document.getElementById('status-indicator');
|
|
297
|
-
if (indicator) {
|
|
298
|
-
indicator.textContent = response.ok ? '🟢' : '🔴';
|
|
299
|
-
}
|
|
300
|
-
} catch {
|
|
301
|
-
const indicator = document.getElementById('status-indicator');
|
|
302
|
-
if (indicator) {
|
|
303
|
-
indicator.textContent = '🔴';
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
|
|
308
|
-
// Initialize scroll indicator
|
|
309
|
-
initScrollIndicator() {
|
|
310
|
-
const scrollProgress = document.getElementById('scroll-progress');
|
|
311
|
-
if (!scrollProgress) return;
|
|
312
|
-
|
|
313
|
-
const updateScrollProgress = () => {
|
|
314
|
-
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
315
|
-
const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
|
|
316
|
-
const progress = (scrollTop / scrollHeight) * 100;
|
|
317
|
-
scrollProgress.style.width = `${Math.min(progress, 100)}%`;
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
window.addEventListener('scroll', updateScrollProgress);
|
|
321
|
-
updateScrollProgress(); // Initial call
|
|
322
|
-
},
|
|
323
|
-
|
|
324
|
-
// Toggle advanced parameters
|
|
325
|
-
toggleAdvanced(section) {
|
|
326
|
-
const advancedParams = document.getElementById(`${section}-advanced`);
|
|
327
|
-
const toggleBtn = document.querySelector(`[onclick="toggleAdvanced('${section}')"]`);
|
|
328
|
-
|
|
329
|
-
if (advancedParams && toggleBtn) {
|
|
330
|
-
const isVisible = advancedParams.classList.contains('show');
|
|
331
|
-
|
|
332
|
-
if (isVisible) {
|
|
333
|
-
advancedParams.classList.remove('show');
|
|
334
|
-
toggleBtn.classList.remove('expanded');
|
|
335
|
-
} else {
|
|
336
|
-
advancedParams.classList.add('show');
|
|
337
|
-
toggleBtn.classList.add('expanded');
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
},
|
|
341
|
-
|
|
342
|
-
// Test chat completion endpoint with simplified parameters
|
|
343
|
-
async testChatCompletion(event) {
|
|
344
|
-
event.preventDefault();
|
|
345
|
-
|
|
346
|
-
const startTime = Date.now();
|
|
347
|
-
|
|
348
|
-
// Get form values
|
|
349
|
-
const model = document.getElementById('chat-model').value;
|
|
350
|
-
const messages = document.getElementById('chat-messages').value;
|
|
351
|
-
const maxTokens = parseInt(document.getElementById('chat-max-tokens').value) || null;
|
|
352
|
-
const temperature = parseFloat(document.getElementById('chat-temperature').value) || null;
|
|
353
|
-
const topP = parseFloat(document.getElementById('chat-top-p').value) || null;
|
|
354
|
-
const timeout = parseInt(document.getElementById('chat-timeout').value) || null;
|
|
355
|
-
const stream = document.getElementById('chat-stream').checked;
|
|
356
|
-
|
|
357
|
-
if (!messages.trim()) {
|
|
358
|
-
this.showToast('Please enter messages', 'error');
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
let parsedMessages;
|
|
363
|
-
try {
|
|
364
|
-
parsedMessages = JSON.parse(messages);
|
|
365
|
-
} catch (error) {
|
|
366
|
-
this.showToast('Invalid JSON format for messages', 'error');
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Build request data with simplified parameters
|
|
371
|
-
const requestData = {
|
|
372
|
-
model: model,
|
|
373
|
-
messages: parsedMessages,
|
|
374
|
-
stream: stream
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
// Add optional parameters only if they have valid values
|
|
378
|
-
if (maxTokens && maxTokens > 0) {
|
|
379
|
-
requestData.max_tokens = maxTokens;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (temperature !== null && temperature >= 0 && temperature <= 2) {
|
|
383
|
-
requestData.temperature = temperature;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if (topP !== null && topP >= 0 && topP <= 1) {
|
|
387
|
-
requestData.top_p = topP;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (timeout && timeout > 0) {
|
|
391
|
-
requestData.timeout = timeout;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const responseDiv = document.getElementById('chat-response');
|
|
395
|
-
responseDiv.innerHTML = `
|
|
396
|
-
<div class="loading modern-loading">
|
|
397
|
-
<div class="loading-spinner"></div>
|
|
398
|
-
<span>Sending request...</span>
|
|
399
|
-
</div>
|
|
400
|
-
`;
|
|
401
|
-
|
|
402
|
-
try {
|
|
403
|
-
const response = await fetch('/v1/chat/completions', {
|
|
404
|
-
method: 'POST',
|
|
405
|
-
headers: {
|
|
406
|
-
'Content-Type': 'application/json',
|
|
407
|
-
'Authorization': 'Bearer your-api-key'
|
|
408
|
-
},
|
|
409
|
-
body: JSON.stringify(requestData)
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
const responseTime = Date.now() - startTime;
|
|
413
|
-
|
|
414
|
-
// Handle streaming response
|
|
415
|
-
if (stream && response.body) {
|
|
416
|
-
responseDiv.innerHTML = `
|
|
417
|
-
<div class="response-header modern-response-header">
|
|
418
|
-
<div class="response-status">
|
|
419
|
-
<span class="status-badge status-${response.status}">${response.status} ${response.statusText}</span>
|
|
420
|
-
<span class="response-time">Streaming...</span>
|
|
421
|
-
</div>
|
|
422
|
-
<button class="copy-btn" onclick="copyStreamContent()">
|
|
423
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
424
|
-
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
425
|
-
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
426
|
-
</svg>
|
|
427
|
-
Copy
|
|
428
|
-
</button>
|
|
429
|
-
</div>
|
|
430
|
-
<div class="response-body modern-response-body streaming">
|
|
431
|
-
<div class="stream-content" id="stream-content"></div>
|
|
432
|
-
<div class="stream-raw" id="stream-raw" style="display: none;"></div>
|
|
433
|
-
<div class="stream-controls">
|
|
434
|
-
<button class="stream-toggle" onclick="toggleStreamView()">Show Raw</button>
|
|
435
|
-
</div>
|
|
436
|
-
</div>
|
|
437
|
-
`;
|
|
438
|
-
|
|
439
|
-
await this.handleStreamingResponse(response, startTime);
|
|
440
|
-
} else {
|
|
441
|
-
// Handle regular response
|
|
442
|
-
const result = await response.json();
|
|
443
|
-
|
|
444
|
-
responseDiv.innerHTML = `
|
|
445
|
-
<div class="response-header modern-response-header">
|
|
446
|
-
<div class="response-status">
|
|
447
|
-
<span class="status-badge status-${response.status}">${response.status} ${response.statusText}</span>
|
|
448
|
-
<span class="response-time">${responseTime}ms</span>
|
|
449
|
-
</div>
|
|
450
|
-
<button class="copy-btn" onclick="copyToClipboard('${JSON.stringify(result).replace(/'/g, "\\'")}')">
|
|
451
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
452
|
-
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
453
|
-
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
454
|
-
</svg>
|
|
455
|
-
Copy
|
|
456
|
-
</button>
|
|
457
|
-
</div>
|
|
458
|
-
<pre class="response-body modern-response-body"><code class="language-json">${JSON.stringify(result, null, 2)}</code></pre>
|
|
459
|
-
`;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
this.showToast('Request completed successfully', 'success');
|
|
463
|
-
} catch (error) {
|
|
464
|
-
const responseTime = Date.now() - startTime;
|
|
465
|
-
responseDiv.innerHTML = `
|
|
466
|
-
<div class="response-header modern-response-header error">
|
|
467
|
-
<div class="response-status">
|
|
468
|
-
<span class="status-badge status-error">Error</span>
|
|
469
|
-
<span class="response-time">${responseTime}ms</span>
|
|
470
|
-
</div>
|
|
471
|
-
</div>
|
|
472
|
-
<div class="response-body modern-response-body error">
|
|
473
|
-
<div class="error-content">
|
|
474
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="error-icon">
|
|
475
|
-
<circle cx="12" cy="12" r="10"/>
|
|
476
|
-
<line x1="15" y1="9" x2="9" y2="15"/>
|
|
477
|
-
<line x1="9" y1="9" x2="15" y2="15"/>
|
|
478
|
-
</svg>
|
|
479
|
-
<div>
|
|
480
|
-
<strong>Request Failed</strong>
|
|
481
|
-
<p>${error.message}</p>
|
|
482
|
-
</div>
|
|
483
|
-
</div>
|
|
484
|
-
</div>
|
|
485
|
-
`;
|
|
486
|
-
this.showToast('Request failed', 'error');
|
|
487
|
-
}
|
|
488
|
-
},
|
|
489
|
-
|
|
490
|
-
// Handle streaming response
|
|
491
|
-
async handleStreamingResponse(response, startTime) {
|
|
492
|
-
const reader = response.body.getReader();
|
|
493
|
-
const decoder = new TextDecoder();
|
|
494
|
-
const streamContent = document.getElementById('stream-content');
|
|
495
|
-
const streamRaw = document.getElementById('stream-raw');
|
|
496
|
-
|
|
497
|
-
let fullContent = '';
|
|
498
|
-
let rawData = '';
|
|
499
|
-
let buffer = '';
|
|
500
|
-
|
|
501
|
-
try {
|
|
502
|
-
while (true) {
|
|
503
|
-
const { done, value } = await reader.read();
|
|
504
|
-
|
|
505
|
-
if (done) {
|
|
506
|
-
const finalTime = Date.now() - startTime;
|
|
507
|
-
document.querySelector('.response-time').textContent = `${finalTime}ms`;
|
|
508
|
-
break;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Decode the chunk
|
|
512
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
513
|
-
buffer += chunk;
|
|
514
|
-
rawData += chunk;
|
|
515
|
-
|
|
516
|
-
// Process complete lines
|
|
517
|
-
const lines = buffer.split('\n');
|
|
518
|
-
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
519
|
-
|
|
520
|
-
for (const line of lines) {
|
|
521
|
-
if (line.trim() === '') continue;
|
|
522
|
-
|
|
523
|
-
if (line.startsWith('data: ')) {
|
|
524
|
-
const data = line.slice(6); // Remove 'data: ' prefix
|
|
525
|
-
|
|
526
|
-
if (data === '[DONE]') {
|
|
527
|
-
streamContent.innerHTML += '<div class="stream-done">✅ Stream completed</div>';
|
|
528
|
-
continue;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
try {
|
|
532
|
-
const parsed = JSON.parse(data);
|
|
533
|
-
|
|
534
|
-
// Extract content from delta
|
|
535
|
-
if (parsed.choices && parsed.choices[0] && parsed.choices[0].delta && parsed.choices[0].delta.content) {
|
|
536
|
-
const content = parsed.choices[0].delta.content;
|
|
537
|
-
fullContent += content;
|
|
538
|
-
|
|
539
|
-
// Update the displayed content
|
|
540
|
-
streamContent.innerHTML = `
|
|
541
|
-
<div class="stream-message">
|
|
542
|
-
<strong>Generated Response:</strong>
|
|
543
|
-
<div class="stream-text">${fullContent}</div>
|
|
544
|
-
</div>
|
|
545
|
-
`;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// Add to raw display
|
|
549
|
-
streamRaw.innerHTML += `<div class="stream-chunk">data: ${JSON.stringify(parsed, null, 2)}</div>`;
|
|
550
|
-
|
|
551
|
-
} catch (e) {
|
|
552
|
-
// Handle non-JSON data lines
|
|
553
|
-
streamRaw.innerHTML += `<div class="stream-chunk">data: ${data}</div>`;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Auto-scroll to bottom
|
|
559
|
-
streamContent.scrollTop = streamContent.scrollHeight;
|
|
560
|
-
streamRaw.scrollTop = streamRaw.scrollHeight;
|
|
561
|
-
}
|
|
562
|
-
} catch (error) {
|
|
563
|
-
streamContent.innerHTML += `<div class="stream-error">❌ Stream error: ${error.message}</div>`;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Store full content for copying
|
|
567
|
-
window.streamFullContent = fullContent;
|
|
568
|
-
window.streamRawData = rawData;
|
|
569
|
-
},
|
|
570
|
-
|
|
571
|
-
// Test image generation endpoint
|
|
572
|
-
async testImageGeneration(event) {
|
|
573
|
-
event.preventDefault();
|
|
574
|
-
|
|
575
|
-
const startTime = Date.now();
|
|
576
|
-
|
|
577
|
-
// Get form values
|
|
578
|
-
const model = document.getElementById('image-model').value;
|
|
579
|
-
const prompt = document.getElementById('image-prompt').value;
|
|
580
|
-
const size = document.getElementById('image-size').value;
|
|
581
|
-
const count = parseInt(document.getElementById('image-count').value);
|
|
582
|
-
|
|
583
|
-
if (!prompt.trim()) {
|
|
584
|
-
this.showToast('Please enter a prompt', 'error');
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// Build request data
|
|
589
|
-
const requestData = {
|
|
590
|
-
model: model,
|
|
591
|
-
prompt: prompt,
|
|
592
|
-
size: size,
|
|
593
|
-
n: count
|
|
594
|
-
};
|
|
595
|
-
|
|
596
|
-
const responseDiv = document.getElementById('image-response');
|
|
597
|
-
responseDiv.innerHTML = `
|
|
598
|
-
<div class="loading modern-loading">
|
|
599
|
-
<div class="loading-spinner"></div>
|
|
600
|
-
<span>Generating image...</span>
|
|
601
|
-
</div>
|
|
602
|
-
`;
|
|
603
|
-
|
|
604
|
-
try {
|
|
605
|
-
const response = await fetch('/v1/images/generations', {
|
|
606
|
-
method: 'POST',
|
|
607
|
-
headers: {
|
|
608
|
-
'Content-Type': 'application/json',
|
|
609
|
-
'Authorization': 'Bearer your-api-key'
|
|
610
|
-
},
|
|
611
|
-
body: JSON.stringify(requestData)
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
const result = await response.json();
|
|
615
|
-
const responseTime = Date.now() - startTime;
|
|
616
|
-
|
|
617
|
-
responseDiv.innerHTML = `
|
|
618
|
-
<div class="response-header modern-response-header">
|
|
619
|
-
<div class="response-status">
|
|
620
|
-
<span class="status-badge status-${response.status}">${response.status} ${response.statusText}</span>
|
|
621
|
-
<span class="response-time">${responseTime}ms</span>
|
|
622
|
-
</div>
|
|
623
|
-
<button class="copy-btn" onclick="copyToClipboard('${JSON.stringify(result).replace(/'/g, "\\'")}')">
|
|
624
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
625
|
-
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
626
|
-
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
627
|
-
</svg>
|
|
628
|
-
Copy
|
|
629
|
-
</button>
|
|
630
|
-
</div>
|
|
631
|
-
<pre class="response-body modern-response-body"><code class="language-json">${JSON.stringify(result, null, 2)}</code></pre>
|
|
632
|
-
`;
|
|
633
|
-
|
|
634
|
-
this.showToast('Image generation completed successfully', 'success');
|
|
635
|
-
} catch (error) {
|
|
636
|
-
const responseTime = Date.now() - startTime;
|
|
637
|
-
responseDiv.innerHTML = `
|
|
638
|
-
<div class="response-header modern-response-header error">
|
|
639
|
-
<div class="response-status">
|
|
640
|
-
<span class="status-badge status-error">Error</span>
|
|
641
|
-
<span class="response-time">${responseTime}ms</span>
|
|
642
|
-
</div>
|
|
643
|
-
</div>
|
|
644
|
-
<div class="response-body modern-response-body error">
|
|
645
|
-
<div class="error-content">
|
|
646
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="error-icon">
|
|
647
|
-
<circle cx="12" cy="12" r="10"/>
|
|
648
|
-
<line x1="15" y1="9" x2="9" y2="15"/>
|
|
649
|
-
<line x1="9" y1="9" x2="15" y2="15"/>
|
|
650
|
-
</svg>
|
|
651
|
-
<div>
|
|
652
|
-
<strong>Image Generation Failed</strong>
|
|
653
|
-
<p>${error.message}</p>
|
|
654
|
-
</div>
|
|
655
|
-
</div>
|
|
656
|
-
</div>
|
|
657
|
-
`;
|
|
658
|
-
this.showToast('Image generation failed', 'error');
|
|
659
|
-
}
|
|
660
|
-
},
|
|
661
|
-
|
|
662
|
-
// Show toast notification
|
|
663
|
-
showToast(message, type = 'info', duration = 3000) {
|
|
664
|
-
const container = document.getElementById('toast-container');
|
|
665
|
-
if (!container) return;
|
|
666
|
-
|
|
667
|
-
const toast = document.createElement('div');
|
|
668
|
-
toast.className = `toast ${type} animate-slideInRight`;
|
|
669
|
-
|
|
670
|
-
const icons = {
|
|
671
|
-
success: '✅',
|
|
672
|
-
error: '❌',
|
|
673
|
-
warning: '⚠️',
|
|
674
|
-
info: 'ℹ️'
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
toast.innerHTML = `
|
|
678
|
-
<span class="toast-icon">${icons[type] || icons.info}</span>
|
|
679
|
-
<div class="toast-content">
|
|
680
|
-
<div class="toast-message">${message}</div>
|
|
681
|
-
</div>
|
|
682
|
-
<button class="toast-close" onclick="this.parentElement.remove()">×</button>
|
|
683
|
-
`;
|
|
684
|
-
|
|
685
|
-
container.appendChild(toast);
|
|
686
|
-
|
|
687
|
-
// Auto remove after duration
|
|
688
|
-
setTimeout(() => {
|
|
689
|
-
if (toast.parentElement) {
|
|
690
|
-
toast.classList.add('animate-slideOutRight');
|
|
691
|
-
setTimeout(() => {
|
|
692
|
-
if (toast.parentElement) {
|
|
693
|
-
toast.remove();
|
|
694
|
-
}
|
|
695
|
-
}, 300);
|
|
696
|
-
}
|
|
697
|
-
}, duration);
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
// Global functions for backward compatibility
|
|
702
|
-
function showTab(tabName) {
|
|
703
|
-
WebScoutApp.showTab(tabName);
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
function toggleEndpoint(header) {
|
|
707
|
-
WebScoutApp.toggleEndpoint(header);
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
function copyCode(elementId) {
|
|
711
|
-
WebScoutApp.copyCode(elementId);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
function copyToClipboard(text) {
|
|
715
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
716
|
-
WebScoutApp.showToast('Copied to clipboard!', 'success');
|
|
717
|
-
}).catch(() => {
|
|
718
|
-
WebScoutApp.showToast('Failed to copy', 'error');
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// Global function for advanced toggle (called from HTML)
|
|
723
|
-
function toggleAdvanced(section) {
|
|
724
|
-
WebScoutApp.toggleAdvanced(section);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
// Global function for testing chat completion (called from HTML)
|
|
728
|
-
function testChatCompletion(event) {
|
|
729
|
-
WebScoutApp.testChatCompletion(event);
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
// Global function for testing image generation (called from HTML)
|
|
733
|
-
function testImageGeneration(event) {
|
|
734
|
-
WebScoutApp.testImageGeneration(event);
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// Global function to toggle stream view
|
|
738
|
-
function toggleStreamView() {
|
|
739
|
-
const streamContent = document.getElementById('stream-content');
|
|
740
|
-
const streamRaw = document.getElementById('stream-raw');
|
|
741
|
-
const toggleBtn = document.querySelector('.stream-toggle');
|
|
742
|
-
|
|
743
|
-
if (streamRaw.style.display === 'none') {
|
|
744
|
-
streamContent.style.display = 'none';
|
|
745
|
-
streamRaw.style.display = 'block';
|
|
746
|
-
toggleBtn.textContent = 'Show Formatted';
|
|
747
|
-
} else {
|
|
748
|
-
streamContent.style.display = 'block';
|
|
749
|
-
streamRaw.style.display = 'none';
|
|
750
|
-
toggleBtn.textContent = 'Show Raw';
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// Global function to copy stream content
|
|
755
|
-
function copyStreamContent() {
|
|
756
|
-
const content = window.streamFullContent || '';
|
|
757
|
-
if (content) {
|
|
758
|
-
navigator.clipboard.writeText(content).then(() => {
|
|
759
|
-
WebScoutApp.showToast('Stream content copied to clipboard!', 'success');
|
|
760
|
-
}).catch(() => {
|
|
761
|
-
WebScoutApp.showToast('Failed to copy stream content', 'error');
|
|
762
|
-
});
|
|
763
|
-
} else {
|
|
764
|
-
WebScoutApp.showToast('No stream content to copy', 'warning');
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
// Utility functions
|
|
769
|
-
function formatJSON(obj) {
|
|
770
|
-
return JSON.stringify(obj, null, 2);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
function formatTimestamp(timestamp) {
|
|
774
|
-
return new Date(timestamp).toLocaleString();
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
function generateId() {
|
|
778
|
-
return Math.random().toString(36).substr(2, 9);
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
// Initialize the application when DOM is loaded
|
|
782
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
783
|
-
WebScoutApp.init();
|
|
784
|
-
});
|