activate_all_gamescomando com a --forceflag para a
@ -5,11 +5,19 @@ from core.pexels import fetch_first
|
||||
import time
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Ativa todos os jogos, gera scripts de IA e capas automaticamente para todo o catálogo.'
|
||||
help = 'Ativa todos os jogos, gera scripts de IA (com história e correção) e capas automaticamente para todo o catálogo.'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--force',
|
||||
action='store_true',
|
||||
help='Força a re-geração de todos os scripts, mesmo que já existam.',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
force = options['force']
|
||||
games = GameProject.objects.all()
|
||||
self.stdout.write(f"Iniciando atualização de {games.count()} jogos...")
|
||||
self.stdout.write(f"Iniciando processamento de {games.count()} jogos (Force={force})...")
|
||||
|
||||
for game in games:
|
||||
self.stdout.write(f"Processando: {game.title}...")
|
||||
@ -17,22 +25,28 @@ class Command(BaseCommand):
|
||||
# 1. Ativar o jogo
|
||||
game.is_active = True
|
||||
|
||||
# 2. Gerar script se estiver vazio ou for muito curto (indicativo de placeholder)
|
||||
if not game.script_code or len(game.script_code) < 100:
|
||||
# 2. Gerar script se estiver vazio, for placeholder ou se force for True
|
||||
needs_script = force or not game.script_code or len(game.script_code) < 500
|
||||
|
||||
if needs_script:
|
||||
if not game.external_url:
|
||||
self.stdout.write(f" -> Gerando script de IA para {game.title}...")
|
||||
self.stdout.write(f" -> Gerando script de IA Autônomo para {game.title}...")
|
||||
script = generate_game_script(game.title, game.prompt, game.genre)
|
||||
if script:
|
||||
game.script_code = script
|
||||
self.stdout.write(self.style.SUCCESS(f" -> Script gerado com sucesso."))
|
||||
else:
|
||||
self.stdout.write(self.style.ERROR(f" -> Falha ao gerar script para {game.title}"))
|
||||
else:
|
||||
self.stdout.write(f" -> Jogo possui URL externa, pulando geração de script.")
|
||||
|
||||
# 3. Gerar Capa se não tiver
|
||||
if not game.image_reference:
|
||||
self.stdout.write(f" -> Buscando capa no Pexels para {game.title}...")
|
||||
pexels_data = fetch_first(f"{game.title} game {game.genre}")
|
||||
pexels_data = fetch_first(f"{game.title} game background")
|
||||
if pexels_data:
|
||||
game.image_reference = pexels_data['local_path'].replace('media/', '')
|
||||
self.stdout.write(self.style.SUCCESS(f" -> Capa encontrada e salva."))
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(f" -> Capa não encontrada para {game.title}"))
|
||||
|
||||
@ -40,6 +54,6 @@ class Command(BaseCommand):
|
||||
self.stdout.write(self.style.SUCCESS(f" -> {game.title} ATUALIZADO E ATIVO!"))
|
||||
|
||||
# Pequena pausa para evitar sobrecarga na API de IA/Pexels
|
||||
time.sleep(1)
|
||||
time.sleep(2)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("Processamento concluído com sucesso! Todos os jogos estão online."))
|
||||
self.stdout.write(self.style.SUCCESS("Processamento concluído! Todos os jogos estão online e atualizados com IA Autônoma."))
|
||||
|
||||
44
core/management/commands/update_all_games_ai.py
Normal file
@ -0,0 +1,44 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from core.models import GameProject
|
||||
from core.views import generate_game_script
|
||||
from core.pexels import fetch_first
|
||||
import time
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Atualiza todos os jogos existentes usando IA para gerar script, história e banners.'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
games = GameProject.objects.all()
|
||||
total = games.count()
|
||||
self.stdout.write(self.style.SUCCESS(f'Iniciando atualização de {total} jogos...'))
|
||||
|
||||
for i, game in enumerate(games):
|
||||
self.stdout.write(f'[{i+1}/{total}] Atualizando: {game.title}')
|
||||
|
||||
# 1. Gerar Script e História via IA
|
||||
# O prompt original do jogo é usado como base
|
||||
new_script = generate_game_script(game.title, game.prompt, game.genre)
|
||||
if new_script:
|
||||
game.script_code = new_script
|
||||
# Se o prompt estiver vazio, podemos pedir para a IA gerar uma descrição/história também
|
||||
# Mas o generate_game_script já coloca a história no código HTML.
|
||||
# Vamos garantir que o is_active esteja True
|
||||
game.is_active = True
|
||||
self.stdout.write(self.style.SUCCESS(f' - Script gerado com sucesso.'))
|
||||
else:
|
||||
self.stdout.write(self.style.ERROR(f' - Erro ao gerar script.'))
|
||||
|
||||
# 2. Gerar Banner via Pexels (IA baseada no título)
|
||||
if not game.image_reference or "pexels" not in str(game.image_reference):
|
||||
pexels_data = fetch_first(f"{game.title} game wallpaper background")
|
||||
if pexels_data:
|
||||
game.image_reference = pexels_data['local_path'].replace('media/', '')
|
||||
self.stdout.write(self.style.SUCCESS(f' - Banner gerado: {game.image_reference}'))
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(f' - Não foi possível gerar banner.'))
|
||||
|
||||
game.save()
|
||||
# Pequeno delay para evitar hitting limits se houver muitos
|
||||
time.sleep(1)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Todos os jogos foram atualizados, ativados e integrados com IA!'))
|
||||
@ -43,6 +43,30 @@
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
}
|
||||
/* Google Translate customization */
|
||||
.goog-te-banner-frame.skiptranslate { display: none !important; }
|
||||
body { top: 0px !important; }
|
||||
#google_translate_element {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.goog-te-gadget-icon { display: none !important; }
|
||||
.goog-te-gadget-simple {
|
||||
background-color: rgba(255,255,255,0.1) !important;
|
||||
border: 1px solid rgba(255,255,255,0.2) !important;
|
||||
padding: 5px 10px !important;
|
||||
border-radius: 20px !important;
|
||||
color: white !important;
|
||||
}
|
||||
.goog-te-menu-value span { color: white !important; }
|
||||
|
||||
/* Auto-translation notification */
|
||||
#translation-note {
|
||||
display: none;
|
||||
font-size: 0.7rem;
|
||||
color: var(--cyan-accent);
|
||||
text-align: right;
|
||||
margin-right: 15px;
|
||||
}
|
||||
</style>
|
||||
{% block extra_css %}{% endblock %}
|
||||
</head>
|
||||
@ -52,11 +76,18 @@
|
||||
<a class="navbar-brand brand-font fs-3" href="{% url 'index' %}">
|
||||
AI <span class="text-info">GAME</span> FORGE
|
||||
</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto align-items-center">
|
||||
<!-- Google Translate -->
|
||||
<li class="nav-item">
|
||||
<div id="google_translate_element"></div>
|
||||
<div id="translation-note">Auto-detecting language...</div>
|
||||
</li>
|
||||
|
||||
{% if request.session.is_admin %}
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'admin_dashboard' %}">Painel Admin</a></li>
|
||||
<li class="nav-item"><a class="nav-link btn btn-outline-danger btn-sm ms-lg-3" href="{% url 'logout' %}">Sair Admin</a></li>
|
||||
@ -92,6 +123,35 @@
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Google Translate Script with Auto-Detection -->
|
||||
<script type="text/javascript">
|
||||
function googleTranslateElementInit() {
|
||||
new google.translate.TranslateElement({
|
||||
pageLanguage: 'pt',
|
||||
includedLanguages: '', // All languages
|
||||
layout: google.translate.TranslateElement.InlineLayout.SIMPLE,
|
||||
autoDisplay: true
|
||||
}, 'google_translate_element');
|
||||
|
||||
// Auto-trigger translation based on browser language
|
||||
setTimeout(function() {
|
||||
var userLang = navigator.language || navigator.userLanguage;
|
||||
var langCode = userLang.split('-')[0];
|
||||
if (langCode !== 'pt') {
|
||||
var select = document.querySelector('select.goog-te-combo');
|
||||
if (select) {
|
||||
select.value = langCode;
|
||||
select.dispatchEvent(new Event('change'));
|
||||
document.getElementById('translation-note').style.display = 'block';
|
||||
document.getElementById('translation-note').innerText = 'Translated to: ' + userLang;
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
|
||||
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -3,7 +3,12 @@
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-5">
|
||||
<h1 class="h2">Painel de Controle</h1>
|
||||
<a href="{% url 'admin_create_game' %}" class="btn btn-primary rounded-pill px-4">+ Criar Novo Jogo</a>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{% url 'admin_batch_update_ai' %}" class="btn btn-outline-info rounded-pill px-4" onclick="return confirm('Isso irá regenerar o código, história e banners de TODOS os jogos usando IA. Pode levar alguns minutos. Deseja continuar?')">
|
||||
🪄 Atualizar Tudo (IA)
|
||||
</a>
|
||||
<a href="{% url 'admin_create_game' %}" class="btn btn-primary rounded-pill px-4">+ Criar Novo Jogo</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@ -14,6 +19,7 @@
|
||||
<table class="table table-dark table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Banner</th>
|
||||
<th>Título</th>
|
||||
<th>Gênero</th>
|
||||
<th>Data</th>
|
||||
@ -24,6 +30,13 @@
|
||||
<tbody>
|
||||
{% for project in projects %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if project.image_reference %}
|
||||
<img src="{{ project.image_reference.url }}" style="height: 40px; width: 60px; object-fit: cover; border-radius: 4px;">
|
||||
{% else %}
|
||||
<div class="bg-secondary" style="height: 40px; width: 60px; border-radius: 4px;"></div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ project.title }}</td>
|
||||
<td>{{ project.get_genre_display }}</td>
|
||||
<td>{{ project.created_at|date:"d/m/Y" }}</td>
|
||||
@ -63,4 +76,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@ -4,17 +4,24 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-10">
|
||||
<div class="glass-card">
|
||||
<h2 class="mb-4">{% if project %}Editar Jogo: {{ project.title }}{% else %}Criar Novo Jogo{% endif %}</h2>
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<h2 class="mb-4">
|
||||
{% if project %}
|
||||
<span class="text-info">🪄 Atualizar:</span> {{ project.title }}
|
||||
{% else %}
|
||||
<span class="text-info">🚀 Criar Novo Jogo</span> (Geração Autônoma)
|
||||
{% endif %}
|
||||
</h2>
|
||||
<form method="POST" enctype="multipart/form-data" id="gameForm">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Título do Jogo</label>
|
||||
<input type="text" name="title" class="form-control bg-dark text-white border-secondary" value="{{ project.title }}" required>
|
||||
<label class="form-label fw-bold">Título do Jogo</label>
|
||||
<input type="text" name="title" class="form-control bg-dark text-white border-secondary" value="{{ project.title }}" placeholder="Ex: Corrida Espacial" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Gênero</label>
|
||||
<label class="form-label fw-bold">Gênero</label>
|
||||
<select name="genre" class="form-select bg-dark text-white border-secondary">
|
||||
<option value="arcade" {% if project.genre == 'arcade' %}selected{% endif %}>Arcade (Padrão)</option>
|
||||
<option value="platformer" {% if project.genre == 'platformer' %}selected{% endif %}>Platformer</option>
|
||||
<option value="shooter" {% if project.genre == 'shooter' %}selected{% endif %}>Shooter</option>
|
||||
<option value="runner" {% if project.genre == 'runner' %}selected{% endif %}>Runner</option>
|
||||
@ -26,44 +33,73 @@
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">URL Externa (Para Jogos Online)</label>
|
||||
<input type="url" name="external_url" class="form-control bg-dark text-white border-secondary" value="{{ project.external_url|default:'' }}" placeholder="https://exemplo.com/jogo">
|
||||
<small class="text-secondary">Se preenchido, o jogo será carregado via Iframe desta URL.</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Prompt de IA / Descrição (Transforma palavras em jogos reais)</label>
|
||||
<textarea name="prompt" rows="3" class="form-control bg-dark text-white border-secondary">{{ project.prompt }}</textarea>
|
||||
<label class="form-label fw-bold">💡 Ideia / História / Prompt de IA</label>
|
||||
<textarea name="prompt" rows="3" class="form-control bg-dark text-white border-secondary" placeholder="Descreva sua ideia. A IA escreverá a história, criará o código e gerará o banner automaticamente.">{{ project.prompt }}</textarea>
|
||||
<div class="form-check mt-2">
|
||||
<input class="form-check-input" type="checkbox" name="use_ai" id="use_ai">
|
||||
<label class="form-check-label text-info" for="use_ai">
|
||||
Usar IA para gerar/atualizar o script do jogo (Transformar descrição em Código Script)
|
||||
<input class="form-check-input" type="checkbox" name="use_ai" id="use_ai" checked>
|
||||
<label class="form-check-label text-info fw-bold" for="use_ai">
|
||||
ATIVAR DESENVOLVEDOR AUTÔNOMO (Gera Script + História + Banner automaticamente)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Código Script (HTML/JS/CSS Completo)</label>
|
||||
<textarea name="script_code" rows="12" class="form-control bg-dark text-white border-secondary font-monospace" style="font-size: 0.85rem;">{{ project.script_code }}</textarea>
|
||||
<small class="text-secondary">Se usar a opção de IA, este campo será preenchido automaticamente.</small>
|
||||
<label class="form-label">URL Externa (Opcional - Para Jogos Existentes)</label>
|
||||
<input type="url" name="external_url" class="form-control bg-dark text-white border-secondary" value="{{ project.external_url|default:'' }}" placeholder="https://exemplo.com/jogo">
|
||||
</div>
|
||||
|
||||
<div class="mb-3" id="scriptContainer" style="display: none;">
|
||||
<label class="form-label">Código Script Manual (HTML/JS/CSS)</label>
|
||||
<textarea name="script_code" rows="8" class="form-control bg-dark text-white border-secondary font-monospace" style="font-size: 0.85rem;">{{ project.script_code }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="text-center my-3">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="toggleScript()">Ver/Editar Código Manualmente</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Imagem de Referência (Capa do Jogo)</label>
|
||||
<label class="form-label fw-bold">Imagem de Capa (Opcional)</label>
|
||||
<p class="small text-secondary">Se deixar em branco, a IA gerará um banner profissional baseado no título.</p>
|
||||
{% if project.image_reference %}
|
||||
<div class="mb-2">
|
||||
<img src="{{ project.image_reference.url }}" alt="Ref" style="height: 100px; border-radius: 8px;">
|
||||
<img src="{{ project.image_reference.url }}" alt="Ref" style="height: 120px; border-radius: 8px; border: 1px solid #333;">
|
||||
</div>
|
||||
{% endif %}
|
||||
<input type="file" name="image" class="form-control bg-dark text-white border-secondary">
|
||||
</div>
|
||||
|
||||
<div class="mt-4 d-flex gap-3">
|
||||
<button type="submit" class="btn btn-primary px-5 rounded-pill">SALVAR JOGO</button>
|
||||
<a href="{% url 'admin_dashboard' %}" class="btn btn-outline-light px-5 rounded-pill">VOLTAR</a>
|
||||
<button type="submit" class="btn btn-primary px-5 rounded-pill btn-lg" id="submitBtn">
|
||||
{% if project %}ATUALIZAR JOGO{% else %}GERAR JOGO COMPLETO{% endif %}
|
||||
</button>
|
||||
<a href="{% url 'admin_dashboard' %}" class="btn btn-outline-light px-5 rounded-pill btn-lg">CANCELAR</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="loadingOverlay" style="display:none; position: fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); z-index:9999; flex-direction:column; align-items:center; justify-content:center;">
|
||||
<div class="spinner-border text-info mb-3" style="width: 3rem; height: 3rem;" role="status"></div>
|
||||
<h3 class="text-white">IA TRABALHANDO...</h3>
|
||||
<p class="text-info">O Desenvolvedor Autônomo está escrevendo a história e o código do seu jogo.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
<script>
|
||||
function toggleScript() {
|
||||
var x = document.getElementById("scriptContainer");
|
||||
if (x.style.display === "none") {
|
||||
x.style.display = "block";
|
||||
} else {
|
||||
x.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('gameForm').onsubmit = function() {
|
||||
if (document.getElementById('use_ai').checked) {
|
||||
document.getElementById('loadingOverlay').style.display = 'flex';
|
||||
document.getElementById('submitBtn').disabled = true;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
@ -14,6 +14,7 @@ urlpatterns = [
|
||||
path('admin/edit-game/<int:pk>/', views.admin_edit_game, name='admin_edit_game'),
|
||||
path('admin/delete-game/<int:pk>/', views.admin_delete_game, name='admin_delete_game'),
|
||||
path('admin/edit-rental/<int:pk>/', views.admin_edit_rental, name='admin_edit_rental'),
|
||||
path('admin/batch-update-ai/', views.admin_batch_update_ai, name='admin_batch_update_ai'),
|
||||
|
||||
# User
|
||||
path('catalog/', views.catalog, name='catalog'),
|
||||
@ -22,4 +23,4 @@ urlpatterns = [
|
||||
path('simulate-payment/<int:purchase_id>/', views.simulate_payment, name='simulate_payment'),
|
||||
path('verify-payment-status/<int:purchase_id>/', views.verify_payment_status, name='verify_payment_status'),
|
||||
path('play/<int:pk>/', views.play_game, name='play_game'),
|
||||
]
|
||||
]
|
||||
103
core/views.py
@ -9,6 +9,7 @@ from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from django.http import JsonResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.core.management import call_command
|
||||
from .models import GameProject, UserSession, AdminConfig, RentalOption, UserPurchase
|
||||
from ai.local_ai_api import LocalAIApi
|
||||
from .pexels import fetch_first
|
||||
@ -73,18 +74,58 @@ def logout(request):
|
||||
def generate_game_script(title, prompt="", genre="arcade"):
|
||||
system_prompt = (
|
||||
"You are the Ultimate Autonomous AI Game Developer and Storyteller. Your mission is to transform a simple title or idea into a "
|
||||
"fully functional, high-quality browser game. You are responsible for the entire development lifecycle: "
|
||||
"1. WRITE A COMPELLING STORY: Based on the title, create an immersive narrative that sets the stage for the gameplay. "
|
||||
"2. DESIGN UNIQUE MECHANICS: Create engaging gameplay that matches the story and title. "
|
||||
"3. VISUAL EXCELLENCE: Use modern CSS (gradients, glassmorphism, smooth animations) to make the game visually stunning. "
|
||||
"4. BUG-FREE CODE: Write perfectly functional HTML5, CSS, and JavaScript in a single file. "
|
||||
"5. PROFESSIONAL UI: Include a 'Start Screen' that displays the story, a 'Game Over' screen, and intuitive controls (Keyboard/Touch). "
|
||||
"6. AUTONOMOUS CORRECTION: Review your own logic to ensure there are no errors. "
|
||||
"fully functional, high-quality browser game. You are responsible for the entire development lifecycle:\n"
|
||||
"1. WRITE A COMPELLING STORY: Based on the title, create an immersive narrative that sets the stage for the gameplay.\n"
|
||||
"2. DESIGN UNIQUE MECHANICS: Create engaging gameplay that matches the story and title.\n"
|
||||
"3. VISUAL EXCELLENCE: Use modern CSS (gradients, glassmorphism, smooth animations) to make the game visually stunning.\n"
|
||||
"4. BUG-FREE CODE: Write perfectly functional HTML5, CSS, and JavaScript in a single file.\n"
|
||||
"5. PROFESSIONAL UI: Include a 'Start Screen' that displays the story, a 'Game Over' screen, and intuitive controls (Keyboard/Touch).\n"
|
||||
"6. AUTONOMOUS CORRECTION: You MUST review your own logic and fix any potential bugs or syntax errors before providing the final code.\n"
|
||||
"Return ONLY the complete HTML5 code starting with <!DOCTYPE html>."
|
||||
)
|
||||
|
||||
full_query = f"Game Title: {title}. Description/Idea: {prompt}. Genre: {genre}."
|
||||
user_prompt = f"Act as an autonomous developer. Develop a complete browser game (Story + Code) for: {full_query}. Ensure the game story is written and displayed clearly on the start screen."
|
||||
user_prompt = f"Act as an autonomous developer. Develop a complete browser game (Story + Code) for: {full_query}. Ensure the game story is written and displayed clearly on the start screen. Use Portuguese (Brazil) for all in-game text, story, and instructions."
|
||||
|
||||
# Step 1: Initial Generation
|
||||
response = LocalAIApi.create_response({
|
||||
"input": [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt},
|
||||
],
|
||||
})
|
||||
|
||||
if not response.get("success"):
|
||||
return None
|
||||
|
||||
code = LocalAIApi.extract_text(response)
|
||||
|
||||
# Step 2: Autonomous Bug Correction
|
||||
correction_prompt = (
|
||||
"Review the HTML/JS code below. Ensure it is fully functional, has no syntax errors, and the game loop works correctly. "
|
||||
"Fix any issues and return the final, polished HTML5 code. ONLY RETURN THE CODE.\n\n"
|
||||
f"CODE TO REVIEW:\n{code}"
|
||||
)
|
||||
|
||||
corrected_response = LocalAIApi.create_response({
|
||||
"input": [
|
||||
{"role": "system", "content": "You are a senior debugger and optimizer. Your goal is to ensure the code is 100% bug-free and optimized."},
|
||||
{"role": "user", "content": correction_prompt},
|
||||
],
|
||||
})
|
||||
|
||||
if corrected_response.get("success"):
|
||||
final_code = LocalAIApi.extract_text(corrected_response)
|
||||
if "<!DOCTYPE" in final_code:
|
||||
return final_code
|
||||
return code
|
||||
|
||||
return code
|
||||
|
||||
def generate_game_story(title, genre="arcade"):
|
||||
"""Generates only the story/description for a game."""
|
||||
system_prompt = "You are a creative writer for video games. Write a short, immersive story/description for a game."
|
||||
user_prompt = f"Write a compelling 2-3 paragraph story in Portuguese (Brazil) for a game titled '{title}' in the {genre} genre."
|
||||
|
||||
response = LocalAIApi.create_response({
|
||||
"input": [
|
||||
@ -95,7 +136,7 @@ def generate_game_script(title, prompt="", genre="arcade"):
|
||||
|
||||
if response.get("success"):
|
||||
return LocalAIApi.extract_text(response)
|
||||
return None
|
||||
return ""
|
||||
|
||||
# ADMIN VIEWS
|
||||
def admin_dashboard(request):
|
||||
@ -123,12 +164,16 @@ def admin_create_game(request):
|
||||
genre = request.POST.get('genre', 'arcade')
|
||||
external_url = request.POST.get('external_url', '')
|
||||
image = request.FILES.get('image')
|
||||
use_ai = request.POST.get('use_ai') == 'on'
|
||||
use_ai = request.POST.get('use_ai') == 'on' or True
|
||||
manual_script = request.POST.get('script_code', '')
|
||||
|
||||
description = prompt
|
||||
if not description:
|
||||
description = generate_game_story(title, genre)
|
||||
|
||||
script = manual_script
|
||||
if use_ai:
|
||||
ai_script = generate_game_script(title, prompt, genre)
|
||||
if use_ai and not manual_script:
|
||||
ai_script = generate_game_script(title, description, genre)
|
||||
if ai_script:
|
||||
script = ai_script
|
||||
else:
|
||||
@ -136,6 +181,7 @@ def admin_create_game(request):
|
||||
|
||||
game = GameProject.objects.create(
|
||||
title=title,
|
||||
description=description,
|
||||
prompt=prompt,
|
||||
genre=genre,
|
||||
image_reference=image,
|
||||
@ -145,9 +191,8 @@ def admin_create_game(request):
|
||||
config_json={"player": {"speed": 200}, "entities": []}
|
||||
)
|
||||
|
||||
# Auto-generate banner if no image uploaded
|
||||
if not image:
|
||||
pexels_data = fetch_first(f"{title} game {genre}")
|
||||
pexels_data = fetch_first(f"{title} game background")
|
||||
if pexels_data:
|
||||
game.image_reference = pexels_data['local_path'].replace('media/', '')
|
||||
game.save()
|
||||
@ -177,16 +222,18 @@ def admin_edit_game(request, pk):
|
||||
use_ai = request.POST.get('use_ai') == 'on'
|
||||
manual_script = request.POST.get('script_code', '')
|
||||
|
||||
if not project.description:
|
||||
project.description = generate_game_story(project.title, project.genre)
|
||||
|
||||
if use_ai:
|
||||
ai_script = generate_game_script(project.title, project.prompt, project.genre)
|
||||
ai_script = generate_game_script(project.title, project.description, project.genre)
|
||||
if ai_script:
|
||||
project.script_code = ai_script
|
||||
else:
|
||||
project.script_code = manual_script
|
||||
|
||||
# Auto-generate banner if no image exists
|
||||
if not project.image_reference:
|
||||
pexels_data = fetch_first(f"{project.title} game {project.genre}")
|
||||
pexels_data = fetch_first(f"{project.title} game background")
|
||||
if pexels_data:
|
||||
project.image_reference = pexels_data['local_path'].replace('media/', '')
|
||||
|
||||
@ -196,6 +243,20 @@ def admin_edit_game(request, pk):
|
||||
|
||||
return render(request, 'core/admin_game_form.html', {'project': project, 'title': 'Editar Jogo'})
|
||||
|
||||
def admin_batch_update_ai(request):
|
||||
"""Triggers the management command to update all games with AI."""
|
||||
is_admin, _ = get_auth_status(request)
|
||||
if not is_admin:
|
||||
return redirect('admin_login')
|
||||
|
||||
try:
|
||||
call_command('update_all_games_ai')
|
||||
messages.success(request, 'Todos os jogos foram atualizados com IA!')
|
||||
except Exception as e:
|
||||
messages.error(request, f'Erro ao atualizar jogos: {str(e)}')
|
||||
|
||||
return redirect('admin_dashboard')
|
||||
|
||||
def admin_delete_game(request, pk):
|
||||
is_admin, _ = get_auth_status(request)
|
||||
if not is_admin:
|
||||
@ -317,15 +378,9 @@ def verify_payment_status(request, purchase_id):
|
||||
'confirmation_code': purchase.confirmation_code
|
||||
})
|
||||
else:
|
||||
invalid_code = ''.join(random.choices(string.digits, k=6))
|
||||
purchase.confirmation_code = "INVALID"
|
||||
purchase.is_paid = False
|
||||
purchase.save()
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'paid': False,
|
||||
'invalid_code': invalid_code
|
||||
'paid': False
|
||||
})
|
||||
|
||||
def play_game(request, pk):
|
||||
|
||||
BIN
media/game_covers/139038.jpg
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
media/game_covers/14421753.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
media/game_covers/15702596.jpg
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
media/game_covers/1637436.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
media/game_covers/1670977.jpg
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
media/game_covers/30771471.jpg
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
media/game_covers/3905310.jpg
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
media/game_covers/619417.jpg
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
media/game_covers/6693058.jpg
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
media/game_covers/718952.jpg
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
media/game_covers/847402.jpg
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
media/game_covers/965875.jpg
Normal file
|
After Width: | Height: | Size: 65 KiB |