From 1a117e583dda5ec837484c24b9a3705ce252321b Mon Sep 17 00:00:00 2001 From: AVGVSTVS96 <122117267+AVGVSTVS96@users.noreply.github.com> Date: Wed, 7 Feb 2024 23:15:27 -0500 Subject: [PATCH 01/14] chore: add utils import alias --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index 091e278c..10c9376d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,7 @@ "@styles/*": ["src/styles/*"], "@components/*": ["src/components/*"], "@subComponents/*": ["src/components/subComponents/*"], + "@utils/*": ["src/utils/*"], } } } From fe84fa85af5fb9301951db7c072b76a2b530c92f Mon Sep 17 00:00:00 2001 From: AVGVSTVS96 <122117267+AVGVSTVS96@users.noreply.github.com> Date: Wed, 7 Feb 2024 23:15:49 -0500 Subject: [PATCH 02/14] chore: import frontend and js code from FastGPT --- src/pages/gpt.astro | 276 +++++++++++++++++++++++++++++++++++++++++ src/utils/chat.js | 39 ++++++ src/utils/interface.js | 89 +++++++++++++ 3 files changed, 404 insertions(+) create mode 100644 src/pages/gpt.astro create mode 100644 src/utils/chat.js create mode 100644 src/utils/interface.js diff --git a/src/pages/gpt.astro b/src/pages/gpt.astro new file mode 100644 index 00000000..5e3718e7 --- /dev/null +++ b/src/pages/gpt.astro @@ -0,0 +1,276 @@ +--- + +--- + + + + + + GPT-4 API Chat + + + + + + +
+

Canvas GPT

+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/src/utils/chat.js b/src/utils/chat.js new file mode 100644 index 00000000..5d1d968c --- /dev/null +++ b/src/utils/chat.js @@ -0,0 +1,39 @@ +// State variables +let messages = []; +let systemMessageRef = null; + +function updateSystemMessage(systemMessage) { + if ( + systemMessage && + (!systemMessageRef || systemMessage !== systemMessageRef.content) + ) { + let systemMessageIndex = messages.findIndex((message) => message.role === "system"); + // If the system message exists in array, remove it + if (systemMessageIndex !== -1) { + messages.splice(systemMessageIndex, 1); + } + systemMessageRef = { role: "system", content: systemMessage }; + messages.push(systemMessageRef); + } +} + +window.onload = function () { + document.getElementById("chat-form").addEventListener("submit", async function (event) { + event.preventDefault(); + + let userInput = userInputElem.value.trim(); + let systemMessage = document.getElementById("system-message").value.trim(); + + updateSystemMessage(systemMessage); + + messages.push({ role: "user", content: userInput }); + addMessageToDiv("user", userInput); + userInputElem.value = ""; + + let messageText = addMessageToDiv("assistant"); + + const response = await postRequest(); + + handleResponse(response, messageText); + }); +}; diff --git a/src/utils/interface.js b/src/utils/interface.js new file mode 100644 index 00000000..7052104a --- /dev/null +++ b/src/utils/interface.js @@ -0,0 +1,89 @@ +// DOM Elements +const chatMessagesDiv = document.getElementById("chat-messages"); +const userInputElem = document.getElementById("user-input"); +const modelToggle = document.getElementById("model-toggle"); +const modelLabelLeft = document.getElementById("model-label-left"); +const modelLabelRight = document.getElementById("model-label-right"); + +// State variables +let modelName = modelToggle.checked ? "gpt-4" : "gpt-3.5-turbo"; +let autoScrollState = true; +let lastScrollTop = 0; + +// Utility functions +window.renderMarkdown = function (content) { + const md = new markdownit(); + return md.render(content); +}; + +function highlightCode(element) { + const codeElements = element.querySelectorAll("pre code"); + codeElements.forEach((codeElement) => { + hljs.highlightElement(codeElement); + }); +} + +function addMessageToDiv(role, content = "") { + let messageDiv = document.createElement("div"); + messageDiv.className = + role === "user" ? "message user-message" : "message assistant-message"; + + let messageText = document.createElement("p"); + messageDiv.appendChild(messageText); + + if (content) { + let renderedContent = window.renderMarkdown(content).trim(); + messageText.innerHTML = renderedContent; + highlightCode(messageDiv); + } + + chatMessagesDiv.appendChild(messageDiv); + autoScroll(); + + return messageText; +} + +// Event listener functions +function handleModelToggle() { + if (modelToggle.checked) { + modelLabelRight.textContent = "GPT-4"; + modelName = "gpt-4"; + } else { + modelLabelLeft.textContent = "GPT-3.5"; + modelName = "gpt-3.5-turbo"; + } +} + +function handleInputKeydown(event) { + if (event.key === "Enter" && !event.shiftKey) { + event.preventDefault(); + document.getElementById("submitBtn").click(); + } +} + +function autoScroll() { + if (autoScrollState) { + chatMessagesDiv.scrollTop = chatMessagesDiv.scrollHeight; + } +} + +function handleChatScroll() { + const isAtBottom = + chatMessagesDiv.scrollHeight - chatMessagesDiv.clientHeight <= + chatMessagesDiv.scrollTop + 150; + + // If user scrolls up, turn off auto-scrolling. + if (chatMessagesDiv.scrollTop < lastScrollTop) { + autoScrollState = false; + } else { + autoScrollState = isAtBottom; + } + + // Update last scroll top value. + lastScrollTop = chatMessagesDiv.scrollTop; +} + +// Event listeners +modelToggle.addEventListener("change", handleModelToggle); +userInputElem.addEventListener("keydown", handleInputKeydown); +chatMessagesDiv.addEventListener("scroll", handleChatScroll); From 45a1226b18dd27a656d63dd0a6eda87311994b66 Mon Sep 17 00:00:00 2001 From: AVGVSTVS96 <122117267+AVGVSTVS96@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:00:00 -0500 Subject: [PATCH 03/14] chore: add link to gpt chat interface --- .gitignore | 4 + bun.lockb | Bin 394187 -> 418711 bytes functions/chat.ts | 55 ++++ package.json | 3 +- src/components/NavBar.astro | 1 + src/pages/gpt.astro | 1 + src/utils/api.js | 35 +++ yarn.lock | 498 +++++++++++++++++++++++++++++++++--- 8 files changed, 556 insertions(+), 41 deletions(-) create mode 100644 functions/chat.ts create mode 100644 src/utils/api.js diff --git a/.gitignore b/.gitignore index 6240da8b..a864e000 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ pnpm-debug.log* # macOS-specific files .DS_Store + + +# Cloudfare +.wrangler \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 316ba9f12211f347ef79ddd878cd92c50833eec4..9e0596c17c1aa08132317d7403943d9b4eb319cf 100755 GIT binary patch delta 54591 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 MD@zX_=K1jd128dw-v9sr delta 41041 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 diff --git a/functions/chat.ts b/functions/chat.ts new file mode 100644 index 00000000..7efecbec --- /dev/null +++ b/functions/chat.ts @@ -0,0 +1,55 @@ +import { Hono } from 'hono'; +import { streamText } from 'hono/streaming'; +import { env } from 'hono/adapter'; + +// Define the structure for messages as expected in the request body +interface Message { + role: string; + content: string; +} + +const app = new Hono(); + +app.post('/chat', (c) => { + const { OPENAI_API_KEY } = env<{ OPENAI_API_KEY: string }>(c); + + return streamText(c, async (stream) => { + try { + const requestBody = await c.req.json() as { modelName: string; messages: Message[] }; + const openaiResponse = await fetch('https://api.openai.com/v1/chat/completions', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${OPENAI_API_KEY}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: requestBody.modelName, + messages: requestBody.messages, + }), + }); + + if (!openaiResponse.ok) { + const errorBody = await openaiResponse.json(); + // Matching the error format from the FastAPI code + const errorMessage = `${errorBody.error.type}: ${errorBody.error.message}`; + await stream.write(errorMessage); + return; + } + + if (openaiResponse.body) { + const reader = openaiResponse.body.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) break; + const text = new TextDecoder().decode(value); + await stream.write(text); + } + } + } catch (error) { + // Writing the error message in the format similar to FastAPI's OpenAIError handling + await stream.write(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + }); +}); + +export default app; diff --git a/package.json b/package.json index 294acc5a..72c78c54 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "prettier-plugin-tailwindcss": "^0.5.11", "semantic-release": "^23.0.0", "tailwindcss": "^3.4.1", - "type-coverage": "^2.27.1" + "type-coverage": "^2.27.1", + "wrangler": "^3.27.0" } } diff --git a/src/components/NavBar.astro b/src/components/NavBar.astro index 7a3bb0dc..0c874f98 100644 --- a/src/components/NavBar.astro +++ b/src/components/NavBar.astro @@ -33,6 +33,7 @@ import { Icon } from 'astro-icon/components'; links={[ { name: 'Minimal Typography', url: '/designProject' }, { name: 'Old Flask Site', url: '/flaskSite' }, + { name: 'GPT Chat', url: '/gpt'} ]} showCaret={true} icon={false} diff --git a/src/pages/gpt.astro b/src/pages/gpt.astro index 5e3718e7..acc99c1f 100644 --- a/src/pages/gpt.astro +++ b/src/pages/gpt.astro @@ -10,6 +10,7 @@ +