diff --git a/.gitignore b/.gitignore
index e427ff3..d387093 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules/
*/node_modules/
*/build/
+.env
diff --git a/ai/__pycache__/__init__.cpython-311.pyc b/ai/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..8bcb2fb
Binary files /dev/null and b/ai/__pycache__/__init__.cpython-311.pyc differ
diff --git a/ai/__pycache__/local_ai_api.cpython-311.pyc b/ai/__pycache__/local_ai_api.cpython-311.pyc
new file mode 100644
index 0000000..fa9977d
Binary files /dev/null and b/ai/__pycache__/local_ai_api.cpython-311.pyc differ
diff --git a/config/__pycache__/wsgi.cpython-311.pyc b/config/__pycache__/wsgi.cpython-311.pyc
index 79ce690..b807168 100644
Binary files a/config/__pycache__/wsgi.cpython-311.pyc and b/config/__pycache__/wsgi.cpython-311.pyc differ
diff --git a/config/wsgi.py b/config/wsgi.py
index e2fbd58..0bd1abf 100644
--- a/config/wsgi.py
+++ b/config/wsgi.py
@@ -8,9 +8,11 @@ https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
"""
import os
+from dotenv import load_dotenv
from django.core.wsgi import get_wsgi_application
+load_dotenv()
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
application = get_wsgi_application()
diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc
index cd6f855..5f1a588 100644
Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ
diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc
new file mode 100644
index 0000000..838490d
Binary files /dev/null and b/core/__pycache__/forms.cpython-311.pyc differ
diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc
index 9aa598b..6e44947 100644
Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ
diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc
index 1f807fa..7e5f23d 100644
Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ
diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc
index 6867ddf..050d896 100644
Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ
diff --git a/core/admin.py b/core/admin.py
index 8c38f3f..80f9113 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -1,3 +1,8 @@
from django.contrib import admin
+from .models import Post
-# Register your models here.
+@admin.register(Post)
+class PostAdmin(admin.ModelAdmin):
+ list_display = ('author', 'created_at', 'intent')
+ list_filter = ('created_at', 'intent')
+ search_fields = ('content', 'author__username')
\ No newline at end of file
diff --git a/core/forms.py b/core/forms.py
new file mode 100644
index 0000000..d660379
--- /dev/null
+++ b/core/forms.py
@@ -0,0 +1,27 @@
+from django import forms
+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth.models import User
+from .models import Post
+
+class SignUpForm(UserCreationForm):
+ email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
+
+ class Meta:
+ model = User
+ fields = ('username', 'email', 'password', 'password2')
+
+class PostForm(forms.ModelForm):
+ content = forms.CharField(
+ widget=forms.Textarea(
+ attrs={
+ "class": "w-full bg-gray-800 border border-gray-700 rounded-lg p-4 text-white focus:outline-none focus:ring-2 focus:ring-teal-500",
+ "placeholder": "What's on your mind?",
+ "rows": 3,
+ }
+ ),
+ label="",
+ )
+
+ class Meta:
+ model = Post
+ fields = ["content"]
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
new file mode 100644
index 0000000..88adf57
--- /dev/null
+++ b/core/migrations/0001_initial.py
@@ -0,0 +1,26 @@
+# Generated by Django 5.2.7 on 2025-12-18 17:57
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Post',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('content', models.TextField()),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/core/migrations/0002_post_intent.py b/core/migrations/0002_post_intent.py
new file mode 100644
index 0000000..1f63823
--- /dev/null
+++ b/core/migrations/0002_post_intent.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.2.7 on 2025-12-18 18:00
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='post',
+ name='intent',
+ field=models.CharField(default='Neutral', max_length=50),
+ ),
+ ]
diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc
new file mode 100644
index 0000000..ccbd2cc
Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ
diff --git a/core/migrations/__pycache__/0002_post_intent.cpython-311.pyc b/core/migrations/__pycache__/0002_post_intent.cpython-311.pyc
new file mode 100644
index 0000000..6fa9c5f
Binary files /dev/null and b/core/migrations/__pycache__/0002_post_intent.cpython-311.pyc differ
diff --git a/core/models.py b/core/models.py
index 71a8362..4c9d4f9 100644
--- a/core/models.py
+++ b/core/models.py
@@ -1,3 +1,13 @@
+from django.contrib.auth.models import User
from django.db import models
-# Create your models here.
+class Post(models.Model):
+ author = models.ForeignKey(User, on_delete=models.CASCADE)
+ title = models.CharField(max_length=200)
+ slug = models.SlugField(unique=True)
+ content = models.TextField()
+ created_at = models.DateTimeField(auto_now_add=True)
+ intent = models.CharField(max_length=50, default='Neutral')
+
+ def __str__(self):
+ return f'Post by {self.author.username} on {self.created_at.strftime("%Y-%m-%d")}'
\ No newline at end of file
diff --git a/core/templates/base.html b/core/templates/base.html
index 1e7e5fb..6ab8899 100644
--- a/core/templates/base.html
+++ b/core/templates/base.html
@@ -3,7 +3,7 @@
- {% block title %}Knowledge Base{% endblock %}
+ {% block title %}Cipher Shield{% endblock %}
{% if project_description %}
@@ -13,13 +13,64 @@
{% endif %}
+
{% load static %}
{% block head %}{% endblock %}
-
- {% block content %}{% endblock %}
+
+
+
+
+
+
+ {% block content %}{% endblock %}
+
+
+
diff --git a/core/templates/core/ad_generator.html b/core/templates/core/ad_generator.html
new file mode 100644
index 0000000..23bdf19
--- /dev/null
+++ b/core/templates/core/ad_generator.html
@@ -0,0 +1,52 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block content %}
+
+
Ad Generation Tool
+
+
+
+
+
+
Enter Product Details
+
+
+
+
+
+
+
+
Generated Ad Creative
+ {% if ad_copy and ad_image_url %}
+
+
+
+
Ad Copy
+
{{ ad_copy }}
+
+
+ {% else %}
+
Your generated ad creative will appear here.
+ {% endif %}
+
+
+
+
+
+{% endblock %}
diff --git a/core/templates/core/ai_chat.html b/core/templates/core/ai_chat.html
new file mode 100644
index 0000000..8200205
--- /dev/null
+++ b/core/templates/core/ai_chat.html
@@ -0,0 +1,53 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
AI Chat
+
+
+ {% csrf_token %}
+
+
+ Send
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/core/templates/core/blog.html b/core/templates/core/blog.html
new file mode 100644
index 0000000..29f69ae
--- /dev/null
+++ b/core/templates/core/blog.html
@@ -0,0 +1,24 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+
Blog
+
+ {% for post in posts %}
+
+
+
+
+
{{ post.content|truncatewords:50 }}
+
Read More →
+
+
+
+
+ {% endfor %}
+
+
+{% endblock %}
diff --git a/core/templates/core/graphics_editor.html b/core/templates/core/graphics_editor.html
new file mode 100644
index 0000000..52f925a
--- /dev/null
+++ b/core/templates/core/graphics_editor.html
@@ -0,0 +1,112 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
Cipher Shield Graphics
+
Your personal graphics designing software
+
+
+
+
+
+
+{% endblock %}
diff --git a/core/templates/core/image_generator.html b/core/templates/core/image_generator.html
new file mode 100644
index 0000000..ea36718
--- /dev/null
+++ b/core/templates/core/image_generator.html
@@ -0,0 +1,47 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block content %}
+
+
+
+
Cipher Shield: Image Generation
+
Unleash your creativity. Describe the image you want to create, and let our AI bring it to life.
+
+
+
+
+ {% csrf_token %}
+
+
+
+ Generate Image
+
+
+
+
+
+
+ Loading...
+
+ {% if image_url %}
+
Your Masterpiece
+
+ {% endif %}
+ {% if error_message %}
+
+ {{ error_message }}
+
+ {% endif %}
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/core/templates/core/index.html b/core/templates/core/index.html
index faec813..5db9952 100644
--- a/core/templates/core/index.html
+++ b/core/templates/core/index.html
@@ -1,145 +1,57 @@
{% extends "base.html" %}
+{% load static %}
-{% block title %}{{ project_name }}{% endblock %}
+{% block title %}Cipher Shield{% endblock %}
{% block head %}
+{{ block.super }}
-
-
+
+
{% endblock %}
{% block content %}
-
-
-
Analyzing your requirements and generating your app…
-
-
Loading…
+
+
+ Cipher Shield
+ The future of secure social networking.
+
+
+
+
+ {% csrf_token %}
+ {{ form.as_p }}
+
+ Post
+
+
-
AppWizzy AI is collecting your requirements and applying the first changes.
-
This page will refresh automatically as the plan is implemented.
-
- Runtime: Django {{ django_version }} · Python {{ python_version }}
- — UTC {{ current_time|date:"Y-m-d H:i:s" }}
-
-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
-
-{% endblock %}
\ No newline at end of file
+
+
+ {% for post in posts %}
+
+
+
+
+ {{ post.author.username.0|upper }}
+
+
+
+
{{ post.author.username }}
+
+
+
{{ post.created_at|date:"F d, Y, P" }}
+
+
+
{{ post.content }}
+
+
+ {% empty %}
+
+
No posts yet. Be the first to share something!
+
+ {% endfor %}
+
+
+{% endblock %}
diff --git a/core/templates/core/landing_page.html b/core/templates/core/landing_page.html
new file mode 100644
index 0000000..484249c
--- /dev/null
+++ b/core/templates/core/landing_page.html
@@ -0,0 +1,29 @@
+{% extends "base.html" %}
+{% load static %}
+
+{% block title %}Super Affiliate AI{% endblock %}
+
+{% block head %}
+{{ block.super }}
+
+
+
+
+{% endblock %}
+
+{% block content %}
+
+
+ Promote HubSpot
+ The Ultimate All-in-One Platform for Your Business
+
+
+
+
+
Why Promote HubSpot?
+
HubSpot offers a full platform of marketing, sales, customer service, and CRM software — plus the methodology, resources, and support to help businesses grow better. As a HubSpot affiliate, you'll earn a commission on every new customer you refer.
+
Get Started with HubSpot!
+
+
+
+{% endblock %}
diff --git a/core/templates/core/login.html b/core/templates/core/login.html
new file mode 100644
index 0000000..4c204c6
--- /dev/null
+++ b/core/templates/core/login.html
@@ -0,0 +1,14 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
Login
+
+ {% csrf_token %}
+ {{ form.as_p }}
+ Login
+
+
+
+{% endblock %}
diff --git a/core/templates/core/signup.html b/core/templates/core/signup.html
new file mode 100644
index 0000000..77c5034
--- /dev/null
+++ b/core/templates/core/signup.html
@@ -0,0 +1,14 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
Sign Up
+
+ {% csrf_token %}
+ {{ form.as_p }}
+ Sign Up
+
+
+
+{% endblock %}
diff --git a/core/urls.py b/core/urls.py
index 6299e3d..65974db 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -1,7 +1,18 @@
from django.urls import path
+from django.contrib.auth import views as auth_views
-from .views import home
+from .views import landing_page, social_feed, image_generator, ad_generator, graphics_editor, signup, ai_chat, post_list, post_detail
urlpatterns = [
- path("", home, name="home"),
+ path("", landing_page, name="landing_page"),
+ path("blog/", post_list, name="post_list"),
+ path("blog/
/", post_detail, name="post_detail"),
+ path("social/", social_feed, name="social_feed"),
+ path("image-generator/", image_generator, name="image_generator"),
+ path("ad-generator/", ad_generator, name="ad_generator"),
+ path("graphics-editor/", graphics_editor, name="graphics_editor"),
+ path("ai-chat/", ai_chat, name="ai_chat"),
+ path("signup/", signup, name="signup"),
+ path("login/", auth_views.LoginView.as_view(template_name="core/login.html"), name="login"),
+ path("logout/", auth_views.LogoutView.as_view(next_page="login"), name="logout"),
]
diff --git a/core/views.py b/core/views.py
index c9aed12..76e1764 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,25 +1,249 @@
+from django.shortcuts import render, redirect, get_object_or_404
+
+def landing_page(request):
+ return render(request, 'core/landing_page.html')
+from django.contrib.auth.decorators import login_required
+from .models import Post
+from .forms import PostForm, SignUpForm
+import logging
import os
-import platform
+import json
+from django.contrib.auth import login
+from ai.local_ai_api import LocalAIApi
-from django import get_version as django_version
-from django.shortcuts import render
-from django.utils import timezone
+logger = logging.getLogger(__name__)
+
+def signup(request):
+ if request.method == 'POST':
+ form = SignUpForm(request.POST)
+ if form.is_valid():
+ user = form.save()
+ return redirect('social_feed')
+ else:
+ form = SignUpForm()
+ return render(request, 'core/signup.html', {'form': form})
-def home(request):
- """Render the landing screen with loader and environment details."""
- host_name = request.get_host().lower()
- agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
- now = timezone.now()
+def social_feed(request):
+ if request.method == 'POST':
+ form = PostForm(request.POST)
+ if form.is_valid():
+ post = form.save(commit=False)
+ post.author = request.user
+ # AI Intent Analysis
+ try:
+ content = form.cleaned_data['content']
+ prompt = (
+ "Analyze the following post and classify its intent into one of "
+ "the following categories: Neutral, Safe, Caution, Warning. "
+ "Only return the category name and nothing else."
+ )
+
+ response = LocalAIApi.create_response(
+ {
+ "input": [
+ {"role": "system", "content": prompt},
+ {"role": "user", "content": content}
+ ],
+ },
+ )
+
+ if response.get("success"):
+ ai_intent = LocalAIApi.extract_text(response)
+ if ai_intent in ["Neutral", "Safe", "Caution", "Warning"]:
+ post.intent = ai_intent
+ else:
+ post.intent = "Neutral"
+ else:
+ post.intent = "Neutral"
+
+ except Exception as e:
+ logger.error("Error during AI intent analysis: %s", e)
+ post.intent = "Neutral"
+
+ post.save()
+ return redirect('social_feed')
+ else:
+ form = PostForm()
+
+ posts = Post.objects.all().order_by('-created_at')
context = {
- "project_name": "New Style",
- "agent_brand": agent_brand,
- "django_version": django_version(),
- "python_version": platform.python_version(),
- "current_time": now,
- "host_name": host_name,
- "project_description": os.getenv("PROJECT_DESCRIPTION", ""),
- "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
+ 'posts': posts,
+ 'form': form,
}
- return render(request, "core/index.html", context)
+ return render(request, 'core/index.html', context)
+
+
+def image_generator(request):
+ if request.method == 'POST':
+ prompt = request.POST.get('prompt')
+
+ try:
+ response = LocalAIApi.create_response({
+ "input": [
+ {
+ "role": "system",
+ "content": "You are an AI image generator. Create an image based on the user's prompt."
+ },
+ {"role": "user", "content": prompt}
+ ],
+ "model": "dall-e-3",
+ "parameters": {
+ "size": "1024x1024"
+ }
+ })
+
+ if response.get("success"):
+ data = response.get("data", {})
+ output = data.get("output", [])
+ image_url = None
+ for item in output:
+ if item.get("type") == "image":
+ image_url = item.get("url")
+ break
+ if image_url:
+ return render(request, 'core/image_generator.html', {'image_url': image_url})
+ else:
+ error_message = "Image URL not found in the response."
+ return render(request, 'core/image_generator.html', {'error_message': error_message})
+ else:
+ error_message = response.get("error", "An unknown error occurred.")
+ return render(request, 'core/image_generator.html', {'error_message': error_message})
+
+ except Exception as e:
+ logger.error("Error during image generation: %s", e)
+ error_message = str(e)
+ return render(request, 'core/image_generator.html', {'error_message': error_message})
+
+ return render(request, 'core/image_generator.html')
+
+
+def ad_generator(request):
+ if request.method == 'POST':
+ product_name = request.POST.get('product_name')
+ product_description = request.POST.get('product_description')
+ target_audience = request.POST.get('target_audience')
+
+ try:
+ # Generate ad copy
+ ad_copy_prompt = f"Create a compelling ad copy for a product named '{product_name}'. " \
+ f"The product is about: {product_description}. " \
+ f"The target audience is {target_audience}."
+
+ ad_copy_response = LocalAIApi.create_response({
+ "input": [
+ {"role": "system", "content": "You are an expert copywriter."},
+ {"role": "user", "content": ad_copy_prompt}
+ ]
+ })
+ if ad_copy_response.get("success"):
+ ad_copy = LocalAIApi.extract_text(ad_copy_response)
+ else:
+ ad_copy = "Could not generate ad copy."
+
+ # Generate ad image
+ ad_image_prompt = f"Create a visually appealing image for an ad for '{product_name}'. " \
+ f"{product_description}"
+
+ ad_image_response = LocalAIApi.create_response({
+ "input": [
+ {
+ "role": "system",
+ "content": "You are an AI image generator. Create an image for an ad based on the user's prompt."
+ },
+ {"role": "user", "content": ad_image_prompt}
+ ],
+ "model": "dall-e-3",
+ "parameters": {
+ "size": "1024x1024"
+ }
+ })
+
+ if ad_image_response.get("success"):
+ data = ad_image_response.get("data", {})
+ output = data.get("output", [])
+ ad_image_url = None
+ for item in output:
+ if item.get("type") == "image":
+ ad_image_url = item.get("url")
+ break
+ else:
+ ad_image_url = ""
+
+
+ return render(request, 'core/ad_generator.html', {
+ 'ad_copy': ad_copy,
+ 'ad_image_url': ad_image_url,
+ 'product_name': product_name,
+ 'product_description': product_description,
+ 'target_audience': target_audience,
+ })
+
+ except Exception as e:
+ logger.error("Error during ad generation: %s", e)
+ error_message = str(e)
+ return render(request, 'core/ad_generator.html', {'error_message': error_message})
+
+ return render(request, 'core/ad_generator.html')
+
+def graphics_editor(request):
+ return render(request, 'core/graphics_editor.html')
+
+
+from django.http import JsonResponse
+from django.views.decorators.csrf import csrf_exempt
+
+@csrf_exempt
+def ai_chat(request):
+ if request.method == 'POST':
+ prompt = request.POST.get('prompt')
+
+ # Basic validation
+ if not prompt:
+ return JsonResponse({'error': 'Prompt is required.'}, status=400)
+
+ try:
+ conversation = [
+ {
+ "role": "system",
+ "content": (
+ "You are a helpful assistant that can control a web browser. "
+ "You can perform tasks like navigating to web pages, filling out forms, and clicking on links. "
+ "When asked to perform a browser action, you should respond with a JavaScript code block to be executed in the browser. "
+ "The browser is displayed in an iframe, and you can access it using `window.frames[0]`. "
+ "For example, to navigate to a new page, you can use `window.frames[0].location.href = 'https://www.google.com';`. "
+ "To click a button, you can use `window.frames[0].document.querySelector('#my-button').click();`. "
+ "To fill out an input field, you can use `window.frames[0].document.querySelector('#my-input').value = 'my value';`. "
+ "To get the text content of an element, you can use `window.frames[0].document.querySelector('#my-element').textContent`. "
+ "If you are not being asked to do a browser action, you can respond with a conversational response."
+ )
+ },
+ {"role": "user", "content": prompt}
+ ]
+
+ response = LocalAIApi.create_response(
+ {
+ "input": conversation,
+ }
+ )
+
+ if response.get("success"):
+ return JsonResponse(response)
+ else:
+ error_message = response.get("error", "An unknown error occurred.")
+ return JsonResponse({'error': error_message}, status=500)
+
+ except Exception as e:
+ logger.error("Error in ai_chat view: %s", e)
+ return JsonResponse({'error': str(e)}, status=500)
+
+ return JsonResponse({'error': 'Only POST requests are allowed.'}, status=405)
+
+def post_list(request):
+ posts = Post.objects.all().order_by('-created_at')
+ return render(request, 'core/blog.html', {'posts': posts})
+
+def post_detail(request, slug):
+ post = get_object_or_404(Post, slug=slug)
+ return render(request, 'core/article_detail.html', {'post': post})
\ No newline at end of file
diff --git a/manage.py b/manage.py
index 8e7ac79..5dfbe21 100755
--- a/manage.py
+++ b/manage.py
@@ -2,10 +2,11 @@
"""Django's command-line utility for administrative tasks."""
import os
import sys
-
+from dotenv import load_dotenv
def main():
"""Run administrative tasks."""
+ load_dotenv()
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
try:
from django.core.management import execute_from_command_line
diff --git a/native_app/index.html b/native_app/index.html
new file mode 100644
index 0000000..da58aca
--- /dev/null
+++ b/native_app/index.html
@@ -0,0 +1,82 @@
+
+
+
+
+
+ AI Chat
+
+
+
+ AI Chat
+
+
+ Go
+
+
+
+
+ Send
+
+
+
+
diff --git a/native_app/main.js b/native_app/main.js
new file mode 100644
index 0000000..5f3a79f
--- /dev/null
+++ b/native_app/main.js
@@ -0,0 +1,71 @@
+const { app, BrowserWindow, ipcMain, BrowserView } = require('electron');
+const fetch = require('node-fetch');
+const path = require('path');
+
+let view;
+
+function createWindow () {
+ const win = new BrowserWindow({
+ width: 1200,
+ height: 600,
+ webPreferences: {
+ preload: path.join(__dirname, 'preload.js'),
+ nodeIntegration: true,
+ contextIsolation: false,
+ }
+ });
+
+ win.loadFile('index.html');
+
+ view = new BrowserView();
+ win.setBrowserView(view);
+ view.setBounds({ x: 400, y: 0, width: 800, height: 600 });
+ view.webContents.loadURL('https://electronjs.org');
+}
+
+app.whenReady().then(() => {
+ createWindow();
+
+ app.on('activate', () => {
+ if (BrowserWindow.getAllWindows().length === 0) {
+ createWindow();
+ }
+ });
+});
+
+app.on('window-all-closed', () => {
+ if (process.platform !== 'darwin') {
+ app.quit();
+ }
+});
+
+ipcMain.on('load-url', (event, url) => {
+ view.webContents.loadURL(url);
+});
+
+ipcMain.on('execute-js', (event, code) => {
+ view.webContents.executeJavaScript(code);
+});
+
+ipcMain.on('send-message', async (event, message) => {
+ try {
+ const response = await fetch('http://127.0.0.1:8000/ai_chat/', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ // Note: You'll need to handle CSRF tokens and authentication if your Django app requires it.
+ },
+ body: `message=${encodeURIComponent(message)}`
+ });
+
+ if (response.ok) {
+ const data = await response.json();
+ event.reply('ai-response', data.reply);
+ } else {
+ event.reply('ai-response', 'Error: Could not get a response from the AI.');
+ }
+ } catch (error) {
+ console.error(error);
+ event.reply('ai-response', 'Error: Could not connect to the AI service.');
+ }
+});
\ No newline at end of file
diff --git a/native_app/package-lock.json b/native_app/package-lock.json
new file mode 100644
index 0000000..87e913a
--- /dev/null
+++ b/native_app/package-lock.json
@@ -0,0 +1,917 @@
+{
+ "name": "native_app",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "native_app",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "node-fetch": "^2.7.0"
+ },
+ "devDependencies": {
+ "electron": "^39.2.7"
+ }
+ },
+ "node_modules/@electron/get": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz",
+ "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "env-paths": "^2.2.0",
+ "fs-extra": "^8.1.0",
+ "got": "^11.8.5",
+ "progress": "^2.0.3",
+ "semver": "^6.2.0",
+ "sumchecker": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "global-agent": "^3.0.0"
+ }
+ },
+ "node_modules/@sindresorhus/is": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+ "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
+ "node_modules/@szmarczak/http-timer": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
+ "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "defer-to-connect": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@types/cacheable-request": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
+ "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-cache-semantics": "*",
+ "@types/keyv": "^3.1.4",
+ "@types/node": "*",
+ "@types/responselike": "^1.0.0"
+ }
+ },
+ "node_modules/@types/http-cache-semantics": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
+ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/keyv": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
+ "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.19.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz",
+ "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/responselike": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
+ "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/yauzl": {
+ "version": "2.10.3",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
+ "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/boolean": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
+ "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
+ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/cacheable-lookup": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
+ "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.6.0"
+ }
+ },
+ "node_modules/cacheable-request": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
+ "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^4.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^6.0.1",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/clone-response": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
+ "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/decompress-response/node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/defer-to-connect": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+ "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/detect-node": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
+ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/electron": {
+ "version": "39.2.7",
+ "resolved": "https://registry.npmjs.org/electron/-/electron-39.2.7.tgz",
+ "integrity": "sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@electron/get": "^2.0.0",
+ "@types/node": "^22.7.7",
+ "extract-zip": "^2.0.1"
+ },
+ "bin": {
+ "electron": "cli.js"
+ },
+ "engines": {
+ "node": ">= 12.20.55"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es6-error": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/global-agent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
+ "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "dependencies": {
+ "boolean": "^3.0.1",
+ "es6-error": "^4.1.1",
+ "matcher": "^3.0.0",
+ "roarr": "^2.15.3",
+ "semver": "^7.3.2",
+ "serialize-error": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=10.0"
+ }
+ },
+ "node_modules/global-agent/node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/got": {
+ "version": "11.8.6",
+ "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
+ "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/is": "^4.0.0",
+ "@szmarczak/http-timer": "^4.0.5",
+ "@types/cacheable-request": "^6.0.1",
+ "@types/responselike": "^1.0.0",
+ "cacheable-lookup": "^5.0.3",
+ "cacheable-request": "^7.0.2",
+ "decompress-response": "^6.0.0",
+ "http2-wrapper": "^1.0.0-beta.5.2",
+ "lowercase-keys": "^2.0.0",
+ "p-cancelable": "^2.0.0",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/got?sponsor=1"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
+ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/http2-wrapper": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
+ "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "quick-lru": "^5.1.1",
+ "resolve-alpn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "license": "MIT",
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/matcher": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
+ "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "escape-string-regexp": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/normalize-url": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
+ "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/p-cancelable": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
+ "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/pump": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
+ "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/resolve-alpn": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+ "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/responselike": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
+ "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lowercase-keys": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/roarr": {
+ "version": "2.15.4",
+ "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
+ "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "dependencies": {
+ "boolean": "^3.0.1",
+ "detect-node": "^2.0.4",
+ "globalthis": "^1.0.1",
+ "json-stringify-safe": "^5.0.1",
+ "semver-compare": "^1.0.0",
+ "sprintf-js": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/serialize-error": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
+ "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "type-fest": "^0.13.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "optional": true
+ },
+ "node_modules/sumchecker": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
+ "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "debug": "^4.1.0"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
+ "node_modules/type-fest": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
+ "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ }
+}
diff --git a/native_app/package.json b/native_app/package.json
new file mode 100644
index 0000000..a6f27b9
--- /dev/null
+++ b/native_app/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "native_app",
+ "version": "1.0.0",
+ "description": "",
+ "main": "main.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "electron ."
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "electron": "^39.2.7"
+ },
+ "dependencies": {
+ "node-fetch": "^2.7.0"
+ }
+}
diff --git a/native_app/preload.js b/native_app/preload.js
new file mode 100644
index 0000000..e69de29
diff --git a/requirements.txt b/requirements.txt
index e22994c..9055bc3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
Django==5.2.7
mysqlclient==2.2.7
python-dotenv==1.1.1
+openai==1.3.3
diff --git a/static/css/custom.css b/static/css/custom.css
index 925f6ed..6c3a8df 100644
--- a/static/css/custom.css
+++ b/static/css/custom.css
@@ -1,4 +1,80 @@
-/* Custom styles for the application */
body {
- font-family: system-ui, -apple-system, sans-serif;
+ background: linear-gradient(to right, #0F2027, #203A43, #2C5364);
+ font-family: 'Inter', sans-serif;
+ color: #fff;
+}
+
+.font-poppins {
+ font-family: 'Poppins', sans-serif;
+}
+
+.font-inter {
+ font-family: 'Inter', sans-serif;
+}
+
+.glass-card {
+ background: rgba(255, 255, 255, 0.1);
+ backdrop-filter: blur(10px);
+ -webkit-backdrop-filter: blur(10px);
+ border-radius: 1rem;
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
+}
+
+/* Redefine form styles from forms.py to avoid specificity issues */
+.glass-card form .w-full.bg-gray-800 {
+ background-color: rgba(31, 41, 55, 0.5) !important;
+ border-color: rgba(55, 65, 81, 0.5) !important;
+}
+
+/* Intent Badge Styles */
+.intent-badge {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ margin-left: 8px;
+ display: inline-block;
+}
+
+.intent-neutral {
+ background-color: #9CA3AF; /* gray-400 */
+}
+
+.intent-safe {
+ background-color: #10B981; /* green-500 */
+}
+
+.intent-caution {
+ background-color: #F59E0B; /* yellow-500 */
+}
+
+.intent-warning {
+ background-color: #EF4444; /* red-500 */
+}
+
+/* Image Generator Styles */
+.btn-primary {
+ background-color: #4A90E2;
+ border-color: #4A90E2;
+ transition: background-color 0.3s ease;
+}
+
+.btn-primary:hover {
+ background-color: #357ABD;
+ border-color: #357ABD;
+}
+
+.form-control {
+ background-color: rgba(255, 255, 255, 0.2);
+ border: none;
+ color: #fff;
+}
+
+.form-control::placeholder {
+ color: rgba(255, 255, 255, 0.7);
+}
+
+.card {
+ background-color: rgba(0,0,0,0.2);
+ border: none;
}
diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css
index 108056f..6c3a8df 100644
--- a/staticfiles/css/custom.css
+++ b/staticfiles/css/custom.css
@@ -1,21 +1,80 @@
-
-: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 {
- margin: 0;
+ background: linear-gradient(to right, #0F2027, #203A43, #2C5364);
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;
+ color: #fff;
+}
+
+.font-poppins {
+ font-family: 'Poppins', sans-serif;
+}
+
+.font-inter {
+ font-family: 'Inter', sans-serif;
+}
+
+.glass-card {
+ background: rgba(255, 255, 255, 0.1);
+ backdrop-filter: blur(10px);
+ -webkit-backdrop-filter: blur(10px);
+ border-radius: 1rem;
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
+}
+
+/* Redefine form styles from forms.py to avoid specificity issues */
+.glass-card form .w-full.bg-gray-800 {
+ background-color: rgba(31, 41, 55, 0.5) !important;
+ border-color: rgba(55, 65, 81, 0.5) !important;
+}
+
+/* Intent Badge Styles */
+.intent-badge {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ margin-left: 8px;
+ display: inline-block;
+}
+
+.intent-neutral {
+ background-color: #9CA3AF; /* gray-400 */
+}
+
+.intent-safe {
+ background-color: #10B981; /* green-500 */
+}
+
+.intent-caution {
+ background-color: #F59E0B; /* yellow-500 */
+}
+
+.intent-warning {
+ background-color: #EF4444; /* red-500 */
+}
+
+/* Image Generator Styles */
+.btn-primary {
+ background-color: #4A90E2;
+ border-color: #4A90E2;
+ transition: background-color 0.3s ease;
+}
+
+.btn-primary:hover {
+ background-color: #357ABD;
+ border-color: #357ABD;
+}
+
+.form-control {
+ background-color: rgba(255, 255, 255, 0.2);
+ border: none;
+ color: #fff;
+}
+
+.form-control::placeholder {
+ color: rgba(255, 255, 255, 0.7);
+}
+
+.card {
+ background-color: rgba(0,0,0,0.2);
+ border: none;
}