Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
73c960f
fix: 增强错误解析以支持中转服务的嵌套错误结构
Silentely Nov 26, 2025
a589e01
refactor: 使用可选链简化错误提取逻辑
Silentely Nov 26, 2025
bb2298b
Merge pull request #212 from Silentely/fix/cubence-error-parsing
ding113 Nov 26, 2025
f435387
feat(availability): 添加供应商可用性监控模块并简化状态逻辑
ding113 Nov 26, 2025
0dc1e81
chore: format code (dev-f435387)
github-actions[bot] Nov 26, 2025
1881a94
perf: 优化供应商页面性能 - 修复 N+1 查询和 SQL 全表扫描问题
ding113 Nov 26, 2025
5f969de
chore: format code (dev-1881a94)
github-actions[bot] Nov 27, 2025
d3ba6bf
fix(provider-testing): 修复响应内容验证失败问题
ding113 Nov 27, 2025
72cd0de
fix(provider-stats): 修复供应商每日用量统计 JSONB 字段名错误
ding113 Nov 27, 2025
cc9ee9f
chore: format code (dev-72cd0de)
github-actions[bot] Nov 27, 2025
bf3814b
style(availability): 统一状态标签配色与请求日志一致
ding113 Nov 27, 2025
8bfb041
fix(i18n): 修复流式静默期超时提示与校验规则不一致
ding113 Nov 27, 2025
decbba1
fix(i18n): 修复登录重定向出现双重 locale 前缀问题
ding113 Nov 27, 2025
f24ed47
refactor(provider-testing): 简化内容验证逻辑,直接匹配原始响应体
ding113 Nov 27, 2025
27a740e
chore: format code (dev-f24ed47)
github-actions[bot] Nov 27, 2025
c0d9d7e
fix(i18n): 补充 zh-TW apiTest 缺失的 8 个翻译键
ding113 Nov 27, 2025
0c3fe23
docs: 添加 relay-pulse 项目致谢
ding113 Nov 27, 2025
9e20e42
fix(ui): 移除 DialogContent 硬编码的 sm:max-w-lg 宽度限制
ding113 Nov 27, 2025
7952f07
fix: 修复 PR review 中的多个问题
ding113 Nov 27, 2025
308375b
chore: format code (dev-7952f07)
github-actions[bot] Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ STORE_SESSION_MESSAGES=false # 是否存储请求 messages 到 Redis
# - 启用:适用于网络稳定环境,连续网络错误也应触发熔断保护,避免持续请求不可达的供应商
ENABLE_CIRCUIT_BREAKER_ON_NETWORK_ERRORS=false

# 智能探测配置
# 功能说明:当熔断器处于 OPEN 状态时,定期探测供应商以实现更快恢复
# - ENABLE_SMART_PROBING:是否启用智能探测(默认:false)
# - PROBE_INTERVAL_MS:探测周期间隔(毫秒,默认:30000 = 30秒)
# - PROBE_TIMEOUT_MS:单次探测超时时间(毫秒,默认:5000 = 5秒)
# 工作原理:
# - 定期检查处于 OPEN 状态的熔断器
# - 使用轻量级测试请求探测供应商
# - 探测成功则提前将熔断器转为 HALF_OPEN 状态
ENABLE_SMART_PROBING=false
PROBE_INTERVAL_MS=30000
PROBE_TIMEOUT_MS=5000

# 多提供商类型支持(实验性功能)
# - false (默认):仅支持 Claude、Codex类型供应商
# - true:支持 Gemini CLI、OpenAI Compatible 等其他类型
Expand Down
2 changes: 1 addition & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ We welcome issues and PRs! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for th

## 🌐 Acknowledgments

This project builds on [zsio/claude-code-hub](https://github.com/zsio/claude-code-hub) and references [router-for-me/CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) for the OpenAI-compatible layer. Huge thanks to the original authors and community contributors!
This project builds on [zsio/claude-code-hub](https://github.com/zsio/claude-code-hub), references [router-for-me/CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) for the OpenAI-compatible layer, and [prehisle/relay-pulse](https://github.com/prehisle/relay-pulse) for provider detection functionality. Huge thanks to the original authors and community contributors!

## ⭐ Star History

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ Docker Compose 是**首选部署方式**,自动配置数据库、Redis 和应

## 🌐 致谢 Acknowledgments

项目基于 [zsio/claude-code-hub](https://github.com/zsio/claude-code-hub) 深度改进,OpenAI 兼容层参考 [router-for-me/CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)。感谢原作者及社区贡献者!
项目基于 [zsio/claude-code-hub](https://github.com/zsio/claude-code-hub) 深度改进,OpenAI 兼容层参考 [router-for-me/CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI),供应商检测功能参考 [prehisle/relay-pulse](https://github.com/prehisle/relay-pulse)。感谢原作者及社区贡献者!

## ⭐ Star History

Expand Down
113 changes: 113 additions & 0 deletions messages/en/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
"dashboard": "Dashboard",
"usageLogs": "Usage Logs",
"leaderboard": "Leaderboard",
"availability": "Availability",
"quotasManagement": "Quota Management",
"userManagement": "User Management",
"documentation": "Documentation",
Expand Down Expand Up @@ -655,5 +656,117 @@
"groupFilter": "Filter by Group",
"allGroups": "All Groups"
}
},
"availability": {
"title": "Provider Availability Monitor",
"description": "Real-time monitoring of provider availability and performance metrics",
"nav": "Availability Monitor",
"status": {
"green": "Healthy",
"red": "Unhealthy",
"unknown": "Unknown"
},
"statusDescription": {
"green": "Service is healthy, requests successful",
"red": "Service unavailable or error",
"unknown": "No data available"
},
"metrics": {
"systemAvailability": "System Availability",
"totalRequests": "Total Requests",
"successRate": "Success Rate",
"avgLatency": "Avg Latency",
"p50Latency": "P50 Latency",
"p95Latency": "P95 Latency",
"p99Latency": "P99 Latency",
"lastRequest": "Last Request",
"requestCount": "Request Count"
},
"timeRange": {
"label": "Time Range",
"last15min": "Last 15 minutes",
"last1h": "Last 1 hour",
"last6h": "Last 6 hours",
"last24h": "Last 24 hours",
"last7d": "Last 7 days",
"custom": "Custom"
},
"filters": {
"provider": "Provider",
"allProviders": "All Providers",
"includeDisabled": "Include Disabled"
},
"sort": {
"label": "Sort By",
"availability": "Availability",
"name": "Name",
"requests": "Requests"
},
"columns": {
"provider": "Provider",
"type": "Type",
"status": "Status",
"availability": "Availability",
"requests": "Requests",
"successRate": "Success Rate",
"avgLatency": "Avg Latency",
"lastRequest": "Last Request",
"actions": "Actions"
},
"chart": {
"title": "Availability Trend",
"description": "Availability changes over time periods",
"availabilityScore": "Availability Score",
"requestVolume": "Request Volume",
"latencyTrend": "Latency Trend",
"noData": "No Data"
},
"details": {
"title": "Provider Details",
"overview": "Overview",
"timeBuckets": "Time Buckets",
"greenCount": "Successful Requests",
"redCount": "Failed Requests"
},
"actions": {
"refresh": "Refresh",
"refreshing": "Refreshing...",
"autoRefresh": "Auto Refresh",
"stopAutoRefresh": "Stop Auto Refresh",
"viewDetails": "View Details",
"testProvider": "Test Provider"
},
"states": {
"loading": "Loading...",
"error": "Load Failed",
"noProviders": "No Providers",
"noData": "No availability data",
"fetchFailed": "Failed to fetch availability data"
},
"legend": {
"green": "Excellent (95%+ availability)",
"lime": "Good (80-95% availability)",
"orange": "Warning (50-80% availability)",
"red": "Unhealthy (<50% availability)",
"noData": "No Data"
},
"summary": {
"title": "Availability Summary",
"healthyProviders": "Healthy Providers",
"unhealthyProviders": "Unhealthy Providers",
"unknownProviders": "No Data",
"totalProviders": "Total Providers"
},
"heatmap": {
"bucketSize": "Bucket Size",
"minutes": "min",
"requests": "requests",
"noData": "No Data",
"noRequests": "No Requests"
},
"toast": {
"refreshSuccess": "Availability data refreshed",
"refreshFailed": "Refresh failed, please retry"
}
}
}
101 changes: 99 additions & 2 deletions messages/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,16 @@
"formatOpenAIResponses": "Codex (Response API)",
"testModel": "Test model",
"testModelDesc": "Leave empty to use the default model or type one manually",
"requestConfig": "Request Configuration",
"presetConfig": "Preset",
"customConfig": "Custom",
"selectPreset": "Select preset template",
"presetDesc": "Preset templates contain authentic CLI request patterns for relay service verification",
"customPayloadPlaceholder": "{\"model\": \"...\", \"messages\": [...]}",
"customPayloadDesc": "Enter custom JSON payload to override default request body",
"successContains": "Success Keyword",
"successContainsPlaceholder": "pong",
"successContainsDesc": "Response must contain this keyword to be considered successful",
"model": "Model",
"responseModel": "Response model",
"responseTime": "Response time",
Expand Down Expand Up @@ -644,6 +654,93 @@
"resultReference": "[IMPORTANT] Results may vary by provider and are for reference only",
"realRequest": "This test sends a real request to the provider and may consume a small quota",
"confirmConfig": "Please verify provider URL, API key, and model configuration"
},
"resultCard": {
"status": {
"green": "Available",
"yellow": "Degraded",
"red": "Unavailable"
},
"dialogTitle": "Provider Test Details",
"validation": {
"title": "Three-tier Validation Details",
"http": {
"title": "Tier 1: HTTP Status",
"statusCode": "Status Code",
"passed": "2xx/3xx Success",
"failed": "4xx/5xx Failed"
},
"latency": {
"title": "Tier 2: Latency Threshold",
"actual": "Actual Latency",
"passed": "Within threshold",
"failed": "Exceeded threshold"
},
"content": {
"title": "Tier 3: Content Validation",
"target": "Target",
"passed": "Contains target string",
"failed": "Target not found"
},
"passed": "Passed",
"failed": "Failed",
"timeout": "Timeout"
},
"labels": {
"http": "HTTP",
"latency": "Latency",
"content": "Content",
"model": "Model",
"firstByte": "First Byte",
"totalLatency": "Total Latency",
"error": "Error",
"responsePreview": "Response Preview"
},
"timing": {
"title": "Timing Info",
"totalLatency": "Total Latency",
"firstByte": "First Byte",
"testedAt": "Tested At"
},
"tokenUsage": {
"title": "Token Usage",
"input": "Input",
"output": "Output",
"cacheCreation": "Cache Creation",
"cacheRead": "Cache Read"
},
"streamInfo": {
"title": "Stream Response Info",
"isStreaming": "Streaming",
"chunksCount": "Chunks Count",
"yes": "Yes",
"no": "No"
},
"rawResponse": {
"title": "Raw Response Body",
"hint": "This shows the raw response content. You can check if the keyword exists in the response here."
},
"errorDetails": {
"title": "Error Details",
"type": "Error Type"
},
"copyText": {
"status": "Status",
"message": "Message",
"latency": "Latency",
"httpStatus": "HTTP Status",
"model": "Model",
"usage": "Usage",
"inputOutput": "Input {input} / Output {output} tokens",
"response": "Response",
"error": "Error",
"testedAt": "Tested At",
"validationDetails": "Validation Details",
"httpCheck": "HTTP Check",
"latencyCheck": "Latency Check",
"contentCheck": "Content Check"
},
"judgment": "Judgment"
}
},
"proxyTest": {
Expand Down Expand Up @@ -1115,8 +1212,8 @@
},
"streamingIdle": {
"label": "Streaming Idle Timeout (seconds)",
"placeholder": "10",
"desc": "Streaming request idle timeout, range 1-120 seconds, default 10 seconds (prevent mid-stream stalling)",
"placeholder": "60",
"desc": "Streaming request idle timeout, range 60-600 seconds, enter 0 to disable (prevent mid-stream stalling)",
"core": "true"
},
"nonStreamingTotal": {
Expand Down
Loading