feature/AI feature updated to accept user input

This commit is contained in:
nicoagostini committed 2025-05-14 11:21:10 -07:00
1 parent 206b31e785
commit 50e2d95fda
3 files changed
+47 -34

No files matched your search

+7 -15
View File
@@ -101,18 +101,16 @@ module.exports = (middleware, users, plans, assets) => {
try { try {
const userPlansFromDB = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray(); const userPlansFromDB = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray();
// Use a for...of loop for proper async/await behavior in series for updates
for (const plan of userPlansFromDB) { for (const plan of userPlansFromDB) {
const percentage = await calculatePlanProgress(plan, assets, req.session.user._id); const percentage = await calculatePlanProgress(plan, assets, req.session.user._id);
await updatePlanProgressInDB(plan._id, percentage, plans); // Pass the 'plans' collection await updatePlanProgressInDB(plan._id, percentage, plans);
} }
// Re-fetch plans to get updated progress for rendering
const updatedUserPlans = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray(); const updatedUserPlans = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray();
res.render('plans', { res.render('plans', {
user: req.session.user, user: req.session.user,
plans: updatedUserPlans, // Send the most up-to-date plans plans: updatedUserPlans,
geoData: req.session.geoData geoData: req.session.geoData
}); });
} catch (err) { } catch (err) {
@@ -142,16 +140,9 @@ module.exports = (middleware, users, plans, assets) => {
return res.status(status.NotFound).redirect('/plans'); return res.status(status.NotFound).redirect('/plans');
} }
// The plan.progress should be up-to-date from the database as it was updated in the /plans route
// or when assets/plans are modified. If an immediate recalculation for this specific view is absolutely needed,
// (e.g., if assets were modified without an immediate plan progress update elsewhere),
// you could do it here:
// const currentProgress = await calculatePlanProgress(plan, assets, req.session.user._id);
// plan.progress = currentProgress; // This would only update the 'plan' object for this render, not in DB
res.render('planDetail', { res.render('planDetail', {
user: req.session.user, user: req.session.user,
plan: plan, // This plan object will have the progress from the database plan: plan,
geoData: req.session.geoData, geoData: req.session.geoData,
assets: userAssets, assets: userAssets,
suggestions: await suggestions.generateSuggestions(), suggestions: await suggestions.generateSuggestions(),
@@ -218,9 +209,10 @@ module.exports = (middleware, users, plans, assets) => {
} }
}); });
router.get('/pun', async (req, res) => { router.post('/fact', async (req, res) => {
const pun = await suggestions.generatePun(); const factInput = req.body.fact;
return res.status(status.Ok).json({ pun }); const fact = await suggestions.generateFact(factInput);
return res.status(status.Ok).json({ fact });
}); });
router.get('/more', (req, res) => { router.get('/more', (req, res) => {
+3 -3
View File
@@ -2,10 +2,10 @@ const { GoogleGenAI } = require("@google/genai");
const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY }); const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY });
async function generatePun() { async function generateFact(factInput) {
const response = await ai.models.generateContent({ const response = await ai.models.generateContent({
model: "gemini-2.0-flash", model: "gemini-2.0-flash",
contents: "Return a funny pun about investments, answer the pun only, no additional text.", contents: `Generate a concise investment fact about "${factInput}". If "${factInput}" is not directly investment-related, provide a general, useful investment fact instead. Deliver only the fact itself, with no extra text or explanation.`,
}); });
return response.text; return response.text;
} }
@@ -19,6 +19,6 @@ async function generateSuggestions() {
} }
module.exports = { module.exports = {
generatePun, generateFact,
generateSuggestions generateSuggestions
}; };
+37 -16
View File
@@ -1,7 +1,14 @@
<div data-dial-init class="fixed end-6 bottom-20 group"> <div class="fixed end-6 bottom-20 group">
<button type="button" id="punButton" class="flex items-center justify-center text-white bg-blue-700 rounded-full w-14 h-14 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700 focus:ring-4 focus:ring-blue-300 focus:outline-none dark:focus:ring-blue-800"> <div id="factMenu" class="absolute right-0 bottom-full mb-2 hidden">
<div id="factContainer" class="bg-white p-4 rounded-lg shadow-md dark:bg-gray-700 w-64">
<p class="mb-2 text-sm text-gray-700 dark:text-gray-300">Insert the kind of short fact you would like to know more about:</p>
<input type="text" id="factInput" placeholder="Enter your pun here" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-600 dark:border-gray-500 dark:text-white dark:placeholder-gray-400">
<button type="button" id="factSubmitButton" class="mt-3 w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-700">Submit</button>
</div>
</div>
<button type="button" id="factButton" class="flex items-center justify-center text-white bg-blue-700 rounded-full w-14 h-14 hover:bg-blue-800 dark:bg-blue-600 dark:hover:bg-blue-700 focus:ring-4 focus:ring-blue-300 focus:outline-none dark:focus:ring-blue-800">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>
<span class="sr-only">Get a Pun</span> <span class="sr-only">Get a Fact</span>
</button> </button>
</div> </div>
@@ -13,21 +20,35 @@
</div> </div>
</footer> </footer>
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script> <script>
const punButton = document.getElementById("punButton"); const factButton = document.getElementById("factButton");
punButton.addEventListener("click", () => { const factMenu = document.getElementById("factMenu");
fetch("/pun") const factInput = document.getElementById("factInput");
.then(response => response.json()) const factSubmitButton = document.getElementById("factSubmitButton");
.then(data => {
Swal.fire('Here is a pun!', data.pun, 'success'); factButton.addEventListener("click", () => {
}) factMenu.classList.toggle("hidden");
.catch(error => { });
console.error("Error fetching pun:", error); factSubmitButton.addEventListener("click", () => {
Swal.fire('Error fetching pun', 'Please try again later', 'error'); fetch("/fact", {
}); method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
fact: factInput.value,
}),
})
.then(response => response.json())
.then(data => {
Swal.fire('Here is a fact!', data.fact, 'success');
})
.catch(error => {
console.error("Error fetching fact:", error);
Swal.fire('Error fetching fact', 'Please try again later', 'error');
});
}); });
</script> </script>
</body> </body>
</html> </html>