diff --git a/ai/__pycache__/__init__.cpython-311.pyc b/ai/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..9beeae7 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..ae12bda Binary files /dev/null and b/ai/__pycache__/local_ai_api.cpython-311.pyc differ diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..6fd5d9f 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..d2cfb77 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 5a69659..0e2453b 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 2a36fd6..d2627c4 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..428ec85 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,17 @@ from django.contrib import admin +from .models import Organization, Profile, ChatMessage -# Register your models here. +@admin.register(Organization) +class OrganizationAdmin(admin.ModelAdmin): + list_display = ('name', 'slug', 'created_at') + prepopulated_fields = {'slug': ('name',)} + +@admin.register(Profile) +class ProfileAdmin(admin.ModelAdmin): + list_display = ('user', 'organization', 'role') + list_filter = ('role', 'organization') + +@admin.register(ChatMessage) +class ChatMessageAdmin(admin.ModelAdmin): + list_display = ('user', 'organization', 'created_at') + readonly_fields = ('created_at',) \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..bd08f28 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,46 @@ +# Generated by Django 5.2.7 on 2026-01-21 19:24 + +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='Organization', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('slug', models.SlugField(unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='ChatMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('message', models.TextField()), + ('response', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('organization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.organization')), + ], + ), + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('role', models.CharField(choices=[('SUPER_ADMIN', 'Super Admin'), ('ORG_ADMIN', 'Organization Admin'), ('USER', 'User')], default='USER', max_length=20)), + ('organization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='members', to='core.organization')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] 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..f26db05 Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..8cbec7a 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,44 @@ from django.db import models +from django.contrib.auth.models import User +from django.db.models.signals import post_save +from django.dispatch import receiver -# Create your models here. +class Organization(models.Model): + name = models.CharField(max_length=255) + slug = models.SlugField(unique=True) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name + +class Profile(models.Model): + ROLE_CHOICES = ( + ('SUPER_ADMIN', 'Super Admin'), + ('ORG_ADMIN', 'Organization Admin'), + ('USER', 'User'), + ) + user = models.OneToOneField(User, on_delete=models.CASCADE) + organization = models.ForeignKey(Organization, on_delete=models.SET_NULL, null=True, blank=True, related_name='members') + role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='USER') + + def __str__(self): + return f"{self.user.username} - {self.role}" + +@receiver(post_save, sender=User) +def create_user_profile(sender, instance, created, **kwargs): + if created: + Profile.objects.create(user=instance) + +@receiver(post_save, sender=User) +def save_user_profile(sender, instance, **kwargs): + instance.profile.save() + +class ChatMessage(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) + organization = models.ForeignKey(Organization, on_delete=models.CASCADE, null=True, blank=True) + message = models.TextField() + response = models.TextField() + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Chat at {self.created_at}" \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..db59b26 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,67 @@ - - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}AIBiz Platform - AI-Driven B2B SaaS{% endblock %} + {% if project_description %} + + + + {% endif %} + {% if project_image_url %} + + + {% endif %} + + + + + + + + + + {% load static %} + + {% block head %}{% endblock %} + + - - {% block content %}{% endblock %} +
+ {% block content %}{% endblock %} +
+ + + + - - + \ No newline at end of file diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..6469d09 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,128 @@ {% extends "base.html" %} - -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% load static %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+
+
+
+ Enterprise Ready AI +

Scale Your Business with Intelligent Workflows

+

The ultimate AI-driven SaaS platform for multitenant organizations. Manage teams, automate documents, and chat with your business intelligence.

+ +
+
+
+
+
AI
+
AIBiz Assistant
+
+
+
+
+ Hello! I'm your AIBiz Assistant. How can I help you optimize your business today? +
+
+
+
+ + +
+
+
+
+
+
-

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" }} -

-
-
- -{% endblock %} \ No newline at end of file + + +
+
+
+

Everything You Need to Succeed

+

Powerful tools designed for the modern B2B ecosystem.

+
+
+
+
+
🏢
+
Multitenancy
+

Built-in organization management with isolated data and custom roles.

+
+
+
+
+
🤖
+
AI Chat
+

Context-aware assistant trained on your business data and workflows.

+
+
+
+
+
📄
+
Doc Ingestion
+

Automated summarization and data extraction from complex business documents.

+
+
+
+
+
+ + +{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..fd499c3 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,7 @@ from django.urls import path - -from .views import home +from .views import home, ai_chat urlpatterns = [ path("", home, name="home"), -] + path("api/ai-chat/", ai_chat, name="ai_chat"), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c9aed12..619c0b7 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,59 @@ import os import platform - +import json from django import get_version as django_version from django.shortcuts import render +from django.http import JsonResponse from django.utils import timezone - +from django.views.decorators.csrf import csrf_exempt +from ai.local_ai_api import LocalAIApi +from .models import ChatMessage, Organization 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" + """Render the landing screen with AI Chat Assistant.""" now = timezone.now() - + context = { - "project_name": "New Style", - "agent_brand": agent_brand, + "project_name": "AIBiz Platform", "django_version": django_version(), "python_version": platform.python_version(), "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), + "project_description": os.getenv("PROJECT_DESCRIPTION", "AI-Driven B2B SaaS Platform for modern enterprises."), "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), } return render(request, "core/index.html", context) + +@csrf_exempt +def ai_chat(request): + if request.method == "POST": + try: + data = json.loads(request.body) + user_message = data.get("message") + + if not user_message: + return JsonResponse({"error": "No message provided"}, status=400) + + # Construct the prompt for the AI + messages = [ + {"role": "system", "content": "You are AIBiz Assistant, an expert in business workflows, SaaS, and AI automation. Help the user with their business questions concisely and professionally."}, + {"role": "user", "content": user_message}, + ] + + response = LocalAIApi.create_response( + {"input": messages}, + {"poll_interval": 2, "poll_timeout": 60} + ) + + if response.get("success"): + ai_reply = LocalAIApi.extract_text(response) or "I'm sorry, I couldn't generate a response." + + # Save message to DB if user is authenticated (optional for landing) + # ChatMessage.objects.create(message=user_message, response=ai_reply) + + return JsonResponse({"reply": ai_reply}) + else: + return JsonResponse({"error": response.get("error", "AI service error")}, status=500) + except Exception as e: + return JsonResponse({"error": str(e)}, status=500) + + return JsonResponse({"error": "Invalid request"}, status=400) \ No newline at end of file diff --git a/static/css/custom.css b/static/css/custom.css index 925f6ed..0ccb83f 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1,4 +1,104 @@ -/* Custom styles for the application */ -body { - font-family: system-ui, -apple-system, sans-serif; +:root { + --primary-color: #2563eb; + --secondary-color: #0f172a; + --accent-color: #10b981; + --bg-light: #f8fafc; + --navy: #0f172a; } + +body { + font-family: 'Plus Jakarta Sans', sans-serif; + color: #334155; + background-color: var(--bg-light); +} + +.text-primary { color: var(--primary-color) !important; } +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); + font-weight: 600; +} +.btn-primary:hover { + background-color: #1d4ed8; +} + +.bg-navy { background-color: var(--navy); } + +/* Hero Section */ +.hero-section { + padding: 100px 0; + background: radial-gradient(circle at top right, rgba(37, 99, 235, 0.05), transparent), + radial-gradient(circle at bottom left, rgba(16, 185, 129, 0.05), transparent); +} + +.glass-card { + background: rgba(255, 255, 255, 0.7); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 20px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); +} + +/* Chat Assistant Widget */ +.chat-container { + height: 400px; + display: flex; + flex-direction: column; +} + +.chat-messages { + flex-grow: 1; + overflow-y: auto; + padding: 15px; +} + +.chat-bubble { + padding: 10px 15px; + border-radius: 15px; + margin-bottom: 10px; + max-width: 85%; + font-size: 0.9rem; +} + +.bubble-ai { + background-color: #f1f5f9; + color: #1e293b; + align-self: flex-start; +} + +.bubble-user { + background-color: var(--primary-color); + color: white; + align-self: flex-end; + margin-left: auto; +} + +.chat-input-area { + padding: 15px; + border-top: 1px solid #e2e8f0; +} + +.feature-card { + padding: 30px; + border-radius: 20px; + background: white; + transition: transform 0.3s ease; + border: 1px solid #e2e8f0; +} + +.feature-card:hover { + transform: translateY(-5px); +} + +.feature-icon { + width: 50px; + height: 50px; + background: rgba(37, 99, 235, 0.1); + color: var(--primary-color); + display: flex; + align-items: center; + justify-content: center; + border-radius: 12px; + margin-bottom: 20px; + font-size: 1.5rem; +} \ No newline at end of file diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css index 108056f..0ccb83f 100644 --- a/staticfiles/css/custom.css +++ b/staticfiles/css/custom.css @@ -1,21 +1,104 @@ - :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); + --primary-color: #2563eb; + --secondary-color: #0f172a; + --accent-color: #10b981; + --bg-light: #f8fafc; + --navy: #0f172a; } + 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; + font-family: 'Plus Jakarta Sans', sans-serif; + color: #334155; + background-color: var(--bg-light); } + +.text-primary { color: var(--primary-color) !important; } +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); + font-weight: 600; +} +.btn-primary:hover { + background-color: #1d4ed8; +} + +.bg-navy { background-color: var(--navy); } + +/* Hero Section */ +.hero-section { + padding: 100px 0; + background: radial-gradient(circle at top right, rgba(37, 99, 235, 0.05), transparent), + radial-gradient(circle at bottom left, rgba(16, 185, 129, 0.05), transparent); +} + +.glass-card { + background: rgba(255, 255, 255, 0.7); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 20px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); +} + +/* Chat Assistant Widget */ +.chat-container { + height: 400px; + display: flex; + flex-direction: column; +} + +.chat-messages { + flex-grow: 1; + overflow-y: auto; + padding: 15px; +} + +.chat-bubble { + padding: 10px 15px; + border-radius: 15px; + margin-bottom: 10px; + max-width: 85%; + font-size: 0.9rem; +} + +.bubble-ai { + background-color: #f1f5f9; + color: #1e293b; + align-self: flex-start; +} + +.bubble-user { + background-color: var(--primary-color); + color: white; + align-self: flex-end; + margin-left: auto; +} + +.chat-input-area { + padding: 15px; + border-top: 1px solid #e2e8f0; +} + +.feature-card { + padding: 30px; + border-radius: 20px; + background: white; + transition: transform 0.3s ease; + border: 1px solid #e2e8f0; +} + +.feature-card:hover { + transform: translateY(-5px); +} + +.feature-icon { + width: 50px; + height: 50px; + background: rgba(37, 99, 235, 0.1); + color: var(--primary-color); + display: flex; + align-items: center; + justify-content: center; + border-radius: 12px; + margin-bottom: 20px; + font-size: 1.5rem; +} \ No newline at end of file