Skip to content

Commit

Permalink
feat: add web ui v2
Browse files Browse the repository at this point in the history
  • Loading branch information
MartialBE committed Dec 25, 2023
1 parent b7fcb31 commit e9de54f
Show file tree
Hide file tree
Showing 155 changed files with 13,325 additions and 3 deletions.
25 changes: 25 additions & 0 deletions controller/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"one-api/common"
"one-api/model"
"strconv"
"time"

"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -248,6 +249,30 @@ func GetUser(c *gin.Context) {
return
}

func GetUserDashboard(c *gin.Context) {
id := c.GetInt("id")
// 获取7天前 00:00:00 和 今天23:59:59 的秒时间戳
now := time.Now()
toDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
endOfDay := toDay.Add(time.Hour * 24).Add(-time.Second).Unix()
startOfDay := toDay.AddDate(0, 0, -7).Unix()

dashboards, err := model.SearchLogsByDayAndModel(id, int(startOfDay), int(endOfDay))
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "无法获取统计信息.",
})
return
}

c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
"data": dashboards,
})
}

func GenerateAccessToken(c *gin.Context) {
id := c.GetInt("id")
user, err := model.GetUserById(id, true)
Expand Down
58 changes: 55 additions & 3 deletions model/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package model
import (
"context"
"fmt"
"gorm.io/gorm"
"one-api/common"

"gorm.io/gorm"
)

type Log struct {
Expand All @@ -22,6 +23,15 @@ type Log struct {
ChannelId int `json:"channel" gorm:"index"`
}

type LogStatistic struct {
Day string `gorm:"column:day"`
ModelName string `gorm:"column:model_name"`
RequestCount int `gorm:"column:request_count"`
Quota int `gorm:"column:quota"`
PromptTokens int `gorm:"column:prompt_tokens"`
CompletionTokens int `gorm:"column:completion_tokens"`
}

const (
LogTypeUnknown = iota
LogTypeTopup
Expand Down Expand Up @@ -134,7 +144,7 @@ func SearchUserLogs(userId int, keyword string) (logs []*Log, err error) {
}

func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int) (quota int) {
tx := DB.Table("logs").Select("ifnull(sum(quota),0)")
tx := DB.Table("logs").Select(assembleSumSelectStr("quota"))
if username != "" {
tx = tx.Where("username = ?", username)
}
Expand All @@ -158,7 +168,7 @@ func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelNa
}

func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string) (token int) {
tx := DB.Table("logs").Select("ifnull(sum(prompt_tokens),0) + ifnull(sum(completion_tokens),0)")
tx := DB.Table("logs").Select(assembleSumSelectStr("prompt_tokens") + " + " + assembleSumSelectStr("completion_tokens"))
if username != "" {
tx = tx.Where("username = ?", username)
}
Expand All @@ -182,3 +192,45 @@ func DeleteOldLog(targetTimestamp int64) (int64, error) {
result := DB.Where("created_at < ?", targetTimestamp).Delete(&Log{})
return result.RowsAffected, result.Error
}

func SearchLogsByDayAndModel(user_id, start, end int) (LogStatistics []*LogStatistic, err error) {
groupSelect := "DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m-%d') as day"

if common.UsingPostgreSQL {
groupSelect = "TO_CHAR(date_trunc('day', to_timestamp(created_at)), 'YYYY-MM-DD') as day"
}

if common.UsingSQLite {
groupSelect = "strftime('%Y-%m-%d', datetime(created_at, 'unixepoch')) as day"
}

err = DB.Raw(`
SELECT `+groupSelect+`,
model_name, count(1) as request_count,
sum(quota) as quota,
sum(prompt_tokens) as prompt_tokens,
sum(completion_tokens) as completion_tokens
FROM logs
WHERE type=2
AND user_id= ?
AND created_at BETWEEN ? AND ?
GROUP BY day, model_name
ORDER BY day, model_name
`, user_id, start, end).Scan(&LogStatistics).Error

fmt.Println(user_id, start, end)

return LogStatistics, err
}

func assembleSumSelectStr(selectStr string) string {
sumSelectStr := "%s(sum(%s),0)"
nullfunc := "ifnull"
if common.UsingPostgreSQL {
nullfunc = "coalesce"
}

sumSelectStr = fmt.Sprintf(sumSelectStr, nullfunc, selectStr)

return sumSelectStr
}
1 change: 1 addition & 0 deletions router/api-router.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func SetApiRouter(router *gin.Engine) {
selfRoute := userRoute.Group("/")
selfRoute.Use(middleware.UserAuth())
{
selfRoute.GET("/dashboard", controller.GetUserDashboard)
selfRoute.GET("/self", controller.GetSelf)
selfRoute.PUT("/self", controller.UpdateSelf)
selfRoute.DELETE("/self", controller.DeleteSelf)
Expand Down
89 changes: 89 additions & 0 deletions web_v2/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"root": true,
"env": {
"browser": true,
"es2021": true
},
"extends": [
"prettier",
"plugin:react/jsx-runtime",
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended",
"eslint:recommended",
"plugin:react/recommended"
],
"settings": {
"react": {
"createClass": "createReactClass", // Regex for Component Factory to use,
// default to "createReactClass"
"pragma": "React", // Pragma to use, default to "React"
"fragment": "Fragment", // Fragment to use (may be a property of <pragma>), default to "Fragment"
"version": "detect", // React version. "detect" automatically picks the version you have installed.
// You can also use `16.0`, `16.3`, etc, if you want to override the detected value.
// It will default to "latest" and warn if missing, and to "detect" in the future
"flowVersion": "0.53" // Flow version
},
"import/resolver": {
"node": {
"moduleDirectory": ["node_modules", "src/"]
}
}
},
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"impliedStrict": true,
"jsx": true
},
"ecmaVersion": 12
},
"plugins": ["prettier", "react", "react-hooks"],
"rules": {
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/react-in-jsx-scope": "off",
"no-undef": "off",
"react/display-name": "off",
"react/jsx-filename-extension": "off",
"no-param-reassign": "off",
"react/prop-types": 1,
"react/require-default-props": "off",
"react/no-array-index-key": "off",
"react/jsx-props-no-spreading": "off",
"react/forbid-prop-types": "off",
"import/order": "off",
"import/no-cycle": "off",
"no-console": "off",
"jsx-a11y/anchor-is-valid": "off",
"prefer-destructuring": "off",
"no-shadow": "off",
"import/no-named-as-default": "off",
"import/no-extraneous-dependencies": "off",
"jsx-a11y/no-autofocus": "off",
"no-restricted-imports": [
"error",
{
"patterns": ["@mui/*/*/*", "!@mui/material/test-utils/*"]
}
],
"no-unused-vars": [
"error",
{
"ignoreRestSiblings": false
}
],
"prettier/prettier": [
"warn",
{
"bracketSpacing": true,
"printWidth": 140,
"singleQuote": true,
"trailingComma": "none",
"tabWidth": 2,
"useTabs": false,
"endOfLine": "auto"
}
]
}
}
26 changes: 26 additions & 0 deletions web_v2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.idea
package-lock.json
yarn.lock
8 changes: 8 additions & 0 deletions web_v2/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"bracketSpacing": true,
"printWidth": 140,
"singleQuote": true,
"trailingComma": "none",
"tabWidth": 2,
"useTabs": false
}
14 changes: 14 additions & 0 deletions web_v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# One API 前端界面

这个项目是 One API 的前端界面,它基于 [Berry Free React Admin Template](https://github.com/codedthemes/berry-free-react-admin-template) 进行开发。

## 使用的开源项目

使用了以下开源项目作为我们项目的一部分:

- [Berry Free React Admin Template](https://github.com/codedthemes/berry-free-react-admin-template)
- [minimal-ui-kit](minimal-ui-kit)

## 许可证

本项目中使用的代码遵循 MIT 许可证。
9 changes: 9 additions & 0 deletions web_v2/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"baseUrl": "src"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
84 changes: 84 additions & 0 deletions web_v2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"name": "one_api_web",
"version": "1.0.0",
"proxy": "http://127.0.0.1:3000",
"private": true,
"homepage": "",
"dependencies": {
"@emotion/cache": "^11.9.3",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@mui/icons-material": "^5.8.4",
"@mui/lab": "^5.0.0-alpha.88",
"@mui/material": "^5.8.6",
"@mui/system": "^5.8.6",
"@mui/utils": "^5.8.6",
"@mui/x-date-pickers": "^6.18.5",
"@tabler/icons-react": "^2.44.0",
"apexcharts": "^3.35.3",
"axios": "^0.27.2",
"dayjs": "^1.11.10",
"formik": "^2.2.9",
"framer-motion": "^6.3.16",
"history": "^5.3.0",
"marked": "^4.1.1",
"material-ui-popup-state": "^4.0.1",
"notistack": "^3.0.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-apexcharts": "^1.4.0",
"react-device-detect": "^2.2.2",
"react-dom": "^18.2.0",
"react-perfect-scrollbar": "^1.5.8",
"react-redux": "^8.0.2",
"react-router": "6.3.0",
"react-router-dom": "6.3.0",
"react-scripts": "^5.0.1",
"react-turnstile": "^1.1.2",
"redux": "^4.2.0",
"yup": "^0.32.11"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app"
]
},
"babel": {
"presets": [
"@babel/preset-react"
]
},
"browserslist": {
"production": [
"defaults",
"not IE 11"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@babel/core": "^7.21.4",
"@babel/eslint-parser": "^7.21.3",
"eslint": "^8.38.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"immutable": "^4.3.0",
"prettier": "^2.8.7",
"sass": "^1.53.0"
}
}
Binary file added web_v2/public/favicon.ico
Binary file not shown.
Loading

0 comments on commit e9de54f

Please sign in to comment.