Skip to content

Commit 6590f04

Browse files
authored
Merge pull request #27 from GYFX35/feature/project-creation-promotion
feat: Add project creation and startup promotion features
2 parents 454829d + 1af13c3 commit 6590f04

File tree

4 files changed

+178
-13
lines changed

4 files changed

+178
-13
lines changed

app.py

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,43 @@ def get_projects():
808808
} for project in projects
809809
])
810810

811+
@app.route('/api/v1/projects', methods=['POST'])
812+
@require_api_key
813+
def create_project():
814+
data = request.get_json()
815+
title = data.get('title')
816+
description = data.get('description')
817+
818+
if not all([title, description]):
819+
return jsonify({"error": _("Title and description are required")}), 400
820+
821+
new_project = Project(
822+
title=title,
823+
description=description,
824+
image_url='https://via.placeholder.com/300x200' # Placeholder image
825+
)
826+
db.session.add(new_project)
827+
db.session.commit()
828+
829+
return jsonify({
830+
'id': new_project.id,
831+
'title': new_project.title,
832+
'description': new_project.description,
833+
'image_url': new_project.image_url
834+
}), 201
835+
836+
@app.route('/api/v1/promotions', methods=['POST'])
837+
@require_api_key
838+
def create_promotion():
839+
data = request.get_json()
840+
description = data.get('description')
841+
842+
if not description:
843+
return jsonify({"error": _("Description is required")}), 400
844+
845+
promotion_text = google_ai.generate_social_media_post(description)
846+
return jsonify({"promotion_text": promotion_text})
847+
811848
@app.route('/api/v1/payment/create-payment-intent', methods=['POST'])
812849
@require_api_key
813850
def create_payment_intent():
@@ -918,21 +955,21 @@ def get_meta_campaigns():
918955

919956

920957
# The following block is for development purposes and should not be used in production.
921-
# Use a production-ready WSGI server like Gunicorn to run the application.
958+
# Use a production-ready WSGI server like Gunicorn to run the.
922959
# Example: gunicorn --bind 0.0.0.0:5000 app:app
923960
# The database initialization is also handled separately in a production environment.
924-
# if __name__ == '__main__':
925-
# with app.app_context():
926-
# db.create_all()
927-
# if not Project.query.first():
928-
# projects = [
929-
# Project(title='Project One', description='A web application that uses AI to generate recipes based on available ingredients.', image_url='https://via.placeholder.com/300x200'),
930-
# Project(title='Project Two', description='A mobile game that uses AI to create dynamic and challenging levels.', image_url='https://via.placeholder.com/300x200'),
931-
# Project(title='Project Three', description='An e-commerce website that uses AI to provide personalized product recommendations.', image_url='https://via.placeholder.com/300x200')
932-
# ]
933-
# db.session.bulk_save_objects(projects)
934-
# db.session.commit()
935-
# app.run(debug=True, port=5000)
961+
if __name__ == '__main__':
962+
with app.app_context():
963+
db.create_all()
964+
if not Project.query.first():
965+
projects = [
966+
Project(title='Project One', description='A web application that uses AI to generate recipes based on available ingredients.', image_url='https://via.placeholder.com/300x200'),
967+
Project(title='Project Two', description='A mobile game that uses AI to create dynamic and challenging levels.', image_url='https://via.placeholder.com/300x200'),
968+
Project(title='Project Three', description='An e-commerce website that uses AI to provide personalized product recommendations.', image_url='https://via.placeholder.com/300x200')
969+
]
970+
db.session.bulk_save_objects(projects)
971+
db.session.commit()
972+
app.run(debug=True, port=5001)
936973

937974
@app.cli.command("init-db")
938975
def init_db_command():

frontend/static/js/script.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,85 @@ document.addEventListener('DOMContentLoaded', () => {
205205
gallery.appendChild(item);
206206
});
207207
}
208+
209+
// --- Create Project ---
210+
const createProjectBtn = document.getElementById('create-project-btn');
211+
if (createProjectBtn) {
212+
createProjectBtn.addEventListener('click', async () => {
213+
const titleInput = document.getElementById('project-title-input');
214+
const descriptionInput = document.getElementById('project-description-input');
215+
const responseContainer = document.getElementById('create-project-response');
216+
const apiKey = prompt("Please enter your API key to create a project:");
217+
218+
if (!apiKey) {
219+
responseContainer.textContent = 'API key is required to create a project.';
220+
return;
221+
}
222+
223+
try {
224+
const response = await fetch('/api/v1/projects', {
225+
method: 'POST',
226+
headers: {
227+
'Content-Type': 'application/json',
228+
'X-API-Key': apiKey
229+
},
230+
body: JSON.stringify({
231+
title: titleInput.value,
232+
description: descriptionInput.value
233+
})
234+
});
235+
236+
if (!response.ok) {
237+
const error = await response.json();
238+
throw new Error(error.error || 'Failed to create project');
239+
}
240+
241+
const newProject = await response.json();
242+
responseContainer.textContent = `Project "${newProject.title}" created successfully!`;
243+
titleInput.value = '';
244+
descriptionInput.value = '';
245+
fetchProjects(); // Refresh the portfolio
246+
} catch (error) {
247+
responseContainer.textContent = `Error: ${error.message}`;
248+
}
249+
});
250+
}
251+
252+
// --- Promote Startup ---
253+
const promoteStartupBtn = document.getElementById('promote-startup-btn');
254+
if (promoteStartupBtn) {
255+
promoteStartupBtn.addEventListener('click', async () => {
256+
const descriptionInput = document.getElementById('startup-description-input');
257+
const responseContainer = document.getElementById('promote-startup-response');
258+
const apiKey = prompt("Please enter your API key to generate a promotion:");
259+
260+
if (!apiKey) {
261+
responseContainer.textContent = 'API key is required to generate a promotion.';
262+
return;
263+
}
264+
265+
try {
266+
const response = await fetch('/api/v1/promotions', {
267+
method: 'POST',
268+
headers: {
269+
'Content-Type': 'application/json',
270+
'X-API-Key': apiKey
271+
},
272+
body: JSON.stringify({
273+
description: descriptionInput.value
274+
})
275+
});
276+
277+
if (!response.ok) {
278+
const error = await response.json();
279+
throw new Error(error.error || 'Failed to generate promotion');
280+
}
281+
282+
const promotion = await response.json();
283+
responseContainer.textContent = promotion.promotion_text;
284+
} catch (error) {
285+
responseContainer.textContent = `Error: ${error.message}`;
286+
}
287+
});
288+
}
208289
});

frontend/templates/index.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,41 @@ <h3>1000 AI Credits</h3>
8282
<section id="portfolio" class="portfolio">
8383
<h2>Our Work</h2>
8484
<div class="portfolio-gallery">
85+
</div>
86+
</section>
87+
88+
<!-- Create Project Section -->
89+
<section id="create-project" class="services">
90+
<h2>{{ _('Create a New Project') }}</h2>
91+
<div class="service-cards">
92+
<div class="card">
93+
<h3>{{ _('Project Details') }}</h3>
94+
<p>{{ _('Enter the title and description for your new project.') }}</p>
95+
<input type="text" id="project-title-input" placeholder="{{ _('Project Title') }}" class="styled-input">
96+
<textarea id="project-description-input" placeholder="{{ _('Project Description') }}" class="styled-textarea" rows="4"></textarea>
97+
<button id="create-project-btn" class="btn">{{ _('Create Project') }}</button>
98+
<div class="response-container" id="create-project-response-container">
99+
<pre id="create-project-response"></pre>
100+
</div>
85101
</div>
102+
</div>
86103
</section>
87104

105+
<!-- Promote Startup Section -->
106+
<section id="promote-startup" class="services">
107+
<h2>{{ _('Promote Your Startup') }}</h2>
108+
<div class="service-cards">
109+
<div class="card">
110+
<h3>{{ _('Startup Details') }}</h3>
111+
<p>{{ _('Enter a description of your startup to generate a promotion.') }}</p>
112+
<textarea id="startup-description-input" placeholder="{{ _('Startup Description') }}" class="styled-textarea" rows="4"></textarea>
113+
<button id="promote-startup-btn" class="btn">{{ _('Generate Promotion') }}</button>
114+
<div class="response-container" id="promote-startup-response-container">
115+
<pre id="promote-startup-response"></pre>
116+
</div>
117+
</div>
118+
</div>
119+
</section>
88120
</main>
89121

90122
<footer id="contact">
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from playwright.sync_api import sync_playwright
2+
3+
def run(playwright):
4+
browser = playwright.chromium.launch(headless=True)
5+
context = browser.new_context()
6+
page = context.new_page()
7+
8+
try:
9+
page.goto("http://127.0.0.1:5001")
10+
page.screenshot(path="jules-scratch/verification/verification.png")
11+
finally:
12+
browser.close()
13+
14+
with sync_playwright() as playwright:
15+
run(playwright)

0 commit comments

Comments
 (0)