Spaces:
Paused
Paused
Update worker.js
Browse files
worker.js
CHANGED
|
@@ -161,9 +161,9 @@ function testBasicConfiguration() {
|
|
| 161 |
return { passed, failed };
|
| 162 |
}
|
| 163 |
|
| 164 |
-
//
|
| 165 |
async function testNetworkConnectivity() {
|
| 166 |
-
log('info', '🌐 开始网络连接性测试...');
|
| 167 |
|
| 168 |
const testUrls = [
|
| 169 |
{ name: '主站', url: 'https://toolbaz.com' },
|
|
@@ -173,40 +173,74 @@ async function testNetworkConnectivity() {
|
|
| 173 |
];
|
| 174 |
|
| 175 |
const results = [];
|
|
|
|
|
|
|
| 176 |
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
}
|
| 211 |
}
|
| 212 |
|
|
@@ -261,19 +295,22 @@ async function testPromptPrefixFiltering() {
|
|
| 261 |
return { results, passed: passCount, failed: results.length - passCount };
|
| 262 |
}
|
| 263 |
|
| 264 |
-
//
|
| 265 |
async function testBrowserEnvironment() {
|
| 266 |
log('info', '🌍 开始浏览器环境测试...');
|
| 267 |
|
|
|
|
|
|
|
| 268 |
try {
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
|
|
|
| 274 |
|
| 275 |
// 测试基本功能
|
| 276 |
-
await testPage.goto('https://example.com', { waitUntil: 'networkidle2' });
|
| 277 |
|
| 278 |
const browserInfo = await testPage.evaluate(() => {
|
| 279 |
return {
|
|
@@ -301,8 +338,6 @@ async function testBrowserEnvironment() {
|
|
| 301 |
}
|
| 302 |
});
|
| 303 |
|
| 304 |
-
await testBrowser.close();
|
| 305 |
-
|
| 306 |
log('verbose', '✅ 浏览器环境测试通过');
|
| 307 |
log('verbose', '📋 浏览器信息:', browserInfo);
|
| 308 |
log('verbose', '📋 JavaScript功能:', jsTest);
|
|
@@ -312,117 +347,132 @@ async function testBrowserEnvironment() {
|
|
| 312 |
} catch (error) {
|
| 313 |
log('error', `❌ 浏览器环境测试失败: ${error.message}`);
|
| 314 |
return { success: false, error: error.message };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
}
|
| 316 |
}
|
| 317 |
|
| 318 |
-
//
|
| 319 |
async function testSessionDetection() {
|
| 320 |
log('info', '🔍 开始深度会话检测测试...');
|
| 321 |
|
| 322 |
-
|
| 323 |
-
const tempPage = await tempBrowser.newPage();
|
| 324 |
|
| 325 |
try {
|
| 326 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
waitUntil: 'networkidle2',
|
| 328 |
timeout: 30000
|
| 329 |
});
|
| 330 |
|
| 331 |
-
//
|
| 332 |
-
const sessionAnalysis = await
|
| 333 |
const analysis = {
|
| 334 |
timestamp: Date.now(),
|
| 335 |
url: window.location.href,
|
| 336 |
title: document.title,
|
| 337 |
elementsFound: [],
|
| 338 |
-
forms: [],
|
| 339 |
hiddenInputs: [],
|
| 340 |
-
scripts: [],
|
| 341 |
cookies: {},
|
| 342 |
sessionStorage: {},
|
| 343 |
-
localStorage: {}
|
| 344 |
-
networkRequests: [],
|
| 345 |
-
potentialSessions: []
|
| 346 |
};
|
| 347 |
|
| 348 |
-
//
|
| 349 |
-
const allElements = document.querySelectorAll('*');
|
| 350 |
const sessionKeywords = ['session', 'sess', 'sid', 'token', 'csrf', 'auth'];
|
| 351 |
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
}
|
| 367 |
});
|
| 368 |
|
| 369 |
-
// 分析表单
|
| 370 |
-
const forms = document.querySelectorAll('form');
|
| 371 |
-
forms.forEach(form => {
|
| 372 |
-
analysis.forms.push({
|
| 373 |
-
action: form.action,
|
| 374 |
-
method: form.method,
|
| 375 |
-
id: form.id,
|
| 376 |
-
className: form.className
|
| 377 |
-
});
|
| 378 |
-
});
|
| 379 |
-
|
| 380 |
// 分析隐藏输入
|
| 381 |
const hiddenInputs = document.querySelectorAll('input[type="hidden"]');
|
| 382 |
hiddenInputs.forEach(input => {
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
// 分析脚本
|
| 391 |
-
const scripts = document.querySelectorAll('script');
|
| 392 |
-
scripts.forEach(script => {
|
| 393 |
-
if (script.src) {
|
| 394 |
-
analysis.scripts.push(script.src);
|
| 395 |
}
|
| 396 |
});
|
| 397 |
|
| 398 |
-
//
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
}
|
| 403 |
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
}
|
| 408 |
|
| 409 |
-
// 分析cookies
|
| 410 |
-
document.cookie.split(';').forEach(cookie => {
|
| 411 |
-
const [name, value] = cookie.trim().split('=');
|
| 412 |
-
if (name && value) {
|
| 413 |
-
analysis.cookies[name] = value;
|
| 414 |
-
}
|
| 415 |
-
});
|
| 416 |
-
|
| 417 |
return analysis;
|
| 418 |
});
|
| 419 |
|
| 420 |
log('verbose', `📊 会话分析结果:`);
|
| 421 |
log('verbose', ` - 页面: ${sessionAnalysis.title}`);
|
| 422 |
log('verbose', ` - 相关元素: ${sessionAnalysis.elementsFound.length}`);
|
| 423 |
-
log('verbose', ` - 表单数量: ${sessionAnalysis.forms.length}`);
|
| 424 |
log('verbose', ` - 隐藏输入: ${sessionAnalysis.hiddenInputs.length}`);
|
| 425 |
-
log('verbose', ` - 脚本数量: ${sessionAnalysis.scripts.length}`);
|
| 426 |
log('verbose', ` - Cookie数量: ${Object.keys(sessionAnalysis.cookies).length}`);
|
| 427 |
log('verbose', ` - SessionStorage: ${Object.keys(sessionAnalysis.sessionStorage).length}`);
|
| 428 |
log('verbose', ` - LocalStorage: ${Object.keys(sessionAnalysis.localStorage).length}`);
|
|
@@ -430,48 +480,63 @@ async function testSessionDetection() {
|
|
| 430 |
if (sessionAnalysis.elementsFound.length > 0) {
|
| 431 |
log('info', '🎯 找到潜在的会话相关元素:');
|
| 432 |
sessionAnalysis.elementsFound.forEach(elem => {
|
| 433 |
-
log('verbose', ` - ${elem.tag}#${elem.id}
|
| 434 |
});
|
| 435 |
}
|
| 436 |
|
| 437 |
-
await tempBrowser.close();
|
| 438 |
return { success: true, analysis: sessionAnalysis };
|
| 439 |
|
| 440 |
} catch (error) {
|
| 441 |
log('error', `❌ 深度会话检测失败: ${error.message}`);
|
| 442 |
-
await tempBrowser.close();
|
| 443 |
return { success: false, error: error.message };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
}
|
| 445 |
}
|
| 446 |
|
| 447 |
-
//
|
| 448 |
async function testAjaxRequest() {
|
| 449 |
log('info', '📡 开始AJAX请求模拟测试...');
|
| 450 |
|
| 451 |
-
|
| 452 |
-
const tempPage = await tempBrowser.newPage();
|
| 453 |
|
| 454 |
try {
|
| 455 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
waitUntil: 'networkidle2',
|
| 457 |
timeout: 30000
|
| 458 |
});
|
| 459 |
|
| 460 |
-
//
|
| 461 |
const networkRequests = [];
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
});
|
| 470 |
-
|
| 471 |
-
|
|
|
|
| 472 |
|
| 473 |
// 测试AJAX请求
|
| 474 |
-
const ajaxTest = await
|
| 475 |
return new Promise((resolve) => {
|
| 476 |
const testData = {
|
| 477 |
text: 'Hello, this is a test message',
|
|
@@ -485,7 +550,9 @@ async function testAjaxRequest() {
|
|
| 485 |
method: 'POST',
|
| 486 |
headers: {
|
| 487 |
'Content-Type': 'application/x-www-form-urlencoded',
|
| 488 |
-
'Accept': '*/*'
|
|
|
|
|
|
|
| 489 |
},
|
| 490 |
body: new URLSearchParams(testData).toString()
|
| 491 |
})
|
|
@@ -520,13 +587,16 @@ async function testAjaxRequest() {
|
|
| 520 |
|
| 521 |
log('verbose', ` - 网络请求数量: ${networkRequests.length}`);
|
| 522 |
|
| 523 |
-
await tempBrowser.close();
|
| 524 |
return { success: ajaxTest.success, data: ajaxTest, networkRequests };
|
| 525 |
|
| 526 |
} catch (error) {
|
| 527 |
log('error', `❌ AJAX测试失败: ${error.message}`);
|
| 528 |
-
await tempBrowser.close();
|
| 529 |
return { success: false, error: error.message };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 530 |
}
|
| 531 |
}
|
| 532 |
|
|
@@ -575,9 +645,9 @@ function showPerformanceStats() {
|
|
| 575 |
log('info', ` - 平均响应时间: ${PERFORMANCE_STATS.averageResponseTime}ms`);
|
| 576 |
}
|
| 577 |
|
| 578 |
-
//
|
| 579 |
async function runComprehensiveTests() {
|
| 580 |
-
log('info', '🧪 开始综合测试套件...');
|
| 581 |
|
| 582 |
const results = {
|
| 583 |
configuration: null,
|
|
@@ -588,8 +658,10 @@ async function runComprehensiveTests() {
|
|
| 588 |
overall: { passed: 0, failed: 0 }
|
| 589 |
};
|
| 590 |
|
|
|
|
|
|
|
| 591 |
try {
|
| 592 |
-
// 1. 基本配置测试
|
| 593 |
results.configuration = testBasicConfiguration();
|
| 594 |
if (results.configuration.failed === 0) {
|
| 595 |
results.overall.passed++;
|
|
@@ -597,7 +669,7 @@ async function runComprehensiveTests() {
|
|
| 597 |
results.overall.failed++;
|
| 598 |
}
|
| 599 |
|
| 600 |
-
// 2. 网络连接性测试
|
| 601 |
results.network = await testNetworkConnectivity();
|
| 602 |
if (results.network.filter(r => r.status === 'success').length >= 3) {
|
| 603 |
results.overall.passed++;
|
|
@@ -605,7 +677,7 @@ async function runComprehensiveTests() {
|
|
| 605 |
results.overall.failed++;
|
| 606 |
}
|
| 607 |
|
| 608 |
-
// 3. 浏览器环境测试
|
| 609 |
results.browser = await testBrowserEnvironment();
|
| 610 |
if (results.browser.success) {
|
| 611 |
results.overall.passed++;
|
|
@@ -613,7 +685,7 @@ async function runComprehensiveTests() {
|
|
| 613 |
results.overall.failed++;
|
| 614 |
}
|
| 615 |
|
| 616 |
-
// 4. 会话检测测试
|
| 617 |
results.session = await testSessionDetection();
|
| 618 |
if (results.session.success) {
|
| 619 |
results.overall.passed++;
|
|
@@ -621,7 +693,7 @@ async function runComprehensiveTests() {
|
|
| 621 |
results.overall.failed++;
|
| 622 |
}
|
| 623 |
|
| 624 |
-
// 5. AJAX请求测试
|
| 625 |
results.ajax = await testAjaxRequest();
|
| 626 |
if (results.ajax.success) {
|
| 627 |
results.overall.passed++;
|
|
@@ -629,7 +701,7 @@ async function runComprehensiveTests() {
|
|
| 629 |
results.overall.failed++;
|
| 630 |
}
|
| 631 |
|
| 632 |
-
// 6. 前缀过滤测试
|
| 633 |
results.prefixFiltering = await testPromptPrefixFiltering();
|
| 634 |
if (results.prefixFiltering.failed === 0) {
|
| 635 |
results.overall.passed++;
|
|
@@ -643,10 +715,23 @@ async function runComprehensiveTests() {
|
|
| 643 |
log('warn', '⚠️ 部分测试失败,请检查相关配置');
|
| 644 |
}
|
| 645 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 646 |
return results;
|
| 647 |
|
| 648 |
} catch (error) {
|
| 649 |
log('error', `❌ 综合测试失败: ${error.message}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 650 |
return { ...results, error };
|
| 651 |
}
|
| 652 |
}
|
|
@@ -1875,69 +1960,413 @@ async function handleImageGenerations(req, res) {
|
|
| 1875 |
});
|
| 1876 |
}
|
| 1877 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1878 |
async function handleModels(req, res) {
|
| 1879 |
try {
|
| 1880 |
log('info', '🔍 开始提取网站模型列表...');
|
| 1881 |
-
const browser = await initBrowser();
|
| 1882 |
-
const page = await browser.newPage();
|
| 1883 |
|
| 1884 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1885 |
|
| 1886 |
-
//
|
| 1887 |
-
|
| 1888 |
-
|
| 1889 |
|
| 1890 |
-
//
|
| 1891 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1892 |
|
| 1893 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1894 |
const models = await page.evaluate(() => {
|
| 1895 |
-
const modelOptions = document.querySelectorAll('.model-dropdown .model-option');
|
| 1896 |
const modelList = [];
|
| 1897 |
|
| 1898 |
-
|
| 1899 |
-
|
| 1900 |
-
|
| 1901 |
-
|
| 1902 |
-
|
| 1903 |
-
|
| 1904 |
-
|
| 1905 |
-
|
| 1906 |
-
|
| 1907 |
-
|
| 1908 |
-
|
| 1909 |
-
|
| 1910 |
-
|
| 1911 |
-
|
| 1912 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1913 |
}
|
| 1914 |
-
}
|
| 1915 |
|
| 1916 |
return modelList;
|
| 1917 |
});
|
| 1918 |
|
| 1919 |
-
|
|
|
|
|
|
|
| 1920 |
|
| 1921 |
-
|
| 1922 |
|
| 1923 |
-
|
| 1924 |
-
|
| 1925 |
-
|
| 1926 |
-
|
| 1927 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1928 |
|
| 1929 |
-
|
| 1930 |
-
|
| 1931 |
-
|
| 1932 |
-
|
| 1933 |
-
|
| 1934 |
-
|
| 1935 |
-
|
| 1936 |
-
|
| 1937 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1938 |
}
|
| 1939 |
}
|
| 1940 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1941 |
// 新增:测试API端点
|
| 1942 |
async function handleTests(req, res) {
|
| 1943 |
if (!verifyAuth(req)) return sendError(res, 401, 'Unauthorized');
|
|
@@ -2003,7 +2432,11 @@ async function handleStatus(req, res) {
|
|
| 2003 |
max_retries: CONFIG.MAX_RETRIES,
|
| 2004 |
performance_monitoring: CONFIG.PERFORMANCE_MONITORING
|
| 2005 |
},
|
| 2006 |
-
browser: browser ? 'running' : 'stopped'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2007 |
};
|
| 2008 |
|
| 2009 |
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
@@ -2015,6 +2448,27 @@ async function handleStatus(req, res) {
|
|
| 2015 |
}
|
| 2016 |
}
|
| 2017 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2018 |
function handleUI(req, res) {
|
| 2019 |
const html = `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>${CONFIG.PROJECT_NAME}</title><style>:root{--bg:#121212;--panel:#1E1E1E;--border:#333;--text:#E0E0E0;--primary:#00FF9D;--secondary:#00BFA5;--error:#F44336;--success:#4CAF50;--warning:#FF9800}body{font-family:Consolas,monospace;background:var(--bg);color:var(--text);margin:0;height:100vh;display:flex;overflow:hidden;font-size:13px}.sidebar{width:320px;background:var(--panel);border-right:1px solid var(--border);display:flex;flex-direction:column;padding:10px;gap:10px}.main{flex:1;display:flex;flex-direction:column}.log-panel{height:40%;border-top:1px solid var(--border);background:#000;overflow-y:auto;padding:10px}.box{background:#252525;padding:15px;border-radius:6px;border:1px solid var(--border)}.label{font-size:11px;color:#888;display:block;margin-bottom:5px;text-transform:uppercase}input,select,textarea{width:100%;background:#333;border:1px solid #444;color:#fff;padding:8px;border-radius:4px;margin-bottom:10px;box-sizing:border-box;font-family:inherit}button{width:100%;padding:10px;background:var(--primary);border:none;border-radius:4px;font-weight:bold;cursor:pointer;color:#000;margin-bottom:5px;transition:all 0.2s}button:disabled{background:#555;cursor:not-allowed}button.secondary{background:#333;color:#fff;border:1px solid #555}button.danger{background:var(--error);color:#fff}button.warning{background:var(--warning);color:#000}.chat-window{flex:1;padding:20px;overflow-y:auto;display:flex;flex-direction:column;gap:15px}.msg{max-width:85%;padding:10px 15px;border-radius:6px;line-height:1.5;word-wrap:break-word}.msg.user{align-self:flex-end;background:#333;color:#fff}.msg.ai{align-self:flex-start;background:#1a1a1a;border:1px solid #333;width:100%}.msg.img img{max-width:100%;border-radius:4px}.log-entry{margin-bottom:8px;border-bottom:1px solid #222;padding-bottom:8px}.log-time{color:#666;margin-right:10px}.log-data{color:#ccc;white-space:pre-wrap;word-break:break-all;margin-top:4px;display:block}.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:10px}.tab{flex:1;text-align:center;padding:8px;cursor:pointer;color:#888;border-bottom:2px solid transparent;transition:all 0.2s}.tab.active{color:var(--primary);border-bottom-color:var(--primary)}.status-item{display:flex;justify-content:space-between;margin-bottom:5px;font-size:12px}.status-value{color:var(--primary)}.test-result{margin:5px 0;padding:5px;border-radius:3px;font-size:11px}.test-pass{background:var(--success);color:#000}.test-fail{background:var(--error);color:#fff}.performance-grid{display:grid;grid-template-columns:1fr 1fr;gap:5px;margin-top:10px}.perf-item{text-align:center;padding:5px;background:#333;border-radius:3px}.perf-value{font-size:16px;color:var(--primary)}.perf-label{font-size:10px;color:#888}</style></head><body><div class="sidebar"><div class="box"><h2 style="margin:0;color:var(--primary)">${CONFIG.PROJECT_NAME}</h2><span style="font-size:11px;color:#666">v${CONFIG.PROJECT_VERSION} | Enhanced Testing</span></div><div class="box"><div class="tabs"><div class="tab active" onclick="switchMode('chat')">聊天</div><div class="tab" onclick="switchMode('image')">绘图</div><div class="tab" onclick="switchMode('test')">测试</div></div><div id="chat-controls"><span class="label">Model</span><select id="chat-model">${CONFIG.CHAT_MODELS.map(m => `<option value="${m}">${m}</option>`).join('')}</select><span class="label">Prompt</span><textarea id="chat-prompt" rows="5" placeholder="输入内容...">你好,请介绍一下你自己</textarea></div><div id="image-controls" style="display:none"><span class="label">Model</span><select id="image-model">${CONFIG.IMAGE_MODELS.map(m => `<option value="${m}">${m}</option>`).join('')}</select><span class="label">Prompt</span><textarea id="image-prompt" rows="5" placeholder="输入图片描述...">A futuristic city at sunset</textarea></div><div id="test-controls" style="display:none"><span class="label">测试类型</span><select id=\"test-type\"><option value=\"comprehensive\">综合测试</option><option value=\"config\">配置测试</option><option value=\"network\">网络测试</option><option value=\"browser\">浏览器测试</option><option value=\"session\">会话测试</option><option value=\"ajax\">AJAX测试</option><option value=\"prefix\">前缀过滤测试</option></select><button class="warning" onclick="runTest()">🧪 运行测试</button></div><button id="btn-send" onclick="handleSend()">发送请求</button></div><div class="box"><div class="status-item"><span>服务状态:</span><span class="status-value" id="service-status">检查中...</span></div><div class="status-item"><span>浏览器:</span><span class="status-value" id="browser-status">未知</span></div><div class="status-item"><span>总请求:</span><span class="status-value" id="total-requests">0</span></div><div class="status-item"><span>成功率:</span><span class="status-value" id="success-rate">0%</span></div><div class="performance-grid"><div class="perf-item"><div class="perf-value" id="ajax-success">0</div><div class="perf-label">AJAX成功</div></div><div class="perf-item"><div class="perf-value" id="ui-fallback">0</div><div class="perf-label">UI回退</div></div><div class="perf-item"><div class="perf-value" id="avg-response">0ms</div><div class="perf-label">平均响应</div></div><div class="perf-item"><div class="perf-value" id="uptime">0m</div><div class="perf-label">运行时间</div></div></div></div><div class="box" style="margin-top:auto"><button class="secondary" onclick="copyLogs()">📋 复制日志</button><button class="secondary" onclick="clearLogs()">🗑️ 清空日志</button><button class="secondary" onclick="refreshStatus()">🔄 刷新状态</button></div></div><div class="main"><div class="chat-window" id="chat"><div class="msg ai">🎉 ${CONFIG.PROJECT_NAME} v${CONFIG.PROJECT_VERSION} 已就绪<br><br>✨ 新功能:<br>• 🧪 增强的测试套件<br>• 📊 性能监控和统计<br>• 🔍 深度调试信息<br>• 🔄 智能重试机制<br><br>请选择聊天或测试模式开始使用!</div></div><div class="log-panel" id="log-container"></div></div><script>const API_KEY="${CONFIG.API_MASTER_KEY}";const ORIGIN=window.location.origin;let currentMode='chat';let statusInterval;function switchMode(mode){currentMode=mode;document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));event.target.classList.add('active');document.getElementById('chat-controls').style.display=mode==='chat'?'block':'none';document.getElementById('image-controls').style.display=mode==='image'?'block':'none';document.getElementById('test-controls').style.display=mode==='test'?'block':'none';const sendBtn=document.getElementById('btn-send');sendBtn.style.display=mode==='test'?'none':'block';}function appendLog(msg,type='info'){const div=document.createElement('div');div.className='log-entry';let color='#ccc';switch(type){case 'error':color='#F44336';break;case 'warn':color='#FF9800';break;case 'success':color='#4CAF50';break;case 'info':color='#2196F3';break;}div.innerHTML=\`<span class="log-time">\${new Date().toLocaleTimeString()}</span><span class="log-data" style="color:\${color}">\${msg}</span>\`;document.getElementById('log-container').appendChild(div);div.scrollIntoView()}function clearLogs(){document.getElementById('log-container').innerHTML=''}function copyLogs(){const logs=Array.from(document.querySelectorAll('.log-entry')).map(e=>e.innerText).join('\\n');navigator.clipboard.writeText(logs).then(()=>appendLog('日志已复制到剪贴板','success'))}function appendMsg(role,content){const div=document.createElement('div');div.className=\`msg \${role}\`;div.innerHTML=content;document.getElementById('chat').appendChild(div);div.scrollIntoView({behavior:"smooth"});return div}async function handleSend(){const btn=document.getElementById('btn-send');btn.disabled=true;clearLogs();appendLog('🚀 开始请求...');if(currentMode==='chat'){const prompt=document.getElementById('chat-prompt').value;const model=document.getElementById('chat-model').value;if(!prompt){btn.disabled=false;return}appendMsg('user',prompt);const aiMsg=appendMsg('ai','...');let fullText='';try{appendLog('📡 发送到浏览器...');const res=await fetch(ORIGIN+'/v1/chat/completions',{method:'POST',headers:{'Authorization':'Bearer '+API_KEY,'Content-Type':'application/json'},body:JSON.stringify({model,messages:[{role:'user',content:prompt}],stream:true})});appendLog('✅ 接收响应...');const reader=res.body.getReader();const decoder=new TextDecoder();while(true){const{done,value}=await reader.read();if(done)break;const chunk=decoder.decode(value);const lines=chunk.split('\\n');for(const line of lines){if(line.startsWith('data: ')){const dataStr=line.slice(6);if(dataStr==='[DONE]')break;try{const json=JSON.parse(dataStr);if(json.choices&&json.choices[0].delta.content){fullText+=json.choices[0].delta.content;aiMsg.innerText=fullText}}catch(e){}}}}appendLog('🎉 完成!','success');refreshStatus();}catch(e){aiMsg.innerText+='\\n[错误]: '+e.message;appendLog('❌ 错误: '+e.message,'error')}}else{const prompt=document.getElementById('image-prompt').value;const model=document.getElementById('image-model').value;if(!prompt){btn.disabled=false;return}appendMsg('user',prompt);const aiMsg=appendMsg('ai','生成中...');try{appendLog('🎨 发送图片请求...');const res=await fetch(ORIGIN+'/v1/images/generations',{method:'POST',headers:{'Authorization':'Bearer '+API_KEY,'Content-Type':'application/json'},body:JSON.stringify({model,prompt})});const data=await res.json();if(data.error)throw new Error(data.error.message);const imgUrl=data.data[0].url;aiMsg.innerHTML=\`<img src="\${imgUrl}" onclick="window.open(this.src)">\`;aiMsg.className='msg ai img';appendLog('✅ 图片生成成功!','success');refreshStatus();}catch(e){aiMsg.innerText='生成失败: '+e.message;appendLog('❌ 错误: '+e.message,'error')}}btn.disabled=false}async function runTest(){const testType=document.getElementById('test-type').value;appendLog(\`🧪 开始运行\${testType}测试...\`,'info');const testMsg=appendMsg('ai','<div id="test-results">正在运行测试...</div>');try{const res=await fetch(ORIGIN+'/v1/tests?type='+testType,{headers:{'Authorization':'Bearer '+API_KEY}});const data=await res.json();let html='<h3>测试结果</h3>';if(data.overall){html+=\`<p><strong>综合测试:</strong> \${data.overall.passed}/\${data.overall.passed+data.overall.failed} 通过</p>\`;if(data.configuration){html+=\`<div class="test-result test-pass">配置测试: \${data.configuration.passed} 通过, \${data.configuration.failed} 失败</div>\`;}}if(data.success===false){html+=\`<div class="test-result test-fail">测试失败: \${data.error}</div>\`;}else if(data.success){html+=\`<div class="test-result test-pass">测试通过</div>\`;}if(data.analysis){html+=\`<p><strong>会话分析:</strong> 找到 \${data.analysis.elementsFound.length} 个相关元素</p>\`;}if(data.length>0){html+='<h4>详细结果:</h4><ul>';data.forEach(result=>{const status=result.status==='success'?'pass':'fail';html+=\`<li class="test-result test-\${status}">\${result.name}: \${result.status}</li>\`;});html+='</ul>';}testMsg.querySelector('#test-results').innerHTML=html;appendLog('测试完成','success');refreshStatus();}catch(e){testMsg.innerHTML='<div class="test-result test-fail">测试执行失败: '+e.message+'</div>';appendLog('测试执行失败: '+e.message,'error');}}async function refreshStatus(){try{const res=await fetch(ORIGIN+'/v1/status',{headers:{'Authorization':'Bearer '+API_KEY}});const data=await res.json();document.getElementById('service-status').textContent='运行中';document.getElementById('browser-status').textContent=data.browser||'未知';document.getElementById('total-requests').textContent=data.performance.totalRequests||0;const successRate=data.performance.totalRequests>0?Math.round(data.performance.successfulRequests/data.performance.totalRequests*100):0;document.getElementById('success-rate').textContent=successRate+'%';document.getElementById('ajax-success').textContent=data.performance.ajaxSuccess||0;document.getElementById('ui-fallback').textContent=data.performance.uiFallback||0;document.getElementById('avg-response').textContent=(data.performance.averageResponseTime||0)+'ms';document.getElementById('uptime').textContent=Math.floor(data.uptime/60)+'m';}catch(e){appendLog('状态刷新失败: '+e.message,'error');}}function init(){refreshStatus();statusInterval=setInterval(refreshStatus,30000);}init();</script></body></html>`;
|
| 2020 |
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
@@ -2048,6 +2502,7 @@ const server = http.createServer(async (req, res) => {
|
|
| 2048 |
// 新增的测试和状态端点
|
| 2049 |
if (url.pathname === '/v1/tests') return await handleTests(req, res);
|
| 2050 |
if (url.pathname === '/v1/status') return await handleStatus(req, res);
|
|
|
|
| 2051 |
|
| 2052 |
sendError(res, 404, 'Not Found');
|
| 2053 |
});
|
|
@@ -2103,8 +2558,9 @@ server.listen(CONFIG.PORT, async () => {
|
|
| 2103 |
log('info', ' - GET / : Web界面');
|
| 2104 |
log('info', ' - POST /v1/chat/completions : 聊天API');
|
| 2105 |
log('info', ' - POST /v1/images/generations : 图片生成API');
|
| 2106 |
-
log('info', ' - GET /v1/models : 模型列表API');
|
| 2107 |
-
log('info', ' - GET /v1/
|
|
|
|
| 2108 |
log('info', ' - GET /v1/tests : 测试API (?type=config|network|browser|session|ajax|comprehensive)');
|
| 2109 |
|
| 2110 |
// 启动性能统计定时显示
|
|
|
|
| 161 |
return { passed, failed };
|
| 162 |
}
|
| 163 |
|
| 164 |
+
// 修改:测试函数 - 网络连接性(使用单个浏览器实例)
|
| 165 |
async function testNetworkConnectivity() {
|
| 166 |
+
log('info', '🌐 开始网络连接性测试(使用单个浏览器实例)...');
|
| 167 |
|
| 168 |
const testUrls = [
|
| 169 |
{ name: '主站', url: 'https://toolbaz.com' },
|
|
|
|
| 173 |
];
|
| 174 |
|
| 175 |
const results = [];
|
| 176 |
+
let testBrowser = null;
|
| 177 |
+
let testPage = null;
|
| 178 |
|
| 179 |
+
try {
|
| 180 |
+
// 启动单个浏览器实例
|
| 181 |
+
testBrowser = await puppeteer.launch({
|
| 182 |
+
headless: true,
|
| 183 |
+
args: [
|
| 184 |
+
'--no-sandbox',
|
| 185 |
+
'--disable-setuid-sandbox',
|
| 186 |
+
'--disable-dev-shm-usage',
|
| 187 |
+
'--disable-gpu'
|
| 188 |
+
]
|
| 189 |
+
});
|
| 190 |
+
testPage = await testBrowser.newPage();
|
| 191 |
+
|
| 192 |
+
// 设置更长的超时时间以应对网络问题
|
| 193 |
+
testPage.setDefaultTimeout(30000);
|
| 194 |
+
|
| 195 |
+
for (const test of testUrls) {
|
| 196 |
+
try {
|
| 197 |
+
const startTime = Date.now();
|
| 198 |
+
|
| 199 |
+
// 重用同一个页面进行测试
|
| 200 |
+
await testPage.goto(test.url, {
|
| 201 |
+
waitUntil: 'networkidle2',
|
| 202 |
+
timeout: 25000 // 增加到25秒
|
| 203 |
+
});
|
| 204 |
+
|
| 205 |
+
const responseTime = Date.now() - startTime;
|
| 206 |
+
const title = await testPage.title();
|
| 207 |
+
|
| 208 |
+
results.push({
|
| 209 |
+
name: test.name,
|
| 210 |
+
url: test.url,
|
| 211 |
+
status: 'success',
|
| 212 |
+
responseTime,
|
| 213 |
+
title: title.substring(0, 50)
|
| 214 |
+
});
|
| 215 |
+
|
| 216 |
+
log('verbose', `✅ ${test.name}: ${responseTime}ms - ${title.substring(0, 30)}...`);
|
| 217 |
+
|
| 218 |
+
// 在测试之间添加短暂延迟,避免过于频繁的请求
|
| 219 |
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
| 220 |
+
|
| 221 |
+
} catch (error) {
|
| 222 |
+
results.push({
|
| 223 |
+
name: test.name,
|
| 224 |
+
url: test.url,
|
| 225 |
+
status: 'failed',
|
| 226 |
+
error: error.message
|
| 227 |
+
});
|
| 228 |
+
log('error', `❌ ${test.name}: ${error.message}`);
|
| 229 |
+
|
| 230 |
+
// 错误后也短暂延迟
|
| 231 |
+
await new Promise(resolve => setTimeout(resolve, 500));
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
} catch (error) {
|
| 236 |
+
log('error', `❌ 网络测试初始化失败: ${error.message}`);
|
| 237 |
+
} finally {
|
| 238 |
+
// 清理资源
|
| 239 |
+
if (testPage) {
|
| 240 |
+
await testPage.close().catch(e => log('warn', `页面关闭失败: ${e.message}`));
|
| 241 |
+
}
|
| 242 |
+
if (testBrowser) {
|
| 243 |
+
await testBrowser.close().catch(e => log('warn', `浏览器关闭失败: ${e.message}`));
|
| 244 |
}
|
| 245 |
}
|
| 246 |
|
|
|
|
| 295 |
return { results, passed: passCount, failed: results.length - passCount };
|
| 296 |
}
|
| 297 |
|
| 298 |
+
// 修改:测试函数 - 浏览器环境(使用全局浏览器实例)
|
| 299 |
async function testBrowserEnvironment() {
|
| 300 |
log('info', '🌍 开始浏览器环境测试...');
|
| 301 |
|
| 302 |
+
let testPage = null;
|
| 303 |
+
|
| 304 |
try {
|
| 305 |
+
// 尝试使用现有的浏览器实例,如果没有则创建
|
| 306 |
+
const testBrowser = browser || await initBrowser();
|
| 307 |
+
testPage = await testBrowser.newPage();
|
| 308 |
+
|
| 309 |
+
// 设置更长的超时时间
|
| 310 |
+
testPage.setDefaultTimeout(20000);
|
| 311 |
|
| 312 |
// 测试基本功能
|
| 313 |
+
await testPage.goto('https://example.com', { waitUntil: 'networkidle2', timeout: 15000 });
|
| 314 |
|
| 315 |
const browserInfo = await testPage.evaluate(() => {
|
| 316 |
return {
|
|
|
|
| 338 |
}
|
| 339 |
});
|
| 340 |
|
|
|
|
|
|
|
| 341 |
log('verbose', '✅ 浏览器环境测试通过');
|
| 342 |
log('verbose', '📋 浏览器信息:', browserInfo);
|
| 343 |
log('verbose', '📋 JavaScript功能:', jsTest);
|
|
|
|
| 347 |
} catch (error) {
|
| 348 |
log('error', `❌ 浏览器环境测试失败: ${error.message}`);
|
| 349 |
return { success: false, error: error.message };
|
| 350 |
+
} finally {
|
| 351 |
+
// 清理页面资源
|
| 352 |
+
if (testPage) {
|
| 353 |
+
await testPage.close().catch(e => log('warn', `页面关闭失败: ${e.message}`));
|
| 354 |
+
}
|
| 355 |
}
|
| 356 |
}
|
| 357 |
|
| 358 |
+
// 修改:测试函数 - 深度会话检测(使用全局浏览器实例)
|
| 359 |
async function testSessionDetection() {
|
| 360 |
log('info', '🔍 开始深度会话检测测试...');
|
| 361 |
|
| 362 |
+
let testPage = null;
|
|
|
|
| 363 |
|
| 364 |
try {
|
| 365 |
+
// 使用现有的浏览器实例或创建新的
|
| 366 |
+
const testBrowser = browser || await initBrowser();
|
| 367 |
+
testPage = await testBrowser.newPage();
|
| 368 |
+
|
| 369 |
+
// 设置更长的超时时间
|
| 370 |
+
testPage.setDefaultTimeout(30000);
|
| 371 |
+
|
| 372 |
+
await testPage.goto('https://toolbaz.com/writer/ai-writer', {
|
| 373 |
waitUntil: 'networkidle2',
|
| 374 |
timeout: 30000
|
| 375 |
});
|
| 376 |
|
| 377 |
+
// 简化的会话检测(减少资源消耗)
|
| 378 |
+
const sessionAnalysis = await testPage.evaluate(() => {
|
| 379 |
const analysis = {
|
| 380 |
timestamp: Date.now(),
|
| 381 |
url: window.location.href,
|
| 382 |
title: document.title,
|
| 383 |
elementsFound: [],
|
|
|
|
| 384 |
hiddenInputs: [],
|
|
|
|
| 385 |
cookies: {},
|
| 386 |
sessionStorage: {},
|
| 387 |
+
localStorage: {}
|
|
|
|
|
|
|
| 388 |
};
|
| 389 |
|
| 390 |
+
// 专注于关键元素,避免过度遍历
|
|
|
|
| 391 |
const sessionKeywords = ['session', 'sess', 'sid', 'token', 'csrf', 'auth'];
|
| 392 |
|
| 393 |
+
// 只检查可能包含会话信息的元素
|
| 394 |
+
const relevantSelectors = [
|
| 395 |
+
'input[type="hidden"]',
|
| 396 |
+
'input[name*="session"]',
|
| 397 |
+
'input[name*="token"]',
|
| 398 |
+
'input[id*="session"]',
|
| 399 |
+
'input[id*="token"]',
|
| 400 |
+
'[data-session]',
|
| 401 |
+
'[data-token]'
|
| 402 |
+
];
|
| 403 |
+
|
| 404 |
+
relevantSelectors.forEach(selector => {
|
| 405 |
+
try {
|
| 406 |
+
const elements = document.querySelectorAll(selector);
|
| 407 |
+
elements.forEach(elem => {
|
| 408 |
+
const info = {
|
| 409 |
+
tag: elem.tagName,
|
| 410 |
+
id: elem.id || '',
|
| 411 |
+
name: elem.name || '',
|
| 412 |
+
value: elem.value || ''
|
| 413 |
+
};
|
| 414 |
+
|
| 415 |
+
const searchText = [info.id, info.name, info.value].join(' ').toLowerCase();
|
| 416 |
+
|
| 417 |
+
if (sessionKeywords.some(keyword => searchText.includes(keyword))) {
|
| 418 |
+
analysis.elementsFound.push(info);
|
| 419 |
+
}
|
| 420 |
+
});
|
| 421 |
+
} catch (e) {
|
| 422 |
+
// 忽略选择器错误
|
| 423 |
}
|
| 424 |
});
|
| 425 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 426 |
// 分析隐藏输入
|
| 427 |
const hiddenInputs = document.querySelectorAll('input[type="hidden"]');
|
| 428 |
hiddenInputs.forEach(input => {
|
| 429 |
+
if (input.name || input.value) {
|
| 430 |
+
analysis.hiddenInputs.push({
|
| 431 |
+
name: input.name,
|
| 432 |
+
id: input.id,
|
| 433 |
+
value: input.value.substring(0, 100)
|
| 434 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 435 |
}
|
| 436 |
});
|
| 437 |
|
| 438 |
+
// 简化存储分析
|
| 439 |
+
try {
|
| 440 |
+
for (let i = 0; i < Math.min(sessionStorage.length, 10); i++) {
|
| 441 |
+
const key = sessionStorage.key(i);
|
| 442 |
+
if (key && sessionKeywords.some(k => key.toLowerCase().includes(k))) {
|
| 443 |
+
analysis.sessionStorage[key] = sessionStorage.getItem(key);
|
| 444 |
+
}
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
for (let i = 0; i < Math.min(localStorage.length, 10); i++) {
|
| 448 |
+
const key = localStorage.key(i);
|
| 449 |
+
if (key && sessionKeywords.some(k => key.toLowerCase().includes(k))) {
|
| 450 |
+
analysis.localStorage[key] = localStorage.getItem(key);
|
| 451 |
+
}
|
| 452 |
+
}
|
| 453 |
+
} catch (e) {
|
| 454 |
+
// 忽略存储访问错误
|
| 455 |
}
|
| 456 |
|
| 457 |
+
// 简化cookie分析
|
| 458 |
+
try {
|
| 459 |
+
document.cookie.split(';').forEach(cookie => {
|
| 460 |
+
const [name, value] = cookie.trim().split('=');
|
| 461 |
+
if (name && value && sessionKeywords.some(k => name.toLowerCase().includes(k))) {
|
| 462 |
+
analysis.cookies[name] = value;
|
| 463 |
+
}
|
| 464 |
+
});
|
| 465 |
+
} catch (e) {
|
| 466 |
+
// 忽略cookie访问错误
|
| 467 |
}
|
| 468 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
return analysis;
|
| 470 |
});
|
| 471 |
|
| 472 |
log('verbose', `📊 会话分析结果:`);
|
| 473 |
log('verbose', ` - 页面: ${sessionAnalysis.title}`);
|
| 474 |
log('verbose', ` - 相关元素: ${sessionAnalysis.elementsFound.length}`);
|
|
|
|
| 475 |
log('verbose', ` - 隐藏输入: ${sessionAnalysis.hiddenInputs.length}`);
|
|
|
|
| 476 |
log('verbose', ` - Cookie数量: ${Object.keys(sessionAnalysis.cookies).length}`);
|
| 477 |
log('verbose', ` - SessionStorage: ${Object.keys(sessionAnalysis.sessionStorage).length}`);
|
| 478 |
log('verbose', ` - LocalStorage: ${Object.keys(sessionAnalysis.localStorage).length}`);
|
|
|
|
| 480 |
if (sessionAnalysis.elementsFound.length > 0) {
|
| 481 |
log('info', '🎯 找到潜在的会话相关元素:');
|
| 482 |
sessionAnalysis.elementsFound.forEach(elem => {
|
| 483 |
+
log('verbose', ` - ${elem.tag}#${elem.id} (${elem.name}): ${elem.value.substring(0, 50)}`);
|
| 484 |
});
|
| 485 |
}
|
| 486 |
|
|
|
|
| 487 |
return { success: true, analysis: sessionAnalysis };
|
| 488 |
|
| 489 |
} catch (error) {
|
| 490 |
log('error', `❌ 深度会话检测失败: ${error.message}`);
|
|
|
|
| 491 |
return { success: false, error: error.message };
|
| 492 |
+
} finally {
|
| 493 |
+
// 清理页面资源
|
| 494 |
+
if (testPage) {
|
| 495 |
+
await testPage.close().catch(e => log('warn', `页面关闭失败: ${e.message}`));
|
| 496 |
+
}
|
| 497 |
}
|
| 498 |
}
|
| 499 |
|
| 500 |
+
// 修改:测试函数 - AJAX请求模拟(使用全局浏览器实例)
|
| 501 |
async function testAjaxRequest() {
|
| 502 |
log('info', '📡 开始AJAX请求模拟测试...');
|
| 503 |
|
| 504 |
+
let testPage = null;
|
|
|
|
| 505 |
|
| 506 |
try {
|
| 507 |
+
// 使用现有的浏览器实例或创建新的
|
| 508 |
+
const testBrowser = browser || await initBrowser();
|
| 509 |
+
testPage = await testBrowser.newPage();
|
| 510 |
+
|
| 511 |
+
// 设置更长的超时时间
|
| 512 |
+
testPage.setDefaultTimeout(30000);
|
| 513 |
+
|
| 514 |
+
await testPage.goto('https://toolbaz.com/writer/ai-writer', {
|
| 515 |
waitUntil: 'networkidle2',
|
| 516 |
timeout: 30000
|
| 517 |
});
|
| 518 |
|
| 519 |
+
// 简化的请求监听
|
| 520 |
const networkRequests = [];
|
| 521 |
+
try {
|
| 522 |
+
await testPage.setRequestInterception(true);
|
| 523 |
+
testPage.on('request', request => {
|
| 524 |
+
if (request.url().includes('writing.php')) {
|
| 525 |
+
networkRequests.push({
|
| 526 |
+
url: request.url(),
|
| 527 |
+
method: request.method(),
|
| 528 |
+
headers: request.headers(),
|
| 529 |
+
postData: request.postData()
|
| 530 |
+
});
|
| 531 |
+
}
|
| 532 |
+
request.continue();
|
| 533 |
});
|
| 534 |
+
} catch (e) {
|
| 535 |
+
log('warn', `请求拦截设置失败,继续测试: ${e.message}`);
|
| 536 |
+
}
|
| 537 |
|
| 538 |
// 测试AJAX请求
|
| 539 |
+
const ajaxTest = await testPage.evaluate(async () => {
|
| 540 |
return new Promise((resolve) => {
|
| 541 |
const testData = {
|
| 542 |
text: 'Hello, this is a test message',
|
|
|
|
| 550 |
method: 'POST',
|
| 551 |
headers: {
|
| 552 |
'Content-Type': 'application/x-www-form-urlencoded',
|
| 553 |
+
'Accept': '*/*',
|
| 554 |
+
'Origin': 'https://toolbaz.com',
|
| 555 |
+
'Referer': 'https://toolbaz.com/writer/ai-writer'
|
| 556 |
},
|
| 557 |
body: new URLSearchParams(testData).toString()
|
| 558 |
})
|
|
|
|
| 587 |
|
| 588 |
log('verbose', ` - 网络请求数量: ${networkRequests.length}`);
|
| 589 |
|
|
|
|
| 590 |
return { success: ajaxTest.success, data: ajaxTest, networkRequests };
|
| 591 |
|
| 592 |
} catch (error) {
|
| 593 |
log('error', `❌ AJAX测试失败: ${error.message}`);
|
|
|
|
| 594 |
return { success: false, error: error.message };
|
| 595 |
+
} finally {
|
| 596 |
+
// 清理页面资源
|
| 597 |
+
if (testPage) {
|
| 598 |
+
await testPage.close().catch(e => log('warn', `页面关闭失败: ${e.message}`));
|
| 599 |
+
}
|
| 600 |
}
|
| 601 |
}
|
| 602 |
|
|
|
|
| 645 |
log('info', ` - 平均响应时间: ${PERFORMANCE_STATS.averageResponseTime}ms`);
|
| 646 |
}
|
| 647 |
|
| 648 |
+
// 修改:综合测试函数(优化浏览器资源管理)
|
| 649 |
async function runComprehensiveTests() {
|
| 650 |
+
log('info', '🧪 开始综合测试套件(优化版)...');
|
| 651 |
|
| 652 |
const results = {
|
| 653 |
configuration: null,
|
|
|
|
| 658 |
overall: { passed: 0, failed: 0 }
|
| 659 |
};
|
| 660 |
|
| 661 |
+
let sharedBrowser = null;
|
| 662 |
+
|
| 663 |
try {
|
| 664 |
+
// 1. 基本配置测试(不需要浏览器)
|
| 665 |
results.configuration = testBasicConfiguration();
|
| 666 |
if (results.configuration.failed === 0) {
|
| 667 |
results.overall.passed++;
|
|
|
|
| 669 |
results.overall.failed++;
|
| 670 |
}
|
| 671 |
|
| 672 |
+
// 2. 网络连接性测试(已优化为使用单个浏览器)
|
| 673 |
results.network = await testNetworkConnectivity();
|
| 674 |
if (results.network.filter(r => r.status === 'success').length >= 3) {
|
| 675 |
results.overall.passed++;
|
|
|
|
| 677 |
results.overall.failed++;
|
| 678 |
}
|
| 679 |
|
| 680 |
+
// 3. 浏览器环境测试(使用全局浏览器)
|
| 681 |
results.browser = await testBrowserEnvironment();
|
| 682 |
if (results.browser.success) {
|
| 683 |
results.overall.passed++;
|
|
|
|
| 685 |
results.overall.failed++;
|
| 686 |
}
|
| 687 |
|
| 688 |
+
// 4. 会话检测测试(使用全局浏览器)
|
| 689 |
results.session = await testSessionDetection();
|
| 690 |
if (results.session.success) {
|
| 691 |
results.overall.passed++;
|
|
|
|
| 693 |
results.overall.failed++;
|
| 694 |
}
|
| 695 |
|
| 696 |
+
// 5. AJAX请求测试(使用全局浏览器)
|
| 697 |
results.ajax = await testAjaxRequest();
|
| 698 |
if (results.ajax.success) {
|
| 699 |
results.overall.passed++;
|
|
|
|
| 701 |
results.overall.failed++;
|
| 702 |
}
|
| 703 |
|
| 704 |
+
// 6. 前缀过滤测试(不需要浏览器)
|
| 705 |
results.prefixFiltering = await testPromptPrefixFiltering();
|
| 706 |
if (results.prefixFiltering.failed === 0) {
|
| 707 |
results.overall.passed++;
|
|
|
|
| 715 |
log('warn', '⚠️ 部分测试失败,请检查相关配置');
|
| 716 |
}
|
| 717 |
|
| 718 |
+
// 添加资源使用统计
|
| 719 |
+
const browserInstance = browser || sharedBrowser;
|
| 720 |
+
if (browserInstance) {
|
| 721 |
+
const pages = await browserInstance.pages().catch(() => []);
|
| 722 |
+
log('info', `📊 浏览器资源统计: ${pages.length} 个页面`);
|
| 723 |
+
}
|
| 724 |
+
|
| 725 |
return results;
|
| 726 |
|
| 727 |
} catch (error) {
|
| 728 |
log('error', `❌ 综合测试失败: ${error.message}`);
|
| 729 |
+
|
| 730 |
+
// 确保清理共享浏览器资源
|
| 731 |
+
if (sharedBrowser) {
|
| 732 |
+
await sharedBrowser.close().catch(e => log('warn', `共享浏览器关闭失败: ${e.message}`));
|
| 733 |
+
}
|
| 734 |
+
|
| 735 |
return { ...results, error };
|
| 736 |
}
|
| 737 |
}
|
|
|
|
| 1960 |
});
|
| 1961 |
}
|
| 1962 |
|
| 1963 |
+
// 模型缓存(避免频繁重新提取)
|
| 1964 |
+
let modelCache = {
|
| 1965 |
+
data: null,
|
| 1966 |
+
timestamp: null,
|
| 1967 |
+
expiresAt: null,
|
| 1968 |
+
isValid: function() {
|
| 1969 |
+
return this.data && this.expiresAt && Date.now() < this.expiresAt;
|
| 1970 |
+
},
|
| 1971 |
+
set: function(models, ttlMinutes = 60) {
|
| 1972 |
+
this.data = models;
|
| 1973 |
+
this.timestamp = Date.now();
|
| 1974 |
+
this.expiresAt = Date.now() + (ttlMinutes * 60 * 1000);
|
| 1975 |
+
log('info', `🔐 模型列表已缓存,有效期 ${ttlMinutes} 分钟`);
|
| 1976 |
+
},
|
| 1977 |
+
clear: function() {
|
| 1978 |
+
this.data = null;
|
| 1979 |
+
this.timestamp = null;
|
| 1980 |
+
this.expiresAt = null;
|
| 1981 |
+
log('info', '🔐 模型缓存已清空');
|
| 1982 |
+
}
|
| 1983 |
+
};
|
| 1984 |
+
|
| 1985 |
async function handleModels(req, res) {
|
| 1986 |
try {
|
| 1987 |
log('info', '🔍 开始提取网站模型列表...');
|
|
|
|
|
|
|
| 1988 |
|
| 1989 |
+
// 检查缓存
|
| 1990 |
+
if (modelCache.isValid()) {
|
| 1991 |
+
log('info', `✅ 使用缓存模型列表 (${modelCache.data.length} 个模型)`);
|
| 1992 |
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
| 1993 |
+
res.end(JSON.stringify({
|
| 1994 |
+
object: 'list',
|
| 1995 |
+
data: modelCache.data
|
| 1996 |
+
}));
|
| 1997 |
+
return;
|
| 1998 |
+
}
|
| 1999 |
|
| 2000 |
+
// 尝试多种方法获取模型列表
|
| 2001 |
+
let models = null;
|
| 2002 |
+
let extractionMethod = '';
|
| 2003 |
|
| 2004 |
+
// 方法1: 尝试访问网站获取最新模型
|
| 2005 |
+
try {
|
| 2006 |
+
log('info', '🌐 方法1: 从网站提取模型列表...');
|
| 2007 |
+
models = await extractModelsFromWebsite();
|
| 2008 |
+
extractionMethod = 'website';
|
| 2009 |
+
} catch (websiteError) {
|
| 2010 |
+
log('warn', `⚠️ 网站提取失败: ${websiteError.message}`);
|
| 2011 |
+
|
| 2012 |
+
// 方法2: 尝试AJAX方式获取模型
|
| 2013 |
+
try {
|
| 2014 |
+
log('info', '📡 方法2: 尝试AJAX方式获取模型...');
|
| 2015 |
+
models = await extractModelsViaAjax();
|
| 2016 |
+
extractionMethod = 'ajax';
|
| 2017 |
+
} catch (ajaxError) {
|
| 2018 |
+
log('warn', `⚠️ AJAX提取失败: ${ajaxError.message}`);
|
| 2019 |
+
|
| 2020 |
+
// 方法3: 使用增强的静态配置
|
| 2021 |
+
try {
|
| 2022 |
+
log('info', '🔧 方法3: 使用增强静态配置...');
|
| 2023 |
+
models = await getEnhancedStaticModels();
|
| 2024 |
+
extractionMethod = 'enhanced-static';
|
| 2025 |
+
} catch (staticError) {
|
| 2026 |
+
log('error', `❌ 所有方法都失败了,使用基础静态配置: ${staticError.message}`);
|
| 2027 |
+
models = getBasicStaticModels();
|
| 2028 |
+
extractionMethod = 'basic-static';
|
| 2029 |
+
}
|
| 2030 |
+
}
|
| 2031 |
+
}
|
| 2032 |
+
|
| 2033 |
+
// 更新缓存
|
| 2034 |
+
if (models && models.length > 0) {
|
| 2035 |
+
modelCache.set(models, 60); // 缓存60分钟
|
| 2036 |
+
|
| 2037 |
+
log('info', `✅ 成功提取 ${models.length} 个模型 (方法: ${extractionMethod})`);
|
| 2038 |
+
|
| 2039 |
+
// 记录提取到的模型(调试用)
|
| 2040 |
+
if (CONFIG.DEBUG_LEVEL === 'verbose') {
|
| 2041 |
+
models.forEach((model, index) => {
|
| 2042 |
+
log('verbose', ` ${index + 1}. ${model.name} (${model.id})`);
|
| 2043 |
+
});
|
| 2044 |
+
}
|
| 2045 |
+
|
| 2046 |
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
| 2047 |
+
res.end(JSON.stringify({
|
| 2048 |
+
object: 'list',
|
| 2049 |
+
data: models,
|
| 2050 |
+
metadata: {
|
| 2051 |
+
extraction_method: extractionMethod,
|
| 2052 |
+
extracted_at: new Date().toISOString(),
|
| 2053 |
+
total_models: models.length
|
| 2054 |
+
}
|
| 2055 |
+
}));
|
| 2056 |
+
} else {
|
| 2057 |
+
throw new Error('没有获取到任何模型数据');
|
| 2058 |
+
}
|
| 2059 |
|
| 2060 |
+
} catch (error) {
|
| 2061 |
+
log('error', `❌ 模型提取完全失败: ${error.message}`);
|
| 2062 |
+
|
| 2063 |
+
// 最后的兜底策略
|
| 2064 |
+
const fallbackModels = getBasicStaticModels();
|
| 2065 |
+
|
| 2066 |
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
| 2067 |
+
res.end(JSON.stringify({
|
| 2068 |
+
object: 'list',
|
| 2069 |
+
data: fallbackModels,
|
| 2070 |
+
metadata: {
|
| 2071 |
+
extraction_method: 'fallback',
|
| 2072 |
+
error: error.message,
|
| 2073 |
+
extracted_at: new Date().toISOString()
|
| 2074 |
+
}
|
| 2075 |
+
}));
|
| 2076 |
+
}
|
| 2077 |
+
}
|
| 2078 |
+
|
| 2079 |
+
// 新增:从网站提取模型的专用函数
|
| 2080 |
+
async function extractModelsFromWebsite() {
|
| 2081 |
+
const browser = await initBrowser();
|
| 2082 |
+
const page = await browser.newPage();
|
| 2083 |
+
|
| 2084 |
+
try {
|
| 2085 |
+
// 设置更长的超时时间
|
| 2086 |
+
page.setDefaultTimeout(30000);
|
| 2087 |
+
|
| 2088 |
+
log('info', '🌐 访问写作页面...');
|
| 2089 |
+
await page.goto('https://toolbaz.com/writer/ai-writer', {
|
| 2090 |
+
waitUntil: 'networkidle2',
|
| 2091 |
+
timeout: 30000
|
| 2092 |
+
});
|
| 2093 |
+
|
| 2094 |
+
// 等待页面加载
|
| 2095 |
+
await page.waitForTimeout(2000); // 给页面一些加载时间
|
| 2096 |
+
|
| 2097 |
+
log('info', '🔍 查找模型选择器...');
|
| 2098 |
+
|
| 2099 |
+
// 尝试多种选择器
|
| 2100 |
+
const modelSelectors = [
|
| 2101 |
+
'#selected-model',
|
| 2102 |
+
'.model-selector',
|
| 2103 |
+
'[data-model]',
|
| 2104 |
+
'.model-dropdown-trigger'
|
| 2105 |
+
];
|
| 2106 |
+
|
| 2107 |
+
let selectorFound = null;
|
| 2108 |
+
for (const selector of modelSelectors) {
|
| 2109 |
+
try {
|
| 2110 |
+
await page.waitForSelector(selector, { timeout: 5000 });
|
| 2111 |
+
selectorFound = selector;
|
| 2112 |
+
log('info', `✅ 找到模型选择器: ${selector}`);
|
| 2113 |
+
break;
|
| 2114 |
+
} catch (e) {
|
| 2115 |
+
continue;
|
| 2116 |
+
}
|
| 2117 |
+
}
|
| 2118 |
+
|
| 2119 |
+
if (!selectorFound) {
|
| 2120 |
+
throw new Error('未找到模型选择器');
|
| 2121 |
+
}
|
| 2122 |
+
|
| 2123 |
+
// 尝试点击选择器
|
| 2124 |
+
try {
|
| 2125 |
+
await page.click(selectorFound);
|
| 2126 |
+
log('info', '✅ 成功点击模型选择器');
|
| 2127 |
+
} catch (e) {
|
| 2128 |
+
log('warn', `⚠️ 点击选择器失败,尝试直接查找模型: ${e.message}`);
|
| 2129 |
+
}
|
| 2130 |
+
|
| 2131 |
+
// 等待下拉列表或模型列表出现
|
| 2132 |
+
await page.waitForTimeout(1000);
|
| 2133 |
+
|
| 2134 |
+
// 查找模型选项
|
| 2135 |
const models = await page.evaluate(() => {
|
|
|
|
| 2136 |
const modelList = [];
|
| 2137 |
|
| 2138 |
+
// 尝试多种模型选项选择器
|
| 2139 |
+
const modelSelectors = [
|
| 2140 |
+
'.model-dropdown .model-option',
|
| 2141 |
+
'.model-list .model-item',
|
| 2142 |
+
'[data-model-option]',
|
| 2143 |
+
'.model-selector option',
|
| 2144 |
+
'select[name="model"] option',
|
| 2145 |
+
'.ai-models .model',
|
| 2146 |
+
'.available-models .model-item'
|
| 2147 |
+
];
|
| 2148 |
+
|
| 2149 |
+
for (const selector of modelSelectors) {
|
| 2150 |
+
try {
|
| 2151 |
+
const elements = document.querySelectorAll(selector);
|
| 2152 |
+
if (elements.length > 0) {
|
| 2153 |
+
log(`✅ 使用选择器 ${selector} 找到 ${elements.length} 个模型选项`);
|
| 2154 |
+
|
| 2155 |
+
elements.forEach((element, index) => {
|
| 2156 |
+
let name = '';
|
| 2157 |
+
let id = '';
|
| 2158 |
+
|
| 2159 |
+
// 尝试获取模型名称
|
| 2160 |
+
const nameElement = element.querySelector('.model-name') ||
|
| 2161 |
+
element.querySelector('.name') ||
|
| 2162 |
+
element.querySelector('span') ||
|
| 2163 |
+
element;
|
| 2164 |
+
|
| 2165 |
+
name = nameElement.innerText || nameElement.textContent ||
|
| 2166 |
+
nameElement.value || nameElement.getAttribute('data-model') || '';
|
| 2167 |
+
|
| 2168 |
+
name = name.trim();
|
| 2169 |
+
|
| 2170 |
+
if (name && name.length > 0) {
|
| 2171 |
+
id = name.toLowerCase()
|
| 2172 |
+
.replace(/[^a-z0-9\s]/g, '')
|
| 2173 |
+
.replace(/\s+/g, '-')
|
| 2174 |
+
.substring(0, 50);
|
| 2175 |
+
|
| 2176 |
+
modelList.push({
|
| 2177 |
+
id: id || `model-${index}`,
|
| 2178 |
+
name: name,
|
| 2179 |
+
icon: element.querySelector('.model-icon, .icon')?.src || '',
|
| 2180 |
+
object: 'model',
|
| 2181 |
+
created: Math.floor(Date.now() / 1000),
|
| 2182 |
+
owned_by: 'toolbaz'
|
| 2183 |
+
});
|
| 2184 |
+
}
|
| 2185 |
+
});
|
| 2186 |
+
|
| 2187 |
+
// 如果找到了模型,就不再尝试其他选择器
|
| 2188 |
+
if (modelList.length > 0) {
|
| 2189 |
+
break;
|
| 2190 |
+
}
|
| 2191 |
+
}
|
| 2192 |
+
} catch (e) {
|
| 2193 |
+
continue;
|
| 2194 |
}
|
| 2195 |
+
}
|
| 2196 |
|
| 2197 |
return modelList;
|
| 2198 |
});
|
| 2199 |
|
| 2200 |
+
if (models.length === 0) {
|
| 2201 |
+
throw new Error('页面中没有找到模型选项');
|
| 2202 |
+
}
|
| 2203 |
|
| 2204 |
+
return models;
|
| 2205 |
|
| 2206 |
+
} finally {
|
| 2207 |
+
await page.close().catch(e => log('warn', `页面关闭失败: ${e.message}`));
|
| 2208 |
+
}
|
| 2209 |
+
}
|
| 2210 |
+
|
| 2211 |
+
// 新增:通过AJAX方式获取模型
|
| 2212 |
+
async function extractModelsViaAjax() {
|
| 2213 |
+
const browser = await initBrowser();
|
| 2214 |
+
const page = await browser.newPage();
|
| 2215 |
+
|
| 2216 |
+
try {
|
| 2217 |
+
await page.goto('https://toolbaz.com/writer/ai-writer', {
|
| 2218 |
+
waitUntil: 'networkidle2',
|
| 2219 |
+
timeout: 20000
|
| 2220 |
+
});
|
| 2221 |
|
| 2222 |
+
const models = await page.evaluate(async () => {
|
| 2223 |
+
return new Promise((resolve) => {
|
| 2224 |
+
// 尝试通过AJAX获取模型列表
|
| 2225 |
+
const modelEndpoints = [
|
| 2226 |
+
'https://data.toolbaz.com/models.php',
|
| 2227 |
+
'https://data.toolbaz.com/api/models',
|
| 2228 |
+
'/api/models',
|
| 2229 |
+
'/models'
|
| 2230 |
+
];
|
| 2231 |
+
|
| 2232 |
+
let requestCount = 0;
|
| 2233 |
+
|
| 2234 |
+
const tryFetch = (url) => {
|
| 2235 |
+
return fetch(url, {
|
| 2236 |
+
method: 'GET',
|
| 2237 |
+
headers: {
|
| 2238 |
+
'Accept': 'application/json',
|
| 2239 |
+
'X-Requested-With': 'XMLHttpRequest',
|
| 2240 |
+
'Referer': window.location.href
|
| 2241 |
+
}
|
| 2242 |
+
})
|
| 2243 |
+
.then(response => {
|
| 2244 |
+
if (response.ok) {
|
| 2245 |
+
return response.json();
|
| 2246 |
+
}
|
| 2247 |
+
throw new Error(`HTTP ${response.status}`);
|
| 2248 |
+
})
|
| 2249 |
+
.then(data => {
|
| 2250 |
+
if (Array.isArray(data) && data.length > 0) {
|
| 2251 |
+
return data.map((model, index) => ({
|
| 2252 |
+
id: model.id || model.name?.toLowerCase().replace(/[^a-z0-9]/g, '-') || `model-${index}`,
|
| 2253 |
+
name: model.name || model.displayName || `Model ${index}`,
|
| 2254 |
+
icon: model.icon || '',
|
| 2255 |
+
object: 'model',
|
| 2256 |
+
created: Math.floor(Date.now() / 1000),
|
| 2257 |
+
owned_by: 'toolbaz'
|
| 2258 |
+
}));
|
| 2259 |
+
}
|
| 2260 |
+
throw new Error('无效的模型数据');
|
| 2261 |
+
});
|
| 2262 |
+
};
|
| 2263 |
+
|
| 2264 |
+
// 尝试所有端点
|
| 2265 |
+
const promises = modelEndpoints.map(url =>
|
| 2266 |
+
tryFetch(url).catch(err => {
|
| 2267 |
+
requestCount++;
|
| 2268 |
+
if (requestCount === modelEndpoints.length) {
|
| 2269 |
+
throw new Error('所有AJAX端点都失败了');
|
| 2270 |
+
}
|
| 2271 |
+
return null;
|
| 2272 |
+
})
|
| 2273 |
+
);
|
| 2274 |
+
|
| 2275 |
+
Promise.all(promises)
|
| 2276 |
+
.then(results => {
|
| 2277 |
+
const validResults = results.filter(r => r !== null);
|
| 2278 |
+
if (validResults.length > 0) {
|
| 2279 |
+
resolve(validResults[0]); // 使用第一个成功的结果
|
| 2280 |
+
} else {
|
| 2281 |
+
throw new Error('没有成功的AJAX请求');
|
| 2282 |
+
}
|
| 2283 |
+
})
|
| 2284 |
+
.catch(() => resolve([])); // 返回空数组表示失败
|
| 2285 |
+
});
|
| 2286 |
+
});
|
| 2287 |
+
|
| 2288 |
+
if (models.length === 0) {
|
| 2289 |
+
throw new Error('AJAX方式未获取到模型');
|
| 2290 |
+
}
|
| 2291 |
+
|
| 2292 |
+
return models;
|
| 2293 |
+
|
| 2294 |
+
} finally {
|
| 2295 |
+
await page.close().catch(e => log('warn', `页面关闭失败: ${e.message}`));
|
| 2296 |
}
|
| 2297 |
}
|
| 2298 |
|
| 2299 |
+
// 新增:增强的静态模型配置
|
| 2300 |
+
async function getEnhancedStaticModels() {
|
| 2301 |
+
// 结合配置中的模型和常见的AI模型
|
| 2302 |
+
const enhancedModels = [
|
| 2303 |
+
// 聊天模型
|
| 2304 |
+
...CONFIG.CHAT_MODELS.map(name => ({
|
| 2305 |
+
id: name.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
| 2306 |
+
name: name,
|
| 2307 |
+
object: 'model',
|
| 2308 |
+
created: Math.floor(Date.now() / 1000),
|
| 2309 |
+
owned_by: 'toolbaz-2api'
|
| 2310 |
+
})),
|
| 2311 |
+
|
| 2312 |
+
// 图片模型
|
| 2313 |
+
...CONFIG.IMAGE_MODELS.map(name => ({
|
| 2314 |
+
id: name.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
| 2315 |
+
name: name,
|
| 2316 |
+
object: 'model',
|
| 2317 |
+
created: Math.floor(Date.now() / 1000),
|
| 2318 |
+
owned_by: 'toolbaz-2api'
|
| 2319 |
+
})),
|
| 2320 |
+
|
| 2321 |
+
// 额外的常见模型
|
| 2322 |
+
{
|
| 2323 |
+
id: 'gpt-4',
|
| 2324 |
+
name: 'GPT-4',
|
| 2325 |
+
object: 'model',
|
| 2326 |
+
created: Math.floor(Date.now() / 1000),
|
| 2327 |
+
owned_by: 'toolbaz-2api'
|
| 2328 |
+
},
|
| 2329 |
+
{
|
| 2330 |
+
id: 'gpt-3.5-turbo',
|
| 2331 |
+
name: 'GPT-3.5 Turbo',
|
| 2332 |
+
object: 'model',
|
| 2333 |
+
created: Math.floor(Date.now() / 1000),
|
| 2334 |
+
owned_by: 'toolbaz-2api'
|
| 2335 |
+
},
|
| 2336 |
+
{
|
| 2337 |
+
id: 'claude-3-sonnet',
|
| 2338 |
+
name: 'Claude 3 Sonnet',
|
| 2339 |
+
object: 'model',
|
| 2340 |
+
created: Math.floor(Date.now() / 1000),
|
| 2341 |
+
owned_by: 'toolbaz-2api'
|
| 2342 |
+
}
|
| 2343 |
+
];
|
| 2344 |
+
|
| 2345 |
+
// 去重
|
| 2346 |
+
const uniqueModels = [];
|
| 2347 |
+
const seenIds = new Set();
|
| 2348 |
+
|
| 2349 |
+
for (const model of enhancedModels) {
|
| 2350 |
+
if (!seenIds.has(model.id)) {
|
| 2351 |
+
seenIds.add(model.id);
|
| 2352 |
+
uniqueModels.push(model);
|
| 2353 |
+
}
|
| 2354 |
+
}
|
| 2355 |
+
|
| 2356 |
+
return uniqueModels;
|
| 2357 |
+
}
|
| 2358 |
+
|
| 2359 |
+
// 新增:基础静态模型配置
|
| 2360 |
+
function getBasicStaticModels() {
|
| 2361 |
+
return [...CONFIG.CHAT_MODELS, ...CONFIG.IMAGE_MODELS].map(id => ({
|
| 2362 |
+
id: id.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
| 2363 |
+
name: id,
|
| 2364 |
+
object: 'model',
|
| 2365 |
+
created: Math.floor(Date.now() / 1000),
|
| 2366 |
+
owned_by: 'toolbaz-2api'
|
| 2367 |
+
}));
|
| 2368 |
+
}
|
| 2369 |
+
|
| 2370 |
// 新增:测试API端点
|
| 2371 |
async function handleTests(req, res) {
|
| 2372 |
if (!verifyAuth(req)) return sendError(res, 401, 'Unauthorized');
|
|
|
|
| 2432 |
max_retries: CONFIG.MAX_RETRIES,
|
| 2433 |
performance_monitoring: CONFIG.PERFORMANCE_MONITORING
|
| 2434 |
},
|
| 2435 |
+
browser: browser ? 'running' : 'stopped',
|
| 2436 |
+
cache: {
|
| 2437 |
+
models: modelCache.isValid() ? 'valid' : 'expired',
|
| 2438 |
+
credentials: credentialCache.isValid() ? 'valid' : 'expired'
|
| 2439 |
+
}
|
| 2440 |
};
|
| 2441 |
|
| 2442 |
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
|
|
| 2448 |
}
|
| 2449 |
}
|
| 2450 |
|
| 2451 |
+
// 新增:模型刷新处理函数
|
| 2452 |
+
async function handleModelsRefresh(req, res) {
|
| 2453 |
+
if (!verifyAuth(req)) return sendError(res, 401, 'Unauthorized');
|
| 2454 |
+
|
| 2455 |
+
try {
|
| 2456 |
+
log('info', '🔄 收到模型刷新请求...');
|
| 2457 |
+
|
| 2458 |
+
// 清除模型缓存
|
| 2459 |
+
modelCache.clear();
|
| 2460 |
+
|
| 2461 |
+
// 强制重新提取模型
|
| 2462 |
+
const response = await handleModels(req, res);
|
| 2463 |
+
|
| 2464 |
+
log('info', '✅ 模型刷新完成');
|
| 2465 |
+
|
| 2466 |
+
} catch (error) {
|
| 2467 |
+
log('error', `❌ 模型刷新失败: ${error.message}`);
|
| 2468 |
+
sendError(res, 500, error.message);
|
| 2469 |
+
}
|
| 2470 |
+
}
|
| 2471 |
+
|
| 2472 |
function handleUI(req, res) {
|
| 2473 |
const html = `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>${CONFIG.PROJECT_NAME}</title><style>:root{--bg:#121212;--panel:#1E1E1E;--border:#333;--text:#E0E0E0;--primary:#00FF9D;--secondary:#00BFA5;--error:#F44336;--success:#4CAF50;--warning:#FF9800}body{font-family:Consolas,monospace;background:var(--bg);color:var(--text);margin:0;height:100vh;display:flex;overflow:hidden;font-size:13px}.sidebar{width:320px;background:var(--panel);border-right:1px solid var(--border);display:flex;flex-direction:column;padding:10px;gap:10px}.main{flex:1;display:flex;flex-direction:column}.log-panel{height:40%;border-top:1px solid var(--border);background:#000;overflow-y:auto;padding:10px}.box{background:#252525;padding:15px;border-radius:6px;border:1px solid var(--border)}.label{font-size:11px;color:#888;display:block;margin-bottom:5px;text-transform:uppercase}input,select,textarea{width:100%;background:#333;border:1px solid #444;color:#fff;padding:8px;border-radius:4px;margin-bottom:10px;box-sizing:border-box;font-family:inherit}button{width:100%;padding:10px;background:var(--primary);border:none;border-radius:4px;font-weight:bold;cursor:pointer;color:#000;margin-bottom:5px;transition:all 0.2s}button:disabled{background:#555;cursor:not-allowed}button.secondary{background:#333;color:#fff;border:1px solid #555}button.danger{background:var(--error);color:#fff}button.warning{background:var(--warning);color:#000}.chat-window{flex:1;padding:20px;overflow-y:auto;display:flex;flex-direction:column;gap:15px}.msg{max-width:85%;padding:10px 15px;border-radius:6px;line-height:1.5;word-wrap:break-word}.msg.user{align-self:flex-end;background:#333;color:#fff}.msg.ai{align-self:flex-start;background:#1a1a1a;border:1px solid #333;width:100%}.msg.img img{max-width:100%;border-radius:4px}.log-entry{margin-bottom:8px;border-bottom:1px solid #222;padding-bottom:8px}.log-time{color:#666;margin-right:10px}.log-data{color:#ccc;white-space:pre-wrap;word-break:break-all;margin-top:4px;display:block}.tabs{display:flex;border-bottom:1px solid var(--border);margin-bottom:10px}.tab{flex:1;text-align:center;padding:8px;cursor:pointer;color:#888;border-bottom:2px solid transparent;transition:all 0.2s}.tab.active{color:var(--primary);border-bottom-color:var(--primary)}.status-item{display:flex;justify-content:space-between;margin-bottom:5px;font-size:12px}.status-value{color:var(--primary)}.test-result{margin:5px 0;padding:5px;border-radius:3px;font-size:11px}.test-pass{background:var(--success);color:#000}.test-fail{background:var(--error);color:#fff}.performance-grid{display:grid;grid-template-columns:1fr 1fr;gap:5px;margin-top:10px}.perf-item{text-align:center;padding:5px;background:#333;border-radius:3px}.perf-value{font-size:16px;color:var(--primary)}.perf-label{font-size:10px;color:#888}</style></head><body><div class="sidebar"><div class="box"><h2 style="margin:0;color:var(--primary)">${CONFIG.PROJECT_NAME}</h2><span style="font-size:11px;color:#666">v${CONFIG.PROJECT_VERSION} | Enhanced Testing</span></div><div class="box"><div class="tabs"><div class="tab active" onclick="switchMode('chat')">聊天</div><div class="tab" onclick="switchMode('image')">绘图</div><div class="tab" onclick="switchMode('test')">测试</div></div><div id="chat-controls"><span class="label">Model</span><select id="chat-model">${CONFIG.CHAT_MODELS.map(m => `<option value="${m}">${m}</option>`).join('')}</select><span class="label">Prompt</span><textarea id="chat-prompt" rows="5" placeholder="输入内容...">你好,请介绍一下你自己</textarea></div><div id="image-controls" style="display:none"><span class="label">Model</span><select id="image-model">${CONFIG.IMAGE_MODELS.map(m => `<option value="${m}">${m}</option>`).join('')}</select><span class="label">Prompt</span><textarea id="image-prompt" rows="5" placeholder="输入图片描述...">A futuristic city at sunset</textarea></div><div id="test-controls" style="display:none"><span class="label">测试类型</span><select id=\"test-type\"><option value=\"comprehensive\">综合测试</option><option value=\"config\">配置测试</option><option value=\"network\">网络测试</option><option value=\"browser\">浏览器测试</option><option value=\"session\">会话测试</option><option value=\"ajax\">AJAX测试</option><option value=\"prefix\">前缀过滤测试</option></select><button class="warning" onclick="runTest()">🧪 运行测试</button></div><button id="btn-send" onclick="handleSend()">发送请求</button></div><div class="box"><div class="status-item"><span>服务状态:</span><span class="status-value" id="service-status">检查中...</span></div><div class="status-item"><span>浏览器:</span><span class="status-value" id="browser-status">未知</span></div><div class="status-item"><span>总请求:</span><span class="status-value" id="total-requests">0</span></div><div class="status-item"><span>成功率:</span><span class="status-value" id="success-rate">0%</span></div><div class="performance-grid"><div class="perf-item"><div class="perf-value" id="ajax-success">0</div><div class="perf-label">AJAX成功</div></div><div class="perf-item"><div class="perf-value" id="ui-fallback">0</div><div class="perf-label">UI回退</div></div><div class="perf-item"><div class="perf-value" id="avg-response">0ms</div><div class="perf-label">平均响应</div></div><div class="perf-item"><div class="perf-value" id="uptime">0m</div><div class="perf-label">运行时间</div></div></div></div><div class="box" style="margin-top:auto"><button class="secondary" onclick="copyLogs()">📋 复制日志</button><button class="secondary" onclick="clearLogs()">🗑️ 清空日志</button><button class="secondary" onclick="refreshStatus()">🔄 刷新状态</button></div></div><div class="main"><div class="chat-window" id="chat"><div class="msg ai">🎉 ${CONFIG.PROJECT_NAME} v${CONFIG.PROJECT_VERSION} 已就绪<br><br>✨ 新功能:<br>• 🧪 增强的测试套件<br>• 📊 性能监控和统计<br>• 🔍 深度调试信息<br>• 🔄 智能重试机制<br><br>请选择聊天或测试模式开始使用!</div></div><div class="log-panel" id="log-container"></div></div><script>const API_KEY="${CONFIG.API_MASTER_KEY}";const ORIGIN=window.location.origin;let currentMode='chat';let statusInterval;function switchMode(mode){currentMode=mode;document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));event.target.classList.add('active');document.getElementById('chat-controls').style.display=mode==='chat'?'block':'none';document.getElementById('image-controls').style.display=mode==='image'?'block':'none';document.getElementById('test-controls').style.display=mode==='test'?'block':'none';const sendBtn=document.getElementById('btn-send');sendBtn.style.display=mode==='test'?'none':'block';}function appendLog(msg,type='info'){const div=document.createElement('div');div.className='log-entry';let color='#ccc';switch(type){case 'error':color='#F44336';break;case 'warn':color='#FF9800';break;case 'success':color='#4CAF50';break;case 'info':color='#2196F3';break;}div.innerHTML=\`<span class="log-time">\${new Date().toLocaleTimeString()}</span><span class="log-data" style="color:\${color}">\${msg}</span>\`;document.getElementById('log-container').appendChild(div);div.scrollIntoView()}function clearLogs(){document.getElementById('log-container').innerHTML=''}function copyLogs(){const logs=Array.from(document.querySelectorAll('.log-entry')).map(e=>e.innerText).join('\\n');navigator.clipboard.writeText(logs).then(()=>appendLog('日志已复制到剪贴板','success'))}function appendMsg(role,content){const div=document.createElement('div');div.className=\`msg \${role}\`;div.innerHTML=content;document.getElementById('chat').appendChild(div);div.scrollIntoView({behavior:"smooth"});return div}async function handleSend(){const btn=document.getElementById('btn-send');btn.disabled=true;clearLogs();appendLog('🚀 开始请求...');if(currentMode==='chat'){const prompt=document.getElementById('chat-prompt').value;const model=document.getElementById('chat-model').value;if(!prompt){btn.disabled=false;return}appendMsg('user',prompt);const aiMsg=appendMsg('ai','...');let fullText='';try{appendLog('📡 发送到浏览器...');const res=await fetch(ORIGIN+'/v1/chat/completions',{method:'POST',headers:{'Authorization':'Bearer '+API_KEY,'Content-Type':'application/json'},body:JSON.stringify({model,messages:[{role:'user',content:prompt}],stream:true})});appendLog('✅ 接收响应...');const reader=res.body.getReader();const decoder=new TextDecoder();while(true){const{done,value}=await reader.read();if(done)break;const chunk=decoder.decode(value);const lines=chunk.split('\\n');for(const line of lines){if(line.startsWith('data: ')){const dataStr=line.slice(6);if(dataStr==='[DONE]')break;try{const json=JSON.parse(dataStr);if(json.choices&&json.choices[0].delta.content){fullText+=json.choices[0].delta.content;aiMsg.innerText=fullText}}catch(e){}}}}appendLog('🎉 完成!','success');refreshStatus();}catch(e){aiMsg.innerText+='\\n[错误]: '+e.message;appendLog('❌ 错误: '+e.message,'error')}}else{const prompt=document.getElementById('image-prompt').value;const model=document.getElementById('image-model').value;if(!prompt){btn.disabled=false;return}appendMsg('user',prompt);const aiMsg=appendMsg('ai','生成中...');try{appendLog('🎨 发送图片请求...');const res=await fetch(ORIGIN+'/v1/images/generations',{method:'POST',headers:{'Authorization':'Bearer '+API_KEY,'Content-Type':'application/json'},body:JSON.stringify({model,prompt})});const data=await res.json();if(data.error)throw new Error(data.error.message);const imgUrl=data.data[0].url;aiMsg.innerHTML=\`<img src="\${imgUrl}" onclick="window.open(this.src)">\`;aiMsg.className='msg ai img';appendLog('✅ 图片生成成功!','success');refreshStatus();}catch(e){aiMsg.innerText='生成失败: '+e.message;appendLog('❌ 错误: '+e.message,'error')}}btn.disabled=false}async function runTest(){const testType=document.getElementById('test-type').value;appendLog(\`🧪 开始运行\${testType}测试...\`,'info');const testMsg=appendMsg('ai','<div id="test-results">正在运行测试...</div>');try{const res=await fetch(ORIGIN+'/v1/tests?type='+testType,{headers:{'Authorization':'Bearer '+API_KEY}});const data=await res.json();let html='<h3>测试结果</h3>';if(data.overall){html+=\`<p><strong>综合测试:</strong> \${data.overall.passed}/\${data.overall.passed+data.overall.failed} 通过</p>\`;if(data.configuration){html+=\`<div class="test-result test-pass">配置测试: \${data.configuration.passed} 通过, \${data.configuration.failed} 失败</div>\`;}}if(data.success===false){html+=\`<div class="test-result test-fail">测试失败: \${data.error}</div>\`;}else if(data.success){html+=\`<div class="test-result test-pass">测试通过</div>\`;}if(data.analysis){html+=\`<p><strong>会话分析:</strong> 找到 \${data.analysis.elementsFound.length} 个相关元素</p>\`;}if(data.length>0){html+='<h4>详细结果:</h4><ul>';data.forEach(result=>{const status=result.status==='success'?'pass':'fail';html+=\`<li class="test-result test-\${status}">\${result.name}: \${result.status}</li>\`;});html+='</ul>';}testMsg.querySelector('#test-results').innerHTML=html;appendLog('测试完成','success');refreshStatus();}catch(e){testMsg.innerHTML='<div class="test-result test-fail">测试执行失败: '+e.message+'</div>';appendLog('测试执行失败: '+e.message,'error');}}async function refreshStatus(){try{const res=await fetch(ORIGIN+'/v1/status',{headers:{'Authorization':'Bearer '+API_KEY}});const data=await res.json();document.getElementById('service-status').textContent='运行中';document.getElementById('browser-status').textContent=data.browser||'未知';document.getElementById('total-requests').textContent=data.performance.totalRequests||0;const successRate=data.performance.totalRequests>0?Math.round(data.performance.successfulRequests/data.performance.totalRequests*100):0;document.getElementById('success-rate').textContent=successRate+'%';document.getElementById('ajax-success').textContent=data.performance.ajaxSuccess||0;document.getElementById('ui-fallback').textContent=data.performance.uiFallback||0;document.getElementById('avg-response').textContent=(data.performance.averageResponseTime||0)+'ms';document.getElementById('uptime').textContent=Math.floor(data.uptime/60)+'m';}catch(e){appendLog('状态刷新失败: '+e.message,'error');}}function init(){refreshStatus();statusInterval=setInterval(refreshStatus,30000);}init();</script></body></html>`;
|
| 2474 |
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
|
|
| 2502 |
// 新增的测试和状态端点
|
| 2503 |
if (url.pathname === '/v1/tests') return await handleTests(req, res);
|
| 2504 |
if (url.pathname === '/v1/status') return await handleStatus(req, res);
|
| 2505 |
+
if (url.pathname === '/v1/models/refresh') return await handleModelsRefresh(req, res);
|
| 2506 |
|
| 2507 |
sendError(res, 404, 'Not Found');
|
| 2508 |
});
|
|
|
|
| 2558 |
log('info', ' - GET / : Web界面');
|
| 2559 |
log('info', ' - POST /v1/chat/completions : 聊天API');
|
| 2560 |
log('info', ' - POST /v1/images/generations : 图片生成API');
|
| 2561 |
+
log('info', ' - GET /v1/models : 模型列表API(带60分钟缓存)');
|
| 2562 |
+
log('info', ' - GET /v1/models/refresh : 强制刷新模型列表API');
|
| 2563 |
+
log('info', ' - GET /v1/status : 服务状态API(包含缓存状态)');
|
| 2564 |
log('info', ' - GET /v1/tests : 测试API (?type=config|network|browser|session|ajax|comprehensive)');
|
| 2565 |
|
| 2566 |
// 启动性能统计定时显示
|