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/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/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/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", 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; + } + } +} 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,