From a6b733d65cfed9d71604b10cbd9370cbf4ca7406 Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Sat, 30 Nov 2024 12:18:38 -0700 Subject: [PATCH 1/8] work on ai title suggestion (cherry picked from commit a65792649cf767e6291fa9a3fc1c1ac667fbcefe) --- package-lock.json | 170 ++++++++++++++++++++++++++++++++++++++- package.json | 1 + src/Odyssey/FetchName.js | 48 +++++++++++ src/Odyssey/Odyssey.js | 9 +++ src/Odyssey/SharePage.js | 20 +++-- 5 files changed, 238 insertions(+), 10 deletions(-) create mode 100644 src/Odyssey/FetchName.js diff --git a/package-lock.json b/package-lock.json index 426a028..5dc6c53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "html2canvas": "1.0.0", "moment": "^2.30.1", "node-fetch": "^3.3.2", + "openai": "^4.73.1", "react": "^18.2.0", "react-datepicker": "^4.24.0", "react-dom": "^18.2.0", @@ -4906,6 +4907,28 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/node-forge": { "version": "1.3.11", "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", @@ -5437,6 +5460,17 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "deprecated": "Use your platform's native atob() and btoa() methods instead" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5535,6 +5569,17 @@ "node": ">= 6.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -8764,6 +8809,14 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -9366,6 +9419,31 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formdata-node/node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -10052,6 +10130,14 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -13742,6 +13828,77 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openai": { + "version": "4.73.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.73.1.tgz", + "integrity": "sha512-nWImDJBcUsqrhy7yJScXB4+iqjzbUEgzfA3un/6UnHFdwWhjX24oztj69Ped/njABfOdLcO/F7CeWTI5dt8Xmg==", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.67", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.67.tgz", + "integrity": "sha512-wI8uHusga+0ZugNp0Ol/3BqQfEcCCNfojtO6Oou9iVNGPTL6QNSdnUdqq85fRgIorLhLMuPIKpsN98QE9Nh+KQ==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/openai/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/openai/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -17934,16 +18091,16 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { @@ -17965,6 +18122,11 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", diff --git a/package.json b/package.json index 9190d63..5b26519 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "html2canvas": "1.0.0", "moment": "^2.30.1", "node-fetch": "^3.3.2", + "openai": "^4.73.1", "react": "^18.2.0", "react-datepicker": "^4.24.0", "react-dom": "^18.2.0", diff --git a/src/Odyssey/FetchName.js b/src/Odyssey/FetchName.js new file mode 100644 index 0000000..fff8998 --- /dev/null +++ b/src/Odyssey/FetchName.js @@ -0,0 +1,48 @@ +const { AzureOpenAI } = require("openai"); +// You will need to set these environment variables or edit the following values +const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; +const apiKey = process.env["AZURE_OPENAI_API_KEY"] || ""; +const apiVersion = "2024-05-01-preview"; +const deployment = "gpt-4o"; //This must match your deployment name. + +export const FetchName = async (concerts) => { + const client = new AzureOpenAI({ endpoint, apiKey, apiVersion, deployment }); + + let inputstring = concerts.map(concert => JSON.stringify(concert)).join(', '); + const result = await client.chat.completions.create({ + response_format:{ "type": "json_object" }, + messages: [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: inputstring }, + ], + model: "", + }).catch((err) => { + console.error("The sample encountered an error:", err); + }); + ; + + for (const choice of result.choices) { + console.log(choice.message); + } + + + + const response = await fetch( + `${REACT_APP_AI_URL}/GetArtistsByName/${artistName}`, + { + method: "GET", + headers: { + "content-type": "application/json;charset=utf-8", + }, + } + ); + console.log(`response status code: ${response.status}`); + if (response.status === 200) { + let resJson = await response.json(); + console.log(`artist count: ${resJson.length}`); + resJson = resJson.filter((value) => value.images.length > 0); + console.log(`artist count after removing artists with no profile picture: ${resJson.length}`); + return resJson; + } + return; +}; diff --git a/src/Odyssey/Odyssey.js b/src/Odyssey/Odyssey.js index 0bc8b97..17da650 100644 --- a/src/Odyssey/Odyssey.js +++ b/src/Odyssey/Odyssey.js @@ -31,7 +31,16 @@ function transformSpecificChildKeys(obj, targetKey) { } } +function GenerateAI(concerts) +{ + //send a request to openAI + //attach the conerts, but strip the GPS data, that is not very useful for suggesting trip titles + // New list with only 'title', 'artist', and location fields + const newList = concerts.map(({ title, artist, location }) => ({ title, artist, venue: location.name, city: location.address })); + // now make a request and send it to open AI + +} const Odyssey = ({ diff --git a/src/Odyssey/SharePage.js b/src/Odyssey/SharePage.js index fcd2e97..94f7016 100644 --- a/src/Odyssey/SharePage.js +++ b/src/Odyssey/SharePage.js @@ -4,7 +4,7 @@ import Map from "./map"; import { useLoadScript } from "@react-google-maps/api" import SharePageList from './SharePageList'; -const SharePage = ({ concerts, userLocation, mapStyle, setPosterName }) => { +const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, AIGenerate }) => { // Your component logic goes here const { isLoaded } = useLoadScript({ googleMapsApiKey: process.env.REACT_APP_GCP_KEY, // Add your API key @@ -18,11 +18,19 @@ const SharePage = ({ concerts, userLocation, mapStyle, setPosterName }) => { return ( {isLoaded ? : null} - setPosterName(e.target.value)} /> + + setPosterName(e.target.value)} /> + + From 26c06d494735f29ece07031dcf15211f967a3074 Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Mon, 2 Dec 2024 22:48:49 -0700 Subject: [PATCH 2/8] adjust input data to AI --- src/Odyssey/FetchName.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Odyssey/FetchName.js b/src/Odyssey/FetchName.js index fff8998..e03b4e7 100644 --- a/src/Odyssey/FetchName.js +++ b/src/Odyssey/FetchName.js @@ -1,7 +1,7 @@ const { AzureOpenAI } = require("openai"); // You will need to set these environment variables or edit the following values -const endpoint = process.env["AZURE_OPENAI_ENDPOINT"] || ""; -const apiKey = process.env["AZURE_OPENAI_API_KEY"] || ""; +const endpoint = process.env["AZURE_OPENAI_ENDPOINT"]; +const apiKey = process.env["AZURE_OPENAI_API_KEY"]; const apiVersion = "2024-05-01-preview"; const deployment = "gpt-4o"; //This must match your deployment name. @@ -12,7 +12,7 @@ export const FetchName = async (concerts) => { const result = await client.chat.completions.create({ response_format:{ "type": "json_object" }, messages: [ - { role: "system", content: "You are a helpful assistant." }, + { role: "system", content: "" }, { role: "user", content: inputstring }, ], model: "", From 230ca699e3a226bc7fb06f31152d3b4001739603 Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Tue, 3 Dec 2024 00:16:31 -0700 Subject: [PATCH 3/8] work on ai title generation --- src/Odyssey/FetchName.js | 29 ++++++----------------------- src/Odyssey/Odyssey.js | 15 +++++++-------- src/Odyssey/SharePage.js | 5 +++-- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/Odyssey/FetchName.js b/src/Odyssey/FetchName.js index e03b4e7..2760ce5 100644 --- a/src/Odyssey/FetchName.js +++ b/src/Odyssey/FetchName.js @@ -2,8 +2,9 @@ const { AzureOpenAI } = require("openai"); // You will need to set these environment variables or edit the following values const endpoint = process.env["AZURE_OPENAI_ENDPOINT"]; const apiKey = process.env["AZURE_OPENAI_API_KEY"]; -const apiVersion = "2024-05-01-preview"; -const deployment = "gpt-4o"; //This must match your deployment name. +const instructions = process.env["AI_INSTRUCTIONS"]; +const apiVersion = "2024-08-01-preview"; +const deployment = "gpt-4o-mini"; //This must match your deployment name. export const FetchName = async (concerts) => { const client = new AzureOpenAI({ endpoint, apiKey, apiVersion, deployment }); @@ -12,7 +13,7 @@ export const FetchName = async (concerts) => { const result = await client.chat.completions.create({ response_format:{ "type": "json_object" }, messages: [ - { role: "system", content: "" }, + { role: "system", content: instructions }, { role: "user", content: inputstring }, ], model: "", @@ -22,27 +23,9 @@ export const FetchName = async (concerts) => { ; for (const choice of result.choices) { - console.log(choice.message); + console.log(choice.title); } + return result; - - const response = await fetch( - `${REACT_APP_AI_URL}/GetArtistsByName/${artistName}`, - { - method: "GET", - headers: { - "content-type": "application/json;charset=utf-8", - }, - } - ); - console.log(`response status code: ${response.status}`); - if (response.status === 200) { - let resJson = await response.json(); - console.log(`artist count: ${resJson.length}`); - resJson = resJson.filter((value) => value.images.length > 0); - console.log(`artist count after removing artists with no profile picture: ${resJson.length}`); - return resJson; - } - return; }; diff --git a/src/Odyssey/Odyssey.js b/src/Odyssey/Odyssey.js index b69d97b..d75a7d9 100644 --- a/src/Odyssey/Odyssey.js +++ b/src/Odyssey/Odyssey.js @@ -1,8 +1,8 @@ import React from 'react'; -import { Grid, Button, Stack, Box } from "@mui/material"; +import { Grid, Button, Stack } from "@mui/material"; // Import other components import SharePage from "./SharePage.js"; - +import { FetchName } from './FetchName.js'; function capitalizeFirstChar(str) { return str.charAt(0).toUpperCase() + str.slice(1); @@ -29,15 +29,13 @@ function transformSpecificChildKeys(obj, targetKey) { } } -function GenerateAI(concerts) -{ +function GenerateAI(concerts) { //send a request to openAI //attach the conerts, but strip the GPS data, that is not very useful for suggesting trip titles // New list with only 'title', 'artist', and location fields - const newList = concerts.map(({ title, artist, location }) => ({ title, artist, venue: location.name, city: location.address })); + const newList = concerts.map(({ title, artist, location, date }) => ({ title, artist, date, venue: location.name, city: location.address })); // now make a request and send it to open AI - - + return FetchName(newList); } @@ -103,13 +101,14 @@ const Odyssey = ({ }; return ( - +
diff --git a/src/Odyssey/SharePage.js b/src/Odyssey/SharePage.js index 4752661..da2b993 100644 --- a/src/Odyssey/SharePage.js +++ b/src/Odyssey/SharePage.js @@ -4,7 +4,8 @@ import Map from "./map"; import { useLoadScript } from "@react-google-maps/api" import SharePageList from './SharePageList'; -const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, AIGenerate }) => { + +const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, GenerateAI }) => { // Your component logic goes here const { isLoaded } = useLoadScript({ googleMapsApiKey: process.env.REACT_APP_GCP_KEY, // Add your API key @@ -26,7 +27,7 @@ const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, AIGenerate onChange={(e) => setPosterName(e.target.value)} /> From 4fe6006c48025ed6bd93ac6b8556e5413eb17b83 Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Wed, 4 Dec 2024 18:47:47 -0700 Subject: [PATCH 4/8] ok finally no more compiler errors --- src/App.js | 3 +++ src/Odyssey/FetchName.js | 6 +++--- src/Odyssey/Odyssey.js | 9 ++++++--- src/Odyssey/SharePage.js | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/App.js b/src/App.js index f8e2ec3..d44780f 100644 --- a/src/App.js +++ b/src/App.js @@ -19,6 +19,7 @@ function App() { const [allConcerts, setAllConcerts] = useState([]); const [userLocation, setUserLocation] = useState(null); const [posterName, setPosterName] = useState(""); + const [posterNameSuggestions, setPosterNameSuggestions] = useState([]); const [followedArtists, setFollowedArtists] = useState([]); const [artistName, setArtistName] = useState("Taylor Swift"); const [artistList, setArtistList] = useState([]); @@ -75,6 +76,8 @@ function App() { ({ title, artist, date, venue: location.name, city: location.address })); // now make a request and send it to open AI - return FetchName(newList); + var suggestions = FetchName(newList); + setPosterName(suggestions[0]); } @@ -48,7 +49,9 @@ const Odyssey = ({ startDate, endDate, shareId, - setShareId + setShareId, + posterNameSuggestions, + setPosterNameSuggestions }) => { const handleShareAsLink = async function () { //gather json for artists, map coordinates, share page schedules, concert list, trip name, map style id, start date, end date diff --git a/src/Odyssey/SharePage.js b/src/Odyssey/SharePage.js index da2b993..e5b6185 100644 --- a/src/Odyssey/SharePage.js +++ b/src/Odyssey/SharePage.js @@ -1,5 +1,5 @@ import React from 'react'; -import { Stack, TextField } from '@mui/material'; +import { Stack, TextField, Button } from '@mui/material'; import Map from "./map"; import { useLoadScript } from "@react-google-maps/api" import SharePageList from './SharePageList'; @@ -27,7 +27,7 @@ const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, GenerateAI onChange={(e) => setPosterName(e.target.value)} /> From 5007cd78be88556476de5b9f56a6a6efdeca4bf0 Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Wed, 4 Dec 2024 22:47:02 -0700 Subject: [PATCH 5/8] change button style --- src/Odyssey/SharePage.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Odyssey/SharePage.js b/src/Odyssey/SharePage.js index e5b6185..759297c 100644 --- a/src/Odyssey/SharePage.js +++ b/src/Odyssey/SharePage.js @@ -19,18 +19,19 @@ const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, GenerateAI return ( {isLoaded ? : null} - + setPosterName(e.target.value)} /> - + From 4de23f15298938efdcb531ee138be0e0bf03e802 Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Wed, 4 Dec 2024 22:52:15 -0700 Subject: [PATCH 6/8] dropping OpenAi package from front end --- package-lock.json | 72 ---------------------------------------- package.json | 1 - src/Odyssey/FetchName.js | 48 ++++++++++----------------- 3 files changed, 18 insertions(+), 103 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5dc6c53..bce8f99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,6 @@ "html2canvas": "1.0.0", "moment": "^2.30.1", "node-fetch": "^3.3.2", - "openai": "^4.73.1", "react": "^18.2.0", "react-datepicker": "^4.24.0", "react-dom": "^18.2.0", @@ -13828,77 +13827,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openai": { - "version": "4.73.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.73.1.tgz", - "integrity": "sha512-nWImDJBcUsqrhy7yJScXB4+iqjzbUEgzfA3un/6UnHFdwWhjX24oztj69Ped/njABfOdLcO/F7CeWTI5dt8Xmg==", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - }, - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "zod": "^3.23.8" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, - "node_modules/openai/node_modules/@types/node": { - "version": "18.19.67", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.67.tgz", - "integrity": "sha512-wI8uHusga+0ZugNp0Ol/3BqQfEcCCNfojtO6Oou9iVNGPTL6QNSdnUdqq85fRgIorLhLMuPIKpsN98QE9Nh+KQ==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/openai/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/openai/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/openai/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/openai/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", diff --git a/package.json b/package.json index 5b26519..9190d63 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "html2canvas": "1.0.0", "moment": "^2.30.1", "node-fetch": "^3.3.2", - "openai": "^4.73.1", "react": "^18.2.0", "react-datepicker": "^4.24.0", "react-dom": "^18.2.0", diff --git a/src/Odyssey/FetchName.js b/src/Odyssey/FetchName.js index d369603..00d181b 100644 --- a/src/Odyssey/FetchName.js +++ b/src/Odyssey/FetchName.js @@ -1,31 +1,19 @@ -const { AzureOpenAI } = require("openai"); -// You will need to set these environment variables or edit the following values -const endpoint = process.env.REACT_APP_AZURE_OPENAI_ENDPOINT; -const apiKey = process.env.REACT_APP_AZURE_OPENAI_API_KEY; -const instructions = process.env.REACT_APP_AI_INSTRUCTIONS; -const apiVersion = "2024-08-01-preview"; -const deployment = "gpt-4o-mini"; //This must match your deployment name. - -export const FetchName = async (concerts) => { - const client = new AzureOpenAI({ endpoint, apiKey, apiVersion, deployment }); - - let inputstring = concerts.map(concert => JSON.stringify(concert)).join(', '); - const result = await client.chat.completions.create({ - response_format:{ "type": "json_object" }, - messages: [ - { role: "system", content: instructions }, - { role: "user", content: inputstring }, - ], - model: "", - }).catch((err) => { - console.error("The sample encountered an error:", err); - }); - ; - - for (const choice of result.choices) { - console.log(choice.title); - } - - return result; - +export const FetchName = async (concerts, setPosterName, setPosterNameSuggestions) => { + const response = await fetch( + `${process.env.REACT_APP_BACKEND}/GetTripTitleSuggestion`, + { + method: 'POST', + headers: { + 'content-type': 'application/json;charset=utf-8' + }, + body: JSON.stringify(concerts), + } + ); + console.log(`response status code: ${response.status}`); + if (response.status === 200) { + let resJson = await response.json(); + setPosterName(resJson[0]); + setPosterNameSuggestions(resJson); + } + return; }; From 328f52e24b32452d52809e22f8fc6f6cd0a66ebc Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Thu, 5 Dec 2024 00:20:14 -0700 Subject: [PATCH 7/8] AI Trip title suggestion is working! --- src/App.js | 3 --- src/Odyssey/FetchName.js | 7 +++---- src/Odyssey/Odyssey.js | 17 +++-------------- src/Odyssey/SharePage.js | 31 ++++++++++++++++++++++--------- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/App.js b/src/App.js index d44780f..f8e2ec3 100644 --- a/src/App.js +++ b/src/App.js @@ -19,7 +19,6 @@ function App() { const [allConcerts, setAllConcerts] = useState([]); const [userLocation, setUserLocation] = useState(null); const [posterName, setPosterName] = useState(""); - const [posterNameSuggestions, setPosterNameSuggestions] = useState([]); const [followedArtists, setFollowedArtists] = useState([]); const [artistName, setArtistName] = useState("Taylor Swift"); const [artistList, setArtistList] = useState([]); @@ -76,8 +75,6 @@ function App() { { +export const FetchName = async (concerts) => { const response = await fetch( `${process.env.REACT_APP_BACKEND}/GetTripTitleSuggestion`, { @@ -11,9 +11,8 @@ export const FetchName = async (concerts, setPosterName, setPosterNameSuggestion ); console.log(`response status code: ${response.status}`); if (response.status === 200) { - let resJson = await response.json(); - setPosterName(resJson[0]); - setPosterNameSuggestions(resJson); + let resJson = await response.json(); + return resJson; } return; }; diff --git a/src/Odyssey/Odyssey.js b/src/Odyssey/Odyssey.js index 3b5b5b5..507adca 100644 --- a/src/Odyssey/Odyssey.js +++ b/src/Odyssey/Odyssey.js @@ -2,7 +2,7 @@ import React from 'react'; import { Grid, Button, Stack } from "@mui/material"; // Import other components import SharePage from "./SharePage.js"; -import { FetchName } from './FetchName.js'; + function capitalizeFirstChar(str) { return str.charAt(0).toUpperCase() + str.slice(1); @@ -29,15 +29,6 @@ function transformSpecificChildKeys(obj, targetKey) { } } -function GenerateAI(concerts, setPosterName) { - //send a request to openAI - //attach the conerts, but strip the GPS data, that is not very useful for suggesting trip titles - // New list with only 'title', 'artist', and location fields - const newList = concerts.map(({ title, artist, location, date }) => ({ title, artist, date, venue: location.name, city: location.address })); - // now make a request and send it to open AI - var suggestions = FetchName(newList); - setPosterName(suggestions[0]); -} const Odyssey = ({ @@ -49,9 +40,7 @@ const Odyssey = ({ startDate, endDate, shareId, - setShareId, - posterNameSuggestions, - setPosterNameSuggestions + setShareId }) => { const handleShareAsLink = async function () { //gather json for artists, map coordinates, share page schedules, concert list, trip name, map style id, start date, end date @@ -111,7 +100,7 @@ const Odyssey = ({ userLocation={userLocation} mapStyle={mapStyle} setPosterName={setPosterName} - GenerateAI={GenerateAI} + posterName={posterName} /> diff --git a/src/Odyssey/SharePage.js b/src/Odyssey/SharePage.js index 759297c..5a6c65f 100644 --- a/src/Odyssey/SharePage.js +++ b/src/Odyssey/SharePage.js @@ -3,9 +3,11 @@ import { Stack, TextField, Button } from '@mui/material'; import Map from "./map"; import { useLoadScript } from "@react-google-maps/api" import SharePageList from './SharePageList'; +import { FetchName } from './FetchName.js'; + +const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, posterName }) => { -const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, GenerateAI }) => { // Your component logic goes here const { isLoaded } = useLoadScript({ googleMapsApiKey: process.env.REACT_APP_GCP_KEY, // Add your API key @@ -15,23 +17,34 @@ const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, GenerateAI const concerts1 = concerts.slice(0, middleIndex); const concerts2 = concerts.slice(middleIndex); + const GenerateTripTitle = async function () { + //send a request to openAI + //attach the conerts, but strip the GPS data, that is not very useful for suggesting trip titles + // New list with only 'title', 'artist', and location fields + const newList = concerts.map(({ title, artist, location, date }) => ({ title, artist, date, venue: location.name, city: location.address })); + // now make a request and send it to open AI + var suggestions = await FetchName(newList); + console.log(`poster name is: ${suggestions[0].title}`); + setPosterName(suggestions[0].title); + }; return ( {isLoaded ? : null} - + setPosterName(e.target.value)} /> - + From ca67447fa710124580771b966c9c4aa0e6adb585 Mon Sep 17 00:00:00 2001 From: Sam Bao Date: Thu, 5 Dec 2024 00:49:30 -0700 Subject: [PATCH 8/8] YES! Working title suggestion in front end --- src/App.js | 6 +++++- src/Odyssey/Odyssey.js | 4 ++++ src/Odyssey/SharePage.js | 28 +++++++++++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/App.js b/src/App.js index f8e2ec3..38dccc9 100644 --- a/src/App.js +++ b/src/App.js @@ -19,6 +19,7 @@ function App() { const [allConcerts, setAllConcerts] = useState([]); const [userLocation, setUserLocation] = useState(null); const [posterName, setPosterName] = useState(""); + const [posterNameSuggestions, setPosterNameSuggestions] = useState([]); const [followedArtists, setFollowedArtists] = useState([]); const [artistName, setArtistName] = useState("Taylor Swift"); const [artistList, setArtistList] = useState([]); @@ -82,7 +83,10 @@ function App() { posterName={posterName} startDate={startDate} endDate={endDate} - shareId={shareId} /> + shareId={shareId} + posterNameSuggestions = {posterNameSuggestions} + setPosterNameSuggestions = {setPosterNameSuggestions} + /> } /> diff --git a/src/Odyssey/Odyssey.js b/src/Odyssey/Odyssey.js index 507adca..b90a88c 100644 --- a/src/Odyssey/Odyssey.js +++ b/src/Odyssey/Odyssey.js @@ -40,6 +40,8 @@ const Odyssey = ({ startDate, endDate, shareId, + posterNameSuggestions, + setPosterNameSuggestions, setShareId }) => { const handleShareAsLink = async function () { @@ -101,6 +103,8 @@ const Odyssey = ({ mapStyle={mapStyle} setPosterName={setPosterName} posterName={posterName} + posterNameSuggestions={posterNameSuggestions} + setPosterNameSuggestions={setPosterNameSuggestions} /> diff --git a/src/Odyssey/SharePage.js b/src/Odyssey/SharePage.js index 5a6c65f..8693097 100644 --- a/src/Odyssey/SharePage.js +++ b/src/Odyssey/SharePage.js @@ -5,7 +5,7 @@ import { useLoadScript } from "@react-google-maps/api" import SharePageList from './SharePageList'; import { FetchName } from './FetchName.js'; -const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, posterName }) => { +const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, posterName, posterNameSuggestions, setPosterNameSuggestions }) => { // Your component logic goes here @@ -18,14 +18,24 @@ const SharePage = ({ concerts, userLocation, mapStyle, setPosterName, posterName const concerts2 = concerts.slice(middleIndex); const GenerateTripTitle = async function () { - //send a request to openAI - //attach the conerts, but strip the GPS data, that is not very useful for suggesting trip titles - // New list with only 'title', 'artist', and location fields - const newList = concerts.map(({ title, artist, location, date }) => ({ title, artist, date, venue: location.name, city: location.address })); - // now make a request and send it to open AI - var suggestions = await FetchName(newList); - console.log(`poster name is: ${suggestions[0].title}`); - setPosterName(suggestions[0].title); + + if (posterNameSuggestions.length < 1) { + // send a request to openAI + // attach the conerts, but strip the GPS data, that is not very useful for suggesting trip titles + // New list with only 'title', 'artist', 'venue', 'city' and 'date' fields + console.log("getting new titles"); + const newList = concerts.map(({ title, artist, location, date }) => ({ title, artist, date, venue: location.name, city: location.address })); + // now make a request and send it to open AI + var suggestions = await FetchName(newList); + setPosterNameSuggestions(suggestions.slice(1)); + setPosterName(suggestions[0].title); + } + else + { + setPosterName(posterNameSuggestions[0].title); + setPosterNameSuggestions(posterNameSuggestions=> posterNameSuggestions.slice(1)); + } + }; return (