This commit is contained in:
GH Action - Upstream Sync 2023-05-21 01:05:17 +00:00
commit 6b7b775b28
20 changed files with 452 additions and 276 deletions

View File

@ -55,10 +55,6 @@ export function auth(req: NextRequest) {
req.headers.set("Authorization", `Bearer ${apiKey}`); req.headers.set("Authorization", `Bearer ${apiKey}`);
} else { } else {
console.log("[Auth] admin did not provide an api key"); console.log("[Auth] admin did not provide an api key");
return {
error: serverConfig.baseUrl?.includes(OPENAI_URL),
msg: "admin did not provide an api key",
};
} }
} else { } else {
console.log("[Auth] use user api key"); console.log("[Auth] use user api key");

View File

@ -30,26 +30,30 @@ export async function requestOpenai(req: NextRequest) {
controller.abort(); controller.abort();
}, 10 * 60 * 1000); }, 10 * 60 * 1000);
const fetchUrl = `${baseUrl}/${openaiPath}`;
const fetchOptions: RequestInit = {
headers: {
"Content-Type": "application/json",
Authorization: authValue,
...(process.env.OPENAI_ORG_ID && {
"OpenAI-Organization": process.env.OPENAI_ORG_ID,
}),
},
cache: "no-store",
method: req.method,
body: req.body,
signal: controller.signal,
};
try { try {
return await fetch(`${baseUrl}/${openaiPath}`, { const res = await fetch(fetchUrl, fetchOptions);
headers: {
"Content-Type": "application/json", if (res.status === 401) {
Authorization: authValue, // to prevent browser prompt for credentials
...(process.env.OPENAI_ORG_ID && { res.headers.delete("www-authenticate");
"OpenAI-Organization": process.env.OPENAI_ORG_ID,
}),
},
cache: "no-store",
method: req.method,
body: req.body,
signal: controller.signal,
});
} catch (err: unknown) {
if (err instanceof Error && err.name === "AbortError") {
console.log("Fetch aborted");
} else {
throw err;
} }
return res;
} finally { } finally {
clearTimeout(timeoutId); clearTimeout(timeoutId);
} }

View File

@ -62,6 +62,7 @@ export function getHeaders() {
const accessStore = useAccessStore.getState(); const accessStore = useAccessStore.getState();
let headers: Record<string, string> = { let headers: Record<string, string> = {
"Content-Type": "application/json", "Content-Type": "application/json",
"x-requested-with": "XMLHttpRequest",
}; };
const makeBearer = (token: string) => `Bearer ${token.trim()}`; const makeBearer = (token: string) => `Bearer ${token.trim()}`;

View File

@ -28,6 +28,7 @@ export const ChatControllerPool = {
remove(sessionIndex: number, messageId: number) { remove(sessionIndex: number, messageId: number) {
const key = this.key(sessionIndex, messageId); const key = this.key(sessionIndex, messageId);
this.controllers[key]?.abort();
delete this.controllers[key]; delete this.controllers[key];
}, },

View File

@ -6,7 +6,7 @@ import Locale from "../../locales";
import { import {
EventStreamContentType, EventStreamContentType,
fetchEventSource, fetchEventSource,
} from "@microsoft/fetch-event-source"; } from "@fortaine/fetch-event-source";
import { prettyObject } from "@/app/utils/format"; import { prettyObject } from "@/app/utils/format";
export class ChatGPTApi implements LLMApi { export class ChatGPTApi implements LLMApi {
@ -145,6 +145,7 @@ export class ChatGPTApi implements LLMApi {
}, },
onerror(e) { onerror(e) {
options.onError?.(e); options.onError?.(e);
throw e;
}, },
openWhenHidden: true, openWhenHidden: true,
}); });

View File

@ -107,3 +107,70 @@
user-select: text; user-select: text;
} }
} }
.clear-context {
margin: 20px 0 0 0;
padding: 4px 0;
border-top: var(--border-in-light);
border-bottom: var(--border-in-light);
box-shadow: var(--card-shadow) inset;
display: flex;
justify-content: center;
align-items: center;
color: var(--black);
transition: all ease 0.3s;
cursor: pointer;
overflow: hidden;
position: relative;
font-size: 12px;
animation: slide-in ease 0.3s;
$linear: linear-gradient(
to right,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 1),
rgba(0, 0, 0, 0)
);
mask-image: $linear;
@mixin show {
transform: translateY(0);
position: relative;
transition: all ease 0.3s;
opacity: 1;
}
@mixin hide {
transform: translateY(-50%);
position: absolute;
transition: all ease 0.1s;
opacity: 0;
}
&-tips {
@include show;
opacity: 0.5;
}
&-revert-btn {
color: var(--primary);
@include hide;
}
&:hover {
opacity: 1;
border-color: var(--primary);
.clear-context-tips {
@include hide;
}
.clear-context-revert-btn {
@include show;
}
}
}

View File

@ -14,6 +14,8 @@ import MaskIcon from "../icons/mask.svg";
import MaxIcon from "../icons/max.svg"; import MaxIcon from "../icons/max.svg";
import MinIcon from "../icons/min.svg"; import MinIcon from "../icons/min.svg";
import ResetIcon from "../icons/reload.svg"; import ResetIcon from "../icons/reload.svg";
import BreakIcon from "../icons/break.svg";
import SettingsIcon from "../icons/chat-settings.svg";
import LightIcon from "../icons/light.svg"; import LightIcon from "../icons/light.svg";
import DarkIcon from "../icons/dark.svg"; import DarkIcon from "../icons/dark.svg";
@ -51,13 +53,14 @@ import { IconButton } from "./button";
import styles from "./home.module.scss"; import styles from "./home.module.scss";
import chatStyle from "./chat.module.scss"; import chatStyle from "./chat.module.scss";
import { ListItem, Modal, showModal } from "./ui-lib"; import { ListItem, Modal, showModal, showToast } from "./ui-lib";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { LAST_INPUT_KEY, Path, REQUEST_TIMEOUT_MS } from "../constant"; import { LAST_INPUT_KEY, Path, REQUEST_TIMEOUT_MS } from "../constant";
import { Avatar } from "./emoji"; import { Avatar } from "./emoji";
import { MaskAvatar, MaskConfig } from "./mask"; import { MaskAvatar, MaskConfig } from "./mask";
import { useMaskStore } from "../store/mask"; import { useMaskStore } from "../store/mask";
import { useCommand } from "../command"; import { useCommand } from "../command";
import { prettyObject } from "../utils/format";
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, { const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
loading: () => <LoadingIcon />, loading: () => <LoadingIcon />,
@ -118,9 +121,13 @@ export function SessionConfigModel(props: { onClose: () => void }) {
icon={<ResetIcon />} icon={<ResetIcon />}
bordered bordered
text={Locale.Chat.Config.Reset} text={Locale.Chat.Config.Reset}
onClick={() => onClick={() => {
confirm(Locale.Memory.ResetConfirm) && chatStore.resetSession() if (confirm(Locale.Memory.ResetConfirm)) {
} chatStore.updateCurrentSession(
(session) => (session.memoryPrompt = ""),
);
}
}}
/>, />,
<IconButton <IconButton
key="copy" key="copy"
@ -288,6 +295,28 @@ export function PromptHints(props: {
); );
} }
function ClearContextDivider() {
const chatStore = useChatStore();
return (
<div
className={chatStyle["clear-context"]}
onClick={() =>
chatStore.updateCurrentSession(
(session) => (session.clearContextIndex = -1),
)
}
>
<div className={chatStyle["clear-context-tips"]}>
{Locale.Context.Clear}
</div>
<div className={chatStyle["clear-context-revert-btn"]}>
{Locale.Context.Revert}
</div>
</div>
);
}
function useScrollToBottom() { function useScrollToBottom() {
// for auto-scroll // for auto-scroll
const scrollRef = useRef<HTMLDivElement>(null); const scrollRef = useRef<HTMLDivElement>(null);
@ -320,6 +349,7 @@ export function ChatActions(props: {
}) { }) {
const config = useAppConfig(); const config = useAppConfig();
const navigate = useNavigate(); const navigate = useNavigate();
const chatStore = useChatStore();
// switch themes // switch themes
const theme = config.theme; const theme = config.theme;
@ -358,7 +388,7 @@ export function ChatActions(props: {
className={`${chatStyle["chat-input-action"]} clickable`} className={`${chatStyle["chat-input-action"]} clickable`}
onClick={props.showPromptModal} onClick={props.showPromptModal}
> >
<BrainIcon /> <SettingsIcon />
</div> </div>
)} )}
@ -390,6 +420,22 @@ export function ChatActions(props: {
> >
<MaskIcon /> <MaskIcon />
</div> </div>
<div
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={() => {
chatStore.updateCurrentSession((session) => {
if (session.clearContextIndex === session.messages.length) {
session.clearContextIndex = -1;
} else {
session.clearContextIndex = session.messages.length;
session.memoryPrompt = ""; // will clear memory
}
});
}}
>
<BreakIcon />
</div>
</div> </div>
); );
} }
@ -496,13 +542,17 @@ export function Chat() {
const stopTiming = Date.now() - REQUEST_TIMEOUT_MS; const stopTiming = Date.now() - REQUEST_TIMEOUT_MS;
session.messages.forEach((m) => { session.messages.forEach((m) => {
// check if should stop all stale messages // check if should stop all stale messages
if (new Date(m.date).getTime() < stopTiming) { if (m.isError || new Date(m.date).getTime() < stopTiming) {
if (m.streaming) { if (m.streaming) {
m.streaming = false; m.streaming = false;
} }
if (m.content.length === 0) { if (m.content.length === 0) {
m.content = "No content in this message."; m.isError = true;
m.content = prettyObject({
error: true,
message: "empty response",
});
} }
} }
}); });
@ -580,7 +630,9 @@ export function Chat() {
inputRef.current?.focus(); inputRef.current?.focus();
}; };
const context: RenderMessage[] = session.mask.context.slice(); const context: RenderMessage[] = session.mask.hideContext
? []
: session.mask.context.slice();
const accessStore = useAccessStore(); const accessStore = useAccessStore();
@ -595,6 +647,12 @@ export function Chat() {
context.push(copiedHello); context.push(copiedHello);
} }
// clear context index = context length + index in messages
const clearContextIndex =
(session.clearContextIndex ?? -1) >= 0
? session.clearContextIndex! + context.length
: -1;
// preview messages // preview messages
const messages = context const messages = context
.concat(session.messages as RenderMessage[]) .concat(session.messages as RenderMessage[])
@ -729,86 +787,91 @@ export function Chat() {
!(message.preview || message.content.length === 0); !(message.preview || message.content.length === 0);
const showTyping = message.preview || message.streaming; const showTyping = message.preview || message.streaming;
const shouldShowClearContextDivider = i === clearContextIndex - 1;
return ( return (
<div <>
key={i} <div
className={ key={i}
isUser ? styles["chat-message-user"] : styles["chat-message"] className={
} isUser ? styles["chat-message-user"] : styles["chat-message"]
> }
<div className={styles["chat-message-container"]}> >
<div className={styles["chat-message-avatar"]}> <div className={styles["chat-message-container"]}>
{message.role === "user" ? ( <div className={styles["chat-message-avatar"]}>
<Avatar avatar={config.avatar} /> {message.role === "user" ? (
) : ( <Avatar avatar={config.avatar} />
<MaskAvatar mask={session.mask} /> ) : (
)} <MaskAvatar mask={session.mask} />
</div> )}
{showTyping && (
<div className={styles["chat-message-status"]}>
{Locale.Chat.Typing}
</div> </div>
)} {showTyping && (
<div className={styles["chat-message-item"]}> <div className={styles["chat-message-status"]}>
{showActions && ( {Locale.Chat.Typing}
<div className={styles["chat-message-top-actions"]}> </div>
{message.streaming ? ( )}
<div className={styles["chat-message-item"]}>
{showActions && (
<div className={styles["chat-message-top-actions"]}>
{message.streaming ? (
<div
className={styles["chat-message-top-action"]}
onClick={() => onUserStop(message.id ?? i)}
>
{Locale.Chat.Actions.Stop}
</div>
) : (
<>
<div
className={styles["chat-message-top-action"]}
onClick={() => onDelete(message.id ?? i)}
>
{Locale.Chat.Actions.Delete}
</div>
<div
className={styles["chat-message-top-action"]}
onClick={() => onResend(message.id ?? i)}
>
{Locale.Chat.Actions.Retry}
</div>
</>
)}
<div <div
className={styles["chat-message-top-action"]} className={styles["chat-message-top-action"]}
onClick={() => onUserStop(message.id ?? i)} onClick={() => copyToClipboard(message.content)}
> >
{Locale.Chat.Actions.Stop} {Locale.Chat.Actions.Copy}
</div> </div>
) : ( </div>
<> )}
<div <Markdown
className={styles["chat-message-top-action"]} content={message.content}
onClick={() => onDelete(message.id ?? i)} loading={
> (message.preview || message.content.length === 0) &&
{Locale.Chat.Actions.Delete} !isUser
</div> }
<div onContextMenu={(e) => onRightClick(e, message)}
className={styles["chat-message-top-action"]} onDoubleClickCapture={() => {
onClick={() => onResend(message.id ?? i)} if (!isMobileScreen) return;
> setUserInput(message.content);
{Locale.Chat.Actions.Retry} }}
</div> fontSize={fontSize}
</> parentRef={scrollRef}
)} defaultShow={i >= messages.length - 10}
/>
<div </div>
className={styles["chat-message-top-action"]} {!isUser && !message.preview && (
onClick={() => copyToClipboard(message.content)} <div className={styles["chat-message-actions"]}>
> <div className={styles["chat-message-action-date"]}>
{Locale.Chat.Actions.Copy} {message.date.toLocaleString()}
</div> </div>
</div> </div>
)} )}
<Markdown
content={message.content}
loading={
(message.preview || message.content.length === 0) &&
!isUser
}
onContextMenu={(e) => onRightClick(e, message)}
onDoubleClickCapture={() => {
if (!isMobileScreen) return;
setUserInput(message.content);
}}
fontSize={fontSize}
parentRef={scrollRef}
defaultShow={i >= messages.length - 10}
/>
</div> </div>
{!isUser && !message.preview && (
<div className={styles["chat-message-actions"]}>
<div className={styles["chat-message-action-date"]}>
{message.date.toLocaleString()}
</div>
</div>
)}
</div> </div>
</div> {shouldShowClearContextDivider && <ClearContextDivider />}
</>
); );
})} })}
</div> </div>

View File

@ -104,25 +104,41 @@ export function MaskConfig(props: {
></input> ></input>
</ListItem> </ListItem>
<ListItem <ListItem
title={Locale.Mask.Config.Sync.Title} title={Locale.Mask.Config.HideContext.Title}
subTitle={Locale.Mask.Config.Sync.SubTitle} subTitle={Locale.Mask.Config.HideContext.SubTitle}
> >
<input <input
type="checkbox" type="checkbox"
checked={props.mask.syncGlobalConfig} checked={props.mask.hideContext}
onChange={(e) => { onChange={(e) => {
if ( props.updateMask((mask) => {
e.currentTarget.checked && mask.hideContext = e.currentTarget.checked;
confirm(Locale.Mask.Config.Sync.Confirm) });
) {
props.updateMask((mask) => {
mask.syncGlobalConfig = e.currentTarget.checked;
mask.modelConfig = { ...globalConfig.modelConfig };
});
}
}} }}
></input> ></input>
</ListItem> </ListItem>
{props.shouldSyncFromGlobal ? (
<ListItem
title={Locale.Mask.Config.Sync.Title}
subTitle={Locale.Mask.Config.Sync.SubTitle}
>
<input
type="checkbox"
checked={props.mask.syncGlobalConfig}
onChange={(e) => {
if (
e.currentTarget.checked &&
confirm(Locale.Mask.Config.Sync.Confirm)
) {
props.updateMask((mask) => {
mask.syncGlobalConfig = e.currentTarget.checked;
mask.modelConfig = { ...globalConfig.modelConfig };
});
}
}}
></input>
</ListItem>
) : null}
</List> </List>
<List> <List>

View File

@ -54,13 +54,13 @@
.actions { .actions {
margin-top: 5vh; margin-top: 5vh;
margin-bottom: 5vh; margin-bottom: 2vh;
animation: slide-in ease 0.45s; animation: slide-in ease 0.45s;
display: flex; display: flex;
justify-content: center; justify-content: center;
font-size: 12px;
.more { .skip {
font-size: 12px;
margin-left: 10px; margin-left: 10px;
} }
} }
@ -68,16 +68,26 @@
.masks { .masks {
flex-grow: 1; flex-grow: 1;
width: 100%; width: 100%;
overflow: hidden; overflow: auto;
align-items: center; align-items: center;
padding-top: 20px; padding-top: 20px;
$linear: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 1),
rgba(0, 0, 0, 0)
);
-webkit-mask-image: $linear;
mask-image: $linear;
animation: slide-in ease 0.5s; animation: slide-in ease 0.5s;
.mask-row { .mask-row {
margin-bottom: 10px;
display: flex; display: flex;
justify-content: center; // justify-content: center;
margin-bottom: 10px;
@for $i from 1 to 10 { @for $i from 1 to 10 {
&:nth-child(#{$i * 2}) { &:nth-child(#{$i * 2}) {

View File

@ -27,32 +27,8 @@ function getIntersectionArea(aRect: DOMRect, bRect: DOMRect) {
} }
function MaskItem(props: { mask: Mask; onClick?: () => void }) { function MaskItem(props: { mask: Mask; onClick?: () => void }) {
const domRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const changeOpacity = () => {
const dom = domRef.current;
const parent = document.getElementById(SlotID.AppBody);
if (!parent || !dom) return;
const domRect = dom.getBoundingClientRect();
const parentRect = parent.getBoundingClientRect();
const intersectionArea = getIntersectionArea(domRect, parentRect);
const domArea = domRect.width * domRect.height;
const ratio = intersectionArea / domArea;
const opacity = ratio > 0.9 ? 1 : 0.4;
dom.style.opacity = opacity.toString();
};
setTimeout(changeOpacity, 30);
window.addEventListener("resize", changeOpacity);
return () => window.removeEventListener("resize", changeOpacity);
}, [domRef]);
return ( return (
<div className={styles["mask"]} ref={domRef} onClick={props.onClick}> <div className={styles["mask"]} onClick={props.onClick}>
<MaskAvatar mask={props.mask} /> <MaskAvatar mask={props.mask} />
<div className={styles["mask-name"] + " one-line"}>{props.mask.name}</div> <div className={styles["mask-name"] + " one-line"}>{props.mask.name}</div>
</div> </div>
@ -63,32 +39,38 @@ function useMaskGroup(masks: Mask[]) {
const [groups, setGroups] = useState<Mask[][]>([]); const [groups, setGroups] = useState<Mask[][]>([]);
useEffect(() => { useEffect(() => {
const appBody = document.getElementById(SlotID.AppBody); const computeGroup = () => {
if (!appBody || masks.length === 0) return; const appBody = document.getElementById(SlotID.AppBody);
if (!appBody || masks.length === 0) return;
const rect = appBody.getBoundingClientRect(); const rect = appBody.getBoundingClientRect();
const maxWidth = rect.width; const maxWidth = rect.width;
const maxHeight = rect.height * 0.6; const maxHeight = rect.height * 0.6;
const maskItemWidth = 120; const maskItemWidth = 120;
const maskItemHeight = 50; const maskItemHeight = 50;
const randomMask = () => masks[Math.floor(Math.random() * masks.length)]; const randomMask = () => masks[Math.floor(Math.random() * masks.length)];
let maskIndex = 0; let maskIndex = 0;
const nextMask = () => masks[maskIndex++ % masks.length]; const nextMask = () => masks[maskIndex++ % masks.length];
const rows = Math.ceil(maxHeight / maskItemHeight); const rows = Math.ceil(maxHeight / maskItemHeight);
const cols = Math.ceil(maxWidth / maskItemWidth); const cols = Math.ceil(maxWidth / maskItemWidth);
const newGroups = new Array(rows) const newGroups = new Array(rows)
.fill(0) .fill(0)
.map((_, _i) => .map((_, _i) =>
new Array(cols) new Array(cols)
.fill(0) .fill(0)
.map((_, j) => (j < 1 || j > cols - 2 ? randomMask() : nextMask())), .map((_, j) => (j < 1 || j > cols - 2 ? randomMask() : nextMask())),
); );
setGroups(newGroups); setGroups(newGroups);
};
computeGroup();
window.addEventListener("resize", computeGroup);
return () => window.removeEventListener("resize", computeGroup);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
@ -105,6 +87,8 @@ export function NewChat() {
const navigate = useNavigate(); const navigate = useNavigate();
const config = useAppConfig(); const config = useAppConfig();
const maskRef = useRef<HTMLDivElement>(null);
const { state } = useLocation(); const { state } = useLocation();
const startChat = (mask?: Mask) => { const startChat = (mask?: Mask) => {
@ -123,6 +107,13 @@ export function NewChat() {
}, },
}); });
useEffect(() => {
if (maskRef.current) {
maskRef.current.scrollLeft =
(maskRef.current.scrollWidth - maskRef.current.clientWidth) / 2;
}
}, [groups]);
return ( return (
<div className={styles["new-chat"]}> <div className={styles["new-chat"]}>
<div className={styles["mask-header"]}> <div className={styles["mask-header"]}>
@ -162,24 +153,24 @@ export function NewChat() {
<div className={styles["actions"]}> <div className={styles["actions"]}>
<IconButton <IconButton
text={Locale.NewChat.Skip}
onClick={() => startChat()}
icon={<LightningIcon />}
type="primary"
shadow
/>
<IconButton
className={styles["more"]}
text={Locale.NewChat.More} text={Locale.NewChat.More}
onClick={() => navigate(Path.Masks)} onClick={() => navigate(Path.Masks)}
icon={<EyeIcon />} icon={<EyeIcon />}
bordered bordered
shadow shadow
/> />
<IconButton
text={Locale.NewChat.Skip}
onClick={() => startChat()}
icon={<LightningIcon />}
type="primary"
shadow
className={styles["skip"]}
/>
</div> </div>
<div className={styles["masks"]}> <div className={styles["masks"]} ref={maskRef}>
{groups.map((masks, i) => ( {groups.map((masks, i) => (
<div key={i} className={styles["mask-row"]}> <div key={i} className={styles["mask-row"]}>
{masks.map((mask, index) => ( {masks.map((mask, index) => (

1
app/icons/break.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><g opacity="1" transform="translate(0 0) rotate(0)"><g opacity="1" transform="translate(1.0001220703125 2) rotate(0)"><path id="路径 1" style="fill:#333333; opacity:1;" d="M13.275,-0.27515c0.261,0.26101 0.3915,0.57606 0.3915,0.94515v10.66c0,0.36907 -0.1305,0.68413 -0.3915,0.9452c-0.261,0.261 -0.57603,0.3915 -0.9451,0.3915h-10.66002c-0.36909,0 -0.68415,-0.1305 -0.94516,-0.3915c-0.26101,-0.26107 -0.39151,-0.57613 -0.39151,-0.9452v-10.66c0,-0.3691 0.1305,-0.68415 0.39151,-0.94515c0.26101,-0.26101 0.57606,-0.39151 0.94516,-0.39151h10.66002c0.36907,0 0.6841,0.1305 0.9451,0.39151zM1.66655,11.33c0,0.0022 0.00111,0.0033 0.00333,0.0033h10.66002c0.0022,0 0.0033,-0.0011 0.0033,-0.0033v-10.66c0,-0.00222 -0.0011,-0.00333 -0.0033,-0.00333l-10.66002,0c-0.00222,0 -0.00333,0.00111 -0.00333,0.00333z"></path><path id="路径 2" style="fill:#333333; opacity:1;" d="M9.76327,7.50715c-0.02999,0.02563 -0.06201,0.04842 -0.09604,0.06837c-0.03403,0.01995 -0.06956,0.03674 -0.10658,0.05039c-0.03702,0.01364 -0.07495,0.02391 -0.11379,0.03082c-0.03885,0.00691 -0.07799,0.01035 -0.11744,0.0103c-0.03945,-0.00004 -0.07859,-0.00356 -0.11742,-0.01055c-0.03883,-0.00699 -0.07674,-0.01734 -0.11373,-0.03106c-0.03699,-0.01372 -0.07248,-0.03059 -0.10647,-0.05061c-0.03399,-0.02002 -0.06596,-0.04288 -0.0959,-0.06858l-1.89578,-1.62728l-1.89578,1.62728c-0.02993,0.0257 -0.0619,0.04856 -0.09589,0.06858c-0.03399,0.02002 -0.06949,0.03689 -0.10648,0.05061c-0.03699,0.01372 -0.07489,0.02407 -0.11372,0.03106c-0.03883,0.00699 -0.07797,0.01051 -0.11742,0.01055c-0.03945,0.00005 -0.0786,-0.00339 -0.11744,-0.0103c-0.03885,-0.00691 -0.07678,-0.01718 -0.11379,-0.03082c-0.03702,-0.01365 -0.07255,-0.03044 -0.10658,-0.05039c-0.03404,-0.01995 -0.06605,-0.04274 -0.09604,-0.06837l-1.90593,-1.629l-1.89671,1.62808c-0.06708,0.05758 -0.14263,0.10013 -0.22664,0.12766c-0.08401,0.02753 -0.17009,0.03793 -0.25824,0.03121c-0.08815,-0.00671 -0.17166,-0.03004 -0.25053,-0.06998c-0.07887,-0.03994 -0.14709,-0.09345 -0.20467,-0.16054c-0.02851,-0.03321 -0.05351,-0.06889 -0.07499,-0.10703c-0.02148,-0.03814 -0.03904,-0.07801 -0.05267,-0.11961c-0.01363,-0.04159 -0.02307,-0.08412 -0.02832,-0.12758c-0.00525,-0.04346 -0.00622,-0.08701 -0.00289,-0.13066c0.00333,-0.04365 0.01088,-0.08655 0.02266,-0.12871c0.01178,-0.04216 0.02755,-0.08277 0.04733,-0.12182c0.01978,-0.03905 0.04317,-0.07579 0.07019,-0.11024c0.02701,-0.03444 0.05713,-0.06592 0.09035,-0.09443l2.32999,-2c0.02994,-0.02569 0.06191,-0.04855 0.0959,-0.06857c0.03399,-0.02003 0.06948,-0.0369 0.10647,-0.05062c0.03699,-0.01372 0.0749,-0.02407 0.11373,-0.03106c0.03883,-0.00699 0.07797,-0.01051 0.11742,-0.01055c0.03945,-0.00004 0.0786,0.00339 0.11744,0.0103c0.03884,0.00691 0.07677,0.01718 0.11379,0.03082c0.03702,0.01365 0.07255,0.03044 0.10658,0.05039c0.03404,0.01995 0.06605,0.04274 0.09604,0.06837l1.90592,1.629l1.89671,-1.62808c0.02998,-0.02573 0.062,-0.04862 0.09605,-0.06866c0.03405,-0.02005 0.0696,-0.03693 0.10665,-0.05065c0.03705,-0.01372 0.07503,-0.02407 0.11392,-0.03104c0.03889,-0.00697 0.07809,-0.01045 0.1176,-0.01045c0.03951,0 0.07872,0.00348 0.11761,0.01045c0.03889,0.00697 0.07686,0.01732 0.11391,0.03104c0.03705,0.01372 0.0726,0.0306 0.10665,0.05065c0.03405,0.02004 0.06607,0.04293 0.09605,0.06866l1.89671,1.62808l1.90595,-1.629c0.03,-0.02563 0.062,-0.04842 0.096,-0.06837c0.03407,-0.01995 0.0696,-0.03674 0.1066,-0.05038c0.037,-0.01365 0.07493,-0.02392 0.1138,-0.03083c0.03887,-0.00691 0.078,-0.01034 0.1174,-0.0103c0.03947,0.00004 0.0786,0.00356 0.1174,0.01055c0.03887,0.00699 0.0768,0.01734 0.1138,0.03106c0.037,0.01372 0.07247,0.03059 0.1064,0.05062c0.034,0.02002 0.06597,0.04288 0.0959,0.06857l2.33,2c0.06713,0.05758 0.12067,0.12581 0.1606,0.20468c0.03993,0.07887 0.06327,0.16237 0.07,0.25052c0.00667,0.08815 -0.00377,0.17424 -0.0313,0.25825c-0.02747,0.08401 -0.07,0.15955 -0.1276,0.22663c-0.02853,0.03322 -0.06,0.06334 -0.0944,0.09035c-0.03447,0.02701 -0.07123,0.05041 -0.1103,0.07019c-0.03907,0.01977 -0.07967,0.03555 -0.1218,0.04733c-0.04213,0.01177 -0.08503,0.01932 -0.1287,0.02265c-0.04367,0.00333 -0.08723,0.00236 -0.1307,-0.00289c-0.04347,-0.00525 -0.086,-0.01469 -0.1276,-0.02832c-0.0416,-0.01363 -0.08147,-0.03118 -0.1196,-0.05267c-0.03813,-0.02148 -0.0738,-0.04648 -0.107,-0.07499l-1.8967,-1.62808z"></path></g><g opacity="1" transform="translate(0 0) rotate(0)"><mask id="bg-mask-0" fill="white"><use xlink:href="#path_0"></use></mask><g mask="url(#bg-mask-0)" ></g></g></g><defs><rect id="path_0" x="0" y="0" width="16" height="16" /></defs></svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -31,8 +31,8 @@ const cn = {
}, },
Send: "发送", Send: "发送",
Config: { Config: {
Reset: "重置默认", Reset: "清除记忆",
SaveAs: "存为面具", SaveAs: "存为面具",
}, },
}, },
Export: { Export: {
@ -47,8 +47,8 @@ const cn = {
EmptyContent: "对话内容过短,无需总结", EmptyContent: "对话内容过短,无需总结",
Send: "自动压缩聊天记录并作为上下文发送", Send: "自动压缩聊天记录并作为上下文发送",
Copy: "复制摘要", Copy: "复制摘要",
Reset: "重置对话", Reset: "[unused]",
ResetConfirm: "重置后将清空当前对话记录以及历史摘要,确认重置", ResetConfirm: "确认清空历史摘要",
}, },
Home: { Home: {
NewChat: "新的聊天", NewChat: "新的聊天",
@ -160,12 +160,11 @@ const cn = {
BotHello: "有什么可以帮你的吗", BotHello: "有什么可以帮你的吗",
Error: "出错了,稍后重试吧", Error: "出错了,稍后重试吧",
Prompt: { Prompt: {
History: (content: string) => History: (content: string) => "这是历史聊天总结作为前情提要:" + content,
"这是 ai 和用户的历史聊天总结作为前情提要:" + content,
Topic: Topic:
"使用四到五个字直接返回这句话的简要主题,不要解释、不要标点、不要语气词、不要多余文本,如果没有主题,请直接返回“闲聊”", "使用四到五个字直接返回这句话的简要主题,不要解释、不要标点、不要语气词、不要多余文本,如果没有主题,请直接返回“闲聊”",
Summarize: Summarize:
"简要总结一下你和用户的对话,用作后续的上下文提示 prompt控制在 200 字以内", "简要总结一下对话内容,用作后续的上下文提示 prompt控制在 200 字以内",
}, },
}, },
Copy: { Copy: {
@ -173,9 +172,11 @@ const cn = {
Failed: "复制失败,请赋予剪切板权限", Failed: "复制失败,请赋予剪切板权限",
}, },
Context: { Context: {
Toast: (x: any) => `已设置 ${x} 条前置上下文`, Toast: (x: any) => `包含 ${x} 条预设提示词`,
Edit: "当前对话设置", Edit: "当前对话设置",
Add: "新增预设对话", Add: "新增预设对话",
Clear: "上下文已清除",
Revert: "恢复上下文",
}, },
Plugin: { Plugin: {
Name: "插件", Name: "插件",
@ -210,6 +211,10 @@ const cn = {
SubTitle: "当前对话是否使用全局模型设置", SubTitle: "当前对话是否使用全局模型设置",
Confirm: "当前对话的自定义设置将会被自动覆盖,确认启用全局设置?", Confirm: "当前对话的自定义设置将会被自动覆盖,确认启用全局设置?",
}, },
HideContext: {
Title: "隐藏预设对话",
SubTitle: "隐藏后预设对话不会出现在聊天界面",
},
}, },
}, },
NewChat: { NewChat: {

View File

@ -163,12 +163,11 @@ const en: RequiredLocaleType = {
Error: "Something went wrong, please try again later.", Error: "Something went wrong, please try again later.",
Prompt: { Prompt: {
History: (content: string) => History: (content: string) =>
"This is a summary of the chat history between the AI and the user as a recap: " + "This is a summary of the chat history as a recap: " + content,
content,
Topic: Topic:
"Please generate a four to five word title summarizing our conversation without any lead-in, punctuation, quotation marks, periods, symbols, or additional text. Remove enclosing quotation marks.", "Please generate a four to five word title summarizing our conversation without any lead-in, punctuation, quotation marks, periods, symbols, or additional text. Remove enclosing quotation marks.",
Summarize: Summarize:
"Summarize our discussion briefly in 200 words or less to use as a prompt for future context.", "Summarize the discussion briefly in 200 words or less to use as a prompt for future context.",
}, },
}, },
Copy: { Copy: {
@ -179,6 +178,8 @@ const en: RequiredLocaleType = {
Toast: (x: any) => `With ${x} contextual prompts`, Toast: (x: any) => `With ${x} contextual prompts`,
Edit: "Contextual and Memory Prompts", Edit: "Contextual and Memory Prompts",
Add: "Add a Prompt", Add: "Add a Prompt",
Clear: "Context Cleared",
Revert: "Revert",
}, },
Plugin: { Plugin: {
Name: "Plugin", Name: "Plugin",
@ -213,15 +214,19 @@ const en: RequiredLocaleType = {
SubTitle: "Use global config in this chat", SubTitle: "Use global config in this chat",
Confirm: "Confirm to override custom config with global config?", Confirm: "Confirm to override custom config with global config?",
}, },
HideContext: {
Title: "Hide Context Prompts",
SubTitle: "Do not show in-context prompts in chat",
},
}, },
}, },
NewChat: { NewChat: {
Return: "Return", Return: "Return",
Skip: "Skip", Skip: "Just Start",
Title: "Pick a Mask", Title: "Pick a Mask",
SubTitle: "Chat with the Soul behind the Mask", SubTitle: "Chat with the Soul behind the Mask",
More: "Find More", More: "Find More",
NotShow: "Not Show Again", NotShow: "Never Show Again",
ConfirmNoShow: "Confirm to disableYou can enable it in settings later.", ConfirmNoShow: "Confirm to disableYou can enable it in settings later.",
}, },

View File

@ -5,7 +5,7 @@ import { trimTopic } from "../utils";
import Locale from "../locales"; import Locale from "../locales";
import { showToast } from "../components/ui-lib"; import { showToast } from "../components/ui-lib";
import { ModelType, useAppConfig } from "./config"; import { ModelType } from "./config";
import { createEmptyMask, Mask } from "./mask"; import { createEmptyMask, Mask } from "./mask";
import { StoreKey } from "../constant"; import { StoreKey } from "../constant";
import { api, RequestMessage } from "../client/api"; import { api, RequestMessage } from "../client/api";
@ -45,6 +45,7 @@ export interface ChatSession {
stat: ChatStat; stat: ChatStat;
lastUpdate: number; lastUpdate: number;
lastSummarizeIndex: number; lastSummarizeIndex: number;
clearContextIndex?: number;
mask: Mask; mask: Mask;
} }
@ -277,13 +278,17 @@ export const useChatStore = create<ChatStore>()(
config: { ...modelConfig, stream: true }, config: { ...modelConfig, stream: true },
onUpdate(message) { onUpdate(message) {
botMessage.streaming = true; botMessage.streaming = true;
botMessage.content = message; if (message) {
botMessage.content = message;
}
set(() => ({})); set(() => ({}));
}, },
onFinish(message) { onFinish(message) {
botMessage.streaming = false; botMessage.streaming = false;
botMessage.content = message; if (message) {
get().onNewMessage(botMessage); botMessage.content = message;
get().onNewMessage(botMessage);
}
ChatControllerPool.remove( ChatControllerPool.remove(
sessionIndex, sessionIndex,
botMessage.id ?? messageIndex, botMessage.id ?? messageIndex,
@ -292,12 +297,12 @@ export const useChatStore = create<ChatStore>()(
}, },
onError(error) { onError(error) {
const isAborted = error.message.includes("aborted"); const isAborted = error.message.includes("aborted");
if ( botMessage.content =
botMessage.content !== Locale.Error.Unauthorized && "\n\n" +
!isAborted prettyObject({
) { error: true,
botMessage.content += "\n\n" + prettyObject(error); message: error.message,
} });
botMessage.streaming = false; botMessage.streaming = false;
userMessage.isError = !isAborted; userMessage.isError = !isAborted;
botMessage.isError = !isAborted; botMessage.isError = !isAborted;
@ -308,7 +313,7 @@ export const useChatStore = create<ChatStore>()(
botMessage.id ?? messageIndex, botMessage.id ?? messageIndex,
); );
console.error("[Chat] error ", error); console.error("[Chat] failed ", error);
}, },
onController(controller) { onController(controller) {
// collect controller for stop/retry // collect controller for stop/retry
@ -337,7 +342,12 @@ export const useChatStore = create<ChatStore>()(
getMessagesWithMemory() { getMessagesWithMemory() {
const session = get().currentSession(); const session = get().currentSession();
const modelConfig = session.mask.modelConfig; const modelConfig = session.mask.modelConfig;
const messages = session.messages.filter((msg) => !msg.isError);
// wont send cleared context messages
const clearedContextMessages = session.messages.slice(
(session.clearContextIndex ?? -1) + 1,
);
const messages = clearedContextMessages.filter((msg) => !msg.isError);
const n = messages.length; const n = messages.length;
const context = session.mask.context.slice(); const context = session.mask.context.slice();
@ -358,17 +368,17 @@ export const useChatStore = create<ChatStore>()(
n - modelConfig.historyMessageCount, n - modelConfig.historyMessageCount,
); );
const longTermMemoryMessageIndex = session.lastSummarizeIndex; const longTermMemoryMessageIndex = session.lastSummarizeIndex;
const oldestIndex = Math.max( const mostRecentIndex = Math.max(
shortTermMemoryMessageIndex, shortTermMemoryMessageIndex,
longTermMemoryMessageIndex, longTermMemoryMessageIndex,
); );
const threshold = modelConfig.compressMessageLengthThreshold; const threshold = modelConfig.compressMessageLengthThreshold * 2;
// get recent messages as many as possible // get recent messages as many as possible
const reversedRecentMessages = []; const reversedRecentMessages = [];
for ( for (
let i = n - 1, count = 0; let i = n - 1, count = 0;
i >= oldestIndex && count < threshold; i >= mostRecentIndex && count < threshold;
i -= 1 i -= 1
) { ) {
const msg = messages[i]; const msg = messages[i];
@ -406,15 +416,15 @@ export const useChatStore = create<ChatStore>()(
const session = get().currentSession(); const session = get().currentSession();
// remove error messages if any // remove error messages if any
const cleanMessages = session.messages.filter((msg) => !msg.isError); const messages = session.messages;
// should summarize topic after chating more than 50 words // should summarize topic after chating more than 50 words
const SUMMARIZE_MIN_LEN = 50; const SUMMARIZE_MIN_LEN = 50;
if ( if (
session.topic === DEFAULT_TOPIC && session.topic === DEFAULT_TOPIC &&
countMessages(cleanMessages) >= SUMMARIZE_MIN_LEN countMessages(messages) >= SUMMARIZE_MIN_LEN
) { ) {
const topicMessages = cleanMessages.concat( const topicMessages = messages.concat(
createMessage({ createMessage({
role: "user", role: "user",
content: Locale.Store.Prompt.Topic, content: Locale.Store.Prompt.Topic,
@ -436,9 +446,13 @@ export const useChatStore = create<ChatStore>()(
} }
const modelConfig = session.mask.modelConfig; const modelConfig = session.mask.modelConfig;
let toBeSummarizedMsgs = cleanMessages.slice( const summarizeIndex = Math.max(
session.lastSummarizeIndex, session.lastSummarizeIndex,
session.clearContextIndex ?? 0,
); );
let toBeSummarizedMsgs = messages
.filter((msg) => !msg.isError)
.slice(summarizeIndex);
const historyMsgLength = countMessages(toBeSummarizedMsgs); const historyMsgLength = countMessages(toBeSummarizedMsgs);

View File

@ -73,7 +73,7 @@ export const ALL_MODELS = [
available: ENABLE_GPT4, available: ENABLE_GPT4,
}, },
{ {
name: "ext-davinci-002-render-sha-mobile", name: "text-davinci-002-render-sha-mobile",
available: true, available: true,
}, },
{ {
@ -106,13 +106,13 @@ export const ALL_MODELS = [
}, },
] as const; ] as const;
export type ModelType = typeof ALL_MODELS[number]["name"]; export type ModelType = (typeof ALL_MODELS)[number]["name"];
export function limitNumber( export function limitNumber(
x: number, x: number,
min: number, min: number,
max: number, max: number,
defaultValue: number defaultValue: number,
) { ) {
if (typeof x !== "number" || isNaN(x)) { if (typeof x !== "number" || isNaN(x)) {
return defaultValue; return defaultValue;
@ -171,6 +171,6 @@ export const useAppConfig = create<ChatConfigStore>()(
return state; return state;
}, },
} },
) ),
); );

View File

@ -10,6 +10,7 @@ export type Mask = {
id: number; id: number;
avatar: string; avatar: string;
name: string; name: string;
hideContext?: boolean;
context: ChatMessage[]; context: ChatMessage[];
syncGlobalConfig?: boolean; syncGlobalConfig?: boolean;
modelConfig: ModelConfig; modelConfig: ModelConfig;

View File

@ -1,8 +1,7 @@
export function prettyObject(msg: any) { export function prettyObject(msg: any) {
const prettyMsg = [ if (typeof msg !== "string") {
"```json\n", msg = JSON.stringify(msg, null, " ");
JSON.stringify(msg, null, " "), }
"\n```", const prettyMsg = ["```json", msg, "```"].join("\n");
].join("");
return prettyMsg; return prettyMsg;
} }

View File

@ -14,13 +14,13 @@
}, },
"dependencies": { "dependencies": {
"@hello-pangea/dnd": "^16.2.0", "@hello-pangea/dnd": "^16.2.0",
"@microsoft/fetch-event-source": "^2.0.1", "@fortaine/fetch-event-source": "^3.0.6",
"@svgr/webpack": "^6.5.1", "@svgr/webpack": "^6.5.1",
"@vercel/analytics": "^0.1.11", "@vercel/analytics": "^0.1.11",
"emoji-picker-react": "^4.4.7", "emoji-picker-react": "^4.4.7",
"fuse.js": "^6.6.2", "fuse.js": "^6.6.2",
"mermaid": "^10.1.0", "mermaid": "^10.1.0",
"next": "^13.4.2", "next": "^13.4.3",
"node-fetch": "^3.3.1", "node-fetch": "^3.3.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",

118
yarn.lock
View File

@ -1032,6 +1032,11 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.37.0.tgz#cf1b5fa24217fe007f6487a26d765274925efa7d" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.37.0.tgz#cf1b5fa24217fe007f6487a26d765274925efa7d"
integrity sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A== integrity sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==
"@fortaine/fetch-event-source@^3.0.6":
version "3.0.6"
resolved "https://registry.npmmirror.com/@fortaine/fetch-event-source/-/fetch-event-source-3.0.6.tgz#b8552a2ca2c5202f5699b93a92be0188d422b06e"
integrity sha512-621GAuLMvKtyZQ3IA6nlDWhV1V/7PGOTNIGLUifxt0KzM+dZIweJ6F3XvQF3QnqeNfS1N7WQ0Kil1Di/lhChEw==
"@hello-pangea/dnd@^16.2.0": "@hello-pangea/dnd@^16.2.0":
version "16.2.0" version "16.2.0"
resolved "https://registry.npmmirror.com/@hello-pangea/dnd/-/dnd-16.2.0.tgz#58cbadeb56f8c7a381da696bb7aa3bfbb87876ec" resolved "https://registry.npmmirror.com/@hello-pangea/dnd/-/dnd-16.2.0.tgz#58cbadeb56f8c7a381da696bb7aa3bfbb87876ec"
@ -1111,15 +1116,10 @@
dependencies: dependencies:
"@types/react" ">=16.0.0" "@types/react" ">=16.0.0"
"@microsoft/fetch-event-source@^2.0.1": "@next/env@13.4.3":
version "2.0.1" version "13.4.3"
resolved "https://registry.npmmirror.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d" resolved "https://registry.npmmirror.com/@next/env/-/env-13.4.3.tgz#cb00bdd43a0619a79a52c9336df8a0aa84f8f4bf"
integrity sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA== integrity sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==
"@next/env@13.4.2":
version "13.4.2"
resolved "https://registry.npmmirror.com/@next/env/-/env-13.4.2.tgz#cf3ebfd523a33d8404c1216e02ac8d856a73170e"
integrity sha512-Wqvo7lDeS0KGwtwg9TT9wKQ8raelmUxt+TQKWvG/xKfcmDXNOtCuaszcfCF8JzlBG1q0VhpI6CKaRMbVPMDWgw==
"@next/eslint-plugin-next@13.2.3": "@next/eslint-plugin-next@13.2.3":
version "13.2.3" version "13.2.3"
@ -1128,50 +1128,50 @@
dependencies: dependencies:
glob "7.1.7" glob "7.1.7"
"@next/swc-darwin-arm64@13.4.2": "@next/swc-darwin-arm64@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.2.tgz#d0b497df972bd02eee3bc823d6a76c2cc8b733ef" resolved "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz#2d6c99dd5afbcce37e4ba0f64196317a1259034d"
integrity sha512-6BBlqGu3ewgJflv9iLCwO1v1hqlecaIH2AotpKfVUEzUxuuDNJQZ2a4KLb4MBl8T9/vca1YuWhSqtbF6ZuUJJw== integrity sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==
"@next/swc-darwin-x64@13.4.2": "@next/swc-darwin-x64@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.2.tgz#09a800bed8dfe4beec4cbf14092f9c22db24470b" resolved "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz#162b15fb8a54d9f64e69c898ebeb55b7dac9bddd"
integrity sha512-iZuYr7ZvGLPjPmfhhMl0ISm+z8EiyLBC1bLyFwGBxkWmPXqdJ60mzuTaDSr5WezDwv0fz32HB7JHmRC6JVHSZg== integrity sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==
"@next/swc-linux-arm64-gnu@13.4.2": "@next/swc-linux-arm64-gnu@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.2.tgz#b7ade28834564120b0b25ffa0b79d75982d290bc" resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz#aee57422f11183d6a2e4a2e8aa23b9285873e18f"
integrity sha512-2xVabFtIge6BJTcJrW8YuUnYTuQjh4jEuRuS2mscyNVOj6zUZkom3CQg+egKOoS+zh2rrro66ffSKIS+ztFJTg== integrity sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==
"@next/swc-linux-arm64-musl@13.4.2": "@next/swc-linux-arm64-musl@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.2.tgz#f5420548234d35251630ddaa2e9a7dc32337a887" resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz#c10b6aaaa47b341c6c9ea15f8b0ddb37e255d035"
integrity sha512-wKRCQ27xCUJx5d6IivfjYGq8oVngqIhlhSAJntgXLt7Uo9sRT/3EppMHqUZRfyuNBTbykEre1s5166z+pvRB5A== integrity sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==
"@next/swc-linux-x64-gnu@13.4.2": "@next/swc-linux-x64-gnu@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.2.tgz#0241dc011d73f08df9d9998cffdfcf08d1971520" resolved "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz#3f85bc5591c6a0d4908404f7e88e3c04f4462039"
integrity sha512-NpCa+UVhhuNeaFVUP1Bftm0uqtvLWq2JTm7+Ta48+2Uqj2mNXrDIvyn1DY/ZEfmW/1yvGBRaUAv9zkMkMRixQA== integrity sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==
"@next/swc-linux-x64-musl@13.4.2": "@next/swc-linux-x64-musl@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.2.tgz#fd35919e2b64b1c739583145799fefd594ef5d63" resolved "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz#f4535adc2374a86bc8e43af149b551567df065de"
integrity sha512-ZWVC72x0lW4aj44e3khvBrj2oSYj1bD0jESmyah3zG/3DplEy/FOtYkMzbMjHTdDSheso7zH8GIlW6CDQnKhmQ== integrity sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==
"@next/swc-win32-arm64-msvc@13.4.2": "@next/swc-win32-arm64-msvc@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.2.tgz#fa95d2dbb97707c130a868a1bd7e83e64bedf4c6" resolved "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz#e76106d85391c308c5ed70cda2bca2c582d65536"
integrity sha512-pLT+OWYpzJig5K4VKhLttlIfBcVZfr2+Xbjra0Tjs83NQSkFS+y7xx+YhCwvpEmXYLIvaggj2ONPyjbiigOvHQ== integrity sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==
"@next/swc-win32-ia32-msvc@13.4.2": "@next/swc-win32-ia32-msvc@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.2.tgz#31a98e61d3cda92ec2293c50df7cb5280fc63697" resolved "https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz#8eb5d9dd71ed7a971671291605ad64ad522fb3bc"
integrity sha512-dhpiksQCyGca4WY0fJyzK3FxMDFoqMb0Cn+uDB+9GYjpU2K5//UGPQlCwiK4JHxuhg8oLMag5Nf3/IPSJNG8jw== integrity sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==
"@next/swc-win32-x64-msvc@13.4.2": "@next/swc-win32-x64-msvc@13.4.3":
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.2.tgz#8435ab6087046355f5de07122d3097949e8fab10" resolved "https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz#c7b2b1b9e158fd7749f8209e68ee8e43a997eb4c"
integrity sha512-O7bort1Vld00cu8g0jHZq3cbSTUNMohOEvYqsqE10+yfohhdPHzvzO+ziJRz4Dyyr/fYKREwS7gR4JC0soSOMw== integrity sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==
"@nodelib/fs.scandir@2.1.5": "@nodelib/fs.scandir@2.1.5":
version "2.1.5" version "2.1.5"
@ -4275,12 +4275,12 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
next@^13.4.2: next@^13.4.3:
version "13.4.2" version "13.4.3"
resolved "https://registry.npmmirror.com/next/-/next-13.4.2.tgz#972f73a794f2c61729facedc79c49b22bdc89f0c" resolved "https://registry.npmmirror.com/next/-/next-13.4.3.tgz#7f417dec9fa2731d8c1d1819a1c7d0919ad6fc75"
integrity sha512-aNFqLs3a3nTGvLWlO9SUhCuMUHVPSFQC0+tDNGAsDXqx+WJDFSbvc233gOJ5H19SBc7nw36A9LwQepOJ2u/8Kg== integrity sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==
dependencies: dependencies:
"@next/env" "13.4.2" "@next/env" "13.4.3"
"@swc/helpers" "0.5.1" "@swc/helpers" "0.5.1"
busboy "1.6.0" busboy "1.6.0"
caniuse-lite "^1.0.30001406" caniuse-lite "^1.0.30001406"
@ -4288,15 +4288,15 @@ next@^13.4.2:
styled-jsx "5.1.1" styled-jsx "5.1.1"
zod "3.21.4" zod "3.21.4"
optionalDependencies: optionalDependencies:
"@next/swc-darwin-arm64" "13.4.2" "@next/swc-darwin-arm64" "13.4.3"
"@next/swc-darwin-x64" "13.4.2" "@next/swc-darwin-x64" "13.4.3"
"@next/swc-linux-arm64-gnu" "13.4.2" "@next/swc-linux-arm64-gnu" "13.4.3"
"@next/swc-linux-arm64-musl" "13.4.2" "@next/swc-linux-arm64-musl" "13.4.3"
"@next/swc-linux-x64-gnu" "13.4.2" "@next/swc-linux-x64-gnu" "13.4.3"
"@next/swc-linux-x64-musl" "13.4.2" "@next/swc-linux-x64-musl" "13.4.3"
"@next/swc-win32-arm64-msvc" "13.4.2" "@next/swc-win32-arm64-msvc" "13.4.3"
"@next/swc-win32-ia32-msvc" "13.4.2" "@next/swc-win32-ia32-msvc" "13.4.3"
"@next/swc-win32-x64-msvc" "13.4.2" "@next/swc-win32-x64-msvc" "13.4.3"
node-domexception@^1.0.0: node-domexception@^1.0.0:
version "1.0.0" version "1.0.0"