Skip to content

Commit

Permalink
Merge pull request ChatGPTNextWeb#839 from Yidadaa/bugfix-0416
Browse files Browse the repository at this point in the history
feat: close ChatGPTNextWeb#813 log user ip time
  • Loading branch information
Yidadaa authored Apr 16, 2023
2 parents e64913c + 18985cf commit b138ac8
Show file tree
Hide file tree
Showing 21 changed files with 206 additions and 137 deletions.
84 changes: 64 additions & 20 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import LightIcon from "../icons/light.svg";
import DarkIcon from "../icons/dark.svg";
import AutoIcon from "../icons/auto.svg";
import BottomIcon from "../icons/bottom.svg";
import StopIcon from "../icons/pause.svg";

import {
Message,
Expand All @@ -38,7 +39,6 @@ import {
isMobileScreen,
selectOrCopy,
autoGrowTextArea,
getCSSVar,
} from "../utils";

import dynamic from "next/dynamic";
Expand Down Expand Up @@ -355,8 +355,8 @@ export function ChatActions(props: {
}) {
const chatStore = useChatStore();

// switch themes
const theme = chatStore.config.theme;

function nextTheme() {
const themes = [Theme.Auto, Theme.Light, Theme.Dark];
const themeIndex = themes.indexOf(theme);
Expand All @@ -365,8 +365,20 @@ export function ChatActions(props: {
chatStore.updateConfig((config) => (config.theme = nextTheme));
}

// stop all responses
const couldStop = ControllerPool.hasPending();
const stopAll = () => ControllerPool.stopAll();

return (
<div className={chatStyle["chat-input-actions"]}>
{couldStop && (
<div
className={`${chatStyle["chat-input-action"]} clickable`}
onClick={stopAll}
>
<StopIcon />
</div>
)}
{!props.hitBottom && (
<div
className={`${chatStyle["chat-input-action"]} clickable`}
Expand Down Expand Up @@ -524,21 +536,45 @@ export function Chat(props: {
}
};

const onResend = (botIndex: number) => {
const findLastUesrIndex = (messageId: number) => {
// find last user input message and resend
for (let i = botIndex; i >= 0; i -= 1) {
if (messages[i].role === "user") {
setIsLoading(true);
chatStore
.onUserInput(messages[i].content)
.then(() => setIsLoading(false));
chatStore.updateCurrentSession((session) =>
session.messages.splice(i, 2),
);
inputRef.current?.focus();
return;
let lastUserMessageIndex: number | null = null;
for (let i = 0; i < session.messages.length; i += 1) {
const message = session.messages[i];
if (message.id === messageId) {
break;
}
if (message.role === "user") {
lastUserMessageIndex = i;
}
}

return lastUserMessageIndex;
};

const deleteMessage = (userIndex: number) => {
chatStore.updateCurrentSession((session) =>
session.messages.splice(userIndex, 2),
);
};

const onDelete = (botMessageId: number) => {
const userIndex = findLastUesrIndex(botMessageId);
if (userIndex === null) return;
deleteMessage(userIndex);
};

const onResend = (botMessageId: number) => {
// find last user input message and resend
const userIndex = findLastUesrIndex(botMessageId);
if (userIndex === null) return;

setIsLoading(true);
chatStore
.onUserInput(session.messages[userIndex].content)
.then(() => setIsLoading(false));
deleteMessage(userIndex);
inputRef.current?.focus();
};

const config = useChatStore((state) => state.config);
Expand Down Expand Up @@ -710,12 +746,20 @@ export function Chat(props: {
{Locale.Chat.Actions.Stop}
</div>
) : (
<div
className={styles["chat-message-top-action"]}
onClick={() => onResend(i)}
>
{Locale.Chat.Actions.Retry}
</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
Expand Down
2 changes: 1 addition & 1 deletion app/icons/bottom.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/icons/pause.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/locales/cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const cn = {
Copy: "复制",
Stop: "停止",
Retry: "重试",
Delete: "删除",
},
Rename: "重命名对话",
Typing: "正在输入…",
Expand Down
1 change: 1 addition & 0 deletions app/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const de: LocaleType = {
Copy: "Kopieren",
Stop: "Stop",
Retry: "Wiederholen",
Delete: "Delete",
},
Rename: "Chat umbenennen",
Typing: "Tippen...",
Expand Down
1 change: 1 addition & 0 deletions app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const en: LocaleType = {
Copy: "Copy",
Stop: "Stop",
Retry: "Retry",
Delete: "Delete",
},
Rename: "Rename Chat",
Typing: "Typing…",
Expand Down
1 change: 1 addition & 0 deletions app/locales/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const es: LocaleType = {
Copy: "Copiar",
Stop: "Detener",
Retry: "Reintentar",
Delete: "Delete",
},
Rename: "Renombrar chat",
Typing: "Escribiendo...",
Expand Down
24 changes: 7 additions & 17 deletions app/locales/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,13 @@ export function getLang(): Lang {

const lang = getLanguage();

if (lang.includes("zh") || lang.includes("cn")) {
return "cn";
} else if (lang.includes("tw")) {
return "tw";
} else if (lang.includes("es")) {
return "es";
} else if (lang.includes("it")) {
return "it";
} else if (lang.includes("tr")) {
return "tr";
} else if (lang.includes("jp")) {
return "jp";
} else if (lang.includes("de")) {
return "de";
} else {
return "en";
for (const option of AllLangs) {
if (lang.includes(option)) {
return option;
}
}

return "en";
}

export function changeLang(lang: Lang) {
Expand All @@ -87,4 +77,4 @@ export default {
tr: TR,
jp: JP,
de: DE,
}[getLang()];
}[getLang()] as typeof CN;
1 change: 1 addition & 0 deletions app/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const it: LocaleType = {
Copy: "Copia",
Stop: "Stop",
Retry: "Riprova",
Delete: "Delete",
},
Rename: "Rinomina Chat",
Typing: "Typing…",
Expand Down
3 changes: 1 addition & 2 deletions app/locales/jp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const jp = {
Copy: "コピー",
Stop: "停止",
Retry: "リトライ",
Delete: "Delete",
},
Rename: "チャットの名前を変更",
Typing: "入力中…",
Expand Down Expand Up @@ -178,6 +179,4 @@ const jp = {
},
};

export type LocaleType = typeof jp;

export default jp;
1 change: 1 addition & 0 deletions app/locales/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const tr: LocaleType = {
Copy: "Kopyala",
Stop: "Durdur",
Retry: "Tekrar Dene",
Delete: "Delete",
},
Rename: "Sohbeti Yeniden Adlandır",
Typing: "Yazıyor…",
Expand Down
1 change: 1 addition & 0 deletions app/locales/tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const tw: LocaleType = {
Copy: "複製",
Stop: "停止",
Retry: "重試",
Delete: "刪除",
},
Rename: "重命名對話",
Typing: "正在輸入…",
Expand Down
15 changes: 11 additions & 4 deletions app/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ChatRequest, ChatResponse } from "./api/openai/typing";
import { Message, ModelConfig, useAccessStore, useChatStore } from "./store";
import { showToast } from "./components/ui-lib";

const TIME_OUT_MS = 30000;
const TIME_OUT_MS = 60000;

const makeRequestParam = (
messages: Message[],
Expand Down Expand Up @@ -167,15 +167,14 @@ export async function requestChatStream(
options?.onController?.(controller);

while (true) {
// handle time out, will stop if no response in 10 secs
const resTimeoutId = setTimeout(() => finish(), TIME_OUT_MS);
const content = await reader?.read();
clearTimeout(resTimeoutId);

if (!content || !content.value) {
break;
}

const text = decoder.decode(content.value, { stream: true });
responseText += text;

Expand Down Expand Up @@ -235,6 +234,14 @@ export const ControllerPool = {
controller?.abort();
},

stopAll() {
Object.values(this.controllers).forEach((v) => v.abort());
},

hasPending() {
return Object.values(this.controllers).length > 0;
},

remove(sessionIndex: number, messageId: number) {
const key = this.key(sessionIndex, messageId);
delete this.controllers[key];
Expand Down
3 changes: 2 additions & 1 deletion app/store/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ export const useChatStore = create<ChatStore>()(
const botMessage: Message = createMessage({
role: "assistant",
streaming: true,
id: userMessage.id! + 1,
});

// get recent messages
Expand Down Expand Up @@ -421,7 +422,7 @@ export const useChatStore = create<ChatStore>()(
onError(error, statusCode) {
if (statusCode === 401) {
botMessage.content = Locale.Error.Unauthorized;
} else {
} else if (!error.message.includes("aborted")) {
botMessage.content += "\n\n" + Locale.Store.Error;
}
botMessage.streaming = false;
Expand Down
7 changes: 3 additions & 4 deletions app/store/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,9 @@ export const usePromptStore = create<PromptStore>()(
})
.concat([...(state?.prompts?.values() ?? [])]);

const allPromptsForSearch = builtinPrompts.reduce(
(pre, cur) => pre.concat(cur),
[],
);
const allPromptsForSearch = builtinPrompts
.reduce((pre, cur) => pre.concat(cur), [])
.filter((v) => !!v.title && !!v.content);
SearchService.count.builtin = res.en.length + res.cn.length;
SearchService.init(allPromptsForSearch);
});
Expand Down
13 changes: 13 additions & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ export const config = {

const serverConfig = getServerSideConfig();

function getIP(req: NextRequest) {
let ip = req.ip ?? req.headers.get("x-real-ip");
const forwardedFor = req.headers.get("x-forwarded-for");

if (!ip && forwardedFor) {
ip = forwardedFor.split(",").at(0) ?? "";
}

return ip;
}

export function middleware(req: NextRequest) {
const accessCode = req.headers.get("access-code");
const token = req.headers.get("token");
Expand All @@ -16,6 +27,8 @@ export function middleware(req: NextRequest) {
console.log("[Auth] allowed hashed codes: ", [...serverConfig.codes]);
console.log("[Auth] got access code:", accessCode);
console.log("[Auth] hashed access code:", hashedCode);
console.log("[User IP] ", getIP(req));
console.log("[Time] ", new Date().toLocaleString());

if (serverConfig.needCode && !serverConfig.codes.has(hashedCode) && !token) {
return NextResponse.json(
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"start": "next start",
"lint": "next lint",
"fetch": "node ./scripts/fetch-prompts.mjs",
"prepare": "husky install"
"prepare": "husky install",
"proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev"
},
"dependencies": {
"@hello-pangea/dnd": "^16.2.0",
Expand All @@ -18,7 +19,7 @@
"emoji-picker-react": "^4.4.7",
"eventsource-parser": "^0.1.0",
"fuse.js": "^6.6.2",
"next": "^13.2.3",
"next": "^13.3.0",
"node-fetch": "^3.3.1",
"openai": "^3.2.1",
"react": "^18.2.0",
Expand Down
1 change: 1 addition & 0 deletions scripts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
proxychains.conf
5 changes: 5 additions & 0 deletions scripts/init-proxy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dir="$(dirname "$0")"
config=$dir/proxychains.conf
host_ip=$(grep nameserver /etc/resolv.conf | sed 's/nameserver //')
cp $dir/proxychains.template.conf $config
sed -i "\$s/.*/http $host_ip 7890/" $config
12 changes: 12 additions & 0 deletions scripts/proxychains.template.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
strict_chain
proxy_dns

remote_dns_subnet 224

tcp_read_time_out 15000
tcp_connect_time_out 8000

localnet 127.0.0.0/255.0.0.0

[ProxyList]
socks4 127.0.0.1 9050
Loading

0 comments on commit b138ac8

Please sign in to comment.