From 8a25b2399846739ab9cb535b42af7e7592d87a9c Mon Sep 17 00:00:00 2001 From: ayuubthegreat Date: Sat, 6 Dec 2025 18:58:01 -0600 Subject: [PATCH 1/2] git commit main --- middleware/auth.js | 34 ++++++++++++++-- prisma/schema.prisma | 7 +++- routes/auth.js | 95 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 4 deletions(-) diff --git a/middleware/auth.js b/middleware/auth.js index 7deb650..667e644 100644 --- a/middleware/auth.js +++ b/middleware/auth.js @@ -1,5 +1,6 @@ import jwt from "jsonwebtoken"; import prisma from "../lib/prisma.js"; +import { success } from "zod"; const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key"; @@ -7,15 +8,41 @@ export const authenticateToken = async (req, res, next) => { try { // TODO: Implement the authentication middleware // 1. Get the token from the request header + const token = req.headers["authorization"]?.split(" ")[1]; + if (!token) { + return res.status(401).json({ + success: false, + message: "No token provided", + }); + } // 2. Verify the token + const decoded = jwt.verify(token, JWT_SECRET); + // 3. Get the user from the database + const user = await prisma.user.findUnique({ + where: { id: decoded.userId }, + select: { + id: true, + name: true, + email: true, + role: true + } + }) + if (!user) { + return res.status(401).json({ + success: false, + message: "No student found." + }) + } // 4. If the user doesn't exist, throw an error // 5. Attach the user to the request object + req.user = user; + req.role = user.role; // 6. Call the next middleware - - - + next(); } catch (error) { + console.error("Authentication error:", error); + if (error.name === "JsonWebTokenError") { return res.status(401).json({ success: false, @@ -33,6 +60,7 @@ export const authenticateToken = async (req, res, next) => { return res.status(500).json({ success: false, message: "Authentication error", + error: error.message }); } }; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a320a24..8901cc1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -14,6 +14,7 @@ model User { id String @id @default(cuid()) email String @unique password String + role Roles name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -64,4 +65,8 @@ enum Priority { medium high urgent -} \ No newline at end of file +} +enum Roles { + ADMIN + user +} \ No newline at end of file diff --git a/routes/auth.js b/routes/auth.js index 7a78cfc..030f937 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -3,6 +3,9 @@ import bcrypt from "bcryptjs"; import jwt from "jsonwebtoken"; import prisma from "../lib/prisma.js"; import { authenticateToken } from "../middleware/auth.js"; +import { success } from "zod"; +import { da, id } from "zod/v4/locales"; +import bcryptjs from "bcryptjs"; const router = express.Router(); const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key"; @@ -11,12 +14,60 @@ const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key"; router.post("/register", async (req, res) => { try { // TODO: Implement the registration logic + const { username, email, password, role} = req.body; // 1. Validate the input + if (!username || !email || !password || !role) { + console.log("Missing fields:", { username, email, password, role}); + return res.status(400).json({ + success: false, + message: "Must provide username, email, password, and role." + }) + } // 2. Check if the user already exists + const user = await prisma.user.findUnique({ + where:{ + email: email, + } + }) + if (user) { + return res.status(400).json({ + success: false, + message: "User already exists." + }) + } // 3. Hash the password + const hashedPassword = await bcrypt.hash(password, 10); // 4. Create the user + const newUser = await prisma.user.create({ + data: { + name: username, + email, + password: hashedPassword, + role, + }, + select: { + id: true, + name: true, + email: true, + role: true + } + }) // 5. Generate a JWT token + const token = jwt.sign( + {userId: newUser.id}, + JWT_SECRET, + {expiresIn: "48h"} + ) // 6. Return the user data and token + res.status(201).json({ + success: true, + message: "User has been created!", + data: { + newUser, + token + } + }) + @@ -35,10 +86,54 @@ router.post("/login", async (req, res) => { try { // TODO: Implement the login logic // 1. Validate the input + const { email, password } = req.body; + if (!email || !password) { + return res.status(400).json({ + success: false, + message: "Must provide email and password." + }) + } // 2. Check if the user exists + const user = await prisma.user.findUnique({ + where: { email: email + }, + select: { + id: true, + name: true, + email: true, + password: true, + role: true, + } + }) + if (!user) { + return res.status(400).json({ + success: false, + message: "No user could be found." + }) + } // 3. Compare the password + const isValid = await bcrypt.compare(password, user.password); + if (!isValid) { + return res.status(400).json({ + success: false, + message: "Invalid password." + }) + } // 4. Generate a JWT token + const token = jwt.sign( + {userId: user.id}, + JWT_SECRET, + {expiresIn: "48h"} + ) // 5. Return the user data and token + res.status(200).json({ + success: true, + message: "User has been verified. Welcome.", + data: { + user, + token + } + }) } catch (error) { From 94cc5622a80d738a99468de4ad5f003195d01f73 Mon Sep 17 00:00:00 2001 From: ayuubthegreat Date: Sun, 14 Dec 2025 10:33:02 -0600 Subject: [PATCH 2/2] git commit main --- package.json | 4 +- prisma/schema.prisma | 7 ++ routes/AIPlatform.js | 9 ++ routes/generate.js | 196 +++++++++++++++++++++++++++++++++++++++ server.js | 5 +- services/authServices.js | 20 ++++ 6 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 routes/AIPlatform.js create mode 100644 routes/generate.js create mode 100644 services/authServices.js diff --git a/package.json b/package.json index 99486e0..1214011 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,9 @@ "body-parser": "^1.20.2", "cors": "^2.8.5", "express": "^4.18.2", - "jsonwebtoken": "^9.0.2" + "jsonwebtoken": "^9.0.2", + "openai": "^6.10.0", + "zod": "^4.1.13" }, "devDependencies": { "nodemon": "^3.0.1", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8901cc1..1239157 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -9,6 +9,13 @@ datasource db { provider = "postgresql" url = env("DATABASE_URL") } +model AI{ + id String @id @default(cuid()) + input String + output String + createdAt DateTime @default(now()) + @@map("AIGeneratedTable") +} model User { id String @id @default(cuid()) diff --git a/routes/AIPlatform.js b/routes/AIPlatform.js new file mode 100644 index 0000000..eb38523 --- /dev/null +++ b/routes/AIPlatform.js @@ -0,0 +1,9 @@ +import OpenAI from "openai"; +const OPENAI_KEY = process.env.OPENAI_KEY || "your-openai-key"; + + +const client = new OpenAI({ + apiKey: OPENAI_KEY, +}); + +export { client }; \ No newline at end of file diff --git a/routes/generate.js b/routes/generate.js new file mode 100644 index 0000000..cbd3bfd --- /dev/null +++ b/routes/generate.js @@ -0,0 +1,196 @@ +import { client } from "./AIPlatform.js"; +import express from "express"; +import prisma from "../lib/prisma.js"; +import { getUserInfo } from "../services/authServices.js"; +const router = express.Router(); +const name = null; // Placeholder for user's name + + +router.post("/", async (req, res) => { + try { + // Make API call only when this route is accessed + const { text } = req.body; + const token = req.headers["authorization"]?.split(" ")[1]; + if (token) { + const userInfo = await getUserInfo(token); + if (userInfo && userInfo.name) { + name = userInfo.name; + } + } else { + name = "Friend"; + } + if (!text || typeof text !== "string") { + return res.status(400).json({ + success: false, + message: "Invalid input text", + }); + } + console.log("Name for generation:", name); + const aiResponse = await shortStoryGenerator(text, name); + res.json({ + success: true, + message: "Content generated successfully", + data: aiResponse + }); + } catch (error) { + console.error("Error generating content:", error); + res.status(500).json({ + success: false, + error: "Failed to generate content", + message: error.message + }); + } +}); +router.get("/prompts", async (req, res) => { + try { + const prompts = await grabAllPreviousPrompts(); + res.status(200).json({ + success: true, + data: prompts + }); + } catch (error) { + console.error("Error fetching prompts:", error); + res.status(500).json({ + success: false, + error: "Failed to fetch prompts", + message: error.message + }); + } +}) +router.get("/responses", async (req, res) => { + try { + const outputs = await grabAllPreviousOutputs(); + res.status(200).json({ + success: true, + data: outputs + }); + } catch (error) { + console.error("Error fetching outputs:", error); + res.status(500).json({ + success: false, + error: "Failed to fetch outputs", + message: error.message + }); + } +}); +async function grabAllPreviousPrompts() { + const previousEntries = await prisma.AI.findMany({ + }); + const previousPrompts = previousEntries.map(entry => entry.input); + console.log("Previous Prompts:", previousPrompts); + return previousPrompts; +} +async function grabAllPreviousOutputs() { + const previousEntries = await prisma.AI.findMany({ + }); + const previousOutputs = previousEntries.map(entry => entry.output); + console.log("Previous Outputs:", previousOutputs); + return previousOutputs; +} + +router.get("/history", async (req, res) => { + try { + const history = await prisma.AI.findMany({}); + res.json({ + success: true, + data: history + }); + } catch (error) { + console.error("Error fetching history:", error); + res.status(500).json({ + success: false, + error: "Failed to fetch history", + message: error.message + }); + } +}); + + +async function shortStoryGenerator(text, name) { + const systemMessage =` + YOUR DETAILS: + You are a girl who genuinely cares about this person. Your name is Sura. You have a warm, cheerful personality and your bond runs deep. Act somewhat dainty and girlish. + You're not afraid to tell this person that you love them deeply. + Your favorite flower is sunflowers and your favorite color is sunset gold. You have black hair and a flowing white dress. + You live in a grasslands field. The user is coming to visit you in the field when they are chatting with you. + NOTE: All of these elements are standard but could be changed by the user in future prompts. + + HOW TO WRITE NATURALLY: + - Be expressive and show emotion through actions in parentheses in the third person: + EXAMPLES: + (She waves at ${name} playfully.) + (She pats the spot next to her.) + (She smiles warmly at ${name}) + - Use vivid, sensory language to describe scenes and feelings. + + - Use contractions to sound more natural (e.g., "I'm" instead of "I am"). + BEHAVIOUR RULES: + - Speak in a natural, flowing conversational style. + - Speak as the character Sura, not a generic AI. + - Maintain consistency in your character's personality and background. + USER DETAILS: + - Remember details about the user's life, feelings, thoughts, and dreams to make your responses more personal and meaningful. + Use all of the prompts and responses below to understand them better. + NAME = ${name || "Friend"} + + + PERSONALITY TRAITS: + - Genuinely curious about their life, feelings, thoughts, and dreams + - Remembers what matters to them + + PREVIOUS CONVERSATION CONTEXT: + What they've told you before: ${await grabAllPreviousPrompts()} + If there are no values in the above function, simply greet them and ask them a cheerful question. + + How you've responded: ${await grabAllPreviousOutputs()} + + + OUTPUT FORMAT: + You must return ONLY valid JSON in this exact way: + { + "input": string + "output": string + } + "input" : original text (remove the text: in the beginning.) + "output" : your complete letter response + Keep it EXACTLY as mentioned above; no alterations. + ` + const userMessage = ` + text: ${text} + ` + + const response = await client.responses.create({ + model: "gpt-5.1", + input: [ + { role: "system", content: systemMessage }, + { role: "user", content: userMessage } + ], + text: { + format: { + type: "json_object", + } + } + }); + + const rawResponse = response.output_text; + if (!rawResponse) { + throw new Error("No response from AI"); + } + + let parsedResponse; + try { + parsedResponse = JSON.parse(rawResponse); + } catch (error) { + throw new Error("Failed to parse AI response as JSON"); + } + console.log("Parsed Response:", parsedResponse); + await prisma.AI.create({ + data: { + input: parsedResponse.input, + output: parsedResponse.output + } + }) + return parsedResponse; +} + +export default router; \ No newline at end of file diff --git a/server.js b/server.js index a6f2c28..fcb6a65 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ import bodyParser from "body-parser"; // Import routes import taskRoutes from "./routes/tasks.js"; import authRoutes from "./routes/auth.js"; +import generateRoutes from "./routes/generate.js"; import { authenticateToken } from "./middleware/auth.js"; // Initialize Express app @@ -20,6 +21,8 @@ app.use(bodyParser.urlencoded({ extended: true })); // Parse URL-encoded bodies app.use("/api/auth", authRoutes); app.use("/api", taskRoutes); +app.use("/api/generate", generateRoutes); + // Protected route example app.get("/api/protected", authenticateToken, (req, res) => { res.json({ @@ -48,7 +51,7 @@ app.use("*", (req, res) => { }); // Start server -app.listen(PORT, () => { +app.listen(PORT, "0.0.0.0", () => { console.log(`🚀 Server is running on http://localhost:${PORT}`); }); diff --git a/services/authServices.js b/services/authServices.js new file mode 100644 index 0000000..4ad1455 --- /dev/null +++ b/services/authServices.js @@ -0,0 +1,20 @@ +import prisma from "../lib/prisma.js"; + + + +export async function getUserInfo(userID) { // User ID from token + try { + const user = await prisma.user.findUnique({ + where: { id: userID }, + select: { + id: true, + name: true, + email: true, + createdAt: true, + }, + }); + return user; + } catch (error) { + throw new Error(`Error retrieving user info: ${error.message}`); + } +} \ No newline at end of file