Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2778aa5fbf |
BIN
ai/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
ai/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
ai/__pycache__/local_ai_api.cpython-311.pyc
Normal file
BIN
ai/__pycache__/local_ai_api.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -56,6 +56,7 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'core',
|
'core',
|
||||||
|
'story_writer',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|||||||
@ -21,6 +21,7 @@ from django.conf.urls.static import static
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
|
path("stories/", include("story_writer.urls")),
|
||||||
path("", include("core.urls")),
|
path("", include("core.urls")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -15,6 +15,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
{% block head %}{% endblock %}
|
{% block head %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@ -1,145 +1,17 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block title %}{{ project_name }}{% endblock %}
|
{% block title %}Creative Story Writer - Unleash Your Imagination{% endblock %}
|
||||||
|
|
||||||
{% block head %}
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg-color-start: #6a11cb;
|
|
||||||
--bg-color-end: #2575fc;
|
|
||||||
--text-color: #ffffff;
|
|
||||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
|
||||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: 'Inter', sans-serif;
|
|
||||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
|
||||||
color: var(--text-color);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 100vh;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
body::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
|
|
||||||
animation: bg-pan 20s linear infinite;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes bg-pan {
|
|
||||||
0% {
|
|
||||||
background-position: 0% 0%;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
background-position: 100% 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
background: var(--card-bg-color);
|
|
||||||
border: 1px solid var(--card-border-color);
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 2.5rem 2rem;
|
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
-webkit-backdrop-filter: blur(20px);
|
|
||||||
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
|
|
||||||
font-weight: 700;
|
|
||||||
margin: 0 0 1.2rem;
|
|
||||||
letter-spacing: -0.02em;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
opacity: 0.92;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
margin: 1.5rem auto;
|
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
border: 4px solid rgba(255, 255, 255, 0.25);
|
|
||||||
border-top-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime code {
|
|
||||||
background: rgba(0, 0, 0, 0.25);
|
|
||||||
padding: 0.15rem 0.45rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 1rem;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main>
|
<div class="hero-shapes">
|
||||||
<div class="card">
|
<div class="shape shape-1"></div>
|
||||||
<h1>Analyzing your requirements and generating your app…</h1>
|
<div class="shape shape-2"></div>
|
||||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
<div class="shape shape-3"></div>
|
||||||
<span class="sr-only">Loading…</span>
|
<div class="container text-center py-5">
|
||||||
|
<h1 class="display-4 fw-bold">Creative Story Writer</h1>
|
||||||
|
<p class="lead my-4">Harness the power of AI to bring your stories to life. Overcome writer's block, generate new ideas, and craft compelling narratives with ease.</p>
|
||||||
|
<a href="{% url 'story_writer:index' %}" class="btn btn-primary btn-lg">Get Started</a>
|
||||||
</div>
|
</div>
|
||||||
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
|
</div>
|
||||||
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
|
|
||||||
<p class="runtime">
|
|
||||||
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
|
|
||||||
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<footer>
|
|
||||||
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
|
|
||||||
</footer>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -2,6 +2,8 @@ from django.urls import path
|
|||||||
|
|
||||||
from .views import home
|
from .views import home
|
||||||
|
|
||||||
|
app_name = "core"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", home, name="home"),
|
path("", home, name="home"),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,4 +1,145 @@
|
|||||||
/* Custom styles for the application */
|
/* Custom styles for the application */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=Inter:wght@400;600;700&display=swap');
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: system-ui, -apple-system, sans-serif;
|
font-family: 'Inter', sans-serif;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: #343a40;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-shapes {
|
||||||
|
position: relative;
|
||||||
|
background: linear-gradient(135deg, #f8f9fa, #e0e7ff);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 100px 0;
|
||||||
|
animation: gradient-animation 10s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradient-animation {
|
||||||
|
0% { background: linear-gradient(135deg, #f8f9fa, #e0e7ff); }
|
||||||
|
50% { background: linear-gradient(135deg, #e0e7ff, #f8f9fa); }
|
||||||
|
100% { background: linear-gradient(135deg, #f8f9fa, #e0e7ff); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: rgba(0, 123, 255, 0.1);
|
||||||
|
animation: shape-animation 20s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-1 {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
top: 10%;
|
||||||
|
left: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-2 {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
top: 60%;
|
||||||
|
right: 20%;
|
||||||
|
animation-delay: 5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-3 {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
bottom: 10%;
|
||||||
|
left: 30%;
|
||||||
|
animation-delay: 10s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shape-animation {
|
||||||
|
0% { transform: translateY(0) rotate(0deg); }
|
||||||
|
100% { transform: translateY(-100px) rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
animation: fade-in 1.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from { opacity: 0; transform: translateY(20px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.display-4.fw-bold {
|
||||||
|
font-family: 'Playfair Display', serif;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #007bff;
|
||||||
|
border-color: #007bff;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 15px 30px;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
transition: background-color 0.2s, transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Story writer specific styles */
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: none;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor, #suggestion {
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor:focus, #suggestion:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #80bdff;
|
||||||
|
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner-border {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-spinner {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,145 @@
|
|||||||
|
/* Custom styles for the application */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=Inter:wght@400;600;700&display=swap');
|
||||||
|
|
||||||
:root {
|
|
||||||
--bg-color-start: #6a11cb;
|
|
||||||
--bg-color-end: #2575fc;
|
|
||||||
--text-color: #ffffff;
|
|
||||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
|
||||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
|
||||||
font-family: 'Inter', sans-serif;
|
font-family: 'Inter', sans-serif;
|
||||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
background-color: #f8f9fa;
|
||||||
color: var(--text-color);
|
color: #343a40;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-shapes {
|
||||||
|
position: relative;
|
||||||
|
background: linear-gradient(135deg, #f8f9fa, #e0e7ff);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 100px 0;
|
||||||
|
animation: gradient-animation 10s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradient-animation {
|
||||||
|
0% { background: linear-gradient(135deg, #f8f9fa, #e0e7ff); }
|
||||||
|
50% { background: linear-gradient(135deg, #e0e7ff, #f8f9fa); }
|
||||||
|
100% { background: linear-gradient(135deg, #f8f9fa, #e0e7ff); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: rgba(0, 123, 255, 0.1);
|
||||||
|
animation: shape-animation 20s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-1 {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
top: 10%;
|
||||||
|
left: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-2 {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
top: 60%;
|
||||||
|
right: 20%;
|
||||||
|
animation-delay: 5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-3 {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
bottom: 10%;
|
||||||
|
left: 30%;
|
||||||
|
animation-delay: 10s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shape-animation {
|
||||||
|
0% { transform: translateY(0) rotate(0deg); }
|
||||||
|
100% { transform: translateY(-100px) rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
animation: fade-in 1.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from { opacity: 0; transform: translateY(20px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.display-4.fw-bold {
|
||||||
|
font-family: 'Playfair Display', serif;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lead {
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #007bff;
|
||||||
|
border-color: #007bff;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 15px 30px;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
transition: background-color 0.2s, transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Story writer specific styles */
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: none;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor, #suggestion {
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor:focus, #suggestion:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #80bdff;
|
||||||
|
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner-border {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-spinner {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 100vh;
|
height: 100%;
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|||||||
0
story_writer/__init__.py
Normal file
0
story_writer/__init__.py
Normal file
BIN
story_writer/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
story_writer/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
story_writer/__pycache__/admin.cpython-311.pyc
Normal file
BIN
story_writer/__pycache__/admin.cpython-311.pyc
Normal file
Binary file not shown.
BIN
story_writer/__pycache__/apps.cpython-311.pyc
Normal file
BIN
story_writer/__pycache__/apps.cpython-311.pyc
Normal file
Binary file not shown.
BIN
story_writer/__pycache__/models.cpython-311.pyc
Normal file
BIN
story_writer/__pycache__/models.cpython-311.pyc
Normal file
Binary file not shown.
BIN
story_writer/__pycache__/urls.cpython-311.pyc
Normal file
BIN
story_writer/__pycache__/urls.cpython-311.pyc
Normal file
Binary file not shown.
BIN
story_writer/__pycache__/views.cpython-311.pyc
Normal file
BIN
story_writer/__pycache__/views.cpython-311.pyc
Normal file
Binary file not shown.
3
story_writer/admin.py
Normal file
3
story_writer/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
story_writer/apps.py
Normal file
6
story_writer/apps.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class StoryWriterConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'story_writer'
|
||||||
0
story_writer/migrations/__init__.py
Normal file
0
story_writer/migrations/__init__.py
Normal file
BIN
story_writer/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
story_writer/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
3
story_writer/models.py
Normal file
3
story_writer/models.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
93
story_writer/templates/story_writer/index.html
Normal file
93
story_writer/templates/story_writer/index.html
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h1 class="text-center mb-4">Creative Story Writer</h1>
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-10">
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Your Story</h5>
|
||||||
|
<div id="editor" contenteditable="true" style="height: 400px; border: 1px solid #ccc; padding: 10px; overflow-y: scroll;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-10">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">AI Assistant</h5>
|
||||||
|
<p>Let the AI help you write your story.</p>
|
||||||
|
<div class="d-flex justify-content-center gap-2 mb-3">
|
||||||
|
<button id="suggest-plot-twist" class="btn btn-primary">Suggest a Plot Twist</button>
|
||||||
|
<button id="describe-setting" class="btn btn-primary">Describe the Setting</button>
|
||||||
|
<button id="continue-story" class="btn btn-primary">Continue the Story</button>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<h5 class="card-title">AI Suggestion</h5>
|
||||||
|
<div id="suggestion" style="height: 200px; border: 1px solid #ccc; padding: 10px; overflow-y: scroll;">
|
||||||
|
<div id="spinner-container" class="center-spinner" style="display: none;">
|
||||||
|
<div class="spinner-border" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const editor = document.getElementById('editor');
|
||||||
|
const suggestionBox = document.getElementById('suggestion');
|
||||||
|
const spinnerContainer = document.getElementById('spinner-container');
|
||||||
|
const suggestPlotTwistBtn = document.getElementById('suggest-plot-twist');
|
||||||
|
const describeSettingBtn = document.getElementById('describe-setting');
|
||||||
|
const continueStoryBtn = document.getElementById('continue-story');
|
||||||
|
|
||||||
|
function getCookie(name) {
|
||||||
|
let cookieValue = null;
|
||||||
|
if (document.cookie && document.cookie !== '') {
|
||||||
|
const cookies = document.cookie.split(';');
|
||||||
|
for (let i = 0; i < cookies.length; i++) {
|
||||||
|
const cookie = cookies[i].trim();
|
||||||
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||||
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
const csrftoken = getCookie('csrftoken');
|
||||||
|
|
||||||
|
async function getAISuggestion(prompt) {
|
||||||
|
suggestionBox.innerHTML = '';
|
||||||
|
spinnerContainer.style.display = 'flex';
|
||||||
|
const response = await fetch('{% url "story_writer:ai_assistant" %}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': csrftoken
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
story: editor.innerText,
|
||||||
|
prompt: prompt
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
spinnerContainer.style.display = 'none';
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
suggestionBox.innerHTML = data.suggestion;
|
||||||
|
} else {
|
||||||
|
suggestionBox.innerHTML = 'Error: Could not get a suggestion.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestPlotTwistBtn.addEventListener('click', () => getAISuggestion('plot twist'));
|
||||||
|
describeSettingBtn.addEventListener('click', () => getAISuggestion('description of the setting'));
|
||||||
|
continueStoryBtn.addEventListener('click', () => getAISuggestion('continuation of the story'));
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
3
story_writer/tests.py
Normal file
3
story_writer/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
9
story_writer/urls.py
Normal file
9
story_writer/urls.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = 'story_writer'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.story_writer, name='index'),
|
||||||
|
path('ai-assistant/', views.ai_assistant, name='ai_assistant'),
|
||||||
|
]
|
||||||
30
story_writer/views.py
Normal file
30
story_writer/views.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
from django.http import JsonResponse
|
||||||
|
from ai.local_ai_api import LocalAIApi
|
||||||
|
import json
|
||||||
|
|
||||||
|
def story_writer(request):
|
||||||
|
return render(request, 'story_writer/index.html')
|
||||||
|
|
||||||
|
def ai_assistant(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
data = json.loads(request.body)
|
||||||
|
story = data.get('story', '')
|
||||||
|
prompt = data.get('prompt', '')
|
||||||
|
|
||||||
|
response = LocalAIApi.create_response(
|
||||||
|
{
|
||||||
|
"input": [
|
||||||
|
{"role": "system", "content": "You are a creative writing assistant."},
|
||||||
|
{"role": "user", "content": f'Here is the story so far:\n\n{story}\n\nNow, please continue the story with a {prompt}.'}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.get("success"):
|
||||||
|
text = LocalAIApi.extract_text(response)
|
||||||
|
return JsonResponse({'suggestion': text})
|
||||||
|
else:
|
||||||
|
return JsonResponse({'error': 'Failed to get a response from the AI.'}, status=500)
|
||||||
|
|
||||||
|
return JsonResponse({'error': 'Invalid request method.'}, status=405)
|
||||||
Loading…
x
Reference in New Issue
Block a user