Skip to content

Commit 9b19b61

Browse files
committed
Revamp README, enhance user model, add animations, and implement Magic Helper feature
1 parent 048896e commit 9b19b61

16 files changed

+321
-108
lines changed

README.md

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,94 @@
1-
```markdown
21
# PythaSpace
32

4-
PythaSpace is a cutting-edge platform for publishing, sharing, and discovering high-quality articles and stories across various domains. It aims to cultivate a vibrant community of writers and readers, promoting intellectual discourse and knowledge exchange.
3+
PythaSpace is a cutting-edge platform designed for publishing, sharing, and discovering high-quality articles and stories across various domains. It aims to foster a vibrant community of writers and readers, promoting intellectual discourse and knowledge exchange.
54

65
## Overview
76

8-
PythaSpace is built with a modern web stack, focusing on a seamless user experience and robust backend services. The architecture includes:
9-
- **Backend**: Node.js with Express framework
10-
- **Database**: MongoDB with Mongoose ORM for data management
11-
- **Frontend**: EJS for templating, Bootstrap for styling, and Vanilla JS for functionality
12-
- **AI Integration**: OpenAI for content moderation and writing assistance
7+
PythaSpace is built with a robust architecture that leverages modern web technologies to deliver an intuitive and seamless user experience. The platform is structured as follows:
138

14-
The project structure is organized as follows:
15-
- **models/**: Mongoose schemas for User and Article
16-
- **routes/**: Express routes for authentication, articles, and API endpoints
17-
- **services/**: Services for AI moderation and LLM requests
18-
- **utils/**: Utility functions for file uploads
19-
- **views/**: EJS templates for rendering pages
20-
- **public/**: Static files including CSS and JavaScript
9+
- **Backend:** Node.js with the Express framework for handling server-side logic.
10+
- **Database:** MongoDB managed with Mongoose ORM for efficient data storage and retrieval.
11+
- **Frontend:** EJS for templating, Bootstrap for responsive design, and Vanilla JS for client-side functionality.
12+
- **AI Integration:** OpenAI for content moderation and writing assistance.
13+
- **Additional Libraries:** bcrypt for password hashing, multer for file uploads, and social-share-js for social media sharing.
14+
15+
The project structure includes:
16+
17+
- **Models:** Mongoose schemas for User, Article, and Comment.
18+
- **Routes:** Express routes for authentication, article management, and API endpoints.
19+
- **Views:** EJS templates for rendering pages.
20+
- **Public:** Static files including CSS, JavaScript, and images.
21+
- **Services:** Helper services for AI interactions and file uploads.
22+
- **Middleware:** Authentication middleware for protecting routes.
2123

2224
## Features
2325

24-
PythaSpace includes the following features:
25-
1. **User Registration and Login**:
26-
- Users can register and log in using their email.
26+
PythaSpace offers a wide range of features to enhance the user experience:
27+
28+
1. **User Registration and Login:**
29+
- Users can register and log in using their email and password.
2730
- Essential for publishing, commenting, and utilizing the AI writer helper.
2831

29-
2. **Article Publishing**:
30-
- Support for multimedia content (images and videos) with specified size and format restrictions.
31-
- AI-powered moderation using OpenAI, with each user's API key stored in their user profile.
32-
- Articles automatically published upon passing AI moderation; issues highlighted otherwise.
32+
2. **Article Publishing:**
33+
- Support for multimedia content (images and videos).
34+
- AI-powered moderation using OpenAI.
35+
- Articles can be saved as drafts or published directly.
36+
- Moderation issues are highlighted for user correction.
3337

34-
3. **Article Organization**:
35-
- Categories: Technology, Science, Health & Wellness, Business & Finance, Arts & Culture, Lifestyle.
36-
- Tags: Specific Topics, Writing Styles, Target Audience, Content Format.
38+
3. **Article Organization:**
39+
- Articles are categorized into Technology, Science, Health & Wellness, Business & Finance, Arts & Culture, and Lifestyle.
40+
- Tagging system for specific topics, writing styles, and content formats.
3741

38-
4. **Commenting System**:
39-
- Single-level comments on articles.
42+
4. **Commenting System:**
43+
- Single-level comments on articles to foster discussions.
4044

41-
5. **Social Sharing**:
42-
- Integration with social-share-js for sharing articles on social media.
45+
5. **Social Sharing:**
46+
- Integration with social-share-js for sharing articles on social media platforms.
4347

44-
6. **AI Writer Helper ("Magic Helper")**:
45-
- Offers writing suggestions based on the title and existing content.
46-
- Utilizes the user's OpenAI API key stored in their profile for generating suggestions.
47-
- Accessible via a modern, intuitive interface with a magic wand icon.
48+
6. **AI Writer Helper ("Magic Helper"):**
49+
- Provides writing suggestions based on the title and existing content.
50+
- Utilizes the user's OpenAI API key for generating suggestions.
4851

4952
## Getting started
5053

5154
### Requirements
5255

53-
To run PythaSpace, you need the following technologies installed on your computer:
56+
To run PythaSpace, ensure you have the following technologies installed on your computer:
57+
5458
- Node.js
5559
- MongoDB (or use a cloud version like MongoDB Atlas)
5660

5761
### Quickstart
5862

59-
1. **Clone the repository**:
60-
```sh
63+
Follow these steps to set up and run the project:
64+
65+
1. **Clone the repository:**
66+
```bash
6167
git clone <repository-url>
6268
cd PythaSpace
6369
```
6470

65-
2. **Install dependencies**:
66-
```sh
71+
2. **Install dependencies:**
72+
```bash
6773
npm install
6874
```
6975

70-
3. **Set up environment variables**:
71-
- Copy `.env.example` to `.env` and fill in the required values:
72-
```sh
73-
cp .env.example .env
74-
```
76+
3. **Set up environment variables:**
77+
- Create a `.env` file in the project root using the provided `.env.example` as a template.
78+
- Populate the `.env` file with your values (e.g., MongoDB URL, session secret).
7579

76-
4. **Start the application**:
77-
```sh
80+
4. **Start the application:**
81+
```bash
7882
npm start
7983
```
8084

81-
5. **Access the application**:
82-
- Open your browser and navigate to `http://localhost:3000`
85+
5. **Access the application:**
86+
- Open your browser and navigate to `http://localhost:3000` to start using PythaSpace.
8387

8488
### License
8589

86-
The project is proprietary (not open source), just output the standard Copyright (c) 2024.
90+
The project is proprietary (not open source), and all rights are reserved.
91+
92+
```
93+
© 2024 PythaSpace.
8794
```

models/User.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,19 @@ const mongoose = require('mongoose');
22
const bcrypt = require('bcrypt');
33

44
const userSchema = new mongoose.Schema({
5-
username: { type: String, unique: true, required: true },
5+
email: { type: String, required: true, unique: true },
66
password: { type: String, required: true },
77
openaiApiKey: {
88
type: String,
99
default: ''
1010
}
1111
});
1212

13-
userSchema.pre('save', function(next) {
14-
const user = this;
15-
if (!user.isModified('password')) return next();
16-
bcrypt.hash(user.password, 10, (err, hash) => {
17-
if (err) {
18-
console.error('Error hashing password:', err);
19-
return next(err);
20-
}
21-
user.password = hash;
22-
next();
23-
});
13+
userSchema.pre('save', async function(next) {
14+
if (this.isModified('password')) {
15+
this.password = await bcrypt.hash(this.password, 10);
16+
}
17+
next();
2418
});
2519

2620
userSchema.virtual('articles', {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"license": "ISC",
1313
"dependencies": {
1414
"@anthropic-ai/sdk": "^0.27.3",
15+
"animate.css": "^4.1.1",
1516
"axios": "^1.7.7",
1617
"bcrypt": "^5.1.1",
1718
"body-parser": "^1.20.2",

public/css/style.css

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,50 @@
1-
/* Placeholder for custom styles */
1+
/* Smooth transitions for all elements */
2+
* {
3+
transition: all 0.3s ease-in-out;
4+
}
5+
6+
/* Hover effect for buttons */
7+
.btn:hover {
8+
transform: translateY(-2px);
9+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
10+
}
11+
12+
/* Animate form inputs on focus */
13+
input:focus, textarea:focus, select:focus {
14+
transform: scale(1.02);
15+
}
16+
17+
/* Animate article cards */
18+
.card {
19+
transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
20+
}
21+
22+
.card:hover {
23+
transform: translateY(-5px);
24+
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
25+
}
26+
27+
/* Animate navigation links */
28+
.nav-link {
29+
position: relative;
30+
overflow: hidden;
31+
}
32+
33+
.nav-link::after {
34+
content: '';
35+
position: absolute;
36+
bottom: 0;
37+
left: 0;
38+
width: 0;
39+
height: 2px;
40+
background-color: currentColor;
41+
transition: width 0.3s ease-in-out;
42+
}
43+
44+
.nav-link:hover::after {
45+
width: 100%;
46+
}
47+
248
body {
349
padding-bottom: 60px;
450
}

public/js/magicHelper.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
document.addEventListener('DOMContentLoaded', function() {
2+
const magicHelperBtn = document.getElementById('magicHelperBtn');
3+
const magicHelperModal = new bootstrap.Modal(document.getElementById('magicHelperModal'));
4+
const magicHelperContent = document.getElementById('magicHelperContent');
5+
6+
magicHelperBtn.addEventListener('click', async function() {
7+
const title = document.getElementById('title').value.trim();
8+
const content = quill.root.innerHTML;
9+
10+
if (!title) {
11+
const errorMessage = document.createElement('span');
12+
errorMessage.textContent = 'Please enter a title before using Magic Helper';
13+
errorMessage.style.color = 'red';
14+
errorMessage.style.marginLeft = '10px';
15+
magicHelperBtn.parentNode.insertBefore(errorMessage, magicHelperBtn.nextSibling);
16+
17+
setTimeout(() => {
18+
errorMessage.remove();
19+
}, 3000);
20+
21+
return;
22+
}
23+
24+
magicHelperContent.innerHTML = '<p>Generating suggestions...</p>';
25+
magicHelperModal.show();
26+
27+
try {
28+
const response = await fetch('/api/articles/magic-helper', {
29+
method: 'POST',
30+
headers: {
31+
'Content-Type': 'application/json',
32+
},
33+
body: JSON.stringify({ title, content }),
34+
});
35+
36+
if (!response.ok) {
37+
throw new Error(`HTTP error! status: ${response.status}`);
38+
}
39+
40+
const data = await response.json();
41+
if (data.error) {
42+
throw new Error(data.error);
43+
}
44+
45+
displaySuggestions(data.suggestions);
46+
} catch (error) {
47+
console.error('Error fetching suggestions:', error);
48+
magicHelperContent.innerHTML = '<p>Error fetching suggestions. Please try again.</p>';
49+
}
50+
});
51+
52+
function displaySuggestions(suggestions) {
53+
let html = '<ol class="animate__animated animate__fadeIn">';
54+
suggestions.forEach((heading) => {
55+
html += `<li><h3 class="animate__animated animate__fadeInLeft">${heading.title}</h3><ol>`;
56+
heading.subHeadings.forEach(subHeading => {
57+
html += `<li><h4 class="animate__animated animate__fadeInLeft animate__delay-1s">${subHeading.title}</h4><ol>`;
58+
subHeading.contentPoints.forEach(point => {
59+
html += `<li class="animate__animated animate__fadeInLeft animate__delay-2s">${point}</li>`;
60+
});
61+
html += '</ol></li>';
62+
});
63+
html += '</ol></li>';
64+
});
65+
html += '</ol>';
66+
magicHelperContent.innerHTML = html;
67+
}
68+
});

routes/api/articleApiRoutes.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
const express = require('express');
22
const router = express.Router();
33
const Article = require('../../models/Article');
4+
const User = require('../../models/User'); // Added to use User model for fetching user's OpenAI API key
45
const { isAuthenticated } = require('../middleware/authMiddleware');
6+
const { sendLLMRequest } = require('../../services/llm');
57

68
// Create a new article
79
router.post('/', isAuthenticated, async (req, res) => {
@@ -89,4 +91,64 @@ router.delete('/:id', isAuthenticated, async (req, res) => {
8991
}
9092
});
9193

94+
// Magic Helper endpoint
95+
router.post('/magic-helper', isAuthenticated, async (req, res) => {
96+
try {
97+
const { title, content } = req.body;
98+
const user = await User.findById(req.user._id);
99+
100+
if (!user.openaiApiKey) {
101+
return res.status(400).json({ error: 'OpenAI API key is required' });
102+
}
103+
104+
const formattedMessage = `Based on the following article title and content, generate 2-3 captivating headings, each with 3-4 sub-headings, and 4-5 killer content ideas for each sub-heading. Format the response as a JSON object with the following structure:
105+
106+
{
107+
"suggestions": [
108+
{
109+
"title": "Captivating Heading",
110+
"subHeadings": [
111+
{
112+
"title": "Engaging Sub-heading",
113+
"contentPoints": [
114+
"Specific and valuable content idea",
115+
"Specific and valuable content idea",
116+
"Specific and valuable content idea",
117+
"Specific and valuable content idea",
118+
"Specific and valuable content idea"
119+
]
120+
},
121+
// Repeat for 3-4 sub-headings
122+
]
123+
},
124+
// Repeat for 2-3 headings
125+
]
126+
}
127+
128+
Ensure that each heading is unique and captivating, each sub-heading is engaging and relevant to its main heading, and each content idea is specific and valuable to the reader. Do not include any numbering or prefixes in the titles or content points.
129+
130+
Title: ${title}
131+
132+
Content: ${content}`;
133+
134+
const response = await sendLLMRequest('openai', 'gpt-3.5-turbo', formattedMessage, user.openaiApiKey);
135+
console.log('Raw AI response:', JSON.stringify(response, null, 2));
136+
const suggestions = parseSuggestions(response);
137+
138+
res.json(suggestions);
139+
} catch (error) {
140+
console.error('Error generating suggestions:', error);
141+
res.status(500).json({ error: 'Error generating suggestions', message: error.message });
142+
}
143+
});
144+
145+
function parseSuggestions(response) {
146+
if (!response || !response.suggestions || !Array.isArray(response.suggestions)) {
147+
console.error('Invalid response format:', response);
148+
return { suggestions: [] };
149+
}
150+
151+
return response;
152+
}
153+
92154
module.exports = router;

0 commit comments

Comments
 (0)