mirror of
https://github.com/linux-do/new-api.git
synced 2025-09-18 00:16:37 +08:00
Merge pull request #439 from guoruqiang/main
改进了聊天页面,增加了初始令牌,方便用户注册后即可使用聊天功能。
This commit is contained in:
commit
fff7609f06
@ -64,6 +64,7 @@
|
|||||||
您可以在渠道中添加自定义模型gpt-4-gizmo-*,此模型并非OpenAI官方模型,而是第三方模型,使用官方key无法调用。
|
您可以在渠道中添加自定义模型gpt-4-gizmo-*,此模型并非OpenAI官方模型,而是第三方模型,使用官方key无法调用。
|
||||||
|
|
||||||
## 比原版One API多出的配置
|
## 比原版One API多出的配置
|
||||||
|
- `GENERATE_DEFAULT_TOKEN`:是否为新注册用户生成初始令牌,默认为 `false`。
|
||||||
- `STREAMING_TIMEOUT`:设置流式一次回复的超时时间,默认为 30 秒。
|
- `STREAMING_TIMEOUT`:设置流式一次回复的超时时间,默认为 30 秒。
|
||||||
- `DIFY_DEBUG`:设置 Dify 渠道是否输出工作流和节点信息到客户端,默认为 `true`。
|
- `DIFY_DEBUG`:设置 Dify 渠道是否输出工作流和节点信息到客户端,默认为 `true`。
|
||||||
- `FORCE_STREAM_OPTION`:是否覆盖客户端stream_options参数,请求上游返回流模式usage,默认为 `true`,建议开启,不影响客户端传入stream_options参数返回结果。
|
- `FORCE_STREAM_OPTION`:是否覆盖客户端stream_options参数,请求上游返回流模式usage,默认为 `true`,建议开启,不影响客户端传入stream_options参数返回结果。
|
||||||
|
@ -46,3 +46,6 @@ func InitEnv() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否生成初始令牌,默认关闭。
|
||||||
|
var GenerateDefaultToken = common.GetEnvOrDefaultBool("GENERATE_DEFAULT_TOKEN", false)
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-contrib/sessions"
|
"github.com/gin-contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"one-api/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginRequest struct {
|
type LoginRequest struct {
|
||||||
@ -186,6 +187,39 @@ func Register(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取插入后的用户ID
|
||||||
|
var insertedUser model.User
|
||||||
|
if err := model.DB.Where("username = ?", cleanUser.Username).First(&insertedUser).Error; err != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"message": "用户注册失败或用户ID获取失败",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 生成默认令牌
|
||||||
|
if constant.GenerateDefaultToken {
|
||||||
|
// 生成默认令牌
|
||||||
|
token := model.Token{
|
||||||
|
UserId: insertedUser.Id, // 使用插入后的用户ID
|
||||||
|
Name: cleanUser.Username + "的初始令牌",
|
||||||
|
Key: common.GenerateKey(),
|
||||||
|
CreatedTime: common.GetTimestamp(),
|
||||||
|
AccessedTime: common.GetTimestamp(),
|
||||||
|
ExpiredTime: -1, // 永不过期
|
||||||
|
RemainQuota: 500000, // 示例额度
|
||||||
|
UnlimitedQuota: true,
|
||||||
|
ModelLimitsEnabled: false,
|
||||||
|
}
|
||||||
|
if err := token.Insert(); err != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"message": "创建默认令牌失败",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "",
|
"message": "",
|
||||||
|
@ -20,12 +20,11 @@ import Redemption from './pages/Redemption';
|
|||||||
import TopUp from './pages/TopUp';
|
import TopUp from './pages/TopUp';
|
||||||
import Log from './pages/Log';
|
import Log from './pages/Log';
|
||||||
import Chat from './pages/Chat';
|
import Chat from './pages/Chat';
|
||||||
|
import Chat2Link from './pages/Chat2Link';
|
||||||
import { Layout } from '@douyinfe/semi-ui';
|
import { Layout } from '@douyinfe/semi-ui';
|
||||||
import Midjourney from './pages/Midjourney';
|
import Midjourney from './pages/Midjourney';
|
||||||
import Pricing from './pages/Pricing/index.js';
|
import Pricing from './pages/Pricing/index.js';
|
||||||
import Task from "./pages/Task/index.js";
|
import Task from "./pages/Task/index.js";
|
||||||
import FooterBar from './components/Footer.js';
|
|
||||||
// import Detail from './pages/Detail';
|
|
||||||
|
|
||||||
const Home = lazy(() => import('./pages/Home'));
|
const Home = lazy(() => import('./pages/Home'));
|
||||||
const Detail = lazy(() => import('./pages/Detail'));
|
const Detail = lazy(() => import('./pages/Detail'));
|
||||||
@ -255,6 +254,17 @@ function App() {
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{/* 方便使用chat2link直接跳转聊天... */}
|
||||||
|
<Route
|
||||||
|
path='/chat2link'
|
||||||
|
element={
|
||||||
|
<PrivateRoute>
|
||||||
|
<Suspense fallback={<Loading></Loading>}>
|
||||||
|
<Chat2Link />
|
||||||
|
</Suspense>
|
||||||
|
</PrivateRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route path='*' element={<NotFound />} />
|
<Route path='*' element={<NotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
|
70
web/src/components/fetchTokenKeys.js
Normal file
70
web/src/components/fetchTokenKeys.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// src/hooks/useTokenKeys.js
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { API, showError } from '../helpers';
|
||||||
|
|
||||||
|
async function fetchTokenKeys() {
|
||||||
|
try {
|
||||||
|
const response = await API.get('/api/token/?p=0&size=999');
|
||||||
|
const { success, data } = response.data;
|
||||||
|
if (success) {
|
||||||
|
const activeTokens = data.filter((token) => token.status === 1);
|
||||||
|
return activeTokens.map((token) => token.key);
|
||||||
|
} else {
|
||||||
|
throw new Error('Failed to fetch token keys');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching token keys:", error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getServerAddress() {
|
||||||
|
let status = localStorage.getItem('status');
|
||||||
|
let serverAddress = '';
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
try {
|
||||||
|
status = JSON.parse(status);
|
||||||
|
serverAddress = status.server_address || '';
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to parse status from localStorage:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverAddress) {
|
||||||
|
serverAddress = window.location.origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTokenKeys() {
|
||||||
|
const [keys, setKeys] = useState([]);
|
||||||
|
const [chatLink, setChatLink] = useState('');
|
||||||
|
const [serverAddress, setServerAddress] = useState('');
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadAllData = async () => {
|
||||||
|
const fetchedKeys = await fetchTokenKeys();
|
||||||
|
if (fetchedKeys.length === 0) {
|
||||||
|
showError('当前没有可用的启用令牌,请确认是否有令牌处于启用状态!');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = '/token';
|
||||||
|
}, 1500); // 延迟 1.5 秒后跳转
|
||||||
|
}
|
||||||
|
setKeys(fetchedKeys);
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
const link = localStorage.getItem('chat_link');
|
||||||
|
setChatLink(link);
|
||||||
|
|
||||||
|
const address = getServerAddress();
|
||||||
|
setServerAddress(address);
|
||||||
|
};
|
||||||
|
|
||||||
|
loadAllData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { keys, chatLink, serverAddress, isLoading };
|
||||||
|
}
|
@ -1,14 +1,35 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTokenKeys } from '../../components/fetchTokenKeys';
|
||||||
|
import { Layout } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
const Chat = () => {
|
const ChatPage = () => {
|
||||||
const chatLink = localStorage.getItem('chat_link');
|
const { keys, chatLink, serverAddress, isLoading } = useTokenKeys();
|
||||||
|
|
||||||
return (
|
const comLink = (key) => {
|
||||||
|
if (!chatLink || !serverAddress || !key) return '';
|
||||||
|
return `${chatLink}/#/?settings={"key":"sk-${key}","url":"${encodeURIComponent(serverAddress)}"}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const iframeSrc = keys.length > 0 ? comLink(keys[0]) : '';
|
||||||
|
|
||||||
|
return !isLoading && iframeSrc ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={chatLink}
|
src={iframeSrc}
|
||||||
style={{ width: '100%', height: '85vh', border: 'none' }}
|
style={{ width: '100%', height: '85vh', border: 'none' }}
|
||||||
|
title="Token Frame"
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<Layout>
|
||||||
|
<Layout.Header>
|
||||||
|
<h3 style={{ color: 'red'}}>
|
||||||
|
当前没有可用的已启用令牌,请确认是否有令牌处于启用状态!<br />
|
||||||
|
正在跳转......
|
||||||
|
</h3>
|
||||||
|
</Layout.Header>
|
||||||
|
</Layout>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Chat;
|
export default ChatPage;
|
26
web/src/pages/Chat2Link/index.js
Normal file
26
web/src/pages/Chat2Link/index.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useTokenKeys } from '../../components/fetchTokenKeys';
|
||||||
|
|
||||||
|
const chat2page = () => {
|
||||||
|
const { keys, chatLink, serverAddress, isLoading } = useTokenKeys();
|
||||||
|
|
||||||
|
const comLink = (key) => {
|
||||||
|
if (!chatLink || !serverAddress || !key) return '';
|
||||||
|
return `${chatLink}/#/?settings={"key":"sk-${key}","url":"${encodeURIComponent(serverAddress)}"}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (keys.length > 0) {
|
||||||
|
const redirectLink = comLink(keys[0]);
|
||||||
|
if (redirectLink) {
|
||||||
|
window.location.href = redirectLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>正在加载,请稍候...</h3>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default chat2page;
|
Loading…
Reference in New Issue
Block a user