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.

+
+ +
+ {% csrf_token %} +
+ + +
+ +
+ + +
+ +
+ + +
A IA criará personagens reais, cenas e roteiro completo com base nisso.
+
+ +
+ +
+
+ +
+

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