mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-09 03:26:38 +08:00
修改一些
This commit is contained in:
parent
741a078c87
commit
69f931543f
@ -33,6 +33,7 @@ export async function handle(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await request(req);
|
const response = await request(req);
|
||||||
|
console.log("我是从api这边进入的2", response);
|
||||||
return response;
|
return response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[Deepseek] ", e);
|
console.error("[Deepseek] ", e);
|
||||||
@ -42,6 +43,7 @@ export async function handle(
|
|||||||
|
|
||||||
async function request(req: NextRequest) {
|
async function request(req: NextRequest) {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
|
console.log("我是从api这边进入的", req.nextUrl.pathname);
|
||||||
|
|
||||||
// alibaba use base url or just remove the path
|
// alibaba use base url or just remove the path
|
||||||
let path = `${req.nextUrl.pathname}`.replaceAll(ApiPath.Deepseek, "");
|
let path = `${req.nextUrl.pathname}`.replaceAll(ApiPath.Deepseek, "");
|
||||||
@ -57,8 +59,8 @@ async function request(req: NextRequest) {
|
|||||||
baseUrl = baseUrl.slice(0, -1);
|
baseUrl = baseUrl.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("[Proxy] ", path);
|
console.log("[Deepseek Proxy] ", path);
|
||||||
console.log("[Base Url]", baseUrl);
|
console.log("[Deepseek Base Url]", baseUrl);
|
||||||
|
|
||||||
const timeoutId = setTimeout(
|
const timeoutId = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
|
@ -157,7 +157,7 @@ export class ClientApi {
|
|||||||
{
|
{
|
||||||
from: "human",
|
from: "human",
|
||||||
value:
|
value:
|
||||||
"Share from [NextChat]: https://github.com/Yidadaa/ChatGPT-Next-Web",
|
"Share from [清明上河图小助手]: https://github.com/Yidadaa/ChatGPT-Next-Web",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
// 敬告二开开发者们,为了开源大模型的发展,请不要修改上述消息,此消息用于后续数据清洗使用
|
// 敬告二开开发者们,为了开源大模型的发展,请不要修改上述消息,此消息用于后续数据清洗使用
|
||||||
@ -279,7 +279,7 @@ export function getHeaders() {
|
|||||||
const bearerToken = getBearerToken(apiKey, isAzure || isAnthropic);
|
const bearerToken = getBearerToken(apiKey, isAzure || isAnthropic);
|
||||||
console.log("bearerToken", bearerToken);
|
console.log("bearerToken", bearerToken);
|
||||||
// TODO: remove this 更换 Deepseek 的 api key
|
// TODO: remove this 更换 Deepseek 的 api key
|
||||||
headers["Authorization"] = `Bearer sk-c8e0505e462f49068758ebcc4331c9ee`;
|
headers["Authorization"] = `Bearer sk-94ee98bc9bd14db495d49eb598b69ff0`;
|
||||||
if (bearerToken) {
|
if (bearerToken) {
|
||||||
headers[authHeader] = bearerToken;
|
headers[authHeader] = bearerToken;
|
||||||
} else if (isEnabledAccessControl && validString(accessStore.accessCode)) {
|
} else if (isEnabledAccessControl && validString(accessStore.accessCode)) {
|
||||||
|
@ -206,14 +206,14 @@ export class DeepseekApi implements LLMApi {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onmessage(msg) {
|
onmessage(msg) {
|
||||||
console.log("msg", msg);
|
// console.log("msg", msg);
|
||||||
if (msg.data === "[DONE]" || finished) {
|
if (msg.data === "[DONE]" || finished) {
|
||||||
return finish();
|
return finish();
|
||||||
}
|
}
|
||||||
const text = msg.data;
|
const text = msg.data;
|
||||||
try {
|
try {
|
||||||
const json = JSON.parse(text);
|
const json = JSON.parse(text);
|
||||||
console.log("json", json);
|
// console.log("json", json);
|
||||||
|
|
||||||
const choices = json.choices as Array<{
|
const choices = json.choices as Array<{
|
||||||
delta: { content: string };
|
delta: { content: string };
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
|
// 导入必要的依赖
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
import Locale from "./locales";
|
import Locale from "./locales";
|
||||||
|
|
||||||
|
// 定义命令类型和命令接口
|
||||||
|
// Command 是一个接受字符串参数并返回 void 的函数类型
|
||||||
type Command = (param: string) => void;
|
type Command = (param: string) => void;
|
||||||
|
// Commands 接口定义了可能的命令及其对应的处理函数
|
||||||
interface Commands {
|
interface Commands {
|
||||||
fill?: Command;
|
fill?: Command;
|
||||||
submit?: Command;
|
submit?: Command;
|
||||||
@ -11,11 +15,18 @@ interface Commands {
|
|||||||
settings?: Command;
|
settings?: Command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义Hook:useCommand
|
||||||
|
* 用于处理URL参数中的命令
|
||||||
|
* @param commands - 命令对象,包含可能的命令及其处理函数
|
||||||
|
*/
|
||||||
export function useCommand(commands: Commands = {}) {
|
export function useCommand(commands: Commands = {}) {
|
||||||
|
// 使用 useSearchParams 钩子获取和设置 URL 参数
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let shouldUpdate = false;
|
let shouldUpdate = false;
|
||||||
|
// 遍历URL参数,执行对应的命令
|
||||||
searchParams.forEach((param, name) => {
|
searchParams.forEach((param, name) => {
|
||||||
const commandName = name as keyof Commands;
|
const commandName = name as keyof Commands;
|
||||||
if (typeof commands[commandName] === "function") {
|
if (typeof commands[commandName] === "function") {
|
||||||
@ -25,6 +36,7 @@ export function useCommand(commands: Commands = {}) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 如果有更新,则设置新的URL参数
|
||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
setSearchParams(searchParams);
|
setSearchParams(searchParams);
|
||||||
}
|
}
|
||||||
@ -32,19 +44,30 @@ export function useCommand(commands: Commands = {}) {
|
|||||||
}, [searchParams, commands]);
|
}, [searchParams, commands]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 定义聊天命令接口
|
||||||
interface ChatCommands {
|
interface ChatCommands {
|
||||||
new?: Command;
|
new?: Command; // 新建聊天
|
||||||
newm?: Command;
|
newm?: Command; // 新建面具聊天
|
||||||
next?: Command;
|
next?: Command; // 下一个聊天
|
||||||
prev?: Command;
|
prev?: Command; // 上一个聊天
|
||||||
clear?: Command;
|
clear?: Command; // 清除聊天历史
|
||||||
del?: Command;
|
del?: Command; // 删除当前聊天
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compatible with Chinese colon character ":"
|
// 定义聊天命令前缀(兼容中文冒号和英文冒号)
|
||||||
export const ChatCommandPrefix = /^[::]/;
|
export const ChatCommandPrefix = /^[::]/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义Hook:useChatCommand
|
||||||
|
* 用于处理聊天命令
|
||||||
|
* @param commands - 聊天命令对象,包含可能的命令及其处理函数
|
||||||
|
*/
|
||||||
export function useChatCommand(commands: ChatCommands = {}) {
|
export function useChatCommand(commands: ChatCommands = {}) {
|
||||||
|
/**
|
||||||
|
* 提取命令
|
||||||
|
* @param userInput - 用户输入的字符串
|
||||||
|
* @returns 提取出的命令(去掉前缀)
|
||||||
|
*/
|
||||||
function extract(userInput: string) {
|
function extract(userInput: string) {
|
||||||
const match = userInput.match(ChatCommandPrefix);
|
const match = userInput.match(ChatCommandPrefix);
|
||||||
if (match) {
|
if (match) {
|
||||||
@ -53,6 +76,11 @@ export function useChatCommand(commands: ChatCommands = {}) {
|
|||||||
return userInput as keyof ChatCommands;
|
return userInput as keyof ChatCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索匹配的命令
|
||||||
|
* @param userInput - 用户输入的字符串
|
||||||
|
* @returns 匹配的命令列表,包含标题和内容
|
||||||
|
*/
|
||||||
function search(userInput: string) {
|
function search(userInput: string) {
|
||||||
const input = extract(userInput);
|
const input = extract(userInput);
|
||||||
const desc = Locale.Chat.Commands;
|
const desc = Locale.Chat.Commands;
|
||||||
@ -64,6 +92,11 @@ export function useChatCommand(commands: ChatCommands = {}) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配并执行命令
|
||||||
|
* @param userInput - 用户输入的字符串
|
||||||
|
* @returns 包含是否匹配和执行函数的对象
|
||||||
|
*/
|
||||||
function match(userInput: string) {
|
function match(userInput: string) {
|
||||||
const command = extract(userInput);
|
const command = extract(userInput);
|
||||||
const matched = typeof commands[command] === "function";
|
const matched = typeof commands[command] === "function";
|
||||||
@ -76,3 +109,9 @@ export function useChatCommand(commands: ChatCommands = {}) {
|
|||||||
|
|
||||||
return { match, search };
|
return { match, search };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 参考资料:
|
||||||
|
// 1. React Router useSearchParams: https://reactrouter.com/web/api/Hooks/usesearchparams
|
||||||
|
// 2. React useEffect Hook: https://reactjs.org/docs/hooks-effect.html
|
||||||
|
// 3. TypeScript Interfaces: https://www.typescriptlang.org/docs/handbook/interfaces.html
|
||||||
|
// 4. JavaScript Regular Expressions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||||
|
@ -208,7 +208,7 @@ export function Artifacts() {
|
|||||||
<a href={REPO_URL} target="_blank" rel="noopener noreferrer">
|
<a href={REPO_URL} target="_blank" rel="noopener noreferrer">
|
||||||
<IconButton bordered icon={<GithubIcon />} shadow />
|
<IconButton bordered icon={<GithubIcon />} shadow />
|
||||||
</a>
|
</a>
|
||||||
<div className={styles["artifacts-title"]}>NextChat Artifacts</div>
|
<div className={styles["artifacts-title"]}>清明上河图小助手</div>
|
||||||
<ArtifactsShareButton
|
<ArtifactsShareButton
|
||||||
id={id}
|
id={id}
|
||||||
getCode={() => code}
|
getCode={() => code}
|
||||||
|
@ -539,7 +539,7 @@ export function ImagePreviewer(props: {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className={styles["main-title"]}>NextChat</div>
|
<div className={styles["main-title"]}>清明上河图小助手</div>
|
||||||
<div className={styles["sub-title"]}>
|
<div className={styles["sub-title"]}>
|
||||||
github.com/ChatGPTNextWeb/ChatGPT-Next-Web
|
github.com/ChatGPTNextWeb/ChatGPT-Next-Web
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,10 +30,14 @@ import { getClientConfig } from "../config/client";
|
|||||||
import { type ClientApi, getClientApi } from "../client/api";
|
import { type ClientApi, getClientApi } from "../client/api";
|
||||||
import { useAccessStore } from "../store";
|
import { useAccessStore } from "../store";
|
||||||
|
|
||||||
|
// Loading组件用于显示加载状态
|
||||||
export function Loading(props: { noLogo?: boolean }) {
|
export function Loading(props: { noLogo?: boolean }) {
|
||||||
return (
|
return (
|
||||||
|
// 使用styles["loading-content"]类名来应用样式,"no-dark"类用于防止暗色主题影响
|
||||||
<div className={styles["loading-content"] + " no-dark"}>
|
<div className={styles["loading-content"] + " no-dark"}>
|
||||||
|
{/* 如果noLogo属性为false,则显示BotIcon */}
|
||||||
{!props.noLogo && <BotIcon />}
|
{!props.noLogo && <BotIcon />}
|
||||||
|
{/* 显示LoadingIcon表示正在加载 */}
|
||||||
<LoadingIcon />
|
<LoadingIcon />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -105,13 +109,17 @@ function useHtmlLang() {
|
|||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 定义一个自定义Hook:useHasHydrated
|
||||||
const useHasHydrated = () => {
|
const useHasHydrated = () => {
|
||||||
|
// 使用useState初始化hasHydrated状态为false
|
||||||
const [hasHydrated, setHasHydrated] = useState<boolean>(false);
|
const [hasHydrated, setHasHydrated] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// 使用useEffect在组件挂载后将hasHydrated设置为true
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHasHydrated(true);
|
setHasHydrated(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 返回hasHydrated的当前值
|
||||||
return hasHydrated;
|
return hasHydrated;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -138,23 +146,31 @@ export function WindowContent(props: { children: React.ReactNode }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Screen 组件:负责渲染应用的主要内容
|
||||||
function Screen() {
|
function Screen() {
|
||||||
|
// 获取应用配置
|
||||||
const config = useAppConfig();
|
const config = useAppConfig();
|
||||||
|
// 获取当前路由位置
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
// 判断当前路径是否为特定页面
|
||||||
const isArtifact = location.pathname.includes(Path.Artifacts);
|
const isArtifact = location.pathname.includes(Path.Artifacts);
|
||||||
const isHome = location.pathname === Path.Home;
|
const isHome = location.pathname === Path.Home;
|
||||||
const isAuth = location.pathname === Path.Auth;
|
const isAuth = location.pathname === Path.Auth;
|
||||||
const isSd = location.pathname === Path.Sd;
|
const isSd = location.pathname === Path.Sd;
|
||||||
const isSdNew = location.pathname === Path.SdNew;
|
const isSdNew = location.pathname === Path.SdNew;
|
||||||
|
|
||||||
|
// 检查是否为移动屏幕
|
||||||
const isMobileScreen = useMobileScreen();
|
const isMobileScreen = useMobileScreen();
|
||||||
|
// 决定是否使用紧凑边框
|
||||||
const shouldTightBorder =
|
const shouldTightBorder =
|
||||||
getClientConfig()?.isApp || (config.tightBorder && !isMobileScreen);
|
getClientConfig()?.isApp || (config.tightBorder && !isMobileScreen);
|
||||||
|
|
||||||
|
// 加载Google字体
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadAsyncGoogleFont();
|
loadAsyncGoogleFont();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 如果是Artifacts页面,渲染特定路由
|
||||||
if (isArtifact) {
|
if (isArtifact) {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
@ -162,13 +178,17 @@ function Screen() {
|
|||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 渲染主要内容的函数
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (isAuth) return <AuthPage />;
|
if (isAuth) return <AuthPage />;
|
||||||
if (isSd) return <Sd />;
|
if (isSd) return <Sd />;
|
||||||
if (isSdNew) return <Sd />;
|
if (isSdNew) return <Sd />;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{/* 侧边栏 */}
|
||||||
<SideBar className={isHome ? styles["sidebar-show"] : ""} />
|
<SideBar className={isHome ? styles["sidebar-show"] : ""} />
|
||||||
|
{/* 主区域 */}
|
||||||
<WindowContent>
|
<WindowContent>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={Path.Home} element={<Chat />} />
|
<Route path={Path.Home} element={<Chat />} />
|
||||||
@ -182,6 +202,7 @@ function Screen() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 返回最终的渲染结果
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${styles.container} ${
|
className={`${styles.container} ${
|
||||||
@ -193,14 +214,21 @@ function Screen() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 定义一个自定义Hook:useLoadData
|
||||||
export function useLoadData() {
|
export function useLoadData() {
|
||||||
|
// 获取应用配置
|
||||||
const config = useAppConfig();
|
const config = useAppConfig();
|
||||||
|
|
||||||
|
// 根据配置中的提供商名称获取客户端API
|
||||||
const api: ClientApi = getClientApi(config.modelConfig.providerName);
|
const api: ClientApi = getClientApi(config.modelConfig.providerName);
|
||||||
|
|
||||||
|
// 使用useEffect钩子在组件挂载时加载数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// 定义一个异步函数来获取模型
|
||||||
(async () => {
|
(async () => {
|
||||||
|
// 从API获取模型列表
|
||||||
const models = await api.llm.models();
|
const models = await api.llm.models();
|
||||||
|
// 将获取到的模型合并到配置中
|
||||||
config.mergeModels(models);
|
config.mergeModels(models);
|
||||||
})();
|
})();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@ -208,19 +236,26 @@ export function useLoadData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Home() {
|
export function Home() {
|
||||||
|
// 切换主题
|
||||||
useSwitchTheme();
|
useSwitchTheme();
|
||||||
|
// 加载数据
|
||||||
useLoadData();
|
useLoadData();
|
||||||
|
// 设置HTML语言
|
||||||
useHtmlLang();
|
useHtmlLang();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// 从构建时获取配置并打印日志
|
||||||
console.log("[Config] got config from build time", getClientConfig());
|
console.log("[Config] got config from build time", getClientConfig());
|
||||||
|
// 获取访问权限
|
||||||
useAccessStore.getState().fetch();
|
useAccessStore.getState().fetch();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 如果组件还未水合,显示加载中
|
||||||
if (!useHasHydrated()) {
|
if (!useHasHydrated()) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 渲染主要内容
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Router>
|
<Router>
|
||||||
|
@ -225,8 +225,8 @@ export function SideBar(props: { className?: string }) {
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<SideBarHeader
|
<SideBarHeader
|
||||||
title="NextChat"
|
title="清明上河图小助手"
|
||||||
subTitle="Build your own AI assistant."
|
subTitle="清明上河图小助手."
|
||||||
logo={<ChatGptIcon />}
|
logo={<ChatGptIcon />}
|
||||||
>
|
>
|
||||||
<div className={styles["sidebar-header-bar"]}>
|
<div className={styles["sidebar-header-bar"]}>
|
||||||
|
@ -157,11 +157,16 @@ export function selectOrCopy(el: HTMLElement, content: string) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取DOM元素的内容宽度
|
||||||
function getDomContentWidth(dom: HTMLElement) {
|
function getDomContentWidth(dom: HTMLElement) {
|
||||||
|
// 获取元素的计算样式
|
||||||
const style = window.getComputedStyle(dom);
|
const style = window.getComputedStyle(dom);
|
||||||
|
// 计算左右内边距的总宽度
|
||||||
const paddingWidth =
|
const paddingWidth =
|
||||||
parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
|
parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
|
||||||
|
// 计算内容宽度:元素客户端宽度减去内边距宽度
|
||||||
const width = dom.clientWidth - paddingWidth;
|
const width = dom.clientWidth - paddingWidth;
|
||||||
|
// 返回计算得到的内容宽度
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user