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 e2fd994..233413a 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 3fec2a3..64e433c 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 2b5aa39..fbac9b4 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 7b260f0..218f670 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 d081776..16b6d6f 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -1,5 +1,5 @@
from django.contrib import admin
-from .models import Project, PipelineStep, CgiAsset
+from .models import Project, PipelineStep, CgiAsset, Scene, StudioConfig
class PipelineStepInline(admin.TabularInline):
model = PipelineStep
@@ -9,13 +9,17 @@ class CgiAssetInline(admin.TabularInline):
model = CgiAsset
extra = 1
+class SceneInline(admin.TabularInline):
+ model = Scene
+ extra = 1
+
@admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
- list_display = ('title', 'project_type', 'status', 'created_at')
- list_filter = ('project_type', 'status')
+ list_display = ('title', 'project_type', 'category', 'status', 'is_ai_generated', 'created_at')
+ list_filter = ('project_type', 'status', 'is_ai_generated')
search_fields = ('title', 'description')
prepopulated_fields = {'slug': ('title',)}
- inlines = [PipelineStepInline, CgiAssetInline]
+ inlines = [PipelineStepInline, CgiAssetInline, SceneInline]
@admin.register(PipelineStep)
class PipelineStepAdmin(admin.ModelAdmin):
@@ -26,3 +30,12 @@ class PipelineStepAdmin(admin.ModelAdmin):
class CgiAssetAdmin(admin.ModelAdmin):
list_display = ('name', 'project', 'asset_type', 'is_realistic')
list_filter = ('asset_type', 'is_realistic')
+
+@admin.register(Scene)
+class SceneAdmin(admin.ModelAdmin):
+ list_display = ('project', 'number', 'title')
+ list_filter = ('project',)
+
+@admin.register(StudioConfig)
+class StudioConfigAdmin(admin.ModelAdmin):
+ list_display = ('id', 'admin_access_key', 'is_setup')
\ No newline at end of file
diff --git a/core/migrations/0004_cgiasset_physical_description_project_category_and_more.py b/core/migrations/0004_cgiasset_physical_description_project_category_and_more.py
new file mode 100644
index 0000000..6eca116
--- /dev/null
+++ b/core/migrations/0004_cgiasset_physical_description_project_category_and_more.py
@@ -0,0 +1,48 @@
+# Generated by Django 5.2.7 on 2026-02-16 01:12
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0003_studioconfig_cgiasset_assigned_artist_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='cgiasset',
+ name='physical_description',
+ field=models.TextField(blank=True, help_text='Detailed physical appearance based on real humans'),
+ ),
+ migrations.AddField(
+ model_name='project',
+ name='category',
+ field=models.CharField(default='Sci-Fi', max_length=100),
+ ),
+ migrations.AddField(
+ model_name='project',
+ name='full_script',
+ field=models.TextField(blank=True),
+ ),
+ migrations.AddField(
+ model_name='project',
+ name='is_ai_generated',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.CreateModel(
+ name='Scene',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('number', models.PositiveIntegerField(default=1)),
+ ('title', models.CharField(max_length=255)),
+ ('description', models.TextField()),
+ ('visual_prompt', models.TextField(blank=True)),
+ ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='scenes', to='core.project')),
+ ],
+ options={
+ 'ordering': ['number'],
+ },
+ ),
+ ]
diff --git a/core/migrations/__pycache__/0004_cgiasset_physical_description_project_category_and_more.cpython-311.pyc b/core/migrations/__pycache__/0004_cgiasset_physical_description_project_category_and_more.cpython-311.pyc
new file mode 100644
index 0000000..220d061
Binary files /dev/null and b/core/migrations/__pycache__/0004_cgiasset_physical_description_project_category_and_more.cpython-311.pyc differ
diff --git a/core/models.py b/core/models.py
index de6be32..76d3dbd 100644
--- a/core/models.py
+++ b/core/models.py
@@ -31,11 +31,14 @@ class Project(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, blank=True)
project_type = models.CharField(max_length=10, choices=TYPES, default='MOVIE')
+ category = models.CharField(max_length=100, default='Sci-Fi')
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='PRE')
description = models.TextField(blank=True)
+ full_script = models.TextField(blank=True)
thumbnail_url = models.URLField(blank=True, help_text="URL to a representative image")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
+ is_ai_generated = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if not self.slug:
@@ -45,6 +48,19 @@ class Project(models.Model):
def __str__(self):
return self.title
+class Scene(models.Model):
+ project = models.ForeignKey(Project, related_name='scenes', on_delete=models.CASCADE)
+ number = models.PositiveIntegerField(default=1)
+ title = models.CharField(max_length=255)
+ description = models.TextField()
+ visual_prompt = models.TextField(blank=True)
+
+ class Meta:
+ ordering = ['number']
+
+ def __str__(self):
+ return f"Scene {self.number}: {self.title}"
+
class PipelineStep(models.Model):
STAGES = (
# Pre-Production
@@ -85,10 +101,11 @@ class CgiAsset(models.Model):
name = models.CharField(max_length=255)
asset_type = models.CharField(max_length=10, choices=ASSET_TYPES)
is_realistic = models.BooleanField(default=True)
+ physical_description = models.TextField(blank=True, help_text="Detailed physical appearance based on real humans")
current_stage = models.CharField(max_length=100, default='Modeling')
version = models.PositiveIntegerField(default=1)
file_location = models.CharField(max_length=500, blank=True, help_text="Path or URL to the digital file")
assigned_artist = models.CharField(max_length=100, blank=True)
def __str__(self):
- return f"{self.name} ({self.get_asset_type_display()})"
+ return f"{self.name} ({self.get_asset_type_display()})"
\ No newline at end of file
diff --git a/core/templates/core/index.html b/core/templates/core/index.html
index 07aa9a3..77d1db7 100644
--- a/core/templates/core/index.html
+++ b/core/templates/core/index.html
@@ -28,6 +28,9 @@
Biblioteca de Assets
+
+ STUDIO AI (Criador Automático)
+
{% if is_admin %}
@@ -55,6 +58,9 @@
{% else %}
+ {% if project.is_ai_generated %}
+
AI GENERATED
+ {% endif %}
{% endif %}
@@ -62,20 +68,23 @@
{{ project.title }}
-
- {{ project.get_status_display }}
-
+
+
+ {{ project.get_status_display }}
+
+ {{ project.category }}
+
{{ project.description|truncatewords:20 }}
- Progresso Geral
- 85%
+ Status Pipeline
+ {% with last=project.steps.last %}{{ last.progress|default:0 }}{% endwith %}%
@@ -98,4 +107,4 @@
}
.bg-cyan { background-color: var(--electric-cyan) !important; }
-{% endblock %}
+{% endblock %}
\ No newline at end of file
diff --git a/core/templates/core/project_detail.html b/core/templates/core/project_detail.html
index 2d25240..42cdab4 100644
--- a/core/templates/core/project_detail.html
+++ b/core/templates/core/project_detail.html
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% load static %}
-{% block title %}{{ project.title }} | Pipeline Detail{% endblock %}
+{% block title %}{{ project.title }} | Studio AI Production{% endblock %}
{% block content %}
@@ -15,13 +15,19 @@
-
{{ project.get_status_display }}
-
{{ project.title }}
+
+ {{ project.get_status_display }}
+ {% if project.is_ai_generated %}
+ AI GENERATED
+ {% endif %}
+ {{ project.category }}
+
+
{{ project.title }}
{{ project.description }}
-
Global Delivery
+
Status da Produção
{% with last_step=project.steps.last %}{{ last_step.progress|default:0 }}{% endwith %}%
@@ -33,71 +39,105 @@
-
-
-
CGI Production Pipeline
-
-
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
{% for step in steps %}
-
-
-
-
- {{ forloop.counter }}
-
-
{{ step.get_name_display }}
+
+
+
ETAPA {{ forloop.counter }}
+
{{ step.get_name_display }}
+
+ Progresso
+ {{ step.progress }}%
+
+
- {% if step.is_completed %}
-
COMPLETO
- {% else %}
-
{{ step.progress }}%
- {% endif %}
-
-
-
- {% empty %}
-
-
Pipeline não inicializado. Configure as etapas no Admin.
-
Adicionar Etapa +
{% endfor %}
-
-
-
-
Assets Digitais
-
- {% for asset in assets %}
-
-
-
{{ asset.name }}
-
{{ asset.get_asset_type_display }} • {{ asset.current_stage }}
+
+
+
+
+
+ {% for scene in scenes %}
+
+
+
+ {{ scene.number }}
+
+
{{ scene.title }}
+
+
+ {{ scene.description|linebreaks }}
- {% if asset.is_realistic %}
-
REALISTA
- {% endif %}
{% empty %}
-
Nenhum asset (personagens/cenários) vinculado.
+
Nenhuma cena gerada para este roteiro.
{% endfor %}
-
-
-
Diretrizes de Qualidade
-
- - ✓ Topologia limpa para rigging
- - ✓ Texturas 4K/8K PBR
- - ✓ Iluminação física (PBR)
- - ✓ Renderização em EXR Multi-camada
-
+
+
+
+
+
+
+ {% for asset in assets %}
+ {% if asset.asset_type == 'CHAR' %}
+
+
+
+
+
+
+
{{ asset.name }}
+
APARÊNCIA REALISTA
+
Físico: {{ asset.physical_description }}
+
+
+ {% endif %}
+ {% empty %}
+
Nenhum personagem definido no elenco.
+ {% endfor %}
-{% endblock %}
\ No newline at end of file
+
+
+{% endblock %}
diff --git a/core/templates/core/studio_ai.html b/core/templates/core/studio_ai.html
new file mode 100644
index 0000000..ebe8adc
--- /dev/null
+++ b/core/templates/core/studio_ai.html
@@ -0,0 +1,79 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block content %}
+
+
+
+
+
+
+
+
STUDIO AI AUTOMÁTICO
+
Crie Super-Produções (Filmes e Séries) totalmente automatizadas com IA.
+
+
+
+
+
+
A IA está gerando o roteiro, personagens e cenas... Aguarde o processamento cinematográfico.
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/core/urls.py b/core/urls.py
index dc67e2f..9faee05 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -1,10 +1,12 @@
from django.urls import path
-from .views import home, project_detail, asset_library, admin_login, admin_logout
+from . import views
urlpatterns = [
- path("", home, name="home"),
- path("project/
/", project_detail, name="project_detail"),
- path("assets/", asset_library, name="asset_library"),
- path("studio-admin/login/", admin_login, name="admin_login"),
- path("studio-admin/logout/", admin_logout, name="admin_logout"),
-]
+ path('', views.home, name='home'),
+ path('admin-login/', views.admin_login, name='admin_login'),
+ path('admin-logout/', views.admin_logout, name='admin_logout'),
+ path('assets/', views.asset_library, name='asset_library'),
+ path('studio-ai/', views.studio_ai, name='studio_ai'),
+ path('generate-production/', views.generate_production, name='generate_production'),
+ path('project//', views.project_detail, name='project_detail'),
+]
\ No newline at end of file
diff --git a/core/views.py b/core/views.py
index e0f522a..76bcbb2 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,11 +1,12 @@
import os
-import platform
+import json
from functools import wraps
-from django import get_version as django_version
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from django.contrib import messages
-from .models import Project, PipelineStep, CgiAsset, StudioConfig
+from django.http import JsonResponse
+from .models import Project, PipelineStep, CgiAsset, StudioConfig, Scene
+from ai.local_ai_api import LocalAIApi
def studio_admin_required(view_func):
"""Decorator to restrict access to studio admin only."""
@@ -19,12 +20,11 @@ def studio_admin_required(view_func):
def home(request):
"""Render the CGI Studio Command Center."""
- # Ensure StudioConfig exists and generate key if needed
config, created = StudioConfig.objects.get_or_create(id=1)
if created or not config.admin_access_key:
- config.save() # Triggers uuid generation
+ config.save()
- projects = Project.objects.prefetch_related('steps').all()
+ projects = Project.objects.prefetch_related('steps').all().order_by('-created_at')
total_projects = projects.count()
active_productions = projects.filter(status='PROD').count()
@@ -40,6 +40,96 @@ def home(request):
}
return render(request, "core/index.html", context)
+@studio_admin_required
+def studio_ai(request):
+ """Page to configure and launch AI-automated productions."""
+ return render(request, "core/studio_ai.html")
+
+@studio_admin_required
+def generate_production(request):
+ """AI logic to create a full production automatically."""
+ if request.method == "POST":
+ category = request.POST.get("category", "Sci-Fi")
+ proj_type = request.POST.get("project_type", "MOVIE")
+ theme = request.POST.get("theme", "Future of humanity")
+
+ prompt = f"""
+ Create a detailed production plan for a {proj_type} in the {category} category.
+ Theme: {theme}
+
+ Requirements:
+ 1. Unique Title and a compelling description.
+ 2. 3 Main Characters with names and detailed physical descriptions (based on REAL humans/actors style).
+ 3. 5 Key Scenes with titles and narrative descriptions.
+
+ Return the result ONLY in JSON format with the following structure:
+ {{
+ "title": "...",
+ "description": "...",
+ "characters": [
+ {{"name": "...", "description": "...", "type": "CHAR"}}
+ ],
+ "scenes": [
+ {{"title": "...", "description": "..."}}
+ ]
+ }}
+ """
+
+ response = LocalAIApi.create_response({
+ "input": [
+ {"role": "system", "content": "You are an expert Hollywood Producer and AI Cinema Director."},
+ {"role": "user", "content": prompt},
+ ],
+ "response_format": {"type": "json_object"},
+ })
+
+ if response.get("success"):
+ try:
+ data = LocalAIApi.decode_json_from_response(response)
+
+ # Create the Project
+ project = Project.objects.create(
+ title=data['title'],
+ project_type=proj_type,
+ category=category,
+ description=data['description'],
+ is_ai_generated=True,
+ status='PRE'
+ )
+
+ # Create default Pipeline Steps
+ stages = [s[0] for s in PipelineStep.STAGES]
+ for stage in stages:
+ PipelineStep.objects.create(project=project, name=stage, progress=0)
+
+ # Create Characters (Assets)
+ for char in data['characters']:
+ CgiAsset.objects.create(
+ project=project,
+ name=char['name'],
+ asset_type='CHAR',
+ physical_description=char['description']
+ )
+
+ # Create Scenes
+ for i, scene in enumerate(data['scenes']):
+ Scene.objects.create(
+ project=project,
+ number=i+1,
+ title=scene['title'],
+ description=scene['description']
+ )
+
+ messages.success(request, f"Super Produção '{project.title}' criada com sucesso pelo Studio AI!")
+ return redirect('project_detail', slug=project.slug)
+
+ except Exception as e:
+ messages.error(request, f"Erro ao processar resposta da AI: {str(e)}")
+ else:
+ messages.error(request, f"Erro na API de IA: {response.get('error')}")
+
+ return redirect('studio_ai')
+
def admin_login(request):
"""View to enter the unique admin access key."""
if request.method == "POST":
@@ -80,11 +170,12 @@ def asset_library(request):
def project_detail(request, slug):
"""Render the detailed pipeline for a specific production."""
- project = get_object_or_404(Project.objects.prefetch_related('steps', 'assets'), slug=slug)
+ project = get_object_or_404(Project.objects.prefetch_related('steps', 'assets', 'scenes'), slug=slug)
context = {
"project": project,
"steps": project.steps.all(),
"assets": project.assets.all(),
+ "scenes": project.scenes.all(),
}
- return render(request, "core/project_detail.html", context)
+ return render(request, "core/project_detail.html", context)
\ No newline at end of file