feat(usage): 在用量查询页面添加服务端时间显示
- 在 UI 中添加服务端时间显示组件,包含样式和国际化支持 - 修改用量 API 返回数据,始终包含 serverTime 字段 - 更新前端 JavaScript 以解析并显示服务端时间 - 新增 OpenClaw 配置指南文档(中/英/日文)
This commit is contained in:
parent
d9f3a8002f
commit
d6c2bd7919
11 changed files with 692 additions and 6 deletions
213
OPENCLAW_CONFIG_GUIDE-JA.md
Normal file
213
OPENCLAW_CONFIG_GUIDE-JA.md
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
# OpenClaw 設定ガイド
|
||||
|
||||
OpenClaw で AIClient-2-API を使用するためのクイック設定ガイド。
|
||||
|
||||
---
|
||||
|
||||
## 前提条件
|
||||
|
||||
1. AIClient-2-API サービスを起動
|
||||
2. Web UI (`http://localhost:3000`) で少なくとも1つのプロバイダーを設定
|
||||
3. 設定ファイルから API Key を記録
|
||||
4. OpenClaw をインストール
|
||||
- Docker バージョン:[justlikemaki/openclaw-docker-cn-im](https://hub.docker.com/r/justlikemaki/openclaw-docker-cn-im)
|
||||
- または他のインストール方法を使用
|
||||
|
||||
---
|
||||
|
||||
## 設定方法
|
||||
|
||||
### 方法1:OpenAI プロトコル(推奨)
|
||||
|
||||
**使用例**:Gemini モデルを使用する場合
|
||||
|
||||
```json5
|
||||
{
|
||||
env: {
|
||||
AICLIENT2API_KEY: "your-api-key"
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "aiclient2api/gemini-3-flash-preview" },
|
||||
models: {
|
||||
"aiclient2api/gemini-3-flash-preview": { alias: "Gemini 3 Flash" }
|
||||
}
|
||||
}
|
||||
},
|
||||
models: {
|
||||
mode: "merge",
|
||||
providers: {
|
||||
aiclient2api: {
|
||||
baseUrl: "http://localhost:3000/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [
|
||||
{
|
||||
id: "gemini-3-flash-preview",
|
||||
name: "Gemini 3 Flash Preview",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 方法2:Claude プロトコル
|
||||
|
||||
**使用例**:Prompt Caching などの機能を持つ Claude モデルを使用する場合
|
||||
|
||||
```json5
|
||||
{
|
||||
env: {
|
||||
AICLIENT2API_KEY: "your-api-key"
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "aiclient2api/claude-sonnet-4-5" },
|
||||
models: {
|
||||
"aiclient2api/claude-sonnet-4-5": { alias: "Claude Sonnet 4.5" }
|
||||
}
|
||||
}
|
||||
},
|
||||
models: {
|
||||
mode: "merge",
|
||||
providers: {
|
||||
aiclient2api: {
|
||||
baseUrl: "http://localhost:3000",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "claude-sonnet-4-5",
|
||||
name: "Claude Sonnet 4.5",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200000,
|
||||
maxTokens: 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## プロバイダーの指定(オプション)
|
||||
|
||||
ルーティングパラメータで特定のプロバイダーを指定:
|
||||
|
||||
```json5
|
||||
{
|
||||
models: {
|
||||
providers: {
|
||||
// Kiro Claude(OpenAI プロトコル)
|
||||
"aiclient2api-kiro": {
|
||||
baseUrl: "http://localhost:3000/claude-kiro-oauth/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Kiro Claude(Claude プロトコル)
|
||||
"aiclient2api-kiro-claude": {
|
||||
baseUrl: "http://localhost:3000/claude-kiro-oauth",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Gemini CLI(OpenAI プロトコル)
|
||||
"aiclient2api-gemini": {
|
||||
baseUrl: "http://localhost:3000/gemini-cli-oauth/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Antigravity(OpenAI プロトコル)
|
||||
"aiclient2api-antigravity": {
|
||||
baseUrl: "http://localhost:3000/gemini-antigravity/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## フォールバックの設定
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "aiclient2api/claude-sonnet-4-5",
|
||||
fallbacks: [
|
||||
"aiclient2api/gemini-3-flash-preview"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## よく使うコマンド
|
||||
|
||||
```bash
|
||||
# すべてのモデルをリスト表示
|
||||
openclaw models list
|
||||
|
||||
# モデルを切り替え
|
||||
openclaw models set aiclient2api/claude-sonnet-4-5
|
||||
|
||||
# 特定のモデルでチャット
|
||||
openclaw chat --model aiclient2api/gemini-3-flash-preview "あなたの質問"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## プロトコル比較
|
||||
|
||||
| 機能 | OpenAI プロトコル | Claude プロトコル |
|
||||
|------|------------------|------------------|
|
||||
| Base URL | `http://localhost:3000/v1` | `http://localhost:3000` |
|
||||
| API タイプ | `openai-completions` | `anthropic-messages` |
|
||||
| サポートモデル | すべてのモデル | Claude のみ |
|
||||
| 特殊機能 | - | Prompt Caching、Extended Thinking |
|
||||
|
||||
---
|
||||
|
||||
## よくある質問
|
||||
|
||||
**Q: 接続に失敗しますか?**
|
||||
- AIClient-2-API サービスが実行中であることを確認
|
||||
- Base URL が正しいか確認(OpenAI プロトコルには `/v1` サフィックスが必要)
|
||||
- `localhost` の代わりに `127.0.0.1` を使用してみる
|
||||
|
||||
**Q: 401 エラー?**
|
||||
- API Key が正しく設定されているか確認
|
||||
- 環境変数 `AICLIENT2API_KEY` が設定されているか確認
|
||||
|
||||
**Q: モデルが利用できない?**
|
||||
- AIClient-2-API Web UI でプロバイダーが設定されているか確認
|
||||
- `openclaw gateway restart` を実行してゲートウェイを再起動
|
||||
- `openclaw models list` を実行してモデルリストを確認
|
||||
|
||||
---
|
||||
|
||||
詳細については、[AIClient-2-API ドキュメント](./README-JA.md) を参照してください
|
||||
213
OPENCLAW_CONFIG_GUIDE-ZH.md
Normal file
213
OPENCLAW_CONFIG_GUIDE-ZH.md
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
# OpenClaw 配置指南
|
||||
|
||||
在 OpenClaw 中使用 AIClient-2-API 的快速配置指南。
|
||||
|
||||
---
|
||||
|
||||
## 前置准备
|
||||
|
||||
1. 启动 AIClient-2-API 服务
|
||||
2. 在 Web UI (`http://localhost:3000`) 配置至少一个提供商
|
||||
3. 记录配置文件中的 API Key
|
||||
4. 安装 OpenClaw
|
||||
- Docker 版本:[justlikemaki/openclaw-docker-cn-im](https://hub.docker.com/r/justlikemaki/openclaw-docker-cn-im)
|
||||
- 或使用其他安装方式
|
||||
|
||||
---
|
||||
|
||||
## 配置方式
|
||||
|
||||
### 方式一:OpenAI 协议(推荐)
|
||||
|
||||
**适用场景**:使用 Gemini 模型
|
||||
|
||||
```json5
|
||||
{
|
||||
env: {
|
||||
AICLIENT2API_KEY: "your-api-key"
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "aiclient2api/gemini-3-flash-preview" },
|
||||
models: {
|
||||
"aiclient2api/gemini-3-flash-preview": { alias: "Gemini 3 Flash" }
|
||||
}
|
||||
}
|
||||
},
|
||||
models: {
|
||||
mode: "merge",
|
||||
providers: {
|
||||
aiclient2api: {
|
||||
baseUrl: "http://localhost:3000/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [
|
||||
{
|
||||
id: "gemini-3-flash-preview",
|
||||
name: "Gemini 3 Flash Preview",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 方式二:Claude 协议
|
||||
|
||||
**适用场景**:使用 Claude 模型,需要 Prompt Caching 等特性
|
||||
|
||||
```json5
|
||||
{
|
||||
env: {
|
||||
AICLIENT2API_KEY: "your-api-key"
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "aiclient2api/claude-sonnet-4-5" },
|
||||
models: {
|
||||
"aiclient2api/claude-sonnet-4-5": { alias: "Claude Sonnet 4.5" }
|
||||
}
|
||||
}
|
||||
},
|
||||
models: {
|
||||
mode: "merge",
|
||||
providers: {
|
||||
aiclient2api: {
|
||||
baseUrl: "http://localhost:3000",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "claude-sonnet-4-5",
|
||||
name: "Claude Sonnet 4.5",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200000,
|
||||
maxTokens: 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 指定提供商(可选)
|
||||
|
||||
通过路由参数指定特定提供商:
|
||||
|
||||
```json5
|
||||
{
|
||||
models: {
|
||||
providers: {
|
||||
// Kiro 提供的 Claude (OpenAI 协议)
|
||||
"aiclient2api-kiro": {
|
||||
baseUrl: "http://localhost:3000/claude-kiro-oauth/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Kiro 提供的 Claude (Claude 协议)
|
||||
"aiclient2api-kiro-claude": {
|
||||
baseUrl: "http://localhost:3000/claude-kiro-oauth",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Gemini CLI (OpenAI 协议)
|
||||
"aiclient2api-gemini": {
|
||||
baseUrl: "http://localhost:3000/gemini-cli-oauth/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Antigravity (OpenAI 协议)
|
||||
"aiclient2api-antigravity": {
|
||||
baseUrl: "http://localhost:3000/gemini-antigravity/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置 Fallback
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "aiclient2api/claude-sonnet-4-5",
|
||||
fallbacks: [
|
||||
"aiclient2api/gemini-3-flash-preview"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
# 列出所有模型
|
||||
openclaw models list
|
||||
|
||||
# 切换模型
|
||||
openclaw models set aiclient2api/claude-sonnet-4-5
|
||||
|
||||
# 使用指定模型对话
|
||||
openclaw chat --model aiclient2api/gemini-3-flash-preview "你的问题"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 协议对比
|
||||
|
||||
| 特性 | OpenAI 协议 | Claude 协议 |
|
||||
|------|------------|------------|
|
||||
| Base URL | `http://localhost:3000/v1` | `http://localhost:3000` |
|
||||
| API 类型 | `openai-completions` | `anthropic-messages` |
|
||||
| 支持模型 | 所有模型 | 仅 Claude |
|
||||
| 特殊特性 | - | Prompt Caching、Extended Thinking |
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
**Q: 连接失败?**
|
||||
- 确认 AIClient-2-API 服务运行中
|
||||
- 检查 Base URL 是否正确(OpenAI 协议需要 `/v1` 后缀)
|
||||
- 尝试使用 `127.0.0.1` 替代 `localhost`
|
||||
|
||||
**Q: 401 错误?**
|
||||
- 检查 API Key 是否正确配置
|
||||
- 确认环境变量 `AICLIENT2API_KEY` 已设置
|
||||
|
||||
**Q: 模型不可用?**
|
||||
- 在 AIClient-2-API Web UI 确认已配置对应提供商
|
||||
- 运行 `openclaw gateway restart` 重启网关
|
||||
- 运行 `openclaw models list` 验证模型列表
|
||||
|
||||
---
|
||||
|
||||
更多信息请参考 [AIClient-2-API 文档](../README-ZH.md)
|
||||
213
OPENCLAW_CONFIG_GUIDE.md
Normal file
213
OPENCLAW_CONFIG_GUIDE.md
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
# OpenClaw Configuration Guide
|
||||
|
||||
Quick configuration guide for using AIClient-2-API with OpenClaw.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Start AIClient-2-API service
|
||||
2. Configure at least one provider in Web UI (`http://localhost:3000`)
|
||||
3. Note the API Key from configuration file
|
||||
4. Install OpenClaw
|
||||
- Docker version: [justlikemaki/openclaw-docker-cn-im](https://hub.docker.com/r/justlikemaki/openclaw-docker-cn-im)
|
||||
- Or use other installation methods
|
||||
|
||||
---
|
||||
|
||||
## Configuration Methods
|
||||
|
||||
### Method 1: OpenAI Protocol (Recommended)
|
||||
|
||||
**Use Case**: For Gemini models
|
||||
|
||||
```json5
|
||||
{
|
||||
env: {
|
||||
AICLIENT2API_KEY: "your-api-key"
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "aiclient2api/gemini-3-flash-preview" },
|
||||
models: {
|
||||
"aiclient2api/gemini-3-flash-preview": { alias: "Gemini 3 Flash" }
|
||||
}
|
||||
}
|
||||
},
|
||||
models: {
|
||||
mode: "merge",
|
||||
providers: {
|
||||
aiclient2api: {
|
||||
baseUrl: "http://localhost:3000/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [
|
||||
{
|
||||
id: "gemini-3-flash-preview",
|
||||
name: "Gemini 3 Flash Preview",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1000000,
|
||||
maxTokens: 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Method 2: Claude Protocol
|
||||
|
||||
**Use Case**: For Claude models with features like Prompt Caching
|
||||
|
||||
```json5
|
||||
{
|
||||
env: {
|
||||
AICLIENT2API_KEY: "your-api-key"
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "aiclient2api/claude-sonnet-4-5" },
|
||||
models: {
|
||||
"aiclient2api/claude-sonnet-4-5": { alias: "Claude Sonnet 4.5" }
|
||||
}
|
||||
}
|
||||
},
|
||||
models: {
|
||||
mode: "merge",
|
||||
providers: {
|
||||
aiclient2api: {
|
||||
baseUrl: "http://localhost:3000",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "claude-sonnet-4-5",
|
||||
name: "Claude Sonnet 4.5",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200000,
|
||||
maxTokens: 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Specify Provider (Optional)
|
||||
|
||||
Specify a specific provider via routing parameters:
|
||||
|
||||
```json5
|
||||
{
|
||||
models: {
|
||||
providers: {
|
||||
// Kiro Claude (OpenAI Protocol)
|
||||
"aiclient2api-kiro": {
|
||||
baseUrl: "http://localhost:3000/claude-kiro-oauth/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Kiro Claude (Claude Protocol)
|
||||
"aiclient2api-kiro-claude": {
|
||||
baseUrl: "http://localhost:3000/claude-kiro-oauth",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "anthropic-messages",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Gemini CLI (OpenAI Protocol)
|
||||
"aiclient2api-gemini": {
|
||||
baseUrl: "http://localhost:3000/gemini-cli-oauth/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
},
|
||||
|
||||
// Antigravity (OpenAI Protocol)
|
||||
"aiclient2api-antigravity": {
|
||||
baseUrl: "http://localhost:3000/gemini-antigravity/v1",
|
||||
apiKey: "${AICLIENT2API_KEY}",
|
||||
api: "openai-completions",
|
||||
models: [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configure Fallback
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "aiclient2api/claude-sonnet-4-5",
|
||||
fallbacks: [
|
||||
"aiclient2api/gemini-3-flash-preview"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Commands
|
||||
|
||||
```bash
|
||||
# List all models
|
||||
openclaw models list
|
||||
|
||||
# Switch model
|
||||
openclaw models set aiclient2api/claude-sonnet-4-5
|
||||
|
||||
# Chat with specific model
|
||||
openclaw chat --model aiclient2api/gemini-3-flash-preview "your question"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Protocol Comparison
|
||||
|
||||
| Feature | OpenAI Protocol | Claude Protocol |
|
||||
|---------|----------------|-----------------|
|
||||
| Base URL | `http://localhost:3000/v1` | `http://localhost:3000` |
|
||||
| API Type | `openai-completions` | `anthropic-messages` |
|
||||
| Supported Models | All models | Claude only |
|
||||
| Special Features | - | Prompt Caching, Extended Thinking |
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Connection failed?**
|
||||
- Confirm AIClient-2-API service is running
|
||||
- Check if Base URL is correct (OpenAI protocol needs `/v1` suffix)
|
||||
- Try using `127.0.0.1` instead of `localhost`
|
||||
|
||||
**Q: 401 error?**
|
||||
- Check if API Key is correctly configured
|
||||
- Confirm environment variable `AICLIENT2API_KEY` is set
|
||||
|
||||
**Q: Model unavailable?**
|
||||
- Confirm provider is configured in AIClient-2-API Web UI
|
||||
- Run `openclaw gateway restart` to restart gateway
|
||||
- Run `openclaw models list` to verify model list
|
||||
|
||||
---
|
||||
|
||||
For more information, see [AIClient-2-API Documentation](./README.md)
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
[](https://github.com/justlovemaki/AIClient-2-API/stargazers)
|
||||
[](https://github.com/justlovemaki/AIClient-2-API/issues)
|
||||
|
||||
[中文](./README-ZH.md) | [English](./README.md) | [**👉 日本語**](./README-JA.md) | [**📚 完全ドキュメント**](https://aiproxy.justlikemaki.vip/ja/)
|
||||
[**🔧 OpenClaw 設定**](./OPENCLAW_CONFIG_GUIDE-JA.md) | [中文](./README-ZH.md) | [English](./README.md) | [**👉 日本語**](./README-JA.md) | [**📚 完全ドキュメント**](https://aiproxy.justlikemaki.vip/ja/)
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
[](https://github.com/justlovemaki/AIClient-2-API/stargazers)
|
||||
[](https://github.com/justlovemaki/AIClient-2-API/issues)
|
||||
|
||||
[**👉 中文**](./README-ZH.md) | [English](./README.md) | [日本語](./README-JA.md) | [**📚 完整文档**](https://aiproxy.justlikemaki.vip/zh/)
|
||||
[**🔧 OpenClaw 配置**](./OPENCLAW_CONFIG_GUIDE-ZH.md) | [**👉 中文**](./README-ZH.md) | [English](./README.md) | [日本語](./README-JA.md) | [**📚 完整文档**](https://aiproxy.justlikemaki.vip/zh/)
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
[](https://github.com/justlovemaki/AIClient-2-API/stargazers)
|
||||
[](https://github.com/justlovemaki/AIClient-2-API/issues)
|
||||
|
||||
[中文](./README-ZH.md) | [**👉 English**](./README.md) | [日本語](./README-JA.md) | [**📚 Documentation**](https://aiproxy.justlikemaki.vip/en/)
|
||||
[**🔧 OpenClaw Config**](./OPENCLAW_CONFIG_GUIDE.md) | [中文](./README-ZH.md) | [**👉 English**](./README.md) | [日本語](./README-JA.md) | [**📚 Documentation**](https://aiproxy.justlikemaki.vip/en/)
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -269,8 +269,14 @@ export async function handleGetUsage(req, res, currentConfig, providerPoolManage
|
|||
await writeUsageCache(usageResults);
|
||||
}
|
||||
|
||||
// Always include current server time
|
||||
const finalResults = {
|
||||
...usageResults,
|
||||
serverTime: new Date().toISOString()
|
||||
};
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify(usageResults));
|
||||
res.end(JSON.stringify(finalResults));
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error('[UI API] Failed to get usage:', error);
|
||||
|
|
@ -300,7 +306,7 @@ export async function handleGetProviderUsage(req, res, currentConfig, providerPo
|
|||
const cachedData = await readProviderUsageCache(providerType);
|
||||
if (cachedData) {
|
||||
logger.info(`[Usage API] Returning cached usage data for ${providerType}`);
|
||||
usageResults = cachedData;
|
||||
usageResults = { ...cachedData, fromCache: true };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -312,8 +318,14 @@ export async function handleGetProviderUsage(req, res, currentConfig, providerPo
|
|||
await updateProviderUsageCache(providerType, usageResults);
|
||||
}
|
||||
|
||||
// Always include current server time
|
||||
const finalResults = {
|
||||
...usageResults,
|
||||
serverTime: new Date().toISOString()
|
||||
};
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify(usageResults));
|
||||
res.end(JSON.stringify(finalResults));
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error(`[UI API] Failed to get usage for ${providerType}:`, error);
|
||||
|
|
|
|||
|
|
@ -515,6 +515,7 @@ const translations = {
|
|||
// Usage
|
||||
'usage.title': '用量查询',
|
||||
'usage.refresh': '刷新用量',
|
||||
'usage.serverTime': '服务端时间',
|
||||
'usage.lastUpdate': '上次更新: {time}',
|
||||
'usage.lastUpdateCache': '缓存时间: {time}',
|
||||
'usage.supportedProvidersPrefix': '支持用量查询的提供商:',
|
||||
|
|
@ -1285,6 +1286,7 @@ const translations = {
|
|||
// Usage
|
||||
'usage.title': 'Usage Query',
|
||||
'usage.refresh': 'Refresh Usage',
|
||||
'usage.serverTime': 'Server Time',
|
||||
'usage.lastUpdate': 'Last Update: {time}',
|
||||
'usage.lastUpdateCache': 'Cache Time: {time}',
|
||||
'usage.supportedProvidersPrefix': 'Providers supporting usage query:',
|
||||
|
|
|
|||
|
|
@ -92,6 +92,14 @@ export async function loadUsage() {
|
|||
// 渲染用量数据
|
||||
renderUsageData(data, contentEl);
|
||||
|
||||
// 更新服务端系统时间
|
||||
if (data.serverTime) {
|
||||
const serverTimeEl = document.getElementById('serverTimeValue');
|
||||
if (serverTimeEl) {
|
||||
serverTimeEl.textContent = new Date(data.serverTime).toLocaleString(getCurrentLanguage());
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后更新时间
|
||||
if (lastUpdateEl) {
|
||||
const timeStr = new Date(data.timestamp || Date.now()).toLocaleString(getCurrentLanguage());
|
||||
|
|
@ -155,6 +163,14 @@ export async function refreshUsage() {
|
|||
// 渲染用量数据
|
||||
renderUsageData(data, contentEl);
|
||||
|
||||
// 更新服务端系统时间
|
||||
if (data.serverTime) {
|
||||
const serverTimeEl = document.getElementById('serverTimeValue');
|
||||
if (serverTimeEl) {
|
||||
serverTimeEl.textContent = new Date(data.serverTime).toLocaleString(getCurrentLanguage());
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后更新时间
|
||||
if (lastUpdateEl) {
|
||||
const timeStr = new Date().toLocaleString(getCurrentLanguage());
|
||||
|
|
|
|||
|
|
@ -18,6 +18,20 @@
|
|||
.usage-last-update {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.server-time-display {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
margin-left: 1.5rem;
|
||||
padding-left: 1.5rem;
|
||||
border-left: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.server-time-display i {
|
||||
color: var(--primary-color);
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.usage-info-banner {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
<i class="fas fa-sync-alt"></i> <span data-i18n="usage.refresh">刷新用量</span>
|
||||
</button>
|
||||
<span class="usage-last-update" id="usageLastUpdate" data-i18n="usage.lastUpdate" data-i18n-params='{"time":"--"}'>上次更新: --</span>
|
||||
<span class="server-time-display" id="serverTimeDisplay">
|
||||
<span data-i18n="usage.serverTime">服务端时间</span>: <span id="serverTimeValue">--</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="usage-info-banner">
|
||||
|
|
|
|||
Loading…
Reference in a new issue