From 69f931543fe61680154f2f8b383e3c9f32c2cd23 Mon Sep 17 00:00:00 2001 From: yangyongju <1243354771@qq.com> Date: Wed, 14 Aug 2024 13:23:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E4=BA=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/deepseek.ts | 6 ++-- app/client/api.ts | 4 +-- app/client/platforms/deepseek.ts | 4 +-- app/command.ts | 53 +++++++++++++++++++++++++++----- app/components/artifacts.tsx | 2 +- app/components/exporter.tsx | 2 +- app/components/home.tsx | 35 +++++++++++++++++++++ app/components/sidebar.tsx | 4 +-- app/utils.ts | 5 +++ 注意事项.md | 7 +++++ 10 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 注意事项.md diff --git a/app/api/deepseek.ts b/app/api/deepseek.ts index 4825ca94e..0eb2e80f8 100644 --- a/app/api/deepseek.ts +++ b/app/api/deepseek.ts @@ -33,6 +33,7 @@ export async function handle( try { const response = await request(req); + console.log("我是从api这边进入的2", response); return response; } catch (e) { console.error("[Deepseek] ", e); @@ -42,6 +43,7 @@ export async function handle( async function request(req: NextRequest) { const controller = new AbortController(); + console.log("我是从api这边进入的", req.nextUrl.pathname); // alibaba use base url or just remove the path let path = `${req.nextUrl.pathname}`.replaceAll(ApiPath.Deepseek, ""); @@ -57,8 +59,8 @@ async function request(req: NextRequest) { baseUrl = baseUrl.slice(0, -1); } - console.log("[Proxy] ", path); - console.log("[Base Url]", baseUrl); + console.log("[Deepseek Proxy] ", path); + console.log("[Deepseek Base Url]", baseUrl); const timeoutId = setTimeout( () => { diff --git a/app/client/api.ts b/app/client/api.ts index 8ca035b24..38869cdef 100644 --- a/app/client/api.ts +++ b/app/client/api.ts @@ -157,7 +157,7 @@ export class ClientApi { { from: "human", 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); console.log("bearerToken", bearerToken); // TODO: remove this 更换 Deepseek 的 api key - headers["Authorization"] = `Bearer sk-c8e0505e462f49068758ebcc4331c9ee`; + headers["Authorization"] = `Bearer sk-94ee98bc9bd14db495d49eb598b69ff0`; if (bearerToken) { headers[authHeader] = bearerToken; } else if (isEnabledAccessControl && validString(accessStore.accessCode)) { diff --git a/app/client/platforms/deepseek.ts b/app/client/platforms/deepseek.ts index 0db844a1b..6d09e8cbc 100644 --- a/app/client/platforms/deepseek.ts +++ b/app/client/platforms/deepseek.ts @@ -206,14 +206,14 @@ export class DeepseekApi implements LLMApi { } }, onmessage(msg) { - console.log("msg", msg); + // console.log("msg", msg); if (msg.data === "[DONE]" || finished) { return finish(); } const text = msg.data; try { const json = JSON.parse(text); - console.log("json", json); + // console.log("json", json); const choices = json.choices as Array<{ delta: { content: string }; diff --git a/app/command.ts b/app/command.ts index bea4e06f3..3973a1811 100644 --- a/app/command.ts +++ b/app/command.ts @@ -1,8 +1,12 @@ +// 导入必要的依赖 import { useEffect } from "react"; import { useSearchParams } from "react-router-dom"; import Locale from "./locales"; +// 定义命令类型和命令接口 +// Command 是一个接受字符串参数并返回 void 的函数类型 type Command = (param: string) => void; +// Commands 接口定义了可能的命令及其对应的处理函数 interface Commands { fill?: Command; submit?: Command; @@ -11,11 +15,18 @@ interface Commands { settings?: Command; } +/** + * 自定义Hook:useCommand + * 用于处理URL参数中的命令 + * @param commands - 命令对象,包含可能的命令及其处理函数 + */ export function useCommand(commands: Commands = {}) { + // 使用 useSearchParams 钩子获取和设置 URL 参数 const [searchParams, setSearchParams] = useSearchParams(); useEffect(() => { let shouldUpdate = false; + // 遍历URL参数,执行对应的命令 searchParams.forEach((param, name) => { const commandName = name as keyof Commands; if (typeof commands[commandName] === "function") { @@ -25,6 +36,7 @@ export function useCommand(commands: Commands = {}) { } }); + // 如果有更新,则设置新的URL参数 if (shouldUpdate) { setSearchParams(searchParams); } @@ -32,19 +44,30 @@ export function useCommand(commands: Commands = {}) { }, [searchParams, commands]); } +// 定义聊天命令接口 interface ChatCommands { - new?: Command; - newm?: Command; - next?: Command; - prev?: Command; - clear?: Command; - del?: Command; + new?: Command; // 新建聊天 + newm?: Command; // 新建面具聊天 + next?: Command; // 下一个聊天 + prev?: Command; // 上一个聊天 + clear?: Command; // 清除聊天历史 + del?: Command; // 删除当前聊天 } -// Compatible with Chinese colon character ":" +// 定义聊天命令前缀(兼容中文冒号和英文冒号) export const ChatCommandPrefix = /^[::]/; +/** + * 自定义Hook:useChatCommand + * 用于处理聊天命令 + * @param commands - 聊天命令对象,包含可能的命令及其处理函数 + */ export function useChatCommand(commands: ChatCommands = {}) { + /** + * 提取命令 + * @param userInput - 用户输入的字符串 + * @returns 提取出的命令(去掉前缀) + */ function extract(userInput: string) { const match = userInput.match(ChatCommandPrefix); if (match) { @@ -53,6 +76,11 @@ export function useChatCommand(commands: ChatCommands = {}) { return userInput as keyof ChatCommands; } + /** + * 搜索匹配的命令 + * @param userInput - 用户输入的字符串 + * @returns 匹配的命令列表,包含标题和内容 + */ function search(userInput: string) { const input = extract(userInput); const desc = Locale.Chat.Commands; @@ -64,6 +92,11 @@ export function useChatCommand(commands: ChatCommands = {}) { })); } + /** + * 匹配并执行命令 + * @param userInput - 用户输入的字符串 + * @returns 包含是否匹配和执行函数的对象 + */ function match(userInput: string) { const command = extract(userInput); const matched = typeof commands[command] === "function"; @@ -76,3 +109,9 @@ export function useChatCommand(commands: ChatCommands = {}) { 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 diff --git a/app/components/artifacts.tsx b/app/components/artifacts.tsx index 326891e73..a46fbf0d1 100644 --- a/app/components/artifacts.tsx +++ b/app/components/artifacts.tsx @@ -208,7 +208,7 @@ export function Artifacts() { } shadow /> -
NextChat Artifacts
+
清明上河图小助手
code} diff --git a/app/components/exporter.tsx b/app/components/exporter.tsx index 1771cc9b0..f72004cf9 100644 --- a/app/components/exporter.tsx +++ b/app/components/exporter.tsx @@ -539,7 +539,7 @@ export function ImagePreviewer(props: {
-
NextChat
+
清明上河图小助手
github.com/ChatGPTNextWeb/ChatGPT-Next-Web
diff --git a/app/components/home.tsx b/app/components/home.tsx index 095cc6dd2..135bc88fc 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -30,10 +30,14 @@ import { getClientConfig } from "../config/client"; import { type ClientApi, getClientApi } from "../client/api"; import { useAccessStore } from "../store"; +// Loading组件用于显示加载状态 export function Loading(props: { noLogo?: boolean }) { return ( + // 使用styles["loading-content"]类名来应用样式,"no-dark"类用于防止暗色主题影响
+ {/* 如果noLogo属性为false,则显示BotIcon */} {!props.noLogo && } + {/* 显示LoadingIcon表示正在加载 */}
); @@ -105,13 +109,17 @@ function useHtmlLang() { }, []); } +// 定义一个自定义Hook:useHasHydrated const useHasHydrated = () => { + // 使用useState初始化hasHydrated状态为false const [hasHydrated, setHasHydrated] = useState(false); + // 使用useEffect在组件挂载后将hasHydrated设置为true useEffect(() => { setHasHydrated(true); }, []); + // 返回hasHydrated的当前值 return hasHydrated; }; @@ -138,23 +146,31 @@ export function WindowContent(props: { children: React.ReactNode }) { ); } +// Screen 组件:负责渲染应用的主要内容 function Screen() { + // 获取应用配置 const config = useAppConfig(); + // 获取当前路由位置 const location = useLocation(); + // 判断当前路径是否为特定页面 const isArtifact = location.pathname.includes(Path.Artifacts); const isHome = location.pathname === Path.Home; const isAuth = location.pathname === Path.Auth; const isSd = location.pathname === Path.Sd; const isSdNew = location.pathname === Path.SdNew; + // 检查是否为移动屏幕 const isMobileScreen = useMobileScreen(); + // 决定是否使用紧凑边框 const shouldTightBorder = getClientConfig()?.isApp || (config.tightBorder && !isMobileScreen); + // 加载Google字体 useEffect(() => { loadAsyncGoogleFont(); }, []); + // 如果是Artifacts页面,渲染特定路由 if (isArtifact) { return ( @@ -162,13 +178,17 @@ function Screen() { ); } + + // 渲染主要内容的函数 const renderContent = () => { if (isAuth) return ; if (isSd) return ; if (isSdNew) return ; return ( <> + {/* 侧边栏 */} + {/* 主区域 */} } /> @@ -182,6 +202,7 @@ function Screen() { ); }; + // 返回最终的渲染结果 return (
{ + // 定义一个异步函数来获取模型 (async () => { + // 从API获取模型列表 const models = await api.llm.models(); + // 将获取到的模型合并到配置中 config.mergeModels(models); })(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -208,19 +236,26 @@ export function useLoadData() { } export function Home() { + // 切换主题 useSwitchTheme(); + // 加载数据 useLoadData(); + // 设置HTML语言 useHtmlLang(); useEffect(() => { + // 从构建时获取配置并打印日志 console.log("[Config] got config from build time", getClientConfig()); + // 获取访问权限 useAccessStore.getState().fetch(); }, []); + // 如果组件还未水合,显示加载中 if (!useHasHydrated()) { return ; } + // 渲染主要内容 return ( diff --git a/app/components/sidebar.tsx b/app/components/sidebar.tsx index 4ec0f8c84..43f6f2aa1 100644 --- a/app/components/sidebar.tsx +++ b/app/components/sidebar.tsx @@ -225,8 +225,8 @@ export function SideBar(props: { className?: string }) { {...props} > } >
diff --git a/app/utils.ts b/app/utils.ts index 2a2922907..f3b1d3337 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -157,11 +157,16 @@ export function selectOrCopy(el: HTMLElement, content: string) { return true; } +// 获取DOM元素的内容宽度 function getDomContentWidth(dom: HTMLElement) { + // 获取元素的计算样式 const style = window.getComputedStyle(dom); + // 计算左右内边距的总宽度 const paddingWidth = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight); + // 计算内容宽度:元素客户端宽度减去内边距宽度 const width = dom.clientWidth - paddingWidth; + // 返回计算得到的内容宽度 return width; } diff --git a/注意事项.md b/注意事项.md new file mode 100644 index 000000000..b769f8f23 --- /dev/null +++ b/注意事项.md @@ -0,0 +1,7 @@ +# 路由相关 + +- 此项目不是使用nextjs的app路由方式,而是使用react-router-dom 的路由方式, +- 定义路由的位置是在 `app/components/Home.tsx` 文件中 +- 根路由 renderContent +- WindowContent下的Routes包裹是切换路由 +- 路由映射是在 [text](app/constant.ts) 文件中定义的Path,如下: