isididiidid commited on
Commit
a54d3d9
·
verified ·
1 Parent(s): 0945455

Update main.ts

Browse files
Files changed (1) hide show
  1. main.ts +307 -57
main.ts CHANGED
@@ -379,74 +379,323 @@ function buildHeaders(cookie: string): Record<string, string> {
379
  function getHealthPage(): string {
380
  return `
381
  <!DOCTYPE html>
382
- <html>
383
  <head>
384
  <title>LMArena API Proxy</title>
385
  <meta charset="utf-8">
 
386
  <style>
387
- body { font-family: Arial, sans-serif; margin: 40px; }
388
- .container { max-width: 800px; margin: 0 auto; }
389
- .status { color: green; font-weight: bold; }
390
- .endpoint { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 5px; }
391
- .model-list { max-height: 300px; overflow-y: auto; background: #f9f9f9; padding: 10px; }
392
- .feature { color: #007acc; font-weight: bold; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  </style>
394
  </head>
395
  <body>
396
  <div class="container">
397
- <h1>LMArena API Proxy</h1>
398
- <p class="status">✅ Service is running</p>
399
-
400
- <h2>Features</h2>
401
- <p class="feature">✨ 支持流式和非流式输出</p>
402
- <p class="feature">🔄 OpenAI API 完全兼容</p>
403
- <p class="feature">🎯 50+ 模型支持</p>
404
-
405
- <h2>API Endpoints</h2>
406
- <div class="endpoint">
407
- <strong>POST /v1/chat/completions</strong><br>
408
- OpenAI compatible chat completions endpoint<br>
409
- <em>支持 stream=true/false 参数</em>
410
- </div>
411
- <div class="endpoint">
412
- <strong>GET /v1/models</strong><br>
413
- List available models
414
  </div>
415
 
416
- <h2>Supported Models (${Object.keys(MODEL_MAPPING).length})</h2>
417
- <div class="model-list">
418
- ${Object.keys(MODEL_MAPPING).map(model => `<div>• ${model}</div>`).join('')}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  </div>
420
 
421
- <h2>Usage Examples</h2>
422
-
423
- <h3>流式输出 (Stream)</h3>
424
- <pre>
425
- curl -X POST "${Deno.env.get("SPACE_HOST") || "http://localhost:" + PORT}/v1/chat/completions" \\
426
- -H "Content-Type: application/json" \\
427
- -H "Authorization: Bearer YOUR_LMARENA_TOKEN" \\
428
- -d '{
429
- "model": "claude-opus-4-20250514",
430
- "messages": [
431
- {"role": "user", "content": "Hello!"}
432
- ],
433
- "stream": true
434
- }'
435
- </pre>
436
-
437
- <h3>非流式输出 (Non-Stream)</h3>
438
- <pre>
439
- curl -X POST "${Deno.env.get("SPACE_HOST") || "http://localhost:" + PORT}/v1/chat/completions" \\
440
- -H "Content-Type: application/json" \\
441
- -H "Authorization: Bearer YOUR_LMARENA_TOKEN" \\
442
- -d '{
443
- "model": "claude-opus-4-20250514",
444
- "messages": [
445
- {"role": "user", "content": "Hello!"}
446
- ],
447
- "stream": false
448
- }'
449
- </pre>
450
  </div>
451
  </body>
452
  </html>
@@ -502,7 +751,7 @@ Deno.serve({ port: PORT, hostname: HOST }, async (req: Request) => {
502
  return new Response(
503
  JSON.stringify({
504
  error: {
505
- message: `不支持的模型: ${modelName}`,
506
  type: 'invalid_request_error',
507
  code: 'model_not_found'
508
  }
@@ -682,3 +931,4 @@ console.log(`📡 监听地址: http://${HOST}:${PORT}`);
682
  console.log(`🔧 支持的模型数量: ${Object.keys(MODEL_MAPPING).length}`);
683
  console.log(`🌐 健康检查: http://${HOST}:${PORT}/`);
684
  console.log(`✨ 支持流式和非流式输出`);
 
 
379
  function getHealthPage(): string {
380
  return `
381
  <!DOCTYPE html>
382
+ <html lang="zh-CN">
383
  <head>
384
  <title>LMArena API Proxy</title>
385
  <meta charset="utf-8">
386
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
387
  <style>
388
+ * {
389
+ margin: 0;
390
+ padding: 0;
391
+ box-sizing: border-box;
392
+ }
393
+
394
+ body {
395
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
396
+ line-height: 1.6;
397
+ color: #333;
398
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
399
+ min-height: 100vh;
400
+ padding: 20px;
401
+ }
402
+
403
+ .container {
404
+ max-width: 900px;
405
+ margin: 0 auto;
406
+ background: white;
407
+ border-radius: 15px;
408
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
409
+ overflow: hidden;
410
+ }
411
+
412
+ .header {
413
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
414
+ color: white;
415
+ padding: 40px;
416
+ text-align: center;
417
+ }
418
+
419
+ .header h1 {
420
+ font-size: 2.5em;
421
+ margin-bottom: 10px;
422
+ font-weight: 300;
423
+ }
424
+
425
+ .status {
426
+ font-size: 1.2em;
427
+ opacity: 0.9;
428
+ }
429
+
430
+ .content {
431
+ padding: 40px;
432
+ }
433
+
434
+ .features {
435
+ display: grid;
436
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
437
+ gap: 20px;
438
+ margin-bottom: 40px;
439
+ }
440
+
441
+ .feature-card {
442
+ background: #f8f9fa;
443
+ padding: 25px;
444
+ border-radius: 10px;
445
+ text-align: center;
446
+ border-left: 4px solid #4facfe;
447
+ }
448
+
449
+ .feature-icon {
450
+ font-size: 2em;
451
+ margin-bottom: 15px;
452
+ }
453
+
454
+ .feature-title {
455
+ font-size: 1.1em;
456
+ font-weight: 600;
457
+ color: #2c3e50;
458
+ margin-bottom: 8px;
459
+ }
460
+
461
+ .feature-desc {
462
+ color: #6c757d;
463
+ font-size: 0.9em;
464
+ }
465
+
466
+ .section {
467
+ margin-bottom: 40px;
468
+ }
469
+
470
+ .section h2 {
471
+ color: #2c3e50;
472
+ margin-bottom: 20px;
473
+ font-size: 1.8em;
474
+ font-weight: 300;
475
+ border-bottom: 2px solid #e9ecef;
476
+ padding-bottom: 10px;
477
+ }
478
+
479
+ .endpoint-grid {
480
+ display: grid;
481
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
482
+ gap: 20px;
483
+ }
484
+
485
+ .endpoint {
486
+ background: #f8f9fa;
487
+ padding: 25px;
488
+ border-radius: 10px;
489
+ border-left: 4px solid #28a745;
490
+ }
491
+
492
+ .endpoint-method {
493
+ background: #28a745;
494
+ color: white;
495
+ padding: 4px 8px;
496
+ border-radius: 4px;
497
+ font-size: 0.8em;
498
+ font-weight: bold;
499
+ margin-right: 10px;
500
+ }
501
+
502
+ .endpoint-path {
503
+ font-family: 'Monaco', 'Menlo', monospace;
504
+ font-weight: bold;
505
+ color: #2c3e50;
506
+ }
507
+
508
+ .endpoint-desc {
509
+ margin-top: 10px;
510
+ color: #6c757d;
511
+ font-size: 0.9em;
512
+ }
513
+
514
+ .model-stats {
515
+ display: flex;
516
+ justify-content: space-around;
517
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
518
+ color: white;
519
+ padding: 30px;
520
+ border-radius: 10px;
521
+ margin-bottom: 20px;
522
+ }
523
+
524
+ .stat {
525
+ text-align: center;
526
+ }
527
+
528
+ .stat-number {
529
+ font-size: 2.5em;
530
+ font-weight: bold;
531
+ display: block;
532
+ }
533
+
534
+ .stat-label {
535
+ font-size: 0.9em;
536
+ opacity: 0.9;
537
+ }
538
+
539
+ .model-grid {
540
+ display: grid;
541
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
542
+ gap: 10px;
543
+ max-height: 400px;
544
+ overflow-y: auto;
545
+ background: #f8f9fa;
546
+ padding: 20px;
547
+ border-radius: 10px;
548
+ border: 1px solid #e9ecef;
549
+ }
550
+
551
+ .model-item {
552
+ background: white;
553
+ padding: 12px;
554
+ border-radius: 6px;
555
+ font-family: 'Monaco', 'Menlo', monospace;
556
+ font-size: 0.85em;
557
+ border: 1px solid #e9ecef;
558
+ transition: all 0.2s ease;
559
+ }
560
+
561
+ .model-item:hover {
562
+ border-color: #4facfe;
563
+ box-shadow: 0 2px 8px rgba(79, 172, 254, 0.2);
564
+ }
565
+
566
+ .footer {
567
+ background: #2c3e50;
568
+ color: white;
569
+ padding: 30px;
570
+ text-align: center;
571
+ }
572
+
573
+ .footer-links {
574
+ margin-top: 15px;
575
+ }
576
+
577
+ .footer-links a {
578
+ color: #4facfe;
579
+ text-decoration: none;
580
+ margin: 0 15px;
581
+ }
582
+
583
+ .footer-links a:hover {
584
+ text-decoration: underline;
585
+ }
586
+
587
+ @media (max-width: 768px) {
588
+ .header h1 {
589
+ font-size: 2em;
590
+ }
591
+
592
+ .content {
593
+ padding: 20px;
594
+ }
595
+
596
+ .features {
597
+ grid-template-columns: 1fr;
598
+ }
599
+
600
+ .model-stats {
601
+ flex-direction: column;
602
+ gap: 20px;
603
+ }
604
+ }
605
  </style>
606
  </head>
607
  <body>
608
  <div class="container">
609
+ <div class="header">
610
+ <h1>🤖 LMArena API Proxy</h1>
611
+ <div class="status">✅ 服务运行正常</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
  </div>
613
 
614
+ <div class="content">
615
+ <div class="features">
616
+ <div class="feature-card">
617
+ <div class="feature-icon">🌊</div>
618
+ <div class="feature-title">流式 & 非流式</div>
619
+ <div class="feature-desc">支持实时流式输出和完整响应两种模式</div>
620
+ </div>
621
+
622
+ <div class="feature-card">
623
+ <div class="feature-icon">🔄</div>
624
+ <div class="feature-title">OpenAI 兼容</div>
625
+ <div class="feature-desc">完全兼容 OpenAI API 格式,无缝迁移</div>
626
+ </div>
627
+
628
+ <div class="feature-card">
629
+ <div class="feature-icon">🎯</div>
630
+ <div class="feature-title">多模型支持</div>
631
+ <div class="feature-desc">支持 Claude、GPT、Gemini 等 50+ 模型</div>
632
+ </div>
633
+
634
+ <div class="feature-card">
635
+ <div class="feature-icon">🚀</div>
636
+ <div class="feature-title">高性能</div>
637
+ <div class="feature-desc">基于 Deno 运行时,快速稳定</div>
638
+ </div>
639
+ </div>
640
+
641
+ <div class="section">
642
+ <h2>📡 API 接口</h2>
643
+ <div class="endpoint-grid">
644
+ <div class="endpoint">
645
+ <div>
646
+ <span class="endpoint-method">POST</span>
647
+ <span class="endpoint-path">/v1/chat/completions</span>
648
+ </div>
649
+ <div class="endpoint-desc">
650
+ 聊天完成接口,支持流式和非流式输出<br>
651
+ 参数:stream=true/false
652
+ </div>
653
+ </div>
654
+
655
+ <div class="endpoint">
656
+ <div>
657
+ <span class="endpoint-method">GET</span>
658
+ <span class="endpoint-path">/v1/models</span>
659
+ </div>
660
+ <div class="endpoint-desc">
661
+ 获取支持的模型列表<br>
662
+ 返回所有可用模型信息
663
+ </div>
664
+ </div>
665
+ </div>
666
+ </div>
667
+
668
+ <div class="section">
669
+ <h2>🎯 模型统计</h2>
670
+ <div class="model-stats">
671
+ <div class="stat">
672
+ <span class="stat-number">${Object.keys(MODEL_MAPPING).length}</span>
673
+ <span class="stat-label">支持模型</span>
674
+ </div>
675
+ <div class="stat">
676
+ <span class="stat-number">5</span>
677
+ <span class="stat-label">主要厂商</span>
678
+ </div>
679
+ <div class="stat">
680
+ <span class="stat-number">24/7</span>
681
+ <span class="stat-label">服务可用</span>
682
+ </div>
683
+ </div>
684
+
685
+ <div class="model-grid">
686
+ ${Object.keys(MODEL_MAPPING).map(model => `<div class="model-item">${model}</div>`).join('')}
687
+ </div>
688
+ </div>
689
  </div>
690
 
691
+ <div class="footer">
692
+ <div>© 2025 LMArena API Proxy - 高性能 AI 模型代理服务</div>
693
+ <div class="footer-links">
694
+ <a href="/v1/models">模型列表</a>
695
+ <a href="https://github.com">GitHub</a>
696
+ <a href="https://docs.openai.com/api-reference">API 文档</a>
697
+ </div>
698
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
699
  </div>
700
  </body>
701
  </html>
 
751
  return new Response(
752
  JSON.stringify({
753
  error: {
754
+ message: `不支持的模型: ${modelName}`,
755
  type: 'invalid_request_error',
756
  code: 'model_not_found'
757
  }
 
931
  console.log(`🔧 支持的模型数量: ${Object.keys(MODEL_MAPPING).length}`);
932
  console.log(`🌐 健康检查: http://${HOST}:${PORT}/`);
933
  console.log(`✨ 支持流式和非流式输出`);
934
+