diff --git a/controller/relay-text.go b/controller/relay-text.go
index 62c0c41a..e5c67126 100644
--- a/controller/relay-text.go
+++ b/controller/relay-text.go
@@ -442,7 +442,7 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
logContent = fmt.Sprintf("单价: $%.6g/1k tokens", inputPrice)
} else {
outputPrice := inputPrice * completionRatio
- logContent = fmt.Sprintf("输入: $%.6g/1k tokens, 输出: $%.6g/1k tokens", inputPrice, outputPrice)
+ logContent = fmt.Sprintf("输入:$%.6g/1k tokens, 输出:$%.6g/1k tokens", inputPrice, outputPrice)
}
model.RecordConsumeLog(ctx, userId, channelId, promptTokens, completionTokens, textRequest.Model, tokenName, quota, logContent)
model.UpdateUserUsedQuotaAndRequestCount(userId, quota)
diff --git a/web/src/components/ChannelsTable.js b/web/src/components/ChannelsTable.js
index b07edd90..dc146345 100644
--- a/web/src/components/ChannelsTable.js
+++ b/web/src/components/ChannelsTable.js
@@ -442,20 +442,18 @@ const ChannelsTable = () => {
+ />
+
- 删除
-
+
}
on='click'
flowing
@@ -471,9 +469,11 @@ const ChannelsTable = () => {
删除渠道 {channel.name}
+
+ />
+
+ />
+
);
})}
diff --git a/web/src/components/Header.js b/web/src/components/Header.js
index 053cf5a8..d2607583 100644
--- a/web/src/components/Header.js
+++ b/web/src/components/Header.js
@@ -43,7 +43,7 @@ let headerButtons = [
{
name: '用户',
to: '/user',
- icon: 'user',
+ icon: 'users',
color: 'var(--czl-primary-color)',
admin: true
},
@@ -54,9 +54,9 @@ let headerButtons = [
color: 'var(--czl-primary-color)'
},
{
- name: '设置',
+ name: '个人',
to: '/setting',
- icon: 'setting',
+ icon: 'user',
color: 'var(--czl-primary-color)'
},
{
diff --git a/web/src/components/LogsTable.js b/web/src/components/LogsTable.js
index a79e13e5..9ce8ca09 100644
--- a/web/src/components/LogsTable.js
+++ b/web/src/components/LogsTable.js
@@ -476,6 +476,8 @@ const LogsTable = () => {
Math.ceil(logs.length / ITEMS_PER_PAGE) +
(logs.length % ITEMS_PER_PAGE === 0 ? 1 : 0)
}
+ firstItem={null} // 不显示第一页按钮
+ lastItem={null} // 不显示最后一页按钮
/>
diff --git a/web/src/components/PersonalSetting.js b/web/src/components/PersonalSetting.js
index 0ade235d..cfbf0eae 100644
--- a/web/src/components/PersonalSetting.js
+++ b/web/src/components/PersonalSetting.js
@@ -32,6 +32,12 @@ const PersonalSetting = () => {
const [usedQuota, setUsedQuota] = useState(null);
const [requestCount, setRequestCount] = useState(null);
const [githubID, setGithubID] = useState(null);
+ const [username, setUsername] = useState(null);
+ const [display_name, setDisplay_name] = useState(null);
+ const [email, setEmail] = useState(null);
+
+ const [modelsByOwner, setModelsByOwner] = useState({});
+ const [key, setKey] = useState("");
@@ -52,7 +58,10 @@ const PersonalSetting = () => {
(async () => {
const res = await API.get(`/api/user/self`);
if (res.data.success) {
+ setDisplay_name(res.data.data.display_name);
+ setUsername(res.data.data.username);
setUserGroup(res.data.data.group);
+ setEmail(res.data.data.email);
setQuota(res.data.data.quota);
setUsedQuota(res.data.data.used_quota);
setRequestCount(res.data.data.request_count);
@@ -64,6 +73,66 @@ const PersonalSetting = () => {
}, []);
const quotaPerUnit = parseInt(localStorage.getItem("quota_per_unit"));
+ // useEffect(() => {
+ // // 获取用户的第一个key
+ // const fetchFirstKey = async () => {
+ // try {
+ // const tokenRes = await API.get('/api/token/?p=0');
+ // if (tokenRes.data.success && tokenRes.data.data.length > 0) {
+ // const firstKey = tokenRes.data.data[0].key;
+ // setKey(firstKey);
+ // fetchModels(firstKey);
+ // } else {
+ // // 如果没有获取到key,显示提示消息
+ // showError('请先创建一个key');
+ // }
+ // } catch (error) {
+ // showError('获取key失败');
+ // }
+ // };
+
+ // // 获取模型信息
+ // const fetchModels = async (key) => {
+ // try {
+ // const modelsRes = await API.get('/v1/models', {
+ // headers: { Authorization: `Bearer sk-${key}` },
+ // });
+ // if (modelsRes.data && modelsRes.data.data) {
+ // const models = modelsRes.data.data;
+ // const groupedByOwner = models.reduce((acc, model) => {
+ // const owner = model.owned_by.toUpperCase();
+ // if (!acc[owner]) {
+ // acc[owner] = [];
+ // }
+ // acc[owner].push(model.id);
+ // return acc;
+ // }, {});
+
+ // // 对owners进行排序
+ // const sortedOwners = Object.keys(groupedByOwner).sort();
+ // const sortedGroupedByOwner = {};
+ // sortedOwners.forEach(owner => {
+ // // 对每个owner的models进行排序
+ // sortedGroupedByOwner[owner] = groupedByOwner[owner].sort();
+ // });
+ // setModelsByOwner(sortedGroupedByOwner);
+ // }
+ // } catch (error) {
+ // showError('获取模型失败');
+ // }
+ // };
+
+ // fetchFirstKey();
+ // }, []);
+
+ // // 定义一个固定宽度的label样式
+ // const fixedWidthLabelStyle = {
+ // display: 'inline-block',
+ // minWidth: '150px', // 根据需要调整宽度
+ // textAlign: 'center',
+ // margin: '5px',
+ // };
+
const transformUserGroup = (group) => {
switch (group) {
@@ -207,25 +276,69 @@ const PersonalSetting = () => {
return (
- {userGroup && (
-
+
+ {display_name && (
+
+ )}
+ {username && (
+
+ )}
+
+
+
+ {userGroup && (
+
+ )}
+ {quota !== null && quotaPerUnit && (
+
+ )}
+ {usedQuota !== null && quotaPerUnit && (
+
+ )}
+ {requestCount !== null && (
+
+ )}
+
+
+
+
+ {/*
+ {Object.keys(modelsByOwner).length > 0 ? (
+ Object.entries(modelsByOwner).map(([owner, models], index) => (
+
+
+
+ {models.map((modelId, index) => (
+
+ ))}
+
+
+ ))
+ ) : (
+
+ 尚未绑定模型
+ 请先创建一个key
+
)}
- {quota !== null && quotaPerUnit && (
-
- )}
- {usedQuota !== null && quotaPerUnit && (
-
- )}
- {requestCount !== null &&
}
-
-
+
*/}
{/*
注意,此处生成的Key用于系统管理,而非用于请求 OpenAI 相关的服务,请知悉。
diff --git a/web/src/components/RedemptionsTable.js b/web/src/components/RedemptionsTable.js
index ee6be19c..1cce8a1c 100644
--- a/web/src/components/RedemptionsTable.js
+++ b/web/src/components/RedemptionsTable.js
@@ -17,13 +17,13 @@ function renderTimestamp(timestamp) {
function renderStatus(status) {
switch (status) {
case 1:
- return ;
+ return ;
case 2:
- return ;
+ return ;
case 3:
- return ;
+ return ;
default:
- return ;
+ return ;
}
}
@@ -232,66 +232,67 @@ const RedemptionsTable = () => {
{redemption.redeemed_time ? renderTimestamp(redemption.redeemed_time) : "尚未兑换"}
-
-
- 删除
-
- }
- on='click'
- flowing
- hoverable
->
-
-
-
-
-
+
+
);
})}
@@ -313,6 +314,8 @@ const RedemptionsTable = () => {
Math.ceil(redemptions.length / ITEMS_PER_PAGE) +
(redemptions.length % ITEMS_PER_PAGE === 0 ? 1 : 0)
}
+ firstItem={null} // 不显示第一页按钮
+ lastItem={null} // 不显示最后一页按钮
/>
diff --git a/web/src/components/TokensTable.js b/web/src/components/TokensTable.js
index 9afd6c2e..0ec94484 100644
--- a/web/src/components/TokensTable.js
+++ b/web/src/components/TokensTable.js
@@ -1,5 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Button, Dropdown, Form, Label, Pagination, Popup, Table } from 'semantic-ui-react';
+// import { Icon } from 'semantic-ui-react';
+
import { Link } from 'react-router-dom';
import { API, copy, showError, showSuccess, showWarning, timestamp2string } from '../helpers';
@@ -7,6 +9,7 @@ import { ITEMS_PER_PAGE } from '../constants';
import { renderQuota } from '../helpers/render';
+
function renderTimestamp(timestamp) {
return (
<>
@@ -234,6 +237,14 @@ const TokensTable = () => {
setLoading(false);
};
+ // 对key脱敏
+ function renderKey(key) {
+ // 使用固定数量的星号(例如8个)
+ const fixedNumberOfAsterisks = '********';
+ return `sk-${key.substring(0, 4)}${fixedNumberOfAsterisks}${key.substring(key.length - 4)}`;
+ }
+
+
return (
<>