ailixir-api / app /Http /Controllers /Api /MdSimulationController.php
AILIXIR Bot
Auto-sync: 201d269f287526269b8ffded5f450ff36b46c740
907b200
Raw
History Blame Contribute Delete
7.17 kB
<?php
namespace App\Http\Controllers\Api;
use App\Http\Requests\MdSimulation\ProcessRequest;
use App\Models\MdSimulationJob;
use App\Services\MdSimulationService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class MdSimulationController extends BaseController
{
private MdSimulationService $service;
public function __construct(MdSimulationService $service)
{
$this->service = $service;
}
public function health(): JsonResponse
{
$response = $this->service->healthCheck();
return response()->json($response->json(), $response->status());
}
public function process(ProcessRequest $request): JsonResponse
{
$protein = $request->file('protein');
$ligand = $request->file('ligand');
$params = $request->safe()->except(['protein', 'ligand']);
$response = $this->service->submitJob(
$protein->getRealPath(),
$protein->getClientOriginalName(),
$ligand->getRealPath(),
$ligand->getClientOriginalName(),
$params
);
if ($response->failed()) {
return $this->errorResponse(
'MD Simulation service error: '.$response->body(),
$response->status()
);
}
$remoteJobId = $response->json('job_id');
if (! $remoteJobId) {
return $this->errorResponse('Service did not return a job ID', 500);
}
$job = MdSimulationJob::create([
'user_id' => Auth::id(),
'remote_job_id' => $remoteJobId,
'status' => 'processing',
'input_params' => $params,
'protein_original_name' => $protein->getClientOriginalName(),
'ligand_original_name' => $ligand->getClientOriginalName(),
]);
return $this->successResponse('MD Simulation job submitted successfully', [
'remote_job_id' => $job->remote_job_id,
'status' => $job->status,
'created_at' => $job->created_at->toDateTimeString(),
], 202);
}
public function status(string $remoteJobId): JsonResponse
{
$job = MdSimulationJob::where('user_id', Auth::id())->where('remote_job_id', $remoteJobId)->firstOrFail();
$response = $this->service->getJobStatus($job->remote_job_id);
if ($response->successful()) {
$remoteStatus = $response->json('status');
if ($remoteStatus) {
$mapped = $this->mapRemoteStatus($remoteStatus);
if ($mapped !== $job->status) {
$update = ['status' => $mapped];
if ($mapped === 'completed') {
$update['result_meta'] = [
'download_url' => $response->json('download_url'),
'download_analysis_url' => $response->json('download_analysis_url'),
];
} elseif ($mapped === 'failed') {
$update['error_message'] = $response->json('error') ?? $remoteStatus;
}
$job->update($update);
}
}
}
return $this->successResponse('Status retrieved', [
'remote_job_id' => $job->remote_job_id,
'status' => $job->status,
'remote_status' => $response->json('status'),
'protein' => $job->protein_original_name,
'ligand' => $job->ligand_original_name,
'result_meta' => $job->result_meta,
'analysis_meta' => $job->analysis_meta,
'error_message' => $job->error_message,
'created_at' => $job->created_at->toDateTimeString(),
]);
}
public function analyze(Request $request, string $remoteJobId): JsonResponse
{
$job = MdSimulationJob::where('user_id', Auth::id())->where('remote_job_id', $remoteJobId)->firstOrFail();
if (! $job->isCompleted()) {
return $this->errorResponse('Job is not completed yet', 400);
}
$response = $this->service->runAnalysis($job->remote_job_id, $request->only([
'rmsd_mask', 'cc_mask', 'skip', 'dpi', 'threshold',
]));
if ($response->failed()) {
return $this->errorResponse(
'Analysis failed: '.$response->body(),
$response->status()
);
}
$data = $response->json();
$job->update([
'analysis_meta' => [
'download_url' => $data['download_url'] ?? null,
'outputs' => $data['outputs'] ?? [],
],
]);
return $this->successResponse('Analysis triggered successfully', [
'download_url' => $data['download_url'] ?? null,
'outputs' => $data['outputs'] ?? [],
]);
}
public function download(string $remoteJobId): JsonResponse|\Illuminate\Http\Response
{
$job = MdSimulationJob::where('user_id', Auth::id())->where('remote_job_id', $remoteJobId)->firstOrFail();
if (! $job->isCompleted()) {
return $this->errorResponse('Simulation not completed yet', 400);
}
$response = $this->service->downloadResults($job->remote_job_id);
if ($response->failed()) {
return $this->errorResponse('Results not available', 404);
}
return response($response->body(), 200)
->header('Content-Type', $response->header('Content-Type') ?? 'application/zip')
->header('Content-Disposition', "attachment; filename=\"{$job->remote_job_id}_Results.zip\"");
}
public function downloadAnalysis(string $remoteJobId): JsonResponse|\Illuminate\Http\Response
{
$job = MdSimulationJob::where('user_id', Auth::id())->where('remote_job_id', $remoteJobId)->firstOrFail();
if (! $job->isCompleted()) {
return $this->errorResponse('Simulation not completed yet', 400);
}
$response = $this->service->downloadAnalysis($job->remote_job_id);
if ($response->failed()) {
return $this->errorResponse('Analysis results not available', 404);
}
return response($response->body(), 200)
->header('Content-Type', $response->header('Content-Type') ?? 'application/zip')
->header('Content-Disposition', "attachment; filename=\"{$job->remote_job_id}_Analysis.zip\"");
}
public function history(Request $request): JsonResponse
{
$perPage = $request->input('per_page', 15);
$jobs = MdSimulationJob::where('user_id', Auth::id())
->orderBy('created_at', 'desc')
->paginate($perPage);
return $this->paginatedResponse('MD Simulation history retrieved', $jobs);
}
private function mapRemoteStatus(string $remoteStatus): string
{
if (str_starts_with($remoteStatus, 'Success:')) {
return 'completed';
}
if (str_starts_with($remoteStatus, 'Failed:')) {
return 'failed';
}
return 'processing';
}
}