Initial commit of the complete City10 virtual city simulation platform. Backend (Laravel 13): - REST API with Sanctum tokens and session-based web authentication - Role-based access control (admin/user) with middleware protection - AI agent CRUD with OpenRouter.ai integration restricted to free models - Store management with 3D coordinates and AI shopkeeper assignment - Versioned legal documents (Terms, Privacy, Cookies) with LGPD audit trail - Math CAPTCHA on public forms and multi-language support (pt_BR, en, es) Frontend: - Responsive Blade templates with Tailwind CSS v4 - Three.js 3D city viewer with SSE chat streaming to AI agents - Admin panel for store and user administration Infrastructure: - MariaDB/MySQL database with comprehensive migrations - Database seeders for demo content and test accounts - PHPUnit test suite and Laravel Pint code styling - Vite build configuration with hot reload
113 lines
3.1 KiB
PHP
Executable File
113 lines
3.1 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\AiAgentRequest;
|
|
use App\Models\AiAgent;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
|
|
/**
|
|
* AI agent management endpoints (admin only).
|
|
*
|
|
* Agents power the NPCs and managers of the virtual city through the
|
|
* OpenRouter.ai API, restricted to the allow-listed free models.
|
|
*/
|
|
class AiAgentController extends Controller
|
|
{
|
|
/**
|
|
* Return the list of models allowed for agent configuration.
|
|
*/
|
|
public function models(): JsonResponse
|
|
{
|
|
return response()->json([
|
|
'models' => config('ai.allowed_models', []),
|
|
'default' => config('ai.default_model'),
|
|
'api_key_configured' => filled(config('ai.openrouter.api_key')),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Paginated listing of registered AI agents.
|
|
*/
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$query = AiAgent::query()->orderBy('name');
|
|
|
|
if ($type = $request->query('type')) {
|
|
$query->where('type', $type);
|
|
}
|
|
|
|
if ($status = $request->query('status')) {
|
|
$query->where('status', $status);
|
|
}
|
|
|
|
return response()->json($query->paginate((int) $request->query('per_page', 15)));
|
|
}
|
|
|
|
/**
|
|
* Return a compact snapshot of active agents for the 3D renderer.
|
|
*/
|
|
public function world(): JsonResponse
|
|
{
|
|
$agents = AiAgent::query()
|
|
->where('status', '!=', 'paused')
|
|
->get(['id', 'name', 'type', 'status', 'pos_x', 'pos_y', 'pos_z', 'rotation_y', 'current_goal'])
|
|
->map(fn (AiAgent $agent): array => [
|
|
'id' => $agent->id,
|
|
'name' => $agent->name,
|
|
'type' => $agent->type,
|
|
'status' => $agent->status,
|
|
'position' => [(float) $agent->pos_x, (float) $agent->pos_y, (float) $agent->pos_z],
|
|
'rotation_y' => (float) $agent->rotation_y,
|
|
'goal' => $agent->current_goal,
|
|
]);
|
|
|
|
return response()->json(['agents' => $agents]);
|
|
}
|
|
|
|
/**
|
|
* Persist a new AI agent.
|
|
*/
|
|
public function store(AiAgentRequest $request): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
|
|
$data['model'] = $data['model'] ?? config('ai.default_model');
|
|
$data['status'] = $data['status'] ?? 'active';
|
|
|
|
$agent = AiAgent::create($data);
|
|
|
|
return response()->json($agent, 201);
|
|
}
|
|
|
|
/**
|
|
* Return a single AI agent.
|
|
*/
|
|
public function show(AiAgent $aiAgent): JsonResponse
|
|
{
|
|
return response()->json($aiAgent->load('stores:id,name,agent_id,is_open'));
|
|
}
|
|
|
|
/**
|
|
* Update an AI agent.
|
|
*/
|
|
public function update(AiAgentRequest $request, AiAgent $aiAgent): JsonResponse
|
|
{
|
|
$aiAgent->update($request->validated());
|
|
|
|
return response()->json($aiAgent->fresh());
|
|
}
|
|
|
|
/**
|
|
* Delete an AI agent.
|
|
*/
|
|
public function destroy(AiAgent $aiAgent): JsonResponse
|
|
{
|
|
$aiAgent->delete();
|
|
|
|
return response()->json(['message' => __('agents.deleted')]);
|
|
}
|
|
}
|