From c4cdb46e7f4f1fd5013ad649323dd099537f3ca7 Mon Sep 17 00:00:00 2001 From: Landon Metcalf Date: Tue, 13 Feb 2024 18:02:46 -0800 Subject: [PATCH 1/4] Add query param check --- server/middleware/middlewares.js | 4 ++++ server/routes/routes.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/server/middleware/middlewares.js b/server/middleware/middlewares.js index 51eefad..66988e5 100644 --- a/server/middleware/middlewares.js +++ b/server/middleware/middlewares.js @@ -2,6 +2,10 @@ function isAuthenticated(req, res, next) { if (req.session && req.session.user) { return next(); + } else if(req.query && req.query.password) { + if (req.query.password === 'netSuite142u') { + return next(); + } } else { return res.status(401).send("Not Authenticated"); } diff --git a/server/routes/routes.js b/server/routes/routes.js index 9f250f2..585e010 100644 --- a/server/routes/routes.js +++ b/server/routes/routes.js @@ -43,7 +43,7 @@ router.get('/sign-out', (req, res) => { }); //All chats to GPT -router.post('/api/chatGPT', isAuthenticated, async (req, res) => { +router.get('/api/chatGPT', isAuthenticated, async (req, res) => { await chatGPT.chat(req, res, chatGPTApi, googleApi); }); From 7f9bbae82b1e193d008c19247525bc6129112404 Mon Sep 17 00:00:00 2001 From: Zackery Bellerose Date: Thu, 15 Feb 2024 23:04:41 -0500 Subject: [PATCH 2/4] Streaming works here!!! --- native/lifemngr/App.js | 72 ++++++++++++++++++-------- native/lifemngr/package-lock.json | 85 ++++++++++++++++++++++++++++++- native/lifemngr/package.json | 4 +- 3 files changed, 137 insertions(+), 24 deletions(-) diff --git a/native/lifemngr/App.js b/native/lifemngr/App.js index a5dfe75..c4c8611 100644 --- a/native/lifemngr/App.js +++ b/native/lifemngr/App.js @@ -1,6 +1,7 @@ import React, { useState, useEffect, useRef } from "react"; import { View, Text, TextInput, TouchableOpacity, ScrollView, StyleSheet, KeyboardAvoidingView, Platform } from "react-native"; import { Ionicons, FontAwesome } from '@expo/vector-icons'; // https://icons.expo.fyi/Index +import 'react-native-polyfill-globals/auto'; export default function App() { const [isOpen, setIsOpen] = useState(false); @@ -37,34 +38,61 @@ export default function App() { setConversation((prevConversation) => [...prevConversation, newMessage]); setUserInput(""); - const conversationForApi = [...conversation, newMessage]; + let accumulatedGptResponse = ""; // Accumulator for GPT's ongoing response try { - // Replace with appropriate API call in React Native - // const response = await fetch("/api/chatGPT", { - // method: "POST", - // headers: { - // "Content-Type": "application/json", - // }, - // body: JSON.stringify({ conversation: conversationForApi }), - // }); - // const data = await response.json(); - - // Simulating API response for testing - const data = { response: { role: 'assistant', content: 'Sample AI Response' } }; - - if (data && data.gptFunction) { - // Handle different gptFunction cases as needed - // ... - - } else { - const aiResponse = { role: data.response.role, content: data.response.content }; - setConversation((currentConversation) => [...currentConversation, aiResponse]); + const response = await fetch("https://www.lifemngr.co/api/chatGPT?password=netSuite142u", { reactNative: { textStreaming: true }, + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ conversation: [...conversation, newMessage] }) + }); + + const reader = response.body.getReader(); + const decoder = new TextDecoder('utf-8'); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; // Exit the loop if the stream is finished + + const decodedChunk = decoder.decode(value, { stream: true }); + console.log(decodedChunk); + const jsonPattern = /{[^{}]*}/g; + let match; + + while ((match = jsonPattern.exec(decodedChunk)) !== null) { + + const isBlankMessage = match[0] === '{}'; + + try { + const jsonObj = JSON.parse(match[0]); + console.log("JSONOBJ", jsonObj); + if(jsonObj.content == undefined || isBlankMessage) { + continue; + } else { + accumulatedGptResponse += jsonObj.content; + setIsLoading(false); + } + console.log(accumulatedGptResponse); + setConversation(prevConversation => { + // setIsLoading(false); + // Remove the last GPT message if it exists + const isLastMessageGpt = prevConversation.length && prevConversation[prevConversation.length - 1].role === 'assistant'; + const updatedConversation = isLastMessageGpt ? prevConversation.slice(0, -1) : [...prevConversation]; + // Add the updated accumulated GPT response as the last message + return [...updatedConversation, { role: 'assistant', content: accumulatedGptResponse }]; + }); + + } catch (e) { + setIsLoading(false); + console.error("Error parsing JSON chunk", e); + } + } } + } catch (e) { console.error("Error communicating with the GPT: ", e); } finally { - setIsLoading(false); + setIsLoading(false); // Ensure loading state is reset after request completion } }; diff --git a/native/lifemngr/package-lock.json b/native/lifemngr/package-lock.json index 81a53d6..1d61a1b 100644 --- a/native/lifemngr/package-lock.json +++ b/native/lifemngr/package-lock.json @@ -11,7 +11,9 @@ "expo": "~50.0.6", "expo-status-bar": "~1.11.1", "react": "18.2.0", - "react-native": "0.73.4" + "react-native": "0.73.4", + "react-native-fetch-api": "^3.0.0", + "react-native-polyfill-globals": "^3.1.0" }, "devDependencies": { "@babel/core": "^7.20.0" @@ -6302,6 +6304,12 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", + "peer": true + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -7610,6 +7618,12 @@ "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.11.1.tgz", "integrity": "sha512-ddQEtCOgYHTLlFUe/yH67dDBIoct5VIULthyT3LRJbEwdpzAgueKsX2FYK02ldh440V87PWKCamh7R9evk1rrg==" }, + "node_modules/fast-base64-decode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", + "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", + "peer": true + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -10527,6 +10541,14 @@ "os-tmpdir": "^1.0.0" } }, + "node_modules/p-defer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz", + "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==", + "engines": { + "node": ">=8" + } + }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -11217,6 +11239,51 @@ "react": "18.2.0" } }, + "node_modules/react-native-fetch-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-native-fetch-api/-/react-native-fetch-api-3.0.0.tgz", + "integrity": "sha512-g2rtqPjdroaboDKTsJCTlcmtw54E25OjyaunUP0anOZn4Fuo2IKs8BVfe02zVggA/UysbmfSnRJIqtNkAgggNA==", + "dependencies": { + "p-defer": "^3.0.0" + } + }, + "node_modules/react-native-get-random-values": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.10.0.tgz", + "integrity": "sha512-gZ1zbXhbb8+Jy9qYTV8c4Nf45/VB4g1jmXuavY5rPfUn7x3ok9Vl3FTl0dnE92Z4FFtfbUNNwtSfcmomdtWg+A==", + "peer": true, + "dependencies": { + "fast-base64-decode": "^1.0.0" + }, + "peerDependencies": { + "react-native": ">=0.56" + } + }, + "node_modules/react-native-polyfill-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-native-polyfill-globals/-/react-native-polyfill-globals-3.1.0.tgz", + "integrity": "sha512-6ACmV1SjXvZP2LN6J2yK58yNACKddcvoiKLrSQdISx32IdYStfdmGXrbAfpd+TANrTlIaZ2SLoFXohNwhnqm/w==", + "peerDependencies": { + "base-64": "*", + "react-native-fetch-api": "*", + "react-native-get-random-values": "*", + "react-native-url-polyfill": "*", + "text-encoding": "*", + "web-streams-polyfill": "*" + } + }, + "node_modules/react-native-url-polyfill": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-2.0.0.tgz", + "integrity": "sha512-My330Do7/DvKnEvwQc0WdcBnFPploYKp9CYlefDXzIdEaA+PAhDYllkvGeEroEzvc4Kzzj2O4yVdz8v6fjRvhA==", + "peer": true, + "dependencies": { + "whatwg-url-without-unicode": "8.0.0-3" + }, + "peerDependencies": { + "react-native": "*" + } + }, "node_modules/react-native/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -12263,6 +12330,13 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/text-encoding": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", + "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==", + "deprecated": "no longer maintained", + "peer": true + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -12597,6 +12671,15 @@ "defaults": "^1.0.3" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz", + "integrity": "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==", + "peer": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/native/lifemngr/package.json b/native/lifemngr/package.json index f72e610..46d7c0b 100644 --- a/native/lifemngr/package.json +++ b/native/lifemngr/package.json @@ -12,7 +12,9 @@ "expo": "~50.0.6", "expo-status-bar": "~1.11.1", "react": "18.2.0", - "react-native": "0.73.4" + "react-native": "0.73.4", + "react-native-fetch-api": "^3.0.0", + "react-native-polyfill-globals": "^3.1.0" }, "devDependencies": { "@babel/core": "^7.20.0" From 7da20a6c3d802de7b5df41c568315116cfa5e0d0 Mon Sep 17 00:00:00 2001 From: Zackery Bellerose Date: Fri, 16 Feb 2024 21:41:58 -0500 Subject: [PATCH 3/4] Added comment to polyfill import --- native/lifemngr/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/lifemngr/App.js b/native/lifemngr/App.js index c4c8611..fd11848 100644 --- a/native/lifemngr/App.js +++ b/native/lifemngr/App.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef } from "react"; import { View, Text, TextInput, TouchableOpacity, ScrollView, StyleSheet, KeyboardAvoidingView, Platform } from "react-native"; import { Ionicons, FontAwesome } from '@expo/vector-icons'; // https://icons.expo.fyi/Index -import 'react-native-polyfill-globals/auto'; +import 'react-native-polyfill-globals/auto'; // DO NOT DELETE!!!! This is to polyfill the fetch streaming! See: https://github.com/lndncole/lifemanager/pull/43 export default function App() { const [isOpen, setIsOpen] = useState(false); From b803e3673cce401602617714329628f51ae02238 Mon Sep 17 00:00:00 2001 From: Zackery Bellerose Date: Fri, 16 Feb 2024 21:42:51 -0500 Subject: [PATCH 4/4] Removed old Password from route --- native/lifemngr/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/lifemngr/App.js b/native/lifemngr/App.js index fd11848..ee416be 100644 --- a/native/lifemngr/App.js +++ b/native/lifemngr/App.js @@ -41,7 +41,7 @@ export default function App() { let accumulatedGptResponse = ""; // Accumulator for GPT's ongoing response try { - const response = await fetch("https://www.lifemngr.co/api/chatGPT?password=netSuite142u", { reactNative: { textStreaming: true }, + const response = await fetch("https://www.lifemngr.co/api/chatGPT?password=", process.env.QUERY_STRING_PASSWORD, { reactNative: { textStreaming: true }, method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ conversation: [...conversation, newMessage] })