Compare commits

..

66 Commits

Author SHA1 Message Date
GH Action - Upstream Sync
3ddbbbdc98 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-09-07 00:41:07 +00:00
GH Action - Upstream Sync
97368f54dd Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-09-05 00:41:50 +00:00
GH Action - Upstream Sync
f51a6a6b6e Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-30 00:41:30 +00:00
GH Action - Upstream Sync
488bf51b93 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-28 00:40:48 +00:00
GH Action - Upstream Sync
91b69c4fb7 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-25 00:43:53 +00:00
GH Action - Upstream Sync
3be687a28a Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-22 00:40:45 +00:00
GH Action - Upstream Sync
b2e364e6dd Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-21 00:39:36 +00:00
GH Action - Upstream Sync
c5ab4d80d1 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-20 00:39:42 +00:00
GH Action - Upstream Sync
b9702a7902 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-17 00:38:36 +00:00
E.da
09b56c9399 fix: CUSTOM_MODELS optional configuration -all,+xxx causes the custom model to be unusable
`CUSTOM_MODELS ` optional configuration ` -all,+xxx ` causes the custom model to be unusable
2024-08-16 10:50:09 +08:00
GH Action - Upstream Sync
4aae37b90c Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-16 00:39:26 +00:00
GH Action - Upstream Sync
2565f5a398 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-14 00:39:55 +00:00
GH Action - Upstream Sync
2c0a73049d Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-09 00:40:02 +00:00
GH Action - Upstream Sync
57a2ce222c Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-08 00:39:37 +00:00
GH Action - Upstream Sync
76eb67d7ac Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-07 00:39:54 +00:00
GH Action - Upstream Sync
b07af51649 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-06 00:39:22 +00:00
GH Action - Upstream Sync
735b8cd8b0 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-04 00:42:56 +00:00
GH Action - Upstream Sync
240058cd32 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-03 00:38:27 +00:00
GH Action - Upstream Sync
433c2f37bd Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-08-02 00:39:07 +00:00
GH Action - Upstream Sync
548e39eb82 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-31 00:32:12 +00:00
GH Action - Upstream Sync
84789c5f26 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-30 00:39:17 +00:00
GH Action - Upstream Sync
24ae8b2015 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-27 00:38:37 +00:00
GH Action - Upstream Sync
d6223e45a4 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-26 00:38:46 +00:00
GH Action - Upstream Sync
0a985fe891 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-23 00:39:22 +00:00
GH Action - Upstream Sync
33f63f3463 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-21 00:42:35 +00:00
GH Action - Upstream Sync
770c265567 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-20 00:38:03 +00:00
GH Action - Upstream Sync
89f1daa226 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-19 02:28:09 +00:00
GH Action - Upstream Sync
914c825725 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-18 00:38:19 +00:00
GH Action - Upstream Sync
d8b774ccfe Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-17 00:39:17 +00:00
GH Action - Upstream Sync
af5de8bdb6 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-16 00:39:21 +00:00
GH Action - Upstream Sync
397a7f56d4 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-14 00:42:50 +00:00
GH Action - Upstream Sync
15d9f82081 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-13 00:38:50 +00:00
GH Action - Upstream Sync
ec653812b9 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-12 00:38:18 +00:00
GH Action - Upstream Sync
8159ebe671 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-11 00:39:05 +00:00
GH Action - Upstream Sync
ccd22742f7 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-10 00:38:55 +00:00
GH Action - Upstream Sync
6b078392ee Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-07 00:42:05 +00:00
GH Action - Upstream Sync
741bd325d6 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-06 00:36:48 +00:00
GH Action - Upstream Sync
01b28f76e5 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-05 00:37:51 +00:00
GH Action - Upstream Sync
1e125b2fdd Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-04 00:38:06 +00:00
GH Action - Upstream Sync
9848ef22ec Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-07-02 00:38:00 +00:00
GH Action - Upstream Sync
7466c75534 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-06-27 00:37:44 +00:00
GH Action - Upstream Sync
3373db8fc7 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-06-25 00:37:18 +00:00
GH Action - Upstream Sync
18d7ec8a01 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-06-08 00:37:12 +00:00
GH Action - Upstream Sync
c6ed7720dc Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-28 00:36:26 +00:00
GH Action - Upstream Sync
724b35d7b5 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-23 00:35:53 +00:00
GH Action - Upstream Sync
1dd1a80f91 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-21 00:36:19 +00:00
GH Action - Upstream Sync
963cdceb83 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-17 00:36:04 +00:00
GH Action - Upstream Sync
90bb307486 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-16 00:35:30 +00:00
GH Action - Upstream Sync
c67b79785e Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-15 00:35:46 +00:00
GH Action - Upstream Sync
c3f91a89b9 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-14 00:35:42 +00:00
GH Action - Upstream Sync
9e4518d5ca Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-08 00:29:15 +00:00
GH Action - Upstream Sync
d3e801780e Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-07 00:35:08 +00:00
GH Action - Upstream Sync
783c314a46 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-05-01 00:37:47 +00:00
GH Action - Upstream Sync
eda303bb0f Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-26 00:34:42 +00:00
GH Action - Upstream Sync
ee1658e826 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-17 00:34:27 +00:00
GH Action - Upstream Sync
3f21cb5435 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-16 00:33:58 +00:00
GH Action - Upstream Sync
9a911fc146 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-15 02:54:48 +00:00
GH Action - Upstream Sync
fcf3de17a5 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-13 00:29:02 +00:00
GH Action - Upstream Sync
2729326131 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-12 00:34:32 +00:00
GH Action - Upstream Sync
f3dcf6ece0 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-11 00:34:42 +00:00
GH Action - Upstream Sync
3acd5fb986 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-10 00:33:53 +00:00
GH Action - Upstream Sync
c8a97db52e Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-09 00:34:26 +00:00
GH Action - Upstream Sync
8e8560417a Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-04-04 00:35:05 +00:00
GH Action - Upstream Sync
101c2602ae Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-03-29 00:33:41 +00:00
GH Action - Upstream Sync
1d8839ae74 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-03-28 00:33:48 +00:00
GH Action - Upstream Sync
3eb6235bf1 Merge branch 'main' of https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 2024-03-27 00:33:21 +00:00
26 changed files with 55 additions and 377 deletions

View File

@@ -13,9 +13,7 @@ function getModels(remoteModelRes: OpenAIListModelResponse) {
if (config.disableGPT4) {
remoteModelRes.data = remoteModelRes.data.filter(
(m) =>
!(m.id.startsWith("gpt-4") || m.id.startsWith("chatgpt-4o")) ||
m.id.startsWith("gpt-4o-mini"),
(m) => !m.id.startsWith("gpt-4") || m.id.startsWith("gpt-4o-mini"),
);
}

View File

@@ -203,7 +203,7 @@ export class ClaudeApi implements LLMApi {
const [tools, funcs] = usePluginStore
.getState()
.getAsTools(
useChatStore.getState().currentSession().mask?.plugin || [],
useChatStore.getState().currentSession().mask?.plugin as string[],
);
return stream(
path,

View File

@@ -125,7 +125,7 @@ export class MoonshotApi implements LLMApi {
const [tools, funcs] = usePluginStore
.getState()
.getAsTools(
useChatStore.getState().currentSession().mask?.plugin || [],
useChatStore.getState().currentSession().mask?.plugin as string[],
);
return stream(
chatPath,

View File

@@ -160,7 +160,6 @@ export class ChatGPTApi implements LLMApi {
let requestPayload: RequestPayload | DalleRequestPayload;
const isDalle3 = _isDalle3(options.config.model);
const isO1 = options.config.model.startsWith("o1");
if (isDalle3) {
const prompt = getMessageTextContent(
options.messages.slice(-1)?.pop() as any,
@@ -182,32 +181,30 @@ export class ChatGPTApi implements LLMApi {
const content = visionModel
? await preProcessImageContent(v.content)
: getMessageTextContent(v);
if (!(isO1 && v.role === "system"))
messages.push({ role: v.role, content });
messages.push({ role: v.role, content });
}
// O1 not support image, tools (plugin in ChatGPTNextWeb) and system, stream, logprobs, temperature, top_p, n, presence_penalty, frequency_penalty yet.
requestPayload = {
messages,
stream: !isO1 ? options.config.stream : false,
stream: options.config.stream,
model: modelConfig.model,
temperature: !isO1 ? modelConfig.temperature : 1,
presence_penalty: !isO1 ? modelConfig.presence_penalty : 0,
frequency_penalty: !isO1 ? modelConfig.frequency_penalty : 0,
top_p: !isO1 ? modelConfig.top_p : 1,
temperature: modelConfig.temperature,
presence_penalty: modelConfig.presence_penalty,
frequency_penalty: modelConfig.frequency_penalty,
top_p: modelConfig.top_p,
// max_tokens: Math.max(modelConfig.max_tokens, 1024),
// Please do not ask me why not send max_tokens, no reason, this param is just shit, I dont want to explain anymore.
};
// add max_tokens to vision model
if (visionModel) {
if (visionModel && modelConfig.model.includes("preview")) {
requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000);
}
}
console.log("[Request] openai payload: ", requestPayload);
const shouldStream = !isDalle3 && !!options.config.stream && !isO1;
const shouldStream = !isDalle3 && !!options.config.stream;
const controller = new AbortController();
options.onController?.(controller);
@@ -247,7 +244,7 @@ export class ChatGPTApi implements LLMApi {
const [tools, funcs] = usePluginStore
.getState()
.getAsTools(
useChatStore.getState().currentSession().mask?.plugin || [],
useChatStore.getState().currentSession().mask?.plugin as string[],
);
// console.log("getAsTools", tools, funcs);
stream(
@@ -316,7 +313,7 @@ export class ChatGPTApi implements LLMApi {
// make a fetch request
const requestTimeoutId = setTimeout(
() => controller.abort(),
isDalle3 || isO1 ? REQUEST_TIMEOUT_MS * 2 : REQUEST_TIMEOUT_MS, // dalle3 using b64_json is slow.
isDalle3 ? REQUEST_TIMEOUT_MS * 2 : REQUEST_TIMEOUT_MS, // dalle3 using b64_json is slow.
);
const res = await fetch(chatPath, chatPayload);
@@ -410,9 +407,7 @@ export class ChatGPTApi implements LLMApi {
});
const resJson = (await res.json()) as OpenAIListModelResponse;
const chatModels = resJson.data?.filter(
(m) => m.id.startsWith("gpt-") || m.id.startsWith("chatgpt-"),
);
const chatModels = resJson.data?.filter((m) => m.id.startsWith("gpt-"));
console.log("[Models]", chatModels);
if (!chatModels) {

View File

@@ -80,7 +80,7 @@ export const HTMLPreview = forwardRef<HTMLPreviewHander, HTMLPreviewProps>(
}, [props.autoHeight, props.height, iframeHeight]);
const srcDoc = useMemo(() => {
const script = `<script>window.addEventListener("DOMContentLoaded", () => new ResizeObserver((entries) => parent.postMessage({id: '${frameId}', height: entries[0].target.clientHeight}, '*')).observe(document.body))</script>`;
const script = `<script>new ResizeObserver((entries) => parent.postMessage({id: '${frameId}', height: entries[0].target.clientHeight}, '*')).observe(document.body)</script>`;
if (props.code.includes("<!DOCTYPE html>")) {
props.code.replace("<!DOCTYPE html>", "<!DOCTYPE html>" + script);
}

View File

@@ -646,51 +646,3 @@
bottom: 30px;
}
}
.shortcut-key-container {
padding: 10px;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.shortcut-key-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 16px;
}
.shortcut-key-item {
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 10px;
background-color: var(--white);
}
.shortcut-key-title {
font-size: 14px;
color: var(--black);
}
.shortcut-key-keys {
display: flex;
gap: 8px;
}
.shortcut-key {
display: flex;
align-items: center;
justify-content: center;
border: var(--border-in-light);
border-radius: 8px;
padding: 4px;
background-color: var(--gray);
min-width: 32px;
}
.shortcut-key span {
font-size: 12px;
color: var(--black);
}

View File

@@ -42,7 +42,6 @@ import SizeIcon from "../icons/size.svg";
import QualityIcon from "../icons/hd.svg";
import StyleIcon from "../icons/palette.svg";
import PluginIcon from "../icons/plugin.svg";
import ShortcutkeyIcon from "../icons/shortcutkey.svg";
import {
ChatMessage,
@@ -68,7 +67,6 @@ import {
isVisionModel,
isDalle3,
showPlugins,
safeLocalStorage,
} from "../utils";
import { uploadImage as uploadImageRemote } from "@/app/utils/chat";
@@ -111,8 +109,6 @@ import { getClientConfig } from "../config/client";
import { useAllModels } from "../utils/hooks";
import { MultimodalContent } from "../client/api";
const localStorage = safeLocalStorage();
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
loading: () => <LoadingIcon />,
});
@@ -192,7 +188,7 @@ function PromptToast(props: {
return (
<div className={styles["prompt-toast"]} key="prompt-toast">
{props.showToast && context.length > 0 && (
{props.showToast && (
<div
className={styles["prompt-toast-inner"] + " clickable"}
role="button"
@@ -441,7 +437,6 @@ export function ChatActions(props: {
showPromptHints: () => void;
hitBottom: boolean;
uploading: boolean;
setShowShortcutKeyModal: React.Dispatch<React.SetStateAction<boolean>>;
}) {
const config = useAppConfig();
const navigate = useNavigate();
@@ -507,8 +502,6 @@ export function ChatActions(props: {
const currentStyle =
chatStore.currentSession().mask.modelConfig?.style ?? "vivid";
const isMobileScreen = useMobileScreen();
useEffect(() => {
const show = isVisionModel(currentModel);
setShowUploadImage(show);
@@ -762,14 +755,6 @@ export function ChatActions(props: {
}}
/>
)}
{!isMobileScreen && (
<ChatAction
onClick={() => props.setShowShortcutKeyModal(true)}
text={Locale.Chat.ShortcutKey.Title}
icon={<ShortcutkeyIcon />}
/>
)}
</div>
);
}
@@ -844,67 +829,6 @@ export function DeleteImageButton(props: { deleteImage: () => void }) {
);
}
export function ShortcutKeyModal(props: { onClose: () => void }) {
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
const shortcuts = [
{
title: Locale.Chat.ShortcutKey.newChat,
keys: isMac ? ["⌘", "Shift", "O"] : ["Ctrl", "Shift", "O"],
},
{ title: Locale.Chat.ShortcutKey.focusInput, keys: ["Shift", "Esc"] },
{
title: Locale.Chat.ShortcutKey.copyLastCode,
keys: isMac ? ["⌘", "Shift", ";"] : ["Ctrl", "Shift", ";"],
},
{
title: Locale.Chat.ShortcutKey.copyLastMessage,
keys: isMac ? ["⌘", "Shift", "C"] : ["Ctrl", "Shift", "C"],
},
{
title: Locale.Chat.ShortcutKey.showShortcutKey,
keys: isMac ? ["⌘", "/"] : ["Ctrl", "/"],
},
];
return (
<div className="modal-mask">
<Modal
title={Locale.Chat.ShortcutKey.Title}
onClose={props.onClose}
actions={[
<IconButton
type="primary"
text={Locale.UI.Confirm}
icon={<ConfirmIcon />}
key="ok"
onClick={() => {
props.onClose();
}}
/>,
]}
>
<div className={styles["shortcut-key-container"]}>
<div className={styles["shortcut-key-grid"]}>
{shortcuts.map((shortcut, index) => (
<div key={index} className={styles["shortcut-key-item"]}>
<div className={styles["shortcut-key-title"]}>
{shortcut.title}
</div>
<div className={styles["shortcut-key-keys"]}>
{shortcut.keys.map((key, i) => (
<div key={i} className={styles["shortcut-key"]}>
<span>{key}</span>
</div>
))}
</div>
</div>
))}
</div>
</div>
</Modal>
</div>
);
}
function _Chat() {
type RenderMessage = ChatMessage & { preview?: boolean };
@@ -1017,7 +941,7 @@ function _Chat() {
.onUserInput(userInput, attachImages)
.then(() => setIsLoading(false));
setAttachImages([]);
chatStore.setLastInput(userInput);
localStorage.setItem(LAST_INPUT_KEY, userInput);
setUserInput("");
setPromptHints([]);
if (!isMobileScreen) inputRef.current?.focus();
@@ -1083,7 +1007,7 @@ function _Chat() {
userInput.length <= 0 &&
!(e.metaKey || e.altKey || e.ctrlKey)
) {
setUserInput(chatStore.lastInput ?? "");
setUserInput(localStorage.getItem(LAST_INPUT_KEY) ?? "");
e.preventDefault();
return;
}
@@ -1449,70 +1373,6 @@ function _Chat() {
setAttachImages(images);
}
// 快捷键 shortcut keys
const [showShortcutKeyModal, setShowShortcutKeyModal] = useState(false);
useEffect(() => {
const handleKeyDown = (event: any) => {
// 打开新聊天 command + shift + o
if (
(event.metaKey || event.ctrlKey) &&
event.shiftKey &&
event.key.toLowerCase() === "o"
) {
event.preventDefault();
setTimeout(() => {
chatStore.newSession();
navigate(Path.Chat);
}, 10);
}
// 聚焦聊天输入 shift + esc
else if (event.shiftKey && event.key.toLowerCase() === "escape") {
event.preventDefault();
inputRef.current?.focus();
}
// 复制最后一个代码块 command + shift + ;
else if (
(event.metaKey || event.ctrlKey) &&
event.shiftKey &&
event.code === "Semicolon"
) {
event.preventDefault();
const copyCodeButton =
document.querySelectorAll<HTMLElement>(".copy-code-button");
if (copyCodeButton.length > 0) {
copyCodeButton[copyCodeButton.length - 1].click();
}
}
// 复制最后一个回复 command + shift + c
else if (
(event.metaKey || event.ctrlKey) &&
event.shiftKey &&
event.key.toLowerCase() === "c"
) {
event.preventDefault();
const lastNonUserMessage = messages
.filter((message) => message.role !== "user")
.pop();
if (lastNonUserMessage) {
const lastMessageContent = getMessageTextContent(lastNonUserMessage);
copyToClipboard(lastMessageContent);
}
}
// 展示快捷键 command + /
else if ((event.metaKey || event.ctrlKey) && event.key === "/") {
event.preventDefault();
setShowShortcutKeyModal(true);
}
};
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [messages, chatStore, navigate]);
return (
<div className={styles.chat} key={session.id}>
<div className="window-header" data-tauri-drag-region>
@@ -1829,7 +1689,6 @@ function _Chat() {
setUserInput("/");
onSearch("");
}}
setShowShortcutKeyModal={setShowShortcutKeyModal}
/>
<label
className={`${styles["chat-input-panel-inner"]} ${
@@ -1901,10 +1760,6 @@ function _Chat() {
}}
/>
)}
{showShortcutKeyModal && (
<ShortcutKeyModal onClose={() => setShowShortcutKeyModal(false)} />
)}
</div>
);
}

View File

@@ -36,8 +36,7 @@ export function Avatar(props: { model?: ModelType; avatar?: string }) {
if (props.model) {
return (
<div className="no-dark">
{props.model?.startsWith("gpt-4") ||
props.model?.startsWith("chatgpt-4o") ? (
{props.model?.startsWith("gpt-4") ? (
<BlackBotIcon className="user-avatar" />
) : (
<BotIcon className="user-avatar" />

View File

@@ -8,7 +8,6 @@ import { ISSUE_URL } from "../constant";
import Locale from "../locales";
import { showConfirm } from "./ui-lib";
import { useSyncStore } from "../store/sync";
import { useChatStore } from "../store/chat";
interface IErrorBoundaryState {
hasError: boolean;
@@ -31,7 +30,8 @@ export class ErrorBoundary extends React.Component<any, IErrorBoundaryState> {
try {
useSyncStore.getState().export();
} finally {
useChatStore.getState().clearAllData();
localStorage.clear();
location.reload();
}
}

View File

@@ -163,7 +163,7 @@ export function PreCode(props: { children: any }) {
);
}
function CustomCode(props: { children: any; className?: string }) {
function CustomCode(props: { children: any }) {
const ref = useRef<HTMLPreElement>(null);
const [collapsed, setCollapsed] = useState(true);
const [showToggle, setShowToggle] = useState(false);
@@ -182,7 +182,6 @@ function CustomCode(props: { children: any; className?: string }) {
return (
<>
<code
className={props?.className}
ref={ref}
style={{
maxHeight: collapsed ? "400px" : "none",
@@ -237,26 +236,9 @@ function escapeBrackets(text: string) {
);
}
function tryWrapHtmlCode(text: string) {
// try add wrap html code (fixed: html codeblock include 2 newline)
return text
.replace(
/([`]*?)(\w*?)([\n\r]*?)(<!DOCTYPE html>)/g,
(match, quoteStart, lang, newLine, doctype) => {
return !quoteStart ? "\n```html\n" + doctype : match;
},
)
.replace(
/(<\/body>)([\r\n\s]*?)(<\/html>)([\n\r]*?)([`]*?)([\n\r]*?)/g,
(match, bodyEnd, space, htmlEnd, newLine, quoteEnd) => {
return !quoteEnd ? bodyEnd + space + htmlEnd + "\n```\n" : match;
},
);
}
function _MarkDownContent(props: { content: string }) {
const escapedContent = useMemo(() => {
return tryWrapHtmlCode(escapeBrackets(escapeDollarNumber(props.content)));
return escapeBrackets(escapeDollarNumber(props.content));
}, [props.content]);
return (

View File

@@ -426,7 +426,16 @@ export function MaskPage() {
const maskStore = useMaskStore();
const chatStore = useChatStore();
const filterLang = maskStore.language;
const [filterLang, setFilterLang] = useState<Lang | undefined>(
() => localStorage.getItem("Mask-language") as Lang | undefined,
);
useEffect(() => {
if (filterLang) {
localStorage.setItem("Mask-language", filterLang);
} else {
localStorage.removeItem("Mask-language");
}
}, [filterLang]);
const allMasks = maskStore
.getAll()
@@ -533,9 +542,9 @@ export function MaskPage() {
onChange={(e) => {
const value = e.currentTarget.value;
if (value === Locale.Settings.Lang.All) {
maskStore.setLanguage(undefined);
setFilterLang(undefined);
} else {
maskStore.setLanguage(value as Lang);
setFilterLang(value as Lang);
}
}}
>

View File

@@ -120,15 +120,12 @@ export const getServerSideConfig = () => {
if (disableGPT4) {
if (customModels) customModels += ",";
customModels += DEFAULT_MODELS.filter(
(m) =>
(m.name.startsWith("gpt-4") || m.name.startsWith("chatgpt-4o")) &&
!m.name.startsWith("gpt-4o-mini"),
(m) => m.name.startsWith("gpt-4") && !m.name.startsWith("gpt-4o-mini"),
)
.map((m) => "-" + m.name)
.join(",");
if (
(defaultModel.startsWith("gpt-4") ||
defaultModel.startsWith("chatgpt-4o")) &&
defaultModel.startsWith("gpt-4") &&
!defaultModel.startsWith("gpt-4o-mini")
)
defaultModel = "";

View File

@@ -246,12 +246,9 @@ export const KnowledgeCutOffDate: Record<string, string> = {
"gpt-4o": "2023-10",
"gpt-4o-2024-05-13": "2023-10",
"gpt-4o-2024-08-06": "2023-10",
"chatgpt-4o-latest": "2023-10",
"gpt-4o-mini": "2023-10",
"gpt-4o-mini-2024-07-18": "2023-10",
"gpt-4-vision-preview": "2023-04",
"o1-mini": "2023-10",
"o1-preview": "2023-10",
// After improvements,
// it's now easier to add "KnowledgeCutOffDate" instead of stupid hardcoding it, as was done previously.
"gemini-pro": "2023-12",
@@ -271,15 +268,12 @@ const openaiModels = [
"gpt-4o",
"gpt-4o-2024-05-13",
"gpt-4o-2024-08-06",
"chatgpt-4o-latest",
"gpt-4o-mini",
"gpt-4o-mini-2024-07-18",
"gpt-4-vision-preview",
"gpt-4-turbo-2024-04-09",
"gpt-4-1106-preview",
"dall-e-3",
"o1-mini",
"o1-preview"
];
const googleModels = [

View File

@@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M42 7H6C4.89543 7 4 7.89543 4 9V37C4 38.1046 4.89543 39 6 39H42C43.1046 39 44 38.1046 44 37V9C44 7.89543 43.1046 7 42 7Z" fill="none" stroke="#000" stroke-width="3" stroke-linejoin="round"/><path d="M12 19H14" stroke="#000" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M21 19H23" stroke="#000" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M29 19H36" stroke="#000" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 28H36" stroke="#000" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>

Before

Width:  |  Height:  |  Size: 734 B

View File

@@ -41,7 +41,7 @@ export default function RootLayout({
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link rel="manifest" href="/site.webmanifest" crossOrigin="use-credentials"></link>
<link rel="manifest" href="/site.webmanifest"></link>
<script src="/serviceWorkerRegister.js" defer></script>
</head>
<body>

View File

@@ -1,4 +1,3 @@
import { ShortcutKeyModal } from "../components/chat";
import { getClientConfig } from "../config/client";
import { SubmitKey } from "../store/config";
@@ -82,14 +81,6 @@ const cn = {
SaveAs: "存为面具",
},
IsContext: "预设提示词",
ShortcutKey: {
Title: "键盘快捷方式",
newChat: "打开新聊天",
focusInput: "聚焦输入框",
copyLastMessage: "复制最后一个回复",
copyLastCode: "复制最后一个代码块",
showShortcutKey: "显示快捷方式",
},
},
Export: {
Title: "分享聊天记录",
@@ -504,8 +495,8 @@ const cn = {
},
},
Copy: {
Success: "已写入剪板",
Failed: "复制失败,请赋予剪板权限",
Success: "已写入剪板",
Failed: "复制失败,请赋予剪板权限",
},
Download: {
Success: "内容已下载到您的目录。",

View File

@@ -83,14 +83,6 @@ const en: LocaleType = {
SaveAs: "Save as Mask",
},
IsContext: "Contextual Prompt",
ShortcutKey: {
Title: "Keyboard Shortcuts",
newChat: "Open New Chat",
focusInput: "Focus Input Field",
copyLastMessage: "Copy Last Reply",
copyLastCode: "Copy Last Code Block",
showShortcutKey: "Show Shortcuts",
},
},
Export: {
Title: "Export Messages",

View File

@@ -18,13 +18,10 @@ import ar from "./ar";
import bn from "./bn";
import sk from "./sk";
import { merge } from "../utils/merge";
import { safeLocalStorage } from "@/app/utils";
import type { LocaleType } from "./cn";
export type { LocaleType, PartialLocaleType } from "./cn";
const localStorage = safeLocalStorage();
const ALL_LANGS = {
cn,
en,
@@ -85,11 +82,17 @@ merge(fallbackLang, targetLang);
export default fallbackLang as LocaleType;
function getItem(key: string) {
return localStorage.getItem(key);
try {
return localStorage.getItem(key);
} catch {
return null;
}
}
function setItem(key: string, value: string) {
localStorage.setItem(key, value);
try {
localStorage.setItem(key, value);
} catch {}
}
function getLanguage() {

View File

@@ -81,14 +81,6 @@ const tw = {
SaveAs: "另存新檔",
},
IsContext: "預設提示詞",
ShortcutKey: {
Title: "鍵盤快捷方式",
newChat: "打開新聊天",
focusInput: "聚焦輸入框",
copyLastMessage: "複製最後一個回覆",
copyLastCode: "複製最後一個代碼塊",
showShortcutKey: "顯示快捷方式",
},
},
Export: {
Title: "將聊天記錄匯出為 Markdown",

View File

@@ -26,11 +26,9 @@ import { nanoid } from "nanoid";
import { createPersistStore } from "../utils/store";
import { collectModelsWithDefaultModel } from "../utils/model";
import { useAccessStore } from "./access";
import { isDalle3, safeLocalStorage } from "../utils";
import { isDalle3 } from "../utils";
import { indexedDBStorage } from "@/app/utils/indexedDB-storage";
const localStorage = safeLocalStorage();
export type ChatMessageTool = {
id: string;
index?: number;
@@ -108,7 +106,7 @@ function createEmptySession(): ChatSession {
function getSummarizeModel(currentModel: string) {
// if it is using gpt-* models, force to use 4o-mini to summarize
if (currentModel.startsWith("gpt") || currentModel.startsWith("chatgpt")) {
if (currentModel.startsWith("gpt")) {
const configStore = useAppConfig.getState();
const accessStore = useAccessStore.getState();
const allModel = collectModelsWithDefaultModel(
@@ -181,7 +179,6 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
const DEFAULT_CHAT_STATE = {
sessions: [createEmptySession()],
currentSessionIndex: 0,
lastInput: "",
};
export const useChatStore = createPersistStore(
@@ -479,8 +476,7 @@ export const useChatStore = createPersistStore(
// system prompts, to get close to OpenAI Web ChatGPT
const shouldInjectSystemPrompts =
modelConfig.enableInjectSystemPrompts &&
(session.mask.modelConfig.model.startsWith("gpt-") ||
session.mask.modelConfig.model.startsWith("chatgpt-"));
session.mask.modelConfig.model.startsWith("gpt-");
var systemPrompts: ChatMessage[] = [];
systemPrompts = shouldInjectSystemPrompts
@@ -704,11 +700,6 @@ export const useChatStore = createPersistStore(
localStorage.clear();
location.reload();
},
setLastInput(lastInput: string) {
set({
lastInput,
});
},
};
return methods;

View File

@@ -23,12 +23,9 @@ export type Mask = {
export const DEFAULT_MASK_STATE = {
masks: {} as Record<string, Mask>,
language: undefined as Lang | undefined,
};
export type MaskState = typeof DEFAULT_MASK_STATE & {
language?: Lang | undefined;
};
export type MaskState = typeof DEFAULT_MASK_STATE;
export const DEFAULT_MASK_AVATAR = "gpt-bot";
export const createEmptyMask = () =>
@@ -105,11 +102,6 @@ export const useMaskStore = createPersistStore(
search(text: string) {
return Object.values(get().masks);
},
setLanguage(language: Lang | undefined) {
set({
language,
});
},
}),
{
name: StoreKey.Mask,

View File

@@ -199,7 +199,7 @@ export const usePluginStore = createPersistStore(
getAsTools(ids: string[]) {
const plugins = get().plugins;
const selected = (ids || [])
const selected = ids
.map((id) => plugins[id])
.filter((i) => i)
.map((p) => FunctionToolService.add(p));

View File

@@ -318,63 +318,3 @@ export function adapter(config: Record<string, unknown>) {
: path;
return fetch(fetchUrl as string, { ...rest, responseType: "text" });
}
export function safeLocalStorage(): {
getItem: (key: string) => string | null;
setItem: (key: string, value: string) => void;
removeItem: (key: string) => void;
clear: () => void;
} {
let storage: Storage | null;
try {
if (typeof window !== "undefined" && window.localStorage) {
storage = window.localStorage;
} else {
storage = null;
}
} catch (e) {
console.error("localStorage is not available:", e);
storage = null;
}
return {
getItem(key: string): string | null {
if (storage) {
return storage.getItem(key);
} else {
console.warn(
`Attempted to get item "${key}" from localStorage, but localStorage is not available.`,
);
return null;
}
},
setItem(key: string, value: string): void {
if (storage) {
storage.setItem(key, value);
} else {
console.warn(
`Attempted to set item "${key}" in localStorage, but localStorage is not available.`,
);
}
},
removeItem(key: string): void {
if (storage) {
storage.removeItem(key);
} else {
console.warn(
`Attempted to remove item "${key}" from localStorage, but localStorage is not available.`,
);
}
},
clear(): void {
if (storage) {
storage.clear();
} else {
console.warn(
"Attempted to clear localStorage, but localStorage is not available.",
);
}
},
};
}

View File

@@ -8,7 +8,7 @@ export function useAllModels() {
const models = useMemo(() => {
return collectModelsWithDefaultModel(
configStore.models,
[configStore.customModels, accessStore.customModels].join(","),
[accessStore.customModels, configStore.customModels].join(","),
accessStore.defaultModel,
);
}, [

View File

@@ -1,8 +1,5 @@
import { StateStorage } from "zustand/middleware";
import { get, set, del, clear } from "idb-keyval";
import { safeLocalStorage } from "@/app/utils";
const localStorage = safeLocalStorage();
class IndexedDBStorage implements StateStorage {
public async getItem(name: string): Promise<string | null> {

View File

@@ -9,7 +9,7 @@
},
"package": {
"productName": "NextChat",
"version": "2.15.2"
"version": "2.14.2"
},
"tauri": {
"allowlist": {