mirror of
				https://github.com/linux-do/new-api.git
				synced 2025-11-04 13:23:42 +08:00 
			
		
		
		
	Merge pull request #439 from guoruqiang/main
改进了聊天页面,增加了初始令牌,方便用户注册后即可使用聊天功能。
This commit is contained in:
		@@ -64,6 +64,7 @@
 | 
			
		||||
您可以在渠道中添加自定义模型gpt-4-gizmo-*,此模型并非OpenAI官方模型,而是第三方模型,使用官方key无法调用。
 | 
			
		||||
 | 
			
		||||
## 比原版One API多出的配置
 | 
			
		||||
- `GENERATE_DEFAULT_TOKEN`:是否为新注册用户生成初始令牌,默认为 `false`。
 | 
			
		||||
- `STREAMING_TIMEOUT`:设置流式一次回复的超时时间,默认为 30 秒。
 | 
			
		||||
- `DIFY_DEBUG`:设置 Dify 渠道是否输出工作流和节点信息到客户端,默认为 `true`。
 | 
			
		||||
- `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-gonic/gin"
 | 
			
		||||
	"one-api/constant"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LoginRequest struct {
 | 
			
		||||
@@ -186,6 +187,39 @@ func Register(c *gin.Context) {
 | 
			
		||||
		})
 | 
			
		||||
		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{
 | 
			
		||||
		"success": true,
 | 
			
		||||
		"message": "",
 | 
			
		||||
 
 | 
			
		||||
@@ -20,12 +20,11 @@ import Redemption from './pages/Redemption';
 | 
			
		||||
import TopUp from './pages/TopUp';
 | 
			
		||||
import Log from './pages/Log';
 | 
			
		||||
import Chat from './pages/Chat';
 | 
			
		||||
import Chat2Link from './pages/Chat2Link';
 | 
			
		||||
import { Layout } from '@douyinfe/semi-ui';
 | 
			
		||||
import Midjourney from './pages/Midjourney';
 | 
			
		||||
import Pricing from './pages/Pricing/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 Detail = lazy(() => import('./pages/Detail'));
 | 
			
		||||
@@ -255,9 +254,20 @@ function App() {
 | 
			
		||||
            </Suspense>
 | 
			
		||||
          }
 | 
			
		||||
        />
 | 
			
		||||
        <Route path='*' element={<NotFound />} />
 | 
			
		||||
      </Routes>
 | 
			
		||||
    </>
 | 
			
		||||
        {/* 方便使用chat2link直接跳转聊天... */}
 | 
			
		||||
          <Route
 | 
			
		||||
            path='/chat2link'
 | 
			
		||||
            element={
 | 
			
		||||
              <PrivateRoute>
 | 
			
		||||
                <Suspense fallback={<Loading></Loading>}>
 | 
			
		||||
                    <Chat2Link />
 | 
			
		||||
                </Suspense>
 | 
			
		||||
              </PrivateRoute>
 | 
			
		||||
            }
 | 
			
		||||
          />
 | 
			
		||||
          <Route path='*' element={<NotFound />} />
 | 
			
		||||
        </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 { useTokenKeys } from '../../components/fetchTokenKeys';
 | 
			
		||||
import {  Layout } from '@douyinfe/semi-ui';
 | 
			
		||||
 | 
			
		||||
const Chat = () => {
 | 
			
		||||
  const chatLink = localStorage.getItem('chat_link');
 | 
			
		||||
const ChatPage = () => {
 | 
			
		||||
  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
 | 
			
		||||
      src={chatLink}
 | 
			
		||||
      src={iframeSrc}
 | 
			
		||||
      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;
 | 
			
		||||
		Reference in New Issue
	
	Block a user