修改一些

This commit is contained in:
yangyongju 2024-08-14 13:23:45 +08:00
parent 741a078c87
commit 69f931543f
10 changed files with 105 additions and 17 deletions

View File

@ -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(
() => { () => {

View File

@ -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)) {

View File

@ -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 };

View File

@ -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;
} }
/**
* HookuseCommand
* 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 = /^[:]/;
/**
* HookuseChatCommand
*
* @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

View File

@ -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}

View File

@ -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>

View File

@ -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() {
}, []); }, []);
} }
// 定义一个自定义HookuseHasHydrated
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() {
); );
} }
// 定义一个自定义HookuseLoadData
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>

View File

@ -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"]}>

View File

@ -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;
} }

7
注意事项.md Normal file
View File

@ -0,0 +1,7 @@
# 路由相关
- 此项目不是使用nextjs的app路由方式而是使用react-router-dom 的路由方式,
- 定义路由的位置是在 `app/components/Home.tsx` 文件中
- 根路由 renderContent
- WindowContent下的Routes包裹是切换路由
- 路由映射是在 [text](app/constant.ts) 文件中定义的Path如下