From 43b68355646e35ddf6d80f04668d6922b3e7b036 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 16:52:00 +0800 Subject: [PATCH 01/11] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de57e4bb..8bbed80b 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ You can star or watch this project or follow author to get release notifictions code1,code2,code3 ``` -增加或修改该环境变量后,请重新部署项目使改动生效。 +增加或修改该环境变量后,请**重新部署**项目使改动生效。 This project provides limited access control. Please add an environment variable named `CODE` on the environment variables page. The value should be a custom control code separated by comma like this: @@ -151,6 +151,10 @@ The free trial of the OpenAI account used by the demo will expire on April 1, 20 If you would like to contribute your API key, you can email it to the author and indicate the expiration date of the API key. +## 鸣谢 Special Thanks +### 捐赠者 Sponsor +[@mushan0x0](https://github.com/mushan0x0) + ## LICENSE - [Anti 996 License](https://github.com/kattgu7/Anti-996-License/blob/master/LICENSE_CN_EN) From a5ec15236ad13b971bafb2684bf2c127b27ef3dd Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 09:32:47 +0000 Subject: [PATCH 02/11] fix: #38 high resolution favicon --- public/android-chrome-192x192.png | Bin 728 -> 12683 bytes public/android-chrome-512x512.png | Bin 728 -> 24236 bytes public/apple-touch-icon.png | Bin 728 -> 11573 bytes public/favicon-16x16.png | Bin 657 -> 633 bytes public/favicon-32x32.png | Bin 728 -> 1546 bytes public/favicon.ico | Bin 8912 -> 15406 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png index 2cd0df467206525aa86c22cfc7fa5e47a364f5c9..df44543f0251e1db7ceee11a978a398ab11bfbe7 100644 GIT binary patch literal 12683 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�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∋>=k5D(MNE-zrXm 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 O{2A$)>6U6c-uWMxqFhD* literal 728 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%0D)*#^r4GkTfRTv@x9CK0E>s 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 delta 619 zcmV-x0+jvv1d#=hF@H-*L_t(IPobhHIE(&WX3hTirG$mVw+#o9T zRGNq#EU``!NQ4j+9ikwR3NM~gG7m{<)}^!}NE5%nR3Z%8vXorXcKdW)_jM=UH`{g> zJvoONX6BjS|CxFIBUo+jW$BQT24Fvu#DD7%qri*gxd_r|vww(TZBJ;O+b^r6#xmj@c}tL+HvuhN9zK-Ua-sN_?z|w1l-2QiBwTIlt^gax@%p=|vBAYZBHt3%#x> zY@6driBF(%M=oY#On7LQ2JnR6x#RU1n)>;oL);u2WO#O(8zto^LeMroLQSqC1d-qs zb4yZc$R$;!;(u-nb@_YAv?kL$+RyQvJ!~vx z_t8a;ZJVypJvE8RV8oy(>`qC;<6ESCa+I0xUixb5F$hJ|{SSCE? zW2-e1pv_J{y2rKRG6p`q*B|lffy4ap`?x(ZqCet0&pgeeFX^m2Nu1HR3J5EsmUhe7 zAlFOEb!3a4>A8<1HG@-mgf;};bs-1ZuAN(z2l#zZd`*lTu;O*Bh6x*}#EG^>l zEO2pONwi_R*0r)0sg>;KvLBPtsH;ae-O3yOOdI{qe*lQb77(<0Q$YX#002ovPDHLk FV1k-1B;Ei3 diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png index 2cd0df467206525aa86c22cfc7fa5e47a364f5c9..fc262b9b791412ef13d758ead9aeb3dc148d396c 100644 GIT binary patch literal 1546 zcmV+l2KD)gP)Px)#7RU!R9HvNmw8ZCWfZ`F_dOmDR2ErOL=Z#-K~hxol|mpW86t`cQcc-HQ%a@z zhnh`I&1l+;W{WndqhsYDkQgo)x#0?CisS;KB0>ntCLqXr@OaI41x6I`{!!ZZ$9psP ze)pW;S-x}5C(*h}>P`MCGnN3Mn6Phq{;&Q^R00QEBvv|`OW8uUBz|rgOs|?+*kl6D zzpAhcVG=Z%OvE`^N?RpixmwMsC#AfNNkAA?jFn3DrbJB4eiD{HqC+A{095>EF@Ky@ z5|vVEqsjEReQocXTUywge}Vl4mnp8TMx#>W?a-GQLr386G(f4C4*L`X+-bbWqVyCl zm6tK1-vE3Z`_b6kOjb!DCAD{m9X5(--p^n#8gaI^p@+s?5s)GPlgY%pdy}|URn8Y- zQyJagwOx3vzLB`y3Ea3-)&5MaQZe3j5b*&)xY+dW7DN%i!Ge629oo&86Qc+kI9L|g zVluJo@_9C#Il*0no=7i0#<{qoRcp9ZUP{u%Y#N#jtbJhyetr9Q3DGUU+0tUxpFYNg z+od>L*{~z#Em_d%n?-z`mBH1jazflZi60Y$v$bspB{lj+-cL)W>RtnhvtI8qBwYgR zy>gM|N7M1>?LeJDk9%)>z6y^fqwoq#4(wuxeIFL+f*I-LA}c;tbd3{51-#@p8rN30 z7v8BPcE?s0>Vlc=JF-(RbP7;ZQ_agMTM2aa;Pa3O-rtvurI|Ua!>5yyn?q*tbyiJ` zLM2IDtEyn_sSGOW?^0)IL?r7>AAjET*I}i#VD7I!)3=uutHPp`1FSl}pF`L4NtqKz zPmMYA_9k`!$g3#h-GD$goHSEMe=AmYX)((V z?ZM8nC!3>Qmf;>=o#wzhd$yyNRIH1*-y+^iOO^}F`YE$X%{z|>!AF7N9b~OImQItg zh5X9f*k~9DKW|bgtc#`Zlj{1p5>ua+K<}N z8&~=E)KM%nW}Sv$y7zFRhYn{^`cCdO8(1H4U*X!U3=S9OlRD>ZWdLH=ietaal}=17 z69#z^9}tL>l?_csBgvPt`6=f#;e)*qtt|aoF4kHL<_sIvDZpnL`^c-fMZ(Ov$^qu5 zC80th*v*rTXHU}5)I_Y`NM0L07OmQh&F8Y%lAR@I_}in#$tBs-zRx27^-Tt%w{K*E zyBCYchbaeGyg!xO^>u8S_6l`+J)6&EB67nkww?czaV~=h9O%)0 z)I^LgSKel2*i_kL3)535tgfV|xmHf#kAuQ_(bHFX9S}R~4F+O<*^GUUo_srbmK@^; zS4mwB-<>+b;leAj7lbzgTHADV;wDP#YVhsj#QcDuZikg_yJ60)5*GfJB6qSFUw?cY zozNSbI9YsMPS9TFS~>nxz5L|9Al8u^R}tY`9vVrg`;bnpRuqD^O`^()vU}T>t<807*qoM6N<$f{oJXn*aa+ literal 728 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 literal 8912 zcmeI1L13R&v)ICWg}tCKTq75W%q?O!6kTf*99~1&(_;J zZLQS^ZP7X{OSbM@!&cfmJ(#VvcO}n)V|Jx=E*;NGvm3MX z?<~#O+3{CweEd~A^669d6g%E^8Uoc>$%^F zlh4`r-@P4S%=c+^_~;XM^`GDD=bsMR{*NEDEA!*_$Lw)ygg6#1pRwtw5A6Ms`|axT ztZ=SNw`;3&_SSp%+J^@ow&@@C+ohSKHg@VoJN@-bc5>{6+<)%(FYNr}oAzh>+miqC z;*@=K@DaPV(zJ8myk-XuJ!;E~)3)~auQq!8>7G9rt>&qcKRPo=Anf zK6}^Q&zU?IYGQr)lJgJyN6owXp--()Gt>?>^yOF2+vMaMk#GJRX;jrOHH)UyaE#x3 z4)vS=25#c_qu=4p{C*|V8|2>muEqRd`M8x!j3-?b5A*aDlg1+AEfLt>Z88GUwy=S}9-U0hgLE6$cnJ zjYl@g>#LG^6dHO%MTlI@|@(A4|%CCu2{R6PaOE+ujj}nd08Voe7#vCK$r74`^#lnk?^-kk;&$pXBw}K6~Z*ZltD>cl|Ih^l?J=YC=mh<}P)-E+{tr$kNXzfQ+nLD;9e%~|BbCL#`VQm#XRf_)W4{Qewo%6v$Es1wzi`l@x+oa#lb#dy8cr8|$6I(m#Ici*e;8zE{_2{WkKeFUC5 Date: Sun, 26 Mar 2023 17:51:46 +0800 Subject: [PATCH 03/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8bbed80b..d7770a40 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ One-Click to deploy your own ChatGPT web UI. -[演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈问题 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) +[演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈问题 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [加入 Discord](https://discord.gg/zrhvHCr79N) [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web) From 86507fa569334a43c7d9e7b40add815c665eae4a Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 10:59:09 +0000 Subject: [PATCH 04/11] feat: #2 #8 add stop and retry button --- app/components/home.tsx | 60 +++++++++++++++++++++++++++++++++++------ app/locales/cn.ts | 1 + app/locales/en.ts | 1 + app/requests.ts | 36 +++++++++++++++++++++++-- app/store/app.ts | 20 +++++++++++++- 5 files changed, 107 insertions(+), 11 deletions(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index 1c665f87..d9f533ae 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -27,6 +27,7 @@ import Locale from "../locales"; import dynamic from "next/dynamic"; import { REPO_URL } from "../constant"; +import { ControllerPool } from "../requests"; export function Loading(props: { noLogo?: boolean }) { return ( @@ -146,28 +147,67 @@ function useSubmitHandler() { export function Chat(props: { showSideBar?: () => void }) { type RenderMessage = Message & { preview?: boolean }; - const session = useChatStore((state) => state.currentSession()); + const [session, sessionIndex] = useChatStore((state) => [ + state.currentSession(), + state.currentSessionIndex, + ]); const [userInput, setUserInput] = useState(""); const [isLoading, setIsLoading] = useState(false); const { submitKey, shouldSubmit } = useSubmitHandler(); const onUserInput = useChatStore((state) => state.onUserInput); + + // submit user input const onUserSubmit = () => { if (userInput.length <= 0) return; setIsLoading(true); onUserInput(userInput).then(() => setIsLoading(false)); setUserInput(""); }; + + // stop response + const onUserStop = (messageIndex: number) => { + console.log(ControllerPool, sessionIndex, messageIndex); + ControllerPool.stop(sessionIndex, messageIndex); + }; + + // check if should send message const onInputKeyDown = (e: KeyboardEvent) => { if (shouldSubmit(e)) { onUserSubmit(); e.preventDefault(); } }; + const onRightClick = (e: any, message: Message) => { + // auto fill user input + if (message.role === "user") { + setUserInput(message.content); + } + + // copy to clipboard + if (selectOrCopy(e.currentTarget, message.content)) { + e.preventDefault(); + } + }; + + const onResend = (botIndex: number) => { + // find last user input message and resend + for (let i = botIndex; i >= 0; i -= 1) { + if (messages[i].role === "user") { + setIsLoading(true); + onUserInput(messages[i].content).then(() => setIsLoading(false)); + return; + } + } + }; + + // for auto-scroll const latestMessageRef = useRef(null); + // wont scroll while hovering messages const [hoveringMessage, setHoveringMessage] = useState(false); + // preview messages const messages = (session.messages as RenderMessage[]) .concat( isLoading @@ -194,6 +234,7 @@ export function Chat(props: { showSideBar?: () => void }) { : [] ); + // auto scroll useLayoutEffect(() => { setTimeout(() => { const dom = latestMessageRef.current; @@ -283,13 +324,20 @@ export function Chat(props: { showSideBar?: () => void }) {
{!isUser && (
- {message.streaming && ( + {message.streaming ? (
showToast(Locale.WIP)} + onClick={() => onUserStop(i)} > {Locale.Chat.Actions.Stop}
+ ) : ( +
onResend(i)} + > + {Locale.Chat.Actions.Retry} +
)}
void }) { ) : (
{ - if (selectOrCopy(e.currentTarget, message.content)) { - e.preventDefault(); - } - }} + onContextMenu={(e) => onRightClick(e, message)} >
diff --git a/app/locales/cn.ts b/app/locales/cn.ts index ab6af587..b0d5801c 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -14,6 +14,7 @@ const cn = { Export: "导出聊天记录", Copy: "复制", Stop: "停止", + Retry: "重试", }, Typing: "正在输入…", Input: (submitKey: string) => `输入消息,${submitKey} 发送`, diff --git a/app/locales/en.ts b/app/locales/en.ts index 85a0caff..e10898b3 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -17,6 +17,7 @@ const en: LocaleType = { Export: "Export All Messages as Markdown", Copy: "Copy", Stop: "Stop", + Retry: "Retry", }, Typing: "Typing…", Input: (submitKey: string) => diff --git a/app/requests.ts b/app/requests.ts index 484fbb93..4d0903f9 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -60,6 +60,7 @@ export async function requestChatStream( modelConfig?: ModelConfig; onMessage: (message: string, done: boolean) => void; onError: (error: Error) => void; + onController?: (controller: AbortController) => void; } ) { const req = makeRequestParam(messages, { @@ -96,12 +97,12 @@ export async function requestChatStream( controller.abort(); }; - console.log(res); - if (res.ok) { const reader = res.body?.getReader(); const decoder = new TextDecoder(); + options?.onController?.(controller); + while (true) { // handle time out, will stop if no response in 10 secs const resTimeoutId = setTimeout(() => finish(), TIME_OUT_MS); @@ -146,3 +147,34 @@ export async function requestWithPrompt(messages: Message[], prompt: string) { return res.choices.at(0)?.message?.content ?? ""; } + +// To store message streaming controller +export const ControllerPool = { + controllers: {} as Record, + + addController( + sessionIndex: number, + messageIndex: number, + controller: AbortController + ) { + const key = this.key(sessionIndex, messageIndex); + this.controllers[key] = controller; + return key; + }, + + stop(sessionIndex: number, messageIndex: number) { + const key = this.key(sessionIndex, messageIndex); + const controller = this.controllers[key]; + console.log(controller); + controller?.abort(); + }, + + remove(sessionIndex: number, messageIndex: number) { + const key = this.key(sessionIndex, messageIndex); + delete this.controllers[key]; + }, + + key(sessionIndex: number, messageIndex: number) { + return `${sessionIndex},${messageIndex}`; + }, +}; diff --git a/app/store/app.ts b/app/store/app.ts index 3c4fcded..e587a731 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -2,7 +2,11 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; import { type ChatCompletionResponseMessage } from "openai"; -import { requestChatStream, requestWithPrompt } from "../requests"; +import { + ControllerPool, + requestChatStream, + requestWithPrompt, +} from "../requests"; import { trimTopic } from "../utils"; import Locale from "../locales"; @@ -296,6 +300,8 @@ export const useChatStore = create()( // get recent messages const recentMessages = get().getMessagesWithMemory(); const sendMessages = recentMessages.concat(userMessage); + const sessionIndex = get().currentSessionIndex; + const messageIndex = get().currentSession().messages.length + 1; // save user's and bot's message get().updateCurrentSession((session) => { @@ -303,13 +309,16 @@ export const useChatStore = create()( session.messages.push(botMessage); }); + // make request console.log("[User Input] ", sendMessages); requestChatStream(sendMessages, { onMessage(content, done) { + // stream response if (done) { botMessage.streaming = false; botMessage.content = content; get().onNewMessage(botMessage); + ControllerPool.remove(sessionIndex, messageIndex); } else { botMessage.content = content; set(() => ({})); @@ -319,6 +328,15 @@ export const useChatStore = create()( botMessage.content += "\n\n" + Locale.Store.Error; botMessage.streaming = false; set(() => ({})); + ControllerPool.remove(sessionIndex, messageIndex); + }, + onController(controller) { + // collect controller for stop/retry + ControllerPool.addController( + sessionIndex, + messageIndex, + controller + ); }, filterBot: !get().config.sendBotMessages, modelConfig: get().config.modelConfig, From 1e89fe14ac08a87249a917b4630671c52d4f03f5 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 11:10:34 +0000 Subject: [PATCH 05/11] fix: #34 only auto scroll when textbox is focused --- app/components/home.tsx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index d9f533ae..1265149a 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -205,7 +205,7 @@ export function Chat(props: { showSideBar?: () => void }) { const latestMessageRef = useRef(null); // wont scroll while hovering messages - const [hoveringMessage, setHoveringMessage] = useState(false); + const [autoScroll, setAutoScroll] = useState(false); // preview messages const messages = (session.messages as RenderMessage[]) @@ -238,7 +238,7 @@ export function Chat(props: { showSideBar?: () => void }) { useLayoutEffect(() => { setTimeout(() => { const dom = latestMessageRef.current; - if (dom && !isIOS() && !hoveringMessage) { + if (dom && !isIOS() && autoScroll) { dom.scrollIntoView({ behavior: "smooth", block: "end", @@ -293,15 +293,7 @@ export function Chat(props: { showSideBar?: () => void }) {
-
{ - setHoveringMessage(true); - }} - onMouseOut={() => { - setHoveringMessage(false); - }} - > +
{messages.map((message, i) => { const isUser = message.role === "user"; @@ -385,6 +377,9 @@ export function Chat(props: { showSideBar?: () => void }) { onInput={(e) => setUserInput(e.currentTarget.value)} value={userInput} onKeyDown={(e) => onInputKeyDown(e as any)} + onFocus={() => setAutoScroll(true)} + onBlur={() => setAutoScroll(false)} + autoFocus /> } From f1b6641f19d8e91e4c7244931d2633dcf7e3ed80 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 19:28:30 +0800 Subject: [PATCH 06/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7770a40..8ec2822f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ One-Click to deploy your own ChatGPT web UI. -[演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈问题 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [加入 Discord](https://discord.gg/zrhvHCr79N) +[演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [加入 Discord](https://discord.gg/zrhvHCr79N) / [微信群](https://user-images.githubusercontent.com/16968934/227772522-b3ba3713-9206-4c8d-a81f-22300b7c313a.jpg) / [打赏开发者](https://user-images.githubusercontent.com/16968934/227772541-5bcd52d8-61b7-488c-a203-0330d8006e2b.jpg) [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web) From df66eef919a3eda0569c94b7ab79523aa3957968 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 11:58:25 +0000 Subject: [PATCH 07/11] feat: support using user api key --- app/api/chat-stream/route.ts | 16 +++++++++++----- app/api/chat/route.ts | 29 ++++++++++++++++------------- app/components/settings.tsx | 14 ++++++++++++++ app/locales/cn.ts | 5 +++++ app/requests.ts | 4 ++++ app/store/access.ts | 6 ++++++ middleware.ts | 3 ++- 7 files changed, 58 insertions(+), 19 deletions(-) diff --git a/app/api/chat-stream/route.ts b/app/api/chat-stream/route.ts index 16c5950c..8803a425 100644 --- a/app/api/chat-stream/route.ts +++ b/app/api/chat-stream/route.ts @@ -2,19 +2,25 @@ import type { ChatRequest } from "../chat/typing"; import { createParser } from "eventsource-parser"; import { NextRequest } from "next/server"; -const apiKey = process.env.OPENAI_API_KEY; - -async function createStream(payload: ReadableStream) { +async function createStream(req: NextRequest) { const encoder = new TextEncoder(); const decoder = new TextDecoder(); + let apiKey = process.env.OPENAI_API_KEY; + + const userApiKey = req.headers.get("token"); + if (userApiKey) { + apiKey = userApiKey; + console.log("[Stream] using user api key"); + } + const res = await fetch("https://api.openai.com/v1/chat/completions", { headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, }, method: "POST", - body: payload, + body: req.body, }); const stream = new ReadableStream({ @@ -49,7 +55,7 @@ async function createStream(payload: ReadableStream) { export async function POST(req: NextRequest) { try { - const stream = await createStream(req.body!); + const stream = await createStream(req); return new Response(stream); } catch (error) { console.error("[Chat Stream]", error); diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index c4e41ca3..18c7db14 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -1,23 +1,26 @@ import { OpenAIApi, Configuration } from "openai"; import { ChatRequest } from "./typing"; -const apiKey = process.env.OPENAI_API_KEY; - -const openai = new OpenAIApi( - new Configuration({ - apiKey, - }) -); - export async function POST(req: Request) { try { - const requestBody = (await req.json()) as ChatRequest; - const completion = await openai!.createChatCompletion( - { - ...requestBody, - } + let apiKey = process.env.OPENAI_API_KEY; + + const userApiKey = req.headers.get("token"); + if (userApiKey) { + apiKey = userApiKey; + } + + const openai = new OpenAIApi( + new Configuration({ + apiKey, + }) ); + const requestBody = (await req.json()) as ChatRequest; + const completion = await openai!.createChatCompletion({ + ...requestBody, + }); + return new Response(JSON.stringify(completion.data)); } catch (e) { console.error("[Chat] ", e); diff --git a/app/components/settings.tsx b/app/components/settings.tsx index a0a477af..56165daa 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -257,6 +257,20 @@ export function Settings(props: { closeSettings: () => void }) { <> )} + + { + accessStore.updateToken(e.currentTarget.value); + }} + > + + 0) { + headers["token"] = accessStore.token; + } + return headers; } diff --git a/app/store/access.ts b/app/store/access.ts index 4ec2111c..9c61dfa0 100644 --- a/app/store/access.ts +++ b/app/store/access.ts @@ -4,7 +4,9 @@ import { queryMeta } from "../utils"; export interface AccessControlStore { accessCode: string; + token: string; + updateToken: (_: string) => void; updateCode: (_: string) => void; enabledAccessControl: () => boolean; } @@ -14,6 +16,7 @@ export const ACCESS_KEY = "access-control"; export const useAccessStore = create()( persist( (set, get) => ({ + token: "", accessCode: "", enabledAccessControl() { return queryMeta("access") === "enabled"; @@ -21,6 +24,9 @@ export const useAccessStore = create()( updateCode(code: string) { set((state) => ({ accessCode: code })); }, + updateToken(token: string) { + set((state) => ({ token })); + }, }), { name: ACCESS_KEY, diff --git a/middleware.ts b/middleware.ts index 0ab3a101..7e671ff1 100644 --- a/middleware.ts +++ b/middleware.ts @@ -8,13 +8,14 @@ export const config = { export function middleware(req: NextRequest, res: NextResponse) { const accessCode = req.headers.get("access-code"); + const token = req.headers.get("token"); const hashedCode = md5.hash(accessCode ?? "").trim(); console.log("[Auth] allowed hashed codes: ", [...ACCESS_CODES]); console.log("[Auth] got access code:", accessCode); console.log("[Auth] hashed access code:", hashedCode); - if (ACCESS_CODES.size > 0 && !ACCESS_CODES.has(hashedCode)) { + if (ACCESS_CODES.size > 0 && !ACCESS_CODES.has(hashedCode) && !token) { return NextResponse.json( { needAccessCode: true, From e57bd5180939f4f134c5a3fb47db7f7203ad6f4a Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 12:29:02 +0000 Subject: [PATCH 08/11] feat: #9 add copy code button --- app/components/markdown.tsx | 29 +++++++++++++++++++++++++---- app/page.tsx | 2 +- app/styles/globals.scss | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index 83bfe4ef..6e0e6d86 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -4,15 +4,36 @@ import RemarkMath from "remark-math"; import RehypeKatex from "rehype-katex"; import RemarkGfm from "remark-gfm"; import RehypePrsim from "rehype-prism-plus"; +import { useRef } from "react"; +import { copyToClipboard } from "../utils"; + +export function PreCode(props: { children: any }) { + const ref = useRef(null); + + return ( +
+       {
+          if (ref.current) {
+            const code = ref.current.innerText;
+            copyToClipboard(code);
+          }
+        }}
+      >
+      {props.children}
+    
+ ); +} export function Markdown(props: { content: string }) { return ( {props.content} diff --git a/app/page.tsx b/app/page.tsx index a986da3f..54300e71 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,5 @@ import { Analytics } from "@vercel/analytics/react"; -import { Home } from './components/home' +import { Home } from "./components/home"; export default function App() { return ( diff --git a/app/styles/globals.scss b/app/styles/globals.scss index e7d35226..46f074df 100644 --- a/app/styles/globals.scss +++ b/app/styles/globals.scss @@ -206,3 +206,36 @@ div.math { text-decoration: underline; } } + +pre { + position: relative; + + &:hover .copy-code-button { + pointer-events: all; + transform: translateX(0px); + opacity: 0.5; + } + + .copy-code-button { + position: absolute; + right: 10px; + cursor: pointer; + padding: 0px 5px; + background-color: var(--black); + color: var(--white); + border: var(--border-in-light); + border-radius: 10px; + transform: translateX(10px); + pointer-events: none; + opacity: 0; + transition: all ease 0.3s; + + &:after { + content: "copy"; + } + + &:hover { + opacity: 1; + } + } +} From b57663bf02d445fd100a82d0557cbd354506c0d8 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 12:32:22 +0000 Subject: [PATCH 09/11] feat: now support gpt-4 model --- app/store/app.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/store/app.ts b/app/store/app.ts index e587a731..703078ad 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -49,22 +49,24 @@ export interface ChatConfig { export type ModelConfig = ChatConfig["modelConfig"]; +const ENABLE_GPT4 = true; + export const ALL_MODELS = [ { name: "gpt-4", - available: false, + available: ENABLE_GPT4, }, { name: "gpt-4-0314", - available: false, + available: ENABLE_GPT4, }, { name: "gpt-4-32k", - available: false, + available: ENABLE_GPT4, }, { name: "gpt-4-32k-0314", - available: false, + available: ENABLE_GPT4, }, { name: "gpt-3.5-turbo", From f858407f9a7d3fc37c3b0405bd37fa4a0c08fb9d Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sun, 26 Mar 2023 12:35:15 +0000 Subject: [PATCH 10/11] fixup --- app/locales/en.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/locales/en.ts b/app/locales/en.ts index e10898b3..5401cda4 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -74,6 +74,11 @@ const en: LocaleType = { SubTitle: "Will compress if uncompressed messages length exceeds the value", }, + Token: { + Title: "API Key", + SubTitle: "Use your key to ignore access code limit", + Placeholder: "OpenAI API Key", + }, AccessCode: { Title: "Access Code", SubTitle: "Access control enabled", From fb2d281aac7c51c932bdb4fbb47f2dbecdba45e8 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Mon, 27 Mar 2023 03:02:25 +0000 Subject: [PATCH 11/11] fix: #7 disable light code theme --- README.md | 13 ++++++++++- app/styles/prism.scss | 53 +++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 8ec2822f..f20debd0 100644 --- a/README.md +++ b/README.md @@ -109,29 +109,36 @@ OPENAI_API_KEY= ``` ### 本地开发 Local Development + > 如果你是中国大陆用户,不建议在本地进行开发,除非你能够独立解决 OpenAI API 本地代理问题。 1. 安装 nodejs 和 yarn,具体细节请询问 ChatGPT; 2. 执行 `yarn install && yarn dev` 即可。 ### 本地部署 Local Deployment + 请直接询问 ChatGPT,使用下列 Prompt: + ``` 如何使用 pm2 和 yarn 部署 nextjs 项目到 ubuntu 服务器上,项目编译命令为 yarn build,启动命令为 yarn start,启动时需要设置环境变量为 OPENAI_API_KEY,端口为 3000,使用 ngnix 做反向代理 ``` Please ask ChatGPT with prompt: + ``` how to deploy nextjs project with pm2 and yarn on my ubuntu server, the build command is `yarn build`, the start command is `yarn start`, the project must start with env var named `OPENAI_API_KEY`, the port is 3000, use ngnix ``` ### Docker Deployment + 请直接询问 ChatGPT,使用下列 Prompt: + ``` 如何使用 docker 部署 nextjs 项目到 ubuntu 服务器上,项目编译命令为 yarn build,启动命令为 yarn start,启动时需要设置环境变量为 OPENAI_API_KEY,端口为 3000,使用 ngnix 做反向代理 ``` Please ask ChatGPT with prompt: + ``` how to deploy nextjs project with docker on my ubuntu server, the build command is `yarn build`, the start command is `yarn start`, the project must start with env var named `OPENAI_API_KEY`, the port is 3000, use ngnix ``` @@ -143,17 +150,21 @@ how to deploy nextjs project with docker on my ubuntu server, the build command ![更多展示 More](./static/more.png) ## 说明 Attention + 本项目的演示地址所用的 OpenAI 账户的免费额度将于 2023-04-01 过期,届时将无法通过演示地址在线体验。 如果你想贡献出自己的 API Key,可以通过作者主页的邮箱发送给作者,并标注过期时间。 -The free trial of the OpenAI account used by the demo will expire on April 1, 2023, and the demo will not be available at that time. +The free trial of the OpenAI account used by the demo will expire on April 1, 2023, and the demo will not be available at that time. If you would like to contribute your API key, you can email it to the author and indicate the expiration date of the API key. ## 鸣谢 Special Thanks + ### 捐赠者 Sponsor + [@mushan0x0](https://github.com/mushan0x0) +[@ClarenceDan](https://github.com/ClarenceDan) ## LICENSE diff --git a/app/styles/prism.scss b/app/styles/prism.scss index 88ab1936..22b20389 100644 --- a/app/styles/prism.scss +++ b/app/styles/prism.scss @@ -1,4 +1,9 @@ .markdown-body { + pre { + background: #282a36; + color: #f8f8f2; + } + code[class*="language-"], pre[class*="language-"] { color: #f8f8f2; @@ -116,32 +121,32 @@ } } -@mixin light { - .markdown-body pre[class*="language-"] { - filter: invert(1) hue-rotate(50deg) brightness(1.3); - } -} +// @mixin light { +// .markdown-body pre[class*="language-"] { +// filter: invert(1) hue-rotate(50deg) brightness(1.3); +// } +// } -@mixin dark { - .markdown-body pre[class*="language-"] { - filter: none; - } -} +// @mixin dark { +// .markdown-body pre[class*="language-"] { +// filter: none; +// } +// } -:root { - @include light(); -} +// :root { +// @include light(); +// } -.light { - @include light(); -} +// .light { +// @include light(); +// } -.dark { - @include dark(); -} +// .dark { +// @include dark(); +// } -@media (prefers-color-scheme: dark) { - :root { - @include dark(); - } -} +// @media (prefers-color-scheme: dark) { +// :root { +// @include dark(); +// } +// }