mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-11-11 02:43:44 +08:00
Compare commits
11 Commits
v0.6.11-al
...
v0.6.11-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e3b8230ac | ||
|
|
07808122a6 | ||
|
|
c96895e35b | ||
|
|
2552c68249 | ||
|
|
5c81e40612 | ||
|
|
0d5318b1b7 | ||
|
|
db65db2807 | ||
|
|
e0b7e6a9e2 | ||
|
|
27c2abe80f | ||
|
|
2c867251b5 | ||
|
|
108111ebd3 |
7
.github/workflows/docker-image.yml
vendored
7
.github/workflows/docker-image.yml
vendored
@@ -32,10 +32,10 @@ jobs:
|
|||||||
git describe --tags > VERSION
|
git describe --tags > VERSION
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
@@ -62,8 +62,9 @@ jobs:
|
|||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
# platforms: linux/amd64,linux/arm64
|
|
||||||
platforms: ${{ contains(github.ref, 'alpha') && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
platforms: ${{ contains(github.ref, 'alpha') && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
TARGETARCH=${{ startsWith(matrix.platform, 'linux/arm64') && 'arm64' || 'amd64' }}
|
||||||
1
.github/workflows/linux-release.yml
vendored
1
.github/workflows/linux-release.yml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v*.*.*'
|
||||||
- '!*-alpha*'
|
- '!*-alpha*'
|
||||||
|
- '!*-preview*'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
|
|||||||
1
.github/workflows/macos-release.yml
vendored
1
.github/workflows/macos-release.yml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v*.*.*'
|
||||||
- '!*-alpha*'
|
- '!*-alpha*'
|
||||||
|
- '!*-preview*'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
|
|||||||
1
.github/workflows/windows-release.yml
vendored
1
.github/workflows/windows-release.yml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v*.*.*'
|
||||||
- '!*-alpha*'
|
- '!*-alpha*'
|
||||||
|
- '!*-preview*'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
|
|||||||
29
Dockerfile
29
Dockerfile
@@ -9,23 +9,23 @@ RUN npm install --prefix /web/default & \
|
|||||||
npm install --prefix /web/air & \
|
npm install --prefix /web/air & \
|
||||||
wait
|
wait
|
||||||
|
|
||||||
RUN DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat /web/default/VERSION) npm run build --prefix /web/default & \
|
RUN DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat ./VERSION) npm run build --prefix /web/default & \
|
||||||
DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat /web/berry/VERSION) npm run build --prefix /web/berry & \
|
DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat ./VERSION) npm run build --prefix /web/berry & \
|
||||||
DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat /web/air/VERSION) npm run build --prefix /web/air & \
|
DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat ./VERSION) npm run build --prefix /web/air & \
|
||||||
wait
|
wait
|
||||||
|
|
||||||
FROM golang AS builder2
|
FROM golang:alpine AS builder2
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apk add --no-cache \
|
||||||
build-essential \
|
gcc \
|
||||||
sqlite3 libsqlite3-dev \
|
musl-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
sqlite-dev \
|
||||||
|
build-base
|
||||||
|
|
||||||
ENV GO111MODULE=on \
|
ENV GO111MODULE=on \
|
||||||
CGO_ENABLED=1 \
|
CGO_ENABLED=1 \
|
||||||
GOOS=linux \
|
GOOS=linux \
|
||||||
CGO_CFLAGS="-I/usr/include" \
|
GOARCH=$TARGETARCH
|
||||||
CGO_LDFLAGS="-L/usr/lib"
|
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
@@ -35,14 +35,11 @@ RUN go mod download
|
|||||||
COPY . .
|
COPY . .
|
||||||
COPY --from=builder /web/build ./web/build
|
COPY --from=builder /web/build ./web/build
|
||||||
|
|
||||||
RUN go build -trimpath -ldflags "-s -w -X 'github.com/songquanpeng/one-api/common.Version=$(cat VERSION)'" -o one-api
|
RUN go build -trimpath -ldflags "-s -w -X 'github.com/songquanpeng/one-api/common.Version=$(cat VERSION)' -linkmode external -extldflags '-static'" -o one-api
|
||||||
|
|
||||||
# Final runtime image
|
FROM alpine:latest
|
||||||
FROM ubuntu:22.04
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apk add --no-cache ca-certificates tzdata
|
||||||
ca-certificates tzdata bash \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY --from=builder2 /build/one-api /
|
COPY --from=builder2 /build/one-api /
|
||||||
|
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ If the channel ID is not provided, load balancing will be used to distribute the
|
|||||||
* [FastGPT](https://github.com/labring/FastGPT): Knowledge question answering system based on the LLM
|
* [FastGPT](https://github.com/labring/FastGPT): Knowledge question answering system based on the LLM
|
||||||
* [VChart](https://github.com/VisActor/VChart): More than just a cross-platform charting library, but also an expressive data storyteller.
|
* [VChart](https://github.com/VisActor/VChart): More than just a cross-platform charting library, but also an expressive data storyteller.
|
||||||
* [VMind](https://github.com/VisActor/VMind): Not just automatic, but also fantastic. Open-source solution for intelligent visualization.
|
* [VMind](https://github.com/VisActor/VMind): Not just automatic, but also fantastic. Open-source solution for intelligent visualization.
|
||||||
|
* * [CherryStudio](https://github.com/CherryHQ/cherry-studio): A cross-platform AI client that integrates multiple service providers and supports local knowledge base management.
|
||||||
|
|
||||||
## Note
|
## Note
|
||||||
This project is an open-source project. Please use it in compliance with OpenAI's [Terms of Use](https://openai.com/policies/terms-of-use) and **applicable laws and regulations**. It must not be used for illegal purposes.
|
This project is an open-source project. Please use it in compliance with OpenAI's [Terms of Use](https://openai.com/policies/terms-of-use) and **applicable laws and regulations**. It must not be used for illegal purposes.
|
||||||
|
|||||||
@@ -287,8 +287,8 @@ graph LR
|
|||||||
+ インターフェイスアドレスと API Key が正しいか再確認してください。
|
+ インターフェイスアドレスと API Key が正しいか再確認してください。
|
||||||
|
|
||||||
## 関連プロジェクト
|
## 関連プロジェクト
|
||||||
[FastGPT](https://github.com/labring/FastGPT): LLM に基づく知識質問応答システム
|
* [FastGPT](https://github.com/labring/FastGPT): LLM に基づく知識質問応答システム
|
||||||
|
* [CherryStudio](https://github.com/CherryHQ/cherry-studio): マルチプラットフォーム対応のAIクライアント。複数のサービスプロバイダーを統合管理し、ローカル知識ベースをサポートします。
|
||||||
## 注
|
## 注
|
||||||
本プロジェクトはオープンソースプロジェクトです。OpenAI の[利用規約](https://openai.com/policies/terms-of-use)および**適用される法令**を遵守してご利用ください。違法な目的での利用はご遠慮ください。
|
本プロジェクトはオープンソースプロジェクトです。OpenAI の[利用規約](https://openai.com/policies/terms-of-use)および**適用される法令**を遵守してご利用ください。違法な目的での利用はご遠慮ください。
|
||||||
|
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ https://openai.justsong.cn
|
|||||||
* [ChatGPT Next Web](https://github.com/Yidadaa/ChatGPT-Next-Web): 一键拥有你自己的跨平台 ChatGPT 应用
|
* [ChatGPT Next Web](https://github.com/Yidadaa/ChatGPT-Next-Web): 一键拥有你自己的跨平台 ChatGPT 应用
|
||||||
* [VChart](https://github.com/VisActor/VChart): 不只是开箱即用的多端图表库,更是生动灵活的数据故事讲述者。
|
* [VChart](https://github.com/VisActor/VChart): 不只是开箱即用的多端图表库,更是生动灵活的数据故事讲述者。
|
||||||
* [VMind](https://github.com/VisActor/VMind): 不仅自动,还很智能。开源智能可视化解决方案。
|
* [VMind](https://github.com/VisActor/VMind): 不仅自动,还很智能。开源智能可视化解决方案。
|
||||||
|
* [CherryStudio](https://github.com/CherryHQ/cherry-studio): 全平台支持的AI客户端, 多服务商集成管理、本地知识库支持。
|
||||||
|
|
||||||
## 注意
|
## 注意
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ func Error(ctx context.Context, msg string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Debugf(ctx context.Context, format string, a ...any) {
|
func Debugf(ctx context.Context, format string, a ...any) {
|
||||||
|
if !config.DebugEnabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
logHelper(ctx, loggerDEBUG, fmt.Sprintf(format, a...))
|
logHelper(ctx, loggerDEBUG, fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package ratio
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/songquanpeng/one-api/common/logger"
|
"github.com/songquanpeng/one-api/common/logger"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var groupRatioLock sync.RWMutex
|
||||||
var GroupRatio = map[string]float64{
|
var GroupRatio = map[string]float64{
|
||||||
"default": 1,
|
"default": 1,
|
||||||
"vip": 1,
|
"vip": 1,
|
||||||
@@ -20,11 +22,15 @@ func GroupRatio2JSONString() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateGroupRatioByJSONString(jsonStr string) error {
|
func UpdateGroupRatioByJSONString(jsonStr string) error {
|
||||||
|
groupRatioLock.Lock()
|
||||||
|
defer groupRatioLock.Unlock()
|
||||||
GroupRatio = make(map[string]float64)
|
GroupRatio = make(map[string]float64)
|
||||||
return json.Unmarshal([]byte(jsonStr), &GroupRatio)
|
return json.Unmarshal([]byte(jsonStr), &GroupRatio)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroupRatio(name string) float64 {
|
func GetGroupRatio(name string) float64 {
|
||||||
|
groupRatioLock.RLock()
|
||||||
|
defer groupRatioLock.RUnlock()
|
||||||
ratio, ok := GroupRatio[name]
|
ratio, ok := GroupRatio[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.SysError("group ratio not found: " + name)
|
logger.SysError("group ratio not found: " + name)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/songquanpeng/one-api/common/logger"
|
"github.com/songquanpeng/one-api/common/logger"
|
||||||
)
|
)
|
||||||
@@ -15,6 +16,8 @@ const (
|
|||||||
RMB = USD / USD2RMB
|
RMB = USD / USD2RMB
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var modelRatioLock sync.RWMutex
|
||||||
|
|
||||||
// ModelRatio
|
// ModelRatio
|
||||||
// https://platform.openai.com/docs/models/model-endpoint-compatibility
|
// https://platform.openai.com/docs/models/model-endpoint-compatibility
|
||||||
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Blfmc9dlf
|
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Blfmc9dlf
|
||||||
@@ -92,7 +95,7 @@ var ModelRatio = map[string]float64{
|
|||||||
"claude-3-sonnet-20240229": 3.0 / 1000 * USD,
|
"claude-3-sonnet-20240229": 3.0 / 1000 * USD,
|
||||||
"claude-3-5-sonnet-20240620": 3.0 / 1000 * USD,
|
"claude-3-5-sonnet-20240620": 3.0 / 1000 * USD,
|
||||||
"claude-3-5-sonnet-20241022": 3.0 / 1000 * USD,
|
"claude-3-5-sonnet-20241022": 3.0 / 1000 * USD,
|
||||||
"claude-3-5-sonnet-latest" : 3.0 / 1000 * USD,
|
"claude-3-5-sonnet-latest": 3.0 / 1000 * USD,
|
||||||
"claude-3-opus-20240229": 15.0 / 1000 * USD,
|
"claude-3-opus-20240229": 15.0 / 1000 * USD,
|
||||||
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/hlrk4akp7
|
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/hlrk4akp7
|
||||||
"ERNIE-4.0-8K": 0.120 * RMB,
|
"ERNIE-4.0-8K": 0.120 * RMB,
|
||||||
@@ -417,11 +420,15 @@ func ModelRatio2JSONString() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateModelRatioByJSONString(jsonStr string) error {
|
func UpdateModelRatioByJSONString(jsonStr string) error {
|
||||||
|
modelRatioLock.Lock()
|
||||||
|
defer modelRatioLock.Unlock()
|
||||||
ModelRatio = make(map[string]float64)
|
ModelRatio = make(map[string]float64)
|
||||||
return json.Unmarshal([]byte(jsonStr), &ModelRatio)
|
return json.Unmarshal([]byte(jsonStr), &ModelRatio)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetModelRatio(name string, channelType int) float64 {
|
func GetModelRatio(name string, channelType int) float64 {
|
||||||
|
modelRatioLock.RLock()
|
||||||
|
defer modelRatioLock.RUnlock()
|
||||||
if strings.HasPrefix(name, "qwen-") && strings.HasSuffix(name, "-internet") {
|
if strings.HasPrefix(name, "qwen-") && strings.HasSuffix(name, "-internet") {
|
||||||
name = strings.TrimSuffix(name, "-internet")
|
name = strings.TrimSuffix(name, "-internet")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Role string `json:"role,omitempty"`
|
Role string `json:"role,omitempty"`
|
||||||
Content any `json:"content,omitempty"`
|
Content any `json:"content,omitempty"`
|
||||||
Name *string `json:"name,omitempty"`
|
ReasoningContent any `json:"reasoning_content,omitempty"`
|
||||||
ToolCalls []Tool `json:"tool_calls,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
ToolCallId string `json:"tool_call_id,omitempty"`
|
ToolCalls []Tool `json:"tool_calls,omitempty"`
|
||||||
|
ToolCallId string `json:"tool_call_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) IsStringContent() bool {
|
func (m Message) IsStringContent() bool {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const CHANNEL_OPTIONS = [
|
|||||||
{ key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
|
{ key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
|
||||||
{ key: 28, text: 'Mistral AI', value: 28, color: 'orange' },
|
{ key: 28, text: 'Mistral AI', value: 28, color: 'orange' },
|
||||||
{ key: 41, text: 'Novita', value: 41, color: 'purple' },
|
{ key: 41, text: 'Novita', value: 41, color: 'purple' },
|
||||||
{ key: 40, text: '字节跳动豆包', value: 40, color: 'blue' },
|
{key: 40, text: '火山引擎', value: 40, color: 'blue'},
|
||||||
{ key: 15, text: '百度文心千帆', value: 15, color: 'blue' },
|
{ key: 15, text: '百度文心千帆', value: 15, color: 'blue' },
|
||||||
{ key: 17, text: '阿里通义千问', value: 17, color: 'orange' },
|
{ key: 17, text: '阿里通义千问', value: 17, color: 'orange' },
|
||||||
{ key: 18, text: '讯飞星火认知', value: 18, color: 'blue' },
|
{ key: 18, text: '讯飞星火认知', value: 18, color: 'blue' },
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const CHANNEL_OPTIONS = {
|
|||||||
},
|
},
|
||||||
40: {
|
40: {
|
||||||
key: 40,
|
key: 40,
|
||||||
text: '字节跳动豆包',
|
text: '火山引擎',
|
||||||
value: 40,
|
value: 40,
|
||||||
color: 'primary'
|
color: 'primary'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const CHANNEL_OPTIONS = [
|
|||||||
{ key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
|
{ key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
|
||||||
{ key: 28, text: 'Mistral AI', value: 28, color: 'orange' },
|
{ key: 28, text: 'Mistral AI', value: 28, color: 'orange' },
|
||||||
{ key: 41, text: 'Novita', value: 41, color: 'purple' },
|
{ key: 41, text: 'Novita', value: 41, color: 'purple' },
|
||||||
{ key: 40, text: '字节跳动豆包', value: 40, color: 'blue' },
|
{key: 40, text: '火山引擎', value: 40, color: 'blue'},
|
||||||
{ key: 15, text: '百度文心千帆', value: 15, color: 'blue' },
|
{ key: 15, text: '百度文心千帆', value: 15, color: 'blue' },
|
||||||
{ key: 17, text: '阿里通义千问', value: 17, color: 'orange' },
|
{ key: 17, text: '阿里通义千问', value: 17, color: 'orange' },
|
||||||
{ key: 18, text: '讯飞星火认知', value: 18, color: 'blue' },
|
{ key: 18, text: '讯飞星火认知', value: 18, color: 'blue' },
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, {useEffect, useState} from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import {useTranslation} from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {Card, Grid} from 'semantic-ui-react';
|
import { Card, Grid } from 'semantic-ui-react';
|
||||||
import {
|
import {
|
||||||
Bar,
|
Bar,
|
||||||
BarChart,
|
BarChart,
|
||||||
@@ -242,7 +242,7 @@ const Dashboard = () => {
|
|||||||
<Card.Content>
|
<Card.Content>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
{t('dashboard.charts.requests.title')}
|
{t('dashboard.charts.requests.title')}
|
||||||
{/* <span className='stat-value'>{summaryData.todayRequests}</span> */}
|
{/* <span className='stat-value'>{summaryData.todayRequests}</span> */}
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<div className='chart-container'>
|
<div className='chart-container'>
|
||||||
<ResponsiveContainer
|
<ResponsiveContainer
|
||||||
@@ -271,7 +271,9 @@ const Dashboard = () => {
|
|||||||
t('dashboard.charts.requests.tooltip'),
|
t('dashboard.charts.requests.tooltip'),
|
||||||
]}
|
]}
|
||||||
labelFormatter={(label) =>
|
labelFormatter={(label) =>
|
||||||
`${t('dashboard.statistics.tooltip.date')}: ${formatDate(label)}`
|
`${t(
|
||||||
|
'dashboard.statistics.tooltip.date'
|
||||||
|
)}: ${formatDate(label)}`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Line
|
<Line
|
||||||
@@ -294,7 +296,7 @@ const Dashboard = () => {
|
|||||||
<Card.Content>
|
<Card.Content>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
{t('dashboard.charts.quota.title')}
|
{t('dashboard.charts.quota.title')}
|
||||||
{/* <span className='stat-value'>
|
{/* <span className='stat-value'>
|
||||||
${summaryData.todayQuota.toFixed(3)}
|
${summaryData.todayQuota.toFixed(3)}
|
||||||
</span> */}
|
</span> */}
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
@@ -321,11 +323,13 @@ const Dashboard = () => {
|
|||||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
||||||
}}
|
}}
|
||||||
formatter={(value) => [
|
formatter={(value) => [
|
||||||
value,
|
value.toFixed(6),
|
||||||
t('dashboard.charts.quota.tooltip'),
|
t('dashboard.charts.quota.tooltip'),
|
||||||
]}
|
]}
|
||||||
labelFormatter={(label) =>
|
labelFormatter={(label) =>
|
||||||
`${t('dashboard.statistics.tooltip.date')}: ${formatDate(label)}`
|
`${t(
|
||||||
|
'dashboard.statistics.tooltip.date'
|
||||||
|
)}: ${formatDate(label)}`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Line
|
<Line
|
||||||
@@ -348,7 +352,7 @@ const Dashboard = () => {
|
|||||||
<Card.Content>
|
<Card.Content>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
{t('dashboard.charts.tokens.title')}
|
{t('dashboard.charts.tokens.title')}
|
||||||
{/* <span className='stat-value'>{summaryData.todayTokens}</span> */}
|
{/* <span className='stat-value'>{summaryData.todayTokens}</span> */}
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<div className='chart-container'>
|
<div className='chart-container'>
|
||||||
<ResponsiveContainer
|
<ResponsiveContainer
|
||||||
@@ -377,7 +381,9 @@ const Dashboard = () => {
|
|||||||
t('dashboard.charts.tokens.tooltip'),
|
t('dashboard.charts.tokens.tooltip'),
|
||||||
]}
|
]}
|
||||||
labelFormatter={(label) =>
|
labelFormatter={(label) =>
|
||||||
`${t('dashboard.statistics.tooltip.date')}: ${formatDate(label)}`
|
`${t(
|
||||||
|
'dashboard.statistics.tooltip.date'
|
||||||
|
)}: ${formatDate(label)}`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Line
|
<Line
|
||||||
@@ -422,7 +428,9 @@ const Dashboard = () => {
|
|||||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
||||||
}}
|
}}
|
||||||
labelFormatter={(label) =>
|
labelFormatter={(label) =>
|
||||||
`${t('dashboard.statistics.tooltip.date')}: ${formatDate(label)}`
|
`${t('dashboard.statistics.tooltip.date')}: ${formatDate(
|
||||||
|
label
|
||||||
|
)}`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Legend
|
<Legend
|
||||||
|
|||||||
Reference in New Issue
Block a user